You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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;
}

关键问题解释

  1. 野指针问题:原代码中arr.ptr = &t1,t1是read_array的局部变量,函数返回后该内存被回收,arr.ptr变为野指针,访问会导致乱码或崩溃。修复后直接赋值堆分配的t1,堆内存不会随函数返回销毁,可安全访问。
  2. 读取逻辑一致性:count_lines和read_array的读取逻辑匹配,避免rewind后fgets读取到fscanf遗留的换行符导致内容错误。
  3. 内存安全:添加内存分配失败检查和free_array函数,避免内存泄漏和程序崩溃。

内容的提问来源于stack exchange,提问作者Grzyb2134

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.27 12:15:41