我试图实现一个动态泛型array.然而,当我测试我的代码时,我得到的结果是"分段错误".我知道这个错误是由函数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函数实际上并没有初始化您在main函数的堆栈上声明的list对象!你有这条线

  ArrayList list;

which sets aside memory for an ArrayList object on the stack. However, since it's a struct, then for efficiency & smaller code size purposes, the values are likely not initialized. Actually, since you've tagged this with , then there are no even implicit constructors and C compilers won't initialize it. Even with a CPP compiler on a .c file, or with a .cpp file since there is no explicit constructor, no initialization will very likely occur even then.

然后,您的代码将在该行中传递指向此对象的指针

  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;

更新新分配的对象,而不是main中的原始list对象.因此,在ArrayListResize中,传递给realloc的值是无效的,无论堆栈字节最初具有什么,从而导致分段错误.

解决这个问题最简单的方法是删除ArrayListInit中的行,这些行将list中传递的指针值更改为新的内存位置.或者,特别是如果你只使用一个ArrayList对象,你可以摆脱ArrayListInit方法,直接初始化对象值,例如,如Neil's comment中所建议的,即,

您肯定希望初始化它;例如,ArrayList list = {0}ArrayList list = {0,0,0}(C90).

您可能还需要对您的ArrayListDelete功能进行适当的相应更改.

或者,如果您希望拥有和使用动态分配的ArrayList对象,则需要进行多项更改.首先,在main中,你的申报行是这样的

ArrayList* list;

然后将您的ArrayListInit函数更改为参数ArrayList** list.在该函数的其余部分中,将list更改为*list.在main函数中,将ArrayListAppend调用更改为只传入list.最后,您需要在ArrayListDelete函数中进行相应的更改.

C++相关问答推荐

为什么海湾合作委员会在共享对象中的. init_data的虚拟内存地址之前留出一个空白

为什么getchar()挂起了,尽管poll()返回了一个好的值?""

GCC引发不明确的诊断消息

核心转储文件中出现奇怪的大小变化

如何在C中引发/处理自定义信号?

在C语言中,是否可以使枚举数向后计数?

为什么函数是按照定义的顺序执行的,而不是按照从avr-c中的int main()调用的顺序执行的?

使用TCL C API导航到列表中的元素

如何仅使用软件重新初始化STM32微控制器中的USB枚举?

处理来自浏览器的HTTP请求

Printf()在C中打印终止字符之后的字符,我该如何解决这个问题?

如果格式字符串的内存与printf的一个参数共享,会发生什么情况?

合并对 struct 数组进行排序

C++中PUTS函数的返回值

基于蝶数恰好有8个除数的事实的代码

在我的函数中实现va_arg的问题

Ubuntu编译:C中的文件格式无法识别错误

中位数和众数不正确

子进程不会修改父进程中的统计信息

如何根据当前舍入方向将float转换为int?