Почему я получаю «запрос на членство в« ****** »во что-то, не являющееся структурой или объединением»? - PullRequest
0 голосов
/ 28 октября 2018

Я получаю ошибку для p->letter = 'A' и p->age = '9'.Я не знаю, что происходит не так.

#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;
}

Ответы [ 6 ]

0 голосов
/ 28 октября 2018

Как уже отмечали многие, у вас есть проблема, потому что при использовании typedef вы зашли слишком далеко :-).Использование typedef для преобразования типов предназначено для повышения ясности, тогда как способ его использования уменьшает ясность.

Позвольте мне сначала показать ваш пример с правильным подходом:

#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;
}

Когда использовать typedef foo_t bar_t

Когда это проясняет ситуацию, например, stdint.h делает это для целых чисел.Скажем, вам нужно 32-битное целое число без знака, вы должны использовать uint32_t, который соответственно typedef'd для различных архитектур, чтобы дать вам то, что вы ожидаете.

Когда НЕ использовать typedef struct foo foo_t

Почти все время.

Когда можно использовать typedef struct foo foo_t

Теперь, по причинам, связанным с изменениями, typedef struct foo foo_t не рекомендуется, за исключением случаев, когда struct foo непрозрачна, как правило, когда вынаписание C API, где структура доступна через предопределенные функции доступа, которые имеют более длительный срок службы, чем внутренняя структура.

Зачем использовать sizeof (* p) вместо sizeof (struct player)?

InВ этом случае по какой-то причине вы решаете изменить то, что *p, тогда все, что вам нужно сделать, это изменить объявление, и не беспокоиться о том, что оно не будет выделено соответствующим образом.

0 голосов
/ 28 октября 2018

Кроме того, что указывали другие, во-первых, переменная typedef pointer не считается хорошей практикой, поскольку скрытие * затрудняет чтение кода. Читать Это хорошая идея, чтобы печатать указатели?

Хотя, если вы хотите набрать указатель, делайте, как показано ниже

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 * */ 

Далее необходимо выделить память для player_p, например, для

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 */   
}

Позже вы можете получить доступ к элементу структуры, например

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

И освободите динамически созданную память, вызвав free().

free(ptr);

Пример кода

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;
}
0 голосов
/ 28 октября 2018

Это пример того, почему вы не должны печатать указатель.

player_t - это typedef для struct player *. Затем вы определяете p как player *, что означает, что полный тип p равен struct player **. Тот факт, что у вас был указатель, скрытый в typedef, в конечном итоге сбил вас с толку, и это может также запутать других, кто читает ваш код.

Удалите указатель из typedef, и он будет работать как положено:

typedef struct player player_t;
0 голосов
/ 28 октября 2018

Вы вводите определение

typedef struct player *player_t;

... поэтому player_t - это тип указателя на struct player.

Затем вы определяете переменную:

player_t* p;

p - указатель на указатель на struct player.Удалить *.

0 голосов
/ 28 октября 2018

player_t* p; не является указателем на struct player;это указатель на указатель на struct player.Удалите * из объявления переменной и из приведения типа перед вызовом malloc (в любом случае вам это не нужно).

0 голосов
/ 28 октября 2018

Измените эти две строки:

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

на:

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

p имеет тип player_t, который уже определен как указатель на player,Нет необходимости в другом * в его определении.Кроме того, вам нужно выделить размер исходной структуры, а не размер указателя (sizeof(player_t) - это размер указателя в байтах, а не размер структуры player).

...