Nav*_*ddy 1 c whitespace scanf conversion-specifier
在 C 中,当我们在or之前使用 ascanf("%s")或时,在输入时,第一个输入的末尾会有一个额外的内容,并且该额外内容将被传递到第二个输入并弄乱输入流。据我所知,我已经在两个不同的系统中使用相同的 gcc 编译器尝试了这些代码。但它每次都做了不同的事情。在第一个系统中,我必须使用 a来丢弃换行符。但在第二个系统中就没有这样的需要了。它自动丢弃换行符。scanf("%c")scanf("%s")scanf("%[^\n]")'\n'scanf("\n")
然后我尝试了三个代码,
代码1:
printf("Enter the name of the student: ");
scanf("%s", name);
printf("Enter the email of the student: ");
scanf("%s", email);
Run Code Online (Sandbox Code Playgroud)
在这里我不必忽略换行符,编译器没有任何问题。
代码2:
printf("Enter the name of the student: ");
scanf("%s", name);
scanf("%*c");
printf("Enter the email of the student: ");
scanf("%s", email);
Run Code Online (Sandbox Code Playgroud)
这里我只是添加了scanf("%*c")来丢弃换行符,这与 具有相同的结果code 1。但是,当我替换scanf("%*c")为scanf("\n")输入时,输入再次混乱,我现在必须提供 3 个输入,因为它没有正确丢弃第一个换行符。
代码3:
char chr, s[100], sen[100];
scanf("%c", &chr);
scanf("\n");
scanf("%s", s);
scanf("\n");
scanf("%[^\n]%*c", sen);
Run Code Online (Sandbox Code Playgroud)
如果没有 s,这里的代码将无法工作scanf("\n")。
我真的不明白这里发生了什么。为什么有时我必须转义换行符,而有时则不需要。
\n\n在 C 中,当我们在or之前使用 a
\nscanf("%s")或时,在输入时,第一个输入的末尾会有一个额外的 \'\\n\' ,它将被传递到第二个输入并弄乱输入流。scanf("%c")scanf("%s")scanf("%[^\\n]")
我不会那样说。我会说:
\n每当我们scanf与任何格式说明符一起使用时,\\n指示用户键入的行结尾的信息都会保留在输入流中,这可能会导致以后出现问题。分三种情况:
scanf任何格式说明符,则延迟将与任何其他前导空格一起自动跳过。%c%[\xe2\x80\xa6]\\nscanf使用%cor %[\xe2\x80\xa6],则将\\n由该格式说明符读取(尽管通常不需要)。scanf,例如fgets或getchar,则\\n该函数将读取 (尽管通常不希望这样做)。(或者更简洁地说:“如果我们在之前调用过其他东西之后使用scanf("%c")或,那么剩下的东西往往会把事情搞砸。”)scanf("%[\xe2\x80\xa6]")scanf\\n
通过向格式说明符添加额外的前导空格,明确指示scanf跳过前导空格(就像它对所有其他格式说明符隐式执行的那样),可以轻松修复情况 #2。
通常不建议单独调用scanf("\\n"),因为它不会执行看起来所执行的操作。
这些规则并不是 的完整故事scanf,但它们是一个良好的开始,并解释了大多数基本用途的行为。
\n\n据我所知,我已经在两个不同的系统中使用相同的 gcc 编译器尝试了这些代码。但它每次都做了不同的事情。
\n
这是令人惊讶的。如果您能够准确且可重复地描述这种差异,那么探索可能会很有趣。
\n在代码 1 中,您正在读取两个简单的字符串,因此只要它们不包含空格,就可以了。\\n读取第一个字符串后剩下一个,scanf但它被第二个字符串跳过%s。
在代码 2 中,调用scanf("%*c")读取并丢弃\\n. 这确实是显式丢弃杂散换行符的一种方法,但我不认为这是最好的方法。(问题是它会读取任何字符 \xe2\x80\x94 不一定只是换行符 \xe2\x80\x94 并且如果你在没有杂散字符要消耗的地方调用它,它会阻塞,等待它可以消耗的角色。)
在你的代码 3 中,你说“如果没有 s,代码就无法工作scanf("\\n")”,这部分是正确的。使用 读取字符串后,输入流上仍然%s存在。\\n于是接下来%[^\\n]就过早地被那流浪满足了\\n。所以你的调用scanf("\\n")是剥离它的一种方法。(但是你不需要scanf("\\n")在%c和%s调用。)
顺便说一句,我相信在以下说明符scanf("\\n")中添加一个前导空格会更干净,而不是调用。%[\xe2\x80\xa6]scanf(" %[^\\n]%*c", sen);
%*c(而且你最后不一定需要它。我知道它的用途,但我想说你不需要或不应该需要它。下面有更多信息。)
底线是这scanf是一个非常有问题的输入函数。在简单的入门程序中,对于非常简单的输入来说,它非常好用且简单。但这并不是很好的 \xe2\x80\x94 这是一个令人沮丧的麻烦,通常比它的价值 \xe2\x80\x94 对于任何花哨的东西来说更麻烦。
“非常简单的输入”是什么意思?这是一个非常简短的列表:
\nint如果您想用%d, 或float用doubleor%f来阅读单曲%lf,也可以。%s,那很好,但要注意该字符串不会包含任何空格。您还必须确保已正确分配scanf将读取字符串的内存。使用宽度修饰符也是一个好主意,%29s这样scanf可以避免内存溢出。" %c",而不是 plain"%c"。就是这样。如果你想做比这更奇特的事情scanf,那就开始变成南瓜吧。尤其:
%s则无法工作,并且没有好的、简单的替代方法。(有%[\xe2\x80\xa6],但并不简单。)scanf不是适合该工作的工具。而且,作为更一般的规则,如果您尝试使用 做某事scanf,但它不起作用,并且您开始相信需要“刷新”一些不需要的输入,请立即停止。事实上,“同花顺”这个词已经进入你的脑海,这是一个几乎完全可靠的指标,它scanf不是你想要做的工作的正确工具,你应该强烈考虑放弃并scanf转而选择其他东西。(无论您想要做什么,尽管使用它可能几乎不可能scanf一些笨拙的输入刷新机制几乎不可能做到,但它肯定会比如果你用了别的东西。)
请参阅此处和此处,了解一些类似的指南,了解使用 时尝试做什么和不做什么scanf。当您准备尝试其他方法时,请阅读我可以使用什么来代替输入转换scanf?。
最后,再多说几句关于您对 的调用scanf("%[^\\n]%*c", sen);,特别是%*c最后的额外说明符。我说我以为你不需要它。这就是原因。
那有什么%*c作用?好吧,%[^\\n]读取一行文本,但不包括换行符,因此%*c读取并丢弃换行符,大概这样它“就不会留在输入流上并在以后引起问题”。但让我们再想一想。
当您认真对待它时,scanf总是在输入流上留下换行符。这是 的默认行为scanf。而且,如果下一次调用总是小心地跳过杂散的换行符,那么一切都会顺利进行。
假设你打电话
\nscanf("%d", &num1);\nscanf("%d", &num2);\nscanf("%d", &num3);\nRun Code Online (Sandbox Code Playgroud)\n扫描后留下了一个换行符num1,扫描后也留下了一个换行符num2,但是它们都没有造成任何问题,因为下一个%d干净地跳过了它。
在 scanf 调用之后总是有一个杂散换行符并不是真正的问题,除非下一个输入调用不会跳过它。如果 (a) 下一个输入调用scanf使用%cor %[\xe2\x80\xa6],或者 (b) 下一个输入调用scanf根本不是,而是类似fgetsor ,就会发生这种情况getchar就会发生这种情况。
因此,处理杂散换行符的一种方法(在我看来是最好和最干净的方法)scanf就是声明它总是是下一个调用的工作来跳过它们:
%dor %for 这样的说明符%s的说明符,它会自动跳过前导空格,所以我们没问题。%c或%[\xe2\x80\xa6],请添加显式前导空格以强制跳过杂散换行符:" %c"或" %[\xe2\x80\xa6]"。scanf……那么,那是个坏主意。我的建议是永远不要scanf与同一程序中的其他输入功能混合。有一个循环不变式的概念,这很有用,你可以说它对于每次循环都是如此,就像\n“变量i始终是我们将填充的下一个单元格的索引\nin" 或 "len始终是迄今为止构建的字符串的长度。"
类似地,当一次读取一行输入时,对于如何处理换行符有一个约定很有用。\n我们可以采用以下任一方法:
\n\\n也会读取它。输入流位于要读取的下一行的开头。” 或者,\\n留在输入流中。首先跳过该行始终是下一行读取函数的工作\\n。”如果这些约定一致的话,两者都是。如果您正在使用 读取输入行fgets,那么您显然正在使用约定#1。\n但如果您正在使用 读取输入scanf,则scanf\n总是对约定#2 感到满意。
我相信,为了理智起见,如果您正在使用scanf,\n您应该全心全意地接受第 2 条约定。\\n读完一行后,不要尝试删除。不要使用类似于%*cafter 的措辞%[\xe2\x80\xa6],这样“换行符稍后不会引起问题”。只需让杂乱的换行符继续存在,并确保\n下次 您始终跳过它们即可。%d并且\n自动%f执行%s此操作。 实际上,如果您显式添加前导空格,则可以这样做%c。%[\xe2\x80\xa6]并且不要尝试在您也使用 的程序中使用fgetsor\n 。(或者,如果\n您必须混合使用和,那么在调用\n之前,执行一些操作来跳过换行符(如果存在)。那是\n可能需要调用的地方。)getcharscanfscanffgetsfgetsscanf("\\n")
| 归档时间: |
|
| 查看次数: |
936 次 |
| 最近记录: |