此代码崩溃:
scanf_s("%c %d",&ch,&x);//Run error
但是此代码有效:
scanf_s("%c",&ch);
scanf_s("%d",&x);//Run succeed
我想知道为什么第一个代码片段是错误的。
“运行错误”表示 运行程序输入时,编译器发出警告,并且出了一些问题
答案 0 :(得分:3)
在使用scanf_s
时(与scanf
相反),您需要为%c
提供一个附加的长度参数(例如,来自this的文档微软关于scanf_s
):
与scanf和wscanf不同,scanf_s和wscanf_s要求您指定 一些参数的缓冲区大小。指定所有c,C,s的大小 S,或字符串控件设置的[]参数。
所以您必须写
scanf_s ("%c %d", &ch, 1, &x);
表示第一个%c
最多只能读取一个字符。
请注意,scanf_s("%c",&ch);
也会发出相同的警告/错误,因为它也缺少%c
的强制长度参数。
命令scanf_s("%d",&x);
可以,因为%d
不需要(不必提供)附加的长度参数。
答案 1 :(得分:2)
我假设您正在运行MSVC,如果您使用scanf
而不是scanf_s
,则会出现错误。我还假设您要使用前者而不是后者。要禁用该错误,请转到项目菜单-> [项目名称]属性-> C / C ++->预处理程序。在“预处理程序定义”字段中,添加宏_CRT_SECURE_NO_WARNINGS
。然后点击“应用”。
现在,您应该可以像在其他任何编译器/ IDE上一样使用scanf
。
答案 2 :(得分:0)
作为the answer by Stephan Lechner的扩展,请考虑执行scanf_s("%c %d",&ch,&x)
时会发生什么。
从技术上讲,这是未定义的行为,因为您没有为scanf_s
指定正确的参数。
但是,实际上,代码将尝试将内存中的垃圾值解释为缺少的参数。也就是说,代码等效于以下内容:
scanf_s("%c %d", &ch, 0xf0000000, 0xdeadbeef);
此处0xf0000000
代表变量x
的地址。 scanf_s
的代码会将其解释为缓冲区大小(一个非常大的缓冲区),但这没有效果,因为%c
告诉它只能读取一个字节。此外,0xdeadbeef
代表垃圾,代码将其解释为写入整数结果的地址。写入随机地址是一个很大的禁忌,因此会崩溃。
当您的代码分别读取char
和int
时,它再也不会遇到写入随机地址的问题,因此一切正常,如果忽略编译器警告,您永远不会知道代码是越野车。