指向变量与数组的外部指针

Extern pointer to variable vs array

我知道这个话题已经讨论过几次了,但我还是不明白。

参考http://c-faq.com/aryptr/aryptr2.html

char a[] = "hello";
char *p = "world";

创建数组 "a"。该变量只是第一个内存地址的地址的标签。 p 是一个变量(== 另一个内存地址的标签),包含第一个字符的地址(w - 可能在内存中的其他地方)。

我不明白的是这个主题的例子(谢谢!): using extern to link array with pointer :

extern1.c

extern int *array;
int test();

int main(int argc, char *argv[])
{
    printf ("in main: array address = %x\n", array);
    test();
    return 0;
}

extern2.c

int array[10] = {1, 2, 3};

int test()
{
    printf ("in test: array address = %x\n", array);
    return 0;
}

为什么extern1中的指针变量"extern int *array"(==内存地址的标号,包含另外一个地址)已经包含数组[0]的内容了?

有什么区别
int array[10] = {1, 2, 3};
int *ptrArrWorking = array; // == &array[0];

? 在外部情况下,它会像

int array[10] = {1, 2, 3};
int *ptrArrNotWorking = array[0]; 

编辑:更明确地说,我们将上面的示例解释为

int array[10] = {1, 2, 3};
int *ptrArrNotWorking = (int *)array[0]; 

所以这模拟了在外部示例中可以看到的相同行为。

间接隐藏在哪里?

非常感谢。

仅使用 extern declares a variable, but not defines it

实际上这意味着 array 变量(在 extern1.c 中声明为 extern)只是实际变量 array 定义在 extern2.c

您在 extern2.c 中定义了一个名为 array:

的对象
int array[10] = {1, 2, 3};

这是包含十个 int 的连续内存段。在将它传递给 test 中的 printf 后,它会衰减为指向其第一个元素的指针——这就是数组传递给函数的方式。因此,printf 打印第一个 int.

的地址

然而,在 extern1.c 中,您在再次声明 array 时撒谎:

extern int *array;

这假装 array 是一个指针,一个保存其他对象地址的对象。这种不匹配导致程序 "ill-formed, no diagnostic required"。那是 "badly broken" 的标准——从那时起,就不再要求程序是否编译,或者它在运行时实际做了什么。

在实践中,该损坏声明之后的代码确实会将 array 视为指针。因此,当您将 array 传递给 printf 时,它会从数组的开头切掉一些字节(通常是 4 或 8,具体取决于您的平台),大喊 "there you go, here's the pointer" 并给出至 printf.

当然,它实际上不是一个有效的指针,而是array的前几个int的比特位塞在一起,所以你看到的是废话。

creates an array "a". The variable is only a label of the address of the first memory address.

不是,a是整个数组hello[=13=]。每当在表达式中使用标识符 a 时,数组 "decays" 就会成为指向其第一个元素的指针。也就是说,在使用 a 的表达式中,您将得到一个指向字母 'h'.

的临时 char*

可以这样想:数组就是通往罗马的道路。您询问编译器 "where is the road to Rome, I need to access it",然后它会帮助您设置一个临时路标。这并不意味着通往罗马的道路成为路标。这也不意味着路标本身就是通往罗马的道路。同样,通往罗马的道路不会因为你在上面行驶(访问它)而成为路标。

Why does the pointer variable "extern int *array" (== a label of memory address, containing an other address) in extern1 already contain the content of array[0]?

没有。您不能编写 extern int* array 并期望获得指向分配在别处的数组 int array[10] 中第一项的指针。因为数组不是指针,指针也不是数组。

反汇编示例中发生的事情是代码调用未定义的行为(错误),程序员向编译器撒谎并说 "what's stored here is actually a pointer, trust me" 即使那里没有指针,而是一个整数。

因此,正如在该特定系统上发生的那样,您将指针的地址设置为 1。不是 pointed-at 数据。这不是你可以依靠的;如果指针和整数在给定系统上具有不同的大小或表示,代码也可能会崩溃。

打个比方,你的编译器就是driver,CPU的程序计数器就是汽车。用 extern int *array 你告诉编译器 "that thing over there a road sign!",指的是实际的道路。编译器然后盲目地按照你告诉它的去做,并尝试从沥青中解释一些方向,然后让汽车跟随它,然后它跑到荒野中,很可能撞毁并且肯定永远不会到达罗马。

这里:

int array[10] = {1, 2, 3};
int *ptrArrWorking = array; // == &array[0];

您将指针设置为指向数组中的第一项。这意味着指针将获得存储该项目的内存地址。您没有将 地址本身 设置为 1,这在大多数系统上很可能是无意义的。

In the extern case it would be something like

int array[10] = {1, 2, 3};
int *ptrArrNotWorking = array[0]; 

是的,这是没有任何意义的代码。它实际上甚至不是有效的 C,因为如果不先执行转换就不能将整数分配给指针——这可以通过类型转换来完成。