我try 了下面的代码(用GCC 13编译,在Ubuntu22.04上)

int x;
int ret = scanf("%d", &x);
char ch;
scanf("%c", &ch);
printf("%c, %d\n", ch, ret);

通过输入

-*

它打印*, 0,这表明对x的第一个输入失败(返回值是0),但是第一个减号被使用了.当我将负号更改为+时,也会发生这种情况,但对于其他字符则不会.

此符号是否被视为整数的开始?如果是这样,为什么这种输入被视为失败?如果不是,为什么会被消费呢?或者这是一种完全没有定义的行为?

另外,当输入为.时,double也会发生同样的情况.

推荐答案

此符号是否被视为整数的开始?如果是这样,为什么这种输入被视为失败?如果不是,为什么会被消费呢?或者这是一种完全没有定义的行为?

以下是从fscanf()起的适用范围:

An input item is read from the stream, ... . An input item is defined as the longest sequence of input characters which does not exceed any specified field width and which is, or is a prefix of, a matching input sequence.348 The first character, if any, after the input item remains unread. If the length of the input item is zero, the execution of the directive fails; this condition is a matching failure ... .
C23dr § 7.23.6.2 9

348 fscanf pushes back at most one input character onto the input stream. Therefore, some sequences that are acceptable to strtod, strtol, etc., are unacceptable to fscanf.

在我阅读本文时,OP的输入为"-*",直到读取了'*',scanf()才意识到输入匹配失败,并将'*'推回到stdin(按照规范的要求).Some系统将成功地将'-'也推回(请注意,脚注本身是信息性的--而不是规范.),但OP的系统没有.

Moral of the story:
(f)scanf() is difficult to use with faulty input. Instead for line input, use fgets() to read the line into a string and then parse the string.


请注意,还会使用可选的前导空格字符(带有"%d").

注意,有更长的输入序列,如"-.*"对应"%f",这会导致问题.

C++相关问答推荐

为指针 struct 创建宏

如何启用ss(另一个调查套接字的实用程序)来查看Linux主机上加入的多播组IP地址?

如何避免重新分配指针数组时,我们从一开始就不知道确切的大小

VS代码C/C++扩展intellisense无法检测环境特定函数'

va_copy的使用是未定义的行为吗?

使用GOTO从多个嵌套循环C继续

如何在C客户端应用程序的ClientHello消息中添加自定义扩展?

X86/x64上的SIGSEGV,由于原始内存访问和C中的DS寄存器之间的冲突,在Linux上用TCC编译为JIT引擎

在 struct 中强制转换空指针

S将C语言宏定义为自身的目的是什么?(在glibc标题中看到)

GCC奇怪的行为,有fork 和印花,有换行符和不换行符

可变宏不能编译

For循环不会迭代所有字符串字符吗?(初学者问题)

在运行时判断C/C++指针是否指向只读内存(在Linux操作系统中)

隐藏测试用例无法在c程序中计算位数.

C编译和运行

发送和接收的消息中的Unix域套接字不匹配

RISC-V GCC编译器错误编译ASM代码

分支预测和UB(未定义的行为)

在链表中插入一个值