'Pointers - What does a '*' after a struct mean in the function definition? [closed]
I am learning about pointers in C. I have come across a function that has a return type I do not understand. The function definition is:
extern PHONE* findPhone()
PHONE is a struct. the function returns a PHONE pointer. If it wanted to do this shouldn't the return type in the function definition BE '*PHONE'
Solution 1:[1]
extern PHONE* findPhone()
is parsed as
extern PHONE (*findPhone())
Declarations in C are broken up into two main sections - a sequence of declaration specifiers (type specifiers, storage class specifiers, type qualifiers, etc.) followed by a comma-separated list of declarators.
Array-ness, function-ness, and pointer-ness are specified as part of the declarator. In the declaration above, extern PHONE are the declaration specifiers and *findPhone() is the declarator; it indicates that the findPhone() function returns a pointer to PHONE.
The idea is that the structure of the declarator match the structure of an expression in the code of the same type. In this case, if you want to access the PHONE object that the function returns, you would call the function and dereference the result:
a_phone = *findPhone();
The type of the expression *findPhone() is PHONE, thus the declaration of the function is
PHONE *findPhone();
Whitespace is not significant beyond separating tokens of the same type (such as extern and PHONE, which are both identifiers). Since the * character can never be part of an identifier, it doesn’t matter if you write
extern PHONE* findPhone();
or
extern PHONE *findPhone();
or
extern PHONE * findPhone() ;
or even
extern PHONE*findPhone();
They will all be interpreted the same way.
Solution 2:[2]
An asterisk in this position is part of the grammar for a declarator. It denotes a pointer.
In C, a declaration is a list of declaration-specifiers followed by a list of declarators with optional initializations.
The declaration-specifiers specify a type like int, double, long long, struct foo, or a typedef name. (They also include additional kinds of specifiers like extern and inline, which are not of consequence in this answer.) Whatever type T this is, the declarators then specify things that have the type T.
Declarators have several forms:
- A plain name,
D, saysDhas the typeT. - A declarator in parentheses,
(D), means the expression(D)has the typeT, which meansDalso has typeT, so this has the same meaning as a plain name in a declarator. However, it groups the declarator for further parsing. - A declarator with brackets,
D[expression], means the expressionD[i]will have the typeT, which meansDmust be an array of the type. - A declarator with an asterisk,
*D, means the expression*Dwill have the typeT, soDmust be a pointer toT. - A declarator with parentheses,
D(), means the expressionD()will have the typeT, which meansDmust be a function that returnsT.
These forms can be combined. A declarator (*D)[] says (*D)[] has type T, so (*D) is an array of T, so *D is also an array of T, so D is a pointer to an array of T.
Essentially, a declarator is a picture of how a name will be used in expressions, and the actual type of the name is figured out by working backwards from what the type of that expression is.
So extern PHONE* findPhone() is grammatically extern PHONE and * findPhone(). It says that the type of * findPhone() is PHONE. So findPhone() is a pointer to a PHONE. So findPhone is a function returning a pointer to the type PHONE.
(There are additional parts of declarators not discussed above, such as parameter lists for functions and some options for the contents of brackets when declaring arrays.)
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | John Bode |
| Solution 2 | Eric Postpischil |
