2013-03-16 22 views
16

È possibile restituire una stringa da una funzione senza chiamare malloc? Ho una funzione, come di seguito:stringa di ritorno dalla funzione senza malloc

char* getString(){ 
     char tempStr[20] 

     // open file, read char by char and assign to tempStr 
     // .... 

     char* str = (char*)malloc(sizeof(char)*20); 
     strcpy(str, tempStr); // assume this copy the null terminating char as well 
     return str; 
} 

E poi quando chiamo il getString(), assegno il valore di ritorno ad un char*, e poi liberarlo quando ho finito, come di seguito:

void randomFunction(){ 
     char* line = NULL; 
     int i = 0; 
     while (i < 1000) { 
      line = getString(); 
      // do stuff with line 
      free (line); 
      line = NULL; 
     } 
} 

Tuttavia, mi chiedo se non vi è alcun modo per farlo senza malloc? E questo è il modo corretto di restituire una stringa da una funzione C? Ho provato a fare qualche ricerca su come restituire senza malloc, ma non ho trovato risposte chiare. Sono nuovo di C e sto ancora imparando.

+3

La chiamata 'malloc' è meglio scritta come' char * str = malloc (20); '' sizeof (char) 'è 1 per definizione e il risultato di' malloc' non è necessario e [non raccomandato] (http://c-faq.com/malloc/mallocnocast.html). –

+0

@KeithThompson Non ho mai saputo che il risultato del malloc può portare a comportamenti indesiderati. Grazie per le informazioni! :) – blenzcoffee

+0

@KeithThompson Non raccomanderei di omettere la sizeof (char); è buona pratica tenerlo lì e sarebbe un compilatore terribile che non lo ottimizzasse. Anche gli argomenti contro il casting malloc mi sono sempre sembrati sciocchi; è richiesto in C++ e, a mio parere, potresti anche scrivere codice in linguaggio portatile quando puoi. – Dave

risposta

11

Non è possibile restituire temporaneamente una funzione e, a meno che non si utilizzi un malloc, l'array di caratteri definito nella funzione sarà temporaneo. Una soluzione alternativa è passare un array di caratteri come parametro della funzione e usarlo come parametro di output.

+0

Proverò il tuo suggerimento per passare un array di caratteri come parametro. Se ottengo la soluzione in modo corretto, la funzione modificherà e restituirà quello stesso array di caratteri passato come input, giusto? E in questo modo possiamo evitare malloc, ho ragione? Grazie – blenzcoffee

+0

@blenzcoffee se ho capito bene cosa vuoi fare, allora si dovrebbe farlo. –

+2

È possibile evitare malloc se la matrice è stata dichiarata dal chiamante con una determinata dimensione. – OregonTrail

7

Dipende.

È possibile decidere e documentare che la stringa restituita è un puntatore a un buffer interno statico. Quindi la tua routine non è rientranti (né thread-safe). Ad esempio, ctime o getpwent.

Una cosa migliore sarebbe passare la stringa di risultati e la dimensione come argomenti, e per riempire quella stringa e possibilmente restituirla. getcwd (o snprintf o strftime che restituisce una dimensione, non un puntatore) funziona in questo modo.

Ma in genere, si decide e si documenta che la stringa restituita è allocata su heap, ed è la responsabilità del chiamante su free. In questo caso potresti voler utilizzare strdup o asprintf.

E si potrebbe utilizzare nel vostro intero programma Boehm's conservative garbage collector (ad esempio, utilizzare il suo GC_STRDUP o GC_MALLOC_ATOMIC per le stringhe, e GC_MALLOC per i valori di heap che contiene alcune indicazioni.)

Se ritieni che di serie malloc o strdup è troppo lento (ma si prega di misurare prima), si potrebbe avere il proprio pool di allocatori, ecc.

Si potrebbe anche avere schemi alternativi (ma è importante documentarli). Ad esempio, è possibile restituire alcuni interned string o anche una stringa interna canonica (a volte denominata "quark" o "simbolo"), quindi essere in grado di utilizzare l'uguaglianza del puntatore anziché l'uguaglianza delle stringhe. Potresti anche avere uno schema reference counter. Guardate per esempio a quello che Glib (da GTK, ma al di fuori utilizzabile di programmi con interfaccia grafica!) Dispone: GString-s, GQuark-s, string utilities

