You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 14:10:35