Complex pointer declarations - c

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.

Related

Why does function pointer in c does not have to be pointer at all?

Having this:
#include <stdio.h>
#include <stdlib.h>
int do_op(int (*op)(int,int),int a, int b){ return op(a,b); }
/*int do_op(int (op)(int,int),int a,int b){return op(a,b);} */
int add(int a, int b){ return a+b; }
int mul(int a, int b){ return a*b; }
int main(){
printf("add:%i;mul:%i\n",do_op(add,5,10),do_op(mul,5,10));
}
From what I know about function pointer so far, is their "type" is of return value's type. (Does not know how it is implemented in gas, wheter the return value is in %rax before ret? just an detail), however what is the point of a reference to a function, when it does not have to be reference at all? What does it mean, when it is not pointer? (like (op)), is then the function used by value (not address)? But function in general does not have value, it has only start address in %rbi and after it finishes, it is retuned back to upper function by ret, so what does it mean in c, a function "pointer" is not pointer? (give some examples please)
The question is relating to the comment in the code, where the (op) part is not a pointer, but still work. So is it a pointer or not?
The type of a function pointer is not its return type. It is the type of the function pointed to.
In the case of the parameter int (*op)(int,int), the type of op is "pointer to function which takes an int and an int, and returns int".
You could also define the parameter as int op(int,int) in which case the type of op is "function which takes an int and an int, and returns int".
Because function pointers point to code, they don't have a "value" in the sense that objects do. In fact, anyplace you specify an expression with a function type it is automatically converted to a pointer to a function. So you can declare the parameter op as int (*op)(int,int) or int op(int,int) and they will be exactly the same.
Section 6.3.2.1p4 of the C standard says the following regarding function types:
A function designator is an expression that has function
type. Except when it is the operand of the sizeof operator,
the _Alignof operator, or the unary & operator, a function
designator with type ‘‘function returning type’’ is converted to an
expression that has type ‘‘pointer to function returning type’’.
Section 6.7.6.3p8 also says the following regarding a function type as a parameter:
A declaration of a parameter as ‘‘function returning type’’ shall be
adjusted to ‘‘pointer to function returning type’’, as in 6.3.2.1.
It is because of this that a parameter of function type is allowed. A variable of function type that is not a parameter is not useful because it can't be initialized or assigned.
From what I know about function pointer so far, is their "type" is of return value's type.
No. I know we've addressed this issue in comments and answers to some of your previous questions. The type of a function pointer is different from the pointed-to function's return type, and also different from a pointer to the function's return type. The type of a function pointer is a particular function pointer type. All function pointer types have a return type as one of their attributes. They also convey information about the number and type of the function's parameters. Function pointer type names also differ from all object pointer type names. In the present case, the type name is int (*)(int,int), which I'm sure you see is different from both int and int *.
what is the point of a reference to a function, when it does not have to be reference at all?
The reason for using a function pointer (not "reference") is to allow different actual functions to be selected at runtime. In your case, different calls to function do_op() can be made to perform different operations. That's no big deal in the example, because do_op() does nothing but call the specified function one time, and the choice of operation is hardcoded into each call, but it would be more interesting if, say, the choice of operation were dictated by user input.
And of course the argument corresponding to the function pointer parameter has to be a (compatible) function pointer. C does not make any exception to its type matching rules in such cases.
What does it mean, when it is not pointer? (like (op)),
But it is a pointer. Wherever an expression of function type appears in a valid C expression, other than as the operand of a unary & operator, it is automatically converted to a pointer to the function it identifies. That applies to the identifier of the function being called, too: the function-call operator, (), is an operator on function pointers. You can regard this as a convenience feature: you do not need to use the & operator to obtain a a function pointer. This makes code a bit easier to write and read. C does not provide any way to express accessing a function value.
The question is relating to the comment in the code, where the (op) part is not a pointer, but still work. So is it a pointer or not?
Parameter op of function do_op() is a pointer to a function that expects two arguments of type int and returns an int. In each call to that function, the corresponding argument is a function identifier. As expressions of function type, these are automatically converted to pointers. The resulting function pointers are of the expected type.
From what I know about function pointer so far, is their "type" is of
return value's type.
From the C Standard (6.2.5 Types)
A function type is characterized by its return type and the number and
types of its parameters.
For example the type of these functions
int add(int a, int b){ return a+b; }
int mul(int a, int b){ return a*b; }
is int( int, int ). That is to describe a function you have to specify what it accepts and what it returns.
What does it mean, when it is not pointer? (like (op))
In this declaration
int do_op(int (op)(int,int),int a,int b){return op(a,b);}
the parameter op has the type int( int, int ). The compiler adjusts a parameter having a function type to a parameter having the type of pointer to the function.
So for example these two declarations
int do_op(int (op)(int,int),int a,int b);
int do_op(int (*op)(int,int),int a,int b);
that can be rewritten without parameter names like
int do_op(int (int,int),int ,int );
int do_op(int (*)(int,int),int ,int );
are equivalent and declare the same one function. You may include the both declarations in your program though the compiler can issue a warning that there are redundant declarations.
From the C Standard (6.7.6.3 Function declarators (including prototypes))
8 A declaration of a parameter as ‘‘function returning type’’ shall be
adjusted to ‘‘pointer to function returning type’’, as in 6.3.2.1.
When a function is used as an argument like in this statement
printf("add:%i;mul:%i\n",do_op(add,5,10),do_op(mul,5,10));
then it is implicitly converted to pointer to the function. The value of the pointer is the entry point of the function where the control can be passed.
From the C Standard (6.3.2.1 Lvalues, arrays, and function designators)
4 A function designator is an expression that has function type.
Except when it is the operand of the sizeof operator65) or the unary &
operator, a function designator with type ‘‘function returning type’’
is converted to an expression that has type ‘‘pointer to function
returning type’’.
Function pointers differ from data pointers in that they point to code, not to data. So the value of the pointer is going to be the memory location for the beginning on the function. Since the value is already and address in memory, there is no reason to deference it like we would a normal pointer.
This article seems to have a clear explanation of the concept with good examples if you want more details:
Function Pointers in C - GeeksforGeeks
A function pointer in c is always a pointer to the first instruction of the function.
A function value in c (the value of applying * to a function pointer) is also implemented the same as a function pointer, leading to this confusion.
In the end functions will always be pointers to code and the compiler is just ignoring whether you used a c function pointer or value.

