在下面的代码中,指针值和指针地址与预期不同。
但是数组值和地址不是!
这怎么可能呢?
输出
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].
B语言是C语言的前身,
指针和整数可以自由互换。系统会表现为
尽管所有的内存都是一个巨大的数组。每个变量名都有一个全局变量名
或堆栈相对地址
与之相关的是,对于每个变量名,编译器唯一需要跟踪的是它是全局变量还是局部变量,以及它相对于第一个全局变量或局部变量的地址。
给定一个像i这样的全局声明;[不需要指定类型,因为所有内容都是整数/指针]将由
编译器:address_of_i = next_global++;内存[address_of_i] = 0;像i++这样的语句将被处理为:memory[address_of_i] = memory[address_of_i]+1;
A declaration like arr[10]; would be processed as address_of_arr = next_global; memory[next_global] = next_global; next_global += 10;. Note that as soon as that declaration was processed, the compiler could immediately forget about arr being an array. A statement like arr[i]=6; would be processed as memory[memory[address_of_a] + memory[address_of_i]] = 6;. The compiler wouldn't care whether arr represented an array and i an integer, or vice versa. Indeed, it wouldn't care if they were both arrays or both integers; it would perfectly happily generate the code as described, without regard for whether the resulting behavior would likely be useful.
One of the goals of the C programming language was to be largely compatible with B. In B, the name of an array [called a "vector" in the terminology of B] identified a variable holding a pointer which was initially assigned to point to to the first element of an allocation of the given size, so if that name appeared in the argument list for a function, the function would receive a pointer to the vector. Even though C added "real" array types, whose name was rigidly associated with the address of the allocation rather than a pointer variable that would initially point to the allocation, having arrays decompose to pointers made code which declared a C-type array behave identically to B code which declared a vector and then never modified the variable holding its address.
在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