48

I'm new to C with a good background in java and I'm trying to understand pointers and arrays.

I know that subscript operator[] is part of an array definition, so:

int numbers[] = {1,3,4,5};

would create a integer array, which would be represented in memory as 16 bytes, 4 lots of 4 bytes:

numbers[0] = 1, address 0061FF1C
numbers[1] = 3, address 0061FF20
numbers[2] = 4, address 0061FF24
numbers[3] = 5, address 0061FF28

However, when it comes to pointers my knowledge starts to break down, so if I was to create a pointer to the array numbers I would do the following:

int *pNumbers = &numbers[0];

which would look something like this:

pointer to numbers

And I'm guessing it would be of size 4 bytes?

However the ** I read as "pointer to a pointer" which makes no sense to me, why would anyone want a pointer to a pointer, surely if a->b->c then a->c would suffice? I know I'm missing something, and it must have something to do with arrays as argv can be of type char[ ] or char ** as seen bellow:

int main(int argc, char **argv){}

So:

  • what is this (**)?
  • what use does it have?
  • how is it represented in memory?
Alexander Ushakov
  • 5,139
  • 3
  • 27
  • 50
James
  • 1,259
  • 1
  • 10
  • 21
  • You'd want a pointer to a pointer for the same reason you'd want a pointer to anything. For example, to modify the pointer it points to. – user2357112 Jan 26 '16 at 18:53
  • 2
    Pointers to pointers make perfect sense, and they're used all the time. Also, `int` is not always 4 bytes. On some machines it is. On 64-bit machines it's probably 8 bytes. On some microprocessors it's 2 bytes. The size of an `int` is `sizeof (int)`. That will always be true. – Tom Karzes Jan 26 '16 at 18:55
  • 1
    @Marged I asked what uses does it have, the other two questions I kind of hinted I might already know, but I wasn't 100% sure, which is why I explicitly asked. The answer I chose illustrates well how these pointers can be used, where as the question you tagged's answer illustrates how the * and & operators work as I already know based on what I've asked in the question, see "int *pNumbers = &numbers[0];" – James Jan 26 '16 at 19:23
  • Do you understand when you would need an array of arrays? Your images already show how a pointer is used to access an array. – Ben Voigt Jan 26 '16 at 20:17
  • 1
    @BenVoigt I think the answers to this question helped me figure out that my problem is more the memory model than pointers of pointers. In Java I just had a rule that you can manipulate objects, but not primitives. That seemed to work for me up until now and I've been programming for almost two years but now I'm starting to question my knowledge of the memory model. Unless you can say C only has primitives and pointers allow you to extend the scope of a primitive by passing a value that references the original primitive? Or am I just being completely stupid. (which is entirely a possibility) – James Jan 26 '16 at 21:04
  • `**` is just `*` twice. `something*` declares a pointer to a `something`, so `char* *` declares a pointer to a `char*`. – user253751 Jan 26 '16 at 21:24
  • 1
    @immibis it was my understanding of the "pass by value" and pass by reference" I understand it now :). Thanks! – James Jan 26 '16 at 22:26

14 Answers14

49

In C arguments are passed by values. For example if you have an integer varaible in main

