创建动态通用数组时,realloc 出现分段错误

问题描述 投票:0回答:1

我尝试实现一个动态通用数组。然而,当我测试我的代码时,得到的结果是“分段错误”。我知道这个错误是由函数 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;
}
c segmentation-fault dynamic-arrays realloc
1个回答
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
函数进行适当的相应更改。

© www.soinside.com 2019 - 2024. All rights reserved.