[英]Segmentation fault occuring with zero-length array
我有這個鏈表節點結構,它使用零長度數組來存儲 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
是一個包含總列表大小的指針)
我正在使用這個 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);
}
所以分段錯誤發生在 memcpy 中,但我不明白為什么,因為我分配了sizeof(t_list) + size
個字節,所以這應該足以對數據執行memcpy(size)
。 此調用發生了段錯誤: lst_new_element((void *)atoll(argv[1]), sizeof(long long))
( argv[1]
為5
)
謝謝您的幫助。
您將long long
值傳遞給 function ,就好像它是有效的void *
一樣。 您的 function 然后嘗試取消引用該指針(無效)以嘗試復制它指向的內容。 這會觸發導致崩潰的未定義行為。
您需要將atoll
的返回值分配給一個局部變量,然后將該變量的地址傳遞給 function。
long long val = atoll(argv[1]);
t_list *l = lst_new_element((&val, sizeof(long long));
此外,使用長度為 0 的數組作為結構的最后一個成員是許多編譯器用來實現靈活數組成員的擴展。 執行此操作的符合標准的方法是將大小留空。
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
您正在將long long
值轉換為指針,這當然是完全錯誤的。 而是將結果存儲在一個臨時變量中並傳遞該變量(按值或引用)。
另請注意, ato...
函數是半過時且危險的,您應該改用strtoll
,它具有更好的錯誤處理能力。
此外(與崩潰無關),零長度 arrays 是 gcc 的一個過時的非標准功能,距今已有 20 多年了。 您應該改用標准 C 靈活數組成員。 它們的工作原理完全相同,只需將代碼更改為: char data[];
.
對於您的 function 調用,您需要一個中間變量來存儲轉換后的值,例如:
long long llval = atoll(argv[1]);
lst_new_element(&llval, sizeof(long long));
您可以使用復合文字來分配一個臨時數組以使值位於 memory 中,而不是像其他答案所建議的那樣使用臨時變量。
lst_new_element((long long[]){ atoll(argv[1]) }, sizeof(long long));
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.