ESP32中C语言读取文件存二维数组,循环内外打印结果不一致
问题描述
在ESP32上通过C语言读取文件,尝试将文件中的字符按行存入二维数组。读取过程中在while循环内打印数组结果符合预期,但循环结束后打印数组出现乱码,仅每行末尾的数值正确,怀疑是内存分配问题,需定位并解决。
输入文件格式
#####B# ##### # #### # #### ## ## A######
循环内打印输出
[ 35 ][ 35 ][ 35 ][ 35 ][ 35 ][ 66 ][ 35 ] [ 35 ][ 35 ][ 35 ][ 35 ][ 35 ][ 32 ][ 35 ] [ 35 ][ 35 ][ 35 ][ 35 ][ 32 ][ 32 ][ 35 ] [ 35 ][ 35 ][ 35 ][ 35 ][ 32 ][ 35 ][ 35 ] [ 32 ][ 32 ][ 32 ][ 32 ][ 32 ][ 35 ][ 35 ] [ 65 ][ 35 ][ 35 ][ 35 ][ 35 ][ 35 ][ 35 ]
循环外打印输出
[ 1073424916 ][ 1073424916 ][ -1688599997 ][ -961455512 ][ -724372320 ][ -1275106563 ][ 35 ] [ 1073424916 ][ 1073424916 ][ -582559471 ][ -930149664 ][ 1510548983 ][ 1629549381 ][ 35 ] [ 1073424916 ][ 1073424916 ][ 479218642 ][ 2091780050 ][ 1271856269 ][ -564334767 ][ 35 ] [ 1073424916 ][ 1073424916 ][ -1348850970 ][ -972490428 ][ 1253901817 ][ 1424904752 ][ 35 ] [ 1073424916 ][ 1073424916 ][ 731742849 ][ 1319147750 ][ -1130554592 ][ -2097033641 ][ 35 ] [ 1073424916 ][ 1073424916 ][ 1671172429 ][ -1512979784 ][ -804137078 ][ -153094939 ][ 35 ]
原代码
static const char* TAG = "Filesystem"; FILE* f = fopen("/storage/test.txt", "r"); if (f == NULL) { ESP_LOGE(TAG, "Failed to open file for reading"); return; } int height = 0; int width = 0; int currentChar; int** walls = (int**)malloc((height + 1) * sizeof(int*)); while ((currentChar = fgetc(f)) != EOF) { if (currentChar == '\n') { width = 0; height++; printf("\n"); } else if (currentChar != '\r') { walls = (int**)realloc(walls, (height + 1) * sizeof(int*)); walls[height] = (int*)malloc((width + 1) * sizeof(int)); walls[height][width] = currentChar; printf("%s %d %s", "[", walls[height][width], "]"); width++; } } printf("\n"); for (int i = 0; i < 6; i++) { for (int j = 0; j < 7; j++) { printf("%s %d %s", "[", walls[i][j], "]"); } printf("\n"); } for (int i = 0; i <= height; i++) { free(walls[i]); } free(walls); fclose(f);
问题定位
核心错误是每行内存分配逻辑错误:
- 读取每个字符时,都对当前行执行
malloc((width + 1) * sizeof(int)),这会丢弃当前行之前分配的内存,仅保留本次分配的新内存块。 - 新内存块中只有当前
width位置的字符被赋值,其余位置都是未初始化的垃圾值。 - 循环内仅打印刚赋值的当前位置,所以结果正确;循环外访问该行其他位置时,读取的是未初始化的垃圾数据,仅最后一个字符(最后一次分配的位置)正确。
- 同时存在内存泄漏:每次重新malloc当前行时,旧的内存块未被释放。
解决方案
修改内存分配逻辑,对当前行使用realloc进行扩容,而非每次重新malloc,保留之前已读取的字符数据。同时优化行指针的分配时机,避免不必要的realloc操作。
修正后代码
static const char* TAG = "Filesystem"; FILE* f = fopen("/storage/test.txt", "r"); if (f == NULL) { ESP_LOGE(TAG, "Failed to open file for reading"); return; } int height = 0; int width = 0; int currentChar; // 记录每行的宽度,避免打印时越界 int* row_widths = NULL; int** walls = NULL; // 初始化第一行的指针和宽度记录 walls = (int**)malloc(sizeof(int*)); row_widths = (int*)malloc(sizeof(int)); walls[height] = NULL; row_widths[height] = 0; while ((currentChar = fgetc(f)) != EOF) { if (currentChar == '\n') { // 保存当前行的宽度 row_widths[height] = width; width = 0; height++; // 为下一行分配指针和宽度记录空间 walls = (int**)realloc(walls, (height + 1) * sizeof(int*)); row_widths = (int*)realloc(row_widths, (height + 1) * sizeof(int)); walls[height] = NULL; row_widths[height] = 0; printf("\n"); } else if (currentChar != '\r') { // 对当前行的内存进行扩容,新增一个int的空间 walls[height] = (int*)realloc(walls[height], (width + 1) * sizeof(int)); walls[height][width] = currentChar; printf("[ %d ]", walls[height][width]); width++; } } // 保存最后一行的宽度(如果文件末尾没有换行) row_widths[height] = width; printf("\n"); // 打印二维数组,根据每行实际宽度遍历 for (int i = 0; i <= height; i++) { for (int j = 0; j < row_widths[i]; j++) { printf("[ %d ]", walls[i][j]); } printf("\n"); } // 释放内存 free(row_widths); for (int i = 0; i <= height; i++) { free(walls[i]); } free(walls); fclose(f);
关键修改点
- 使用
realloc对当前行内存进行扩容,保留已读取的字符数据,避免内存丢失和泄漏。 - 新增
row_widths数组记录每行的实际宽度,打印时按需遍历,避免越界访问。 - 仅在换行时扩容行指针数组,减少不必要的内存操作。
内容的提问来源于stack exchange,提问作者MajorAnonymous
相关产品推荐
相关产品推荐

