2009-07-01 9 views
0

Ich analysiere einige CSV-Daten in C für die Zwecke einer Ruby-Erweiterung. Um die Daten aus jeder Zeile zu ziehen Ich bin mit sscanf wie folgt:sscanf und strings

char* line = RSTRING_PTR(arg); 
    double price; 
    double volume_remaining; 
    unsigned int type_id, range, order_id, volume_entered, minimum_volume, duration, station_id, region_id, solar_system_id, jumps; 
    char* issued; 
    char* bid; 
    printf("I got %s\n",line); 
    int res = sscanf(line, "%lf,%lf,%u,%u,%u,%u,%u,%s,%s,%u,%u,%u,%u,%u", &price, &volume_remaining, &type_id, &range, &order_id, &volume_entered, &minimum_volume, bid, issued, &duration, &station_id, &region_id, &solar_system_id, &jumps); 
    printf("I matched %d values\n", res); 
    printf("I have price %f, vol_rem %f, type_id %d, range %d, order_id %d, vol_ent %d, min_vol %d, issued %s, bid %s, duration %d, station_id %d, region_id %d, solar_system_id %d, jumps %d, source %s \n",price, volume_remaining, type_id, range, order_id, volume_entered, minimum_volume, issued, bid, duration, station_id, region_id, solar_system_id, jumps, source); // and hash build follows below 

Laufen sie produziert diese:

I got 728499.93,437.0,2032,32767,1132932560,588,1,False,2009-05-24 19:52:08.000,90,60003760,10000002,30000142,0 
I matched 7 values 
I have price 728499.930000, vol_rem 437.000000, type_id 2032, range 32767, order_id 1132932560, vol_ent 588, min_vol 1, issued (null), bid (null), duration -1210229476, station_id 3001, region_id 3001, solar_system_id 1, jumps -1210299816 

Beachten Sie die Null-Strings. Grundsätzlich scheint es, dass sscanf aus irgendeinem Grund auf diese stolpert. Ich kann nicht herausfinden, warum ich die Dokumente gründlich gelesen habe. Irgendwelche Ideen?

+0

Diese Frage hat nichts mit Ruby zu tun. Bitte löschen Sie den Verweis auf Ruby im Text und löschen Sie das Ruby-Tag. –

Antwort

2

Ihre Zeichenzeiger sind unitialisiert und zeigen auf ein zufälliges Speichersegment. Sie müssen einen Puffer für sscanf() zuweisen, um zu schreiben, und es muss groß genug sein. (Sie haben Glück, dass nicht segfault.) Dieser zweite Teil ist der schwierige Teil - scanf() ist hier vielleicht nicht das richtige Werkzeug für den Job.

+0

Ah, OK, das macht Sinn. Die Saiten haben eine vorgeschriebene feste Länge. Was ist der beste Weg, Platz für die Zeiger zu reservieren? –

+0

Meine Definition wurde in char geändert [30], bid [10]; und der Matcher zu% [^,] anstelle von% s. Nicht perfekt, aber macht den Job und funktioniert. –

+0

Noch einmal ein klassisches ScanF-Problem. IMHO scanf ist die Funktion des Teufels (zusammen mit Realloc ...) und sollte nicht verwendet werden, es sei denn, es gibt wirklich keine Alternative. – AAT

1

%s entspricht Nicht-Leerzeichen Zeichen. Was Sie wahrscheinlich wollen, ist %[^,]255, die jedes Zeichen außer , anstelle von %s übereinstimmen wird. 255 (optional) gibt die Feldbreite an, die Sie für dieses Feld erwarten.

+0

Guter Rat, aber nicht sofort die Ursache des Problems. –

+0

Ja, obwohl es so aussieht, als würde der Sscanf auf das Datum stoßen, und würde nichts darüber hinaus passen, da er ein ',' anstelle eines Leerzeichens erwartet. –

0

Ich stimme mit Thanatos überein. Als ersten Start müssen Sie Speicher für ausgestellt und bieten, können Sie tun:

Char ausgegeben [1024]; Zeichengebot [1024];

2

Die Zuweisung von Speicher auf dem Stapel ist der einfache Weg. Beispiel:

char issued[1024] = {0}; 
char bid[1024] = {0}; 

Durch die Art und Weise, „Zuweisen von Speicher auf dem Stapel“ wirklich nur bedeutet, dass die aktuelle Position des Stapelzeigers nehmen, um es zu dem Variablennamen zuweisen und dann durch die Größe des Typs der Stapelzeiger inkrementierte der Variable. Es ist eine extrem schnelle Operation verglichen mit dem Zuweisen von Speicher auf dem Heap mit malloc und Freunden. Anders als bei malloc verlieren Sie jedoch jeden Stapelspeicher, sobald Sie den aktuellen Stapelrahmen öffnen (d. H. Die Ausführung erreicht das Ende der aktuellen Funktion).