How does an unsized array declaration act as a pointer?

How does char s[] act as a pointer while it looks like an array declaration?
#include<stdio.h>
void test(char s[]);
int main()
{
char s[10]="test";
char a[]=s;
test(s);
char p[]=s;
return 0;
}
void test(char s[])
{
printf(s);
}
In the context of a function parameter declaration (and only in that context), T a[N] and T a[] are the same as T *a; they declare a as a pointer to T, not an array of T.
Chapter and verse:
6.7.6.3 Function declarators (including prototypes)
...
7 A declaration of a parameter as ‘‘array of type’’ shall be adjusted to ‘‘qualified pointer to
type’’, where the type qualifiers (if any) are those specified within the [ and ] of the
array type derivation. If the keyword static also appears within the [ and ] of the
array type derivation, then for each call to the function, the value of the corresponding
actual argument shall provide access to the first element of an array with at least as many
elements as specified by the size expression.
Anywhere else, T a[]; declares a as an array with an as-yet-unspecified size. At this point the declaration is incomplete, and a cannot be used anywhere until a size has been specified, either by specifying it explicitly:
T a[N];
or using an initializer:
T a[] = { /* comma-separated list of initial values */ }
Chapter and verse, again:
6.7.6.2 Array declarators
...
3 If, in the declaration ‘‘T D1’’, D1 has one of the forms: D[ type-qualifier-listopt assignment-expressionopt ]
D[ static type-qualifier-listopt assignment-expression ]
D[ type-qualifier-list static assignment-expression ]
D[ type-qualifier-listopt * ]
and the type specified for ident in the declaration ‘‘T D’’ is ‘‘derived-declarator-type-list
T’’, then the type specified for ident is ‘‘derived-declarator-type-list array of T’’.142)
(See 6.7.6.3 for the meaning of the optional type qualifiers and the keyword static.)
4 If the size is not present, the array type is an incomplete type. If the size is * instead of
being an expression, the array type is a variable length array type of unspecified size,
which can only be used in declarations or type names with function prototype scope;143)
such arrays are nonetheless complete types. If the size is an integer constant expression
and the element type has a known constant size, the array type is not a variable length
array type; otherwise, the array type is a variable length array type. (Variable length
arrays are a conditional feature that implementations need not support; see 6.10.8.3.)
142) When several ‘‘array of’’ specifications are adjacent, a multidimensional array is declared.
143) Thus, * can be used only in function declarations that are not definitions (see 6.7.6.3).
...
6.7.9 Initialization
...
22 If an array of unknown size is initialized, its size is determined by the largest indexed
element with an explicit initializer. The array type is completed at the end of its
initializer list.
So, why are arrays as function parameters treated differently than arrays as regular objects? This is why:
6.3.2.1 Lvalues, arrays, and function designators
...
3 Except when it is the operand of the sizeof operator, the _Alignof operator, or the
unary & operator, or is a string literal used to initialize an array, an expression that has
type ‘‘array of type’’ is converted to an expression with type ‘‘pointer to type’’ that points
to the initial element of the array object and is not an lvalue. If the array object has
register storage class, the behavior is undefined.
Under most circumstances, an expression of type "N-element array of T" is converted ("decays") to an expression of type "pointer to T". If you pass an array expression as an argument to a function, like so:
int foo[10];
...
bar( foo );
what the function bar actually receives is a pointer to int, not a 10-element array of int, so the prototype for bar can be written
void bar( int *f );
"But why..." I hear you starting to ask. I'm getting to it, really.
C was derived from an earlier language called B (go figure), and in B the following things were true:
Pointer objects were declared using empty bracket notation - auto p[];. This syntax was kept for pointer function parameter declarations in C.
Array declarations set aside memory not only for the array elements, but also for an explicit pointer to the first element, which was bound to the array variable (i.e., auto v[10] would set aside 11 memory cells, 10 for the array contents, and the remaining one to store an offset to the first element).
The array subscript operation a[i] was defined as *(a + i) -- you'd offset i elements from the base address stored in the variable a and dereference the result (B was a "typeless" language, so all scalar objects were the same size).
For various reasons, Ritchie got rid of the explicit pointer to the first element of the array, but kept the definition of the subscript operation. So in C, when the compiler sees an array expression that isn't the operand of the sizeof or unary & operators, it replaces that expression with a pointer expression that evaluates to the address of the first element of the array; that way the *(a + i) operation still works the way it did in B, without actually setting aside any storage for that pointer value. However, it means arrays lose their "array-ness" in most circumstances, which will bite you in the ass if you aren't careful.
You can't assign to arrays, only copy to them or initialize them with a valid initializer (and another array is not a valid initializer).
And when you declare a function like
void test(char s[]);
it's actually the same as declaring it
void test(char *s);
What happens when you call a function taking an "array" is that the array decays to a pointer to the first element, and it's that pointer that is passed to the function.
So the call
test(s);
is the same as
test(&s[0]);
Regarding the function declaration, declaring a function taking an array of arrays is not the same as declaring a function taking a pointer to a pointer. See e.g. this old answer of mine as an explanation of why.
So if you want a function taking an array of arrays, like
void func2(char a[][X]);
it's not the same as
void func2(char **a);
Instead it's the same as
void func2(char (*a)[X]);
For more "dimensions" it doesn't change anything, e.g.
void func3(char a[][X][Y]);
is the same as
void func3(char (*a)[X][Y]);
char a[] is an array and not a pointer, the inittialization is invalid.
s is an array, too, but in the context of an expression it evaluates to a pointer to its first element.
char a[] is only valid if you have a following initializer list. It has to be an array of characters. As a special case for strings, C allows you to type an array of characters as "str", rather than {'s','t','r','\0'}. Either initializer is fine.
In the code char a[]=s;, s is an array type and not a valid initializer, so the code will not compile.
void test(char s[]) is another special case, because arrays passed as parameters always get replaced by the compiler with a pointer to the first element. Don't confuse this with array initialization, even though the syntax is similar.

