Diese Frage soll als Referenz für alle häufig gestellten Fragen der Natur dienen:
Warum erhalte ich einen mysteriösen Absturz oder „Segmentierungsfehler“, wenn ich Daten an die Adresse kopiere/scanne, auf die ein nicht initialisierter Zeiger zeigt?
Zum Beispiel:
char* ptr;
strcpy(ptr, "hello world"); // crash here!
oder
char* ptr;
scanf("%s", ptr); // crash here!
Ein Zeiger ist eine spezielle Art von Variable, die nur eine Adresse einer anderen Variablen enthalten kann. Es darf keine Daten enthalten. Sie können keine Daten in einen Zeiger kopieren/speichern – das ergibt keinen Sinn. Sie können einen Zeiger nur so setzen, dass er auf anderweitig zugeordnete Daten zeigt.
Damit ein Zeiger sinnvoll ist, muss er also immer auf eine gültige Speicherstelle zeigen. Zum Beispiel könnte es auf Speicher zeigen, der auf dem Stack zugewiesen ist:
{
int data = 0;
int* ptr = &data;
...
}
Oder dynamisch auf dem Heap zugewiesener Speicher:
int* ptr = malloc(sizeof(int));
Es ist immer ein Fehler, einen Zeiger zu verwenden, bevor er initialisiert wurde. Es zeigt noch nicht auf eine gültige Erinnerung.
Diese Beispiele können alle zu Programmabstürzen oder anderen unerwarteten Verhaltensweisen wie „Segmentierungsfehlern“ führen:
/*** examples of incorrect use of pointers ***/
// 1.
int* bad;
*bad = 42;
// 2.
char* bad;
strcpy(bad, "hello");
Stattdessen müssen Sie sicherstellen, dass der Zeiger auf (genügend) allozierten Speicher zeigt:
/*** examples of correct use of pointers ***/
// 1.
int var;
int* good = &var;
*good = 42;
// 2.
char* good = malloc(5 + 1); // allocates memory for 5 characters *and* the null terminator
strcpy(good, "hello");
Beachten Sie, dass Sie einen Zeiger auch so einstellen können, dass er auf ein wohldefiniertes “Nirgendwo” zeigt, indem Sie ihn darauf zeigen lassen NULL
. Das macht es zu einem Null Zeiger, was ein Zeiger ist, der garantiert nicht auf einen gültigen Speicher zeigt. Dies unterscheidet sich davon, den Zeiger vollständig uninitialisiert zu lassen.
int* p1 = NULL; // pointer to nowhere
int* p2; // uninitialized pointer, pointer to "anywhere", cannot be used yet
Sollten Sie jedoch versuchen, auf den Speicher zuzugreifen, auf den ein Nullzeiger zeigt, können Sie ähnliche Probleme bekommen wie bei der Verwendung eines nicht initialisierten Zeigers: Abstürze oder Segmentierungsfehler. Im besten Fall bemerkt Ihr System, dass Sie versuchen, auf die Adresse null zuzugreifen, und wirft dann eine „Nullzeiger-Ausnahme“ aus.
Die Lösung für Nullzeiger-Ausnahmefehler ist dieselbe: Sie müssen den Zeiger so einstellen, dass er auf einen gültigen Speicher zeigt, bevor Sie ihn verwenden.
Weiterlesen:
Zeiger, die auf ungültige Daten zeigen
Wie greife ich mit Zeigern von einer anderen Funktion auf eine lokale Variable zu?
Kann auf den Speicher einer lokalen Variablen außerhalb ihres Geltungsbereichs zugegriffen werden?
Segmentierungsfehler und Ursachen
Was ist ein Segmentierungsfehler?
Warum erhalte ich einen Segmentierungsfehler, wenn ich in eine Zeichenfolge schreibe, die mit „char *s“, aber nicht mit „char s“ initialisiert wurde[]”?
Was ist der Unterschied zwischen char s[] und Char*s?
Endgültige Liste häufiger Gründe für Segmentierungsfehler
Was ist ein Busfehler?
Eine Situation, die beim Erlernen von C häufig auftritt, ist der Versuch, einfache Anführungszeichen zu verwenden, um ein Zeichenfolgenliteral zu bezeichnen:
char ptr[5];
strcpy(ptr, 'hello'); // crash here!
// ^ ^ because of ' instead of "
In C, 'h'
ist ein einzelnes Zeichenliteral, während "h"
ist ein Zeichenfolgenliteral, das ein enthält 'h'
und ein Nullterminator \0
(d. h. ein 2-Zeichen-Array). Auch in C ist der Typ eines Zeichenliterals int
das ist, sizeof('h')
ist äquivalent zu sizeof(int)
während sizeof(char)
ist 1
.
char h="h";
printf("Size: %zu\n", sizeof(h)); // Size: 1
printf("Size: %zu\n", sizeof('h')); // likely output: Size: 4
Dies geschieht, weil Sie haben nicht zugewiesen Erinnerung für die Zeiger char* ptr
. In diesem Fall müssen Sie dynamisch zuordnen Speicher für den Zeiger.
Zwei Funktionen malloc()
und calloc()
kann verwendet werden für dynamic memory allocation
.
Versuchen Sie diesen Code:-
char* ptr;
ptr = malloc(50); // allocate space for 50 characters.
strcpy(ptr, "hello world");
Bei der Verwendung von *ptr
vorbei nicht vergessen Speicher freigeben zugeteilt für *ptr
.Dies kann mit erfolgen free()
Funktion.
free(ptr); // deallocating memory.
Größe von dynamisch zugewiesener Speicher kann mit geändert werden realloc()
.
char *tmp = realloc(ptr, 100); // allocate space for 100 characters.
if (! tmp) {
// reallocation failed, ptr not freed
perror("Resize failed");
exit(1);
}
else {
// reallocation succeeded, old ptr freed
ptr = tmp;
}
In den meisten Fällen “Segmentierungsfehler” passiert aufgrund eines Fehlers in Speicherzuweisung oder Array außerhalb der Grenze Fälle.
Um eine änderbare Kopie einer Zeichenfolge zu erstellen, anstatt sie zu verwenden malloc
, strlen
und strcpy
hat die POSIX C-Bibliothek eine praktische Funktion namens strdup
in <string.h>
die eine Kopie der übergebenen nullterminierten Zeichenfolge mit zugewiesener Speicherdauer zurückgibt. Nach Gebrauch sollte der Zeiger mit losgelassen werden free
:
char* ptr;
ptr = strdup("hello world");
ptr[0] = 'H';
puts(ptr);
free(ptr);
Das Problem ist eher, dass OPs nicht einmal wissen, dass der Zeiger nicht initialisiert ist, sondern dass auf magische Weise ein Objekt erscheint, sobald Sie den Zeiger deklarieren/definieren (sie verwirren dies auch).
– zu ehrlich für diese Seite
31. Mai 2016 um 15:21 Uhr
Sie sollten wahrscheinlich den Titel ändern, wenn Sie darauf abzielen, dass diese Frage von Personen gelesen wird, bei denen dieses Problem auftritt Vor sie posten es hier.
– barak manos
31. Mai 2016 um 15:22 Uhr
@Olaf In der Tat, dann stimmen Sie ihre Segmentierungsfragen als Duplikate mit einem Link zu diesem ab. Ich habe eine FAQ-Frage wie diese ewig vermisst; kam endlich dazu, einen aufzuschreiben.
– Ludin
31. Mai 2016 um 15:22 Uhr
@barakmanos Die Absicht ist, diesen Beitrag als “kanonisches Duplikat” für häufig gestellte Fragen zu verwenden. Ich erwarte nicht wirklich, dass Neulinge es selbst finden.
– Ludin
31. Mai 2016 um 15:23 Uhr
@Lundin: Ich schätze deine Bemühungen. Wenn das als dup-CV gemeint ist, bin ich dabei. Aber eigentlich wäre es mir lieber, sie würden es selbst finden, bevor sie posten. Aber das ist wahrscheinlich sowieso Wunschdenken, da Anfänger dazu neigen, zu glauben, dass ihr Problem einzigartig ist. Also, habe +1 und ich werde es mir merken – danke!
– zu ehrlich für diese Seite
31. Mai 2016 um 15:25 Uhr