C语言中 数组名何时代表数组首元素地址的指针何时代表整个数组

问题如题,代码中有注释

#include

#define SIZE 4

int sum(int marbles1[], int n);

int main(void)

{
int answer;
int marbles[SIZE] = {20,10,30,40};

printf("The size of marbles is %u bytes.\n", sizeof marbles);
answer =sum(marbles, SIZE);//调用函数

getch();
return 0;

}

int sum(int marbles1[], int n)//如果此处marbles1是指向首元素地址的指针,主函数体中的调用函数中的marbles参量也应该是指针,为什么主函数体中的marbles占字节大小是16----即被认成了整个数组包含了4个整数
{
int i;
int total = 0;

for(i =0;i <n; i++)
    total += marbles1[i];
printf("The size of marbles1 is %u bytes.\n", sizeof marbles1);

return total;

}//以上两个数组名一个marbles,一个marbles1一个结果是16,一个是4;我就想知道,数组名什么时候把它认成指向首元素的地址,什么时候把它认成代表整个数组?图片说明

首先 数组名的值是数组首元素的指针常量,也就是指向数组首元素的指针
第二 对数组名使用sizeof运算符会得到整个数组所占的内存大小,这里还是指的实参
第三 函数调用时,数组名退化成指针,即形参,这时sizeof只能获得指针的大小
所以 你第一次是对一个实参数组名sizeof, 但是第二次只是对一个指向这个数组的指针进行的sizeof

这个题目涉及了至少如下几个知识点。
1,sizeof
详细准确的知识自行百度。它不是函数。叫操作符。
需要强调的是sizeof的计算发生在编译时刻。啥叫编译时刻?就是编译器在读你的代码的时候,就直接转换成了一个数值,然后写到了最终的机器码里去了。
所以这个操作符是编译器根据代码上下文情况来决定应该怎么计算大小。

2,
int marbles[SIZE] = {20,10,30,40};
sizeof(marbles)
在编译时刻,marbles根据上下文,可以得到数组的整个大小。因为此时,编译器明显的知道marbles是什么东西。

但是,当编译这个函数的时候:
int sum(int marbles1[], int n)
{
}
由于函数的参数声明marbles1是个没有元素个数的数组形式,那么编译器不会真的认为marbles真的是数组,而只会将它看作指针。就是一个普通的指针而已。
注意此时跟数组首指针完全没有关系。
如果您定义成这样:
int sum(int marbles1[5])
{
sizeof(marbles1);
}
那么结局可能就不一样了。我只根据理论推导,认为这次就是正常的20,而不再是4.因为这里,编译器明显地知道这就是一个数组,是一个真的数组。

以上,都是编译器关心的。但是程序运行起来之后,情况又变化了。

3,运行后,数组名,仅仅代表数组首地址,不代表什么全部数组。
如下定义了一个函数,要求传递一个数组,3 个元素:
int sum(int m[3]){
}

int main(...){

int marbles[5]={...}

sum(marbles+2); //但是传递的是一个指针,可以吗?
}
代码中的问题,我理论推导,应该是可以的。实地运行代码后证明是对的。您仔细思考,就明白了运行期和编译期,数组名所代表的含义差别了。
数组名在运行期,从来都只代表了数组首地址,不代表什么全部数组。仅仅是在编译期,编译器明白这个名称是数组的时候,知道整个数组大小而已。