5

我想在 main.c 中使用来自 foo.c 的变量 a,我写:

foo.c
#include <stdio.h>

int a[] = {3, 2};

void foo()
{
    printf("foo\taddress of a:%x\n", a);
    printf("foo\tvalue of a[0]:%x\n", a[0]);
}

main.c
#include <stdio.h>

extern int *a;

int main(void)
{
    foo();
    printf("main\taddress of a : %x\n", a);
    printf("main\tvalue of a[0] : %x\n", a[0]);

    return 0;
}

和结果输出:

foo address of a:804a014
foo value of a[0]:3
main    address of a : 3
Segmentation fault (core dumped)

为什么?

4

2 回答 2

8

的类型aint[2],不是int*。再试一次

extern int a[2];

C 编译器无法跨源文件进行类型检查。因此,当您说 时int* a,编译器会假定您说的是真话,使用指针语义,并且不会发出任何编译器错误。

数组和指针之间存在细微差别。让我们假设一个 32 位系统。那么“a”的内容会这样分布:

    一种
0x100 0x104 0x108 ← 地址
    +------------+----------+
    | 3 | 2 | ← 内容
    +------------+----------+

什么时候a数组

  • 表达式的值a将转换为 的地址a。因此,当你打印时a,你会得到它的地址,即“0x100”。
  • C中的操作a[n]等价于,即按单位*(a + n)前进地址,然后解引用得到内容。因此,等价于,返回0x100 处的内容,即“3”。ana[0]*0x100

什么时候a指针

  • 的“值”a是提供地址的内容。其实这是常态,数组类型是个特例。因此,当您打印时a,您将获得该地址的内容,即“3”。
  • 手术a[n]还在*(a + n)。因此,a[0]等价于*3,由于地址“3”无效,导致分段错误。
于 2012-06-23T08:30:27.800 回答
1

您必须对跨不同翻译单元声明的对象使用一致的类型。

给定int a[] = {2, 3};,声明extern int a[];extern int a[2]; 将是兼容的,而extern int *a;不会因为指针和数组是完全独立的类型。

数组的特殊之处在于,当数组的名称出现在任何表达式上下文中,而不是作为“地址”(一元&)的操作数或sizeof时,它们会自动转换为指向其第一个元素的指针。这是提供数组和指针之间语法兼容性的原因,但它们不是同一类型。

考虑这两个函数作为注释示例。请注意,表达式在第一个函数a的第二个(技术上是第三个)中转换为指向其第一个元素的指针,但不是在它是操作数printf的第一个函数中。printf&

#include <stdio.h>

void print_array_info(void)
{
    extern int a[];
    printf("address of a:  %p\n", (void*) &a);   // prints address of a
    printf(" converted a:  %p\n", (void*) a);    // prints address of a[0]
    printf("value of a[0]: %x\n", a[0]);         // prints value of a
}

void print_pointer_info(void) {
    extern int a[];
    int *b = a; // == &a[0]

    printf("address of b:  %p\n", (void*) &b);  // prints address of b
    printf("  value of b:  %p\n", (void*) b);   // prints value of b (== &a[0])
    printf("value of b[0]: %x\n", b[0]);        // prints value of b[0] (== a[0])
}

请注意,我使用%p打印指针并显式转换为void*.

于 2012-06-23T09:22:30.943 回答