strncpy与直接分配段故障

uhry853o  于 2023-01-25  发布在  其他
关注(0)|答案(4)|浏览(121)

下面的代码在运行时不会出现seg错误

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct node {
    char *data;
    struct node *next;
};

int main(void)
{   
    struct node *head = malloc(sizeof(struct node));
    
    head->data = "test";
    printf("data: %s\n", head->data);

    return 0;
}

当我把代码切换成so时

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct node {
    char *data;
    struct node *next;
};

int main(void)
{   
    struct node *head = malloc(sizeof(struct node));
    
    strncpy(head->data, "test", 512);
    printf("data: %s\n", head->data);

    return 0;
}

我收到了一个seg错误,并被迫将我的节点属性数据切换为char数据类型[512]。为什么需要这样做?我认为数组本质上是指针,所以这种行为对我来说没有意义。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct node {
    char data[512];
    struct node *next;
};

int main(void)
{   
    struct node *head = malloc(sizeof(struct node));
    
    strncpy(head->data, "test", 512);
    printf("data: %s\n", head->data);

    return 0;
}

我希望指针和数组都能以同样的方式被赋予字符串值。

7kqas0il

7kqas0il1#

在这份声明中

head->data = "test";

具有数组类型char[5]的字符串文字被隐式转换为指向其第一元素的指针,并且该指针被分配给指针head->data
在这份声明中

strncpy(head->data, "test", 512);

你正在使用一个未初始化的指针head->data,并试图将整个字符串文本复制到该指针所指向的内存中,该指针具有一个不确定的值。这将调用未定义的行为。
我认为数组本质上是指针,所以这种行为对我来说没有意义。
数组不是指针。在大多数情况下,数组可以隐式转换为指向其第一个元素的指针,但这并不意味着数组是指针。
考虑下面的简单演示程序。

#include <stdio.h>

int main( void )
{
    char data[512];
    char *p = data;

    printf( "sizeof( data ) = %zu\n", sizeof( data ) );
    printf( "sizeof( p ) = %zu\n", sizeof( p ) );
}

其输出可能如下所示

sizeof( data ) = 512
sizeof( p ) = 8
flseospp

flseospp2#

在第二个代码段(崩溃的代码段)中,为node结构体分配内存,该结构体包含指针data,但是,该指针从未初始化,它指向某个任意内存地址(或仅指向NULL),这意味着写入它的操作是undefined behavior,实际上可能只是segfault。
为了让它指向一个有效的内存地址,你必须显式地分配它:

struct node *head = malloc(sizeof(struct node));
head->data = malloc(sizeof(char) * 512 /* or some other size, of course */);
jdgnovmf

jdgnovmf3#

我认为数组本质上是指针,所以这种行为对我来说没有意义。
指针只是指针,它们占用的内存只是存储地址所需的内存。如果你想让指针指向动态分配的内存,你需要自己分配它。
示例:

struct node {
    char *data;
    struct node *next;
};

struct node *create_node(const char *str) {
    struct node *nn = malloc(sizeof *nn);
    if(nn) {
        nn->data = strdup(str); // allocate strlen(str)+1 bytes and copy the string
        if(nn->data) {          // strdup was successful
            nn->next = NULL;
        } else {                // strdup failed
            free(nn);
            nn = NULL;
        }
    }
    return nn;
}

void destroy_node(struct node *n) {
    free(n->data);
    free(n);
}
lvmkulzt

lvmkulzt4#

我以为数组本身就是指针

    • 数组与指针:**

数组在表达式和函数参数中可能会退化为指针,数组访问可能会被编译器重写为指针访问,但它们是不可互换的。数组名是地址,指针是地址的地址。
为什么需要这样做?
声明指针只为指针分配内存。
您可以通过两种方式初始化指针:

  • 使用字符串文字:
ptr = "abcd";

最初,ptr是不确定的,但是这改变了它所指向的内容,现在它指向一个字符串,编译器将字符串的第一个元素的地址存储在ptr中。
如果你对一个
阵列:

char s[] = "String";

然后尝试改变它的值:

s = "String2"; 

/* error: assignment to expression 
with array type */

它不能编译,因为数组不像指针,是不可修改的左值,你不能改变它的值。

  • 或为其分配内存,然后

写信给它。

errno = 0;

ptr = malloc (size);
if (!ptr) {
    errno = ENOMEM;
    perror ("malloc ()");
    deal with error here...
}

现在您可以使用strcpy ()复制到它。

相关问题