C语言引用传递参数动态初始化二维字符串数组相关问题求解
问题解答
1. 为什么不能在while循环内释放line变量的存储空间?
getline函数的工作逻辑是:接收的line指针如果为NULL,会自动分配内存;如果line指向的已分配内存长度不足以存储当前行,会自动调用realloc扩容。如果在循环内释放line后没有手动将line重置为NULL、len重置为0,下一轮循环getline会把已经释放的野指针当做有效内存地址访问,直接触发内存访问错误,导致后续行读取失败。
如果一定要在循环内释放line,需要每次释放后执行line = NULL; len = 0;,但这会增加不必要的内存分配释放开销,不如循环结束后统一释放效率高。
2. 如何实现main函数中通过array[0]、array[1]的方式访问行数据?
你要存储的是「字符串指针的数组」,因此main函数中的array变量需要声明为char**类型(即指向char指针的指针),对应read_lines的第二个入参需要是三级指针char*** lines,用来修改外部char**类型的array的指向。
3. 当前写法触发段错误的原因
有四处核心错误:
- 指针层级错误:你要修改外部的指针数组地址,
read_lines的第二个参数需要是char***,当前你用char**的写法会导致内存写入越界。 - 扩容逻辑错误:每次扩容时的大小计算错误,当已经读取了
*num_lines行、要存入新的一行时,需要分配(*num_lines + 1)个char*的空间,当前代码扩容时大小为(*num_lines)*sizeof(char*),少分配了一个指针的存储空间。 - 赋值逻辑错误:你当前的
*(lines + (*num_lines))是对三级指针lines直接偏移,访问的是不属于你的内存地址,正确写法是先解引用拿到指针数组首地址*lines,再偏移取值(*lines)[*num_lines]。 - main中变量类型错误:
array声明为char*类型,自然无法通过下标访问到第二个字符串指针,array[1]实际取的是第一个字符串的第二个字符,和你的预期完全不符。
修正后代码
#define _GNU_SOURCE #include <stdio.h> #include <stdlib.h> #include <string.h> // 第二个参数改为三级指针,用来修改外部的char**变量 void read_lines(FILE *fp, char*** lines, int *num_lines) { ssize_t read; char * line = NULL; size_t len = 0; *num_lines = 0; *lines = NULL; // 初始化指针数组为空 while ((read = getline(&line, &len, fp)) != -1) { // 扩容:每次多分配一个char*的空间 *lines = realloc(*lines, (*num_lines + 1) * sizeof(char *)); if (*lines == NULL) { perror("realloc failed"); exit(EXIT_FAILURE); } // 分配当前行的存储空间,长度+1是为了存储字符串结束符'\0' (*lines)[*num_lines] = malloc((read + 1) * sizeof(char)); if ((*lines)[*num_lines] == NULL) { perror("malloc failed"); exit(EXIT_FAILURE); } // 拷贝字符串 strcpy((*lines)[*num_lines], line); printf("Retrieved line of length %zu:\n", read); printf("%s", line); // getline已经包含换行符,不需要额外加\n (*num_lines)++; } free(line); // 循环结束统一释放getline的缓存 } int main(void) { FILE * fp; char **array; // 改为char**类型,存储字符串指针数组 int num_lines; int i; fp = fopen("file.txt", "r"); if (fp == NULL) { perror("fopen failed"); exit(EXIT_FAILURE); } read_lines(fp, &array, &num_lines); fclose(fp); printf("\nAfter returning, read %d lines:\n", num_lines); // 按array[0]、array[1]的方式访问 for (i = 0; i < num_lines; i++) { printf("Line %d: %s", i, array[i]); // 用完记得释放每行的内存 free(array[i]); } // 释放指针数组本身的内存 free(array); return 0; }
相关C语言核心概念说明
- 多级指针传递:如果需要在函数内修改外部的
Type类型变量,需要给函数传入Type*类型的参数。你要修改的外部变量是char**类型的指针数组,因此入参需要是char***。 - 动态数组扩容:每次扩容的大小需要对应实际要存储的元素个数,避免少分配内存导致越界。
- getline的使用:传入的line指针如果非空,会默认指向已分配的有效内存,不要随意提前释放。
内容的提问来源于stack exchange,提问作者user3138594
相关产品推荐
相关产品推荐

