c中的数组名称究竟是什么?

dar*_*rix 28 c arrays pointers memory-address

我很难理解C中数组名称的类型和用法.这可能看起来很长,但请耐心等待.

我理解以下语句声明a是类型,int []整数数组.

int a[30];
Run Code Online (Sandbox Code Playgroud)

同时a也指出数组的第一个元素和类似*(a+2)的东西是有效的.因此,a看起来像一个指向整数指针.但实际上类型int []int*不同; 前者是数组类型,后来是指向整数指针.

类型int []变量int*在传递给函数时也会转换为类型变量; 因为C数组是通过引用传递的(sizeof运算符除外).

这就是让我垂涎的观点.看看下面这段代码:

int main()
{
    int (*p)[3];
    int a[3] = { 5, 4, 6 };

    p = &a;

    printf("a:%d\t&a:%d\n",a,&a);
    printf("%d",*(*p + 2));
}
Run Code Online (Sandbox Code Playgroud)

OUTPUT:

a:2686720       &a:2686720
6
Run Code Online (Sandbox Code Playgroud)

那么,上面的代码是如何工作的呢?我有两个问题:

  1. a&a具有相同的值.为什么?
  2. 到底是int (*p)[3];做什么的?它声明了一个指向数组指针,我知道这一点.但是,如何是一个指针数组从不同的阵列的第一个元素的指针所述阵列的名字

任何人都可以澄清一切吗?我有很多困惑.

我知道我应该使用%p占位符而不是%d用于打印指针变量的值.使用整数占位符可能会打印截断的地址.但我只想保持简单.

hac*_*cks 48

其他答案已经解释了这个问题.我试图用一些图解释它.希望这会有所帮助.


声明数组时

int a[3] = {5, 4, 6}  
Run Code Online (Sandbox Code Playgroud)

记忆安排看起来像

在此输入图像描述

现在回答你的问题:

  1. a并且&a具有相同的价值.怎么样?

正如您所知,a数组类型和数组名称a成为指向数组第一个元素的指针a(在衰减之后),即它指向地址0x100.注意,它0x100也是内存块(数组a)的起始地址.你应该知道,通常,第一个字节的地址被称为变量的地址.也就是说,如果变量是100个字节,那么它的地址等于其第一个字节的地址.

&a是整个存储块的地址,即它是数组的地址a.见图:

在此输入图像描述

现在您可以理解为什么a并且&a两者具有相同的地址值,尽管两者的类型不同.

它究竟是什么int (*p)[3];声明一个指向数组的指针,我知道这个.但是,指向数组的指针与指向数组的第一个元素和数组名称的指针有何不同?

参见上图,清楚地解释了指向数组的指针与指向数组元素的指针的不同之处.
分配&ap,然后p指向具有起始地址的整个数组0x100.


注意:关于线路

...在C数组中通过引用传递(sizeof函数除外).

在C中,参数按值传递.C中没有通过引用传递.当普通变量传递给函数时,其值被复制 ; 对相应参数的任何更改都不会影响变量.
数组也通过值传递,但区别在于数组名称衰减到指向第一个元素的指针,并且该指针分配给函数的参数(这里,指针值被复制); 数组本身不会被复制.
相比于普通变量,作为自变量的阵列无法防止发生任何变化,因为没有复制由与阵列本身的,对第一元件由代替指针的复制.

您还应该注意,这sizeof不是函数,在这种情况下,数组名称不作为参数.sizeof运算符,数组名称用作操作数.当数组名是一元运算&符的操作数时,同样适用.

  • 奇怪的是,我找不到"*第一个*字节的地址被称为变量的地址"这一陈述的任何"合法"基础.当然,我无法想到实现设计师以其他方式实现它的实际原因,但据我所知,标准并没有禁止这样做.因此,从纯粹的角度来看,`printf("a:%p\t&a:%p \n",reinterpret_cast <void*>(a),reinterpret_cast <void*>(&a));`*可能*打印两个不同的价值观 (2认同)
  • @haccks,你还没有明白我的观点.标准从未定义对象的地址.实现将其定义为为对象保留的内存位置的*first*字节的地址是很自然的.但是假设一个厌恶的设计者希望将它定义为*last*字节的地址.标准中是否有任何条款禁止这样做?据我所见,没有.当然,某些类型转换(包括数组类型衰减)必须调整地址,但如果准确完成,则将保留定义的语义. (2认同)

oua*_*uah 16

  1. a和&a有相同的值.怎么样?

它们具有相同的值但不同的类型.数组对象在元素之间(之前或之后)没有填充,因此数组的地址和数组的第一个元素的地址是相同的.

那是:

(void *) a == (void *) &a
Run Code Online (Sandbox Code Playgroud)
  1. 它究竟是做什么int(*p)[3]; 声明一个指向数组的指针,我知道这个.但是,指向数组的指针与指向数组的第一个元素的指针和数组的名称有何不同?

这是两种不同的指针类型.以比例算术为例:

a + 1   /* address of the second element of the array */
&a + 1  /* address one past the last element of the array */
Run Code Online (Sandbox Code Playgroud)

编辑:由于受欢迎的需求,我在下面添加了一些有关数组转换的信息.

除了三个例外,在表达式中,将array类型的对象T转换为T指向数组的第一个元素的类型指针的值.例外情况是对象是操作数sizeof&一元运算符,或者对象是初始化数组的字符串文字.

例如这句话:

printf("a:%d\t&a:%d\n", a, &a);
Run Code Online (Sandbox Code Playgroud)

实际上相当于:

printf("a:%d\t&a:%d\n", &a[0], &a);
Run Code Online (Sandbox Code Playgroud)

另请注意,d转换说明符只能用于打印有符号整数; 要打印指针值,你必须使用p说明符(并且参数必须是void *).所以要正确使用:

printf("a:%p\t&a:%p\n", (void *) a, (void *) &a);
Run Code Online (Sandbox Code Playgroud)

分别:

printf("a:%p\t&a:%p\n", (void *) &a[0], (void *) &a);
Run Code Online (Sandbox Code Playgroud)

  • 无法解释数组表达式到指向其第一个元素的指针的隐式转换,以及不会发生转换的情况. (9认同)
  • @JeffD.如果`int*p; p =&a;`是无效的C代码. (2认同)