C语言中动态数组结构体指针的函数传递问题求助
问题分析与代码修复
核心问题总结
你的代码出现乱码和未定义行为的主要原因有以下几点:
- 结构体
array使用了不必要的三级指针char*** ptr,且错误返回局部变量地址导致野指针 print_array函数错误引用局部变量t1,而非结构体中的指针count_lines函数的循环条件和读取逻辑存在问题,且与read_array的读取方式不匹配- 重复调用
count_lines导致文件指针操作混乱
分步修复说明
1. 修正结构体array的指针类型
将char*** ptr改为char** ptr,char**已足够表示指向字符串数组的指针,三级指针完全多余,还会引入野指针风险。
2. 修复read_array的指针传递
read_array中t1是堆分配的数组,直接将t1赋值给arr.ptr即可,无需取地址。堆内存不会随函数返回销毁,main函数能安全访问数组内容。
3. 修复print_array的输出逻辑
通过arr.ptr[i]访问数组每一行,替换原代码中不存在的局部变量t1,同时循环使用变量i而非固定值1。
4. 修正count_lines函数逻辑
- 用
fscanf的返回值判断是否成功读取一行的4个字段,替换错误的!feof(file)循环条件 - 修正
fscanf参数:数组名temp1本身就是指针,无需加& - 保留
rewind确保文件指针回到开头,供后续读取使用
5. 简化main函数流程
移除main中多余的count_lines调用,避免重复操作文件指针,read_array内部已完成行数统计。
修复后的完整代码
#define _CRT_SECURE_NO_WARNINGS #include <stdlib.h> #include <stdio.h> #include <string.h> struct vehicle { char brand[40]; char model[40]; int production_year; float engine_capacity; }; // 修正结构体指针类型为char** struct array { char** ptr; int size; }; int count_lines(FILE* file) { char temp1[50]; char temp2[50]; int production_year; float engine_capacity; int line_count = 0; // 通过fscanf返回值判断是否成功读取一行的4个字段 while (fscanf(file, "%s %s %d %f", temp1, temp2, &production_year, &engine_capacity) == 4) { line_count++; } rewind(file); return line_count; } struct array read_array(FILE* file) { struct array arr; int n = count_lines(file); // 分配字符串数组内存 char** t1 = malloc(n * sizeof(char*)); if (!t1) { // 添加内存分配失败检查 arr.ptr = NULL; arr.size = 0; return arr; } for (int i = 0; i < n; i++) { t1[i] = malloc(50 * sizeof(char)); if (!t1[i]) { // 检查每行内存分配 // 分配失败时释放已分配的空间 for (int j = 0; j < i; j++) { free(t1[j]); } free(t1); arr.ptr = NULL; arr.size = 0; return arr; } } int i = 0; while (i < n && fgets(t1[i], 50, file)) { // 移除fgets读取的换行符(可选) t1[i][strcspn(t1[i], "\n")] = '\0'; i++; } // 直接赋值堆指针,而非局部变量地址 arr.ptr = t1; arr.size = n; return arr; } void print_array(struct array arr) { if (!arr.ptr) { printf("数组为空或内存分配失败\n"); return; } printf("数组内容:\n"); for (int i = 0; i < arr.size; i++) { printf("%s\n", arr.ptr[i]); } } // 添加内存释放函数,避免内存泄漏 void free_array(struct array arr) { if (arr.ptr) { for (int i = 0; i < arr.size; i++) { free(arr.ptr[i]); } free(arr.ptr); } } int main() { FILE* stream_read = fopen("dane.txt", "r"); if (!stream_read) { printf("无法打开文件'dane.txt'\n"); return 1; } printf("文件'dane.txt'已成功打开\n"); struct array my_array = read_array(stream_read); print_array(my_array); if (fclose(stream_read)) { printf("文件'dane.txt'未能关闭\n"); } // 释放动态分配的内存 free_array(my_array); getchar(); return 0; }
关键问题解释
- 野指针问题:原代码中
arr.ptr = &t1,t1是read_array的局部变量,函数返回后该内存被回收,arr.ptr变为野指针,访问会导致乱码或崩溃。修复后直接赋值堆分配的t1,堆内存不会随函数返回销毁,可安全访问。 - 读取逻辑一致性:
count_lines和read_array的读取逻辑匹配,避免rewind后fgets读取到fscanf遗留的换行符导致内容错误。 - 内存安全:添加内存分配失败检查和
free_array函数,避免内存泄漏和程序崩溃。
内容的提问来源于stack exchange,提问作者Grzyb2134
相关产品推荐
相关产品推荐

