C语言从文件按块行生成动态二维数组报错求助
问题排查与修复建议
1. 内存分配核心错误点
二维字符串数组层级遗漏:多数崩溃源于只分配了外层指针数组,未给内层每个字符串指针分配内存,或未预留
\0的存储空间。比如:// 错误示例:内层字符串指针未初始化 char ***str_arr = malloc(3 * sizeof(char**)); for (int i=0; i<3; i++) { str_arr[i] = malloc(3 * sizeof(char*)); // 漏了给str_arr[i][j]分配存储字符串的内存 }修复:读取每行前先获取字符串长度,分配
len + 1字节内存(保留终止符位置)。未检查malloc返回值:内存分配失败会返回
NULL,后续直接操作会触发野指针崩溃。必须添加校验:char ***str_arr = malloc(3 * sizeof(char**)); if (!str_arr) { perror("malloc failed for str_arr"); exit(EXIT_FAILURE); }float数组大小匹配错误:若每块第4行对应一个float值,一维数组需分配3个元素的空间;若第4行含多个float,需按分割后的元素数动态分配,硬编码大小会导致越界或浪费。
2. 文件读取逻辑漏洞
空行判断未处理换行符:空行实际是
"\n"而非空字符串,直接用strlen(buf) == 0判断会失效。正确处理方式:char buf[256]; while (fgets(buf, sizeof(buf), fp)) { // 移除行尾的换行/回车符 buf[strcspn(buf, "\n\r")] = '\0'; if (strlen(buf) == 0) { // 块结束,切换到下一个块 block_idx++; line_in_block = 0; continue; } // 处理当前行 }块与行的边界未校验:未限制块数量(最多3块)和每块行数(最多4行),会导致数组越界。需添加边界检查:
if (block_idx >= 3) { fprintf(stderr, "文件块数量超过3个\n"); exit(EXIT_FAILURE); } if (line_in_block >= 4) { fprintf(stderr, "第%d块行数超过4行\n", block_idx+1); exit(EXIT_FAILURE); }float转换未做有效性检查:用
atof转换失败时会返回0.0,无法区分合法0值和无效输入。改用sscanf并校验返回值:float val; if (sscanf(buf, "%f", &val) != 1) { fprintf(stderr, "第%d块第4行不是合法float值\n", block_idx+1); exit(EXIT_FAILURE); } float_arr[block_idx] = val;
3. 修正后的完整代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #define BLOCK_COUNT 3 #define LINES_PER_BLOCK 4 #define MAX_LINE_LEN 256 int main() { FILE *fp = fopen("data.txt", "r"); if (!fp) { perror("fopen failed"); exit(EXIT_FAILURE); } // 分配3块×3行的二维字符串数组 char ***str_arr = malloc(BLOCK_COUNT * sizeof(char**)); if (!str_arr) { perror("malloc str_arr"); exit(1); } for (int i=0; i<BLOCK_COUNT; i++) { str_arr[i] = malloc(3 * sizeof(char*)); if (!str_arr[i]) { perror("malloc str_arr[i]"); exit(1); } for (int j=0; j<3; j++) str_arr[i][j] = NULL; // 初始化为NULL方便释放 } // 分配对应3块的float数组 float *float_arr = malloc(BLOCK_COUNT * sizeof(float)); if (!float_arr) { perror("malloc float_arr"); exit(1); } char buf[MAX_LINE_LEN]; int block_idx = 0; int line_in_block = 0; while (fgets(buf, MAX_LINE_LEN, fp)) { buf[strcspn(buf, "\n\r")] = '\0'; // 清理行尾符号 // 处理空行:仅允许在块结束后出现 if (strlen(buf) == 0) { if (line_in_block != LINES_PER_BLOCK) { fprintf(stderr, "第%d块未读完出现空行\n", block_idx+1); exit(1); } block_idx++; line_in_block = 0; continue; } // 边界校验 if (block_idx >= BLOCK_COUNT) { fprintf(stderr, "块数量超标\n"); exit(1); } if (line_in_block >= LINES_PER_BLOCK) { fprintf(stderr, "第%d块行数超标\n", block_idx+1); exit(1); } // 存储前3行字符串 if (line_in_block < 3) { size_t len = strlen(buf); str_arr[block_idx][line_in_block] = malloc(len + 1); if (!str_arr[block_idx][line_in_block]) { perror("malloc string"); exit(1); } strcpy(str_arr[block_idx][line_in_block], buf); } // 转换第4行float值 else { if (sscanf(buf, "%f", &float_arr[block_idx]) != 1) { fprintf(stderr, "第%d块第4行无效:%s\n", block_idx+1, buf); exit(1); } } line_in_block++; } // 校验文件是否完整 if (block_idx != BLOCK_COUNT-1 || line_in_block != LINES_PER_BLOCK) { fprintf(stderr, "文件块数量不足或最后一块未读完\n"); exit(1); } // 测试输出 for (int i=0; i<BLOCK_COUNT; i++) { printf("第%d块:\n", i+1); for (int j=0; j<3; j++) printf(" 第%d行:%s\n", j+1, str_arr[i][j]); printf(" 第4行float:%.2f\n", float_arr[i]); } // 释放内存 for (int i=0; i<BLOCK_COUNT; i++) { for (int j=0; j<3; j++) free(str_arr[i][j]); free(str_arr[i]); } free(str_arr); free(float_arr); fclose(fp); return 0; }
4. 测试用文件示例(data.txt)
apple banana cherry 1.23 dog cat bird 4.56 red green blue 7.89
内容的提问来源于stack exchange,提问作者slime
相关产品推荐
相关产品推荐

