在 C 语言中,为什么数组的地址等于它的值?

发布于 2024-12-15 07:14:47 字数 634 浏览 0 评论 0原文

在下面的代码中,指针值和指针地址与预期不同。

但数组值和地址则不然!

怎么会这样呢?

输出

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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

倦话 2024-12-22 07:14:47

数组的名称通常计算为数组第一个元素的地址,因此 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

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, so array+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. Thus sizeof 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 type T *. 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 type T(*)[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:

char array[16];
printf("%p\t%p", (void*)&array, (void*)(&array+1));

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:

0x12341000    0x12341010
彩虹直至黑白 2024-12-22 07:14:47

这是因为数组名称 (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.

橪书 2024-12-22 07:14:47

在 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_arraypointer_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 the sizeof 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 type char[100] which decays to a char* when you pass it to printf.

&my_array has type char (*)[100] (pointer to array of 100 char). As it is the operand to &, this is one of the cases that my_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 type char * - initialized to point at the first element of the array as that is what my_array decays to in the initializer expression - and &pointer_to_array has type char ** (pointer to a pointer to a char).

Of these: my_array (after decay to char*), &my_array and pointer_to_array all point directly at either the array or the first element of the array and so have the same address value.

花开半夏魅人心 2024-12-22 07:14:47

当您查看数组的内存布局时,可以很容易地理解 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].

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).

char my_array[10];

Memory for my_array looks something like:

+---+---+---+---+---+---+---+---+---+---+
|   |   |   |   |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+---+---+
^
|
Address of my_array.

In C/C++, an array decays to the pointer to the first element in an expression such as

printf("my_array = %p\n", my_array);

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:

my_array[0]
|
v
+---+---+---+---+---+---+---+---+---+---+
|   |   |   |   |   |   |   |   |   |   |
+---+---+---+---+---+---+---+---+---+---+
^
|
Address of my_array[0].
梦幻之岛 2024-12-22 07:14:47

在 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 the
compiler as: address_of_i = next_global++; memory[address_of_i] = 0; and a statement like i++ would be processed as: 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.

别念他 2024-12-22 07:14:47

实际上 &myarraymyarray 都是基地址。

如果你想看到差异而不是使用

printf("my_array = %p\n", my_array);
printf("my_array = %p\n", &my_array);

use

printf("my_array = %s\n", my_array);
printf("my_array = %p\n", my_array);

Actually &myarray and myarray both are the base address.

If you want to see the difference instead of using

printf("my_array = %p\n", my_array);
printf("my_array = %p\n", &my_array);

use

printf("my_array = %s\n", my_array);
printf("my_array = %p\n", my_array);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文