Es ist eine einfache, aber wichtige Frage. Was sind die Do's und Donts bei der Verwendung eines Zeigers in C und C ++, um sicherzustellen, dass SEGMENTATION FAULT auf AIX vermieden wird?
Wo char * wird vor Zeichenarray bevorzugt?
std::auto_ptr
, boost::scoped_ptr
, boost::shared_ptr
und die entsprechenden Array-Container. Noch einfacher, oft funktioniert std::vector
einwandfrei und erfordert keinerlei Zeigerverwendung. Schließlich können Sie, anstatt Zeiger auf große oder veränderbare Datenstrukturen zu übergeben, Referenzen übergeben. Zeiger können Arrays darstellen, während Referenzen diese Mehrdeutigkeit vermeiden. delete[]
ist für Arrays reserviert, die nur über new ...[]
, delete
nur für Zeiger auf einzelne Objekte und free(...)
nur für über C api zugewiesenen Speicher (z als malloc(..)
). Diese dürfen nicht verwechselt werden; C ++ - Deallokationsroutinen enthalten Destruktoraufrufe und müssen daher korrekt aufgerufen werden. NULL
explizit. Es ist einfacher, eine zufällige Null-Dereferenzierung zu debuggen als einen inkorrekten Speicherzugriff. Es ist in Ordnung, den NULL
-Zeiger aufzuheben, sodass Sie Ihren Destruktor nicht mit Überprüfungen überdecken müssen, um dies zu vermeiden. Wenn Sie delete
vorzeitig auf ein Objekt setzen, sollten Sie den Zeiger auf NULL
setzen, um zu vermeiden, dass derselbe Zeiger doppelt gelöscht wird und damit nicht versehentlich ein Dangling-Zeiger dereferenziert wird. delete
der Zeiger darauf ist. boost::shared_ptr
ist ein problemloser, relativ niedriger Overhead-Container, der oft in Ordnung ist, wenn Sie einen Zeiger teilen müssen. Und zu guter Letzt
Verwenden Sie niemals Zeiger, es sei denn, Sie müssen ... Es gibt (const) Verweise, um die Konstruktion von Objekten zu vermeiden, die an Funktionen und STL-Container und Zeichenfolgen für die anderen Speicheranforderungen übergeben werden :: shared_ptr) Zeiger, wenn Sie wirklich Zeiger brauchen und diese nicht von Hand verfolgen wollen.
In C
void*
. char*
ist nicht dasselbe wie double**
. Schreiben Sie standardkonformen Code. Das sollte sich um die Plattform kümmern. Und viele andere Probleme. Und verwende const
. Das sorgt für mehr Probleme.
Verwenden Sie in C ++ immer virtuelle Destruktoren. Wenn Sie die Basisklasse löschen, wird sichergestellt, dass der destuctor der abgeleiteten Klasse aufgerufen wird. Wenn Sie dies nicht tun und die abgeleitete Klasse einige Zuweisungen vorgenommen hat, haben Sie keine Chance, sie zu bereinigen.
HINWEIS: C spezifische Antwort- & gt;
Im Folgenden sind die häufigsten Ursachen für diese Segmentierungsverletzung oder Segmentierungsfehler aufgeführt:
Falsche Formatkontrollzeichenfolge in printf- oder scanf-Anweisungen: Stellen Sie sicher, dass die Formatsteuerungszeichenfolge die gleiche Anzahl von Konvertierungsspezifizierern (% 's) aufweist, wie printf oder scanf Argumente zum Drucken oder Lesen haben und dass die Spezifizierer dem Typ der zu druckenden oder zu lesenden Variablen entsprechen. Dies gilt auch für fprintf und fscanf.
Vergessen, "& amp;" zu verwenden zu den Argumenten für scanf: Die Funktion scanf nimmt als Argumente den Format-Kontrollstring und die Adressen der Variablen, in die er die eingelesenen Daten einfügt. Das "& amp;" Der (Adresse des) Operators wird verwendet, um die Adresse einer Variablen zu liefern. Es ist üblich zu vergessen, "& amp;" mit jeder Variable in einem Scanf-Aufruf. Das "& amp;" kann eine Segmentierungsverletzung verursachen.
Zugriff über die Grenzen eines Arrays hinaus: Stellen Sie sicher, dass Sie die Grenzen eines von Ihnen verwendeten Arrays nicht verletzt haben. h., Sie haben das Array nicht mit einem Wert subskribiert, der kleiner als der Index des niedrigsten Elements oder größer als der Index des höchsten Elements ist.
Fehler beim Initialisieren eines Zeigers vor dem Zugriff: Eine Zeigervariable muss einer gültigen Adresse zugewiesen werden (d. H. Auf der linken Seite einer Zuweisung erscheinen), bevor auf sie zugegriffen wird (d. H. Auf der rechten Seite einer Zuweisung erscheint). Stellen Sie sicher, dass Sie alle Zeiger initialisiert haben, um auf einen gültigen Speicherbereich zu zeigen. Die korrekte Zeigerinitialisierung kann auf verschiedene Arten erfolgen. Beispiele sind unten aufgeführt.
Falsche Verwendung des "& amp;" (Adresse von) und "" (Dereferenzierung) Operatoren: Stellen Sie sicher, dass Sie verstehen, wie diese Operatoren funktionieren. Wissen Sie, wann sie angewendet werden sollten und wann Sie sie nicht anwenden sollten. Wie oben erwähnt, ist es üblich zu vergessen, "& amp;" mit jeder Variable in einem Scanf-Aufruf. Denken Sie daran, scanf benötigt die Adresse der Variablen, die es einliest. Insbesondere wissen, wann "& amp;" und "" sind absolut notwendig und wenn es besser ist, sie zu vermeiden.
Fehlerbehebung für das Problem:
Überprüfen Sie JEDEN Platz in Ihrem Programm, der Zeiger verwendet, ein Array tiefstellt oder den Adressoperator (& amp;) und den Dereferenzierungsoperator (*) verwendet. Jeder ist ein Kandidat für die Ursache einer Segmentierungsverletzung. Stellen Sie sicher, dass Sie die Verwendung von Zeigern und der zugehörigen Operatoren verstehen. Wenn das Programm viele Zeiger verwendet und viele Vorkommen von & amp; und *, fügen Sie einige printf-Anweisungen hinzu, um den Ort anzugeben, an dem das Programm den Fehler verursacht, und untersuchen Sie die Zeiger und Variablen, die an dieser Anweisung beteiligt sind.
Denken Sie daran, dass printf-Anweisungen zu Debugging-Zwecken am Ende ihrer Formatsteuerungszeichenfolgen ein Zeilenvorschubzeichen (\ n) haben müssen, um das Löschen des Druckpuffers zu erzwingen.
Ich habe vor einiger Zeit an einem Projekt teilgenommen, bei dem ein paar gute Entwickler nur nackte Zeiger benutzten. Obwohl sie über ausgezeichnete Fähigkeiten verfügen, verursachte ihr Programm (unter Windows / Linux / HP-UX) von Zeit zu Zeit Segfaults und es gab einige Speicherlecks.
Ich verstehe, dass, wenn ein Programm ziemlich groß ist und Threads hat, es sehr schwierig ist, alle Fehler zu finden, die mit Zeigern zusammenhängen, und wenn Sie unbedingt einen blossen Zeiger brauchen, sollten Sie Boost.Smart_ptr .
Die Eigentumsfrage ist oft die schwierigste: Ihr Design sollte bereits darüber entscheiden. Dasjenige , das das Objekt besitzt, sollte dafür verantwortlich sein, es zu zerstören.
Aber ich habe Szenarios gesehen, in denen auch auf zerstörte Objekte Bezug genommen wurde - auch als "dangling pointers". Ihr Design sollte auch die "Gültigkeit" berücksichtigen. Jede Bezugnahme auf ein gelöschtes Objekt sollte deutlich ungültig sein. Wenn ich mich nicht irre, kann die weak_ptr
-Klasse diese Entscheidung verschieben.
Nicht wirklich eine Antwort auf das "Wo Char * gegenüber Character-Array bevorzugt werden?" Frage, aber eine Sache, die vor kurzem jemanden gebissen, den ich überprüfte, war "sizeof".
Bedenken Sie Folgendes:
%Vor%An vielen Stellen verwenden Sie "a" und "b" auf ähnliche Weise. Die Probleme beginnen, wenn Sie etwas tun wie:
%Vor%Ich denke, die Moral der Geschichte ist: Sei vorsichtig mit sizeof (). Es ist wahrscheinlich besser, eine Größe konstant zu halten.