confusione di sintassi con array e puntatori
Considera quanto segue:
typedef struct node
{
int number;
struct node *left;
struct node *right;
} node;
node test[511];
node *test1 = malloc(511 * sizeof(node));
node (*test2)[511] = malloc(511 * sizeof(node));
è corretto quanto segue:
- test è un array di 511 nodi. possiamo accedere a ogni nodo con test [i] dove i è il nodo che vogliamo
- test1 è un puntatore in cui mallociamo lo spazio per 511 nodi. possiamo accedere a ogni nodo con test1 [i]
quindi test e test1 sono fondamentalmente uguali tranne che test è sullo stack e test1 sull'heap?
test2 sembra un puntatore a un array. malloc alloca 511 * sizeof (nodo) a ciascun puntatore o all'intero array? se il secondo allora possiamo accedere a ciascun nodo con test2 [i] e se il primo può fare quanto segue:
node (*test2)[511] = malloc(sizeof(node));
e quindi accedere a ciascun nodo con test2 [i]?
in generale qual è la differenza tra * test1 e (* test2)?
Risposte
La differenza è che test1ci si riferisce al file node. test2si riferisce alla matrice di 511 nodeelementi.
test1 + 1farà riferimento nodeall'oggetto successivo
test2 + 1farà riferimento al prossimo array di 511 nodeoggetti
quindi test e test1 sono fondamentalmente uguali tranne che test è sullo stack e test1 sull'heap?
Nessuno è un array che può decadere in puntatore, un altro è un puntatore che fa riferimento a un oggetto di tipo node
Quando si mallocmemorizza è meglio usare gli oggetti invece dei tipi
node test[511];
node *test1 = malloc(511 * sizeof(*test1));
node (*test2)[511] = malloc(511 * sizeof(*test2));
{
int number;
struct node *left;
struct node *right;
} node;
int main(void)
{
node test[511];
node *test1;
node (*test2)[511];
printf("sizeof test = %zu\n", sizeof(test));
printf("sizeof *test1 = %zu\n", sizeof(*test1));
printf("sizeof *test2 = %zu\n", sizeof(*test2));
}
typedef struct node
{
int number;
struct node *left;
struct node *right;
} node;
int main(void)
{
node test[511];
node *test1;
node (*test2)[511];
printf("sizeof test = %zu\n", sizeof(test));
printf("sizeof *test1 = %zu\n", sizeof(*test1));
printf("sizeof *test2 = %zu\n", sizeof(*test2));
}
in generale qual è la differenza tra * test1 e (* test2)?
In questa dichiarazione
node *test1 = malloc(511 * sizeof(node));
viene dichiarato un puntatore a un oggetto del tipo node. Quindi dereferenziando il puntatore come *test1si otterrà un oggetto del tipo node. Cioè avrai accesso al primo oggetto dell'array allocato dinamicamente.
In questa dichiarazione
node (*test2)[511] = malloc(511 * sizeof(node));
viene dichiarato un puntatore a un oggetto del tipo node[511]. Questo è l'oggetto appuntito ha il tipo di matrice node[511]. Dereferenziando il puntatore si otterrà la matrice puntata allocata dinamicamente.
Quindi sizeof( *test1 )è uguale a sizeof( node ). Mentre sizeof( *test2 )è uguale a sizeof( node[511] )quello è lo stesso di 511 * sizeof( node ).
Per accedere al primo elemento dell'array allocato utilizzando il puntatore test2è necessario prima dereferenziarlo per ottenere l'array puntato che a sua volta utilizzato in un'espressione con l'operatore di accesso ai membri -> viene convertito implicitamente in puntatore al suo primo elemento.
Ecco un programma dimostrativo.
#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
int number;
struct node *left;
struct node *right;
} node;
int main(void)
{
node *test1 = malloc(511 * sizeof(node));
node (*test2)[511] = malloc(511 * sizeof(node));
printf( "sizeof( *test1 ) = %zu\n", sizeof( *test1 ) );
printf( "sizeof( *test2 ) = %zu\n", sizeof( *test2 ) );
( *test1 ).number = 10;
( **test2 ).number = 20;
printf( "test1->number = %d\n", test1->number );
printf( "( *test2 )->number = %d\n", ( *test2 )->number );
free( test1 );
free( test2 );
return 0;
}
L'output del programma è
sizeof( *test1 ) = 24
sizeof( *test2 ) = 12264
test1->number = 10
( *test2 )->number = 20
Il puntatore test2potrebbe anche essere inizializzato, ad esempio, nel modo seguente
node test[511];
node (*test2)[511] = &test;
Mentre il puntatore test1potrebbe essere inizializzato come
node *test1 = test;
Quindi sono
testetest1fondamentalmente la stessa cosa tranne chetestè in pila etest1in pila?
Sì, parlando liberamente, possiamo dirlo. Con una dichiarazione di non responsabilità, questi sono tipi diversi.
test2sembra un puntatore a un array. nonmallocassegnare511 * sizeof(node)ad ogni puntatore o per l'intera matrice?
Di nuovo, parlando liberamente, possiamo dire a ciascun puntatore, che in questo caso è anche l'intero array, poiché allochi solo 1 blocco di 511 nodi.
Questo è un puntatore all'array di 511, in quanto tale dovresti assegnargli solo blocchi di memoria multipli di 511 * sizeof(node). Potresti assegnargli qualcosa come:
node (*test2)[511] = malloc(sizeof(node) * 511 * 5);
In tal caso avresti un array di 5 node (*test2)[511]. Puoi equipararlo a node test2[5][511]come la notazione di accesso è la stessa.
Se il secondo, possiamo accedere a ciascun nodo con
test2[i]e se il primo può fare quanto segue:node (*test2)[511] = malloc(sizeof(node));e poi accedi a ogni nodo con
test2[i]?
Questa allocazione non è corretta. test2[0]punta al primo blocco di 511 nodi, in particolare al primo elemento di ogni blocco di 511 nodi, test2[1]punta al primo elemento del successivo blocco di 511 nodi, non è possibile utilizzare questo puntatore per accedere a singoli nodi, ad eccezione di ogni primo nodo di ogni blocco di 511 nodi.
L'accesso ai singoli nodi deve essere effettuato, ad esempio test2[0][1], per il secondo nodo (indice 1) del primo blocco di 511 nodi.
Quindi, ancora una volta, l'allocazione deve essere di blocchi di multipli di 511 * sizeof(node).
In generale qual è la differenza tra
*test1e(*test2)?
Questo è tutto, test1è un puntatore a node, test2è un puntatore a un array di 511 nodi. Le spiegazioni precedenti dovrebbero fare la differenza rilevata.
test1viene utilizzato per accedere a qualsiasi membro di ciascun blocco dell'array di nodi, test2viene utilizzato per accedere a ciascun blocco di 511 nodi.
è corretto quanto segue:
testè un array di 511 nodi. possiamo accedere a ogni nodo contest[i]dove siitrova il nodo che vogliamo
sì
test1è un puntatore in cuimallocspaziamo per 511 nodi. possiamo accedere a ogni nodo contest1[i]
Sì.
così sono
testetest1fondamentalmente gli stessi tranne che test è sullo stack e test1 sull'heap?
Non esiste il concetto di stack o heap nello standard C, tuttavia, a parte questo, non sono la stessa cosa. testè un array ed test1è un puntatore, sono tipi completamente diversi.
Ho preso il tuo codice e ho aggiunto anche una quarta alternativa. E posterò un programma e una discussione che possono essere utili per renderlo un po 'più chiaro.
Credo che questa linea
Node* test1 = malloc(_SIZE_ * sizeof(Node));
è la chiave per capire come le cose possono confondersi. malloc()restituisce solo un puntatore a un'area delle dimensioni dell'argomento. In effetti queste 2 linee sono simili
int* example = malloc(511);
Node* test1 = malloc(_SIZE_ * sizeof(Node));
e illustra perché le persone di C ++ rendono obbligatorio il cast di un tipo per la restituzione di malloc()like in
int* example = (int*) malloc(511);
Node* test1 = (Node*) malloc(_SIZE_ * sizeof(Node));
rende le cose più chiare, hanno detto. E io credo. In questo modo vediamo che test1è solo un puntatore a Nodee può avvertirci che forse le cose stanno andando male, o potrebbe non essere come ci aspettavamo: non fa differenza il numero di byte allocati, sarà un file NODE*. Un puntatore a un'area.
torna alla roba di prova [123] qui
test1 come
Node* test1 = malloc(_SIZE_ * sizeof(Node));
test1è solo un puntatore a Node. malloc()assegnerà felicemente quanti byte come valuta dall'argomento. Anche meno della dimensione di uno Node, e il programma potrebbe bloccarsi molto velocemente ... o 511 byte, non facendo alcuna differenza pratica nel test ma portandolo a questo argomento in SO :)
test
#define _SIZE_ 16
Node test[_SIZE_];
test è solo un array di Node
typedef struct node
{
int number;
struct node* left;
struct node* right;
} Node;
test2
Node (*test2)[_SIZE_] = malloc(_SIZE_ * sizeof(Node));
Questo non è visto di frequente perché non è flessibile: test2è un puntatore a un array di [_SIZE_]elementi di Node. Una cosa proprio come test. In effetti mostrerò di seguito che è perfettamente corretto scrivere
Node test[_SIZE_];
Node (*test2)[_SIZE_] = &test;
perché questa è solo la definizione della cosa a cui test2punta, ma poiché _SIZE_il noto in fase di compilazione è usato raramente. Invece abbiamo cose molto più flessibili come il familiare
int main(int argc, char** argv);
E introducendo test3
Node** test3;
Ecco test3un puntatore a un array di puntatori a Node, e questo è il modo utile, come ogni C o C ++ o qualsiasi programma conosce. Cerchiamo di riempirlo
Node** test3 = (Node**)malloc(sizeof(Node*) * _SIZE_);
for (int i = 0; i < _SIZE_; i += 1)
{
test3[i] = (Node*)malloc(sizeof(Node));
test3[i]->number = 1000 + i;
};
Ora test3punta a un'area di _SIZE_volte il sizeof()di un puntatore a NODE. E andiamo nell'area e impostiamo i singoli riferimenti a un reale NODE, ognuno. E mettiamo un valore nel numero membro di ogni nodo in modo da poterlo stampare in seguito nel programma di esempio.
- Qual è la differenza? Ora possiamo iterare sui nodi proprio come facciamo ancora e ancora
argv[i] - Che cosa manca? Le informazioni sulla dimensione. Questo è il motivo per cui abbiamo
argcin ogni programma. Potremmo scrivere
// now to iterate over Nodes: should be as familiar as
typedef struct
{
int nodec;
Node** nodev;
} NodeArray;
così familiare ... E possiamo NodeArraysignorare matrici iterabili di strutture, proprio come gli argomenti della riga di comando ...
output dell'esempio
sizeof(test) = 384
sizeof(test1) = 8
sizeof(test2) = 8
test is Node[_SIZE_]. Values are
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
test2 is a pointer to Node[_SIZE_]. So we can assign &test to it
Done. Now the values of test2:
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
test2 restored. Now set up from 500
500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515
test1 is just a pointer to Node. Let's set it to 300
*test1 is 300
test3 is an array of pointers to Node, set up from 1000:
1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015
Codice d'esempio
#define _SIZE_ 16
#include <stdio.h>
#include <stdlib.h>
typedef struct node
{
int number;
struct node* left;
struct node* right;
} Node;
int main(void)
{
Node test[_SIZE_];
Node* test1 = malloc(_SIZE_ * sizeof(Node));
int* example = malloc(511); // no meaning
Node (*test2)[_SIZE_] = malloc(_SIZE_ * sizeof(Node));
// test2 points to Node[_SIZE_]
for (int i = 0; i < _SIZE_; i += 1) test[i].number = i;
printf("sizeof(test) = %zd\n", sizeof(test));
printf("sizeof(test1) = %zd\n", sizeof(test1));
printf("sizeof(test2) = %zd\n", sizeof(test2));
// test is an array of Node
printf("\ntest is Node[_SIZE_]. Values are \n");
for (int i = 0; i < _SIZE_; i += 1)
printf("%6d", test[i].number);
printf("\n");
// test2 points to an array of Node
printf("\ntest2 is a pointer to Node[_SIZE_]. So we can assign &test to it\n");
void* save = test2; // or it will leak
test2 = &test;
printf("\nDone. Now the values of test2:\n");
for (int i = 0; i < _SIZE_; i += 1)
printf("%6d", (*test2)[i].number);
printf("\n");
test2 = save; // restored
printf("\ntest2 restored. Now set up from 500\n");
for (int i = 0; i < _SIZE_; i += 1) (*test2)[i].number = 500 + i;
for (int i = 0; i < _SIZE_; i += 1)
printf("%6d", (*test2)[i].number);
printf("\n");
// test1 is just a pointer to node
printf("\ntest1 is just a pointer to Node. Let's set it to 300\n");
test1->number = 300;
printf("*test1 is %d\n", test1->number);
// now to iterate over Nodes: should be as familiar as
typedef struct
{
int nodec;
Node** nodev;
} NodeArray;
//Node** test3;
Node** test3 = (Node**)malloc(sizeof(Node*) * _SIZE_);
for (int i = 0; i < _SIZE_; i += 1)
{
test3[i] = (Node*)malloc(sizeof(Node));
test3[i]->number = 1000 + i;
};
// test3 is an array of Node
printf("\ntest3 is an array of pointers to Node, set up from 1000:\n");
for (int i = 0; i < _SIZE_; i += 1)
printf("%6d", test3[i]->number);
printf("\n");
// now free() all this
// test is static
free(test1); // test1 is Node*
// test2 is Node (*)[]
free(test2);
// test3 is a pointer to an array of pointers...
for (int i = 0; i < _SIZE_; i += 1) free(test3[i]);
// all gone
test3 = NULL; // invalidate it
printf("\n");
return 0;
};