Basic C Pointer and Functions - c

Im trying to figure out what the function declarations mean:
int *f();
and
int (*g)();

int *f();
The above line is the declaration of a function f that has an unspecified number of parameters and that returns an int *.
int (*g)();
The above line is the declaration of a pointer g to a function that has an unspecified number of parameters and that returns an int.

As an addition to the other correct answers here, I thought I'd mention that cdecl(1) is a handy tool for deciphering these sorts of declarations:
$ cdecl
Type `help' or `?' for help
cdecl> explain int *f();
declare f as function returning pointer to int
cdecl> explain int (*g)();
declare g as pointer to function returning int
cdecl may already be installed on your machine, or you can use it via a handy web interface at http://cdecl.org.

f is a function, returning int* and g is a pointer to function returning int.

Postfix operators such as function-call () have higher precedence than unary operators like *, so
T *f();
reads as
f -- f
f() -- is a function (() binds before *)
*f() -- returning a pointer
T *f(); -- to T (for some type T)
If you want to force * to bind before (), you must explicitly group with parentheses, so
T (*g)();
reads as
g -- g
(*g) -- is a pointer
(*g)() -- to a function
T (*g)(); -- returning T.
The rule is similar for arrays: T *a[N] is an array of pointer to T, whereas T (*p)[N] is a pointer to an array of T.

Related

Complex pointer declarations

I tried the declaration int * p()[] in cdecl.org and it says "declare p as function returning array of pointer to int".
According to me, the declaration means "p is array of functions returning pointer to int" and this doesn't make any sense. So this declaration should not be allowed right ?
Where am I going wrong ?
This declaration indeed should not be allowed; functions may not return array types, and you may not have arrays of function type:
6.7.6.2 Array declarators
Constraints
1 In addition to optional type qualifiers and the keyword static, the [ and ] may delimit
an expression or *. If they delimit an expression (which specifies the size of an array), the
expression shall have an integer type. If the expression is a constant expression, it shall
have a value greater than zero. The element type shall not be an incomplete or function
type. The optional type qualifiers and the keyword static shall appear only in a
declaration of a function parameter with an array type, and then only in the outermost
array type derivation.
...
6.7.6.3 Function declarators (including prototypes)
Constraints
1 A function declarator shall not specify a return type that is a function type or an array
type.
C 2011 Online Draft
Emphasis added. I don't know why cdecl doesn't return some kind of error on that.
If you want a function that returns a pointer to an array, you'd write
int (*p())[N];
This parses as
p -- p is a
p() -- function returning
*p() -- pointer to
(*p())[N] -- array of
int (*p())[N]; -- int
If you want an array of function pointers, you'd write
int (*p[N])();
which parses as
p -- p is an
p[N] -- array of
*p[N] -- pointer to
(*p[N])() -- function returning
int (*p[N])(); -- int
If you want a function that returns a pointer to an array of pointers, you'd write
int *(*p())[N];
which reads as
p -- p is a
p() -- function returning
*p() -- pointer to
(*p())[N] -- array of
*(*p())[N] -- pointer to
int *(*p())[N]; -- int
Postfix [] and () have higher precedence than unary *, so:
T *a[N]; // a is an array of pointer to T
T (*a)[N]; // a is a pointer to an array of T
T *f(); // f is a function returning pointer to T
T (*f)(); // f is a pointer to a function returning T
Starting with those rules, you can use substitution to build more complex declarations. If you want a function returning a pointer to an array, take
T (*a)[N];
and replace a with a function declarator:
T (* a )[N];
|
V
T (* f() )[N];
If you want an array of pointers to functions, take a function pointer declarator
T (*f)();
and replace f with an array declarator:
T (* f )()
|
V
T (* a[N] )();
From here, you should be able to read (and generate) more complex types.
cdecl's a nice tool, but once you learn how C declaration syntax really works, you shouldn't need it anymore.

Function with a pointer in its declaration. Why?

Not sure if the title explains it. What is the difference between:
char *s_gets(char * st, int n);
and
char s_gets(char * st, int n);
I would like to ask also why is there a pointer in the function declaration in the first place? What is its purpose?
char s_gets(char * st, int n); returns a character, that's all.
char *s_gets(char * st, int n); returns a pointer to a character, which can be interpreted as a pointer to a string, if it is the programmer's will.
char *s_gets(char * st, int n);
returns a pointer to char, while
char s_gets(char * st, int n);
returns a plain char.
I would like to ask also why is there a pointer in the function declaration in the first place? What is its purpose?
It indicates that the function returns a pointer value.
C declaration syntax uses something called a declarator to convey the pointer-ness, array-ness, function-ness, or combination thereof of an item. For example, take the declaration
int *p;
The type of p is int * (pointer to int). The type is specified by the combination of the type specifier int and the declarator *p. The int-ness of p is given by the type specifier int and the pointer-ness is given by the declarator *p.
If you substitute p with f(void), you get
int *f(void);
The type of f is "function returning pointer to int". The pointer-ness and function-ness of f are specified with the declarator *f(void).
For any type T and any declarator D, the following are true:
T D; // D is an instance of T
T D[N]; // D is an array of T
T D(); // D is a function returning T
T *D; // D is a *pointer* to T
T *D[N]; // D is an array of pointers to T
T *D(); // D is a function returning a pointer to T
T (*D)[N]; // D is a pointer to an array of T
T (*D)(); // D is a pointer to a function returning T
In both declarations and expressions, the postfix [] subscript and () function-call operators have higher precedence than unary *, so *a[N] will always be parsed as *(a[N]) (array of pointers). To declare something as a pointer to an array or a pointer to a function, you need to explicitly group the * operator with the declarator using parentheses.
Declarators can get arbitrarily complex:
T (*D())[N]; // D is a function returning a pointer to an array of T
T (*D[N])(); // D is an array of pointers to functions returning T
T *(*(*D)[N])[M]; // D is a pointer to an array of pointers to an array of pointers to T

