2010-04-04 18 views
164

Attualmente sto imparando C leggendo un buon libro per principianti chiamato "Teach Yourself C in 21 Days" (Ho già imparato Java e C# così mi sto muovendo ad un ritmo molto più veloce) . Stavo leggendo il capitolo sui puntatori e l'operatore -> (freccia) si avvicinò senza spiegazione. Penso che sia usato per chiamare membri e funzioni (come l'equivalente dell'operatore. (Punto), ma per puntatori invece di membri). Ma non ne sono del tutto sicuro. Potrei ottenere una spiegazione e un esempio di codice?Operatore freccia (->) utilizzo in C

+32

Solo una nota a margine - i libri intitolati "insegnare a te XXX in XXX giorni/settimane/ore" di solito non sono buoni. Ottieni una copia di K & R. – qrdl

+8

qrdl è corretto - i libri "Impara X in Y giorni" sono generalmente inutili. Oltre a K & R, consiglierei anche "C Primer Plus" di Prata, che approfondisce più di K & R. –

+56

Ottieni un libro migliore. http://norvig.com/21-days.html – joshperry

risposta

307

foo->bar è equivalente a (*foo).bar, cioè si ottiene l'elemento chiamato bar dal struct che foo punti.

+26

Vale la pena notare che se l'operatore dereference era stato fatto postfix, come in Pascal, l'operatore '->' non sarebbe stato affatto necessario, in quanto sarebbe stato equivalente al 'foo * .bar' molto più leggibile. Sarebbe stato anche evitato l'intero casino delle funzioni typedef con tutte le parentesi extra. – EJP

+0

@kritzikratzi Non c'è l'overloading degli operatori in C. – sepp2k

+0

@kritzikratzi Si potrebbe rimuovere quel commento ora! – Tim

90

Sì, è tutto.

È solo la versione punto quando si desidera accedere agli elementi di una struttura/classe che è un puntatore anziché un riferimento.

struct foo 
{ 
    int x; 
    float y; 
}; 

struct foo var; 
struct foo* pvar; 

var.x = 5; 
(&var)->y = 14.3; 
pvar->y = 22.4; 
(*pvar).x = 6; 

Questo è tutto!

+16

Solo per segnalarlo (nessun gioco di parole), hai dimenticato il; alla parentesi finale della struct, dovrebbe essere}; –

+2

incredibile, stavo modificandolo mentre stavi scrivendo il commento .. precog! – Jack

+1

Dato che pvar non è inizializzato, come lo si inizializza se si desidera che pvar indichi una nuova struttura, che non sia 'pvar = & var'? – CMCDragonkai

24

a->b è solo l'abbreviazione di (*a).b in ogni modo (lo stesso per le funzioni: a->b() è l'abbreviazione di (*a).b()).

+0

c'è documentazione che dice che funziona anche in questo modo per i metodi? – AsheKetchum

13

foo->bar è solo una scorciatoia per (*foo).bar. Questo è tutto ciò che c'è da fare.

1

Punto è un operatore di dereferenziazione e viene utilizzato per connettere la variabile di struttura per un particolare record di struttura. Ad esempio:

struct student 
    { 
     int s.no; 
     Char name []; 
     int age; 
    } s1,s2; 

main() 
    { 
     s1.name; 
     s2.name; 
    } 

In tal modo siamo in grado di utilizzare un operatore punto per accedere alla struttura variabile

+5

Quale valore aggiunge? L'esempio è un po 'scarso rispetto alle altre risposte che effettivamente lo confrontano con '->'. Anche questa domanda ha ricevuto risposta per 4,5 anni già. – EWit

1

ho dovuto fare una piccola modifica al programma di Jack per farlo funzionare. Dopo aver dichiarato il puntatore della struct pvar, puntalo all'indirizzo di var. Ho trovato questa soluzione a pagina 242 della programmazione di Stephen Kochan in C.

#include <stdio.h> 

