For pointers, I'm getting confused with declarations and function parameters on when to use char ** or char * or *array[n], etc. Like if a function takes a (*array[n]) parameter, do I pass it a **type?
I try using the Right-Left rule and know that p would be a pointer to a pointer to a char (char **p), and p is an array of n pointers (*p[n]), but someone said that *p[n] and **p are essentially equivalent. Is that true?
In the correct context (namely, arguments to a function), then the following declarations are equivalent:
int main(int argc, char *argv[]);
int main(int argc, char **argv);
int main(int argc, char *argv[12]); // Very aconventional!
Similar comments apply to the function definitions (which have a block enclosed in braces in place of the semi-colon).
In any other context, there are important differences between the notations. For example:
extern char *list1[];
extern char **list2;
extern char *list3[12];
The first says that somewhere there is an array of indeterminate size containing 'char *' values. The second says that somewhere - possibly here - there is a single value containing a pointer to a char pointer. The third says that somewhere - possibly here - there is an array of 12 character pointers.
However, all the three lists can be referenced in somewhat the same way - assuming that they actually have been defined and initialized.
list1[0][0] = '1';
list2[0][0] = '2';
list3[0][0] = '3';
Further, if they are passed into a function like this:
function(list1, list2, list3);
then the function can be declared as:
void function(char **list1, char **list2, char **list3);
The arrays (list1, list3) decay from the array to the pointer to the first element of the array; list2, of course, is already a pointer to a pointer.
One detail to note in a function such as:
void otherfunction(char *list[12])
{
...
}
The C compiler does not treat that declaration any differently from:
void otherfunction(char **list)
{
...
}
or
void otherfunction(char *list[])
{
...
}
In particular, it does no array bounds checking, and as far as the function is concerned, the 12 may as well be absent.
C99 introduces VLA (variable length array) types and also introduces a notation with 'static' and a size in the array bounds. You would need to read the standard to understand those fully.
Suffice to say in a function like the following the size of the array does matter, and is determined at run-time. With two-dimensional arrays in general, all the dimensions except the first need to be specified.
void vla_function(size_t m, int vla[m][m]);
Quoting from the standard (section 6.7.5.3):
void f(double (* restrict a)[5]);
void f(double a[restrict][5]);
void f(double a[restrict 3][5]);
void f(double a[restrict static 3][5]);
(Note that the last declaration also specifies that the argument corresponding to a in any call to f must be a non-null pointer to the first of at least three arrays of 5 doubles, which the others do not.)
Reading C declarators (that's the part of the variable with the * and []) is fairly nuanced. There are some websites with tips:
A char**
is a pointer to (possible multiple) pointer(s) to (possibly multiple) char(s). For example, it might be a pointer to a string pointer, or a pointer to an array of string pointers.
A char*[]
is an array of pointers to char. When you have a function that takes this as a parameter, the C compiler makes it "decay" into a char**
. This only happens to the first layer... so, taking a complicated example, char*[4][]
becomes char*(*)[4]
. Read the links above so you can understand what the heck that means.
Or you can do a (very sensible) thing and make a bunch of typedefs. I don't do this, but until you're good at reading declarators, it's a good idea.
typedef char * stringp;
void func(stringp array[]) { ... }
static stringp FOUR_STRINGS[4] = { ... };
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With