C Reference Manual Appendix A - Meaning of declarators

While reading through the C reference manual, specifically Appendix A, I found the following statement
In a declaration T D where D has the form ( D1 ), then the type of the identifier in D1 is the same as that of D. The parenthesis do not alter the type but may change the binding in complex declarators.
How can a declarator take a form of ( D1 ) and what is the difference in binding that is being referred here.
eg: int a is a proper declaration but what would int (a) mean?
int (a) means exactly the same as int a. This is not a "complex declarator".
An example where it does make a difference is when declaring a function pointer:
int (*f)(float);
This means "f is a pointer to a function that takes a float and returns an int". Without the parentheses, it would read:
int *f(float);
This means "f is a function that takes a float and returns an int* (pointer to an int)". Something quite different indeed.
Try the website cdecl.org (or the command line tool cdecl) to explain these:
cdecl> explain int (*f)(float);
declare f as pointer to function (float) returning int
cdecl> explain int *f(float);
declare f as function (float) returning pointer to int

What does double* (*p[3]) (void* (*)()); mean?

I am having difficulty trying to understand what the following declaration means. Is this declaration standard?
double* (*p[3]) (void* (*)());
Can anyone help me to understand the meaning of this declaration?
Rule for reading hairy declarations: find the leftmost identifier and work outward, remembering that () and [] bind before *, so T *a[N] is an array of pointers to T, T (*a)[N] is a pointer to an array of T, T *f() is a function returning a pointer to T, and T (*f)() is a pointer to a function returning T. Since a function prototype may omit parameter names, you may see things like T *[N] or T (*)(). The meaning is mostly the same1, just pretend that there's an identifier of 0 length.
Thus,
p -- p
p[3] -- is a 3-element array
*p[3] -- of pointers
(*p[3]) ( ) -- to functions
(*p[3]) ( (*)()) -- taking a pointer to a function
(*p[3]) ( * (*)()) -- returning a pointer
(*p[3]) (void* (*)()) -- to void
* (*p[3]) (void* (*)()) -- returning a pointer
double* (*p[3]) (void* (*)()); -- to double
The important thing to take away here is that you are declaring p as an array of ..., not a function returning ....
What would such a beast look like in practice? Well, first, you need three functions to point to. Each of these functions takes a single parameter, which is a pointer to a function returning a pointer to void:
double *foo(void *(*)());
double *bar(void *(*)());
double *bletch(void *(*)());
double *(*p[3]) (void *(*)()) = {foo, bar, bletch};
Each of foo, bar, and bletch would call the function passed to it and somehow return a pointer to double.
You would also want to define one or more functions that satisfy the parameter type for each of foo, bar, and bletch:
void *blurga() {...}
so if you called foo directly, you'd call it like
double *pv;
...
pv = foo(blurga);
So we could imagine a call like
double *pv = (*p[0])(blurga);
1 - the difference is that in the context of a function parameter declaration, T a[] and T a[N] are identical to T *a; in all three cases, a is a pointer to T, not an array of T. Note that this is only true in a function parameter declaration. Thus, T *[] will be identical to T **.
Just use http://cdecl.org:
declare p as array 3 of pointer to function (pointer to function returning pointer to void) returning pointer to double
For more info, see this MSDN article: Interpreting more complex declarators.
But typedefs would help:
typedef void *(*foo)(); // foo is a function-pointer type
typedef double *(*bar)(foo); // bar is also a function-pointer type
bar p[3];
(Obviously, use appropriate names in place of foo and bar!)
Your p is an array of 3 pointers to a function returning a double pointer, and taking as argument a pointer to another function that returns a void pointer and that takes no arguments.
But, don't use this syntax, try using typedef instead.
It is array (of size 3) of function pointers which returns pointer to double and take another function pointer as argument.
Type of function whose pointer can be stored in the array: double *(func)(void* (*)())
Type of function whose pointer can be passed as argument to func: void *(func1)(void)
"There is a technique known as the ``Clockwise/Spiral Rule'' which enables any C programmer to parse in their head any C declaration!"
Clockwise Spiral Rule - http://c-faq.com/decl/spiral.anderson.html

