我写了这个简单的程序
#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
,即使它们实际上具有相同的值?
答案 0 :(得分:3)
数组衰减到指针,因此使用数组作为参数与将指针传递给第一个元素相同。
当你执行&array
时,你得到一个指向数组的指针(int (*)[10]
的东西),而不是指向整数的指针。
答案 1 :(得分:2)
对于scanf
和printf
系列,您必须传递他们期望的确切类型(在应用默认参数提升后 - 但在此示例中不相关)。
这是因为参数对应于原型中的...
,这意味着编译器不会尝试将您的参数转换为期望的类型。如果你使用了错误的类型,你就会得到未定义的行为。
第二种情况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]
。
array
是int
的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]
。