C语言中传递结构体成员引用修改数据无效果的问题
问题分析与解决方案
核心问题排查
你的代码存在几个关键错误,导致结构体和文件数据未更新:
feof循环逻辑错误while (!feof(*user_registry))的写法会导致循环多执行一次——feof仅在读取操作尝试越过文件末尾后才会置位,而非到达末尾时。正确的做法是用fread的返回值判断是否成功读取到完整的结构体。文件定位计算错误
找到目标用户后,你试图回退到该用户数据的起始位置,但fseek(*user_registry, 0, SEEK_CUR - 1)完全错误:每次fread读取了sizeof(struct user)字节,因此需要回退整个结构体的大小,而非1字节。原代码中的无效输入判断(最小复现中已移除,但需注意)
初始函数里的if (strcmp(input, "...")) return;逻辑完全反转,会导致只要输入不是"..."就直接返回,完全不符合修改需求。文件缓存未同步
修改文件后未调用fflush或关闭文件,导致内存中的修改未写入磁盘。
修正后的完整代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #define MAXLEN 64 struct user { char user_name[MAXLEN]; char password[MAXLEN]; }; void placeholder_function(struct user *logged_user); void change_user_data(char *input, struct user **logged_user, char *data_to_alter, FILE **user_registry); int main() { struct user logged_user; placeholder_function(&logged_user); return 0; } void placeholder_function(struct user *logged_user) { FILE *user_registry; if (!(user_registry = fopen("user_registry.bin", "w+b"))) { printf("无法打开文件\n"); exit(1); } strcpy(logged_user->user_name, "Admin"); strcpy(logged_user->password, "Admin"); fseek(user_registry, 0, SEEK_SET); fwrite(logged_user, sizeof(struct user), 1, user_registry); fflush(user_registry); // 立即刷新缓存到磁盘 // 预期输出: Admin Admin printf("%s %s\n", logged_user->user_name, logged_user->password); // 修改密码 change_user_data("1234", &logged_user, logged_user->password, &user_registry); printf("%s %s\n", logged_user->user_name, logged_user->password); // 期望输出: Admin 1234 fclose(user_registry); // 关闭文件确保数据持久化 } void change_user_data(char *input, struct user **logged_user, char *data_to_alter, FILE **user_registry) { struct user find_user; // 简单输入有效性判断 if (!input || strlen(input) == 0 || strlen(input) >= MAXLEN) { return; } fseek(*user_registry, 0, SEEK_SET); // 用fread返回值判断是否成功读取结构体 while (fread(&find_user, sizeof(struct user), 1, *user_registry) == 1) { if (strcmp(find_user.user_name, (*logged_user)->user_name) != 0) { continue; } // 安全修改目标成员,避免溢出 strncpy(data_to_alter, input, MAXLEN - 1); data_to_alter[MAXLEN - 1] = '\0'; // 回退到当前用户数据的起始位置 fseek(*user_registry, -sizeof(struct user), SEEK_CUR); // 写入修改后的结构体 fwrite((*logged_user), sizeof(struct user), 1, *user_registry); fflush(*user_registry); // 刷新缓存 break; } }
额外优化建议
- 用
strncpy替代strcpy,避免输入过长导致数组溢出,提升安全性。 - 可以给
change_user_data增加返回值(比如int类型),用来标识修改是否成功,方便上层逻辑处理。 - 原代码中的三重指针
struct user ***logged_user完全冗余,当前场景下二重指针足够。
内容的提问来源于stack exchange,提问作者Kuudere-san
相关产品推荐
相关产品推荐

