1

I am struggling with pointers concept of C, precisely with Array of pointers. See the below program for reference.

#include <stdio.h> 

int a1[] = {6,7,8,18,34,67};
int a2[] = {23,56,28,29};
int a3[] = {-12,27,-31};
int *x[] = {a1,a2,a3};

void print (int *a[]){
  printf ("%d",a[0][2]);
  printf ("%d",*a[2]);
  printf ("%d",*++a[0]);
  printf ("%d",*(++a)[0]);
  printf ("%d",a[-1][1]);
 
}

void main (){ 
  print (x);
}

what I don't understand is, if we are passing int *a[] as an array of pointers, it should be an array after all right ? but I'm being told that here a is only a single pointer variable which acts as an alias to x but according to the syntax a should be an Array, ie. the activation record of print() function should contain an array not merely a pointer variable that holds the base address of x but that's the whole confusion is it a pointer or an array of pointers, the syntax surely suggests that it should be an array of int pointers, I read online but got way more confused, please don't disregard this question by flagging irrelevant.

Pawan Nirpal
  • 565
  • 1
  • 12
  • 29
  • 1
    Did you read [*Modern C*](https://modernc.gforge.inria.fr/), the documentation of your C compiler (e.g. [GCC](http://gcc.gnu.org/)... to be invoked as `gcc -Wall -Wextra -g`), and of your debugger (e.g. [GDB](https://www.gnu.org/software/gdb/)...). See also [this C reference](https://en.cppreference.com/w/c) and [n1570](http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf) or some newer C standard – Basile Starynkevitch May 10 '21 at 05:31
  • I don't think I am facing problems with semantics but rather with understanding the concept of array of pointers. – Pawan Nirpal May 10 '21 at 05:35
  • 1
    Are you allowed to use a debugger? And to run your program step by step? And to draw on paper figures (representing pointers by arrows, like in [linked list](https://en.wikipedia.org/wiki/Linked_list) wikipage?) What will happen to you if you read the [documentation of GDB](http://sourceware.org/gdb/current/onlinedocs/gdb/) ? BTW, you could consider installing [Debian](http://debian.org/) on your laptop – Basile Starynkevitch May 10 '21 at 05:37
  • BTW, you could code `printf ("at line %d, we have %d\n",__LINE__, a[0][2]);` and likewise elsewhere, then recompile and run your program in a debugger – Basile Starynkevitch May 10 '21 at 05:43
  • 1
    Did you read the wikipage about [pointer](https://en.wikipedia.org/wiki/Pointer_(computer_programming))s? And the one on [virtual address space](https://en.wikipedia.org/wiki/Virtual_address_space) ? You may want to read some [good operating system textbook](https://pages.cs.wisc.edu/~remzi/OSTEP/). Can you reads books on paper? Are you allowed to use the [Clang static analyzer](https://clang-analyzer.llvm.org/) ? Or [Frama-C](https://frama-c.com)? – Basile Starynkevitch May 10 '21 at 05:46
  • I did now, but it's taking me away from the point, I'm not concerned about the ourput but about the memory layout of these arrays, as in say, a1,a2,a3 will reside in static memory and will be integer arrays? – Pawan Nirpal May 10 '21 at 05:51
  • 1
    You may want to run `gcc -fverbose-asm -Wall -Wextra -O2 -S your-prog.c` and look inside the generated assembler code `your-prog.s`, assuming you are allowed to use [GCC](http://gcc.gnu.org/) – Basile Starynkevitch May 10 '21 at 05:53
  • Ok thank you for your time, I will surely debug this with GCC. All I was looking for was the memory layout and variable profiles. – Pawan Nirpal May 10 '21 at 05:58
  • If you are allowed to use both the [GCC](http://gcc.gnu.org/) compiler and the [GDB](https://www.gnu.org/software/gdb/) debugger, I recommend compiling with `gcc -Wall -Wextra -g your-prog.c -o your-binary` then using `gdb your-binary`. But **you need to read the documentation of your compiler and of your debugger.** – Basile Starynkevitch May 10 '21 at 05:59
  • Surely thanks, I will. – Pawan Nirpal May 10 '21 at 05:59
  • 4
    Do you know about how [array pointer decay](https://stackoverflow.com/questions/1461432/what-is-array-to-pointer-decay) works? – Nate Eldredge May 10 '21 at 06:01
  • @Nate Eldredge Not formally though, I read it online that an array name is converted to a pointer. – Pawan Nirpal May 10 '21 at 06:06
  • 1
    No, array names are not converted to pointers. Names are relevant in source code. Pointers are relevant in your executable. Think of [cross-compilation](https://en.wikipedia.org/wiki/Cross_compiler): names in source code and pointers can be on *different* computers. And you could lose your source code and still keep your executable – Basile Starynkevitch May 10 '21 at 06:07
  • Thank you guys I am starting to get this now, As I realize, I was short on understanding the decay concept. – Pawan Nirpal May 10 '21 at 06:14

1 Answers1

2

There are two cases where an array "decays" into a pointer to its first item:

  • Whenever the array name is used in (most) expressions, or
  • When a function parameter is declared with array type.

The reason int *x[] = {a1,a2,a3}; works is because those 3 arrays "decay" into a pointer to their first element here. Which in all 3 cases is of type int*, so it is compatible with the element type of the x array.

Then when you define a function such as void print (int *a[]), the compiler silently and implicitly "decays" this array declaration into a pointer to the first element. The first element of an int* [] array is an int* and a pointer to one is int**. So this function is equivalent to void print (int** a);. That's why we can write an empty [] here - the compiler doesn't care about the array size since it will replace the array with a pointer anyway.

And that's also why the multiple levels of indirection a[0][2] works. This is not because a is a 2D array - it isn't. But the first [] does pointer arithmetic on the int** type to get the relevant int* element. And the second does pointer arithmetic on that pointer element in turn, to get to the actual int.

As for the various lines inside that function, it's some sort of artificial school example meant to teach about operator precedence. Hint: postfix operators usually have the highest precedence.

The line a[-1][1] is a bug since it invokes undefined behavior - we shouldn't write programs like that and the reason why is a somewhat advanced topic of it's own. Detailed info here: Is it undefined behaviour to just make a pointer point outside boundaries of an array without dereferencing it?

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • what pointer arithmetic does the operator ```[]```do on an address, can you please elaborate more on that? – Pawan Nirpal May 11 '21 at 15:22
  • 1
    @PawanNirpal Like any pointer arithmetic, each index or +1 increases the offset by `sizeof(type)`. So in case you do pointer arithmetic on a `int**` pointer, you'll get chunks of `sizeof(int*)`. – Lundin May 12 '21 at 06:07
  • Yes thank you, that's what I was expecting wasn't sure though, now I am, thanks again. – Pawan Nirpal May 12 '21 at 10:58