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

C语言读取命令行传参文件存入二维数组时乱码问题求助

C语言读取CSV格式地图文件到二维数组时出现乱码问题

我需要用C语言读取通过命令行传入的CSV格式地图文件,将每个字符(忽略逗号)存储到二维数组中,之后修改数组并保存到新文件。

示例文件内容:

#,#,#,#,#,#,.,#,.,.,.$
#,.,#,.,.,#,.,#,#,#,#$
#,.,#,.,.,.,.,.,.,#,#$
#,.,#,.,.,#,#,#,#,#,#$
#,.,.,#,.,.,.,.,.,.,#$
#,.,.,.,#,.,#,#,.,.,#$
#,.,.,.,.,#,.,.,.,.,#$
#,.,.,.,.,#,.,.,.,.,#$
#,.,.,.,.,.,.,.,.,.,#$
#,#,#,#,#,#,#,#,#,.,#$

我的代码:

int main(int argc, char *argv[]) {
    int startX = 3;
    int startY = 3;
    int endX = 6;
    int endY = 6;
    int count = 0;
    int x = 0;
    int y = 0;
    int fd = open(argv[1], O_RDONLY);
    char ch;
    if (fd == -1) {
        mx_printerr("map does not exist\n");
        exit(-1);
    }
    int targetFile = open("path.txt", O_CREAT | O_EXCL | O_WRONLY, S_IWUSR | S_IRUSR);
    while (read(fd, &ch, 1)) {
        if (ch == '\n') {
            x++;
        }
        if (ch != ',') {
            count++;
        }
    }
    fd = open(argv[1], O_RDONLY);
    y = (count - x) / x;
    char **arr;
    arr = malloc(sizeof(char *) * x);
    for (int i = 0; i < x; i++)
        arr[i] = malloc(y);
    int tempX = 0, tempY = 0, tempCount = 0;
    char tempString[count - x];
    // 存在问题的循环
    for (int i = 0; i < 10; i++) {
        for (int j = 0; j < 11; j++) {
            while (read(fd, &ch, 1)) {
                if (ch != ',') {
                    arr[i][j] = ch;
                    // mx_printchar(arr[i][j]);
                }
            }
        }
    }
    for (int i = 0; i < 10; i++) {
        for (int j = 0; j < 11; j++) {
            mx_printchar(arr[i][j]);
        }
    }
    for (int i = 0; i < x; i++)
        free(arr[i]);
    free(arr);
    close(fd);
    close(targetFile);
    exit(0);
}

问题现象:

运行后打印数组内容出现乱码,比如� ��pp �� ��8��,显然数组没有被正确填充。


问题分析

你的代码主要有几个关键逻辑错误,导致数组填充失败并出现乱码:

  1. 行数统计错误:
    你的示例文件每行结尾是$而不是\n,但第一个循环里用ch == '\n'来统计行数x,这会导致x始终为0,后续计算y的逻辑完全错误,数组的维度就不对了。

  2. 内层while(read)循环的逻辑错误:
    外层嵌套了for (i)和for (j)循环,但内层的while(read)会一次性把整个文件读完,所以只有第一次i=0,j=0时会读取到字符,后续的i/j循环读取不到任何内容,数组的大部分位置都是未初始化的垃圾值,打印时自然出现乱码。

  3. 列数y的计算错误:
    原代码中y = (count - x)/x,但count统计了所有非逗号的字符(包括每行结尾的$),所以count实际上是x * (每行有效字符数),count -x就是去掉所有$后的字符数,除以x得到的是每行的有效字符数,但因为之前x统计错误,这个值也不对。

  4. 数组越界风险:
    你手动写了for (i=0; i<10)和for(j=0; j<11),但如果文件行数或列数变化,这种硬编码会导致数组越界或者读取不完整。


修正后的解决方案

我们可以重新梳理逻辑,先正确统计文件的行数和每行的列数,然后逐字符读取并填充数组:

#include <fcntl.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdio.h>

