C语言读取TXT到字符串数组时数据覆盖问题求助
C语言读取TXT填充数组元素被覆盖问题修复
原始问题
需要将TXT文件中的名称填充到数组中,但代码运行时新读取的数据会覆盖之前所有数组元素,且调用inicializarNombre()后数组元素会被清空。
原始代码
#include <stdio.h> void inicializarNombre (char* nombre) { for (int i = 0; i < 20; ++i) { nombre[i] = '\0'; } } int main() { setbuf(stdout, 0); char *vectoristoNombres[10]; char *vectoristoApellidos[10][20]; FILE *nombres; nombres = fopen("nombres.txt" , "r"); if(nombres == NULL) { perror("Error opening file"); return(-1); } for (int i = 0; i < 10; ++i) { vectoristoNombres[i] = ""; } for (int i = 0; i < 10; i++) { char caracter; char nombre[20]; inicializarNombre(nombre); int index = 0; while ((caracter = fgetc(nombres)) != EOF) { if (caracter != '\n') { nombre[index] = caracter; index++; } else { vectoristoNombres[i] = nombre; break; } } } for (int i = 0; i < 10; ++i) { printf("%s\n", vectoristoNombres[i]); } fclose(nombres); return 0; }
TXT文件内容
data secondData yesMoreData moreData
问题根源
- 局部栈内存共享:循环内定义的
char nombre[20]是栈上的局部变量,每次循环都会复用同一块内存地址。将vectoristoNombres[i] = nombre赋值后,所有数组元素实际指向同一块内存,后续修改这块内存(比如初始化、写入新内容)会直接覆盖所有元素的内容。 - 初始化函数误操作共享内存:每次调用
inicializarNombre(nombre)时,修改的就是这块所有数组元素都指向的内存,导致所有元素被清空。 - 未处理文件提前结束:TXT仅4条数据,但循环强制跑10次,后续循环读取到EOF后,数组元素仍指向共享内存,内容混乱。
修复方案
采用二维数组存储字符串,让每个元素拥有独立内存空间,同时简化读取逻辑:
修复后的代码
#include <stdio.h> #include <string.h> void inicializarNombre (char* nombre) { memset(nombre, '\0', 20); // 用memset简化初始化逻辑 } int main() { setbuf(stdout, 0); char vectoristoNombres[10][20]; // 改为二维数组,每个元素占独立的20字节内存 // char *vectoristoApellidos[10][20]; 原变量未使用,可注释或删除 FILE *nombres; nombres = fopen("nombres.txt" , "r"); if(nombres == NULL) { perror("Error opening file"); return(-1); } // 初始化数组所有元素为空字符串 for (int i = 0; i < 10; ++i) { inicializarNombre(vectoristoNombres[i]); } int count = 0; // 记录实际读取的行数 while (count < 10) { // 用fgets直接读取一行,简化逐字符处理逻辑 if (fgets(vectoristoNombres[count], 20, nombres) == NULL) { break; // 文件读取完毕或出错,退出循环 } // 移除fgets读取到的换行符 vectoristoNombres[count][strcspn(vectoristoNombres[count], "\n")] = '\0'; count++; } // 打印所有数组元素 for (int i = 0; i < 10; ++i) { if (strlen(vectoristoNombres[i]) > 0) { printf("%s\n", vectoristoNombres[i]); } else { printf("(空)\n"); } } fclose(nombres); return 0; }
关键修改点
- 把
char *vectoristoNombres[10]改为char vectoristoNombres[10][20]:每个元素拥有独立内存,避免互相覆盖。 - 使用
fgets替代逐字符读取:简化代码,减少手动处理EOF和换行符的错误。 - 添加
count变量:记录实际读取行数,避免强制循环10次导致的无效操作。 - 用
strcspn清除换行符:解决fgets会读取换行符的问题。
可选方案(堆内存分配)
如果需要更灵活的内存管理(比如字符串长度不固定),可以用malloc分配堆内存:
// 仅修改核心部分 char *vectoristoNombres[10]; // ... int count = 0; while (count < 10) { char temp[20]; inicializarNombre(temp); if (fgets(temp, 20, nombres) == NULL) { break; } temp[strcspn(temp, "\n")] = '\0'; // 分配足够内存存储字符串并复制内容 vectoristoNombres[count] = malloc(strlen(temp) + 1); if (vectoristoNombres[count] != NULL) { strcpy(vectoristoNombres[count], temp); } count++; } // 记得最后释放堆内存 for (int i = 0; i < count; ++i) { free(vectoristoNombres[i]); }
内容的提问来源于stack exchange,提问作者Ricardo Roel
相关产品推荐
相关产品推荐

