2011-10-05 7 views
14

Diciamo che ho questo struct in ANSI C:ANSI C devi usare malloc() quando crei una struct?

typedef struct _point 
{ 
    float x; 
    float y; 
} Point; 

e questa funzione per creare questa struct:

Point createpoint(float x, float y) 
{ 
    Point p; 
    p.x = x; 
    p.y = y; 
    return p; 
} 

Questo mi permette di creare un struct con questa funzione vale a dire:

int main() 
{ 
    Point pointOne = createpoint(5, 6); 
    Point pointTwo = createpoint(10, 4); 
    float distance = calculatedistancefunc(pointOne, pointTwo); 

    /* ...other stuff */ 

    return 0; 
} 

Qualcuno mi ha detto che questo codice non è valido, perché il struct no ot ottenere malloc 'd nella funzione createpoint(float x, float y) prima che venga restituito e che lo struct venga eliminato. Tuttavia, quando uso il mio struct in questo modo, non sembra essere cancellato.

Quindi la mia domanda è: devo malloc questo struct, e perché?/perchè no?

risposta

13

Qualunque cosa stiate facendo è del tutto corretta. La dichiarazione -

return p; 

nella funzione restituisce una copia della variabile locale p. Ma se vuoi lo stesso oggetto che è stato creato nella funzione, devi farlo malloc. Tuttavia, è necessario free in seguito.

Point createpoint(float x, float y) 
{ 
    Point p; 
    p.x = x; 
    p.y = y; 
    return p; 
} // p is no longer valid from this point. So, what you are returning is a copy of it. 

Ma -

Point* createpoint(float x, float y) 
{ 
    Point *p = malloc(sizeof(Point)); 
    p->x = x; 
    p->y = y; 
    return p; 
}// Now you return the object that p is pointing to. 
+0

Qual è il tipo IMHO di mal consigliato. Se si desidera eseguire correttamente la gestione della memoria, non si dovrebbe tornare con un puntatore a una struttura allocata dinamicamente allocata nella propria funzione. Dovresti richiedere un puntatore preallocato in un terzo parametro e riempirlo con il tuo metodo. – mg30rg

+0

@ mg30rg Perché dovresti passare un puntatore di struttura pre-allocata quando puoi farlo nella funzione e restituirlo? – Houssni

+3

@YassineHoussni - Perché molto probabilmente leggerete il vostro codice più volte di quanto lo scriviate, quindi la leggibilità del codice è più importante della comodità di codifica. Se mantieni la memoria allocaton e release nello stesso blocco, sarà più difficile perdere memoria, perché le risorse sono riservate solo per il periodo esatto in cui sono necessarie e ogni resevation (es .: 'malloc()'/'getmem() '/' new') è visivamente associato a una disallocazione ('free()'/'freemem()'/'delete'). Puoi facilmente individuare un 'nuovo' senza' delete', ma vedrai un 'createpoint()' senza 'delete'? E farà il programmatore di manutenzione? – mg30rg

7

È possibile restituire struct in pila, il codice è valido. Si verificherebbe un problema se dovessi restituire un puntatore alla variabile locale, ma non è quello che stai facendo, stai restituendo una copia, va bene.

+2

Ma dovresti preoccuparti dell'utilizzo della memoria se segui lo stesso processo con una struttura più grande, poiché ogni campo viene copiato quando si verifica il ritorno. In quel caso specifico, non dovrebbe comunque essere un problema. –

+1

@Kernald - ci sono preoccupazioni relative all'utilizzo della memoria, problemi di prestazioni, problemi di profondità dello stack, ma è irrilevante per la domanda diretta dell'OP. ** è ** un codice C valido. – littleadv

+0

Grazie per le chiare risposte a tutti, Ma non riesco a capire perché 'passare per riferimento' sia più efficiente in memoria di 'passare per valore'. Voglio dire, entrambi i modi memorizzano la stessa quantità di dati nella struct? –

3
Point createpoint(float x, float y) 
{ 
    Point p; 
    p.x = x; 
    p.y = y; 
    return p; 
}/

Tutte le variabili locali nella funzione vengono eliminati after funzione ritorna.

1>passaggio per riferimento Quindi, se si sta tornando puntatore a questa variabile locale poi, dopo la funzione restituire questo variabili vengono cancellati in modo che i puntatori non sono validi.

2>passaggio per valore Ma qui si sta tornando copia di questa variabile locale per cui il suo sicuro perché la variabile locale sono gona morto quando restituisce la funzione, ma la copia del valore di ritorno verranno memorizzati nella variabile ricevitore chiamata di funzione prima del ritorno della funzione.

+0

Grazie per la chiara spiegazione, tuttavia ho una nuova domanda ora. Quando si preferisce passare per la restrizione e quando si preferisce passare per valore? –

+0

quando si sta andando a malloc qualcosa in funzione locale, quindi passarlo per conferma e quando si restituisce qualcosa variabile locale passarlo per valore .. più si può google .. .. !!! –

+0

puoi fare un'altra domanda anche per questo ...! –

5

C99 consente la creazione di strutture ancora più semplice in pila.
Dato il seguito struct

typedef struct 
{ 
    float x; 
    float y; 
} Point; 

è possibile inizializzare in un po 'di C++ maniera stile costruttore con la seguente dichiarazione:

Point p = (Point){0.4, 0.5}; 

e quindi si potrebbe o accorciare il createpoint o rottami del tutto :

int main() 
{ 
    Point pointOne = (Point){5, 6}; 
    Point pointTwo = (Point){10, 4}; 
    float distance = calculatedistancefunc(pointOne, pointTwo); 
    //...other stuff 
    return 0; 
} 
0

Una chiamata a un metodo che restituisce una struttura si comporterà come se il chiamante crea una variabile temporanea della struttura tipo da qualche parte che non è visibile in nessun altro ambito e fornisce alla funzione chiamata un puntatore. La funzione chiamata inserirà quindi i dati nella posizione richiesta e, dopo la sua restituzione, il chiamante sarà in grado di leggere i dati dalla nuova variabile. Data una funzione e chiamando il codice:

StructType BuildStruct(void) 
{ 
    StructType it; 
    it.this=4; 
    it.that=23; 
    return it; 
} 

StructType myStruct; 
myStruct = BuildStruct(); 

è probabile che ci sarà almeno un'operazione di copia, se non due; la dichiarazione return it; potrebbe dover copiare dalla variabile locale it nella struttura temporanea e l'assegnazione a myStruct potrebbe richiedere la copia dalla posizione temporanea a myStruct. Nessuna situazione richiede effettivamente due operazioni di copia; alcuni ne richiedono uno (che potrebbe essere eseguito dal chiamante o dal metodo chiamato) e alcuni non ne richiedono, ma la necessità di copiare dipende dai dettagli sia nel chiamante che nel metodo chiamato.

Un disegno alternativa sarebbe:

void BuildStruct(StructType *it) 
{ 
    it->this=4; 
    it->that=23; 
} 

StructType myStruct; 
BuildStruct(&myStruct); 

Questa sarebbe probabilmente resa codice equivalente al codice meglio si possa sperare utilizzando una variabile di ritorno struttura-tipo, poiché i dati struct sarebbero disposte direttamente nella sua finale spot senza che sia necessaria alcuna copia della struttura.

Problemi correlati