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

C语言结构体字段无法打印?文件读写指针问题求助

结构体含指针字段的文件读写问题解决

我编写了用于练习的program.c代码,定义了包含int字段和char*字段的Data结构体,创建3个结构体实例并写入数据文件后程序运行正常。但编写仅用于读取该数据文件的program2.c时,程序编译通过却要么只能打印文件指针位置、无法输出结构体字段,调整代码后又仅能打印num字段,str字段显示为NULL。以下是问题代码及解决方法:

原问题代码

program.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

int main(void)
{
    typedef struct{
        int num;
        char* str;
    }Data;

    // 创建数据文件
    FILE* fptr = fopen("stuff.dat", "wb");

    // 声明3个Data结构体和一个Data结构体数组
    Data data1, data2, data3, dataf[3];

    // 初始化每个Data结构体的字段值
    data1.num = 5;
    data1.str = malloc(100);
    strcpy(data1.str, "Scott Pilgrim");
    data1.str = (char*) realloc(data1.str, strlen(data1.str) + 1);
    data2.num = 7;
    data2.str = malloc(100);
    strcpy(data2.str, "Dave Patel");
    data2.str = (char*) realloc(data2.str, strlen(data2.str) + 1);
    data3.num = 67;
    data3.str = malloc(100);
    strcpy(data3.str, "Matthew Skinner red riding hood");
    data3.str = (char*) realloc(data3.str, strlen(data3.str) + 1);
    
    // 如果文件指针不为空,将数据结构体写入"data.dat"文件并关闭文件
    if(fptr != NULL){
        fwrite(&data1, sizeof(data1), 1, fptr);
        fwrite(&data2, sizeof(data2), 1, fptr);
        fwrite(&data3, sizeof(data3), 1, fptr);
        printf("%ld\n", ftell(fptr));
        fclose(fptr);
    }

    // 打开数据文件用于读取
    fptr = fopen("stuff.dat", "rb");

    // 如果文件指针不为空,将数据文件中的数据读取到Data结构体数组中,并将每个结构体的字段打印到屏幕上
    if (fptr != NULL){
        for (int i = 0; i < 3; i++){
            fread((dataf+i), sizeof(data1), 1, fptr);
            printf("%d: %s", dataf[i].num, dataf[i].str);
            if (i != 2){
                printf(", ");
            }
            // printf("%d\n", feof(fptr)); - 忽略此行,我之前在验证一些内容
        }
        // printf("\n");
        // printf("%ld\n", ftell(fptr));
        // fseek(fptr, 1*sizeof(data1), SEEK_SET);
        // printf("%ld\n", ftell(fptr)); 忽略此行,我之前在测试一些内容
        fclose(fptr);
        
    }
    
    // 释放为Data结构体的字符串字段分配的所有内存
    free(dataf[0].str);
    free(dataf[1].str);
    free(dataf[2].str);
    free(data1.str);
    free(data2.str);
    free(data3.str);
    return 0;
}

program2.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>

typedef struct{
    int num;
    char* str;
}Data;

int main(void)
{
    // 打开数据文件用于读取
    FILE* fp = fopen("stuff.dat", "rb");
    
    // 分配内存用于存储Data类型结构体
    Data* dataf = malloc(sizeof(Data));
    // dataf.str = malloc(100);
    // char s[100];
    if (fp != NULL){
        // printf("%ld\n", ftell(fp)); 此行用于检查指针位置,忽略
        // 将指针移动到写入文件的最后一个数据的位置
        fseek(fp, 2*sizeof(dataf), SEEK_SET);
        // 打印指针位置
        printf("%ld\n", ftell(fp));

        // 将数据读取到dataf结构体中
        fread(dataf, sizeof(Data), 1, fp);
        // 打印指针位置
        printf("%ld\n", ftell(fp));
        
      
        // (*dataf).str = (char*) malloc((strlen((*dataf).str) + 1)); 忽略此行

        // 将dataf的字段打印到屏幕
        printf("%d: %s\n", (*dataf).num, (*dataf).str);

        fclose(fp);
    }
    return 0;
}

问题根源

