C语言函数内动态分配二维数组后外部访问段错误问题分析
动态分配二维数组时传参导致段错误的原因与解决方法
问题描述
想在独立函数中为char类型二维数组(字符串数组)动态分配内存,主函数定义双指针res并传入alloc_arr函数,函数内用malloc完成内存分配并写入字符串,但退出函数后主函数访问res时出现段错误。原本以为主函数的res指针在函数结束后仍可使用,malloc返回的动态内存地址能正常访问,可只有让函数直接返回指针程序才能正常运行,int类型二维数组也遇到同样问题。需要明确第一种方式失效的原因,以及修复方法。
错误代码示例
#include <stdio.h> #include <string.h> #include <stdlib.h> int alloc_arr(char **res) { size_t i; res = (char **)malloc(200 * sizeof(char *)); if (res == NULL) return 0; i = 0; while (i < 200) { res[i] = (char *)malloc(100 * sizeof(char)); if (res[i] == NULL) return 0; i++; } strncpy(&res[0][0], "string", 100); printf("res[0] = %s\n", res[0]); return 1; } void free_arr(char **res) { int i = 0; for (; i < 200; i++) free(res[i]); free(res); } int main(void) { char **res; res = NULL; if (alloc_arr(res)) printf("res[0] = %s\n", res[0]); /* 此处触发段错误 */ else return 1; free(res); return 0; }
可行的返回指针方式示例
int **alloc_int(int **res) { size_t i; res = (int **)malloc(20 * sizeof(int *)); if (res == NULL) return NULL; i = 0; while (i < 20) { res[i] = (int *)malloc(10 * sizeof(int)); if (res[i] == NULL) return NULL; i++; } res[0][0] = 10; printf("res[0] = %d\n", res[0][0]); return res; } void free_int(int **res) { int i = 0; for (; i < 20; i++) free(res[i]); free(res); } int main(void) { int **res; res = NULL; if ((res = alloc_int(res)) != NULL) printf("res[0] = %d\n", res[0][0]); else return 1; free(res); return 0; }
失效原因
- C语言的函数参数传递是值传递:当把
char **res传入alloc_arr时,函数会创建一个res的副本。函数内给这个副本赋值malloc返回的地址,修改的只是副本,主函数里的原始res指针始终是NULL。主函数访问res[0]本质是访问NULL指针指向的内存,直接触发段错误。 - 返回指针的方式能正常运行,是因为函数把分配好的内存地址返回给了主函数的
res,让原始指针指向了正确的动态内存区域。
修复方法
要修改主函数中的原始指针,需要传递指针的指针(即char ***res),通过三级指针间接修改主函数里的二级指针值。
修正后的代码
#include <stdio.h> #include <string.h> #include <stdlib.h> int alloc_arr(char ***res) { size_t i; // 解引用三级指针,修改主函数中的原始二级指针 *res = (char **)malloc(200 * sizeof(char *)); if (*res == NULL) return 0; i = 0; while (i < 200) { (*res)[i] = (char *)malloc(100 * sizeof(char)); if ((*res)[i] == NULL) return 0; i++; } strncpy((*res)[0], "string", 100); printf("res[0] = %s\n", (*res)[0]); return 1; } void free_arr(char **res) { int i = 0; for (; i < 200; i++) free(res[i]); free(res); } int main(void) { char **res; res = NULL; // 传入res的地址,传递三级指针 if (alloc_arr(&res)) printf("res[0] = %s\n", res[0]); else return 1; free_arr(res); return 0; }
关键修改点
- 函数参数从
char **res改为char ***res,接收主函数中二级指针的地址。 - 函数内通过
*res访问并修改主函数的原始二级指针,让它指向malloc分配的内存。 - 主函数调用
alloc_arr时传入&res,传递二级指针的地址。
内容的提问来源于stack exchange,提问作者elo2cx
相关产品推荐
相关产品推荐

