编程新手求助:如何读取文本文件并使用malloc分配二维字符串数组内存
解决文本文件读取到动态分配二维字符串数组的问题
嘿,我来帮你一步步搞定这个问题!首先得指出你代码里的几个核心问题,然后给你两种符合需求的实现方案,再详细解释每个步骤的逻辑。
你的原代码存在的问题
- 类型不匹配:你用了
int**来定义数组,但我们要存储的是字符串(字符序列),应该用char**(或更复杂的char***,如果要拆分命令和参数)。int类型是用来存整数的,和字符完全不兼容,这就是你只能单个字符赋值的主要原因。 - malloc大小计算错误:
- 第一行分配行指针时,
row*sizeof(array)是错的——sizeof(array)是指针本身的大小(通常4或8字节),但你需要的是每个元素是char*(指向每行的指针),所以应该写成row * sizeof(char*)。 - 循环里分配每行空间时,
col*sizeof(array)也错了,每行是char数组,每个元素是单个字符,所以应该是col * sizeof(char)。
- 第一行分配行指针时,
- 缺少内存泄漏处理:如果某一行的内存分配失败,你没有释放之前已经分配的内存,会造成内存泄漏。
方案1:存储每行完整的字符串(array[i]是第i行的内容)
如果你只是想把每行完整内容存到数组里,array[i]直接对应第i行的字符串,array[i][0]是该行的第一个字符,这种实现比较简单:
#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_ROWS 100 #define MAX_LINE_LEN 256 int main() { // 1. 分配行指针数组:每个元素是指向一行字符串的指针 char **array = malloc(MAX_ROWS * sizeof(char*)); if (!array) { perror("Failed to allocate row pointers"); exit(EXIT_FAILURE); } // 2. 为每行分配字符数组空间 for (int i = 0; i < MAX_ROWS; i++) { array[i] = malloc(MAX_LINE_LEN * sizeof(char)); if (!array[i]) { perror("Failed to allocate line buffer"); // 内存泄漏处理:释放之前分配的所有行 for (int j = 0; j < i; j++) { free(array[j]); } free(array); exit(EXIT_FAILURE); } // 初始化每行,避免垃圾值干扰 memset(array[i], 0, MAX_LINE_LEN); } // 3. 读取文件内容到数组 FILE *fp = fopen("commands.txt", "r"); if (!fp) { perror("Failed to open file"); // 释放内存后退出 for (int i = 0; i < MAX_ROWS; i++) { free(array[i]); } free(array); exit(EXIT_FAILURE); } int current_row = 0; char line[MAX_LINE_LEN]; while (fgets(line, MAX_LINE_LEN, fp) != NULL && current_row < MAX_ROWS) { // 去掉换行符,避免每行末尾带\n line[strcspn(line, "\n")] = '\0'; // 把行内容复制到数组对应位置 strncpy(array[current_row], line, MAX_LINE_LEN - 1); current_row++; } fclose(fp); // 测试输出 for (int i = 0; i < current_row; i++) { printf("Line %d: %s\n", i, array[i]); } // 4. 释放内存(必须做,避免泄漏) for (int i = 0; i < MAX_ROWS; i++) { free(array[i]); } free(array); return 0; }
方案2:拆分每行成命令和参数(array[i][j]是第i行的第j个参数)
如果你的需求是直接访问每行的命令和每个参数(比如array[0][0]是第一行的命令,array[0][1]是第一个参数),那需要用三维指针char***,因为每个行本身又是一个字符串数组:
#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAX_ROWS 100 #define MAX_LINE_LEN 256 #define MAX_ARGS_PER_LINE 10 // 对应command + 9个参数的最大情况 int main() { // 1. 分配行指针数组:每个元素是指向参数数组的指针 char ***array = malloc(MAX_ROWS * sizeof(char**)); if (!array) { perror("Failed to allocate row pointers"); exit(EXIT_FAILURE); } // 2. 为每行分配参数指针数组 for (int i = 0; i < MAX_ROWS; i++) { array[i] = malloc(MAX_ARGS_PER_LINE * sizeof(char*)); if (!array[i]) { perror("Failed to allocate argument pointers"); // 释放已分配的内存 for (int j = 0; j < i; j++) { for (int k = 0; k < MAX_ARGS_PER_LINE; k++) { if (array[j][k]) free(array[j][k]); } free(array[j]); } free(array); exit(EXIT_FAILURE); } // 初始化每个参数指针为NULL,方便后续判断是否有值 for (int j = 0; j < MAX_ARGS_PER_LINE; j++) { array[i][j] = NULL; } } // 3. 读取文件并拆分每行的命令和参数 FILE *fp = fopen("commands.txt", "r"); if (!fp) { perror("Failed to open file"); // 释放内存后退出 for (int i = 0; i < MAX_ROWS; i++) { for (int j = 0; j < MAX_ARGS_PER_LINE; j++) { if (array[i][j]) free(array[i][j]); } free(array[i]); } free(array); exit(EXIT_FAILURE); } int current_row = 0; char line[MAX_LINE_LEN]; while (fgets(line, MAX_LINE_LEN, fp) != NULL && current_row < MAX_ROWS) { line[strcspn(line, "\n")] = '\0'; // 用strtok拆分字符串,分隔符是空格 char *token = strtok(line, " "); int arg_idx = 0; while (token != NULL && arg_idx < MAX_ARGS_PER_LINE) { // 为每个参数分配内存(长度是字符串长度+1,存终止符\0) array[current_row][arg_idx] = malloc(strlen(token) + 1); if (!array[current_row][arg_idx]) { perror("Failed to allocate argument memory"); // 释放当前行已分配的参数 for (int k = 0; k < arg_idx; k++) { free(array[current_row][k]); } // 释放所有已分配内存 for (int i = 0; i <= current_row; i++) { for (int j = 0; j < MAX_ARGS_PER_LINE; j++) { if (array[i][j]) free(array[i][j]); } free(array[i]); } free(array); fclose(fp); exit(EXIT_FAILURE); } // 复制参数内容 strcpy(array[current_row][arg_idx], token); token = strtok(NULL, " "); arg_idx++; } current_row++; } fclose(fp); // 测试输出 for (int i = 0; i < current_row; i++) { printf("Line %d:\n", i); for (int j = 0; j < MAX_ARGS_PER_LINE && array[i][j] != NULL; j++) { printf(" %d: %s\n", j, array[i][j]); } } // 4. 释放内存 for (int i = 0; i < MAX_ROWS; i++) { for (int j = 0; j < MAX_ARGS_PER_LINE; j++) { if (array[i][j]) free(array[i][j]); } free(array[i]); } free(array); return 0; }
关键知识点解释
- 指针类型的选择:
- 如果你要存每行完整字符串,用
char**:第一层指针指向行的数组,第二层指针指向每行的字符数组。 - 如果你要拆分命令和参数,用
char***:第一层指针指向行的数组,第二层指针指向每行的参数数组,第三层指针指向具体的命令/参数字符串。
- 如果你要存每行完整字符串,用
- malloc的大小计算:
- 分配指针数组时,用
数量 * sizeof(指针类型),比如MAX_ROWS * sizeof(char*)。 - 分配字符数组时,用
长度 * sizeof(char),因为每个字符占1字节。 - 分配单个字符串时,用
strlen(字符串) + 1,加1是为了存储字符串终止符\0。
- 分配指针数组时,用
- 内存泄漏处理:任何时候malloc失败,都要把之前已经分配的内存全部释放,避免内存泄漏。
内容的提问来源于stack exchange,提问作者Daniel
相关产品推荐
相关产品推荐

