简体   繁体   English

零长度数组发生分段错误

[英]Segmentation fault occuring with zero-length array

I have this linked list node struct that's using a zero-length array for storing memory:我有这个链表节点结构,它使用零长度数组来存储 memory:

typedef struct s_list
{
    size_t          *list_size;
    struct s_list   *prev;
    struct s_list   *next;
    size_t          size;
    char            data[0];
}   t_list;

( list_size is a pointer containing the size of the total list) list_size是一个包含总列表大小的指针)

And I'm using this function to allocate a new node:我正在使用这个 function 来分配一个新节点:

static t_list   *lst_new_element(void *data, size_t size)
{
    t_list  *new_element;

    new_element = malloc(sizeof(t_list) + size);
    if (!new_element)
        return (NULL);
    new_element->size = size;
    memcpy(new_element->data, data, size); // <--- Segfault occurs here
    return (new_element);
}

So the segmentation fault occurs in the memcpy, but I don't understand why because I allocate sizeof(t_list) + size bytes so this should be enough to do a memcpy(size) on data.所以分段错误发生在 memcpy 中,但我不明白为什么,因为我分配了sizeof(t_list) + size个字节,所以这应该足以对数据执行memcpy(size) The segfault occured with this call: lst_new_element((void *)atoll(argv[1]), sizeof(long long)) ( argv[1] is 5 )此调用发生了段错误: lst_new_element((void *)atoll(argv[1]), sizeof(long long))argv[1]5

Thanks for the help.谢谢您的帮助。

You're passing a long long value to your function as if it's a valid void * .您将long long值传递给 function ,就好像它是有效的void *一样。 Your function then attempts to dereference that pointer (which in invalid) in an attempt to copy what it points to.您的 function 然后尝试取消引用该指针(无效)以尝试复制它指向的内容。 This triggers undefined behavior leading to a crash.这会触发导致崩溃的未定义行为

You need to assign the return value of atoll to a local variable, then pass the address of that variable to the function.您需要将atoll的返回值分配给一个局部变量,然后将该变量的地址传递给 function。

long long val = atoll(argv[1]);
t_list *l = lst_new_element((&val, sizeof(long long));

Also, using a 0 length array as the last member of a struct is an extension many compilers use to implement a flexible array member .此外,使用长度为 0 的数组作为结构的最后一个成员是许多编译器用来实现灵活数组成员的扩展。 The standard-compliant way of doing this is to leave the size blank.执行此操作的符合标准的方法是将大小留空。

typedef struct s_list
{
    size_t          *list_size;
    struct s_list   *prev;
    struct s_list   *next;
    size_t          size;
    char            data[];
}   t_list;

(void *)atoll You are converting a long long value to a pointer which is of course plain wrong. (void *)atoll您正在将long long值转换为指针,这当然是完全错误的。 Instead store the results in a temporary variable and pass that one (by value or reference).而是将结果存储在一个临时变量中并传递该变量(按值或引用)。

Also please note that ato... functions are semi-obsolete and dangerous, you should be using strtoll instead, which has better error handling.另请注意, ato...函数是半过时且危险的,您应该改用strtoll ,它具有更好的错误处理能力。

In addition (not related to the crash), zero-length arrays is an obsolete non-standard feature of gcc since well over 20 years.此外(与崩溃无关),零长度 arrays 是 gcc 的一个过时的非标准功能,距今已有 20 多年了。 You should be using standard C flexible array members instead.您应该改用标准 C 灵活数组成员。 They work exactly the same, just change the code to: char data[];它们的工作原理完全相同,只需将代码更改为: char data[]; . .

For your function call you need an intemediate variable to store the converted value, for example:对于您的 function 调用,您需要一个中间变量来存储转换后的值,例如:

long long llval = atoll(argv[1]);
lst_new_element(&llval, sizeof(long long));

You can use compound literals to allocate a temporally array to have the value be in the memory instead of using temporally variable as othe answers suggests.您可以使用复合文字来分配一个临时数组以使值位于 memory 中,而不是像其他答案所建议的那样使用临时变量。

lst_new_element((long long[]){ atoll(argv[1]) }, sizeof(long long));

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM