2009-07-01 3 views
0

Я разбираю некоторые данные CSV в C для расширения Ruby. Для того, чтобы вытащить данные из каждой строки, я использую sscanf следующим образом:sscanf и строки

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 

Забегая производит это:

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 

Обратите внимание на пустые строки. В принципе, похоже, что sscanf по какой-то причине отключается от них. Я не могу понять, почему даже прочитал документы полностью. Есть идеи?

+0

Этот вопрос не имеет ничего общего с Ruby. Удалите ссылку на Ruby в тексте и удалите тег Ruby. –

ответ

2

Ваши указатели на объекты унифицированы и указывают на случайный сегмент памяти. Вы должны выделить буфер для sscanf() для записи, и он должен быть достаточно большим. (Вам повезло, что это не было segfault.) Вторая часть - трудная часть - scanf() может быть не лучшим инструментом для работы здесь.

+0

Ах, хорошо, это имеет смысл. Строки имеют заданную фиксированную длину. Каков наилучший способ выделить пространство для указателей? –

+0

Изменено мое определение на char, выпущенное [30], ставка [10]; и совпадение с% [^,] вместо% s. Не идеально, но выполняет работу и работает. –

+0

Еще раз классическая проблема scanf. IMHO scanf - это функция дьявола (наряду с realloc ...) и НЕ должна использоваться, если нет альтернативы. – AAT

1

%s соответствует символам без пробелов. То, что вы, вероятно, хотите, - %[^,]255, которое будет соответствовать любому персонажу, кроме ,, а не %s. 255, который является необязательным, указывает ширину поля, которую вы ожидаете для этого поля.

+0

Хороший совет, но не сразу источник проблемы. –

+0

Да, хотя кажется, что sscanf будет зависеть от даты и не будет соответствовать чему-либо за пределами этого, поскольку он ожидает «,» вместо пространства. –

0

Я согласен с Танатосом. В качестве первого запуска вам необходимо выделить память для выпущенных и заявленных ставок, вы можете сделать:

char issu [1024]; char bid [1024];

2

Выделение памяти в стеке является простым способом. Пример:

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

Кстати, «Выделение памяти в стеке» на самом деле просто означает, принимая текущее положение указателя стека, присвоив его имя переменной, а затем увеличивающиеся указатель стека на размер типа от переменной. Это чрезвычайно быстрая операция по сравнению с распределением памяти в куче с помощью malloc и друзей. В отличие от malloc, однако вы теряете любую выделенную стек, как только вы поместите свой текущий стек стека (т. Е. Выполнение достигнет конца текущей функции).