我尝试实现一个动态通用数组。然而,当我测试我的代码时,得到的结果是“分段错误”。我知道这个错误是由函数 ArrayListResize 中的 realloc 发生的,但为什么呢?
这是我的几个方法的实现:
typedef struct ArrayList {
void** arr;
size_t allocated, len;
} ArrayList;
int ArrayListInit(ArrayList *list) {
list = (ArrayList *)malloc(sizeof(ArrayList));
if (list == NULL) {
fprintf(stderr, FAILED_ALLOCATION_MSG);
return -1;
}
list->allocated = 0;
list->len = 0;
list->arr = (void **)NULL;
return 0;
}
int ArrayListAppend(ArrayList *list, void *item) {
if (item == NULL) {
fprintf(stderr, INVALID_ARG_MSG);
return -1;
}
if (ArrayListResize(list, list->len + 1) == -1) {
return -1;
}
list->arr[list->len] = item;
return 0;
}
int ArrayListResize(ArrayList *list, size_t len) {
void **arr;
size_t allocated = list->allocated, new_allocated;
if (allocated >= len && len >= (allocated >> 1)) {
assert(list->arr != NULL || len == 0);
list->len = len;
return 0;
}
if (len == 0)
new_allocated = 0;
else
new_allocated = len + (len >> 3) + (len < 9 ? 3 : 6);
arr = (void**)realloc(list->arr, sizeof(void *) * new_allocated); // Here I get the segmentation fault
if (arr == NULL) {
fprintf(stderr, FAILED_REALLOCATION_MSG);
return -1;
}
list->arr = arr;
list->allocated = new_allocated;
list->len = len;
return 0;
}
这是测试代码:
int* GenerateIntPointer(int n) {
int* ptr_int = (int*)malloc(sizeof(int));
*ptr_int = n;
return ptr_int;
}
int main() {
ArrayList list;
ArrayListInit(&list);
for (size_t i = 0; i < 10; i++) {
ArrayListAppend(&list, (void*)GenerateIntPointer((int)i));
}
ArrayListDelete(&list, free);
return 0;
}
一个重要的问题是您的
ArrayListInit
函数实际上并未初始化您在 list
函数中在堆栈上声明的 main
对象!你有这条线
ArrayList list;
为堆栈上的
ArrayList
对象预留内存。然而,尽管我相信这取决于编译器,但出于效率目的,由于没有构造函数并且它是一个结构,因此这些值未初始化。
然后,您的代码将在该行中传递指向该对象的指针
ArrayListInit(&list);
其中,在
ArrayListInit
中,您将其参数(也称为 list
)重新分配到新的内存位置,即使用
list = (ArrayList *)malloc(sizeof(ArrayList));
if (list == NULL) {
fprintf(stderr, FAILED_ALLOCATION_MSG);
return -1;
}
因此,剩下的初始化行,即
list->allocated = 0;
list->len = 0;
list->arr = (void **)NULL;
更新新分配的对象,而不是
list
中的原始main
对象。因此,在 ArrayListResize
中,传递给 realloc
的值无效,无论堆栈字节最初具有什么,从而导致分段错误。
解决此问题的最简单方法是删除
ArrayListInit
中的行,这些行将传入的 list
指针值更改为新的内存位置。您可能还需要对您的 ArrayListDelete
函数进行适当的相应更改。