Related
While going through an example of pointers I came across a line which was *p[5] declares p as an array of 5 pointers while (*p)[5] declares p as a pointer to an array of five elements. I didn't understand the difference between them.
Could anyone explain it with an example?
1. int (*p)[5]
is called a Pointer to an Array(Array Pointer). We can declare a pointer that can point to whole array instead of only one element of the array.This pointer is useful when talking about multidimensional arrays.
In this example p is pointer that can point to an array of 5 integers.
/*Pointer to an array*/
#include<stdio.h>
int main(void)
{
int *ptr; /*can point to an integer*/
int (*p)[5];/*can point to an array of 5 integers*/
int arr[5];
ptr=arr;/*points to 0th element of arr*/
p=&arr;/*points to the whole array arr*/
printf("ptr=%p,p=%p\n",ptr,p);
ptr++;
p++;
printf("ptr=%p,p=%p\n",ptr,p);
return 0;
}
Output:
ptr=0012FEAC,p=0012FEAC
ptr=0012FEB0,P=0012FEC0
Here ptr is pointer that points to 0th element of array arr,while p is pointer that points to the whole array arr.The base type of ptr is int while base type of p is ‘an array of 5 integers’.
We know that pointer arithmetic is performed relative to the base size,so if we write p++ then the pointer will be shifted forward by 20 bytes.
2. Now coming to *p[5]:
This is called Array of Pointers(Pointer Array)
Correct syntax is datatype *arrayname[size];
We can declare an array that contains pointers as its elements.Every element of this array is a pointer variable that can hold address of any variable of appropriate type.
/*Array of pointers*/
#include<stdio.h>
int main(void)
{
int *p[5];
int i,a=5,b=10,c=15;
p[0]=&a;
p[1]=&b;
p[2]=&c;
for(i=0;i<3;i++)
{
printf("p[%d]=%p\t",i,p[i]);
printf("*p[%d]=%d\n",i,*p[i]);
}
return 0;
}
Output:
p[0]=0012FEB4 *p[0]=5
p[1]=0012FEA8 *p[1]=10
p[2]=0012FE9C *p[2]=15
I hope this explanation along with examples will clear your concepts.
Hope this is helpful :)
The order of evaluation differs. *p[3] resolves to *(p[3]) but not (*p)[3]. Also note that *p is equivalent to p[0]. Therefore, ...
*p[3] ⇔ *(p[3]) ⇔ (p[3])[0] ⇔ p[3][0]
(*p)[3] ⇔ (p[0])[3] ⇔ p[0][3]
Assuming you have an array of arrays, the difference is shown below:
A pointer is like a sticky note; you write on it where you put the actual object.
An array is a box with equal compartments. It can store objects of the same type.
You have three balls.
An array of three pointers is a box that contains three stickers. Each sticker tells where each ball is located (they might not be all in the same place).
A pointer to an array of three elements is a sticky note that tells where to find the box. The box contains all tree balls.
Let us see if this helps ,in short, assuming int
1) int *p[3]
int *p1 = &i;
int *p2 = &j;
int *p3 = &k;
Instead of the above 3 separate pointers, I can have an array of pointers as int *p[3]. Each element in the array can point to i,j, and k, all are ints
2) int (*p)[3]
int array[3];
If I want a pointer which points to this array which have 3 elements, the pointer declaration will be int (*p)[3]. This is a pointer pointing to array
I'm new in programming and learning about pointers in array. I'm a bit confused right now. Have a look at the program below:
#include <stdio.h>
int fun();
int main()
{
int num[3][3]={23,32,478,55,0,56,25,13, 80};
printf("%d\n",*(*(num+0)+1));
fun(num);
printf("%d\n", *(*(num+0)+1));
*(*(num+0)+0)=23;
printf("%d\n",*(*(num+0)));
return 0;
}
int fun(*p) // Compilation error
{
*(p+0)=0;
return 0;
}
This was the program written in my teacher's notes. Here in the main() function, in the printf() function dereference operator is being used two times because num is pointer to array so first time dereference operator will give pointer to int and then second one will give the value at which the pointer is pointing to.
My question is that when I'm passing the array name as argument to the function fun() then why *p is used; why not **p as num is a pointer to array?
Second thing why *(p+0) is used to change the value of zeroth element of the array; why not *(*(p+0)+0)=0 as in the main() function *(*(num+0)+0) is used to change the value of zeroth element?
The whole thing is very confusing for me but I have to understand it anyway. I have searched about this and found that there is a difference between pointer to array and pointer to pointer but I couldn't understand much.
The trick is the array-pointer-decay: When you mention the name of an array, it will decay into a pointer to its first element in almost all contexts. That is num is simply an array of three arrays of three integers (type = int [3][3]).
Lets analyse the expression *(*(num + 1) + 2).
When you mention num in the expression *(num + 1), it decays into a pointer to its first element which is an array of three integers (type = int (*)[3]). On this pointer pointer arithmetic is performed, and the size of whatever the pointer points to is added to the value of the pointer. In this case it is the size of an array of three integers (that's 12 bytes on many machines). After dereferencing the pointer, you are left with a type of int [3].
However, this dereferencing only concerns the type, because right after the dereferencing operation, we see expression *(/*expression of type int[3]*/ + 2), so the inner expression decays back into a pointer to the first array element. This pointer contains the same address as the pointer that results from num + 1, but it has a different type: int*. Consequently, the pointer arithmetic on this pointer advances the pointer by two integers (8 bytes). So the expression *(*(num + 1) + 2) yields the integer element at an offset of 12 + 8 = 20 bytes, which is the sixth integer in the array.
Regarding your question about the call of fun(), that call is actually broken, and only works because your teacher did not include the arguments in the forward declaration of fun(). The code
int fun(int* arg);
int main() {
int num[3][3] = ...;
...
fun(num);
}
would have generated a compile time error due to the wrong pointer type. The code of your teacher "works", because the pointer to the first array in num is the same as the pointer to the first element of the first array in num, i. e. his code is equivalent to
int fun(int* arg);
int main() {
int num[3][3] = ...;
...
//both calls are equivalent
fun(num[0]);
fun(&num[0][0]);
}
which would compile without error.
This example shows a matrix, pointers to the first integers of arrays, and pointer to pointer
#include<stdio.h>
int fun(int (*p)[3]); /* p is pointer to array of 3 ints */
int main()
{
/* matrix */
int num[3][3]={{23,32,478},{55,0,56},{25,13, 80}};
/* three pointers to first integer of array */
int *pnum[3] = {num[0], num[1], num[2]};
/* pointer to pointer */
int **ppnum = pnum;
printf("%d\n", *(*(num+1)+2));
fun(num);
printf("%d\n", *(*(num+1)+2));
pnum[1][2] = 2;
printf("%d\n", *(*(num+1)+2));
ppnum[1][2] = 3;
printf("%d\n", *(*(num+1)+2));
return 0;
}
int fun(int (*p)[3])
{
p[1][2]=1;
return 0;
}
You do not actually need any pointers to print anything here.
Your int num[3][3] is actually an array of three elements, each of which is an array of three integers. Thus num[0][0] = 23, num[1][1] = 0, and so on. Thus you can say printf("%d", num[0][0]) to print the first element of the array.
Pointer to variable:
Pointer is variable which stores the address( of a variable). Every one know that.
Pointer to Array:
An array is a variable which has the starting point(address) of group of same objects.
And the pointer is a variable which stores the starting point(address) of an Array.
For example:
int iArray[3];
iArray is a variable which has an address value of three integers and the memory is allocated statically. And the below syntax is provided in a typical programming languages.
// iArray[0] = *(iArray+0);
// iArray[1] = *(iArray+1);
// iArray[2] = *(iArray+2);
In the above the iArray is a variable through which we can access the three integer variables, using any of the syntax mentioned above.
*(iArray+0); // Here iArray+0 is the address of the first object. and * is to dereference
*(iArray+1); // Here iArray+1 is the address of the second object. and * is to dereference
So simple, what is there to confuse.
The below lines are for your understanding
int iArray1[3];
int iArray2[3][3];
int *ipArray = 0;
ipArray = iArray1; // correct
ipArray = iArray2[0]; // correct
ipArray = iArray2[2]; // correct
int **ippArray = iArray2; // wrong
As per the above last line, compiler will not take it as a valid assignment. So **p is not used.
Pointer arthmatic cannot be applied on double arrays because of the way memory is allocated.
I am trying to compute the power of the matrix A using multiplications.
I am having problems with the ArrayPower function. It does not function as i think it should.The MultiArray function however seems to work fine. Can anyone help me ?
#include <stdio.h>
int** MultiArray(int a[2][2],int b[2][2]);
int** ArrayPower(int a[2][2],int e);
int main(void)
{
int fa[2][2];
fa[0][0]=0;
fa[0][1]=1;
fa[1][0]=1;
fa[1][1]=1;
int **multifa=malloc(sizeof(int)*2);
for (int i=0;i<2;i++) {
multifa[i]=malloc(sizeof(int)*2);
}
multifa=ArrayPower(fa,2);
printf("%d %d\n",multifa[0][0],multifa[0][1]);
printf("%d %d\n",multifa[1][0],multifa[1][1]);
return 0;
}
int** MultiArray(int a[2][2], int b[2][2]) {
//multi a *b
//memory allocation
int i,rows=2,cols=2;
int **c=malloc(rows*sizeof(int));
for (i=0;i<rows;i++) {
c[i]=malloc(cols*sizeof(int));
}
c[0][0]=a[0][0]*b[0][0]+a[0][1]*b[1][0];
c[0][1]=a[0][0]*b[0][1]+a[0][1]*b[1][1];
c[1][0]=a[1][0]*b[0][0]+a[1][1]*b[1][0];
c[1][1]=a[1][0]*b[0][1]+a[1][1]*b[1][1];
return c;
}
int** ArrayPower(int a[2][2],int e) {
//memory allocation
int i,rows=2,cols=2;
int **c=malloc(rows*sizeof(int));
for (i=0;i<rows;i++) {
c[i]=malloc(cols*sizeof(int));
}
c[0][0]=a[0][0];
c[0][1]=a[0][1];
c[1][0]=a[1][0];
c[1][1]=a[1][1];
for (i=1;i<e;i++) {
c=MultiArray(a,c);
}
return c;
}
MultiArray is declared as taking a second parameter of type int [2][2], but it is called with an argument of c, which as type int **. These are not compatible types.
In a parameter, the type int [2][2] is automatically converted to a pointer to an array of two int, the type int (*)[2]. This is a pointer to a place where there are two int objects (and, because we know it is the first element of an array of two arrays of two int objects, we know there are two more int objects beyond the first two).
The definition of c with int **c means that c is a pointer to a pointer to an int. A pointer to a pointer and a pointer to an array are different and are not compatible.
One way to fix this is to define c with int (*c)[2] = malloc(2 * sizeof *c);. It is then unnecessary to have the loop after the definition that allocates more space; the single allocation allocates the entire array.
The return type of MultiArray should be changed similarly, as well as the code within it and elsewhere in the program. Alternatively, the second parameter of MultiArray can be changed from int b[2][2] to int **b. (This latter is an easier edit but produces an inferior program, since it uses more pointers and allocations than necessary.)
You should always compile your code with warnings enabled. That would have alerted you to the incorrect call.
My program is
#define ARRLEN 10
#define SIZEALCO 128
#define MAX_STRING_LENGTH 12
in main function,
char TYPEDATA_XML_FN[ARRLEN][SIZEALCO];
char TYPEDATA_MD5_FN[ARRLEN][SIZEALCO];
char identifier[ARRLEN][MAX_STRING_LENGTH];
char Temppath[SIZEALCO];
int arraynum;
// ...
arraynum = 0;
for(arraynum = 0; arraynum <ARRLEN; arraynum++)
{
/* Create the file name with the path*/
strcpy(Temppath,"/fw/TYPEDATA/");
nameFil(Temppath,identifier[arraynum],TYPEDATA_XML_FN[arraynum],TYPEDATA_MD5_FN[arraynum]);
}
subfunction is :
void nameFil(char *SourPath,char *InPinName,char *FilePathNameXml,char *FilePathNameMd5)
{
sprintf(FilePathNameXml, "%s\\%s_TYPEDATA.XML",SourPath,InPinName);
sprintf(FilePathNameMd5, "%s\\%s_TYPEDATA.MD5",SourPath,InPinName);
}
I checked with your example. I used (trial)
char** a = calloc(ARRLEN, sizeof(char *));
for(i = 0; i < ARRLEN ; ++i)
a[i] = ucmalloc(MAX_STRING_LENGTH);
pase(a);
subfunction :
void pase(char b[ARRLEN][MAX_STRING_LENGTH])
{
// ...
}
Now I got the warning message as "warning: passing arg 1 of `pase' from incompatible pointer type".
Actually, I would like to pass the full string array identifier,TYPEDATA_XML_FN,TYPEDATA_MD5_FN. Now I am passing single string to the subfunction. Kindly guide me. Thank you
The prototype void pase(char b[ARRLEN][MAX_STRING_LENGTH]) is rather mis-leading,
void pase(char b[][MAX_STRING_LENGTH])
would be better, since otherwise there is the implication of bounds checking (the first array dimension is ignored).
The reason why you get "incompatible pointer type" is because a is an array of pointers. If a was incremented (as a pointer itself) then the address would increase by the size of a pointer. However, b is an array of arrays of size MAX_STRING_LENGTH, so if b was incremented then the value would increase by MAX_STRING_LENGTH.
The way you have allocated the array a will (probably) not give you contiguous memory, which is what is required here. You could achieve what you want using an array of pointers, but you really must decide what you want to do. If you want to use [][] notation then you need to
calloc(MAX_STRING_LENGTH,ARRLEN);
You are getting confused because although an one dimensional array char[] behaves like a pointer char *, in two dimensions a char[][N] is not convertible to a char **, being actually more like a (*char)[N] (pointer to arrays of length n of char).
So if you want to make a function that receives a two dimensional array, you have two choices:
Use pointers to pointers:
void f(char ** array, int nrows, int ncols);
To create a char**, do like you are already doing now: create an array for pointers and call malloc for each one of them.
Use two dimensional arrays:
void f(char array[][NCOLS], int nrows);
//note: NCOLS is a compile time constant now
//NROWS is the first dimension and can be omited from array[NROWS][NCOLS]
The tricky bit is malloc-ing a two dimensional array:
char (*my_array)[NCOLS];
//my_identifiers is a pointer to arrays of length NCOLS
// it can be passed to any function expecting a car[][NCOLS]
my_array = malloc(number_of_rows*(sizeof *my_array));
You can also make it easier to understand all of this with a good choice of typedefs:
typedef char MY_STRING[MAX_STR_LENGTH];
//define my strings as arrays of MAX_STRING_LENGTH
void f(MY_STRING array[]);
...
MY_STRING *arr = malloc(nstrings*sizeof(MY_STRING));
f(arr);
How do I understand following complicated declarations?
char (*(*f())[])();
char (*(*X[3])())[5];
void (*f)(int,void (*)());
char far *far *ptr;
typedef void (*pfun)(int,float);
int **(*f)(int**,int**(*)(int **,int **));
As others have pointed out, cdecl is the right tool for the job.
If you want to understand that kind of declaration without help from cdecl, try reading from the inside out and right to left
Taking one random example from your list char (*(*X[3])())[5];
Start at X, which is the identifier being declared/defined (and the innermost identifier):
char (*(*X[3])())[5];
^
X is
X[3]
^^^
X is an array of 3
(*X[3])
^ /* the parenthesis group the sub-expression */
X is an array of 3 pointers to
(*X[3])()
^^
X is an array of 3 pointers to function accepting an unspecified (but fixed) number of arguments
(*(*X[3])())
^ /* more grouping parenthesis */
X is an array of 3 pointers to function accepting an unspecified (but fixed) number of arguments and returning a pointer
(*(*X[3])())[5]
^^^
X is an array of 3 pointers to function accepting an unspecified (but fixed) number of arguments and returning a pointer to an array of 5
char (*(*X[3])())[5];
^^^^ ^
X is an array of 3 pointers to function accepting an unspecified (but fixed) number of arguments and returning a pointer to an array of 5 char.
Read it out from the inside, similar to how you would solve equations such as {3+5*[2+3*(x+6*2)]}=0 - you'd start by solving what's inside () then [] and finally {}:
char (*(*x())[])()
^
This means that x is something.
char (*(*x())[])()
^^
x is a function.
char (*(*x())[])()
^
x returns a pointer to something.
char (*(*x())[])()
^ ^^^
x returns a pointer to an array.
char (*(*x())[])()
^
x returns a pointer to an array of pointers.
char (*(*x())[])()
^ ^^^
x returns a pointer to an array of pointers to functions
char (*(*x())[])()
^^^^
Meaning the array pointer returned by x points to an array of function pointers that point to functions that return a char.
But yeah, use cdecl. I used it myself to check my answer :).
If this is still confusing you (and it probably should), try to do the same thing on a piece of paper or in your favorite text editor. There's no way of knowing what it means just by looking at it.
Sounds like a job for the cdecl tool:
cdecl> explain char (*(*f())[])();
declare f as function returning pointer to array of pointer to function returning char
I looked around for an official homepage for the tool, but couldn't find one that seemed genuine. In Linux, you can typically expect your distribution of choice to include the tool, so I just installed it in order to generate the above sample.
You should be using cdecl tool. It should be available on most Linux distributions.
e.g. for this function, it will return you:
char (*(*f())[])(); - declare f as function returning pointer to array of pointer to function returning char
void (*f)(int,void (*)()); - prototype of function pointer f. f is a function that takes two parameters, the first one is int, and the second one is a function pointer for a function which returns void.
char far *far *ptr; - ptr is a far pointer to a far pointer (which points to some char/byte).
char (*(*X[3])())[5]; - X is an array of 3 pointers to function accepting an undeterminate number of arguments and returning a pointer to an array of 5 char.
typedef void (*pfun)(int,float); - declaring function pointer pfun. pfun is a fuctnion that takes two parameters, first one is int, second one is of float type. the function does not have a return value;
e.g.
void f1(int a, float b)
{ //do something with these numbers
};
Btw, complicated declarations as the last one are not seen often. Here is an example I just made up for this purpose.
int **(*f)(int**,int**(*)(int **,int **));
typedef int**(*fptr)(int **,int **);
int** f0(int **a0, int **a1)
{
printf("Complicated declarations and meaningless example!\n");
return a0;
}
int ** f1(int ** a2, fptr afptr)
{
return afptr(a2, 0);
}
int main()
{
int a3 = 5;
int * pa3 = &a3;
f = f1;
f(&pa3, f0);
return 0;
}
It appears that your actual question is this:
What's the use case for a pointer to a pointer?
A pointer to a pointer tends to show up when you have an array of some type T, and T itself is a pointer to something else. For example,
What's a string in C? Typically, it's a char *.
Would you like an array of strings from time to time? Sure.
How would you declare one? char *x[10]: x is an array of 10 pointers to char, aka 10 strings.
At this point, you might be wondering where char ** comes in. It enters the picture from the very close relationship between pointers arithmetic and arrays in C. An array name, x is (almost) always converted to a pointer to it's first element.
What's the first element? A char *.
What's a pointer to the first element? A char **.
In C, array E1[E2] is defined to be equivalent to *(E1 + E2). Usually, E1 is the array name, let's say x, which automatically converted to a char **, and E2 is some index, say 3. (This rule also explains why 3[x] and x[3] are the same thing.)
Pointers to pointers also show up when you want a dynamically allocated array of some type T, which is itself a pointer. To start with, let's pretend we don't know what type T is.
If we want a dynamically allocated vector of T's, what type do we need? T *vec.
Why? Because we can perform pointer arithmetic in C, any T * can serve as the base of a contiguous sequence of T's in memory.
How do we allocate this vector, say of n elements? vec = malloc(n * sizeof(T));
This story is true for absolutely any type T, and so it's true for char *.
What's the type of vec if T is char *? char **vec.
Pointers to pointers also show up when you have a function that needs to modify an argument of type T, itself a pointer.
Look at the declaration for strtol: long strtol(char *s, char **endp, int b).
What's this all about? strtol converts a string from base b to an integer. It wants to tell you how far into the string it got. It could perhaps return a struct containing both a long and a char *, but that's not how it's declared.
Instead, it returns its second result by passing in the address of a string which it modifies before returning.
What's a string again? Oh yeah, char *.
So what's an address of a string? char **.
If you wander down this path long enough, you can also run into T *** types, although you can almost always restructure the code to avoid them.
Finally, pointers to pointers appear in certain tricky implementations of linked lists. Consider the standard declaration of a doubly-linked list in C.
struct node {
struct node *next;
struct node *prev;
/* ... */
} *head;
This works fine, although I won't reproduce the insertion/deletion functions here, but it has a little problem. Any node can be removed from the list (or have a new node inserted before it) without reference the head of the list. Well, not quite any node. This isn't true of the first element of the list, where prev will be null. This can be moderately annoying in some kinds of C code where you work more with the nodes themselves than with the list as a concept. This is a reasonably common occurrence in low-level systems code.
What if we rewrite node like this:
struct node {
struct node *next;
struct node **prevp;
/* ... */
} *head;
In each node, prevp points not at the previous node, but at the previous nodes's next pointer. What about the first node? It's prevp points at head. If you draw out a list like this (and you have to draw it out to understand how this works) you'll see that you can remove the first element or insert a new node before the first element without explicitly referencing head by name.
x: function returning pointer to
array[] of pointer to function
returning char" - huh?
You have a function
That function returns a pointer.
That pointer points to an array.
That array is an array of function pointers(or pointers to functions)
Those functions returns char*.
what's the use case for a pointer to a pointer?
One is to facilitate return values through arguments.
Lets say you have
int function(int *p)
*p = 123;
return 0; //success !
}
You call it like
int x;
function(&x);
As you can see, for function to be able to modify our x we have to pass it a pointer to our x.
What if x was not an int, but a char * ? Well, its still the same, we have to pass a pointer to that. A pointer to a pointer:
int function(char **p)
*p = "Hello";
return 0; //success !
}
You call it like
char *x;
function(&x);
Remo.D's answer for reading functions is a good suggestion. Here are some answers to the others.
One use-case for a pointer to a pointer is when you wish to pass it to a function that will modify the pointer. For example:
void foo(char **str, int len)
{
*str = malloc(len);
}
Also, this could be an array of strings:
void bar(char **strarray, int num)
{
int i;
for (i = 0; i < num; i++)
printf("%s\n", strarray[i]);
}
Typically, one shouldn't use declarations this complicated, although sometimes you do need types that are pretty complicated for things like function pointers. In those cases, it's much more readable to use typedefs for intermediate types; for example:
typedef void foofun(char**, int);
foofun *foofunptr;
Or, for your first example of "function returning pointer to array[] of pointer to function returning char", you might do:
typedef char fun_returning_char();
typedef fun_returning_char *ptr_to_fun;
typedef ptr_to_fun array_of_ptrs_to_fun[];
typedef array_of_ptrs_to_fun *ptr_to_array;
ptr_to_array myfun() { /*...*/ }
In practice, if you're writing anything sane, many of those things will have meaningful names of their own; for instance, these might be functions returning names (of some sort), so fun_returning_char could be name_generator_type, and array_of_ptrs_to_fun could be name_generator_list. So you could collapse it a couple of lines, and only define those two typedefs -- which are probably going to be useful elsewhere in any case.
char far *far *ptr;
This is an obsolete Microsoft form, dating back to MS-DOS and very early Windows days. The SHORT version is that this is a far pointer to a far pointer to a char, where a far pointer can point anywhere in memory, as opposed to a near pointer which could only point anywhere in 64K data segment. You really don't want to know the details about Microsoft memory models for working around the utterly brain-dead Intel 80x86 segmented memory architecture.
typedef void (*pfun)(int,float);
This declares pfun as a typedef for a pointer to a procedure that takes an int and a float.
You would normally use this in a function declaration or a prototype, viz.
float foo_meister(pfun rabbitfun)
{
rabbitfun(69, 2.47);
}
We have to evaluate all pointer declaration statements from left to right, starting from where the pointer name or declaration name is declared on the statement.
While evaluating the declaration, we have to start from the innermost parenthesis.
Start with the pointer name or function name followed by the rightmost characters in the parenthersis and then follwed by the leftmost characters.
Example:
char (*(*f())[])();
^
char (*(*f())[])();
^^^
In here f is a function name, so we have to start from that.
f()
char (*(*f())[])();
^
Here there are no declarations on the righthand side of the current
parenthesis, we do have to move to the lefthand side and take *:
char (*(*f())[])();
^
f() *
We have completed the inner parenthesis characters, and now we have to go back to one level behind this:
char (*(*f())[])();
------
Now take [], because this is on the right side of the current parenthesis.
char (*(*f())[])();
^^
f() * []
Now take the * because there is no character on the right side.
char (*(*f())[])();
^
char (*(*f())[])();
^
f() * [] *
char (*(*f())[])();
Next evaluate the outer open and close parenthesis, it's indicating a function.
f() * [] * ()
char (*(*f())[])();
Now we can add data type at the end of the statement.
f() * [] * () char.
char (*(*f())[])();
Final answer:
f() * [] * () char.
f is a function returning pointer to array[] of pointers to function returning char.
Forget about 1 and 2 - this is just theoretical.
3: This is used in the program entry function int main(int argc, char** argv). You can access a list of strings by using a char**. argv[0] = first string, argv[1] = second string, ...
Passing a pointer as an argument to a function lets that function change the contents of the variable pointed to, which can be useful for returning information by means other than the function return value. For example, the return value might already be used to indicate error/success, or you might want to return multiple values. The syntax for this in the calling code is foo(&var), which takes the address of var, i.e., a pointer to var.
So as such, if the variable whose contents you want the function to change is itself a pointer (e.g., a string), the parameter would be declared as a pointer to a pointer.
#include <stdio.h>
char *some_defined_string = "Hello, " ;
char *alloc_string() { return "World" ; } //pretend that it's dynamically allocated
int point_me_to_the_strings(char **str1, char **str2, char **str3)
{
*str1 = some_defined_string ;
*str2 = alloc_string() ;
*str3 = "!!" ;
if (str2 != 0) {
return 0 ; //successful
} else {
return -1 ; //error
}
}
main()
{
char *s1 ; //uninitialized
char *s2 ;
char *s3 ;
int success = point_me_to_the_strings(&s1, &s2, &s3) ;
printf("%s%s%s", s1, s2, s3) ;
}
Note that main() does not allocate any storage for the strings, so point_me_to_the_strings() does not write to str1, str2, and str3 as it would if they were passed as pointers to chars. Rather, point_me_to_the_strings() changes the pointers themselves, making them point to different places, and it can do this because it has pointers to them.