C语言中如何正确将文本文件逐行存储到动态数组?
C语言读取变长行到动态数组的问题解决
你的代码运行后重复打印最后一行,核心原因和你猜测的完全一致:所有数组元素都指向同一个buffer的内存地址,每次fgets只是覆盖了buffer内的内容,并没有为每行文本分配独立的存储空间。
解决方案
需要为每行文本分配独立内存并复制内容,而不是直接传入buffer的指针。以下是修改后的完整代码:
优化后的动态数组实现
#include <stdio.h> #include <stdlib.h> #include <string.h> struct array { char **elements; long size; long capacity; }; void array_init(struct array *array, long capacity) { array->size = 0; // 必须初始化size为0,原代码遗漏了这一步 array->capacity = capacity; array->elements = malloc(capacity * sizeof(char*)); if (!array->elements) { perror("malloc failed for array elements"); } } void array_push_back(struct array *array, char *element) { if (!array || !element) return; if (array->size == array->capacity) { long new_capacity = array->capacity * 2; // 先分配新内存,再替换原指针,避免分配失败时丢失原数据 char **new_elements = realloc(array->elements, new_capacity * sizeof(char*)); if (!new_elements) { perror("realloc failed for array expansion"); return; } array->elements = new_elements; array->capacity = new_capacity; } array->elements[array->size++] = element; }
修改后的文件读取代码
int main(int argc, char *argv[]) { if (argc < 2) { fprintf(stderr, "Usage: %s <filename>\n", argv[0]); return 1; } const char *filename = argv[1]; struct array array; FILE *file = fopen(filename, "r"); if (!file) { perror("failed to open file"); return 1; } const unsigned MAX_LENGTH = 256; char buffer[MAX_LENGTH]; array_init(&array, 1000); while (fgets(buffer, MAX_LENGTH, file)) { // 复制当前行到新分配的内存,strdup自动处理内存分配和字符串复制 char *line = strdup(buffer); if (!line) { perror("strdup failed for line"); // 清理已分配的内存 for (long i = 0; i < array.size; i++) { free(array.elements[i]); } free(array.elements); fclose(file); return 1; } array_push_back(&array, line); } // 打印所有行 for (long i = 0; i < array.size; i++) { printf("%s", array.elements[i]); // 使用格式化字符串更安全 } // 释放所有内存 for (long i = 0; i < array.size; i++) { free(array.elements[i]); } free(array.elements); fclose(file); return 0; }
关键修改说明
- 初始化
size成员:原动态数组代码未初始化size,会导致array_push_back中的判断逻辑出现未定义行为,必须显式设为0。 - 为每行分配独立内存:用
strdup复制buffer内容,生成新的字符串指针,确保数组中每个元素指向独立的内存块,不会被后续fgets覆盖。 - 错误检查:增加了文件打开、内存分配的错误处理,避免程序崩溃或内存泄漏。
- 安全的内存扩容:扩容时先通过
realloc获取新内存,再替换原指针,防止分配失败时丢失已存储的数据。 - 内存释放:程序结束前释放所有分配的内存,避免内存泄漏。
如果你的环境不支持strdup,可以手动实现一个替代函数:
char* my_strdup(const char* s) { if (!s) return NULL; size_t len = strlen(s) + 1; char* dup = malloc(len); if (dup) { strcpy(dup, s); } return dup; }
内容的提问来源于stack exchange,提问作者mltm
相关产品推荐
相关产品推荐

