Frage

    

Diese Frage bereits eine Antwort hier:

         

Ich versuche, Code zu schreiben, eine Zeichenfolge anstelle zu umkehren (ich bin gerade bei C-Programmierung und Zeigermanipulation, um besser versuchen), aber ich kann nicht herausfinden, warum ich ein Segmentierungsfehler :

#include <string.h>

void reverse(char *s);

int main() {
    char* s = "teststring";
    reverse(s);

    return 0;
}

void reverse(char *s) {
    int i, j;
    char temp;

    for (i=0,j = (strlen(s)-1); i < j; i++, j--) {
        temp = *(s+i);     //line 1
        *(s+i) = *(s+j);   //line 2
        *(s+j) = temp;     //line 3
    }
}

Es sind Linien 2 und 3, die die Segmentierungsfehler verursachen. Ich verstehe, dass es möglicherweise bessere Möglichkeiten, dies zu tun, aber ich bin daran interessiert, herauszufinden, was speziell in meinem Code ist den Segmentierungsfehler verursacht wird.

Aktualisieren :. I die anrufende Funktion enthalten sind, wie gewünscht

War es hilfreich?

Lösung

Es gibt keine Möglichkeit zu sagen, aus genau diesem Code. Höchstwahrscheinlich Sie sind in einem Zeiger vorbei, die die Punkte in dem Speicher, nicht veränderbare Speicher oder eine andere Art von Speicher ungültig einfach nicht so, wie Sie es hier verarbeiten verarbeitet werden.

Wie nennen Sie Ihre Funktion?

hinzugefügt: Sie sind in einem Zeiger auf einen String übergeben wörtlich zu nehmen. Stringliterale sind nicht modifizierbaren. Sie können keine Stringliteral umkehren.

Der Pass in einem Zeiger auf eine veränderbare Zeichenfolge anstelle

char s[] = "teststring";
reverse(s); 

Dies wurde hier bereits zum Tod erklärt. "teststring" ist ein String-Literal. Die Stringliteral selbst ist ein nicht modifizierbares Objekt. In der Praxis Compiler könnte (und wird) setzt es in Nur-Lese-Speicher. Wenn Sie initialisieren einen Zeiger wie das

char *s = "teststring";

der Zeiger direkt am Anfang des Stringliteral. Alle Versuche, zu ändern, was s zeigt auf, gilt als im allgemeinen Fall zum Scheitern verurteilt. Sie können es lesen, aber man kann in ihm nicht schreiben. Aus diesem Grund ist es sehr zu Punkt empfohlen, Stringliterale mit Zeiger auf const Variablen nur

const char *s = "teststring";

Aber wenn erklären Sie s als

char s[] = "teststring";

Sie erhalten eine völlig unabhängige Array s in gewöhnlichen modifizierbaren Speicher befinden, die nur initialisiert mit Stringliteral. Dies bedeutet, dass der unabhängige änderbare Array s seinen Anfangswert erhalten wird kopiert aus dem Stringliteral. Danach Ihre s Array und die Stringliteral weiterhin als vollständig unabhängige Objekte existieren. Die wörtliche ist noch nicht modifizierbare, während s Array veränderbar ist.

Grundsätzlich ist die letztgenannte Erklärung funktionell äquivalent zu

char s[11];
strcpy(s, "teststring");

Andere Tipps

Sie Code könnte für eine Reihe von Gründen, Speicherzugriffsfehler. Hier sind diejenigen, die in den Sinn kommen

  1. s ist NULL
  2. s deutet auf eine konstante Zeichenfolge, die in Nur-Lese-Speicher gehalten wird
  3. s ist nicht NULL beendet

Ich denke, # 2 ist die wahrscheinlichste. Können Sie uns die Aufrufort Reverse zeigen?

Bearbeiten

Auf der Basis Ihrer Probe # 2 ist auf jeden Fall die Antwort. Ein Stringliteral in C / C ++ ist nicht modifizierbar. Die richtige Art ist eigentlich const char* und nicht char*. Was Sie tun müssen, ist eine veränderbare Zeichenfolge in diesen Puffer übergeben.

