In C, what does a variable declaration with two asterisks (**) mean?
Solution 1:
It declares a pointer to a char
pointer.
The usage of such a pointer would be to do such things like:
void setCharPointerToX(char ** character) {
*character = "x"; //using the dereference operator (*) to get the value that character points to (in this case a char pointer
}
char *y;
setCharPointerToX(&y); //using the address-of (&) operator here
printf("%s", y); //x
Here's another example:
char *original = "awesomeness";
char **pointer_to_original = &original;
(*pointer_to_original) = "is awesome";
printf("%s", original); //is awesome
Use of **
with arrays:
char** array = malloc(sizeof(*array) * 2); //2 elements
(*array) = "Hey"; //equivalent to array[0]
*(array + 1) = "There"; //array[1]
printf("%s", array[1]); //outputs There
The []
operator on arrays does essentially pointer arithmetic on the front pointer, so, the way array[1]
would be evaluated is as follows:
array[1] == *(array + 1);
This is one of the reasons why array indices start from 0
, because:
array[0] == *(array + 0) == *(array);
Solution 2:
C and C++ allows the use of pointers that point to pointers (say that five times fast). Take a look at the following code:
char a;
char *b;
char **c;
a = 'Z';
b = &a; // read as "address of a"
c = &b; // read as "address of b"
The variable a
holds a character. The variable b
points to a location in memory that contains a character. The variable c
points to a location in memory that contains a pointer that points to a location in memory that contains a character.
Suppose that the variable a
stores its data at address 1000 (BEWARE: example memory locations are totally made up). Suppose that the variable b
stores its data at address 2000, and that the variable c
stores its data at address 3000. Given all of this, we have the following memory layout:
MEMORY LOCATION 1000 (variable a): 'Z'
MEMORY LOCATION 2000 (variable b): 1000 <--- points to memory location 1000
MEMORY LOCATION 3000 (variable c): 2000 <--- points to memory location 2000
Solution 3:
It declares aPointer
as a pointer to a pointer to char.
Declarations in C are centered around the types of expressions; the common name for it is "declaration mimics use". As a simple example, suppose we have a pointer to int named p
and we want to access the integer value it's currently pointing to. We would dereference the pointer with the unary *
operator, like so:
x = *p;
The type of the expression *p
is int
, so the declaration of the pointer variable p
is
int *p;
In this case, aPointer
is a pointer to a pointer to char; if we want to get to the character value it's currently pointing to, we would have to dereference it twice:
c = **aPointer;
So, going by the logic above, the declaration of the pointer variable aPointer
is
char **aPointer;
because the type of the expression **aPointer
is char
.
Why would you ever have a pointer to a pointer? It shows up in several contexts:
- You want a function to modify a pointer value; one example is the
strtol
library function, whose prototype (as of C99) islong strtol(const char * restrict str, char ** restrict ptr, int base);
strtol
, you pass the address of a pointer to char as the second argument, and after the call it will point to the first character in the string that wasn't converted.
- Remember that in most contexts, an expression of type "N-element array of T" is implicitly converted to type "pointer to T", and its value is the address of the first element of the array. If "T" is "pointer to char", then an expression of type "N-element array of pointer to char" will be converted to "pointer to pointer to char". For example:
void foo(char **arr) { size_t i = 0; for (i = 0; arr[i] != NULL; i++) printf("%s\n", arr[i]); } void bar(void) { char *ptrs[N] = {"foo", "bar", "bletch", NULL}; foo(ptrs); // ptrs decays from char *[N] to char ** }
- You want to dynamically allocate a multi-dimensional array:
#define ROWS ... #define COLS ... ... char **arr = malloc(sizeof *arr * ROWS); if (arr) { size_t i; for (i = 0; i < ROWS; i++) { arr[i] = malloc(sizeof *arr[i] * COLS); if (arr[i]) { size_t j; for (j = 0; j < COLS; j++) { arr[i][j] = ...; } } } }
Solution 4:
It means that aPointer
points to a char pointer.
So
aPointer: pointer to char pointer
*aPointer :pointer to char
**aPointer: char
An example of its usage is creating a dynamic array of c strings
char **aPointer = (char**) malloc(num_strings);
aPointer gives you a char, which can be used to represent a zero-terminated string.
*aPointer = (char*)malloc( string_len + 1); //aPointer[0]
*(aPointer + 1) = (char*)malloc( string_len + 1); //aPointer[1]