Is an array a pointer?

“Array is a pointer” (also “an array’s name is a pointer to the array’s first element”) – I think most of us have heard that nonsense. So many people believe it’s true. And some of them think that they’re absolutely right, don’t even taking into account they may be wrong. I’m getting tired of this, so… I think it’s great time to write a post about this ;>

Let’s see what the standard says (4.2.1): “An lvalue or rvalue of type ‘array of N T’ or ‘array of unknown bound of T’ can be converted to an value of type ‘pointer to T.’ The result is a pointer to the first element of the array”. It’s pretty clear it means that these types are convertible (and, since they’re convertible, they can’t be the same type). Someone who doesn’t know that may think they’re in fact the same, since it’s perfectly fine to do something like:

int foo[11];
int* bar = foo;
*(foo + 8) = 42;
void sth(int*);
sth(foo);

Sure, it compiles and runs just fine. But this doesn’t mean that arrays are pointers. Consider this:

void function(float num);
int x = /* ... */;
function(x);

It compiles and runs fine, too. But it’s because of implicit conversion, not because the types are the same (I hope nobody thinks int and float are the same ;>).

If arrays and pointer actually were the same, then the following code wouldn’t compile:

template <typename T> struct sth;
 
template <> struct sth<int []> {};
 
// okay, int [] and int [6] are distinct types
template <> struct sth<int [6]> {};
 
// okay, int*, int [] and int [6] are distinct types
template <> struct sth<int*> {};
 
// sizeof(pointer to int) is not equal to sizeof(array of six ints)
// (in fact it could be true for a very obscure machine, though)
typedef char x[sizeof(int*) != sizeof(int[6]) ? 1 : -1];

But what about “arrays” in function arguments list? Let’s suppose we have something like

void f(int arr[])
{
 
}

In this function, arr is a pointer. sizeof(arr) will yield size of a pointer to int. It’s legal to do ++arr. It’s because an array passed to function by value decays to a pointer (this doesn’t mean that arrays are pointers!), arrays simply can’t be passed by value. Even if we’ll tell the compiler the size of the array:

void f(int arr[123])
{
 
}

it’s still a pointer. And because it’s a pointer, it’s not possible to overload a function based on the size of the “array” passed “by value”. “Arrays” in argument lists are pointers. So overloading for int [123] and int [456] is ill-formed – they’re both int*.

If we really want to pass an array and not a pointer to the function, then we can pass a reference to an array (possibly making the hard-coded 123 a template parameter, so that the function can take arrays with different sizes):

// void f(const int (&arr)[123]) if array of consts
void f(int (&arr)[123])
{
 
}

It’s impossible to pass a pointer to this function, the code won’t compile. This function takes a reference to an array, so pointers won’t do:

int array[123];
int* pointer;
 
f(array); // okay
// f(pointer); // error

To sum up: pointers and arrays are two different things. They often behave similarly, they’re related, but they’re nonetheless different.

~ - autor: Fanael w dniu Styczeń 15, 2010.

Jedna odpowiedź to “Is an array a pointer?”

  1. Cześć!

    Dzięki za post ;>
    Przyznaje, że zawszę traktowałem nazwę tablicy jako const pointer. I w sumie na pewnym poziomie abstrakcji nawet miałem rację ;>
    Natomiast po tym poście przyznaje, że patrząc na poziomie kompilatora, faktycznie nazwa tablicy jest tablicą, a nie pointerem, i jest dopiero rzutowana na pointer ;> Chociaż upierał się będę, że w użyciu to za dużo nie zmienia.

    Anyway, dorzucę w takim razie jeszcze jeden przykład do zacytowanych przez Ciebie – dla odmiany będzie to C, a konkretniej GCC i jego extenstion typeof() oraz opcja -fdump-tree-all:

    #include <stdio.h>
     
    int
    main(void)
    {
      int a[12];
      typeof(a) b;
      typeof(&a) c;
     
      return 0;
    }

    Jeżeli typeof(a) było by const pointerem, to b powinno być const pointerem. Natomiast jeżeli typeof(a) jest tablicą 12 intów, to b będzie tablicą 12 intów. Zmienna c natomiast powinna być pointerem.
    Na pytanie “jak jest w rzeczywistości” odpowie -fdump-tree-all (od 4.4.1 dostępne bodajże), czyli zrzut półproduktów kompilatora. A konkretniej .original:

     
    ;; Function main (null)
    ;; enabled by -tree-original
     
     
    {
      int a[12];
      int b[12];
      int[12] * c;
     
      [...]
     
      return 0;
    }

    Co w zasadzie sprawę przesądza ;>

    Pozdrawiam!

Dodaj komentarz

Wprowadź swoje dane lub kliknij jedną z tych ikon, aby się zalogować:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Zmień )

Twitter picture

You are commenting using your Twitter account. Log Out / Zmień )

Facebook photo

You are commenting using your Facebook account. Log Out / Zmień )

Connecting to %s

 
Follow

Otrzymuj każdy nowy wpis na swoją skrzynkę e-mail.