[Powered by Google Translate] Parliamo di strutture.
Le strutture ci forniscono un modo per raggruppare un gruppo di variabili insieme
in un bel pacchetto.
E 'probabilmente più facile vedere un esempio subito,
così diciamo struct,
quindi aprendo parentesi graffa,
e in questa struttura, ci hanno un'età int,
un nome char *,
e questo è tutto.
Può sembrare strano con un punto e virgola dopo una parentesi graffa,
ma è in realtà necessario, con le strutture.
Qualsiasi tipo valido può andare nella definizione della struttura.
In questo caso, abbiamo usato un int e un char *,
ma si potrebbe anche usare un array, di dire, 100 elementi
o anche un altro struct.
Quando si utilizza le strutture in C,
si sta creando nuovi tipi
su una raccolta di altri tipi.
Qui, stiamo facendo un nuovo tipo di
di un intero e un char *.
Come vedremo più avanti, una struttura di tipo
è in un sacco di modi equivalenti a qualsiasi altro tipo cui siete abituati.
Di solito, sarò a confronto come un tipo struct
è simile a un tipo intero.
Mentre il codice che abbiamo scritto è C valido,
non è molto utile,
clang e ci darà un avvertimento.
Ricordate come le strutture e le sue sono simili?
Bene, abbiamo praticamente appena detto
int,
che non è una linea molto utile.
Quindi cerchiamo di realtà dichiarare una variabile di quel tipo
dando un nome prima del punto e virgola.
Chiameremo lo studente variabile.
Ora abbiamo dichiarato uno studente variabile chiamata
con il tipo in struttura.
Come si arriva alle variabili all'interno della struttura?
Tecnicamente, i nomi di queste variabili
sono membri.
Per accedere a qualsiasi membro particolare in una struttura studente,
si aggiunge un punto al nome della variabile,
seguito dal nome del membro che si desidera.
Così qui, gli unici 2 posti validi
sono student.age
e student.name.
E siamo in grado di fare qualcosa di simile
student.age = 12
e student.name = studente.
Ora, se volessimo fare un secondo studente?
Si potrebbe pensare di copiare e incollare queste righe
e cambiare studente a studente 2 o qualcosa del genere,
e che funziona,
ma tecnicamente, studente e studente 2
non hanno lo stesso tipo.
Vedi, non sarà in grado di assegnare l'uno all'altro.
Questo perché, finora,
struct è stato anonimo.
Abbiamo bisogno di dargli un nome.
Per fare questo, inseriamo il nome della struttura
dopo la parola struct.
studente,
seguita dalla definizione.
Possiamo ancora immediatamente dichiarare una variabile di tipo
struct studente, come abbiamo fatto prima.
Lo chiameremo S1
Dando il struct un nome,
ora possiamo usare struct studente
quasi nello stesso identico modo si userebbe int.
Così siamo in grado di dichiarare una variabile di tipo struct studente,
come
struct studente S2.
Come gli array, le strutture forniscono una sintassi di inizializzazione di scelta rapida,
così si può dire, struct studente S2
è uguale a
parentesi graffa sinistra 3, S2.
Qui, S2.age saranno 3,
e S2.name punterà a S2.
Pensate a tutte le cose che puoi fare con un tipo int
e la maggior parte di loro si può fare con un tipo struct studente.
Possiamo usare uno studente struct come un tipo di un parametro di funzione.
Possiamo usare struct studente all'interno di una struttura nuova.
Possiamo avere un puntatore ad una struct studente.
Possiamo fare il formato di studente struct.
Studente struct è un tipo
proprio come int è un tipo.
Possiamo anche assegnare S1 a S2
poiché entrambi sono dello stesso tipo, in modo da poter fare
S1 = S2.
Che cosa succede se lo facciamo
S1.age = 10?
Non cambia S2 a tutti?
Anche in questo caso, pensare alle strutture solo come numeri interi regolari.
Se si assegna un certo X int a qualche int Y,
come X = Y
e poi cambiare X,
come in X + +,
Y si cambia affatto?
Y non cambia qui, e così nemmeno S2 sopra.
S2.age è ancora 3.
Ma si noti che quando si assegna uno struct ad un altro,
tutti i puntatori ancora puntare alla stessa cosa,
da quando sono stati appena copiato.
Se non si desidera che i puntatori da condividere,
è necessario gestire manualmente che,
magari malicking un blocco di memoria per uno dei puntatori per puntare a
e copiare i dati su.
Potrebbe essere fastidioso dover scrivere struct studente in tutto il mondo.
Utilizzando una definizione di tipo, si può fare
Tipo di def
struct
e noi chiameremo studente.
Ora, possiamo usare degli studenti in tutto il mondo
che abbiamo usato per usare struct studente.
Questo tipo di definizione è un anonimo struct
e lo chiama studente.
Ma se anche a mantenere l'identificatore studente
accanto alla struttura parola, come in typedef struct studente,
potremmo usare sia struct studente e studente intercambiabile ora.
Non hanno nemmeno bisogno di avere lo stesso nome.
Potremmo scrivere struct studente def a Bob
e poi struct studente e Bob
Sarebbe tipi intercambiabili.
Indipendentemente dal tipo DEF,
abbiamo bisogno l'identificatore successivo a struct
se la definizione della struct
è ricorsiva.
Per esempio,
tipo def struct nodo
e sarà definito come un int val
e avrà un puntatore che punta ad un altro nodo struct.,
come nella struct nodo * prossimo.
E poi la chiameremo nodo.
Questa struttura è ricorsiva,
poiché la definizione di struct nodo contiene al suo
un puntatore ad una struct nodo.
Si noti che abbiamo da dire struct nodo * prossimo
all'interno della definizione del nodo struct,
in quanto la definizione di tipo non è ancora finita per permetterci di semplificare questo
a poco * nodo successivo.
Imparerete di più su strutture simili a questa
quando si tratta di liste concatenate e alberi.
Che dire di strutture in una funzione?
Questo è anche perfettamente valido.
Potremmo avere
void func
che prende come argomento,
studente s
e fa qualcosa con quello studente.
E poi possiamo passare come struct studente in questo modo.
Func di S1 ​​da prima.
La struttura si comporta
esattamente come un numero intero quando sarebbe passato a una funzione.
Func riceve una copia di S1
e quindi non può modificare S1;
piuttosto, solo la copia di esso che è memorizzato in S.
Se si desidera che la funzione di essere in grado di modificare S1,
func sarà bisogno di prendere un * studenti S,
e dovrete passare S1 per indirizzo, in questo modo.
Student * S, funzioni & S1.
C'è un altro motivo per passare per indirizzo qui.
E se la nostra struttura conteneva 100 campi?
Ogni singola volta che si passa a uno studente di funzione,
il nostro programma ha bisogno di copiare tutti i 100 campi in funzione di S argomento,
anche se non si utilizza la stragrande maggioranza di essi.
Quindi, anche se funzione non ha intenzione di modificare lo studente,
se può ancora essere utile passare per indirizzo.
Ok, e se vogliamo creare un puntatore ad una struct?
Si potrebbe fare qualcosa di simile
studenti * S
è uguale a malloc
dimensione di studente.
Si noti che le dimensioni delle opere ancora qui.
Quindi, come possiamo ora accedere al membro età
del blocco che punta a S?
Si potrebbe prima cosa da fare
* V.età = 4,
ma questo potrebbe non funzionare.
Dal momento che questo sarà davvero essere interpretato come
V.età * tra parentesi = 4,
che non sarà nemmeno la compilazione,
poiché S non è una struttura o piuttosto un puntatore ad una struct,
e quindi il punto non funziona qui.
Potremmo fare
(* S). Anni = 4
ma le parentesi possono ottenere fastidioso e confuso.
Fortunatamente, abbiamo un operatore speciale freccia
che sembra qualcosa di simile
S-> = 4 anni.
Questi 2 modi di riferimento età
sono equivalenti
e non si ha realmente bisogno mai l'operatore freccia,
ma rende le cose aspetto molto più gradevole.
Poiché S è un puntatore a un blocco di memoria che contiene la struttura,
si può pensare di età S> come seguire la freccia del puntatore
e afferrare il membro età.
Allora perché dovremmo mai usare le strutture?
E 'sicuramente possibile ottenere via con solo i numeri interi primitivi,
caratteri, puntatori e simili
che siamo abituati a;
invece di S1 ​​e S2 prima,
avremmo potuto avere age1, age2, nome1, nome2 e
il tutto a variabili separate.
Questo va bene con solo 2 studenti,
ma cosa succede se abbiamo avuto 10 di loro?
E se invece di solo 2 campi,
struct studente aveva 100 campi?
GPA, corsi, colore dei capelli, il sesso, e così via.
Invece di appena 10 strutture, abbiamo bisogno di 1.000 variabili separate.
Inoltre, si consideri una funzione di
che prende tale struttura con 100 campi con il suo unico argomento
e stampa tutti i campi.
Se non abbiamo usato una struttura,
ogni volta che chiamiamo quella funzione,
abbiamo bisogno di passare a tutti i 100 variabili,
e se abbiamo 100 variabili per gli studenti 1,
e 100 variabili per studente 2,
abbiamo bisogno di essere sicuri che non oltrepassa accidentalmente alcune variabili da studente 1
e alcune variabili da studente 2.
E 'impossibile fare lo stesso errore con una struttura,
100 poiché tutte le variabili sono contenuti in un singolo pacchetto.
Solo un paio di note finali:
Se hai capito tutto fino a questo punto, grande.
Il resto del video è solo per amor di completezza '.
Dato che le strutture possono contenere qualsiasi tipo di puntatore,
possono anche contenere puntatori a funzione.
Se si ha familiarità con programmazione orientata agli oggetti,
questo fornisce un modo per utilizzare le strutture per programmare in uno stile orientato agli oggetti.
Altro su puntatori a funzione in un altro momento.
Inoltre, a volte si possono avere 2 strutture
le cui definizioni dipendono l'uno dall'altro.
Per esempio,
potremmo avere struct A,
che è definito come
un puntatore ad una struct B,
struct B * X,
e ora siamo in grado di avere una struttura B
che è definito come un puntatore
Una struttura ad una,
struct A * Y.
Ma questo non viene compilato,
poiché B struct non esiste nel momento in cui una struttura è in fase di compilazione.
E se ci scambiamo struct struct A e B,
poi avevamo appena lasciato con lo stesso problema;
questa volta, con struct A non esistente.
Per risolvere questo problema, possiamo scrivere
struct B;
prima della definizione di struct A.
Questo si chiama una dichiarazione anticipata.
In questo modo solo il compilatore a sapere che
struct B è un tipo valido che sarà completamente definito più tardi o altrove.
Il mio nome è Rob Bowden, e questo è CS50.
[CS50.TV]