在 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;
}
In the following bit of code, pointer values and pointer addresses differ as expected.
But array values and addresses don't!
How can this be?
Output
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;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
数组的名称通常计算为数组第一个元素的地址,因此
array
和&array
具有相同的值(但类型不同,因此如果数组长度超过 1 个元素,>array+1
和&array+1
将不相等。有两个例外:当数组名称是
sizeof
或一元&
(address-of) 的操作数时,名称指的是数组对象本身。因此,sizeof array
为您提供整个数组的大小(以字节为单位),而不是指针的大小。对于定义为
T array[size]
的数组,其类型为T *
。当/如果你增加它,你就会到达数组中的下一个元素。&array
求值为相同的地址,但给定相同的定义,它创建一个类型为T(*)[size]
的指针——即,它是一个指针到一个数组,而不是单个元素。如果增加此指针,它将添加整个数组的大小,而不是单个元素的大小。例如,对于这样的代码:我们可以预期第二个指针比第一个指针大 16(因为它是一个 16 个字符的数组)。由于 %p 通常将指针转换为十六进制,因此它可能看起来像:
The name of an array usually evaluates to the address of the first element of the array, so
array
and&array
have the same value (but different types, soarray+1
and&array+1
will not be equal if the array is more than 1 element long).There are two exceptions to this: when the array name is an operand of
sizeof
or unary&
(address-of), the name refers to the array object itself. Thussizeof array
gives you the size in bytes of the entire array, not the size of a pointer.For an array defined as
T array[size]
, it will have typeT *
. When/if you increment it, you get to the next element in the array.&array
evaluates to the same address, but given the same definition, it creates a pointer of the typeT(*)[size]
-- i.e., it's a pointer to an array, not to a single element. If you increment this pointer, it'll add the size of the entire array, not the size of a single element. For example, with code like this:We can expect the second pointer to be 16 greater than the first (because it's an array of 16 char's). Since %p typically converts pointers in hexadecimal, it might look something like:
这是因为数组名称 (
my_array
) 与指向数组的指针不同。它是数组地址的别名,其地址被定义为数组本身的地址。然而,该指针是堆栈上的普通 C 变量。因此,您可以获取它的地址并获得与它内部保存的地址不同的值。
我在此处写了有关此主题的文章 - 请看看吧。
That's because the array name (
my_array
) is different from a pointer to array. It is an alias to the address of an array, and its address is defined as the address of the array itself.The pointer is a normal C variable on the stack, however. Thus, you can take its address and get a different value from the address it holds inside.
I wrote about this topic here - please take a look.
在 C 中,当您在表达式中使用数组名称(包括将其传递给函数)时,除非它是地址 (
&
) 运算符或的操作数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
都直接指向任一数组或数组的第一个元素,因此具有相同的地址值。In C, when you use the name of an array in an expression (including passing it to a function), unless it is the operand of the address-of (
&
) operator or thesizeof
operator, it decays to a pointer to its first element.That is, in most contexts
array
is equivalent to&array[0]
in both type and value.In your example,
my_array
has typechar[100]
which decays to achar*
when you pass it to printf.&my_array
has typechar (*)[100]
(pointer to array of 100char
). As it is the operand to&
, this is one of the cases thatmy_array
doesn't immediately decay to a pointer to its first element.The pointer to the array has the same address value as a pointer to the first element of the array as an array object is just a contiguous sequence of its elements, but a pointer to an array has a different type to a pointer to an element of that array. This is important when you do pointer arithmetic on the two types of pointer.
pointer_to_array
has typechar *
- initialized to point at the first element of the array as that is whatmy_array
decays to in the initializer expression - and&pointer_to_array
has typechar **
(pointer to a pointer to achar
).Of these:
my_array
(after decay tochar*
),&my_array
andpointer_to_array
all point directly at either the array or the first element of the array and so have the same address value.当您查看数组的内存布局时,可以很容易地理解
my_array
和&my_array
产生相同地址的原因。假设您有一个包含 10 个字符的数组(而不是代码中的 100 个字符)。
my_array
的内存看起来像这样:在 C/C++ 中,数组衰减为指向表达式中第一个元素的指针,例如
如果您检查数组的第一个元素所在的位置,您会发现它地址与数组的地址相同:
The reason why
my_array
and&my_array
result in the same address can be easily understood when you look at the memory layout of an array.Let's say you have an array of 10 characters (instead the 100 in your code).
Memory for
my_array
looks something like:In C/C++, an array decays to the pointer to the first element in an expression such as
If you examine where the first element of the array lies you will see that its address is the same as the address of the array:
在 B 编程语言(C 的前身)中,
指针和整数可以自由互换。该系统将表现为
尽管所有的内存都是一个巨大的数组。每个变量名都有一个全局变量
或堆栈相对地址
与之相关的是,对于每个变量名,编译器必须跟踪的唯一事情是它是全局变量还是局部变量,以及它相对于第一个全局变量或局部变量的地址。
给定像
i;
这样的全局声明[不需要指定类型,因为一切都是整数/指针]将由编译器为:
address_of_i = next_global++; memory[address_of_i] = 0;
并且像i++
这样的语句将被处理为:memory[address_of_i] = memory[address_of_i]+1;
。像
arr[10];
这样的声明将被处理为address_of_arr = next_global;内存[next_global] = next_global; next_global += 10;
。请注意,一旦处理该声明,编译器就会立即忘记arr
是一个数组。像arr[i]=6;
这样的语句将被处理为memory[memory[address_of_a] + memory[address_of_i]] = 6;
。编译器不会关心arr
是否表示数组而i
是否表示整数,反之亦然。事实上,它不会关心它们是否都是数组或都是整数;它会非常高兴地生成所描述的代码,而不考虑生成的行为是否可能有用。C 编程语言的目标之一是与 B 很大程度上兼容。在 B 中,数组的名称[在 B 的术语中称为“向量”]标识了一个包含指针的变量,该指针最初被分配为指向到给定大小的分配的第一个元素,因此如果该名称出现在函数的参数列表中,则该函数将接收指向该向量的指针。尽管 C 添加了“真正的”数组类型,其名称与分配的地址严格相关,而不是最初指向分配的指针变量,但将数组分解为指针使得声明 C 类型数组的代码表现相同B 代码声明了一个向量,然后从未修改保存其地址的变量。
In the B programming language, which was the immediate predecessor to C,
pointers and integers were freely interchangeable. The system would behave as
though all of memory was a giant array. Each variable name had either a global
or stack-relative address
associated with it, for each variable name the only things the compiler had to keep track of was whether it was a global or local variable, and its address relative to the first global or local variable.
Given a global declaration like
i;
[there was no need to specify a type, since everything was an integer/pointer] would be processed by thecompiler as:
address_of_i = next_global++; memory[address_of_i] = 0;
and a statement likei++
would be processed as:memory[address_of_i] = memory[address_of_i]+1;
.A declaration like
arr[10];
would be processed asaddress_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 aboutarr
being an array. A statement likearr[i]=6;
would be processed asmemory[memory[address_of_a] + memory[address_of_i]] = 6;
. The compiler wouldn't care whetherarr
represented an array andi
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.
实际上
&myarray
和myarray
都是基地址。如果你想看到差异而不是使用
use
Actually
&myarray
andmyarray
both are the base address.If you want to see the difference instead of using
use