How do both of these function pointer calling syntax variations work?

I'm relatively new to C, and found it intriguing that both of the following calls to the function pointer compile and work fine. One with and one without dereferencing the function pointer before calling it.
#include <stdio.h>
#include <stdlib.h>
void func() {
puts("I'm a func");
}
int main(void) {
void (*f)() = func;
f();
(*f)();
return EXIT_SUCCESS;
}
I think I understand that (*f)() is the "official" way to call a function pointer, but why does simply calling f() work? Is that syntactic sugar of recent C versions?
This is a piece of syntactic/semantic sugar that has, AFAIK, worked since the very earliest versions of C. It makes sense if you think of functions as pointers to code.
The only special rule needed to make function pointers work this way is that indirecting a function pointer gives the same pointer back (because you can't manipulate code in standard C anyway): when f is a function pointer, then f == (*f) == (**f), etc.
(Aside: watch out with declaration such as void (*f)(). An empty argument list denotes an old-style, pre-C89 function declaration that matches on the return type only. Prefer void (*f)(void) for type safety.)
A function call expression is always of the form "function pointer", "round parenthesis", "arguments", "round parenthesis". In order for you not to have to spell out (&printf)("Hello World\n") every time1, there is a separate rule by which an expression which denotes a function decays to the respective function pointer.
Since a function pointer can be dereferenced to give an expression that denotes a function again, this will again decay, so you can keep dereferencing and there'll be a lot of decay:
(&f)(); // no decay (decay does not happen when the expression
// is the operand of &)
f(); // one decay
(*f)(); // two decays
(**f)(); // three decays
1) Early Perl has function syntax like that.
The C 2011 standard says in clause 6.3.2.1, paragraph 4:
Except when it is the operand of the sizeof operator, the _Alignof operator, or the unary & operator, a function designator with type ‘‘function returning type’’ is converted to an expression that has type ‘‘pointer to function returning type’’.
This means that, if f designates a function, then, in a call such as f(), f is automatically converted to &f, resulting in (&f)(). This is actually the “proper” way to call a function, because the function-call expression requires a pointer to a function.
Now consider what happens in *f. The f is automatically converted to &f, so we have *&f. In this expression, the result of the * operator is a function, f; it just reverse the operation performed by &. So *&f is the same as f. We can repeat this indefinitely: **f is automatically converted to **&f, which is *f, which is automatically converted to *&f, which is f, which is automatically converted to &f.
In C you can call your function like:
f();
(*f)();
(**f)();
(********f)();
(*****************************f)();
all are valid. In C, dereferencing or taking the address of a function just evaluates to a pointer to that function, and dereferencing a function pointer just evaluates back to the function pointer. C is designed in such a way that both function name identifier as well as variable holding function's pointer mean the same: address to CODE memory. And it allows to jump to that memory by using call () syntax either on an identifier or variable.
And the last but but least, standard says that:
C11: 6.3.2.1:
4 A function designator is an expression that has function type. Except when it is the
operand of the sizeof operator, the _Alignof operator,65) or the unary & operator, a
function designator with type ‘‘function returning type’’ is converted to an expression that has type ‘‘pointer to function returning type’’.

