2017-10-19 6 views
0

Ich versuche, einen einfachen String-Parser für Benutzereingaben neu zu erstellen. Ich kann die Eingabe String ohne Problem erhalten und bestimmen, wie viele einzelne Strings darin sind, um malloc die richtige Größe zu geben. Anfangs fand ich nicht die Anzahl der Strings in stdin und würde einfach mein String-Array neu zuweisen, um Platz für einen weiteren String zu lassen und dann den neuen String malloc. Jetzt, da ich die Größe habe, glaube ich, dass dies nicht notwendig ist, da ich nur Malloc mit der richtigen Größe bereitstellen kann.Realloc Auswirkungen auf Fgets

(Versuchte mit calloc(), an der gleichen Stelle segfaulted)

Was ich bin verwirrt mit, ist, wenn ich realloc in meinem Code lasse kein Problem (abgesehen von zu wissen, ist es wahrscheinlich, meine Array anpassen in eine unerwünschte Mode). Aber, wenn ich realloc entferne, segmentiert mein Code die sofortige Ausführung von fgets().

Dies ist nur, wo ich den Parser nennen, und meine # enthält. "Appserver.h" hält alle Prototypen und std (lib/Bool/io), string/unistd/limits.h

#include "appserver.h" 

int main(int argc, char *argv[]) 
{ 
    if(argc != 4) 
    { 
    exit(0); 
    } 
    struct userInput user = { parseInt(*argv[1]), parseInt(*argv[2]), argv[3] }; 

    printf("> "); 
    char **newArgs = stringParser(); 
    for (int i = 0; newArgs[i] != NULL; i++) 
    { 
    free(newArgs[i]); 
    } 
    free(newArgs); 
} 

Unten ist mein Code für den Parser. Wenn ich das realloc unkommentiert belasse, kann ich ohne Probleme durch meinen Code gehen (das Durchlaufen von gdb zeigt "input" mit der ganzen Zeichenkette von stdin), aber wenn ich es auszeichne, segle ich richtig, wenn ich versuche, Benutzereingaben in fgets abzurufen (). Warum wirkt sich das Auskommentieren von realloc() sogar auf fgets() aus?

char **stringParser() 
{ 
    char *input; 
    fgets(input, INT_MAX, stdin); 
    int size = numberOfStrings(input); 
    char **inputArray = malloc((size)*(sizeof(char*))); 
    inputArray[0] = malloc(sizeof(char*)); 
    strcpy(inputArray[0], strtok(input, " ")); 
    for(int i = 1; i < size /*inputArray[i-1] != NULL*/; i++) 
    { 
    // inputArray = realloc(inputArray, (i+1)*sizeof(char*)); 
    inputArray[i] = malloc(sizeof(char*)); 
    strcpy(inputArray[i], strtok(NULL, " ")); 
    printf("Inside inputArray[%d]: %s\n", i-1, inputArray[i-1]); 
    } 
    return inputArray; 
} 

Hier ist der Code für meine numberOfStrings() -Methode als auch in dem Fall, dies in wert sein könnte suchen, aber ich auch durch sie mit GDB getreten und es scheint ziemlich konkret.

int numberOfStrings(char *input) 
{ 
    int count = 0; 
    char *tempCopy = malloc(sizeof(char*)); 
    strcpy(tempCopy, input); 
    char* token = strtok(tempCopy, " "); 
    while(token != NULL) 
    { 
    token = strtok(NULL, " "); 
    count++; 
    } 
    free(tempCopy); 
    return count; 
} 


EDIT: Ich wollte ich habe vermieden die meisten Bereiche potenziellen undefinierten Verhalten, um sicherzustellen, followup. Ich habe nichts in Haupt-ändern, so hier sind meine Änderungen in **stringParser()

char **stringParser() 
{ 
    char *input = nextLine(stdin); 
    int size = numberOfStrings(input, strlen(input)); 
    char **inputArray = calloc(size, sizeof(*inputArray)); 
    char *token = strtok(input, " "); 
    inputArray[0] = malloc(strlen(token)); 
    strcpy(inputArray[0], token); 
    for(int i = 1; i < size - 1; i++) 
    { 
    token = strtok(NULL, " "); 
    inputArray[i] = malloc(strlen(token)); 
    strcpy(inputArray[i], token); 
    } 
    free(input); 
    inputArray[size-1] = (char*)NULL; 
    return inputArray; 
} 

