为什么scanf()不会对数组和&数组进行相同处理?

时间:2014-07-04 12:54:13

标签: c arrays pointers scanf fread

我写了这个简单的程序

#include <stdio.h>

int main(void)
{
    int array[10];

    printf("sizeof(array):  %lu\n", sizeof(array));
    printf("sizeof(&array): %lu\n", sizeof(&array));

    printf("array:          %p\n", array);
    printf("&array:         %p\n", &array);

    printf("value:          ");
    scanf("%d", array); // 1
    //scanf("%d, &array"); // 2
}

输出:

sizeof(array):  40
sizeof(&array): 8
array:          0x7fffaab6f480
&array:         0x7fffaab6f480
value:          10

当我使用 1 时编译。但是,当我使用 2

时,它不会

我收到此编译警告

warning: format ‘%d’ expects argument of type ‘int *’, but argument 2 has type 
‘int (*)[10]’ [-Wformat=]
  scanf("%d", &array);
  ^

虽然array&array具有相同的值,但它们在我的系统上具有不同的大小(分别为 40 8 )。

另一方面,这段代码

int array[10];
fread(&array, x, y, z);

编译并完美地工作

int array[10];
fread(array, x, y, z);

我在警告消息中注意到&array的类型为int (*)[10]。这是什么意思?

我也相信我对fread()没有麻烦,因为它接受了void *,但是scanf()呢?它如何区分指针类型?

为什么它不将array视为&array,即使它们实际上具有相同的值?

4 个答案:

答案 0 :(得分:3)

数组衰减到指针,因此使用数组作为参数与将指针传递给第一个元素相同。

当你执行&array时,你得到一个指向数组的指针(int (*)[10]的东西),而不是指向整数的指针。

答案 1 :(得分:2)

对于scanfprintf系列,您必须传递他们期望的确切类型(在应用默认参数提升后 - 但在此示例中不相关)。

这是因为参数对应于原型中的...,这意味着编译器不会尝试将您的参数转换为期望的类型。如果你使用了错误的类型,你就会得到未定义的行为。

第二种情况scanf("%d", &array)会发生这种情况。如您的示例所示,&array 的类型为int *,因此行为未定义。

实际上,如果你的编译器对int *使用与int (*)[10]相同的表示形式,那么它很可能会工作,所有现代编译器都会使用AFAIK。但是,当然,您不应该依赖未定义的行为,尤其是在可以轻松修复的情况下。

fread示例中,它与原型参数void *匹配。因此,编译器将您的参数转换为void *。由于数组的第一个元素与数组本身位于相同的内存地址(void *)&array == (void *)array,即使array&array具有不同的类型(甚至可能是不同的表示形式),它们都是指向相同的内存地址。

答案 2 :(得分:0)

两者在语法上都是正确的C,并且完全按照你的建议做同样的事情。但是,其中一个更多正确。也就是说,两者都不完美。

要适当迂腐,你应该这样:

scanf("%d", &array[0]);

..因为这是一个指向整数array[0]的指针,以及你真正想要的东西。

实际上,您可以将任何传递给scanf(如果忽略文档),并且编译器应该接受它(滥用标准传统上不会触发错误)。如果你传递了一些无效的东西,那么你的程序应该会在运行时失败(或者,如果你很幸运,那么未定义的行为就是这样)。

但是,您的编译器正在尝试提供帮助并为您解释scanf格式字符串,以确保您做的正确,但如果您仔细查看,则错误,这是一个警告。如果你愿意,你可以随意忽略它。

你没有得到fread错误的原因是因为该函数不采用整数,它需要void *,并且两种形式都可以很容易地转换为该类型。 / p>

答案 3 :(得分:0)

首先,您的程序编译得非常好 - 警告不是错误。

警告消息告诉您格式和类型不匹配:“%d”格式需要int *,但您发送了&array,其类型为int (*)[10]


arrayint的10长度数组。它的类型是int [10]。但是,数组可以转换为指针,即&array[0]

当您尝试将数组传递给函数时,实际上传递了一个指针&array[0]。所以这个代码都是

printf("%d", array);
scanf("%d", array);

和另一个代码

printf("%d", &array[0]);
scanf("%d", &array[0]);

是一样的。

现在让我们看看另一件事&array。它的类型是int (*)[10],即指向数组的指针

当然,&array[0]&array的实际值相同,但它们具有不同的类型。所以他们是不同的东西,因为'A'65是不同的。

尽管它看起来没问题,因为价值相同,我认为这不是一个好习惯 - 使用array&array[0]