// 假设你的mx_printerr是类似这样的函数,如果不是可以替换成perror或者自定义打印
void mx_printerr(const char *msg) {
    write(2, msg, __builtin_strlen(msg));
}

void mx_printchar(char c) {
    write(1, &c, 1);
}

int main(int argc, char *argv[]) {
    if (argc < 2) {
        mx_printerr("Please provide a map file path\n");
        exit(1);
    }

    int fd = open(argv[1], O_RDONLY);
    char ch;
    if (fd == -1) {
        mx_printerr("map does not exist\n");
        exit(-1);
    }

    // 第一步:统计行数x和每行的列数y(忽略逗号,不包含结尾的$)
    int x = 0;
    int y = 0;
    int current_line_length = 0;
    while (read(fd, &ch, 1)) {
        if (ch == ',') {
            continue; // 跳过逗号
        }
        if (ch == '$') {
            x++; // 行数加1
            if (y == 0) {
                y = current_line_length; // 记录第一行的列数,假设所有行长度一致
            }
            current_line_length = 0;
        } else {
            current_line_length++;
        }
    }

    // 重新打开文件,回到开头
    close(fd);
    fd = open(argv[1], O_RDONLY);
    if (fd == -1) {
        mx_printerr("Failed to reopen map file\n");
        exit(-1);
    }

    // 第二步:分配二维数组内存
    char **arr = malloc(sizeof(char *) * x);
    if (!arr) {
        mx_printerr("Memory allocation failed\n");
        close(fd);
        exit(-1);
    }
    for (int i = 0; i < x; i++) {
        arr[i] = malloc(y);
        if (!arr[i]) {
            mx_printerr("Memory allocation failed\n");
            // 释放已分配的内存
            for (int k = 0; k < i; k++) {
                free(arr[k]);
            }
            free(arr);
            close(fd);
            exit(-1);
        }
    }

    // 第三步:填充二维数组
    int current_x = 0;
    int current_y = 0;
    while (read(fd, &ch, 1)) {
        if (ch == ',') {
            continue;
        }
        if (ch == '$') {
            current_x++; // 切换到下一行
            current_y = 0;
            continue;
        }
        // 填充当前位置
        if (current_x < x && current_y < y) {
            arr[current_x][current_y] = ch;
            current_y++;
        }
    }

    // 测试打印数组
    for (int i = 0; i < x; i++) {
        for (int j = 0; j < y; j++) {
            mx_printchar(arr[i][j]);
        }
        mx_printchar('\n'); // 换行方便查看
    }

    // 后续可以在这里修改数组内容,然后写入到目标文件
    int targetFile = open("path.txt", O_CREAT | O_TRUNC | O_WRONLY, S_IWUSR | S_IRUSR);
    if (targetFile != -1) {
        for (int i = 0; i < x; i++) {
            for (int j = 0; j < y; j++) {
                write(targetFile, &arr[i][j], 1);
                if (j != y - 1) {
                    write(targetFile, ",", 1); // 写入逗号分隔
                }
            }
            write(targetFile, "$\n", 2); // 每行结尾加$和换行
        }
        close(targetFile);
    } else {
        mx_printerr("Failed to create target file\n");
    }

    // 释放内存
    for (int i = 0; i < x; i++) {
        free(arr[i]);
    }
    free(arr);
    close(fd);
    exit(0);
}

关键改进点:

  • 正确统计维度:通过识别$来统计行数,同时记录每行的有效字符数(忽略逗号)。
  • 逐字符填充数组:用单个while(read)循环配合current_x和current_y指针,逐个填充数组的每个位置,避免了嵌套循环的逻辑错误。
  • 内存安全:添加了内存分配失败的处理,避免内存泄漏。
  • 可扩展性:不再硬编码行数和列数,适配不同大小的地图文件。
  • 写入目标文件:补充了将修改后的数组写回CSV格式文件的逻辑,保持原文件的格式。

内容的提问来源于stack exchange,提问作者Karyna

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.07 13:12:48