【问题标题】:Using scanf to create new struct object使用 scanf 创建新的结构对象
【发布时间】:2018-04-08 01:31:45
【问题描述】:

您好,我正在使用创建一个包含用户列表的简单程序(基于下面的结构),并且我正在尝试根据用户输入创建新用户,其中我使用 @ 分别请求每个属性987654321@。但是我在结构限制方面遇到了麻烦,例如 id 应该最多 10 个字符,而 nome 最多可以有 25 个字符。这是我的代码以获得更多上下文:

struct user {
  char id[10];
  char name[25];
  char group;
  float score;
};

struct user list[25];
int registered = 0;

void createNewUser() {
  struct user *userPtr, newUser;
  userPtr = &newUser;

  printf("\nId: ");
  scanf("%10s", &(*userPtr).id);
  printf("\nName: ");
  scanf("%25s", &(*userPtr.name);
  printf("\nGroup: ");
  scanf("%c", &(*userPtr).group);
  printf("\nScore: ");
  scanf("%f", &(*userPtr).score);

  insert(newUser);

  printf("%10s\n", list[0].id);
  printf("%25s\n", list[0].name);
  printf("%c\n", list[0].group);
  printf("%.1f\n", list[0].score);
}

void insert(struct user newUser) {
  if (registered < 25){
    list[registered] = newUser;
    registered += 1;
  }
}

使用我上面提供的代码,如果我为第一个输入键入超过 10 个字符,则忽略接下来的 2 个字符。而我的第三个 scanf 总是被忽略,一个用于组。这里有人可以帮我解决这个问题吗?

【问题讨论】:

  • 关于:struct user *userPtr, newUser; 这会将“新用户”放入堆栈。它应该通过动态内存 I.E.在堆上,通过调用malloc()calloc()。否则,当函数:createNewUser() 退出时,它会被破坏(和未定义的行为)。
  • 关于:scanf("%10s", &(*userPtr).id);`(和类似的语句)输入格式说明符:'%s' 总是在输入中附加一个 NUL 字节,所以 MAX Characters 修饰符(即 10)应该比输入缓冲区的长度小 1(即应该是 9)
  • 在 C 中,当仅通过其名称引用数组时,数组名称会降级为数组第一个字节的地址。所以这一行:scanf("%10s", &amp;(*userPtr).id); 应该是:scanf( "%9s", userPtr-&gt;id );。结构中的其他数组也存在类似的考虑
  • 关于:scanf("%c", &amp;(*userPtr).group); 需要消耗/跳过前导“空白”。建议:scanf( " %c", &amp;userPtr-&gt;group );。注意格式字符串中的前导空格

标签: c struct scanf


【解决方案1】:

scanf 的问题是当它停止转换字符并且有 输入缓冲区中的更多内容(因为用户输入的内容超出了您的预期),那么scanf 会将这些字符留在那里。 特别是换行符(当用户按下 ENTER 时输入) 保留在输入缓冲区中,这会导致后续调用出现问题 scanf 读取字符或字符串。所以在这种情况下,你必须“清理”输入缓冲区, 这样下一个scanf 就不会消耗之前的scanf 调用的剩余部分。

你可以在每个scanf之后使用这个功能:

void clean_stdin(void)
{
    int c;
    while((c = getchar()) != '\n' && c != EOF);
}

那么你可以这样做:

printf("\nId: ");
scanf("%10s", (*userPtr).id); // no need for &, id is char[]
clean_stdin();

printf("\nName: ");
scanf("%25s", (*userPtr).name); // same here
clean_stdin();

printf("\nGroup: ");
scanf("%c", &(*userPtr).group);
clean_stdin();

printf("\nScore: ");
scanf("%f", &(*userPtr).score);

还请注意,如果 ID 的最大长度为 10,那么您的方式是 缓冲区的长度必须为 11,因为在 C 中您需要用 '\0'-终止字节。所以把你的结构改成这样:

struct user {
  char id[11];
  char name[26];
  char group;
  float score;
};

还要记住,使用这样的指针

struct user *userPtr, newUser;
  userPtr = &newUser;

  printf("\nId: ");
  scanf("%10s", (*userPtr).id);
  ...

不是必需的,它实际上使代码更难阅读。你可以这样做:

void createNewUser() {
    struct user newUser;

    printf("\nId: ");
    scanf("%10s", newUser.id);
    clean_stdin();
    ...

    printf("\nScore: ");
    scanf("%f", &newUser.score);
    ...
}

【讨论】:

  • @chux 我知道,这就是为什么我建议更改结构本身,idname 是 11 和 26 而不是 10 和 25。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-10
  • 2023-03-21
  • 2019-01-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多