Die Hauptbereiche des Wandels sind:

  • Ich benutze calloc() statt malloc(), obwohl, wenn mein Verständnis korrekt ist dann calloc(size, sizeof(*inputArray)) verhält sich das gleiche (Ignorieren der '0' oder Müll Wert Initialisierung) als malloc((size)*sizeof(*inputArray))
  • Ein Freund von mir schrieb eine *nextLine(FILE *input), die mir erlaubt, Zeichen für Zeichen durchzu scannenbis ich entweder EOF oder '\n' erreiche. Dies hat den Vorteil, genau die Menge an Speicher zuzuweisen, die ich für die Benutzereingabe benötige.
  • Ich stelle sicher, dass jeder String in meinem Array nur die notwendige Menge an Speicher zugewiesen wird. (Im Gegensatz zu sizeof(char*) wie ich zuvor getan hatte)
  • Ich habe sichergestellt, einen Null-Abschluss-Wert am Ende meiner String-Array enthalten. (I eine Änderung in numberOfStrings gemacht(), wo habe ich nur noch count++ vor der return-Anweisung.

Diese Veränderungen haben brachte mir nur zu einem Punkt, wo ich nicht mehr Speicherverluste. Ich darf nicht davon ausgehen, ich habe Ich glaube, ich mache jetzt ein bisschen besser, aber ich werde diesen Beitrag nicht mit ein paar anderen Fragen verstopfen, sondern dieses Update hier lassen, falls jemand das möchte finde es nützlich oder relevant.

+1

Bitte erläutern Sie die Zeile 'char * tempCopy = malloc (sizeof (char *));' –

+2

'fgets (Eingabe, INT_MAX, stdin);': 'Eingabe' ist nicht initialisiert. – BLUEPIXY

+0

@ M.M Ich mag es einfach nicht, rohe Ganzzahlwerte zu setzen, und habe noch keine Möglichkeit implementiert, die genaue Länge des Strings noch zuzuweisen. Oder wenn es einen einfachen eingebauten Weg dafür gibt, habe ich es noch nicht entdeckt. Aus Unwissenheit habe ich gerade Größe (char *) benutzt, da es mir noch keine Probleme bereitet hat. – Drewzillawood

Antwort

1

Der Anruf von realloc() betrifft nicht fgets() - zumindest nicht direkt, vorhersagbar oder zuverlässig. Der erste Aufruf von fgets(input, INT_MAX, stdin) in hat ein undefiniertes Verhalten, weil der Zeiger input nicht initialisiert ist.

Praktisch der Aufruf von fgets() wahrscheinlich einig Bereich des Speichers überschrieben wird, dass es nicht sollte.

Durch Hinzufügen (oder Auskommentieren) des Aufrufs von realloc() wird das Ergebnis eine Anpassung des Layouts des von Ihrem Programm verwendeten Speichers sein (z. B. Ändern, ob Code oder Daten an den Speicherorten überschrieben werden) fgets()).

Aber das ist nicht, weil realloc() direkt fgets() beeinflusst. Es ist einfach ein Nebeneffekt der Tatsache, dass der Aufruf von realloc() etwas in Ihrem Programm ändert.

Die Wirkung der Kommentierung aus dem realloc() Anruf oder wieder aufstecken könnte alles sein. Sie können beispielsweise unterschiedliche Effekte erzielen, wenn Ihr Code mit anderen Compilereinstellungen (wie Optimierungsflags) oder sogar einem anderen Compiler erstellt wird.

Um das Problem mit fgets() Pass es ein Array

char input[some_positive_value]; 
    fgets(input, sizeof(input), stdin); 

oder initialisiert den Zeiger zu beseitigen an einem geeigneten Puffer zu zeigen.

char *input = malloc(some_positive_value); /* remember to `free()` when done */ 
    fgets(input, some_positive_value, stdin); 

anzumerken, dass die Schleife, wie beschrieben, braucht sich die realloc() Anruf

// inputArray = realloc(inputArray, (i+1)*sizeof(char*)); 
inputArray[i] = malloc(sizeof(char*)); 

ohne realloc() Anrufs, die Zuordnung zu inputArray[i] auch undefiniertes Verhalten haben. Wenn Sie keine Symptome davon gesehen haben, haben Sie einfach Glück gehabt - wieder ist es ein Affekt, auf den Sie sich nicht verlassen können.

Es wäre auch eine gute Idee zu überprüfen, dass verschiedene Funktionen (fgets(), , etc) tatsächlich erfolgreich ist. Ihr Code verläuft auf der Annahme basiert, dass die Funktionen alle Arbeiten wie geplant, aber das Verhalten undefiniert, wenn sie nicht (zum Beispiel, wenn der Speicher Neuzuweisung von realloc() ausfällt).