0

I'm getting the error for p->letter = 'A' and p->age = '9'. I don't know what is going wrong.

#include<stdio.h>
#include<stdlib.h>

struct player {
    char letter;
    int age;
};

typedef struct player *player_t;

int main (void)
{
    player_t* p;
    p = (player_t*)malloc(1 * sizeof(player_t));
    if (p == NULL)
    {
        /* EDITED by @ahmedmasud removed original printf line for language */
        printf("Unable to allocate\n");
        return 1;
    }
    p->letter = 'A';
    p->age = '9';
    free(p);
    return 0;
}
DYZ
  • 55,249
  • 10
  • 64
  • 93
N.Curry
  • 3
  • 1

6 Answers6

3

This is an example of why you shouldn’t typedef a pointer.

player_t is a typedef for struct player *. You then define p as a player *, which means the full type of p is struct player **. The fact that you had a pointer hidden in a typedef ended up confusing you, and it can similarly confuse others who read your code.

Remove the pointer from the typedef and it will work as expected:

typedef struct player player_t;
dbush
  • 205,898
  • 23
  • 218
  • 273
3

As many folks have pointed out you have a problem because in using typedef you went one step too far :-). Using typedef to recast types is meant for increasing clarity whereas the way you're using it decreases clarity.

Let me first show your example with the correct approach:

#include <stdio.h>
#include <stdlib.h>

struct player {
    char letter;
    int age;
};

/* typedef struct player *player_t;  NOT NEEDED */

int main (void)
{
    struct player *p;

    p = malloc(sizeof(*p)); /* used *p for sizeof instead of struct player */

    if (p == NULL)
    {
        fprintf(stderr, "Unable to allocate memory\n");
        return 1;
    }

    p->letter = 'A';
    p->age = '9';

    free(p);
    return 0;
}

When to use typedef foo_t bar_t

When it makes things clearer, e.g. stdint.h does this for integers. Say, you want a 32-bit unsigned int, you would use uint32_t which is appropriately typedef'd for various architectures to give you what you expect.

When NOT to use typedef struct foo foo_t

Pretty much all the time.

When it's OK to use typedef struct foo foo_t

Now for the reasons behind the changes, typedef struct foo foo_t is discouraged except when struct foo is opaque, typically when you are writing a C API where the structure is accessed through predefined access functions that have a longer life than internal structure.

Why use sizeof(*p) instead of sizeof(struct player) ?

In case, for some reason, you decide to change what *p is then all you have to do is change the declaration, and not worry that it's not going to get appropriately allocated.

Ahmed Masud
  • 21,655
  • 3
  • 33
  • 58
  • 1
    `sizeof` is an operator, not a function so `sizeof *p` would just do. No need for parenthesis here. – alk Oct 28 '18 at 11:44
1

player_t* p; is not a pointer to struct player; it is a pointer to a pointer to struct player. Remove the * from the variable declaration and from the type cast before the call to malloc (you do not need that cast, anyway).

DYZ
  • 55,249
  • 10
  • 64
  • 93
1

You typedef

typedef struct player *player_t;

... so player_t is a type of pointer to struct player.

Then you define a variable:

player_t* p;

p is a pointer to pointer to struct player. Remove the *.

0

Change these two lines:

player_t* p;
p = (player_t*) malloc(1*sizeof(player_t));

into:

player_t p;
p = (player_t) malloc(1*sizeof(struct player));

p is of type player_t, which is already defined as a pointer to a player. No need for another * in its definition. Also, you need to allocate the size of the original struc, not the size of the pointer (sizeof(player_t) is the size in bytes of a pointer, not the size of the struct player).

AhmadWabbi
  • 2,253
  • 1
  • 20
  • 35
0

Apart from what others pointed, Firstly typedef a pointer variable is not considered as good practice as hiding the * makes the code hard to read. Read Is it a good idea to typedef pointers?

Though if you want to typedef a pointer then do like below

typedef struct player {
    char letter;
    int age;
}player_t, *player_p; /* player_t is normal struct & player_p is pointer struct, here when someone see _p at the end of variable means it has * */ 

Next you need to allocate memory for player_p for e.g

player_p ptr = malloc(sizeof(struct player)); /* here don't take like "player_p *ptr" as player_p is already a pointer to struct */
if(ptr == NULL) {
    /* error handling @TODO */   
}

Later you can access structure member like

ptr->letter = 'A';
ptr->age = '9'; /* age is integer member, you may want to assign integer value directly like 57 instead of '9' */ 

And free the dynamically created memory by calling free().

free(ptr);

Sample code

typedef struct player {
        char letter;
        int age;
}player_t, *player_p;
int main(void) {
        player_p ptr = malloc(sizeof(struct player));
        if(ptr == NULL) {
                /* error handling @TODO */
        }
        ptr->letter = 'A';
        ptr->age = 50;
        printf("%c .. %d \n",ptr->letter,ptr->age);
        free(ptr);
        return 0;
}
Achal
  • 11,821
  • 2
  • 15
  • 37