0

I've read various articles and questions here on SO about pointers and arrays equivalency. Nearly each article explains it different. I know that arrays and pointers are strongly related and bellow are my experiments with pointers and arrays equivalency, including comments which explain given behavior (feel free to correct me if I'm wrong somewhere). My question is: are arrays are just constant pointers or is there also another differences?

#include <stdio.h>
int main ()
{
  // declaring array this way in fact declares a pointer with name "a" which points to the first element in the array:
  int a[] = {0,1,2,3,4};

  // assigning an array to the pointer in fact assigns the address of the first array element to the pointer, those two are thus equivalents:
  int *pa1 = a;
  int *pa2 = &a[0];

  printf("########################\n");

  // REFERENCING: arrays can use pointer syntax (following are equivalents)
  printf("%p\n", (a+0)); // a+0 == 0+a
  printf("%p\n", a);
  printf("%p\n", &a[0]);
  printf("%p\n", &0[a]); // a+0 == 0+a

  printf("########################\n");

  // DEREFERENCING: arrays can use pointer syntax (following are equivalents)
  printf("%d\n", *(a+0)); // a+0 == 0+a
  printf("%d\n", *a);
  printf("%d\n", a[0]);
  printf("%d\n", 0[a]);   // a+0 == 0+a

  printf("########################\n");

  // REFERENCING: arrays can use pointer syntax (following are equivalents)
  printf("%p\n", (a+1));
  printf("%p\n", &a[1]);

  // REFERENCING: pointers can use array syntax (following are equivalents)
  printf("%p\n", (pa1+1));
  printf("%p\n", &pa1[1]);

  printf("########################\n");

  // DEREFERENCING: assigning values via pointers using pointer/array syntax (following are equivalents)
  *(pa1+1) = *(pa1+1) + 10;
  pa2[1] = pa2[1] + 10;

  // DEREFERENCING: arrays can use pointer syntax (following are equivalents)
  printf("%d\n", *(a+1));
  printf("%d\n", a[1]);
  printf("%d\n", 1[a]);

  // DEREFERENCING: assigning values via arrays using pointer/array syntax (following are equivalents)
  *(a+2) = *(a+2) + 10;
  a[2]   = a[2] + 10;

  // DEREFERENCING: pointers can use array syntax (following are equivalents)
  printf("%d\n", *(pa1+2));
  printf("%d\n", pa1[2]);
  printf("%d\n", 2[pa1]);

  printf("########################\n");

  // REFERENCING: those two pointers points to the same address
  printf("%p\n", pa1);
  printf("%p\n", pa2);

  // DEREFERENCING: those two pointers points to the same address
  printf("%d\n", *pa1);
  printf("%d\n", *pa2);

  printf("########################\n");

  // This is correct:
  pa1++;

  printf("%p\n", pa1);
  printf("%d\n", *pa1);

  printf("%p\n", pa2);
  printf("%d\n", *pa2);
  printf("########################\n");

  return 0;
}

I would say that arrays are just constant pointers, the only thing that misleads me is that the error messages are different when I try to increment array and constant pointer, here is what I mean:

#include <stdio.h>
int main (){
  int var1=0;
  int * const ptr;
  int a[] = {0,1,2,3,4,5};

  // This gives an error:
  // error: increment of read-only variable ‘ptr’
  ptr++;

  // This gives an error:
  // error: lvalue required as increment operand
  a++;
return 0;
}

If they are not the same can you please post some scenario where this difference is obvious?

Wakan Tanka
  • 7,542
  • 16
  • 69
  • 122

2 Answers2

3

Arrays and pointers are completely different animals.

Under most circumstances, an expression of type "N-element array of T" will be converted ("decay") to an expression of type "pointer to T", but the array object itself is not a pointer.

This behavior has its roots in the B language, from which C was derived. In B, an array object was a pointer, and the subscript operation a[i] was interpreted as *(a + i) (offset i elements from address stored in a, dereference the result).

Ritchie kept the *(a + i) semantics, but got rid of the explicit pointer; C converts the array expression to a pointer expression instead (except when the array expression is the operand of the unary & or sizeof operators).

John Bode
  • 119,563
  • 19
  • 122
  • 198
1

You may pretend, that arrays are the same as constant pointers, but in fact they are different types. One notable difference is a result of the sizeof operator. For instance:

#include <stdio.h>

int main(void)
{
    int a[] = {0, 1, 2, 3, 4, 5};
    int * const p = a;

    printf("sizeof(a) = %zu\n", sizeof(a));
    printf("sizeof(p) = %zu\n", sizeof(p));
}

For the former, you are getting total size of array. Assuming that sizeof(int) = 4, it prints 24. OTOH, for the latter, you just get the same as size of int pointer.

Also, you cannot use array initializer for pointer variable:

int * const p = {0, 1, 2, 3, 4, 5};

results into compiler's error if you set it with -pedantic-errors flag, e.g.:

error: excess elements in scalar initializer

Another important difference is that arrays are copied for each element during a struct assignment:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct threeNumbers {
    int t[3];
} a = {{1, 2, 3}}, b = {{4, 5, 6}};

int main(void)
{
    a = b;
    a.t[0] = 100;

    printf("%d\n", a.t[0]); // prints 100
    printf("%d\n", b.t[0]); // prints 4
}

This is not the case for pointers. Structures with const pointers cannot be assigned to each other. For non-const pointers members, only an adress is copied. If pointers were set with malloc, then this might result into memory leak.

Grzegorz Szpetkowski
  • 36,988
  • 6
  • 90
  • 137
  • 1
    By default `excess elements in scalar initializer` is just a warning. So people tend to ignore it an then wonder what is going on.. – Eugene Sh. Jul 28 '15 at 15:01
  • 1
    The other difference is the type you get when you use the address of operator (`&`) with an array variable. – R Sahu Jul 28 '15 at 15:08