2017-12-01 1 views
-3

Ich arbeite derzeit an dem Erstellen eines kleinen Compilers, der C++ verwendet. Ich habe die folgenden Objekte definiert:Segmentierungsfehler beim Zugriff auf den Speicherort nach dem Zuweisen von Speicher mit malloc()

struct ValueNode 
{ 
    std::string name; 
    int value; 
}; 

struct StatementNode 
{ 
    StatementType type; 

    union 
    { 
     struct AssignmentStatement * assign_stmt; 
     struct PrintStatement * print_stmt; 
     struct IfStatement * if_stmt; 
     struct GotoStatement * goto_stmt; 
    }; 

    struct StatementNode * next; // next statement in the list or NULL 
}; 

Ich habe eine Reihe von Funktionen definiert, die sich auf verschiedene Arten von Anweisungen in der Sprache beziehen. Eine dieser Funktionen heißt parse_assignment_stmt(). Der Segmentierungsfehler, den ich erfahre, tritt in dieser Funktion unmittelbar nach dem Versuch auf, dem kürzlich zugewiesenen Speicher einen Wert zuzuweisen. Hier ist die Funktion:

struct StatementNode* parse_assign_stmt() { 

    //Object to be returned. Holds an object representing a statement 
    //made within the input program. 
    struct StatementNode* st = (struct StatementNode*)malloc(sizeof(struct StatementNode)); 

    st->type = ASSIGN_STMT; 

    //First token should be an ID. Represents memory location we are assigning to. 
    Token tok = lexer->GetToken(); 

    if(tok.token_type == ID) { 

     //Second token in an assignment should be an equal sign 
     Token tok2 = lexer->GetToken(); 

     if (tok2.token_type == EQUAL) { 

      //This function reads the next token, makes sure it is of type NUM or ID, then creates and returns a ValueNode containing the relevant value. 
      struct ValueNode* rhs1 = parse_primary(); 

      Token tok3 = lexer->GetToken(); 

      //Assignment format for this logical branch: "x = 5;" 
      if(tok3.token_type == SEMICOLON) { 
       //first type 

       //Allocate memory for objects needed to build StatementNode st 
       struct AssignmentStatement* assign_stmt = (struct AssignmentStatement*)malloc(sizeof(struct AssignmentStatement)); 

       struct ValueNode* lhs = (struct ValueNode*)malloc(sizeof(struct ValueNode)); 

       printf("Name: %s, Value: %d\n", lhs->name.c_str(), lhs->value); 


       //PROBLEM ARISES HERE*** 
       //lhs->name = tok.lexeme;    

       //return the proper structure 
       return st; 
      } 
      else if(tok3.token_type == PLUS || tok3.token_type == MINUS || tok3.token_type == DIV || tok3.token_type == MULT) { 
       //second type 

       //TODO 
      } 
      else { 
       printf("Syntax error. Semicolon or operator expected after first primary on RHS of assignment."); 
       exit(1); 
      } 
     } 
     else { 
      //not of proper form 
      printf("Syntax error. EQUAL expected after LHS of assignment."); 

      exit(1); 
     } 
    } 
    else { 
     //Not of proper form. Syntax error 
     printf("Syntax error. ID expected at beginning of assignment."); 

     exit(1); 
    } 
} 

Im Wesentlichen bin ich Speicher für einen neuen ValueNode zuweisen, um die Variable lhs zu erstellen. Ich drucke die Felder Name und Wert sofort aus, um sicherzustellen, dass nichts vorhanden ist. In meiner Compiler-Ausgabe (ich verwende übrigens g ++), sagt es mir, dass der Name (null) ist und der Wert 0 ist, was erwartet wird. Sobald ich die Zeile auslasse

lhs->name = tok.lexeme; 

bekomme ich einen Segmentierungsfehler. An diesem Punkt habe ich keine Ahnung, was schief gehen könnte. Ich erstelle die Variable, benutze malloc, um dem Ort Speicher zuzuweisen, stelle sicher, dass dort nichts gespeichert ist, und versuche dann sofort, einen Wert zu schreiben. Und es gibt mir immer einen Segmentierungsfehler.

Hier ist das Eingabeprogramm (.txt-Datei), das dem Programm über stdin zugeführt wird.

i; 
{ 
    i = 42 ; 
    print i; 
} 

ich versucht habe, mit calloc() statt, da das sollte darauf achten, dass der Speicher vor der Rückkehr in den Zeiger gelöscht wird, aber das hat nichts ändern. Irgendwelche Vorschläge wären wunderbar. Vielen Dank!

+5

Verwenden Sie 'malloc()' nicht mit C++ - Code. – user0042

