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
相关产品推荐
相关产品推荐

