“在非结构体或联合体中请求成员 '*******'”的意思是什么?

94

这个错误有没有简单的解释?

request for member '*******' in something not a structure or union

在我学习C语言的过程中,我遇到了几次这个问题,但我不知道它的含义。

9个回答

123

如果您尝试访问一个实例,但是使用了指针,或者反之亦然,也会发生这种情况:

struct foo
{
  int x, y, z;
};

struct foo a, *b = &a;

b.x = 12;  /* This will generate the error, should be b->x or (*b).x */

正如评论中指出的那样,如果有人使用 typedef 定义了一个指针类型,即在 typedef 中包含了 *,那么这将会变得非常棘手:
typedef struct foo* Foo;

这是因为有时候代码看起来像是在处理实例,但实际上是在处理指针:

Foo a_foo = get_a_brand_new_foo();
a_foo->field = FANTASTIC_VALUE;

注意以上代码中看起来应该写成 a_foo.field,但是这样会失败,因为Foo是指向结构体的指针。我强烈建议不要在C语言中使用typedef关键字定义指针类型,指针很重要,不要隐藏星号,让它们发光。

8
我敢打赌这就是实际问题。有时我仍会受到影响,尤其是当有人将指针类型定义为typedef时。 - John Bode
2
我只想补充一下,如果访问了一个未分配(malloc)的数组,就会出现这个错误。 - max
我知道这篇文章已经发布了十年或更长时间,但最后两句话让它成为了我新的最爱。"指针很重要,不要隐藏你的星号。让它们闪耀吧。" - Aiden Blishen Cuneo

20
你正在尝试访问结构体的成员,但是在一个不是结构体的地方。例如:
struct {
    int a;
    int b;
} foo;
int fum;
fum.d = 5;

6
以下情况也可能发生:
例如,如果我们考虑一个栈的push函数:
typedef struct stack
{
    int a[20];
    int head;
}stack;

void push(stack **s)
{
    int data;
    printf("Enter data:");
    scanf("%d",&(*s->a[++*s->head])); /* this is where the error is*/
}

main()
{
    stack *s;
    s=(stack *)calloc(1,sizeof(stack));
    s->head=-1;
    push(&s);
    return 0;
}

错误出现在 push 函数和被注释的行中。指针 s 必须包含在括号内。正确的代码是:
scanf("%d",&( (*s)->a[++(*s)->head]));

2
感谢您明确指出指针的指向(没有糟糕的语言游戏)。其他答案提到了它(例如“让您的指针发光”),但在凌晨2点与GDB和Valgrind进行一场史诗般的战斗时,像我这样的人很感激您的回答明确地展示了指针可能存在的问题以及如何解决这些问题。 - Max von Hippel

4

我已经列举出可能导致代码中出现此错误的所有情况及其注释。如果您遇到更多情况,请添加。

#include<stdio.h>
#include<malloc.h>

typedef struct AStruct TypedefedStruct;

struct AStruct
{
    int member;
};

