一个数组的地址是如何等于它在C中的值?
在下面的代码中,指针值和指针地址与预期不同。
但数组值和地址不!
这怎么可能?
产量
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; }
数组的名称通常是数组的第一个元素的地址,所以array
和&array
的值是相同的(但是不同的types,所以如果数组大于1, array+1
和&array+1
将不相等)元素长)。
有两个例外:当数组名称是sizeof
或一元&
(地址 – )的操作数时,名称引用数组对象本身。 因此sizeof array
给你的是整个数组的字节大小,而不是指针的大小。
对于定义为T array[size]
,它将具有typesT *
。 当/如果你增加它,你到达数组中的下一个元素。
&array
求值到相同的地址,但给定相同的定义,它会创build一个types为T(*)[size]
的指针,即它是一个指向数组的指针,而不是单个元素。 如果你增加这个指针,它将增加整个数组的大小,而不是单个元素的大小。 例如,用这样的代码:
char array[16]; printf("%p\t%p", (void*)&array, (void*)(&array+1));
我们可以期望第二个指针比第一个大16(因为它是16个char的数组)。 由于%p通常以hex转换指针,因此可能如下所示:
0x12341000 0x12341010
这是因为数组名 ( my_array
)不同于指向数组的指针。 它是数组地址的别名,其地址被定义为数组本身的地址。
然而,指针是堆栈上的一个普通的Cvariables。 因此,你可以把它的地址从它所保存的地址中得到一个不同的值。
我在这里写了这个话题 – 请看看。
在C中,当你在一个expression式中使用一个数组的名称(包括将它传递给一个函数),除非它是( &
)的运算符或sizeof
运算符的操作数,它会衰减到一个指向它的第一个元件。
也就是说,在大多数情况下, array
在数据types和数值上都等同于&array[0]
。
在你的例子中, my_array
types为char[100]
,当你将它传递给printf的时候它会衰减到char*
。
&my_array
types是char (*)[100]
(指向100个char
数组)。 因为它是&
的操作数,所以这是my_array
不会立即衰减到第一个元素的指针的情况之一。
指向数组的指针与指向数组第一个元素的指针具有相同的地址值,因为数组对象只是其元素的连续序列,但指向数组的指针的types与指向元素的指针的types不同那个数组。 对两种types的指针进行指针运算时,这一点很重要。
pointer_to_array
types为char *
– 初始化为指向数组的第一个元素,因为my_array
会在初始化expression式中衰减 – 而&pointer_to_array
types为char **
(指向char **
的指针)。
其中: my_array
(衰减到char*
), &my_array
和pointer_to_array
都直接指向数组或数组的第一个元素,因此具有相同的地址值。
从comp.lang.c FAQ:
- 那么C中“指针和数组的等价性”是什么意思呢?
- 由于数组引用衰减为指针,如果arr是一个数组,arr和&arr之间有什么区别?
或者阅读整个数组和指针部分。
当您查看数组的内存布局时,可以很容易地理解为什么my_array
和&my_array
导致相同的地址。
假设您有10个字符的数组(而不是您的代码中的100个)。
char my_array[10];
my_array
内存看起来像这样:
+---+---+---+---+---+---+---+---+---+---+ | | | | | | | | | | | +---+---+---+---+---+---+---+---+---+---+ ^ | Address of my_array.
在C / C ++中,数组会衰减到指针,如expression式中的第一个元素
printf("my_array = %p\n", my_array);
如果您检查数组的第一个元素的位置,您将看到它的地址与数组的地址相同:
my_array[0] | v +---+---+---+---+---+---+---+---+---+---+ | | | | | | | | | | | +---+---+---+---+---+---+---+---+---+---+ ^ | Address of my_array[0].
在C语言的前身B语言中,指针和整数是可以自由互换的。 该系统的行为就像所有的内存都是一个巨大的arrays。 每个variables名都有一个全局或相对地址的地址,每个variables名只有编译器必须跟踪的东西是全局variables还是局部variables,以及它的地址是相对于第一个全局variables还是本地variablesvariables。
鉴于像i;
这样的全球性声明i;
[无需指定types,因为所有东西都是整数/指针]将被编译器处理为: address_of_i = next_global++; memory[address_of_i] = 0;
address_of_i = next_global++; memory[address_of_i] = 0;
像i++
这样的语句会被处理为: memory[address_of_i] = memory[address_of_i]+1;
。
像arr[10];
这样的声明arr[10];
将被处理为address_of_arr = next_global; memory[next_global] = next_global; next_global += 10;
address_of_arr = next_global; memory[next_global] = next_global; next_global += 10;
。 请注意,一旦声明被处理, 编译器可以立即忘记arr
是一个数组 。 像arr[i]=6;
将作为memory[memory[address_of_a] + memory[address_of_i]] = 6;
处理memory[memory[address_of_a] + memory[address_of_i]] = 6;
。 编译器不会在乎arr
表示一个数组,而i
是一个整数,反之亦然。 实际上,它不会在意它们是数组还是两个整数; 它会非常愉快地生成所描述的代码,而不考虑是否可能有用的结果行为。
C程序devise语言的目标之一是在很大程度上与B兼容。在B中,一个数组的名称(在B术语中称为“向量”)标识了一个variables,该variables保存了一个指针,该指针最初被指定指向到给定大小的分配的第一个元素,所以如果这个名字出现在函数的参数列表中,函数将接收到一个指向该向量的指针。 即使C添加了“真实”的数组types,其名称与分配的地址严格相关,而不是最初指向分配的指针variables,将数组分解为指针,使声明Ctypes数组的代码具有相同的行为B代码声明一个向量,然后从来没有修改variables保持其地址。
其实&myarray
和myarray
都是基地址。
如果你想看到的差异,而不是使用
printf("my_array = %p\n", my_array); printf("my_array = %p\n", &my_array);
使用
printf("my_array = %s\n", my_array); printf("my_array = %p\n", my_array);