移除未使用变量引发程序崩溃,疑因dataArr越界求解答
首先得戳破这个“黑魔法”的假象——你遇到的根本不是什么越界问题,而是返回局部栈数组导致的未定义行为,那个n[80]只是碰巧掩盖了问题而已。
核心问题:返回局部栈数组是未定义行为
你的dataArr是在read_file函数里声明的局部数组:
char * dataArr[80];
这种数组是分配在栈内存上的,栈内存的特点是:当函数执行完毕返回时,当前函数的栈帧会被销毁,这块内存会被标记为可复用。后续任何函数调用(比如你调用read_file之后的代码)都会覆盖这块内存的内容。
你返回dataArr的指针,本质上是返回了一块已经无效的内存地址。后续访问dataArr的元素时,你看到的都是随机的垃圾数据,崩溃或者不崩溃完全取决于后续操作有没有覆盖这块内存——这就是所谓的“未定义行为”,结果完全不可预测。
为什么n[80]存在时没崩溃?
这纯粹是巧合:n[80]作为另一个局部栈数组,占据了栈上的一部分空间。当read_file返回后,n的内存区域刚好“挡住”了后续操作对dataArr内存的覆盖,让你误以为程序能正常运行。
当你把n改成n[20]时,它占据的栈空间变小,dataArr的内存更快被后续操作覆盖,所以程序直接报错;改成n[21]时,又碰巧让dataArr的内存暂时没被覆盖——但这依然是未定义行为,换个环境、换个编译器版本可能还是会崩溃。
另外,你的代码还有一个小bug:fp == NULL的检查放在了while循环里面,这时候如果fopen失败,fgets已经被调用了,会导致非法访问。正确的做法是在fopen之后立刻检查。
正确的修复方案
要解决这个问题,你需要把dataArr分配在堆内存上,这样函数返回后内存依然有效。这里提供两种可行的方案:
方案1:动态分配字符串数组
char ** read_file(char * userFile) { // 动态分配能存储80个字符串指针的数组 char **dataArr = malloc(80 * sizeof(char *)); if (!dataArr) { fprintf(stderr, "Memory allocation failed!\n"); exit(1); } char currLine[256]; char *eof; int i = 0; FILE *fp = fopen(userFile, "r"); if (fp == NULL) { fprintf(stderr, "Can't open input file %s!\n", userFile); free(dataArr); // 分配的内存要释放 exit(1); } while((eof = fgets(currLine, sizeof(currLine), fp)) != NULL) { dataArr[i] = strdup(eof); // 检查strdup是否成功(如果内存不足会返回NULL) if (!dataArr[i]) { fprintf(stderr, "Failed to duplicate string!\n"); // 释放已经分配的字符串和数组 for (int j = 0; j < i; j++) { free(dataArr[j]); } free(dataArr); fclose(fp); exit(1); } i++; // 防止数组越界 if (i >= 80) { fprintf(stderr, "File has too many lines (max 80 allowed)!\n"); break; } } fclose(fp); return dataArr; }
注意:调用这个函数后,记得在使用完dataArr后释放内存——先逐个释放每个字符串,再释放数组本身:
char **dataArr = read_file(argv[1]); // 使用dataArr... for (int i = 0; dataArr[i]; i++) { free(dataArr[i]); } free(dataArr);
方案2:让调用者提供数组
如果你不想用动态内存,可以让调用者提前分配好数组,传递给read_file函数:
int read_file(char * userFile, char **dataArr, int maxLines) { char currLine[256]; char *eof; int i = 0; FILE *fp = fopen(userFile, "r"); if (fp == NULL) { fprintf(stderr, "Can't open input file %s!\n", userFile); return -1; } while((eof = fgets(currLine, sizeof(currLine), fp)) != NULL && i < maxLines) { dataArr[i] = strdup(eof); if (!dataArr[i]) { fprintf(stderr, "Failed to duplicate string!\n"); for (int j = 0; j < i; j++) { free(dataArr[j]); } fclose(fp); return -1; } i++; } fclose(fp); return i; // 返回实际读取的行数 }
调用方式:
char *dataArr[80]; int lineCount = read_file(argv[1], dataArr, 80); // 使用dataArr... for (int i = 0; i < lineCount; i++) { free(dataArr[i]); }
内容的提问来源于stack exchange,提问作者Alex Wittwer

