如何用fwrite()结合结构体指针写入含char指针的结构体到文本文件?
问题原因
你的car结构体里的plate、model等都是char*指针,fwrite写入的是指针本身的内存地址值,不是指针指向的字符串内容。这些地址是程序运行时的临时内存地址,写入文件后就是一堆无意义的二进制数据,所以看起来是乱码;而且每次程序运行时内存地址可能变化,导致乱码内容不同。
修复方案
方案1:改用固定长度字符数组(最简单直接)
把结构体里的char*换成固定大小的char数组,这样结构体里直接存储字符串内容,fwrite就能一次性把整个结构体的实际数据写入文件:
#include <stdio.h> #include <stdlib.h> #include <string.h> int numberOfCars; // 替换char*为固定长度数组,长度根据实际需求调整 typedef struct { char plate[20]; char model[30]; char color[20]; char ownerName[50]; char problems[100]; char status[20]; int year; } car ; void writeIntoDatabase(car *); int main() { car *Cars; numberOfCars=2; Cars=(car *)calloc(numberOfCars, sizeof(car)); int i=0; // 使用strcpy复制字符串到数组 strcpy((Cars+i)->plate, "CJ23YOU"); strcpy((Cars+i)->model, "Mazda"); strcpy((Cars+i)->color, "Black"); strcpy((Cars+i)->ownerName, "Makro_And"); strcpy((Cars+i)->problems, "Rattling_noise"); strcpy((Cars+i)->status, "Fixed"); (Cars+i)->year=2019; i++; strcpy((Cars+i)->plate, "CJ65YOM"); strcpy((Cars+i)->model, "Volkswagen"); strcpy((Cars+i)->color, "White"); strcpy((Cars+i)->ownerName, "Mars Andy"); strcpy((Cars+i)->problems, "Rattling noise lllas"); strcpy((Cars+i)->status, "Pending"); (Cars+i)->year=2009; writeIntoDatabase(Cars); printf("%s", (Cars+i)->plate); // 记得释放内存 free(Cars); return 0; } void writeIntoDatabase(car *Cars) { FILE *DB_ptr=fopen("carsDBwrite.txt","w"); if(DB_ptr == NULL){ // 增加文件打开失败判断 perror("Failed to open file"); return; } fwrite(Cars,sizeof(car),numberOfCars,DB_ptr); fclose(DB_ptr); }
方案2:手动序列化指针指向的内容(保留指针的灵活性)
如果必须用char*动态分配内存,需要手动把每个字符串的内容写入文件,而不是直接写结构体。可以先写入字符串的长度,再写入字符串内容,这样后续读取时能准确还原:
#include <stdio.h> #include <stdlib.h> #include <string.h> int numberOfCars; typedef struct { char *plate; char *model; char *color; char *ownerName; char *problems; char *status; int year; } car ; void writeIntoDatabase(car *); int main() { car *Cars; numberOfCars=2; Cars=(car *)calloc(numberOfCars, sizeof(car)); int i=0; // 用strdup分配内存并复制字符串,避免指向只读常量区 (Cars+i)->plate=strdup("CJ23YOU"); (Cars+i)->model=strdup("Mazda"); (Cars+i)->color=strdup("Black"); (Cars+i)->ownerName=strdup("Makro_And"); (Cars+i)->problems=strdup("Rattling_noise"); (Cars+i)->status=strdup("Fixed"); (Cars+i)->year=2019; i++; (Cars+i)->plate=strdup("CJ65YOM"); (Cars+i)->model=strdup("Volkswagen"); (Cars+i)->color=strdup("White"); (Cars+i)->ownerName=strdup("Mars Andy"); (Cars+i)->problems=strdup("Rattling noise lllas"); (Cars+i)->status=strdup("Pending"); (Cars+i)->year=2009; writeIntoDatabase(Cars); printf("%s", (Cars+i)->plate); // 释放每个字符串的内存 for(int j=0;j<numberOfCars;j++){ free((Cars+j)->plate); free((Cars+j)->model); free((Cars+j)->color); free((Cars+j)->ownerName); free((Cars+j)->problems); free((Cars+j)->status); } free(Cars); return 0; } void writeIntoDatabase(car *Cars) { FILE *DB_ptr=fopen("carsDBwrite.txt","wb"); // 用二进制模式写入更可靠 if(DB_ptr == NULL){ perror("Failed to open file"); return; } // 先写入车辆数量 fwrite(&numberOfCars, sizeof(int), 1, DB_ptr); for(int i=0;i<numberOfCars;i++){ car *current = Cars + i; // 写入每个字符串:先写长度,再写内容 size_t len = strlen(current->plate); fwrite(&len, sizeof(size_t), 1, DB_ptr); fwrite(current->plate, sizeof(char), len, DB_ptr); len = strlen(current->model); fwrite(&len, sizeof(size_t), 1, DB_ptr); fwrite(current->model, sizeof(char), len, DB_ptr); len = strlen(current->color); fwrite(&len, sizeof(size_t), 1, DB_ptr); fwrite(current->color, sizeof(char), len, DB_ptr); len = strlen(current->ownerName); fwrite(&len, sizeof(size_t), 1, DB_ptr); fwrite(current->ownerName, sizeof(char), len, DB_ptr); len = strlen(current->problems); fwrite(&len, sizeof(size_t), 1, DB_ptr); fwrite(current->problems, sizeof(char), len, DB_ptr); len = strlen(current->status); fwrite(&len, sizeof(size_t), 1, DB_ptr); fwrite(current->status, sizeof(char), len, DB_ptr); // 写入年份 fwrite(¤t->year, sizeof(int), 1, DB_ptr); } fclose(DB_ptr); }
注意事项
- 方案1的优点是简单,直接用
fwrite/fread即可,但缺点是字符串长度固定,可能浪费内存或不够用。 - 方案2的优点是灵活,支持任意长度的字符串,但需要手动处理序列化和反序列化,代码更复杂,读取时也要对应先读长度再读内容。
- 无论哪种方案,都要检查文件是否成功打开,避免空指针操作;使用动态内存后记得释放,防止内存泄漏。
内容的提问来源于stack exchange,提问作者Mikeș
相关产品推荐
相关产品推荐

