MODIFICA: aggiornata la sezione "BIG MISTAKE".
Una lezione veloce su typedef in stile C (diverso da C++!), E perché è così com'è e come usarlo.
In primo luogo, un semplice trucco typedef.
typedef int* int_pointer;
int_pointer ip1;
int *ip2;
int a; // Just a variable
ip1 = &a; // Sets the pointer to a
ip2 = &a; // Sets the pointer to a
*ip1 = 4; // Sets a to 4
*ip2 = 4; // Sets a to 4
IP1 e IP2 sono dello stesso tipo: un puntatore-a-tipo-int, anche se non ha messo un * nella dichiarazione di IP1. Quello * era invece nella dichiarazione.
Argomenti di commutazione. Lei parla di array dichiarano come
int array1[4];
Per fare questo in modo dinamico in fase di esecuzione, si potrebbe fare:
int *array2 = malloc(sizeof(int) * 4);
int a = 4;
array1[0] = a;
array2[0] = a; // The [] implicitly dereferences the pointer
Ora, che cosa se vogliamo un array di puntatori? Sarebbe come questo:
int *array1[4];
int a;
array1[0] = &a; // Sets array[0] to point to variable a
*array1[0] = 4; // Sets a to 4
Assegniamo quell'array dinamicamente.
int **array2 = malloc(sizeof(int *) * 4);
array2[0] = &a; // [] implicitly dereferences
*array2[0] = 4; // Sets a to 4
Avviso l'int **. Ciò significa pointer-to pointer-to-int. Possiamo, se lo vogliamo, usare un puntatore typedef.
typedef int* array_of_ints;
array_of_ints *array3 = malloc(sizeof(array_of_ints) * 4);
array3[0] = &a; // [] implicitly dereferences
*array3[0] = 4; // Sets a to 4
Vedere come c'è solo uno * in quest'ultima dichiarazione? Questo perché uno di loro è "nel typedef". Con quest'ultima dichiarazione, ora disponi di una matrice di dimensione 4 che consiste di 4 puntatori a ints (int *).
È importante indicare PRECEDENZA OPERATORE qui. L'operatore di dereferenza [] ha la preferenza su *. Quindi, per essere assolutamente chiaro, quello che stiamo facendo è questo:
*(array3[0]) = 4;
Ora, cambiamo argomenti da strutture e typedef.
struct foo { int a; }; // Declares a struct named foo
typedef struct { int a; } bar; // Typedefs an "ANONYMOUS STRUCTURE" referred to by 'bar'
Perché dovresti digitare una struttura anonima? Bene, per leggibilità!
struct foo a; // Declares a variable a of type struct foo
bar b; // Notice how you don't have to put 'struct' first
Dichiarare una funzione ...
funca(struct foo* arg1, bar *arg2);
Guarda come non abbiamo avuto bisogno di mettere 'struct' davanti arg2?
Ora, vediamo che il codice è necessario utilizzare definisce una struttura IN QUESTO MODO:
typedef struct { } * foo_pointers;
Questo è analogo a come abbiamo fatto un array di puntatori prima:
typedef int* array_of_ints;
Confronta side-by-side
typedef struct { } * foo_pointers;
typedef int* array_of_ints;
l'unica differenza è che uno è ad una struct {} e l'altro è in int.
Con i nostri foo_pointers, possiamo dichiarare un array di puntatori a foo come tale:
foo_pointers fooptrs[4];
Ora abbiamo una matrice che memorizza 4 puntatori ad una struttura anonima che non possiamo accedere.
TOPIC SWITCH!
PURTROPPO PER TE, il tuo insegnante ha commesso un errore. Se si guarda la dimensione di() del tipo foo_pointers sopra, si troverà che restituisce la dimensione di un puntatore a quella struttura, NON la dimensione della struttura. Questo è 4 byte per la piattaforma a 32 bit o 8 byte per la piattaforma a 64 bit. Questo perché abbiamo tipizzato un POINTER TO A STRUCT, non una struct stessa. sizeof (pStudentRecord) restituirà 4.
Quindi non è possibile allocare lo spazio per le strutture stesse in modo ovvio! Tuttavia, i compilatori tengono conto di questa stupidità. pStudentRecord non è un nome/tipo che puoi usare per allocare validamente memoria, è un puntatore a una struttura "concettuale" anonima, ma possiamo alimentare la dimensione di questo al compilatore.
pStudnetRecord g_ppRecords [2]; pStudentRecord * record = malloc (sizeof (* g_ppRecords [1]));
Una pratica meglio è quello di fare questo:
typedef struct { ... } StudentRecord; // Struct
typedef StudentRecord* pStudentRecord; // Pointer-to struct
Saremmo Ora abbiamo la possibilità di fare struct StudentRecord di, così come puntatori a loro con pStudentRecord di, in modo chiaro.
Anche se il metodo che si è obbligati a utilizzare è una pratica molto negativa, non è esattamente un problema al momento. Torniamo al nostro esempio semplificato usando gli interi.
E se voglio essere un typedef per complicare la mia vita ma spiegare il concetto che sta succedendo qui? Torniamo al vecchio codice int.
typedef int* array_of_ints;
int *array1[4];
int **array2 = malloc(sizeof(int *) * 4); // Equivalent-ish to the line above
array_of_ints *array3 = malloc(sizeof(array_of_ints) * 4);
int a, b, c, d;
*array1[0] = &a; *array1[1] = &b; *array1[2] = &c; *array1[3] = &d;
*array2[0] = &a; *array2[1] = &b; *array2[2] = &c; *array2[3] = &d;
*array3[0] = &a; *array3[1] = &b; *array3[2] = &c; *array3[3] = &d;
Come potete vedere, siamo in grado di utilizzare questo con il nostro pStudentRecord:
pStudentRecord array1[4];
pStudentRecord *array2 = malloc(sizeof(pStudentRecord) * 4);
Mettere tutto insieme, e ne consegue logicamente che:
array1[0]->firstName = "Christopher";
*array2[0]->firstName = "Christopher";
sono equivalenti. (Nota: non fare esattamente come ho fatto sopra, l'assegnazione di un puntatore char * in runtime a una stringa è OK solo se sai di avere già abbastanza spazio assegnato).
Questo mostra solo un ultimo bit.Cosa facciamo con tutto questo ricordo che abbiamo mallocato? Come lo liberiamo?
free(array1);
free(array2);
E c'è una alla fine di una lezione a tarda notte su puntatori, typedef di struct anonimi, e altre cose.
Un puntatore punta semplicemente a un indirizzo. Puoi avere tutta la memoria riservata a partire da quell'indirizzo che desideri (fino a esaurimento spazio). – chris
Penso che sia una domanda povera, capisci che un array può essere definito in questo modo, dato che provi ad allocare uno spazio per esso, quindi cosa stai chiedendo ?, non è sufficiente allocare uno spazio per il puntatore struct, che è btw pStudentRecord e non pSt ... ord *, per poterlo usare, è necessario anche assegnare un posto per la struct it self! – Michael