转义序列在 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
这就是为什么你有奇怪的输出:值没有分配给 b
和 c
。
当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等字符。它看不到原始转义序列。
我已经翻阅了一些东西来找出答案,但没有找到合适的东西(或者我是一个糟糕的搜索者)。
现在我正在学习 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
这就是为什么你有奇怪的输出:值没有分配给 b
和 c
。
当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等字符。它看不到原始转义序列。