+2

Sie sollten in Erwägung ziehen, Ihre unionierte 'Struktur' durch eine geeignete Vererbungshierarchie zu ersetzen. Dann werden Sie nicht als C + -Programmierer gedacht, diese seltsame Rasse, die nie ganz den Übergang voll von C nach C++ macht :-) – paxdiablo

+0

[Diese Frage] (https://stackoverflow.com/questions/46991224/are- there-any-valid-use-cases-to-use-new-and-delete-raw-pointers-oder-c-style-arr) gibt Ihnen auch einige Hinweise, wie und warum man die manuelle Zuweisung von dynamischem Speicher für die meisten Fälle fallen lassen sollte in C++ vollständig. – user0042

Antwort

0

Wenn das Problem stellt sich in der Zeile:

lhs->name = tok.lexeme; 

dann würde ich garantiert das Problem entweder mit lhs oder tok.lexeme liegt.

Da vor, dass scheinen Sie bestätigt zu haben, dass lhs mit in Ordnung ist:

printf("Name: %s, Value: %d\n", lhs->name.c_str(), lhs->value); 

dann sind die Chancen, dass es ein Problem mit dem Token-Struktur die Höhe schießen.

Allerdings sollten wir nicht vermuten müssen, sollten Sie in der Lage sein, den Code in einen guten Debugger zu laden (oder sogar gdb, in einer Prise (a)), einen Haltepunkt an der fehlerhaften Zeile gesetzt, und tatsächlich Blick auf die Variablen, um zu sehen, ob sie wie erwartet sind. Oder drucken Sie mindestens ein paar Dinge aus, bevor Sie versuchen, es zu benutzen.


Abgesehen: Es ist immer ein Popanz von mir gewesen, dass der ersten Kurs an der Universität gelehrt wird Debuggen 101 nicht, dass die ersten Sache, die ich meinen Sohn lehrte, sobald er Python Entwicklung begann zu tun.


(a) Pax Enten Deckung :-)

+0

Neben^2: hängt von der Universität, denke ich. Das erste, was sie uns nach Malloc und Free zeigten, war Valgrind. Und sie haben uns vorher auch gdb gezeigt, aber das ist für die meisten Leute zu gruselig – Ordoshsen

+0

Hi Pax. Ich wünsche mir auch, dass das Debugging in meinem Programm ein eingehenderes Thema ist. Ich schätze den Vorschlag, einen Haltepunkt zu verwenden. Gibt es bestimmte Ressourcen, die Sie mir empfohlen haben, um das Debuggen besser zu verstehen? –

+0

Hey, Pax, ich habe das Programm über gdb ausgeführt und einige neue Informationen gefunden! Ich habe einen Breakpoint direkt vor dieser Zeile hinzugefügt: lhs-> name = tok.lexeme; Zu diesem Zeitpunkt scheinen die zwei störenden Strukturen rhs1 und lhs zu sein. Wenn "p * rhs1" in gdb ausgeführt wird, erhalte ich: {Name = , Wert = 42} Ich bekomme etwas fast identisch für "p * lhs", mit Auf eine andere Speicheradresse kann nicht zugegriffen werden, und der Wert ist 0. Beide Werte sind wie erwartet, aber aus irgendeinem Grund ist der Speicher für beide Namen nicht lesbar. Irgendwelche Ideen? –

0

Nach einer weiteren Untersuchung fand ich, dass, wenn das Zuweisen von Speicher (malloc()) für meine ValueNode Objekte (und aus irgendeinem Grund nur, diese), malloc() gab einen Zeiger auf unzugänglichen Speicher zurück. Der Fehler, den ich in GDB erhalten, wenn ich meine ValueNode Struktur drucken war:

{name = < ‚Fehler beim Lesen der Variable: Speicher kann nicht an der Adresse 0xfffffffe8 zugreifen>, Wert = 42}

Leider war ich nicht in der Lage einen Weg finden, den Speicher für dieses Objekt mit malloc() zu belegen. Eine Problemumgehung, die ich zustande gebracht habe, bestand jedoch darin, einen Konstruktor in der Strukturdefinition von ValueNode zu erstellen, dann "new" zu verwenden, um das Objekt zu erstellen und den Speicher zuzuweisen, anstatt zu versuchen, malloc() zu zwingen. Im Rückblick hätte ich diesen einfacheren Ansatz wahrscheinlich zuerst über malloc() verwenden sollen.

+0

Wenn du aus irgendeinem Grund malloc mit C++ verwenden musst, google "placement new", mit dem du Objekte auf bereits zugewiesenem Speicher erstellen kannst. – hyde

Verwandte Themen