Complex declarations

How do I interpret complex declarations like:
int * (* (*fp1) (int) ) [10]; ---> declaration 1
int *( *( *[5])())(); --------> declaration 2
Is there any rule that should be followed to understand the above declarations?
Here is a great article about how to read complex declarations in C: http://www.codeproject.com/KB/cpp/complex_declarations.aspx
It helped me a lot!
Especially - You should read "The right rule" section. Here quote:
int * (* (*fp1) (int) ) [10];
This can be interpreted as follows:
Start from the variable name -------------------------- fp1
Nothing to right but ) so go left to find * -------------- is a pointer
Jump out of parentheses and encounter (int) --------- to a
function that takes an int as argument
Go left, find * ---------------------------------------- and returns a pointer
Jump put of parentheses, go right and hit [10] -------- to an array of
10
Go left find * ----------------------------------------- pointers to
Go left again, find int -------------------------------- ints.
You can use cdecl*:
cdecl> explain int *( *( *a[5])())();
declare a as array 5 of pointer to function
returning pointer to function returning pointer to int
cdecl> explain int * (* (*fp1) (int) ) [10];
declare fp1 as pointer to function (int) returning
pointer to array 10 of pointer to int
*Linked is a website that uses this command line tool in the backend.
I've learned the following method long ago:
Start from the type identifier (or the inner parenthesis) and move following a spiral taking the element at right first
In case of
int * (* (*fp1) (int) ) [10];
You can say:
fp1 is a (nothing on the right so move left)
pointer to (move out of the inner parenthesis
a function taking int as agument (the 1st on the right)
and returns a pointer to (exit from parenthesis)
an array of 10 elements of type
pointer to (nothing left on the right)
int
Resulting in:
fp1 is a pointer to a function taking an int and returning a pointer to an array of 10 pointers to int
Drawing the actual spiral (in you your mind, at least) helps a lot.
For solving these complicated declarations, the rule you need to keep in mind is that the precedence of function-call operator () and array subscript operator [] is higher than dereference operator *. Obviously, parenthesis ( ) can be used to override these precedences.
Now, work out your declaration from the middle, which means from the identifier name.
int * (* (*fp1) (int) ) [10]; --->declaration 1
Based on the precedences rule mentioned above, you can easily understand it by breaking down the declaration as
fp1 * (int) * [10] * int
and read it directly from left-to-right in English as
"fp1 is a pointer to a function accepting an int & returning a pointer to an array [10] of pointers to int". Note that the declaration is broken this way only to help understand it manually. The compiler need NOT parse it this way.
Similarly,
int *( *( *[5])())(); -------->declaration 2
is broken as
[5] * () * () * int
So, it declares "an array [5] of type pointers to function () which returns a pointer to a function () which in turn returns a pointer to int".
Though it's has been answered already, but you may also read this article :
http://unixwiz.net/techtips/reading-cdecl.html
Start with the leftmost identifier and work your way out, remembering that absent any explicit grouping [] and () bind before *, e.g:
*a[] -- is an array of pointer
(*a)[] -- is a pointer to an array
*f() -- is a function returning pointer
(*f)() -- is a pointer to a function
Thus, we read int *(*(*fp1)(int))[10] as:
fp1 -- fp1
*fp1 -- is a pointer
(*fp1)(int) -- to a function
taking an int parameter
*(*fp1)(int) -- returning a pointer
(*(*fp1)(int))[10] -- to a 10-element array
*(*(*fp1)(int))[10] -- of pointer
int *(*(*fp1)(int))[10] -- to int
The declaration int *(*(*[5])())() presents a bit of a challenge since there's no identifier; you typically see this in function declarations where a parameter is of that type:
void foo(int *(*(*[5])())(), double);
It's the same principle as the unnamed int parameter in the declaration of fp1. The array gives us the clue, you can also look for the leftmost inner grouping of parentheses.
-- unnamed
[5] -- is a 5-element array ([] binds before *)
*[5] -- of pointers
(*[5])() -- to functions
*(*[5])() -- returning pointers
(*(*[5])())() -- to functions
*(*(*[5])())() -- returning pointers
int *(*(*[5])())() -- to int
The clockwise/spiral:
* http://c-faq.com/decl/spiral.anderson.html
No, you don't need to read it loud with complex steps like "clockwise/spiral rule" and "the right rule". Why should you? You only need to know how to use it! Don't make the simple one complex.
C declarations in fact work in a simple rule: declare as how would be used.
Consider the code you gives out:
int * (* (*fp1) (int) ) [10]; ---> declaration 1
int *( *( *[5])())(); --------> declaration 2
For the first declaration, this means that *(*(*fp1)(int))[int] is an int. And that's it.
For example, you know that *(*(*fp1)(5))[0] is an int, and *(*(*fp1)(2))[9] is an int too.
And The second declaration is incomplete. Even gcc won't know what you want to convey.

Resources