【问题标题】:scanf("%[^\n]") gets skippedscanf("%[^\n]") 被跳过
【发布时间】:2016-01-24 06:07:28
【问题描述】:

我想写一个小程序来学习C;在这里:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int total;
char suffix[3];
struct person {
    char id[11];
    char name[21];
    char sex[7];
    int age;
    char phone[12];
};

char* number_suffix (int number) {
    int mod;
    mod = number % 10;

    switch (mod) {
        case 1:
            strcpy(suffix, "st");
            break;
        case 2:
            strcpy(suffix, "nd");
            break;
        case 3:
            strcpy(suffix, "rd");
            break;
        default:
            strcpy(suffix, "th");
            break;
    }
    return suffix;
}

void input_info (struct person info[], int total_people) {
    int counter;
    for (counter=0; counter<total_people; counter++){
        printf("%s%d%s%s\n","Please input the ID(10 digits) of ", (counter+1),
                number_suffix(counter), " person: ");
        scanf("%s", info[counter].id);
        fflush(stdin);

        printf("%s%d%s%s\n", "Please input the Name(20 chars) of ", (counter+1),
                number_suffix(counter), " person: ");
        scanf("%[^\n]", info[counter].name);
        fflush(stdin);

        printf("%s%d%s%s\n", "Please input the Sex(Male/Female) of ", (counter+1),
                number_suffix(counter), " person: ");
        scanf("%s", info[counter].sex);
        fflush(stdin);

        printf("%s%d%s%s\n", "Please input the Age(1~100) of ", (counter+1),
                number_suffix(counter), " person: ");
        scanf("%d", &info[counter].age);
        fflush(stdin);

        printf("%s%d%s%s\n", "Please input the Phone of ", (counter+1),
                number_suffix(counter), " person: ");
        scanf("%s", info[counter].phone);
        fflush(stdin);
    }
    printf("%s\n%s\n%s\n%d\n%s\n", info[counter].id, info[counter].name, info[counter].sex, &info[counter].age, info[counter].phone);
}

int main (void) {
    printf("%s\n", "Please input a number that how many people you want to record:");
    scanf("%d", &total);
    fflush(stdin);
    struct person *person_info = malloc(sizeof(struct person)*total);
    input_info(person_info, total);

    free(person_info);
    return 0;
}

当我运行它时,我发现了一些奇怪的东西。

Please input a number that how many people you want to record:
1
Please input the ID(10 digits) of 1th person:
A01
Please input the Name(20 chars) of 1th person:
Please input the Sex(Male/Female) of 1th person:
Male
Please input the Age(1~100) of 1th person:
32
Please input the Phone of 1th person:
1224464
[empty line]
[empty line]
[empty line]
1926234464
[empty line]

该程序在运行时是否跳过scanf("%[^\n]", info[counter].name); 这一行?

为什么,是什么原因造成的?

【问题讨论】:

  • fflush(stdin) 不推荐。在许多实现中,刷新输入流是未定义的行为。在您的特定情况下,它可能不会摆脱第一个 scanf 留下的换行符。见scanf Getting Skipped
  • "如何理解指针、struct、malloc、函数参数之间的关系?" -- 什么?这太宽泛了,无法回答。所以,我已经删除了它。
  • 详情请咨询Using fflush(stdin) — 除非您使用的是 Windows 系统,否则它不会执行您想要/期望的操作。
  • 打印counter+1时需要调用number_suffix(counter+1)。别忘了它是11th12th13th(但1st21st2nd22nd3rd23rd)。
  • 总的来说,你应该每次检查scanf()的结果,以确保你得到了你期望的结果。调试问题时的一项基本技术是回显您刚刚获得的输入,以确保计算机得到您期望的结果。

标签: c pointers struct parameters malloc


【解决方案1】:

fflush(stdin) 根据 C 标准未定义,但它适用于某些实现。但最好避免使用它,因为它不可移植并且可能会调用未定义的行为。

要解决此问题,请将所有 fflush(stdin)s 替换为

int c; /* Declare it once */
while((c = getchar()) != '\n' && c != EOF); /* Discards everything until a newline character or EOF */

另一个问题是

printf("%s\n%s\n%s\n%d\n%s\n", info[counter].id, info[counter].name, info[counter].sex, &info[counter].age, info[counter].phone);

应该是

printf("%s\n%s\n%s\n%d\n%s\n", info[counter].id, info[counter].name, info[counter].sex, info[counter].age, info[counter].phone);

并且应该放在 for 循环。否则,您会调用未定义的行为,因为

  1. 您为 %d 传递了一个 int*,它需要一个 int
  2. 您访问了超出已分配内存段的无效内存位置。

另外,正如其他人所说,将counter + 1 传递给number_suffix

【讨论】:

  • 你说有问题的printf行没有区别。即使您发布的已更改的内容也是一样的。
  • @AshishAhuja 仔细看。我删除了与号。
  • 糟糕,我的错误:-(
  • @CoolGuy 虽然printf 需要放在for 循环中以便它可以打印我需要的信息,但是我输入的信息确实在我使用@ 获得的内存中987654335@,对吧?
  • @JoshuaLee 是的。但是如果不将其放入循环中,您会调用我的回答中所说的未定义行为(您访问分配的内存段之外的无效内存位置
【解决方案2】:
  1. 问题在于您的 scanf 模式。使用" %[^\n]" 而不是"%[^\n]" 来不捕获\n(在之前的数据输入之后)
  2. counter + 1 传递给number_suffix

如何理解指针、struct、malloc、函数参数之间的关系?

O'Reilly Media

阅读 Understanding and Using C Pointers

【讨论】:

  • 使用%[^\n]而不是%s的原因是允许人们有两个(或多个)名称,由一个(或多个)空格分隔:John Doe等。
  • 为什么是图书广告? :-)
  • @JonathanLeffler 感谢您的评论。我修好了。
  • @CoolGuy 你是对的。当不访问字符串(数组)的任何项目时,将检索字符串(数组)字段的地址。 &(info[counter].id) ~= info[counter].id 当传递 byref
  • @AshishAhuja 这是基于 OP 的问题。 I removed it 因为它太宽泛了。见original question before all edits
猜你喜欢
  • 1970-01-01
  • 2013-01-07
  • 1970-01-01
  • 2021-10-06
  • 1970-01-01
  • 2021-11-07
  • 1970-01-01
相关资源
最近更新 更多