5

I want to use variable a from foo.c in main.c, and I write:

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;
}

and the result output:

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

why?

che
  • 12,097
  • 7
  • 42
  • 71
Victor S
  • 4,021
  • 15
  • 43
  • 54

2 Answers2

8

The type of a is int[2], not int*. Try again with

extern int a[2];

The C compiler cannot type-check across source files. Therefore, when you say int* a, the compiler will assume you're telling the truth, use pointer semantics, and will not issue any compiler error.

There are subtle difference between arrays and pointers. Let's assume a 32-bit system. Then the content of "a" will be distributed like this:

    a
0x100       0x104      0x108   ← address
    +-----------+----------+
    |         3 |        2 |   ← content
    +-----------+----------+

When a is an array,

  • The value of the expression a is will be converted to the address of a. Therefore, when you print a, you will get its address, i.e. "0x100".
  • The operation a[n] in C is equivalent to *(a + n), i.e. advance the address a by n units, and then dereference it to get the content. Therefore, a[0] is equivalent to *0x100, which returns the content at 0x100, i.e. "3".

When a is a pointer,

  • The "value" of a is the content at the provided address. In fact this is the norm, the array type is a special case. Therefore, when you print a, you will get the content at that address, i.e. "3".
  • The operation a[n] is still *(a + n). Therefore, a[0] is equivalent to *3, which causes segmentation fault because the address "3" is invalid.
kennytm
  • 510,854
  • 105
  • 1,084
  • 1,005
  • But `int a[2]` is pointer, too, except the compiler just knows it's size at compile-time. Or is my understanding wrong here? – Niklas R Jun 23 '12 at 08:35
  • 4
    @NiklasR: No `int a[2]` is not a pointer, it's an array. `extern int a[];` would work as well so the difference is not the known size. – CB Bailey Jun 23 '12 at 08:47
  • @user1468181: Compiling successfully does not imply there is no error. Here the error is having declarations with incompatible types for the same object (`a`). – CB Bailey Jun 23 '12 at 08:52
  • @KennyTM huh? Since when is the value of a pointer the dereference of it's address, or whatver? (I'm a bit confused :x ) What about this? http://codepad.org/3gpO5RTe It does not proof your answer. – Niklas R Jun 23 '12 at 08:59
  • @NiklasR: What `a` prints in your code is the value of `a`, not the address of `a` (`&a`). http://codepad.org/BUNwi5z2. – kennytm Jun 23 '12 at 09:05
  • Yes, the value of the pointer is just the address stored in the pointer object. (A pointer object has its own address but that isn't being printed or accessed directly here.) For a pointer, the statement in the `printf` statement "address of a" is misleading when printing `a`. It's printing its value, not its address. – CB Bailey Jun 23 '12 at 09:07
  • I have completely confused, see below comment. – Victor S Jun 23 '12 at 11:14
1

You have to use consistent types for objects declared across different translation units.

Given int a[] = {2, 3};, either of the declarations extern int a[]; or extern int a[2]; would be compatible whereas extern int *a; would not as pointers and arrays are completely separate types.

The one thing special about arrays is the when the name of an array appears in any expression context other than as an operand to "address of" (unary &) or sizeof, they are automatically converted to a pointer to their first element. This is what provides the syntax compatibility between arrays and pointers, but they are not the same type.

Consider these two functions for a commented example. Note that the expression a is converted to a pointer to its first element in the second (and technically third) printf of the first function, but not in the first printf where it is the operand to &.

#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])
}

Note that I use %p to print pointers and explicitly cast to void*.

CB Bailey
  • 755,051
  • 104
  • 632
  • 656