为何C语言函数内对数组的修改无法在main函数中持久化?
问题:为何C语言函数内对数组的修改无法在main函数中持久化?
我编写了一个读取CSV文件的函数,当仅调用read_csv而不接收其返回的void**时,在main函数中打印数组值会触发段错误;但将函数返回的数组赋值给main中的array变量后则能正常运行。请问为何函数内对数组的修改无法在main函数中持久化?
#include <stdio.h> #include <stdlib.h> #include <string.h> #define NITEMS 7 #define SIZE sizeof(Data) #define K 5 typedef struct _data { int id; char field1[50]; int field2; float field3; }Data; void ** read_csv(void **array, const char *filename){ int capacity = 1, size = 0; FILE *file = fopen(filename, "r"); if (file == NULL) { printf("errore"); return NULL; } Data *row; while (!feof(file)){ row = malloc(sizeof(Data)); if (row == NULL) { printf("Unable to allocate new row!"); exit(EXIT_FAILURE); } fscanf(file,"%d,%49[^,],%d,%f\n",&row->id,&row->field1,&row->field2,&row->field3); if (size >= capacity) { capacity = 2 * capacity; array = (void **)realloc(array, capacity * sizeof(void**)); } array[size] = row; size++; printf("\n\n%d", ((Data*)array[0])->id); } fclose(file); return array; } int main(int argc, char const *argv[]) { if(argc < 3){ printf("\n Please make sure that each file is inserted in correct way: \n ./main first(csv) second (ordered csv) third(k) fourth(field)\n\n"); exit(EXIT_FAILURE); } void ** array = malloc(sizeof(void **)); if(array == NULL) exit(EXIT_FAILURE); // read_csv(array,argv[1]) --> this don't mantain the changes array = read_csv(array, argv[1]); // this yes return 0; }
解答
核心原因是C语言的参数传递是值传递,加上realloc的内存重分配特性共同导致的:
值传递的特性:
当你把main函数中的array指针传给read_csv时,函数会创建一个该指针的副本。函数内部对array的所有修改(比如重新赋值)都只作用于这个副本,完全不会影响main函数里的原指针。realloc的影响:
当数组容量不足时,realloc会申请一块新的更大内存,把旧内存的数据拷贝过去,然后释放旧内存。此时函数内的array副本会被更新为新内存的地址,但main函数里的原指针仍然指向已经被释放的旧内存。两种调用方式的差异:
- 直接调用
read_csv(array, argv[1])不接收返回值:main里的array还是旧地址,这块内存已经被realloc释放,后续访问会触发段错误。 - 用
array = read_csv(array, argv[1])接收返回值:main里的array被赋值为函数返回的新内存地址,这个地址是有效的,所以能正常访问数组内容。
- 直接调用
如果不想用返回值的方式,也可以通过传递指针的指针(比如void ***array)来让函数修改外层指针的指向,但返回值的写法更直观易读,也是这类场景的常规做法。
内容的提问来源于stack exchange,提问作者Matteo Pagliarello
相关产品推荐
相关产品推荐

