&安培; C中数组的运算符定义

时间:2011-05-01 20:28:28

标签: c arrays pointers standards

最近的一个问题引发了一场以数组和指针为中心的讨论。问题是参考scanf("%s", &name) vs scanf("%s", name)

对于以下代码,Microsoft实际上在VS2010中解决了这个问题(也许是早期版本?),

#include <stdio.h>

int main()
{
    char name[30];

    printf("Scan \"name\" - ");
    scanf("%s", name);
    printf("Print \"&name\" - %s\n", &name);
    printf("Print \"name\"  - %s\n", name);

    printf("Pointer to &name - %p\n", &name);
    printf("Pointer to name  - %p\n", name);

    printf("\n\n");

    printf("Scan \"&name\" - ");
    scanf("%s", &name);
    printf("Print \"&name\" - %s\n", &name);
    printf("Print \"name\"  - %s\n", name);

    printf("Pointer to &name - %p\n", &name);
    printf("Pointer to name  - %p\n", name);

    return 0;
}

这实际上是在ANSI C标准中定义的,还是允许编译器依赖?这是否有效,因为MS将所有内容都视为C ++?请暂时忽略缓冲区溢出问题。

2 个答案:

答案 0 :(得分:7)

name&name都应该给出相同的结果。严格来说,只有name符合C语言标准且&name会导致未定义的行为,因此您绝对应该使用name,但实际上两者都有效。

name是一个数组,因此当你将它用作函数的参数时(就像你将它传递给printf时那样),它会“衰减”到指向其初始元素的指针(这里是char*)。

&name为您提供数组的地址;此地址与初始元素的地址相同(因为在数组的初始元素之前或数组中的元素之间不能有填充字节),因此&namename具有相同的地址指针值。

但是,它们有不同的类型:&name类型为char (*)[30](指向30 char的数组的指针)而name,当它衰减到指针时其初始元素的类型为char*(指向char的指针,在本例中为数组char的初始name元素)。

由于它们具有相同的值,并且由于printfscanf函数无论如何都将参数重新解释为char*,因此无论您是否通过name&name

答案 1 :(得分:2)

根据标准的未定义行为。

printf转换说明符"%p"需要void*:其他任何内容都会调用UB printf转换说明符"%s"期望char*包含指向对象内某处的空字节:其他任何调用UB scanf转换说明符"%s"期望char*具有足够的空间用于输入和额外的空终止字节:其他任何调用UB

如果任何实现定义了行为,那么可以在该实现中使用

通常使用char*打印char(*)[30]void*而不是printf("%p")会导致与预期行为无法区分的UB表现形式。

通常使用char(*)[30]打印char*而不是printf("%s")会导致UB表现形式与预期行为无法区分。

根据您的说法,在这些情况下,UB的MS表现与预期相同。

但它仍然是未定义的行为。