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

C语言中传递结构体成员引用修改数据无效果的问题

问题分析与解决方案

核心问题排查

你的代码存在几个关键错误,导致结构体和文件数据未更新:

  1. feof循环逻辑错误
    while (!feof(*user_registry))的写法会导致循环多执行一次——feof仅在读取操作尝试越过文件末尾后才会置位,而非到达末尾时。正确的做法是用fread的返回值判断是否成功读取到完整的结构体。

  2. 文件定位计算错误
    找到目标用户后,你试图回退到该用户数据的起始位置,但fseek(*user_registry, 0, SEEK_CUR - 1)完全错误:每次fread读取了sizeof(struct user)字节,因此需要回退整个结构体的大小,而非1字节。

  3. 原代码中的无效输入判断(最小复现中已移除,但需注意)
    初始函数里的if (strcmp(input, "...")) return;逻辑完全反转,会导致只要输入不是"..."就直接返回,完全不符合修改需求。

  4. 文件缓存未同步
    修改文件后未调用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.19 16:46:37