void main()
{
    /*  Case 1
        ============================================================================
        Use (->) operator to access structure member with structure pointer, instead
        of dot (.) operator. 
    */
    struct AStruct *aStructObjPtr = (struct AStruct *)malloc(sizeof(struct AStruct));
    //aStructObjPtr.member = 1;      //Error: request for member ‘member’ in something not 
                                      //a structure or union. 
                                      //It should be as below.
    aStructObjPtr->member = 1;
    printf("%d",aStructObjPtr->member); //1


    /*  Case 2
        ============================================================================
        We can use dot (.) operator with struct variable to access its members, but 
        not with with struct pointer. But we have to ensure we dont forget to wrap 
        pointer variable inside brackets.
    */
    //*aStructObjPtr.member = 2;     //Error, should be as below.
    (*aStructObjPtr).member = 2;
    printf("%d",(*aStructObjPtr).member); //2


    /* Case 3
       =============================================================================
       Use (->) operator to access structure member with typedefed structure pointer, 
       instead of dot (.) operator. 
    */
    TypedefedStruct *typedefStructObjPtr = (TypedefedStruct *)malloc(sizeof(TypedefedStruct));
    //typedefStructObjPtr.member=3;  //Error, should be as below.
    typedefStructObjPtr->member=3;
    printf("%d",typedefStructObjPtr->member);  //3


    /*  Case 4
        ============================================================================
        We can use dot (.) operator with struct variable to access its members, but 
        not with with struct pointer. But we have to ensure we dont forget to wrap 
        pointer variable inside brackets.
    */
    //*typedefStructObjPtr.member = 4;  //Error, should be as below.    
    (*typedefStructObjPtr).member=4;
    printf("%d",(*typedefStructObjPtr).member);  //4


    /* Case 5
       ============================================================================
       We have to be extra carefull when dealing with pointer to pointers to 
       ensure that we follow all above rules.
       We need to be double carefull while putting brackets around pointers.
    */

    //5.1. Access via struct_ptrptr and  ->
    struct AStruct **aStructObjPtrPtr = &aStructObjPtr;
    //*aStructObjPtrPtr->member = 5;  //Error, should be as below.
    (*aStructObjPtrPtr)->member = 5;
    printf("%d",(*aStructObjPtrPtr)->member); //5

    //5.2. Access via struct_ptrptr and .
    //**aStructObjPtrPtr.member = 6;  //Error, should be as below.
    (**aStructObjPtrPtr).member = 6;
    printf("%d",(**aStructObjPtrPtr).member); //6

    //5.3. Access via typedefed_strct_ptrptr and ->
    TypedefedStruct **typedefStructObjPtrPtr = &typedefStructObjPtr;
    //*typedefStructObjPtrPtr->member = 7;  //Error, should be as below.
    (*typedefStructObjPtrPtr)->member = 7;
    printf("%d",(*typedefStructObjPtrPtr)->member); //7

    //5.4. Access via typedefed_strct_ptrptr and .
    //**typedefStructObjPtrPtr->member = 8;  //Error, should be as below.
    (**typedefStructObjPtrPtr).member = 8;
    printf("%d",(**typedefStructObjPtrPtr).member); //8

    //5.5. All cases 5.1 to 5.4 will fail if you include incorrect number of *
    //     Below are examples of such usage of incorrect number *, correspnding
    //     to int values assigned to them

    //(aStructObjPtrPtr)->member = 5; //Error
    //(*aStructObjPtrPtr).member = 6; //Error 
    //(typedefStructObjPtrPtr)->member = 7; //Error 
    //(*typedefStructObjPtrPtr).member = 8; //Error
}

基本思想很简单:
  • 对于结构体变量,请使用 . 。 (情况2和4)
  • 对于指向结构体的指针,请使用 -> 。 (情况1和3)
  • 如果您通过跟随指针到达结构体变量或指向结构体变量,则请将指针包含在括号内:(*ptr)。(*ptr)-> vs *ptr。*ptr->(除了情况1外的所有情况)
  • 如果您通过跟随指针到达,请确保已正确到达所需的指向结构体或结构体的指针。(情况5,特别是5.5)

1
这可能意味着您忘记包含定义此结构/联合体的头文件。 例如: foo.h文件:
typedef union
{
    struct
    {
        uint8_t FIFO_BYTES_AVAILABLE    : 4;
        uint8_t STATE                   : 3;
        uint8_t CHIP_RDY                : 1;
    };
    uint8_t status;
} RF_CHIP_STATUS_t;

RF_CHIP_STATUS_t getStatus();

main.c文件:

.
.
.
if (getStatus().CHIP_RDY) /* This will generate the error, you must add the  #include "foo.h" */
.
.
.

0

https://dev59.com/Y3I95IYBdhLWcg3wtwb4#42668014

上面是对同一个问题的回答。我想补充一个我遇到的案例。
typedef struct Node{
    int data;
    Node *next;
} Node;

这段代码不起作用,我遇到了与问题中讨论的相同错误。
我找到的解决方案如下:
typedef struct Node{
    int data;
    struct Node *next;
} Node;

或者

typedef struct Node Node;
struct Node{
    int data;
    Node *next;
};

我认为这是因为编译器在提供 typedef 之前不知道 typedefedStructure Node 是什么。

0

如果出现以下情况,也可能会出现:

struct foo {   int x, int y, int z }foo; 

foo.x=12

而不是

struct foo {   int x; int y; int z; }foo; 

foo.x=12

这两个语句没有任何区别吗? - Nick
1
@AlaaM。几个月后回头看,我错过了分号! - Nick

0

我荒谬的经历是我错误地使用了“.”而不是“,”。

printf("%c". ch);

0

当我尝试访问成员时,我看到了这个。

我的结构体是这样的:

struct test { 
    int a;
    int b;
};
    
struct test testvar;

通常我们访问结构成员时会这样做:

testvar.a;
testvar.b;

我错误地将 testvar 视为指针并执行了这个操作。

testvar->a;

那时我看到了这个错误。

请求访问非结构体或联合体的成员“a”


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接