int main() 
{ 
    struct foo 
    { 
    int x; 
    float y; 
    }; 

    struct foo var; 
    struct foo* pvar; 
    pvar = &var; 

    var.x = 5; 
    (&var)->y = 14.3; 
    printf("%i - %.02f\n", var.x, (&var)->y); 
    pvar->x = 6; 
    pvar->y = 22.4; 
    printf("%i - %.02f\n", pvar->x, pvar->y); 
    return 0; 
} 

Esegui questo vim con il seguente comando:

:!gcc -o var var.c && ./var 

Will uscita:

5 - 14.30 
6 - 22.40 
+2

suggerimento vim: usa '%' per rappresentare il nome file corrente. Così: '! Gcc% &&./A.out' – jibberia

1
#include<stdio.h> 

int main() 
{ 
    struct foo 
    { 
     int x; 
     float y; 
    } var1; 
    struct foo var; 
    struct foo* pvar; 

    pvar = &var1; 
    /* if pvar = &var; it directly 
     takes values stored in var, and if give 
     new > values like pvar->x = 6; pvar->y = 22.4; 
     it modifies the values of var 
     object..so better to give new reference. */ 
    var.x = 5; 
    (&var)->y = 14.3; 
    printf("%i - %.02f\n", var.x, (&var)->y); 

    pvar->x = 6; 
    pvar->y = 22.4; 
    printf("%i - %.02f\n", pvar->x, pvar->y); 

    return 0; 
} 
1

L'operatore -> rende il codice più leggibile rispetto all'operatore * in alcune situazioni.

Come: (citato dal EDK II project)

typedef 
EFI_STATUS 
(EFIAPI *EFI_BLOCK_READ)(
    IN EFI_BLOCK_IO_PROTOCOL   *This, 
    IN UINT32       MediaId, 
    IN EFI_LBA      Lba, 
    IN UINTN       BufferSize, 
    OUT VOID       *Buffer 
); 


struct _EFI_BLOCK_IO_PROTOCOL { 
    /// 
    /// The revision to which the block IO interface adheres. All future 
    /// revisions must be backwards compatible. If a future version is not 
    /// back wards compatible, it is not the same GUID. 
    /// 
    UINT64    Revision; 
    /// 
    /// Pointer to the EFI_BLOCK_IO_MEDIA data for this device. 
    /// 
    EFI_BLOCK_IO_MEDIA *Media; 

    EFI_BLOCK_RESET  Reset; 
    EFI_BLOCK_READ  ReadBlocks; 
    EFI_BLOCK_WRITE  WriteBlocks; 
    EFI_BLOCK_FLUSH  FlushBlocks; 

}; 

Il _EFI_BLOCK_IO_PROTOCOL struct contiene 4 membri puntatore a funzione.

Supponiamo di avere una variabile struct _EFI_BLOCK_IO_PROTOCOL * pStruct e si desidera utilizzare il buon vecchio operatore * per chiamare il suo puntatore funzione membro.Vi ritroverete con codice come questo:

(*pStruct).ReadBlocks(...arguments...)

Ma con l'operatore ->, è possibile scrivere in questo modo:

pStruct->ReadBlocks(...arguments...).

Quale aspetto migliore?

4
struct Node { 
    int i; 
    int j; 
}; 
struct Node a, *p = &a; 

Qui l'accesso ai valori di i e j possiamo utilizzare la variabile a e il puntatore p come segue: a.i, (*p).i e p->i sono tutti uguali.

Qui . è un "Selettore diretto" e -> è un "Selettore indiretto".

0

Vorrei solo aggiungere alle risposte il "perché?".

. è un operatore di accesso membro standard con precedenza superiore rispetto all'operatore di puntatore *.

Quando si sta tentando di accedere agli interni di una struttura e lo si è scritto come *foo.bar, il compilatore avrebbe pensato di volere un elemento "bar" di "foo" (che è un indirizzo in memoria) e ovviamente quel semplice indirizzo non avere qualche membro.

Quindi è necessario chiedere al compilatore di prima dereference whith (*foo) e quindi accedere all'elemento membro: (*foo).bar, che è un po 'goffo di scrivere in modo che i bravi ragazzi hanno creato una versione abbreviata: foo->bar, che è una sorta di membro accesso tramite operatore puntatore.