2012-04-06 6 views
1

Ich versuche, ein Programm ähnlich 20 Fragen zu implementieren, in denen eine Textdatei der Fragen und Vermutungen für Antworten geladen werden, in ein Char-Array kopiert (wo die neue Leerzeichen werden durch '/ 0' ersetzt, um die Fragen in einzelne Strings aufzuteilen. Das Array funktioniert einwandfrei, nachdem die Textdatei darin kopiert wurde. Eine Baumstruktur wird eingerichtet, um die Phrasen in den Ja/Nein-Fragenbaum zu organisieren, wobei das linke Kind die Ja-Antwort ist, während das Rechte die Nicht-Antwort ist und Blätter sind die Vermutungen, die das Programm verwendet, um das Ende zu erraten.C Char-Array wird nach der Übergabe in Funktion beschädigt

Das Problem, das ich habe, ist, dass nach dem Erstellen der Struktur (Aufruf von Tree Builder von InitTree) der Inhalt des Arrays, wo die Sätze aus der Textdatei kopiert wurden, wurde beschädigt.

Bevor ich InitTree nennen, sehen die Array-Inhalt wie folgt aus:

Ist es pelzigen? Miaut es? eine Katze ein Hund Hat es Stoßzähne? Hat es große Ohren? ein Elefant ein Nashorn einen Alligator

Nachdem er ruft, sieht es wie folgt aus:

Ist es pelzigen? - ??? `? p? ein Hund Hat es Stoßzähne? Hat es große Ohren? ein Elefant ein Nashorn ein Alligator

Ich habe die Prüfung worden, wo es nicht mehr funktioniert, und innerhalb TreeBuilder, alle Elemente des Arrays sind intakt, aber sobald der Funktionsaufruf an TreeBuilder zu Ende, das Array wird beschädigt. Ich habe versucht, den Speicher zu schützen, indem ich bei jeder Zuweisung von Speicher Calloc verwendete und sogar das Zeichenfeld statisch machte, was in einer ähnlichen Situation funktionierte, in der dies geschah. Aber alle meine vorbeugenden Maßnahmen scheinen nicht zu funktionieren und ich bin mir nicht sicher, wo das Problem liegt. Ich habe schon versucht, ähnliche Fälle hier auf Stackoverflow zu betrachten, aber ich konnte nichts mit meinem Problem in Verbindung bringen.

Dies führt schließlich zu einem seg-Fehler, wenn das Programm tatsächlich beginnt, den Baum aus offensichtlichen Gründen zu verwenden.

Ich habe versucht, gdb zu laufen, aber aus irgendeinem Grund wird es mich nicht Zeile für Zeile gehen lassen, weil es die Zeileninformationen nicht finden kann, und alles überspringt, bis es entweder zur Eingabe auffordert oder einen Speicher abruft Fehler oder etwas, so running gdb ist hier nicht sehr hilfreich. Ich vermute, das könnte daran liegen, dass die Hauptfunktion in einer enthaltenen Datei oder etwas enthalten ist. Aber das ist nebensächlich.

Hier ist der Code mit dem Problem:

struct treeStruct { 
    char *string; 
    struct treeStruct *left, *right; 
}; 

typedef struct treeStruct *TreeType; 

// Builds a tree 
void treeBuilder(TreeType tree, char **phrase, long level){ 
    // Gets the level (number of tabs) of the next phrase 
    long nextLevel = countTabs(*phrase + strlen(*phrase) + 1); 

    tree->string = *phrase + level; // Assigns the response pointer to the tree array 

    // Move the pointer to the next string, since the the strings need to be 
    // put into the tree in linear order 
    (*phrase) += strlen(*phrase) + 1; 

    if (level >= nextLevel){ 
    // Compares the current level with the level of the next string 
      // to determine if returning up the tree is necessary; 
      // This should be the answer to a question. 
      tree->left = NULL; 
      tree->right = NULL; 
      return; 
    } 
    else{ 
      // Makes sure the left and right pointers of the struct have 
      // allocated space 
      tree->left = calloc(1, sizeof(TreeType)); 
      tree->right = calloc(1, sizeof(TreeType)); 

      // Adds the yes and no branches to the tree, recursion will take care 
      // of adding sub-branches 
      treeBuilder(tree->left, phrase, level + 1); 
      treeBuilder(tree->right, phrase, level + 1); 
    } 

    return; 

} 


TreeType InitTree (char *file){ 
    if(file == NULL){ 
      printf("File '%s' does not exist.\n", file); 
      exit(2); 
    } 

    FILE *fp; 
    fp = fopen(file, "r"); 

    // Create a space in memory for the loaded questions to occupy 
    static char *phrases; 
    phrases = (char *)malloc(MAXSTR * MAXNUMQS * sizeof(char)); 

    copyText(fp, phrases); 

    fclose(fp); 

    // Create space in memory for the tree structure 
    TreeType tree; 
    tree = (TreeType) calloc(1, sizeof(TreeType)); 

    // Create a pointer to a pointer so that treeBuilder can 
    // change what the first pointer is pointing to, so the strings in 
    // phrases can be added in order throughout the recursion 
    static char *phrase_ptr, **phrase_ptr2; 
    phrase_ptr = &phrases[0]; 
    phrase_ptr2 = &phrase_ptr; 

    //Build the tree 
    treeBuilder(tree, phrase_ptr2, 0); 

    topNode = tree; 

    return tree; 
} 

Sorry, wenn dies tl ist; dr, aber ich wollte so klar wie möglich auf mein Thema.

+1

Es wäre großartig, wenn Sie ein so genanntes http://sscce.org Beispiel bereitstellen könnten. Der minimale, aber kompilierbare Code, der Ihr Problem noch reproduzieren kann. Dies könnte Ihnen auch helfen, den Fehler selbst zu finden. – ArjunShankar

+0

z.B. Hier öffnen Sie eine Datei und lesen sie mit einer Funktion, die wir nicht einmal sehen können. Stattdessen "strcpy" eine String-Konstante in "Phrasen". – ArjunShankar

+0

Wenn du rekursiv bist, willst du wirklich "level + 1"? oder das 'nextLevel', das du vorher berechnet hast? – jpm

Antwort

3

Nur eine Sache, die ich bemerkte, ist, dass Sie sizeof(TreeType) verwenden, aber TreeType ist ein Zeiger auf eine Struktur und nicht die Struktur selbst. Dies bedeutet, dass Sie einen Zeiger erstellen, der nach nirgendwo zeigt, und dass das Dereferenzieren des Zeigers zu undefiniertem Verhalten führt. Wer gerade den Rest der Frage gelesen hat, würde sicherlich die Segfaults erklären.

Ich denke, Sie wären besser dran, Ihre Struktur nicht als Zeiger zu definieren, und expliziter mit Ihrer Verwendung von Zeigern.

z.

typedef struct treeStruct TreeType; 

void treeBuilder(TreeType *tree, char **phrase, long level){ 
    ... 
    if (!tree->left) { 
     // calloc returns a pointer to a new bit of memory that has been 
     // assigned on the heap 
     TreeType *temp = calloc(1, sizeof(TreeType)); 
     // assignments below not explicitly needed as you're using calloc 
     temp->string = NULL; 
     temp->left = NULL; 
     temp->right = NULL; 

     tree->left = temp; 
    } 
    ... 
} 

Hier ist ein question über typedef-ing Zeigern. Scheint relativ üblich in C zu sein und impliziert, dass der Datentyp undurchsichtig ist und nicht vom Benutzer dereferenziert werden sollte (nur durch die API-Aufrufe, an die der Benutzer ihn weiterleitet).

+0

Normalerweise würde ich das tun, aber die Aufgabe, die ich mache, erfordert, dass TreeType ein Zeiger ist. – jtcramer

+0

+1, guter Fang. – codaddict

+0

@jtcramer: Vielleicht ist der Zweck der Aufgabe, Ihnen beizubringen, Zeiger hinter Typedefs nicht zu verstecken? – wildplasser

Verwandte Themen