2009-09-14 13 views
6

Ho letto da qualche parte che se vuoi una funzione C/C++ per restituire un array di caratteri (al contrario di std :: string), devi restituire const char * piuttosto che char *. Facendo quest'ultimo potrebbe causare il crash del programma.Può/Perché usare char * invece di const char * nel tipo restituito causa arresti anomali?

Qualcuno sarebbe in grado di spiegare se questo è vero o no? Se è vero, perché restituire un char * da una funzione così pericolosa? Grazie.

const char * my_function() 
{ 
    .... 
} 

void main(void) 
{ 
    char x[] = my_function(); 
} 
+6

main() dovrebbe sempre restituire int! http://users.aber.ac.uk/auj/voidmain.shtml – nmuntz

risposta

14

Se si dispone di una funzione che restituisce "stringhe", allora deve restituire const char *. Questi non devono essere allocati nell'heap da malloc perché sono compilati in una sezione di sola lettura dell'eseguibile stesso.

Esempio:

const char* errstr(int err) 
{ 
    switch(err) { 
     case 1: return "error 1"; 
     case 2: return "error 2"; 
     case 3: return "error 3"; 
     case 255: return "error 255 to make this sparse so people don't ask me why I didn't use an array of const char*"; 
     default: return "unknown error"; 
    } 
} 
+0

Si deve inoltre notare per completezza che questi sono internati e altre variabili possono puntare alla posizione identica. Questo non dovrebbe essere un problema se const è rispettato, però. –

2

Se il char * è allocato nello stack, si restituisce un puntatore pendente. In caso contrario, purché corrisponda al prototipo della funzione e la dichiarazione corrisponda al valore restituito, si dovrebbe andare bene.

11

Quello che è stato detto è non vero.

Restituire un const char * può migliorare la semantica di una funzione (ad esempio, non confondere ciò che sto dando) ma restituire un char * è perfettamente a posto.

Tuttavia, in entrambi i casi, si necessario fare in modo che si restituisce un char * o const char * che è stato assegnato sul mucchio in my_function (cioè assegnate utilizzando malloc o new), altrimenti ogni volta my_function rendimenti, la memoria per lo [const] char * sarà deallocato e accederai a un puntatore non valido.

E, infine, si necessario ricordarsi di free o delete la [const] char * che è stato rispedito al mittente una volta che hai finito con esso, o si perderà la memoria. I linguaggi C/C++ non sono così grandi?

Così, in C, si avrebbe

const char *my_function() { 
    const char *my_str = (const char *)malloc(MY_STR_LEN + 1); // +1 for null terminator. 
    /* ... */ 
    return my_str; 
} 

int main() { 
    const char *my_str = my_function(); 
    /* ... */ 
    free(my_str); 
    /* ... */ 
    return 0; 
} 
+1

Questo genere di cose è il motivo per cui mi piace lo std :: string di C++ (anche se si tratta di un brutto lavoro di hacking di una definizione di stringa di classe) e puntatori intelligenti . Hai solo bisogno di sopportare così tanto dolore in C. –

+0

@DavidThornley la documentazione corretta riduce il dolore a quasi zero. – Qix

1

semplicemente cambiando il codice di ritorno sarà non causare un crash. Tuttavia, se la stringa restituita è statica (ad esempio return "AString"), è necessario restituire const char * per assicurarsi che il compilatore rilevi qualsiasi tentativo di modifica di tale memoria, che causerà un arresto anomalo del. Puoi sicuramente usare cast e simili per aggirare i controlli del compilatore, ma in tal caso dovresti fare di lavoro per fare in modo che l'arresto si verifichi.

+0

Grazie. Stai dicendo che se restituisci una stringa letterale (ad esempio restituisci "Questo è un test";), il tipo restituito deve essere const char *? Qual è il pericolo se il tipo di ritorno è invece char *? – Andy

+0

Se la stringa non viene modificata, non c'è pericolo, ma se il chiamante tenta di modificare la stringa, l'applicazione si bloccherà. Se il tipo di ritorno è 'const char *', allora il compilatore non ti permetterà di modificarlo. –

+0

Grazie. Questo è probabilmente quello di cui stanno parlando. Un altro aspetto di C non lo sapevo (e tre applausi a std :: string è fantastico!). – Andy

4

Di solito, questo non è un problema, ma ci sono cose da considerare. Di solito è una questione di cost-correttezza, il che significa tenere traccia di ciò che è possibile modificare e ciò che non si può.

Se si restituisce una stringa con quotatura doppia, è const char * e trattarla come qualsiasi altra cosa è un invito per problemi. Cambiare una stringa di questo tipo non è un comportamento indefinito, ma in genere causerà il crash del programma o cambierà la stringa a cui è riferita.

Se si restituisce una serie di caratteri nello stack (ad esempio, una variabile locale della funzione chiamata), essa andrà via e il puntatore non punta a nulla in particolare, probabilmente con risultati errati in qualche momento.

Se la funzione chiamata restituisce qualcosa che è già const char *, la modifica a char * richiede un cast. Inoltre, se hai intenzione di cambiarlo, devi essere sicuro che sia mutevole. Di solito è molto meglio tenerlo come const char *.

Non c'è nessun problema immediato con ritorno di memoria allocata con malloc() o new, ma si ha il problema della proprietà: quale funzione dovrebbe free()/delete, quando, e che cosa fare su eventuali copie? È qui che brillano gli intelligenti puntatori di C++.

Problemi correlati