数组变量是否指向自身

Does an Array variable point to itself?

本文关键字:变量 是否 数组      更新时间:2023-10-16

我尝试了一些代码来检查数组和指针的行为。其如下。

#include <stdio.h>
main(){
int s[]={1,2};
int *b=s;
printf("%d, %d, %dn", s, &s, *s);
printf("%d, %d, %dn", b ,&b, *b);
}

最初我认为指针和数组是相同的,但是......
令我惊讶的是,"s"和"&s"的值与"b"相同。这是否意味着数组变量"指向自身"?

我现在也对变量"名称"实际上是什么感到困惑?它如何与内存中的某个位置进行绑定?我只是无法想象那里发生的事情!运行时存储的所有信息在内存 (RAM( 中的哪个位置?

好的,假设以下是执行时内存的外观

int s[]={1,2};
int *b=s;
s[]
+-----+-----+
|  1  |  2  |
+-----+-----+
100   104 
^
|
|  int *b = &s
+-----+
| 100 |
+-----+
200

s是一个数组。这意味着,它是一个与变量s相关联的连续内存位置,并且每个元素都通过偏移数组变量名称来访问。

因此,当您使用s时,它实际上归结为数组的地址(在这种情况下100(。当你做*s时,它归结为*(s+0)相当于s[0],所以*s表示存储在第0个位置的内容(在本例中s[0] 1(。什么时候做一个&s,这将打印s (which is的地址 100' 在这种情况下(。

请注意,这里的s&s表示一个地址; *ss[x] 表示一个整数。

这同样适用于指针。因此,b打印它拥有的内容,即s的地址(在本例中100(。 &b打印b的地址,在这种情况下200。并且,*b打印数组s的第一个元素的内容,即1

我已经修改了您的程序以使其打印地址。

#include <stdio.h>
int main(void)
{
    int s[]={1,2};
    int *b=s;
    printf("%p, %p, %dn", (void *)s, (void *)&s, *s);
    printf("%p, %p, %dn", (void *)b, (void *)&b, *b);
    return 0;
}

输出:

0xbfc4f3e4, 0xbfc4f3e4, 1
0xbfc4f3e4, 0xbfc4f3ec, 1

编辑:%p期望void *。添加相同!

当数组用作函数的参数时,会衰减为指向其第一个元素的指针。同样,获取数组的地址会产生指向第一个元素位置的指针(但类型不同(。

至于你的第二个问题,变量名只存在于编译时。它在运行时在内存中通常没有表示形式。

除非它是 sizeof 或一&元运算符的操作数,或者是一个字符串文本用于初始化声明中的另一个数组,否则类型为"T 的 N 元素数组"的表达式将替换为"指向T的指针"类型的表达式,并且表达式的值将是数组中第一个元素的地址。

假设以下代码:

int arr[10];
foo(arr);

在对函数 foo 的调用中,表达式 arr 从类型"10 元素数组 int"转换为"指向int的指针",arr的第一个元素的地址是实际传递给foo的。

我们将foo定义为

void foo(int a[]) {}

void foo(int *a) {}

在函数参数声明的上下文中,T a[]T a[N]T *a相同;参数是指针类型,而不是数组类型。 请注意,这仅适用于函数参数声明。

如上所述,此规则的一个例外是数组表达式是一元运算符的操作数&。 如果我们将调用更改为foo阅读

foo(&arr);

那么表达式&arr的类型是"指向 int 10 元素数组的指针",即 int (*)[10] ,表达式的值是 a 的地址。 为此,foo的定义将是

void foo(int (*a)[10]) {}
在 C 中,数组的地址和

数组的第一个元素的地址是相同的 - 因此表达式 arr&arr 具有相同的,但它们的类型不同。 这对于涉及指针算术的操作很重要。 例如,假设我们的代码已经编写好了

int arr[10];
foo(arr);
...
void foo(int *a)
{
   ...
   a++;  
   ...
}

进入时,a指向arr[0]。 表达式 a++ 将推进指针以指向数组中的下一个整数 (arr[1] (。

现在假设代码被编写为

int arr[10];
foo(&arr);
...
void foo(int (*a)[10])
{
  ...
  a++;
  ...
}

在输入时,a仍然指向arr[0](请记住,数组的地址与数组的第一个元素的地址相同(,但这次表达式a++将推进指针以指向下一个 10 个元素的整数数组;而不是将指针前进sizeof (int)字节, 我们将其推进sizeof (int[10])字节。

因此,这就是为什么在您的printf语句中看到s&s相同的。 您应该使用 %p 转换说明符打印指针值,并且它期望相应的参数为 void * 类型,因此请将这些printf语句更改为

printf("%p %p %dn", (void *) s, (void *) &s, *s);
printf("%p %p %dn", (void *) b, (void *) &b, *b);

考虑这个问题的一种简单方法是,作为指针的数组不能通过赋值来更改,它实际上是指向已知内存量的常量指针。

要尝试这样做,请使用:

myptr = myarray;

这完全没问题,然后尝试:

myarray = myptr;

这不是。