C扫描()格式的行为



免责声明。我见过很多问题,包括几乎完全相同的代码片段,但似乎没有一个能回答这个问题

对于入门级CS类,我们的任务是制作一个简单的程序,该程序接受用户输入的ID、姓名和年龄,并将其保存到文件中。这很简单,我很快就完成了。问题是,为了获得一个部分,名称输入,正常工作,我必须";欺骗;我解决遇到的一个问题的方法
有问题的代码段。

int id, age;
char name[40]={0};
printf("ID: ");
scanf("%i",&id);
printf("Name: ");
scanf("%*c");
scanf("%[^n]%*c",name);
printf("Age: ");
scanf("%i",&age);

这很好用。但这句话让我很恼火;scanf("%*c");它的唯一目的是处理隐藏在流中的'n'字符,可能来自以前的输入。出于某种原因,如果必须使用这种变通方法,我觉得这是作弊,或者我做错了什么。任何提示都将不胜感激。

但这句话让我很恼火;scanf("%*c"(;它的唯一目的是处理隐藏在流中的"\n"字符,可能来自前一个输入

scanf()对于读取单个字符来说是相当重量级的。我通常会选择getchar(),如果你不在乎结果是什么,就忽略它

然而,对于您的特定情况,我同意@OlafDietsche在评论中提出的建议:在下一个scanf:的格式字符串的开头插入一个空格(或换行符或制表符(

scanf(" %[^n]%*c",name);

这将匹配任何一次零个或多个空白字符,因此将占用您的换行符,以及任何后续的空白行和下一行中任何非空白的前导空白。无论如何,这是大多数其他字段指令的标准行为,这就是为什么数字字段没有同样的问题,但对于%[%c字段,这是有意而不是自动执行的,这样它们就可以读取并返回空白。

这也意味着您不需要显式地使用名称行末尾的换行符,或者。。。

scanf(" %[^n]",name);

因为它将在随后的CCD_ 9调用中被CCD_。

考虑使用fget()读取用户输入@Barmar的,然后进行解析。

char buffer[100];
int id, age;
char name[40]={0};
printf("ID: ");
fgets(buffer, sizeof buffer, stdin);
sscanf(buffer, "%i", &id);
printf("Name: ");
fgets(buffer, sizeof buffer, stdin);
sscanf(buffer, "%[^n]", name);
printf("Age: ");
fgets(buffer, sizeof buffer, stdin);
sscanf(buffer, "%i", &age);

随着技能的提高,增加错误检查。

printf("ID: ");
if (fgets(buffer, sizeof buffer, stdin) == NULL) Handle_end_of_file();
if (sscanf(buffer, "%i",&id) != 1) Handle_non_numeric_input();
// also research strtol()
printf("Name: ");
if (fgets(buffer, sizeof buffer, stdin) == NULL) Handle_end_of_file();
if (sscanf(buffer, " %99[^n]",name) != 1) Handle_space_only_name();
// Later, additional code to detect excessively long name