2016-04-07 4 views
0

Ich arbeite daran, ein C-Programm zu machen, das grundsätzlich einen Satz aufnehmen kann und zählt, wie oft jedes Wort darin erscheint. Ich habe eine abgespeckte Version erstellt, die das Problem genau reproduziert.Warum ist dieses C-Programm an diesem Standort segzufällig?

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

typedef struct testStrut{ 
    char * string; 
    int uses; 
}word; 

void grow(); 

int main(){ 
    int i; 
    int count = 1; 
    word ** words; 

    words = (word **) malloc(count * sizeof(word *)); 
    words[0] = (word *) malloc(sizeof(word)); 

    for(i = 0; i < 10; i++){ 
     printf("Re-looping i: %d \n", i); 
     printf("words[0]->string = %s \n", words[0]->string); 
     grow("TEST", words, &count); 
    } 

    printf("Done."); 
    return 0; 
} 

void grow(char * str, word ** words, int * count){ 
    word ** tmp; 

    tmp = realloc(words, (*count) * sizeof(word *)); 

    if(tmp){ 
     tmp[(*count)-1] = malloc(sizeof(word)); 
     tmp[(*count)-1]->string = malloc(strlen(str)+1); /*+1 for null terminator as pointed out */ 
     strcpy(tmp[(*count)-1]->string, str); 
     tmp[(*count)-1]->uses = 1;  
     words = tmp; 
     (*count)++; 
    } else{ 
     printf("Failure to allocate. \n"); 
     exit(0); 
    } 
    printf("Count: %d and word[0] %s \n", (*count), str); 
} 

Neben der Ausgabe von einem Lauf:

Re-looping i: 0 
words[0]->string = (null) 
Count: 2 and word[0] TEST 
Re-looping i: 1 
words[0]->string = TEST 
Count: 3 and word[0] TEST 
Re-looping i: 2 
words[0]->string = TEST 
Count: 4 and word[0] TEST 
Re-looping i: 3 
words[0]->string = TEST 
Count: 5 and word[0] TEST   /*Prints it fine? */ 
Re-looping i: 4 
Segmentation fault (core dumped)  /*Suddenly unable to print it? */ 

ich verstehen mich nicht, warum die wachsen Funktion zwischen endet und durch die Schleife um den Wert der Worte wieder gehen [0] -> str ist plötzlich verloren. Gibt es etwas, das mir fehlt?

[Ich weiß, dass ich etwas zu befreien sollte ich malloc.I auch meine Methode Prototyp realisieren nicht die richtige ist, aber ich wollte nur ein schnelles Programm machen, dass mein Problem demonstriert]

+4

Hinweis: Was bedeutet ' void f (int i) {i = 7;} int main() {int x = 5; f (x); printf ("% d \ n", x); Rückgabe 0;} 'Drucken? Nun 'int ändern I' zu' Wort ** words' und 'int x' zu' Wort ** words' und '7' zu' realloc (...) ' – immibis

+1

Ein weiterer Fehler ist, dass Sie eine gemacht haben Falsche "String" -Zuweisung, Länge eines Strings ist "strlen (str) + 1", um das NUL-Beendigungszeichen zu berücksichtigen. –

+0

Ihr Beispiel druckt 5, da ich von Wert übergeben wird, nicht ist, wenn ich Wort passieren ** Worte es ein Zeiger so würden alle Änderungen auch in Haupt widerspiegeln? Danke Jean für das fangen! Mein schlechtes, ich habe bearbeitet, um diese Änderung widerzuspiegeln. – Nateb1121

Antwort

0

Das Problem ist hier:

words = tmp; 

Diese Anweisung hat keine Auswirkungen außerhalb der Funktion.

Da realloc kann (oder auch nicht) einen neuen Zeiger zu einem anderen Speicherplatz zurückkehren, Sie Code können vor dem Absturz ein paar Mal arbeiten.

sollten Sie ein Wort verwenden *** anstelle des Wortes ** Parameter oder einfach den neuen Zeiger zurück:

