[英]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.