2014-10-05 16 views
5

Si consideri il seguente codice:Dobbiamo malloc una struttura?

struct Node { 
    void* data; 
    int ref; 
    struct Node* next; 
}; 
typedef struct Node* NodePtr; 

ho scoperto che sto ottenendo segfaults ogni volta che provo a fare qualsiasi cosa con i campi di NodePtr. Es .:

NodePtr node; 
node->ref = 1; 

Così ho assegnato po 'di spazio per il NodePtr, e ora sembra funzionare bene. Perchè è questo? La mia ipotesi è che poiché il nodo è solo un puntatore, non ha memoria per i suoi campi.

così ho cercato di inizializzare la NodePtr:

NodePtr node = { 
    node->data = 0; 
    node->next = NULL; 
    node->ref = 0; 
}; 

E bene, ho ottenuto questo errore:

error: expected â}â before â;â token 

Questo riduce a quattro domande:

  1. Se la mia ipotesi non è corretto, perché non funziona se non utilizzo malloc()?
  2. Perché la mia inizializzazione non funziona?
  3. Inizializza una memoria di offerta di struttura nello stack e risolve il mio problema?
  4. In caso contrario, devo un'alternativa a dover allocare memoria per ogni struct che uso?
+0

Non è necessario 'malloc'. Ad esempio, 'struct Node n = {NULL, 42, NULL};'. Hai solo errori di sintassi dappertutto. – juanchopanza

+2

Non è necessario allocare memoria se si sta creando un oggetto non puntatore. – Ares

+1

L'inizializzazione 'NodePtr' non è nemmeno corretta sintassi C, questo non può essere il codice che hai provato. –

risposta

17

Un struct possono essere assegnate automaticamente, ma si utilizza un puntatore a struct che sarà non allocare spazio per la destinazione struct. Quindi questo è il motivo per cui diventi segfault.

Il motivo per il vostro di inizializzazione non è corretto è che si inizializza structmembri, non il struct stesso. Anche tu lo stai facendo in modo sbagliato.

Ci sono 2 modi per inizializzare un struct: pila assegnato struct

  1. Uso:

    struct example { 
        int foo; 
    }; 
    int main() { 
        struct example e; 
        e.foo=1; 
    } 
    
  2. Utilizzando heap allocata struct con l'aiuto di malloc():

    struct example { 
        int foo; 
    }; 
    int main() { 
        struct example *e=malloc(sizeof(struct example)); 
        e->foo=1; 
    } 
    

Si prega di notare che quando si sta assegnando valore a un membro di una struct dal suo puntatore (heap allocata struct) è necessario utilizzare '->' ma per la struct normale (lo stack assegnato uno) si deve utilizzare '.' .

1

La tua ipotesi è corretta: un puntatore non dispone di memoria per l'oggetto che si suppone al punto da solo, è necessario allocare da soli.

In ogni caso, come ha osservato juanchopanza: non hai bisogno di un puntatore e una dotazione di memoria, se hai a che fare con un oggetto locale.

Entrambe le tecniche seguono:

typedef struct Node { 
    void* data; 
    int ref; 
    struct Node* next; 
} Node; 
typedef struct Node* NodePtr; 

int main() { 

     NodePtr node = (NodePtr)malloc(sizeof(Node)); 
     node->data = 0; 
     node->next = 0; 
     node->ref = 42; 
     printf("%d", node->ref); 

     Node obj = {0,42,0}; // this is not on the heap 
     printf("%d", obj.ref); 

Le altre sintassi si è tentato sono non corretta. Neanche parte della lingua.

2

Un puntatore non è una struct. È un numero che indica a C dove si trova la struttura nella memoria. Qualsiasi varible con tipo NodePtr è essenzialmente un numero.

Come ha senso, quindi, per impostare una variabile di tipo NodePtr ad una struct? Una struttura non è un numero!

Quando lo si dichiara con NodePtr node, potrebbe essere impostato su un valore non definito come 0. Non è possibile accedere a tale memoria, che porta a un segfault. Invece, si individua un po 'di memoria da usare con malloc() e si rende quel punto variabile lì dove i suoi campi possono essere usati.


Per rispondere al commento di potrzebie, sembra funzionare con le stringhe, ma questo è lo zucchero in realtà solo sintattico:

#include <stdio.h> 

int main() { 
    char *a = "Does this make sense?"; 
    printf("%d\n", a); // %u is the correct one, but this is for illustrational purposes 

    return 0; 
} 


> test.exe 
4214884 
+0

Avrebbe senso, puoi farlo con le stringhe. – potrzebie

+0

@potrzebie 'char * x =" ... "'? Quello è zucchero sintattico, è ancora un numero e la stringa è archiviata da qualche altra parte. È stato questo il motivo del downvoting (se fossi stato tu)? – itdoesntwork