Home > OS >  How can I declare a Pointer to a struct in C?
How can I declare a Pointer to a struct in C?

Time:10-15

I have learned that pointers can be declared in 3 diffrent ways:

int* a;
int *b;
int * c;

I preffer:

int* a;

While declaring a pointer to a structure, is it correct to write it like following:

struct Card {
   int a;
};
struct Card my_card = { 3, 7 };
struct Card* p = &my_card; 
(*p).a = 8; 

I am confused because everywhere I have found it is declared as following:

struct Card *p = &my_card;

Thanks in advance.

CodePudding user response:

It doesn't matter where you put the spaces. struct Card* p and struct Card *p are equally valid; it's just a matter of style as to which one you prefer.

I agree the second form is more common, but what's most important is that you use one form consistently throughout your code. Your boss / teacher / other developers may also have coding style standards that specify which form to use.

CodePudding user response:

If T is some type specifier then a pointer to an object of the type T can be declared in any of the following ways

T*p;
T* p;
T *p;
T * p;

For example if T is int * then the pointer declaration can look like

int **p;
int ** p;
int * *p;
int * * p;

The same way you can declare a pointer to a structure

struct Card*p = &my_card;
struct Card* p = &my_card;
struct Card *p = &my_card;
struct Card * p = &my_card;

Pay attention to that you may write

T ( *p );

but you may not write

( T* ) p;

Also there exists another subtlety. If you will write for example

int* p1, p2

then the variable p1 has the type int * while the variable p2 has the type int instead of int *.

But if you will write

typedef int * T;

when in this declaration

T p1, p2;

the both variables have the type int *.

CodePudding user response:

IMO int *a is more meaningful than int* a. In C, *a can be read as 'content of a', so int *a can be read as 'content of a is an integer', the same way int a reads as 'a is an integer'. As the other answers cleared it, the spaces do not really matter here- they are all the same to the compiler.

This way of writing also makes more sense while declaring multiple pointer variables like int *a, *b. It's easy to make a mistake writing int* a, b and expecting both a and b to be int pointers.

CodePudding user response:

As far as the compiler is concerned,

T *a;
T* a;
T*a;
T      *      a;

all mean exactly the same thing - all are interpreted as T (*a) (a has type "pointer to T"). Whitespace is not significant in this case. With your struct type, struct Card *p and struct Card* p do exactly the same thing, and both are interpreted as struct Card (*p).

Syntactically, the * is always bound to the declarator (more on that below). This means that declarations like

T* a, b;

are interpreted as

T (*a), b;

and only declare a as a pointer to T - b is a regular T. This is one of many reasons I advise against using the T* p style (I will give more reasons below).

In C, declarations have two main parts - a sequence of declaration specifiers (type specifiers, struct, union, and enum specifiers, storage class specifiers, type qualifiers, etc.) followed by a comma-separated list of declarators. In a declaration like

static unsigned long int a[10], *p, f(void);

the declaration specifiers are static unsigned long int and the declarators are a[10], *p, and f(void).

The declarator introduces the name of the thing being declared (a, p, and f) along with information about that thing's array-ness, pointer-ness, and function-ness. The type of each item is fully specified by the combination of the declaration specifiers and the declarator.

The structure of the declarator matches the structure of an expression in the code - if you have an array of pointers to int and you want to access a specific int value, you need to index into the array and dereference the result using the unary * operator:

printf( "%d\n", *ap[i] );

The expression *ap[i] has type int, so the declaration of the ap array is

int *ap[N];

The declarator *ap[N] matches the structure of the expression *ap[i].

In a declaration the * and [] and () operators are only there to indicate type - you're not actually dereferencing or indexing or calling anything. However, they do obey the same precedence rules as they do in expressions. Postfix operators have higher precedence than unary operators, so [] and () "bind" before *:

T *a[N];    // parsed as *(a[N]) -- a is an array of pointers
T *f(void); // parsed as *(f(void)) - f is function returning a pointer

To declare a pointer to an array or function, you must explicitly group the * operator with the array or function expression:

T (*a)[N];    // a is a pointer to an array
T (*f)(void); // f is a pointer to a function

And now for the editorial portion of this answer (which you are free to ignore)...

Over time I've become more militant about discouraging the T* p style of pointer declarations. It's the preferred style among C programmers, but the more you think about it the less sense it makes, and in my experience it just causes problems.

Its stated purpose - emphasizing the "pointer-ness" of the variable - is spurious. You can't emphasize the "array-ness" of a variable by declaring it as

T[N] a; // syntax error

or the "function-ness" as

T(void) f; // syntax error

because the operands of the postfix [] and () operators are a and f, not T. Similarly, in a declaration like

T* p; // parsed as T (*p);

the operand of the unary * operator is p, not T. And the * operator is unary (prefix), not postfix, so T* just looks wrong anyway. Because it's unary and because whitespace doesn't matter T* p will work as expected, but you're kind of ignoring the rules of the language when you do it.

If nothing else, it's inconsistent with declaring pointers to arrays or pointers to functions:

T (*ap)[N];     // ap is a pointer to an N-element array of T
T (*fp)(void);  // fp is a pointer to a function returning T

and declaring a pointer to an array of pointers like

T* (*ap)[N];    // ap is a pointer to an array of pointers to T

is ugly and just indicates confused thinking, and like I said earlier you can't follow that convention with array or function declarations:

T[N] a;    // syntax error
T(void) f; // syntax error

and if you use it you will inevitably screw up and write

T* a, b;

when you meant to write

T *a, *b;

Now, the inevitable response to that objection is to put separate declarations on separate lines:

T* a;
T* b;

and yes, there are plenty of good reasons to have one declaration per line, but working around bad practice isn't one of them. Write those declarations as

T *a;
T *b;

instead.

  • Related