C语言封装读文件到字符串数组的函数后出现段错误如何排查
问题根因
段错误的直接原因是运算符优先级错误:C语言中[]下标运算符的优先级高于*解引用运算符,你在函数中写的*rows[i]实际等价于*(rows[i]),完全不符合预期逻辑。你想要的是先对入参rows(三级指针)解引用得到存储行的char**数组,再取下标i的元素,正确写法应该是(*rows)[i]。
额外还有一个不必要的设计问题:你传入了FILE**二级文件指针,但函数内部并没有修改FILE指针本身的值,完全不需要传二级指针,直接传FILE*即可。
修复后的完整代码
#define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <string.h> size_t readFile(FILE *fp, char ***rows) { char *lineBuf = NULL; size_t n = 0; size_t nLines = 0; ssize_t lineLength = 0; size_t i = 0; while ((lineLength = getline(&lineBuf, &n, fp)) != -1) { lineBuf[strcspn(lineBuf, "\n")] = 0; lineBuf[strcspn(lineBuf, "\r")] = 0; // 修正优先级问题,先解引用rows再取下标 (*rows)[i] = malloc(lineLength + 1); strcpy((*rows)[i], lineBuf); i++; nLines = i; char **temp = realloc(*rows, (nLines + 1) * sizeof(char *)); // 增加realloc失败判断,避免内存泄漏 if (temp == NULL) { perror("realloc failed"); // 可补充已分配内存的释放逻辑,进一步避免泄漏 break; } *rows = temp; } // 释放getline分配的缓冲区 free(lineBuf); return nLines; } int main(int argc, char **argv) { if (argc != 2) { fprintf(stderr, "Please supply a file path:\n%s <file path>\n", argv[0]); return EXIT_FAILURE; } FILE *fp = fopen(argv[1], "r"); if (!fp) { perror("ERROR"); return EXIT_FAILURE; } char **rows = malloc(sizeof(char *)); // 直接传FILE*即可,不需要传二级指针 size_t nLines = readFile(fp, &rows); printf("nLines: %lu\n", nLines); if (nLines >= 1) printf("row 1: %s\n", rows[0]); if (nLines >= 2) printf("row 2: %s\n", rows[1]); // 最后记得释放rows数组和每个行的内存、关闭文件,避免泄漏 for (size_t i = 0; i < nLines; i++) { free(rows[i]); } free(rows); fclose(fp); return 0; }
其他优化说明
- 新增了
realloc返回值判断,避免分配失败时直接覆盖原指针导致内存泄漏 - 新增了
getline分配的lineBuf的释放逻辑,避免内存泄漏 - 新增了数组下标访问的边界判断,避免文件行数不足时访问越界
- 移除了
malloc/realloc返回值的强制转换,C语言中该转换是非必要的,反而可能隐藏隐含错误
内容的提问来源于stack exchange,提问作者Max888
相关产品推荐
相关产品推荐