Schnell Beispiel:

char* pStr = strdup("foobar");
reverse(pStr);
free(pStr);

Testen Sie das so etwas wie das?

int main() {
    char * str = "foobar";
    reverse(str);
    printf("%s\n", str);
}

Das macht str einen Stringliteral und Sie werden wahrscheinlich nicht in der Lage sein, es (segfaults für mich) zu bearbeiten. Wenn Sie char * str = strdup(foobar) definieren sollte es funktionieren (tut für mich).

Ihre Erklärung ist völlig falsch:

char* s = "teststring";

„Teststring“ wird im Codesegment gespeichert, die schreibgeschützt ist, wie Code. Und, s ist ein Zeiger auf „Teststring“, zur gleichen Zeit, Sie versuchen, den Wert eines Nur-Lese-Speicherbereich zu ändern. So Segmentierungsfehler.

Aber mit:

char s[] = "teststring";

s ist mit „Teststring“ initialisiert, was natürlich im Codesegment ist, aber es ist ein zusätzlicher Kopiervorgang weitergeht, auf den Stapel in diesem Fall.

Welche Compiler und Debugger verwenden Sie? Mit gcc und gdb, würde ich den Code mit Option -g kompiliert und dann in gdb laufen. Wenn es Segfaults, würde ich nur einen Backtrace (bt Befehl in GDB) und sehen, welche die Codezeile ist das Problem verursacht. Außerdem würde ich nur den Code Schritt für Schritt ausgeführt werden, während der Zeigerwerte in gdb „beobachten“ und weiß, wo genau das Problem ist.

Viel Glück.

Wie einige der Antworten oben vorgesehen ist, wird der String-Speicher schreibgeschützt. Allerdings bieten einige Compiler eine Option mit beschreibbaren Strings zu kompilieren. Z.B. mit gcc, 3.x-Versionen unterstützt -fwritable-strings aber neuere Versionen nicht.

Siehe Frage 1.32 in der C-FAQ-Liste:

  

Was ist der Unterschied zwischen diesen Initialisierungen?

char a[] = "string literal";
char *p  = "string literal";
     

Mein Programm stürzt ab, wenn ich versuche, einen neuen Wert zuweisen p[i].

     

Antwort:

     

Ein Zeichenfolgenliteral (die formale Bezeichnung für einen Strings in doppelten Anführungszeichen in C-Quelle) kann in zwei leicht unterschiedlichen Arten verwendet werden:

     

Als Initialisierer für eine Reihe von Zeichen, wie in der Erklärung der char a[], es gibt die Anfangswerte der Zeichen in diesem Feld (und, falls erforderlich, seine Größe).

     

Überall sonst, verwandelt es sich in eine unbenannte, statisches Array von Zeichen und diese unbenannte Array in Nur-Lese-Speicher gespeichert werden können, und die deshalb nicht unbedingt geändert werden . In einem Expressionskontext ist das Array auf einmal auf einen Zeiger, wie üblich umgesetzt, so dass die zweite Deklaration initialisiert p verweisen auf die unnamed Array der ersten Element (siehe Abschnitt 6).

     

Einige Compiler haben einen Schalter steuern, ob Stringliterale beschreibbar sind oder nicht (für alten Code kompiliert), und einige können Optionen zur Stringliterale verursachen formal als Arrays von const char behandelt werden (für eine besseren Fehlerfang).

     

( Hervorhebung von mir )

Siehe auch Back to Basics von Joel .

Ich denke, strlen kann nicht funktionieren, da s nicht NULL-termini ist . Also das Verhalten Ihrer für Iteration ist nicht diejenige, die Sie erwarten. Da das Ergebnis der Strlen überlegen sein wird als s Länge werden Sie in den Speicher schreiben, wo man nicht sein sollte.

Zusätzlich s deutet auf eine konstante Strings halten von einem Nur-Lese-Speicher. Sie können es nicht ändern. Versuchen Sie, init s unter Verwendung der Funktion wird, wie es in der Strlen Beispiel

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top