E 'comunque importante per decidere se il risultato è heap allocata o meno, e di definire chiaramente chi ha la responsabilità di liberare (e come dovrebbe essere liberato) quel risultato assegnato all'heap.

È possibile utilizzare valgrind per individuare perdite di memoria. Non dimenticare di passare -Wall -g al tuo compilatore gcc!

PS. Vorrei prendere in considerazione l'utilizzo del GC di Boehm. E non penso che malloc (o strdup, asprintf ....) debba essere rifiutato per motivi di prestazioni (è possibile scegliere altre & più veloci malloc implementazione o utilizzare i propri pool di memoria). Tuttavia, le perdite di memoria potrebbero essere un problema.

+0

Boehm gc url si è rotto. Trovalo qui. http://www.hboehm.info/gc/ –

2

modo normale per spostare l'allocazione di memoria fuori da una funzione è passare in puntatori. Anche se in pratica dovresti assicurarti di non andare oltre i limiti del buffer.

char* getString(char* tempStr){ 
      // open file, read char by char and assign to tempStr 
      // .... 

      return tempStr; 
    } 


void randomFunction(){ 
     char line[20]; 
     int i = 0; 
     while (i < 1000) { 
      getString(line); 
      // do stuff with line 

     } 
    } 
+0

In Linux, suggerirei 'strdup' o' asprintf' –

+0

'strdup' e' asprintf' usa 'malloc', che l'OP sta cercando in particolare di evitare. –

+0

Il tuo codice imposta 'line' su quello che presumo sia una variabile locale di' getString'. Penso che intendevi restituire 'tempStr', e non sono sicuro del motivo per cui' 'strcpy'', o riassegnerai' line' affatto. – Dave

2

Dal momento che la stringa è (apparentemente) sempre di 20 caratteri, si può semplicemente fare questo:

void getString(char *outputString) { 
    // do stuff to outputString instead of mallocing, or use local memory and copy it at the end 
} 

char line[20]; 
for(...) { 
    getString(line); 
    // do things with line 
} 

Perché questo evita tanti piccoli mallocs, è più veloce.

12

Esistono tre metodi comuni per restituire una stringa da una funzione. (Beh, in realtà non ce ne sono, ma ci sono tre modi comuni per restituire un puntatoread una stringa, che il chiamante può quindi utilizzare per accedere alla stringa.)

  1. allocare spazio per la stringa utilizzando malloc() all'interno della funzione. Questo è il metodo più flessibile, ma rende il chiamante responsabile di free() nell'array assegnato. Può anche imporre alcuni overhead delle prestazioni.

  2. Richiede al chiamante di allocare lo spazio per la stringa e passare un puntatore a quello spazio. Ciò impone alcuni inconvenienti al chiamante. In particolare, il chiamante deve decidere quanto può essere grande la stringa.

  3. Restituisce un puntatore a (il primo elemento di) un array static definito all'interno della funzione. La matrice continuerà ad esistere dopo il ritorno della funzione, ma c'è solo una copia, il che significa che le chiamate successive colmeranno il risultato restituito dalle chiamate precedenti. Significa anche che l'array deve essere di alcune dimensioni fisse, scelto quando si scrive il codice.

2

Un modo comune per eseguire questa operazione in C consiste nel passare la stringa come argomento alla funzione.

char *getString(char *str, int size){ 
     // open file, read char by char and assign to tempStr 
     // .... 

     strncpy(str, tempStr, size); // assume this copies the null terminator 
     return str; 
} 

In alternativa, è possibile avere la stringa dichiarata statica, o in un file o ambito globale e copiarvi. Tuttavia, assicurati che se si memorizza un puntatore su un buffer allocato nell'heap in questo simbolo, lo si libera prima di ripartire.

0

Basta dichiarare la stringa come statica nella funzione e restituirla.

Problemi correlati