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��,显然数组没有被正确填充。
问题分析
你的代码主要有几个关键逻辑错误,导致数组填充失败并出现乱码:
行数统计错误:
你的示例文件每行结尾是$而不是\n,但第一个循环里用ch == '\n'来统计行数x,这会导致x始终为0,后续计算y的逻辑完全错误,数组的维度就不对了。内层
while(read)循环的逻辑错误:
外层嵌套了for (i)和for (j)循环,但内层的while(read)会一次性把整个文件读完,所以只有第一次i=0,j=0时会读取到字符,后续的i/j循环读取不到任何内容,数组的大部分位置都是未初始化的垃圾值,打印时自然出现乱码。列数
y的计算错误:
原代码中y = (count - x)/x,但count统计了所有非逗号的字符(包括每行结尾的$),所以count实际上是x * (每行有效字符数),count -x就是去掉所有$后的字符数,除以x得到的是每行的有效字符数,但因为之前x统计错误,这个值也不对。数组越界风险:
你手动写了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
相关产品推荐
相关产品推荐

