转义序列在 scanf() 函数中的实际行为

How do escape sequences actually behave in the scanf() function

我已经翻阅了一些东西来找出答案,但没有找到合适的东西(或者我是一个糟糕的搜索者)。

现在我正在学习 stdio.h header 的 scanf 函数,他们说这里不推荐转义序列,因为它 'confuses' 输入,但实际发生了什么?我测试了一些代码并得到了不同 ES 的结果:

#include <stdio.h>

int main(void)
{
    int a, b, c;

    printf("Enter values: \n");
    scanf("%d%d%d\n", &a, &b, &c);
    printf("The values are %d, %d and %d.\n", a, b, c);
}

Enter values: 
1
2
3
randomstuff
The values are 1, 2 and 3.

'\t' 序列也是如此——它要求再输入一个值(我输入 'randomstuff'),该值不会存储在任何地方。 另一方面,'\a' 和 '\b' 的行为不同并且不影响输入:

    ...
    scanf("%d%d%d\a", &a, &b, &c);
    printf("The values are %d, %d and %d.\n", a, b, c);
}

Enter values: 
1
2
3
The values are 1, 2 and 3.

搞乱ES的位置就更乱了。 '\n' 和 '\t' 停止影响输入:

    ...
    scanf("%d\t%d\n%d", &a, &b, &c);
    printf("The values are %d, %d and %d.\n", a, b, c);
}

Enter values: 
1
2
3
The values are 1, 2 and 3.

而“\a”和“\b”开始产生一些影响:

    ...
    scanf("%d\b%d%d", &a, &b, &c);
    printf("The values are %d, %d and %d.\n", a, b, c);
}

Enter values: 
1    
The values are 1, 0 and 32766.

有人说 ES 不被 scanf() 解释,只是被当作普通字符,但这似乎也不正确,因为它确实按照规则解释像 \' 或 \" 这样的 ES。

这是怎么回事? PS 为什么最后的结果是0和32766?

正如我在上面评论的那样,scanf 格式字符串中的空白字符从输入中删除了一个或多个空白字符。但是 \b 不是空白字符,因此必须在输入中进行匹配。如果您对 scanf 返回的值进行了 essential 检查,这里应该是 3(转换的项目数),您会看到值未全部读取。

#include <stdio.h>

int main(void)
{
    int a, b, c, r;
    r = scanf("%d\b%d%d", &a, &b, &c);
    printf("return val = %d\n", r);
    return 0;
}

节目环节:

7 8 9
return val = 1

这就是为什么你有奇怪的输出:值没有分配给 bc

scanf接收到一个字符串时,其中没有转义序列。如果将字符串文字用作参数,则在翻译(编译)程序时会处理其中的转义序列。 C 6.4.4.4 指定如何处理转义序列:

  • \'\"\?\ 变为 '"?\,分别.
  • \a\b\f\n\r\t\v成为字符警报、后退space、换页、换行、回车return、水平制表符和垂直制表符。
  • \d\dd\ddd,其中每个d都是八进制数字,成为具有该值的字符。
  • \x后跟一个或多个十六进制数字成为具有该值的字符。

那么对于scanf,字符的含义是:

  • 如果字符是白色-space字符(space、水平制表符、换行符、垂直制表符、换页符),它指示scanf读取输入直到第一个非白色 space 字符(保持未读状态)或直到无法读取更多字符。
  • 如果字符是 %(可以由八进制或十六进制转义序列产生),它会引入一个转换规范,例如 %d.
  • 否则,它指示scanf读取下一个字符并逐字匹配(格式字符串中的警告字符必须与输入流中的警告字符匹配,依此类推)。

The same is with '\t' sequence – it asks for one more value (I typed 'randomstuff') which is not stored anywhere.

字符串文字中的

\t 成为(水平)制表符,制表符是白色-space 字符,因此它指示 scanf 读取输入直到它看到白色-space 字符或无法获得更多输入。这就是为什么当您添加 \t 时,scanf 一直读取直到它看到您的“randomstuff”的非白色 space 字符“r”。

'\a' and '\b', on the other hand, behave differently and does not affect the input:

这些不是 white-space 字符,也不是 %,因此它们指示 scanf 尝试将它们与输入流中的字符逐字匹配。对于 "%d%d%d\a"scanf 匹配三个 %d 规范,然后它再读取一个字符以尝试将其与警告字符匹配。那失败了,所以 scanf 停止并 returned 3 为三场成功的比赛。 (scanf 还将不匹配的字符“放回”输入流中。)

It becomes more confusing when I mess around with the position of the ES. '\n' and '\t' stop affecting the input:

"%d\t%d\n%d"中,制表符和换行符指示scanf匹配白色-space字符。但是,作为 %d 转换规范的一部分,scanf 通常会跳过这些,因此它们在 %d.

之前无效

whereas '\a' and '\b' start having some influence:

"%d\b%d%d"处理第一个十进制数字,然后backspace指示scanf匹配一个backspace字符。由于输入中没有backspace字符,匹配失败,scanf停止。

请注意,none 这些行为涉及 scanf 处理转义序列。 scanf正在处理它接收到的字符,即tab、alert、backspace等字符。它看不到原始转义序列。