int main( void )
{
    int x = 10;
    //...

and the following function

void f( int x )
{
    x = 20;
    printf( "x = %d\n", x );
} 

then if you call the function in main like this

f( x );

then the parameter gets the value of variable x in main. However the parameter itself occupies a different extent in memory than the argument. So any changes of the parameter in the function do not influence to the original variable in main because these changes occur in different memory extent.

So how to change the varible in main in the function?

You need to pass a reference to the variable using pointers.

In this case the function declaration will look like

void f( int *px );

and the function definition will be

void f( int *px )
{
    *px = 20;
    printf( "*px = %d\n", *px );
} 

In this case it is the memory extent occupied by the original variable x is changed because within the function we get access to this extent using the pointer

    *px = 20;

Naturally the function must be called in main like

f( &x );

Take into account that the parameter itself that is the pointer px is as usual a local variable of the function. That is the function creates this variable and initializes it with the address of variable x.

Now let's assume that in main you declared a pointer for example the following way

int main( void )
{
   int *px = malloc( sizeof( int ) );
   //..

And the function defined like

void f( int *px )
{
    px = malloc( sizeof( int ) );

    printf( "px = %p\n", px );
}

As parameter px is a local variable assigning to it any value does not influence to the original pointer. The function changes a different extent of memory than the extent occupied by the original pointer px in main.

How to change the original pointer in the function? Just pass it by reference!

For example

f( &px );
//...

void f( int **px )
{
    *px = malloc( sizeof( int ) );

    printf( "*px = %p\n", *px );
}

In this case the value stored in the original pointer will be changed within the function because the function using dereferencing access the same memory extent where the original pointer was defined.

Vlad from Moscow
  • 301,070
  • 26
  • 186
  • 335
17

Q: what is this (**)?

A: Yes, it's exactly that. A pointer to a pointer.

Q: what use does it have?

A: It has a number of uses. Particularly in representing 2 dimensional data (images, etc). In the case of your example char** argv can be thought of as an array of an array of chars. In this case each char* points to the beginning of a string. You could actually declare this data yourself explicitly like so.

char* myStrings[] = {
    "Hello",
    "World"
};

char** argv = myStrings;

// argv[0] -> "Hello"
// argv[1] -> "World"

When you access a pointer like an array the number that you index it with and the size of the element itself are used to offset to the address of the next element in the array. You could also access all of your numbers like so, and in fact this is basically what C is doing. Keep in mind, the compiler knows how many bytes a type like int uses at compile time. So it knows how big each step should be to the next element.

*(numbers + 0) = 1, address 0x0061FF1C
*(numbers + 1) = 3, address 0x0061FF20
*(numbers + 2) = 4, address 0x0061FF24
*(numbers + 3) = 5, address 0x0061FF28

The * operator is called the dereference operator. It is used to retrieve the value from memory that is pointed to by a pointer. numbers is literally just a pointer to the first element in your array.

In the case of my example myStrings could look something like this assuming that a pointer/address is 4 bytes, meaning we are on a 32 bit machine.

myStrings = 0x0061FF14

// these are just 4 byte addresses
(myStrings + 0) -> 0x0061FF14 // 0 bytes from beginning of myStrings
(myStrings + 1) -> 0x0061FF18 // 4 bytes from beginning of myStrings

myStrings[0] -> 0x0061FF1C // de-references myStrings @ 0 returning the address that points to the beginning of 'Hello'
myStrings[1] -> 0x0061FF21 // de-references myStrings @ 1 returning the address that points to the beginning of 'World'

// The address of each letter is 1 char, or 1 byte apart
myStrings[0] + 0 -> 0x0061FF1C  which means... *(myStrings[0] + 0) = 'H'
myStrings[0] + 1 -> 0x0061FF1D  which means... *(myStrings[0] + 1) = 'e'
myStrings[0] + 2 -> 0x0061FF1E  which means... *(myStrings[0] + 2) = 'l'
myStrings[0] + 3 -> 0x0061FF1F  which means... *(myStrings[0] + 3) = 'l'
myStrings[0] + 4 -> 0x0061FF20  which means... *(myStrings[0] + 4) = 'o'
kirk roerig
  • 371
  • 1
  • 12
  • "*`char** argv` can be thought of as an array of an array of `char`s.*" No, pointers are not arrays. `char**` is pointer to pointer to `char`. That's it. – alk Apr 16 '19 at 17:01
  • @alk I never said a pointer IS an array, I said "a pointer can be THOUGHT OF as an array", since from the perspective of the user they can be interacted with similarly, primarily via the subscript operator. The reason I made the comparison is because newcomers who are trying to understand pointers often first have an understanding of arrays, which is helpful because of similarities. – kirk roerig Jul 15 '21 at 15:20
9

The traditional way to write the argv argument is char *argv[] which gives more information about what it is, an array of pointers to characters (i.e. an array of strings).

However, when passing an array to a function it decays to a pointer, leaving you with a pointer to pointer to char, or char **.


Of course, double asterisks can also be used when dereferencing a pointer to a pointer, so without the added context at the end of the question there are two answers to the question what ** means in C, depending on context.

To continue with the argv example, one way to get the first character of the first element in argv would be to do argv[0][0], or you could use the dereference operator twice, as in **argv.

Array indexing and dereferencing is interchangeable in most places, because for any pointer or array p and index i the expression p[i] is equivalent to *(p + i). And if i is 0 then we have *(p + 0) which can be shortened to *(p) which is the same as *p.

As a curiosity, because p[i] is equivalent to *(p + i) and the commutative property of addition, the expression *(p + i) is equal to *(i + p) which leads to p[i] being equal to i[p].


Finally a warning about excessive use of pointers, you might sometime hear the phrase three-star programmer, which is when one uses three asterisks like in *** (like in a pointer to a pointer to a pointer). But to quote from the link

Just to be clear: Being called a ThreeStarProgrammer is usually not a compliment

And another warning: An array of arrays is not the same as a pointer to a pointer (Link to an old answer of mine, which also shows the memory layout of a pointer to a pointer as a substitute of an array of arrays.)

Community
  • 1
  • 1
Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
8

** in declaration represents pointer to pointer. Pointer is itself a data type and like other data types it can have a pointer.

int i = 5, j = 6; k = 7;
int *ip1 = &i, *ip2 = &j; 
int **ipp = &ip1;  

enter image description here

Pointer to pointer are useful in case of allocating dynamic 2D array. To allocate a 10x10 2D array (may not be contiguous)

int **m = malloc(sizeof(int *)*10;  
for(int i = 0; i < 10; i++)
    m[i] = malloc(sizeof(int)*10  

It is also used when you want to change the value of a pointer through a function.

void func (int **p, int n)  
{
    *p = malloc(sizeof(int)*n); // Allocate an array of 10 elements 
}

int main(void)
{
    int *ptr = NULL;
    int n = 10;
    func(&ptr, n);
    if(ptr)
    {
        for(int i = 0; i < n; i++)
        {  
             ptr[i] = ++i;
        }  
    }

    free(ptr);
}

Further reading: Pointer to Pointer.

4pie0
  • 29,204
  • 9
  • 82
  • 118
haccks
  • 104,019
  • 25
  • 176
  • 264
  • 1
    "Pointer to pointer are useful in case of allocating dynamic 2D array" ... and in case you need to change a pointer from different scope (e.g. in different function) – 4pie0 Jan 26 '16 at 18:58
  • 1
    @tinky_winky; Yes. Added to the answer. – haccks Jan 26 '16 at 19:15
5

** represents a pointer to a pointer. If you want to pass a parameter by reference, you would use *, but if you want to pass the pointer itself by reference, then you need a pointer to the pointer, hence **.

John Sensebe
  • 1,386
  • 8
  • 11
5

** stands for pointer to pointer as you know the name. I will explain each of your question:

what is this (**)?

Pointer to Pointer. Sometime people call double pointer. For example:

int a = 3;
int* b = &a; // b is pointer. stored address of a
int**b = &b;  // c is pointer to pointer. stored address of b
int***d = &c; // d is pointer to pointer to pointer. stored address of d. You get it. 

how is it represented in memory?

c in above example is just a normal variable and has same representation as other variables (pointer, int ...). Memory size of variable c same as b and it depends on platform. For example, 32-bit computer, each variable address includes 32bit so size will be 4 bytes (8x4=32 bit) On 64-bit computer, each variable address will be 64bit so size will be 8 bytes (8x8=64 bit).

what use does it have?

There are many usages for pointer to pointer, depends on your situation. For example, here is one example I learned in my algorithm class. You have a linked list. Now, you want to write a method to change that linked list, and your method may changed head of linked list. (Example: remove one element with value equals to 5, remove head element, swap, ...). So you have two cases:

1. If you just pass a pointer of head element. Maybe that head element will be removed, and this pointer doesn't valid anymore.

2. If you pass pointer of pointer of head element. In case your head element is removed, you meet no problem because the pointer of pointer still there. It just change values of another head node.

You can reference here for above example: pointer to pointer in linked list

Another usage is using in two-dimensional array. C is different from Java. Two dimensional array in C, in fact just a continuous memory block. Two dimensional array in Java is multi memory block (depend on your row of matrix)

Hope this help :)

Community
  • 1
  • 1
hqt
  • 29,632
  • 51
  • 171
  • 250
  • you mean: int**c = &b; // c is pointer to pointer. stored address of b int***d = &c; // d is pointer to pointer to pointer. stored address of c. You get it. – J.Doe Sep 20 '20 at 20:13
4

Consider if you have a table of pointers - such as a table of strings (since strings in "C" are handled simply as pointers to the first character of the string).

Then you need a pointer to the first pointer in the table. Hence the "char **".

If you have an inline table with all the values, like a two-dimensional table of integers, then it's entirely possible to get away with only one level of indirection (i.e. just a simple pointer, like "int *"). But when there is a pointer in the middle that needs to be dereferenced to get to the end result, that creates a second level of indirection, and then the pointer-to-pointer is essential.

Another clarification here. In "C", dereferencing via pointer notation (e.g. "*ptr") vs array index notation (e.g. ptr[0]) has little difference, other than the obvious index value in array notation. The only time asterisk vs brackets really matters is when allocating a variable (e.g. int *x; is very different than int x[1]).

ash
  • 4,867
  • 1
  • 23
  • 33
4

Of your int * example you say

And I'm guessing it would be of size 4 bytes?

Unlike Java, C does not specify the exact sizes of its data types. Different implementations can and do use different sizes (but each implementation must be consistent). 4-byte ints are common these days, but ints can be as small two bytes, and nothing inherently limits them to four. The size of pointers is even less specified, but it usually depends on the hardware architecture at which the C implementation is targeted. The most common pointer sizes are four bytes (typical for 32-bit architectures) and eight bytes (common for 64-bit architectures).

what is this (**)?

In the context you present, it is part of the type designator char **, which describes a pointer to a pointer to char, just as you thought.

what use does it have?

More or less the same uses as a pointer to any other data type. Sometimes you want or need to access a pointer value indirectly, just like you may want or need to access a value of any other type indirectly. Also, it's useful for pointing to (the first element of) an array of pointers, which is how it is used in the second parameter to a C main() function.

In this particular case, each char * in the pointed-to array itself points to one of the program's command-line arguments.

how is it represented in memory?

C does not specify, but typically pointers to pointers have the same representation as pointers to any other type of value. The value it points to is simply a pointer value.

John Bollinger
  • 160,171
  • 8
  • 81
  • 157
4

First of all, remember that C treats arrays very differently from Java. A declaration like

char foo[10];

allocates enough storage for 10 char values and nothing else (modulo any additional space to satisfy alignment requirements); no additional storage is set aside for a pointer to the first element or any other kind of metadata such as array size or element class type. There's no object foo apart from the array elements themselves1. Instead, there's a rule in the language that anytime the compiler sees an array expression that isn't the operand of the sizeof or unary & operator (or a string literal used to initialize another array in a declaration), it implicitly converts that expression from type "N-element array of T" to "pointer to T", and the value of the expression is the address of the first element of the array.

This has several implications. First is that when you pass an array expression as an argument to a function, what the function actually receives is a pointer value:

char foo[10];
do_something_with( foo );
...
void do_something_with( char *p )
{
  ...
}

The formal parameter p corresponding to the actual parameter foo is a pointer to char, not an array of char. To make things confusing, C allows do_something_with to be declared as

void do_something_with( char p[] )

or even

void do_something_with( char p[10] )

but in the case of function parameter declarations, T p[] and T p[N] are identical to T *p, and all three declare p as a pointer, not an array2. Note that this is only true for function parameter declarations.

The second implication is that the subscript operator [] can be used on pointer operands as well as array operands, such as

char foo[10];
char *p = foo;
...
p[i] = 'A'; // equivalent to foo[i] = 'A';

The final implication leads to one case of dealing with pointers to pointers - suppose you have an array of pointers like

const char *strs[] = { "foo", "bar", "bletch", "blurga", NULL };

strs is a 5-element array of const char *3; however, if you pass it to a function like

do_something_with( strs );

then what the function receives is actually a pointer to a pointer, not an array of pointers:

void do_something_with( const char **strs ) { ... }

Pointers to pointers (and higher levels of indirection) also show up in the following situations:

  • Writing to a parameter of pointer type: Remember that C passes all parameters by value; the formal parameter in the function definition is a different object in memory than the actual parameter in the function call, so if you want the function to update the value of the actual parameter, you must pass a pointer to that parameter:

    void foo( T *param ) // for any type T
    {
      *param = new_value(); // update the object param *points to*
    }
    
    void bar( void )
    {
      T x;
      foo( &x );   // update the value in x
    }
    
    Now suppose we replace the type T with the pointer type R *, then our code snippet looks like this:

    void foo( R **param ) // for any type R *
    {
      ...
      *param = new_value(); // update the object param *points to*
      ...
    } 
    
    void bar( void )
    {
      R *x;
      foo( &x );   // update the value in x
    }
    
    Same semantics - we're updating the value contained in x. It's just that in this case, x already has a pointer type, so we must pass a pointer to the pointer. This can be extended to higher levels of direction:

    void foo( Q ****param ) // for any type Q ***
    {
      ...
      *param = new_value(); // update the object param *points to*
      ...
    } 
    
    void bar( void )
    {
      Q ***x;
      foo( &x );   // update the value in x
    }
    
  • Dynamically-allocated multi-dimensional arrays: One common technique for allocating multi-dimensional arrays in C is to allocate an array of pointers, and for each element of that array allocate a buffer that the pointer points to:

    T **arr;
    arr = malloc( rows * sizeof *arr );  // arr has type T **, *arr has type T *
    if ( arr )
    {
      for ( size_t i = 0; i < rows; i++ )
      {
        arr[i] = malloc( cols * sizeof *arr[i] ); // arr[i] has type T *
        if ( arr[i] )
        {
          for ( size_t j = 0; j < cols; j++ )
          {
            arr[i][j] = some_initial_value();
          }
        }
      }
    }
    
    This can be extended to higher levels of indirection, so you have have types like T *** and T ****, etc.


1. This is part of why array expressions may not be the target of an assignment; there's nothing to assign anything to.
  1. This is a holdover from the B programming language from which C was derived; in B, a pointer is declared as auto p[].

  2. Each string literal is an array of char, but because we are not using them to initialize individual arrays of char, the expressions are converted to pointer values.

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

I think I'm going to add my own answer in here as well as everyone has done an amazing job but I was really confused at what the point of a pointer to a pointer was. The reason why I came up with this is because I was under the impression that all the values except pointers, were passed by value, and pointers were passed by reference. See the following:

void f(int *x){
    printf("x: %d\n", *x);
    (*x)++;
}

void main(){
   int x = 5;
   int *px = &x;
   f(px);
   printf("x: %d",x);
}

would produce:

x: 5
x: 6

This made my think (for some reason) that pointers were passed by reference as we are passing in the pointer, manipulating it and then breaking out and printing the new value. If you can manipulate a pointer in a function... why have a pointer to a pointer in order to manipulate the pointer to begin with!

This seemed wrong to me, and rightly so because it would be silly to have a pointer to manipulate a pointer when you can already manipulate a pointer in a function. The thing with C though; is everything is passed by value, even pointers. Let me explain further using some pseudo values instead of the addresses.

//this generates a new pointer to point to the address so lets give the
//new pointer the address 0061FF28, which has the value 0061FF1C.
void f(int 0061FF1C){
    // this prints out the value stored at 0061FF1C which is 5
    printf("x: %d\n", 5);
    // this FIRST gets the value stored at 0061FF1C which is 5
    // then increments it so thus 6 is now stored at 0061FF1C
    (5)++;
}

void main(){
   int x = 5;

   // this is an assumed address for x
   int *px = 0061FF1C;

   /*so far px is a pointer with the address lets say 0061FF24 which holds
    *the value 0061FF1C, when passing px to f we are passing by value...
    *thus 0061FF1C is passed in (NOT THE POINTER BUT THE VALUE IT HOLDS!)
    */

   f(px);

   /*this prints out the value stored at the address of x (0061FF1C) 
    *which is now 6
    */
   printf("x: %d",6);
}

My main misunderstanding of pointers to pointers is the pass by value vs pass by reference. The original pointer was not passed into the function at all, so we cannot change what address it is pointing at, only the address of the new pointer (which has the illusion of being the old pointer as its pointing to the address the old pointer was pointing to!).

alk
  • 69,737
  • 10
  • 105
  • 255
James
  • 1,259
  • 1
  • 10
  • 21
3

It is a pointer to a pointer. If you are asking why you would want to use a pointer to a pointer, here is a similar thread that answers that in a variety of good ways.

Why use double pointer? or Why use pointers to pointers?

Community
  • 1
  • 1
moonboy
  • 1,296
  • 4
  • 16
  • 29
1

I would understand char **argv as char** argv. Now, char* is basically an array of char, so (char*)* is an array of arrays of char.

In other (loose) words, argv is an array of strings. In this particular example: the call

myExe dummyArg1 dummyArg2

in console would make argv as

argv[0] = "myExe"
argv[1] = "dummyArg1"
argv[2] = "dummyArg2"
Quang Hoang
  • 146,074
  • 10
  • 56
  • 74
  • 1
    It's *not* an array of arrays. that would be [][], with a fixed memory layout. – Karoly Horvath Jan 26 '16 at 18:55
  • @TomKarzes My C++ is not from book, mostly from practice. So please correct me if I'm wrong. But I think my point is valid, as the following runs: `long long a[3]={1,1,1};cout<< ((int*)a)[1]<<"\n";` and returns `0`. – Quang Hoang Jan 26 '16 at 19:12
  • My comment wasn't very precise. My point is that the `*` characters in a declarator are associated with the individual items being declared, not the top-level data type. So `char **x` is, in effect, `char (*(*x))`. That's how it is parsed and interpreted. Similarly, if one writes `char* x, y`, it's really `char (*x), y`, i.e. `y` has type `char`, not `char *`. – Tom Karzes Jan 26 '16 at 19:24
  • @TomKarzes Thanks, I see what you meant now and learned a new thing. Nevertheless, I would call `char *x,y;` a bad practice -). – Quang Hoang Jan 26 '16 at 19:35
  • "*`char*` is basically an array of `char`, so `(char*)*` is an array of arrays of `char`.*" No and No. Pointers are not arrays. – alk Apr 16 '19 at 16:56
1

For example, ** is a pointer to a pointer. char **argv is the same as char *argv[] and this is the same with char argv[][]. It's a matrix.

You can declare a matrix with 4 lines, for example, but different number of columns, like JaggedArrays.

It is represented as a matrix.

Here you have a representation in memory.

Simply Me
  • 1,579
  • 11
  • 23
  • "*It's a matrix.*" No, `char**` is a pointer to pointer to `char`, nothing more, nothing less. – alk Apr 16 '19 at 16:58
-4

In fact, in C arrays are pointers :

char* string = "HelloWorld!";

is equivalent to this : char string[] = "HelloWorld"; And this : char** argv is as you said a "pointer to a pointer".

It can be seen as an array of strings, i.e multiple strings. But remember that strings are char pointers!

See : in Java the main method is similar to the C main function. It's something like this :

public static void main(String[] args){}

I.e an array of strings. It works the same way in C, String[] args becomes char** args or char* args[].

To sum up : type* name = blablabla; is potentially an array of "type". And type** name = blabla; is potentially an array of arrays.

spin_orbit
  • 79
  • 1
  • 7
  • 4
    C arrays are *not* pointers. The two have a close association, but it is very important to understand that they are not -- at all -- the same thing. – John Bollinger Jan 26 '16 at 19:19