如何修复C语言结构体文件读写时的‘内存无法写入’错误?
问题说明
参考YouTube教程实现结构体读写文件功能,仅修改变量名后,用编译指令gcc -o _main _main.c编译运行时,弹出错误:
0x00000000765AF391处的指令引用了0x000000000000000F处的内存,该内存无法写入。
怀疑是内存泄漏导致,需要排查代码问题并学习C语言FILE操作知识。
错误原因逐条分析
结构体成员定义与初始化不匹配
Worker结构体中workerCode被定义为int workerCode[5](整数数组),但初始化时却用.workerCode = 12345直接赋值单个整数。数组不能直接用单个值初始化,这会导致内存越界;后续fprintf用%d输出数组名时,实际是输出数组的内存地址而非工号值,fscanf读入时也会把值写到错误的内存位置。fscanf参数严重错误
格式串WORKER_FORMAT_IN为(%[^,], %[^,], %d)\n,对应3个参数,但代码中传入了4个参数:worker2.workerFirstName, 15, &worker2.workerLasttName, &worker2.workerCode。其中15被fscanf当成第二个字符串的内存地址(15的十六进制是0xF,正好对应错误提示里的非法地址),往这个只读低地址写入数据直接触发内存访问错误。结构体成员拼写错误
Worker结构体中workerLasttName多写了一个t,虽然当前未直接引发错误,但属于潜在bug,后续维护时容易出错。未关闭文件
fopen打开文件后未调用fclose,虽然程序结束时系统会回收资源,但这是不良编程习惯,可能导致缓冲区数据未及时写入磁盘。
修复后的完整代码
#include <stdio.h> #include <stdlib.h> #include <ctype.h> #include <string.h> typedef struct Client { char userFirstName[15]; char userLastName[15]; char userPassword[20]; float userBankMoney; float userHandMoney; } Client; // 修正格式串:给字符串读取添加长度限制,避免缓冲区溢出 const char* WORKER_FORMAT_IN = "(%14[^,], %14[^,], %d)\n"; const char* WORKER_FORMAT_OUT = "(%s, %s, %d)\n"; typedef struct Worker { char workerFirstName[15]; char workerLastName[15]; // 修正拼写错误 int workerCode; // 改为单个整数,符合工号的实际需求 } Worker; //>>>FUNCTIONS PROTOTYPES<<<// void printOptions(); void loginAsWorker(); void createAccount(); void payment(); void withdrawal(); void moneyTransfer(); void balanceReview(double balance); int main() { Worker worker1 = { .workerFirstName = "Matija", .workerLastName = "Davidovic", .workerCode = 12345 }; Worker worker2; FILE* worker_file = fopen("worker.dat", "w+"); if(worker_file == NULL) { perror("Failed to open file"); // 添加错误提示,便于排查 return 1; } // 格式化写入结构体数据 fprintf(worker_file, WORKER_FORMAT_OUT, worker1.workerFirstName, worker1.workerLastName, worker1.workerCode); // 将文件指针移回开头,准备读取 fseek(worker_file, 0, SEEK_SET); // 格式化读取数据,参数与格式串严格匹配 fscanf(worker_file, WORKER_FORMAT_IN, worker2.workerFirstName, worker2.workerLastName, &worker2.workerCode); // 验证读取结果(可选,用于调试) printf("Read worker data: %s, %s, %d\n", worker2.workerFirstName, worker2.workerLastName, worker2.workerCode); // 关闭文件,释放资源 fclose(worker_file); return 0; }
C语言FILE操作关键知识点
- 格式化读写参数匹配:
fprintf/fscanf的格式串必须与后续参数的类型、数量、顺序完全一致,否则会触发未定义行为(比如内存访问错误)。 - 字符串读取安全:使用
%N[^,]格式限制读取长度(N为数组长度-1,留一位给字符串结束符\0),避免缓冲区溢出导致的内存问题。 - 文件打开模式:
w+模式会清空原有文件内容,若要保留原有内容并读写,应使用r+模式;写入后必须通过fseek/rewind将文件指针移回开头才能读取刚写入的数据。 - 文件资源管理:打开的文件必须用
fclose关闭,确保缓冲区数据写入磁盘,避免资源泄漏。 - 结构体成员操作:数组类型的成员不能直接用单个值初始化或赋值,若只需存储单个值,应改为普通变量类型。
内容的提问来源于stack exchange,提问作者mata023

