2009-09-14 9 views
6

Ich habe irgendwo gelesen, dass, wenn Sie möchten, dass eine C/C++ - Funktion ein Zeichen-Array zurückgibt (im Gegensatz zu std :: string), müssen Sie const char * anstelle von char * zurückgeben. Letzteres kann zum Absturz des Programms führen.Kann/warum die Verwendung von char * anstelle von const char * im Rückgabetyp Abstürze verursacht?

Würde jemand erklären können, ob das stimmt oder nicht? Wenn es wahr ist, warum ist ein char * aus einer Funktion so gefährlich? Vielen Dank.

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

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

main() sollte immer int zurückgeben! http://users.aber.ac.uk/auj/voidmain.shtml – nmuntz

Antwort

14

haben Wenn Sie eine Funktion haben, die "Stringliterale" gibt, dann muss es * const char zurück. Diese müssen nicht auf dem Heap von malloc zugewiesen werden, da sie in einen schreibgeschützten Abschnitt der ausführbaren Datei kompiliert werden.

Beispiel:

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

Es sollte auch darauf hingewiesen werden, dass diese interniert sind und andere Variablen auf den identischen Ort zeigen können. Das sollte kein Problem sein, wenn const respektiert wird. –

2

Wenn char * auf dem Stapel zugeordnet ist, geben Sie einen freien Zeiger zurück. Andernfalls, solange es mit dem Prototyp der Funktion übereinstimmt und die Deklaration mit dem Rückgabewert übereinstimmt, sollte alles in Ordnung sein.

11

Was Ihnen gesagt wurde, ist nicht wahr.

Die Rückgabe einer const char * kann die Semantik einer Funktion verbessern (d. H. Nicht mit dem, was ich Ihnen gebe, verwirren), aber eine char * ist völlig in Ordnung.

jedoch in jedem Fall Sie müssen stellen Sie sicher, dass Sie ein char * oder const char * zurück, die auf dem Heap in my_function zugewiesen wurde (dh malloc oder new teilt Siemens), andernfalls, wenn my_function zurückkehrt, den Speicher für Die [const] char * wird aufgehoben, und Sie greifen auf einen ungültigen Zeiger zu.

Und du endlich muss zu free oder delete die [const] char * erinnern, die an Sie zurückgeschickt worden ist, wenn Sie mit ihm fertig sind, oder Sie werden ein Speicherleck. Sind nicht C/C++ so großartige Sprachen?

also in C, würden Sie

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

Diese Art von Sache ist, warum ich C++ 's st :: string (auch wenn es ein schlechter Hack-Job einer String-Klasse-Definition ist), und intelligente Zeiger . Sie müssen nur durch so viel Schmerz in C gehen. –

+0

@DavidThornley ordnungsgemäße Dokumentation reduziert diesen Schmerz auf nahezu Null. – Qix

1

einfach den Return-Code ändern, wird nicht zu einem Absturz führen. Wenn die zurückgegebene Zeichenfolge jedoch statisch ist (z. B. return "AString"), sollten Sie const char * zurückgeben, um sicherzustellen, dass der Compiler eine versuchte Änderung dieses Speichers erkennt, die wahrscheinlich einen Absturz verursacht. Sie können sicherlich Casts und solche verwenden, um die Compiler-Checks zu umgehen, aber in diesem Fall müssten Sie arbeiten, um den Absturz passieren zu lassen.

+0

Danke. Wollen Sie damit sagen, dass, wenn Sie eine literale Zeichenfolge zurückgeben (z. B. return "Dies ist ein Test";), der Rückgabetyp const char *? Was ist die Gefahr, wenn der Rückgabetyp char * ist? – Andy

+0

Wenn die Zeichenfolge nicht geändert wird, besteht keine Gefahr. Wenn der Aufrufer jedoch versucht, die Zeichenfolge zu ändern, stürzt die Anwendung ab. Wenn der Rückgabetyp "const char *" ist, kann der Compiler sie nicht ändern. –

+0

Danke. Davon reden sie wahrscheinlich. Ein weiterer Aspekt von C wusste ich nicht (und drei Jubel zu Std :: String ist großartig!). – Andy

4

Normalerweise ist das kein Problem, aber es gibt Dinge zu beachten. Es ist normalerweise eine Frage der Korrektheit, was bedeutet, dass Sie im Auge behalten, was Sie ändern können und was nicht.

Wenn Sie eine Zeichenfolge mit doppelten Anführungszeichen zurückgeben, lautet sie const char *. Wenn Sie sie wie alles andere behandeln, ist das eine Einladung zu Problemen. Das Ändern einer solchen Zeichenfolge ist ein nicht definiertes Verhalten, führt jedoch normalerweise zum Absturz des Programms oder zum Ändern der Zeichenfolge, unabhängig davon, auf was verwiesen wird.

Wenn Sie ein Zeichenarray auf dem Stapel zurückgeben (d. H. Die lokale Variable einer aufgerufenen Funktion), wird es verschwinden und der Zeiger wird auf nichts ausgerichtet sein, wahrscheinlich mit schlechten Ergebnissen zu einem bestimmten Zeitpunkt.

Wenn die aufgerufene Funktion etwas zurückgibt, das bereits const char * ist, dann erfordert das Ändern auf char * eine Umwandlung. Weiter, wenn Sie es wirklich ändern, müssen Sie sicher sein, dass es veränderbar ist. Es ist normalerweise viel besser, es als const char * zu behalten.

Es gibt kein unmittelbares Problem mit Speicher mit malloc() oder new zugeordnet Rückkehr, aber Sie haben das Problem des Eigentums haben: Welche Funktion sollte free()/delete es, wann und was tun Sie über mögliche Kopien? Hier leuchten C++ Smartpointer.