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