When are array names constants or pointers?

In a document by Nick Parlante, it says, Array names are constant i.e array base address behaves like a const pointer.
e.g
{
int array[100], i;
array = NULL; //cannot change base address
array = &i; // not possible
}
But at the same time why is this valid:
void foo(int arrayparm[]){
arrayparm = NULL; // says it changes the local pointer
}
Function parameter declarations are different then formal declaration is C, in function declaration:
void foo(int arrayparm[])
^^^^^^^^^ is pointer not array
arrayparm is pointer but not array its type is int*. This is equivalent to:
void foo(int *arrayparm)
In function foo you can modify arrayparm.
Whereas in formal declaration(in side function) e.g.
int array[100];
array is not a pointer but it is a constant, It is type is char[100] and it is not modifiable lvalue.
Arrays decay into pointers in functions. The array name is a non-modifable lvalue. What this means is that, you can do this:
int x=10,y=20;
int *p = &x; // <---- p Now points to x
p = &y; // <---- p Now points to y
But not this:
int arr[10], x=10;
arr = &x; // <----- Error - Array name is a non-modifiable lvalue.
Since arrays decay immediately into pointers, an array is never actually passed to a function. As a convenience, any parameter declarations which "look like" arrays, e.g.
f(a)
char a[];
are treated by the compiler as if they were pointers, since that is what the function will receive if an array is passed:
f(a)
char *a;
This conversion holds only within function formal parameter declarations, nowhere else. If this conversion bothers you, avoid it; many people have concluded that the confusion it causes outweighs the small advantage of having the declaration "look like" the call and/or the uses within the function.
References: K&R I Sec. 5.3 p. 95, Sec. A10.1 p. 205; K&R II Sec. 5.3 p. 100, Sec. A8.6.3 p. 218, Sec. A10.1 p. 226;
When array names are passed as function argument, it "decays" to a pointer. So you can treat it like a normal pointer.
Reference: C FAQ what is meant by the ``equivalence of pointers and arrays'' in C?
Array types are not assignable in C. It was just a design decision. (It is possible to make assignment of array types copy one array over another, like assignment of structs. They just chose not to do this.)
The C99 standard, 6.5.16 paragraph 2:
An assignment operator shall have a modifiable lvalue as its left
operand.
C99 standard, 6.3.2.1 paragraph 1:
... A modifiable lvalue is an lvalue that does not have array type,
...
Plus, even if array types were assignable, NULL is not a value of type int[100].

Basic C Pointer and Functions

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.

Resources