Warum erhalte ich ein Segmentation fault?



  • Ich bekomme hier beim Zusammenfügen von 2 Char Arrays in einer Funktion einen Segmentation fault.
    Sowohl Variante 1 als auch Variante 2 funktionieren nicht, siehe Quellcode.

    Warum ist das so?

    PS: Ich möchte klassische C Char Arrays verwenden, also keine String Funktionen von C++, da das ganze Progamm bald auf C umgemoddelt werden soll, sobald es mal funktioniert.

    #include <iostream>
    #include <string>
    
    using namespace std;
    
    int mounte(char *pw)
    {
      char command[] = "sudo truecrypt testfile.tc tc --password=\"";
      char command_rest[] = "\" --non-interactive";
    
      cout << pw << endl;
    
      /* Variante 1 
         So war es am Anfang, das wirft sofort einen Segmentation fault
         nach dem 2. strcat Kommando: /*
      /*
      strcat (command, pw);
      strcat (command, command_rest); /* Das letzte Char Array sollte dem ersten
                                         angefuegt werden. */
      */
    
      /* Variante 2
         Da Variante 1 nicht funktionierte, dachte ich, ich bin schlau
         und habe einfach zuerst den command_rest char array dem pw char array
         angefügt um dann erst im zweiten Schritt das pw char array dem
         command char array hinzuzufuegen, aber das geht auch nicht:
         Diesmal bekomme ich aber keinen Segmentation Fault, sondern einen  
         Backtrace.
      */
      strcat (pw, command_rest);
      strcat (command, command_rest);
    
      /* Hier geht es jetzt normal weiter, aber da obiges
         nicht funktioneirt habe ich das mal ausgeklammert. */
      /*
      cout << "Befehl: " << endl << command << endl; 
    
      if (system(command) == true)
      {
        cerr << "Alles ok. " << endl;
      }
      else
      {
        cerr << "Nichts ist ok. " << endl;
      }
      */
      return 0;
    
    }
    
    int main()
    {
      char pw_false [] = "fdklksdlf123456";
      char pw_correct [] = "shjdfghherffdf4234";  
    
      cout << pw_false << endl;
      mounte(pw_false);
    
      return 0;
    }
    


  • Das Problem ist, dass sowohl command als auch command_rest vom Compiler genau so lang gemacht werden, dass die stringliterale inlusive abschließendem '\0' aufgenommen werden können. Mit strcat schreibst du aber in den Speicher dahinter (der dir garnicht gehört). Lösung ist also dir einen Char-Buffer zu erstellen der groß genug ist und in den du dann alles nacheinander rein strcat-est. Längenchecks dabei nicht vergessen.

    http://www.cplusplus.com/reference/clibrary/cstring/strcat.html

    Was mich wundert ist, dass du strcat überhaupt verwenden kannst, obwohl du <cstring> nicht eingebunden hast.

    Im übrigen solltest du gleich mit C anfangen wenn das Programm später in C geschrieben sein soll - das erst als halb-C-Programm unter nem C++ Compiler zum Laufen zu bringen und dann nochmal umzustricken für C halte ich nicht für besonders sinnvoll.

    Zu allerletzt sei noch auf das C-Unterforum verwiesen, wo dir auf solche C-Fragen vermutlich schneller geantwortet wird (und wo du vor "benutz einfach C++ und std::string"-Tips sicher bist).



  • pumuckl schrieb:

    Das Problem ist, dass sowohl command als auch command_rest vom Compiler genau so lang gemacht werden, dass die stringliterale inlusive abschließendem '\0' aufgenommen werden können. Mit strcat schreibst du aber in den Speicher dahinter (der dir garnicht gehört). Lösung ist also dir einen Char-Buffer zu erstellen der groß genug ist und in den du dann alles nacheinander rein strcat-est. Längenchecks dabei nicht vergessen.

    http://www.cplusplus.com/reference/clibrary/cstring/strcat.html

    Vielen Dank.
    Mit dem Char Buffer und Längencheck funktioniert es jetzt.

    Aber jetzt habe ich eine weitere Frage.

    sizeof(pw);
    liefert mir ja jetzt nur die Größe eines Zeigers,
    was auf meinem 32 Bit OS genau 4 Bytes wären.

    D.h. mein String Kommando ist im Prinzip größer als mein derzeitiger
    Char Buffer, da für den Pointers nur 4 Byte gezählt werden, anstatt
    ein paar mehr für den Dateninhalt des Pointers.

    Wie bestimme ich nun die Größe des Dateninhalts auf den ein Pointer zeigt korrekt?
    Ich dachte mir, daß ich die Größe des Strings beim Funktionsaufruf ja mitübergeben könnte.
    Z.b. so

    main{
      ...
      char pwfalse[] = "12345";
      mounte(pw_false, sizeof(pw_false);
      ...
    

    Aber dann muß ich 2 Werte übergeben und brauche auf der Funktionsseite auch
    noch eine Variable die den Wert aufnimmt.

    Wie ist hier eigentlich die professionelle Vorgehensweise?

    Was ich meine, geht das irgendwie eleganter?
    Also kann ich innerhalb der Funktion die Größe des Strings auf den mein Pointer zeigt irgendwie bestimmen?

    Was mich wundert ist, dass du strcat überhaupt verwenden kannst, obwohl du <cstring> nicht eingebunden hast.

    Eventuell liegt es an dem C++
    #include <string>

    Im übrigen solltest du gleich mit C anfangen wenn das Programm später in C geschrieben sein soll - das erst als halb-C-Programm unter nem C++ Compiler zum Laufen zu bringen und dann nochmal umzustricken für C halte ich nicht für besonders sinnvoll.

    Ja, du hast schon recht, nur finde ich daß cout weniger Tipparbeit bedeutet
    als printf bzw. schneller von der Hand geht um mal schnell etwas zu testen
    und mir ja auch noch ein paar weitere C++ Features für temporäre Tests zur Verfügung stehen.
    Deswegen habe ich bisher so einen C/C++ Mischmasch verwendet.
    Aber ich werde das im späteren Verlauf ja noch alles bereinigen.



  • Nunja, der Pointer selbst beinhaltet nur eine Adresse und damit nicht die Information auf wieviel Dateninhalt er zeigen soll. Über den Typ des pointers weiß der compiler aber auf wieviel Speicher er zeigt. Ein char* zeigt eben auf einen char. Diese Information suchst du aber garnicht. Dein char* zeigt nicht nur auf einen char sondern auf ein array aus chars. Davon hat der compiler nun keine Ahnung. Deshalb werden c strings (also char arrays) mit dem Zeichen '\0' abgeschlossen. Um die Länge zu ermitteln läuft man Zeichen für Zeichen ab und sucht nach dieser '\0'. Dafür gibts natürlich bereits eine Funktion, die nennt sich strlen(). Beachte, wenn du deinen buffer anlegst, Platz für die '\0' am Ende einzuplanen!



  • Problem schrieb:

    ......da das ganze Progamm bald auf C umgemoddelt werden soll, sobald es mal funktioniert....

    Nur mal aus Interesse: Warum das?

    Gruß,

    Simon2.



  • Problem schrieb:

    Wie bestimme ich nun die Größe des Dateninhalts auf den ein Pointer zeigt korrekt?

    mit strlen() (wie schon von HyperSonic geschrieben wurde)

    Ich dachte mir, daß ich die Größe des Strings beim Funktionsaufruf ja mitübergeben könnte.

    Bei C-Strings machst du das indirekt durch den terminierenden '\0'-Character. Du kannst die Länge also innerhalb der Funktion bestimmen. Bei normalen Arrays gibts das allerding nicht.

    Was ich meine, geht das irgendwie eleganter?

    Jap. Mit C++ *SCNR*

    Ja, du hast schon recht, nur finde ich daß cout weniger Tipparbeit bedeutet
    als printf bzw. schneller von der Hand geht um mal schnell etwas zu testen
    und mir ja auch noch ein paar weitere C++ Features für temporäre Tests zur Verfügung stehen.
    Deswegen habe ich bisher so einen C/C++ Mischmasch verwendet.
    Aber ich werde das im späteren Verlauf ja noch alles bereinigen.

    Es gibt noch einiges mehr was weniger Tipparbeit, weniger Kopfzerbrechen und mehr Sicherheit bereitet in C++. Z.B. die Stringübergabe, -länge und -verknüpfung. Warum du in C arbeiten willst ist mir ehrlich gesagt schleierhaft.



  • HyperSonic schrieb:

    Dafür gibts natürlich bereits eine Funktion, die nennt sich strlen().

    Das ist super, danke.

    Beachte, wenn du deinen buffer anlegst, Platz für die '\0' am Ende einzuplanen!

    Ja, das ist mir gestern Nacht auch schon aufgefallen, zumal alle Char arrays deren Größe die mit sizeof berechnet werden um genau 1 Byte wegen der Nullterminierung größer sind.



  • Simon2 schrieb:

    Problem schrieb:

    ......da das ganze Progamm bald auf C umgemoddelt werden soll, sobald es mal funktioniert....

    Nur mal aus Interesse: Warum das?

    Gruß,

    Simon2.

    Das hat ganz einfache Gründe, ich muß demnächst ein paar kleine Projekte in C realisieren und wollte daher schonmal sanft anfangen mich etwas in C einzuarbeiten bzw. mal sporadisches Wissen von früher wieder zu erneuern.


Anmelden zum Antworten