直接用fwrite写入整个结构体时,char* str字段存储的是当前进程内的内存地址,而非字符串实际内容。这个地址仅在program.c运行时有效,当program2.c启动后,该内存地址已被释放或不属于当前进程,因此读取到的str是无效指针,表现为NULL或未定义行为。此外program2.c中fseek的偏移计算错误:sizeof(dataf)是指针的大小(如8字节),而非结构体Data的大小。

解决方法

需要修改读写逻辑,将字符串的长度+内容与数字字段分开写入/读取,确保读取时能正确分配内存并获取字符串内容。

1. 修正写入逻辑(更新program.c)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct {
    int num;
    char* str;
} Data;

// 封装写入单条数据的函数
void write_data(FILE* fp, const Data* d) {
    size_t str_len = strlen(d->str);
    // 先写数字字段
    fwrite(&d->num, sizeof(int), 1, fp);
    // 再写字符串长度(用于读取时分配内存)
    fwrite(&str_len, sizeof(size_t), 1, fp);
    // 最后写字符串内容
    fwrite(d->str, sizeof(char), str_len, fp);
}

int main(void) {
    FILE* fptr = fopen("stuff.dat", "wb");
    if (!fptr) {
        perror("打开文件失败");
        return 1;
    }

    // 初始化数据(用strdup简化内存分配+拷贝)
    Data data1 = {5, strdup("Scott Pilgrim")};
    Data data2 = {7, strdup("Dave Patel")};
    Data data3 = {67, strdup("Matthew Skinner red riding hood")};

    // 写入三条数据
    write_data(fptr, &data1);
    write_data(fptr, &data2);
    write_data(fptr, &data3);

    fclose(fptr);

    // 可选:测试读取验证写入正确性
    fptr = fopen("stuff.dat", "rb");
    if (fptr) {
        Data temp;
        // 封装读取单条数据的函数
        void read_data(FILE* fp, Data* d) {
            size_t str_len;
            fread(&d->num, sizeof(int), 1, fp);
            fread(&str_len, sizeof(size_t), 1, fp);
            // 分配足够内存存储字符串+结束符
            d->str = malloc(str_len + 1);
            fread(d->str, sizeof(char), str_len, fp);
            d->str[str_len] = '\0'; // 手动添加字符串结束符
        }

        for (int i = 0; i < 3; i++) {
            read_data(fptr, &temp);
            printf("%d: %s\n", temp.num, temp.str);
            free(temp.str);
        }
        fclose(fptr);
    }

    // 释放初始分配的内存
    free(data1.str);
    free(data2.str);
    free(data3.str);
    return 0;
}

2. 修正读取逻辑(更新program2.c)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct {
    int num;
    char* str;
} Data;

int main(void) {
    FILE* fp = fopen("stuff.dat", "rb");
    if (!fp) {
        perror("打开文件失败");
        return 1;
    }

    Data* dataf = malloc(sizeof(Data));
    if (!dataf) {
        perror("分配结构体内存失败");
        fclose(fp);
        return 1;
    }

    // 跳过前两条数据(定位到第三条)
    for (int i = 0; i < 2; i++) {
        int dummy_num;
        size_t dummy_len;
        fread(&dummy_num, sizeof(int), 1, fp);
        fread(&dummy_len, sizeof(size_t), 1, fp);
        fseek(fp, dummy_len, SEEK_CUR); // 跳过当前数据的字符串内容
    }

    // 读取第三条数据
    size_t str_len;
    fread(&dataf->num, sizeof(int), 1, fp);
    fread(&str_len, sizeof(size_t), 1, fp);
    dataf->str = malloc(str_len + 1);
    if (!dataf->str) {
        perror("分配字符串内存失败");
        free(dataf);
        fclose(fp);
        return 1;
    }
    fread(dataf->str, sizeof(char), str_len, fp);
    dataf->str[str_len] = '\0'; // 添加字符串结束符

    printf("%d: %s\n", dataf->num, dataf->str);

    // 释放内存
    free(dataf->str);
    free(dataf);
    fclose(fp);
    return 0;
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.15 15:57:04