Home > Enterprise >  Pointers - What does a '*' after a struct mean in the function definition?
Pointers - What does a '*' after a struct mean in the function definition?

Time:03-31

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'

CodePudding user response:

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, says D has the type T.
  • A declarator in parentheses, (D), means the expression (D) has the type T, which means D also has type T, 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 expression D[i] will have the type T, which means D must be an array of the type.
  • A declarator with an asterisk, *D, means the expression *D will have the type T, so D must be a pointer to T.
  • A declarator with parentheses, D(), means the expression D() will have the type T, which means D must be a function that returns T.

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.)

CodePudding user response:

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.

  • Related