2013-05-24 6 views
6

Diese 2 Fehler kommen mit einer verknüpften Liste/Low-Level-Datei lesen/STRTok-Programm. HierC: Valgrind: Verwendung von nicht initialisierten Wert der Größe 4 UND Verwendung von nicht initialisierten Wert der Größe 4

==10982== Use of uninitialised value of size 4 
==10982== at 0x40C3899: strtok (strtok.S:197) 
==10982== by 0x8048719: main (main.c:9) 
==10982== Uninitialised value was created by a stack allocation 
==10982== at 0x80487D2: buildList (functions.c:13) 
==10982== 
==10982== Use of uninitialised value of size 4 
==10982== at 0x40C38C1: strtok (strtok.S:223) 
==10982== by 0x8048719: main (main.c:9) 
==10982== Uninitialised value was created by a stack allocation 
==10982== at 0x80487D2: buildList (functions.c:13) 
==10982== 
==10982== Conditional jump or move depends on uninitialised value(s) 
==10982== at 0x40C38C4: strtok (strtok.S:224) 
==10982== by 0x8048719: main (main.c:9) 
==10982== Uninitialised value was created by a stack allocation 
==10982== at 0x80487D2: buildList (functions.c:13) 

ist die Funktion Buildlist

void buildList(int fdin, int lines) 
{ 
    char ara[4096]; 
    int num; 
    double p; 
    read(fdin, ara, 4096); 
    char *nl = "\n"; 
    char *ws = " "; 
    char *temp = strtok(ara, " "); 
    while(temp != NULL) 
    { 
     Stock *s = (Stock*)calloc(1, sizeof(Stock)); 
     s->c.symbol = (char*)calloc(strlen(temp)+1, sizeof(char)); 
     strcpy(s->c.symbol, temp); 
     temp = strtok(NULL, "\n"); 
     s->c.name = (char*)calloc(strlen(temp)+1, sizeof(char)); 
     strcpy(s->c.name, temp); 
     temp = strtok(NULL, "\n"); 
     sscanf(temp, "%lf", &p); 
     temp = strtok(NULL, "\n"); 
     s->price = p; 
     sscanf(temp, "%d", &num); 
     s->shares = num; 
     Node *n = (Node*)calloc(1, sizeof(Node)); 
     n->data = s; 
     addOrdered(n); 
     temp = strtok(NULL, " "); 
    } 
    close(fdin); 
} 

Ich kann nicht herausfinden, warum dieser Fehler auftritt. Von dem, was ich gelesen habe, ist es, weil ich Sachen zu einem char * von strtok zuweise, ohne ihnen Speicher zuzuweisen. Aber so habe ich es in der Vergangenheit gemacht, und ich denke, es war gut.

+0

Was ist Zeile 13 von functions.c? – aschepler

+0

Sieht aus, als würde Valgrind die Tatsache vermissen, dass 'ara' durch' read() '" initialisiert "wird. Nur zum Grinsen, versuche etwas wie "memset (ara, 0, sizeof (ara))" direkt vor dem Lesen zu platzieren und schau, ob das die Warnung unterdrückt. Wenn dies der Fall ist, entfernen Sie es und wissen Sie, dass Sie die Warnung ignorieren können (oder erfahren Sie, wie Sie Valgrind dazu bringen, den Mund zu halten). Natürlich kann 'read()' auch fehlschlagen, in diesem Fall ist Valgrind korrekt. –

+0

Sie geben weder die Definition von 'main' an, noch zeigen Sie die Eingabe an, die das Problem verursacht. Sie können auch keine Fehler im obigen Code überprüfen. Bitte erstellen Sie eine [SSCCE] (http://sscce.org), die uns nicht raten muss! –

Antwort

1

Haben die von read gelesenen Daten am Ende einen Nullabschluss? Wenn nicht, ist das wahrscheinlich das Problem.

4

Wie andere vermutet haben, beschwert sich valgrind, dass strtok uninitialisierten Speicher verwendet. Die Frage dreht sich dann, warum, da es scheint, wie es durch initialisiert wird:

read(fdin, ara, 4096); 

Allerdings ist read()\0 die Daten nicht beenden, während strtok erwartet eine \0 terminierten String. Stellen Sie sicher, dass die Eingabe beendet ist richtig:

ssize_t result = read(fdin, ara, sizeof[ara]-1); /* leave room for '\0' */ 
ara[result > 0 ? result : 0] = '\0'; 

Der memset(ara, 0, sizeof(ara)); Vorschlag von Lee Daniel Crocker beläuft sich auf die gleiche Art von Lösung, aber es funktioniert nur, wenn die Datei enthält weniger als sizeof(ara) Byte Eingangs. Sie sind einem ähnlichen Problem weiterhin ausgesetzt, wenn die Datei, aus der Sie lesen, über 4096 Byte Daten oder mehr verfügt. Dann wird strtok gezwungen, nach dem Ende des Puffers zu scannen, um nach dem \0 zu suchen, was zu undefiniertem Verhalten führt.

+0

Aber der Aufruf zu "strtok", über den man sich beschwert, ist in 'main', nicht in der obigen Funktion ... –

+0

@OliCharlesworth: Ich denke das ist nur, weil die Funktion inline wurde. – jxh

+0

@OliCharlesworth Ich benutze keine strtok irgendwo in main. –

3

read(fdin, ara, 4096);

..., die zurückkehren konnte:

  • -1, die Lese Bedeutung bekam einen Fehler und ara wurde nicht gefüllt;
  • 0, was bedeutet, dass Sie das Ende der Datei angetippt haben und ara nicht ausgefüllt wurde;
  • ein Wert < 4096, was bedeutet, es gibt weniger als 4096 Bytes in der Datei belassen und nicht in.

Prüfen Sie immer den Rückgabewert von read() alle Bytes von ara gefüllt sind.

char * temp = strtok (ara, "");

$ man strtok 

...

The strtok() function is used to isolate sequential tokens in a null-ter- 
minated string, str. ... 

Es gibt nichts, was auch immer das garantiert, dass ara ein Null-Zeichen hat ('\0') drin, so dass Sie nicht wirksam Hand es zu strtok(). Machen Sie es char ara[4097] und tun Sie ara[4096] = '\0'; nach dem Lesen, wenn Sie sicherstellen möchten, dass es eine '\0' drin ist.

Oder, noch besser, wenn read() ‚s Rückgabewert in einer Variablen data_read, und Sie haben bereits überprüft, um sicherzustellen, dass es nicht -1, tun ara[data_read] = '\0';, so dass Sie das Byte nach der letzten Lese auf '\0'.

Und was passiert, wenn die Datei mehr als 4096 Zeichen hat, und Ihr read() Aufruf liest zum Beispiel mehrere Zeilen und die Anfang einer anderen Zeile? Gegebenenfalls sollten Sie in Betracht ziehen, zu verwenden, um die Datei zu öffnen, und fgets() zu verwenden, um Zeilen zu lesen.