在下面的代码中,指针值和指针地址与预期不同。
但是数组值和地址不是!
这怎么可能呢?
输出
my_array = 0022FF00
&my_array = 0022FF00
pointer_to_array = 0022FF00
&pointer_to_array = 0022FEFC
#include <stdio.h>
int main()
{
char my_array[100] = "some cool string";
printf("my_array = %p\n", my_array);
printf("&my_array = %p\n", &my_array);
char *pointer_to_array = my_array;
printf("pointer_to_array = %p\n", pointer_to_array);
printf("&pointer_to_array = %p\n", &pointer_to_array);
printf("Press ENTER to continue...\n");
getchar();
return 0;
}
当您查看数组的内存布局时,就很容易理解为什么my_array和&my_array会产生相同的地址。
假设您有一个10个字符的数组(而不是代码中的100个字符)。
char my_array[10];
my_array的内存如下所示:
+---+---+---+---+---+---+---+---+---+---+
| | | | | | | | | | |
+---+---+---+---+---+---+---+---+---+---+
^
|
Address of my_array.
在C/ c++中,数组衰减为指向表达式中第一个元素的指针,例如
printf("my_array = %p\n", my_array);
如果你检查数组的第一个元素所在的位置,你会发现它的地址与数组的地址相同:
my_array[0]
|
v
+---+---+---+---+---+---+---+---+---+---+
| | | | | | | | | | |
+---+---+---+---+---+---+---+---+---+---+
^
|
Address of my_array[0].
在C语言中,当您在表达式中使用数组的名称(包括将其传递给函数)时,除非它是address-of(&)操作符或sizeof操作符的操作数,否则它将衰减为指向其第一个元素的指针。
也就是说,在大多数情况下,array在类型和值上都等同于&array[0]。
在你的例子中,my_array的类型是char[100],当你把它传递给printf时,它会衰减为char*类型。
&my_array类型为char(*)[100](指向100个char的数组的指针)。由于它是&的操作数,这是my_array不会立即衰减为指向其第一个元素的指针的情况之一。
指向数组的指针与指向数组第一个元素的指针具有相同的地址值,因为数组对象只是其元素的连续序列,但指向数组的指针与指向该数组的元素的指针具有不同的类型。在对这两种类型的指针进行指针算术时,这很重要。
Pointer_to_array的类型是char *——初始化为指向数组的第一个元素,因为my_array在初始化表达式中衰减为这个元素——而&pointer_to_array的类型是char **(指向一个char指针的指针)。
其中:my_array(在衰减为char*之后),&my_array和pointer_to_array都直接指向数组或数组的第一个元素,因此具有相同的地址值。
当您查看数组的内存布局时,就很容易理解为什么my_array和&my_array会产生相同的地址。
假设您有一个10个字符的数组(而不是代码中的100个字符)。
char my_array[10];
my_array的内存如下所示:
+---+---+---+---+---+---+---+---+---+---+
| | | | | | | | | | |
+---+---+---+---+---+---+---+---+---+---+
^
|
Address of my_array.
在C/ c++中,数组衰减为指向表达式中第一个元素的指针,例如
printf("my_array = %p\n", my_array);
如果你检查数组的第一个元素所在的位置,你会发现它的地址与数组的地址相同:
my_array[0]
|
v
+---+---+---+---+---+---+---+---+---+---+
| | | | | | | | | | |
+---+---+---+---+---+---+---+---+---+---+
^
|
Address of my_array[0].
数组的名称通常计算为数组的第一个元素的地址,因此array和&array具有相同的值(但类型不同,因此如果数组长度超过1个元素,则array+1和&array+1将不相等)。
有两个例外:当数组名是sizeof或一元& (address-of)的操作数时,该名称指的是数组对象本身。因此sizeof array给出了整个数组的字节大小,而不是指针的大小。
对于定义为T array[size]的数组,它的类型为T *。当/如果你增加它,你会得到数组中的下一个元素。
&array的计算结果是相同的地址,但是给出了相同的定义,它创建了一个类型为T(*)[size]的指针——也就是说,它是指向数组的指针,而不是指向单个元素的指针。如果你增加这个指针,它会增加整个数组的大小,而不是单个元素的大小。例如,使用这样的代码:
char array[16];
printf("%p\t%p", (void*)&array, (void*)(&array+1));
我们可以预期第二个指针比第一个指针大16(因为它是一个包含16个字符的数组)。由于%p通常以十六进制形式转换指针,它可能看起来像这样:
0x12341000 0x12341010