What does ** do in C language? [duplicate] What does ** do in C language? [duplicate] arrays arrays

What does ** do in C language? [duplicate]


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.


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 myStringsmyStrings[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 apartmyStrings[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'


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.)