Zwróć uwagę, jak powyższe wygląda, jakby powinno być napisane a_foo.field, ale to się nie powiedzie, ponieważ Foojest wskaźnikiem do struktury. Gorąco polecam przeciwkotypedef : Ed wskaźniki w C Wskaźniki są ważne, nie ukrywają swoje gwiazdki. Niech lśnią.
Założę się, że to jest rzeczywisty problem. Nadal czasami mnie gryzie, zwłaszcza jeśli ktoś wpisał typ wskaźnika.
John Bode
2
Dodam tylko, że ten błąd pojawi się, jeśli tablica nie została przydzielona (malloc) i jest dostępna.
max
Wiem, że od opublikowania tego artykułu minęło około dziesięciu lat, ale te dwa ostatnie zdania sprawiły, że stał się moim nowym ulubionym postem. „Wskaźniki są ważne, nie ukrywaj gwiazdek. Niech świecą”.
Aiden Blishen Cuneo
20
Próbujesz uzyskać dostęp do elementu struktury, ale w czymś, co nie jest strukturą. Na przykład:
Dziękuję za wyraźne wskazanie punktu wskaźnika (bez strasznej gry językowej). Inne odpowiedzi wspominały o tym (np. „Niech świecą wskaźniki”), ale o 2 w nocy walcząc w epickiej bitwie z GDB i Valgrind, ludzie tacy jak ja doceniają, że Twoja odpowiedź wyraźnie pokazuje, w jaki sposób wskaźnik może być problemem i jak można go naprawić .
Max von Hippel
3
Wymieniłem prawdopodobnie wszystkie przypadki, w których ten błąd może wystąpić w kodzie i jego komentarzach poniżej. Dodaj do tego, jeśli napotkasz więcej przypadków.
#include<stdio.h>#include<malloc.h>typedefstructAStructTypedefedStruct;structAStruct
{int member;
};
voidmain(){
/* Case 1
============================================================================
Use (->) operator to access structure member with structure pointer, instead
of dot (.) operator.
*/structAStruct *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 ->structAStruct **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
}
Podstawowe pomysły są proste:
Użyj .ze zmienną strukturalną. (Przypadki 2 i 4)
Używaj ->ze wskaźnikiem do struktury. (Przypadki 1 i 3)
Jeśli osiągniesz zmienną strukturalną lub wskaźnik do zmiennej struktury, podążając za wskaźnikiem, a następnie zawiń wskaźnik w nawias: (*ptr).i (*ptr)->vs *ptr.i *ptr-> (Wszystkie przypadki z wyjątkiem przypadku 1)
Jeśli osiągasz przez następujące wskaźniki, upewnij się, że poprawnie osiągnąłeś wskaźnik do struct lub struct, w zależności od tego, co jest pożądane. (Przypadek 5, zwłaszcza 5.5)
Odpowiedzi:
Dzieje się tak również, jeśli próbujesz uzyskać dostęp do instancji, gdy masz wskaźnik, i odwrotnie:
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 */
Jak wskazano w komentarzu, może to być rozdzierające, jeśli ktoś pójdzie i
typedef
sa pointer, tj.*
Włączy w typedef, na przykład:typedef struct foo* Foo;
Ponieważ wtedy otrzymujesz kod, który wygląda tak, jakby zajmował się instancjami, podczas gdy w rzeczywistości ma do czynienia ze wskaźnikami:
Zwróć uwagę, jak powyższe wygląda, jakby powinno być napisane
a_foo.field
, ale to się nie powiedzie, ponieważFoo
jest wskaźnikiem do struktury. Gorąco polecam przeciwkotypedef
: Ed wskaźniki w C Wskaźniki są ważne, nie ukrywają swoje gwiazdki. Niech lśnią.źródło
Próbujesz uzyskać dostęp do elementu struktury, ale w czymś, co nie jest strukturą. Na przykład:
struct { int a; int b; } foo; int fum; fum.d = 5;
źródło
Może się to również zdarzyć w następującym przypadku:
na przykład. jeśli weźmiemy pod uwagę funkcję push stosu:
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; }
Błąd występuje w funkcji push oraz w skomentowanej linii. Wskaźnik
s
musi znajdować się w nawiasach. Prawidłowy kod:scanf("%d",&( (*s)->a[++(*s)->head]));
źródło
Wymieniłem prawdopodobnie wszystkie przypadki, w których ten błąd może wystąpić w kodzie i jego komentarzach poniżej. Dodaj do tego, jeśli napotkasz więcej przypadków.
#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 }
Podstawowe pomysły są proste:
.
ze zmienną strukturalną. (Przypadki 2 i 4)->
ze wskaźnikiem do struktury. (Przypadki 1 i 3)(*ptr).
i(*ptr)->
vs*ptr.
i*ptr->
(Wszystkie przypadki z wyjątkiem przypadku 1)źródło
Może to oznaczać, że zapomniałeś dołączyć pliku nagłówkowego, który definiuje tę strukturę / unię. Na przykład:
plik 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();
plik main.c:
. . . if (getStatus().CHIP_RDY) /* This will generate the error, you must add the #include "foo.h" */ . . .
źródło
może się również pojawić, jeśli:
struct foo { int x, int y, int z }foo; foo.x=12
zamiast
struct foo { int x; int y; int z; }foo; foo.x=12
źródło
Widziałem to, kiedy próbowałem uzyskać dostęp do członków.
Moja struktura była następująca:
struct test { int a; int b; }; struct test testvar;
Zwykle uzyskujemy dostęp do członków struktury jako
Pomylili ja testVar się wskaźnik i to zrobił.
Wtedy zobaczyłem ten błąd.
źródło