最近的一个问题促成了以数组和指针为中心的讨论。 问题是参考scanf("%s", &name)
vs scanf("%s", name)
。
对于以下代码,Microsoft实际上在VS2010(也许是早期版本?)中为您解决了这个问题,
#include int main() { char name[30]; printf("Scan "name" - "); scanf("%s", name); printf("Print "&name" - %sn", &name); printf("Print "name" - %sn", name); printf("Pointer to &name - %pn", &name); printf("Pointer to name - %pn", name); printf("nn"); printf("Scan "&name" - "); scanf("%s", &name); printf("Print "&name" - %sn", &name); printf("Print "name" - %sn", name); printf("Pointer to &name - %pn", &name); printf("Pointer to name - %pn", name); return 0; }
这实际上是在ANSI C标准中定义的,还是允许编译器相关的? 这是否有效,因为MS将所有内容都视为C ++? 请暂时忽略缓冲区溢出问题。
name
和&name
都应该给出相同的结果。 严格来说,只有name
根据C语言标准有效且&name
导致未定义的行为,因此您绝对应该使用name
,但实际上两者都有效。
name
是一个数组,因此当你将它用作函数的参数时(就像你将它传递给printf
),它会“衰减”到指向其初始元素的指针(这里是一个char*
)。
&name
为您提供数组的地址; 此地址与初始元素的地址相同(因为在数组的初始元素之前或数组中的元素之间不能有填充字节),因此&name
和name
具有相同的指针值。
但是,它们有不同的类型: &name
是char (*)[30]
类型char (*)[30]
(指向30个char
的数组的指针)而name
,当它衰减到指向其初始元素的指针时,类型为char*
(指针)到一个char
,在这种情况下,是数组name
的初始char
元素)。
由于它们具有相同的值,并且由于printf
和scanf
函数无论如何都将参数重新解释为char*
,因此传递name
或&name
应该没有区别。
根据标准的未定义行为。
printf转换说明符"%p"
需要void*
:其他任何内容调用UB printf转换说明符"%s"
需要一个char*
,它包含指向对象内部某处的空字节:其他任何调用UB scanf转换说明符"%s"
期望一个char*
具有足够的空间用于输入和一个额外的空终止字节:其他任何东西调用UB
如果任何实现定义了行为,那么在该实现中应该可以使用它 。
通常使用printf("%p")
打印char*
或char(*)[30]
而不是void*
导致UB表现与预期行为无法区分。
通常使用printf("%s")
打印char(*)[30]
而不是char*
导致UB表现与预期行为无法区分。
根据你的说法,在这些情况下,UB的MS表现与预期相同。
但它仍然是未定义的行为。
需要了解更多c/c++开发分享&C中数组的运算符定义,也可以关注C/ C++技术分享栏目—计算机技术网(www.ctvol.com)!
以上就是c/c++开发分享&C中数组的运算符定义相关内容,想了解更多C/C++开发(异常处理)及C/C++游戏开发关注计算机技术网(www.ctvol.com)!)。
本文来自网络收集,不代表计算机技术网立场,如涉及侵权请联系管理员删除。
ctvol管理联系方式QQ:251552304
本文章地址:https://www.ctvol.com/c-cdevelopment/979541.html