C 为什么数组的名称、地址和数组的值都是相同的?
这是一个二维数组。我知道数组的名称指向数组中的第一个元素,即&array[0][0]。但是当我尝试打印时,数组的名称、数组的地址和数组的值都是相同的C 为什么数组的名称、地址和数组的值都是相同的?,c,arrays,memory-address,C,Arrays,Memory Address,这是一个二维数组。我知道数组的名称指向数组中的第一个元素,即&array[0][0]。但是当我尝试打印时,数组的名称、数组的地址和数组的值都是相同的 #include <stdio.h> int main(void) { int array[4][2]={1,2,3,4,5,6,7,8}; printf("%d %d\n", &array[0][0], array[0][0]); printf("%d %d %d
#include <stdio.h>
int main(void)
{
int array[4][2]={1,2,3,4,5,6,7,8};
printf("%d %d\n",
&array[0][0], array[0][0]);
printf("%d %d %d %d\n",
array, &array, *array, **array);
}
您没有指针变量。它是一个数组(表达式),在大多数上下文中,它在内部转换为第一个元素的地址 指针应该是
int(*arrptr)[4][2]=&array代码>。这种差异在本文中得到了很好的解释
在这里,您可以看到指针在堆栈中是一个不同的地址,而静态指针在堆中是一个更为不同的地址。数组的内部表示如下所示。数组只是常量指针。它们表示为连续内存位置
因此,如果我们以A[1]
的形式访问数组,它将转换为*(A+1)
,即A
这里指向第一个元素的地址,1表示偏移量。如果数组是<代码> int <代码>,那么1代表<<代码>代码> >代码>。因此,4个字节被添加到A
,现在它将指向数组A
中的第二个元素。因此,在2D数组中,它将表示为*(*(A+i)+j)
,其中i
是行,j
是列。因此,在此基础上,您将在代码中获得上述输出(已更正):
应向您发出警告,同时:
int (*p)[2] = array;
不应该
然而,由于数组在内存中的布局方式,array
的地址与array[0]
的地址相同,后者与array[0][0]
的地址相同
&array
是数组的地址,它与其第一个元素的地址相同…依此类推
*数组
相当于数组[0]
。数组[0]
的类型是大小为2
的int
数组。由于数组[0]
本身就是一个数组,因此它在此处也会衰减为指向其第一个元素的指针,正如所解释的那样,该元素与数组
的地址相同,而数组
的地址在此处衰减为
**array
相当于数组[0][0]
,它最后是一个实际的int
,而不是数组,因此不会衰减到任何类型的地址,它只是值1
这就是为什么前三个表达式都计算到相同的地址
请注意,%p
用于指针,由于printf()
是一个可变函数,编译器无法像通常那样将指针隐式转换为void*
,因为它不知道printf()
需要void*
作为%p
说明符,因此,您应该显式地将它们强制转换为void*
。实际上,你可能要花很长时间才能找到一台现代台式计算机,其中void*
、int*
、int(*)[2]
、和int(*)[4][2]
没有完全相同的表示形式,但正确总比不正确好。它们不是一回事
数组是由一个或多个连续元素的序列组成的对象,所有元素都是相同类型的。二维数组就是数组的数组
数组的名称是一个表达式。与任何数组类型的表达式一样,它在大多数(但不是所有)上下文中隐式转换为指向数组第一个元素的指针。例外情况是当它是sizeof
的操作数时(sizeof arr
产生数组对象的大小,而不是指针的大小),以及当它是一元和
的操作数时(&arr
产生整个数组的地址)
数组的地址类似于任何对象的地址。它引用一个特定的内存地址,它有一个类型:指向数组类型的指针。例如,假设:
int arr[10];
表达式arr
(如果它不是&
或sizeof
的操作数)生成arr[0]
,类型为int*
。表达式&arr
生成整个数组的地址;它是相同的内存位置,但类型为int(*)[10]
,或“指向10int
s数组的指针”
数组的值通常不是您可以直接引用的值。它由数组元素的值组成
现在让我们看看您的程序:
#include <stdio.h>
int main(void)
{
int array[4][2]={1,2,3,4,5,6,7,8};
#include <stdio.h>
int main(void)
{
int array[4][2] = {{1, 2}, {3, 4}, {5, 6}, {7, 8}};
printf("%p %d\n",
(void*)&array[0][0], array[0][0]);
printf("%p %p %p %d\n",
(void*)array, (void*)&array, (void*)*array, **array);
}
array[0][0]
是一个int
对象,因此&array[0][0]
是它的地址,类型为int*
。打印地址(指针值)的正确方法是使用%p
格式;它需要一个类型为void*
的参数,因此您应该转换它
printf("%p %d\n", (void*)&array[0][0], array[0][0]);
printf("%d %d %d %d\n",
array, &array, *array, **array);
array
是数组类型的表达式,因此它“衰减”到指向该数组第一个元素的指针。该元素的类型为int[2]
,因此指针的类型为int(*)[2]
。同样,您应该使用%p
并转换为void*
&array
是整个数组的地址。它的类型是int(*)[4][2]
在*array
中,子表达式array
衰减为指针*
然后取消对该指针的引用,这将为我们提供一个类型为int[2]
的对象(数组的第一个元素)。这是一个数组类型的表达式,所以它再次衰减为指向该数组第一个元素的指针。它的类型是int*
在**数组
中,*数组
的评估如上所述;它是指向int
对象的指针。下一个*
取消对
int arr[10];
#include <stdio.h>
int main(void)
{
int array[4][2]={1,2,3,4,5,6,7,8};
int array[4][2] = {{1, 2}, {3, 4}, {5, 6}, {7, 8}};
printf("%d %d\n",
&array[0][0], array[0][0]);
printf("%p %d\n", (void*)&array[0][0], array[0][0]);
printf("%d %d %d %d\n",
array, &array, *array, **array);
}
#include <stdio.h>
int main(void)
{
int array[4][2] = {{1, 2}, {3, 4}, {5, 6}, {7, 8}};
printf("%p %d\n",
(void*)&array[0][0], array[0][0]);
printf("%p %p %p %d\n",
(void*)array, (void*)&array, (void*)*array, **array);
}