word** grow(char * str, word ** words, int * count){ 
    word ** tmp; 

    tmp = realloc(words, (*count) * sizeof(word *)); 

    if(tmp){ 
     tmp[(*count)-1] = malloc(sizeof(word)); 
     tmp[(*count)-1]->string = malloc(strlen(str)+1); /*+1 for null terminator as pointed out */ 
     strcpy(tmp[(*count)-1]->string, str); 
     tmp[(*count)-1]->uses = 1; 
     (*count)++; 
    } else{ 
     printf("Failure to allocate. \n"); 
     exit(0); 
    } 
    printf("Count: %d and word[0] %s \n", (*count), str); 
    return tmp; 
} 

Und nennen Sie es so:

words = grow("TEST", words, &count); 
+0

Was wäre der richtige Weg, um sicherzustellen, dass der Wert des Wortes überschrieben wird, um die Adresse von tmp zu sein? Es scheint, ich bin falsch in meiner Annahme, dass Wort ** Worte als Zeiger übergeben wird und dass alle Änderungen daran außerhalb der Funktion reflektiert werden ... – Nateb1121

+0

@ Nateb1121 Sie können einfach den neuen Zeiger als Wert zurückgeben, anstatt zu versuchen Aktualisieren Sie einen Funktionsparameter. Andernfalls wäre ein Zeiger auf das Wort ** (d. H. Wort ***) notwendig. – zakinster

+0

Oh, Duh! Entschuldigung für meine Fragefrage, aber wenn ich verstehe, weil Wort ** words ein Zeiger ist, kann ich den Inhalt dieses Zeigers ändern und ihn außerhalb der grow() -Funktion widerspiegeln, jedoch kann ich den tatsächlichen Ort wo Worte nicht ändern Punkte und erwarten, dass es außerhalb des Wachstums() einen Effekt hat? – Nateb1121

2

Auf der ersten Iteration der for-Schleife Die folgende Zeile greift auf nicht initialisierten Speicher zu.

printf("words[0]->string = %s \n", words[0]->string); 

Sie haben auch

erklärt
void grow(); 

aber die tatsächliche Unterschrift dh

void grow(char * str, word ** words, int * count) 

Als erstes müssen Sie grow vor dieser Linie dh nennen. Sie sind auch realloc und davon ausgegangen, dass der Zeiger words in den Hauptpunkten auf den ursprünglichen Zeiger zeigt.

Versuchen Sie dies. Ich habe ein wenig ...

vereinfacht
#include <assert.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
typedef struct testStrut{ 
    char * string; 
    int uses; 
} word; 

void grow(const char *str, word *words, int count); 

int main(){ 
    int i; 
    word * words; 
    printf("sizeof word == %zu\n", sizeof(word)); 
    assert(sizeof(word) == 16); 
    words = malloc(sizeof(word)); 
    for(i = 0; i < 10; i++){ 
    printf("Re-looping i: %d \n", i); 
    grow("TEST", words, i); 
    printf("words[0]->string = %s \n", words[0].string); 
    } 
    printf("Done."); 
    return 0; 
} 
void grow(const char * str, word *words, int count){ 
    word ** tmp; 
    int idx = count - 1; 
    printf("size == %zu\n", count * sizeof(word)); 
    tmp = realloc(words, count * sizeof(word)); 
    size_t str_len = strlen(str); 
    if(tmp != NULL) { 
    tmp[idx]   = malloc(sizeof(word*)); 
    tmp[idx]->string = malloc(str_len + 1); 
    strcpy(tmp[idx]->string, str); 
    tmp[idx]->string[4] = '\0'; 
    tmp[idx]->uses = 1; 
    } else{ 
    printf("Failure to allocate. \n"); 
    exit(0); 
    } 
    printf("Count: %d and word[0] %s \n", count, str); 
} 
+0

Ich realisiere, dass jetzt in meiner Eile, dies zu machen, das das Problem verursachen würde Ich habe erlebt? Ich verstehe, dass ich jetzt die richtige Methode Prototyp verwende, dies ist nur ein schnelles schmutziges Beispiel, um das Problem zu demonstrieren. – Nateb1121

+0

count wird jedes Mal erhöht, wenn die grow-Methode von der (* count) ++ - Zeile ausgeführt wird. – Nateb1121

+0

'void grow();' ist erlaubt, es bedeutet nur, dass der Compiler die Argumenttypen nicht für Sie validiert. Glücklicherweise hat OP die richtigen Typen im Anruf verwendet. Natürlich ist es eine gute Idee, den Prototyp zu verwenden, damit der Compiler Ihnen hilft. –