Strtok - чтение пустой строки в конце строки

В моем коде ниже я использую strtok для анализа строки кода из файла, который выглядит так:

1023.89,863.19  1001.05,861.94  996.44,945.67   1019.28,946.92  1023.89,863.19

Поскольку в файле могут быть строки разной длины, я не использую fscanf. Приведенный ниже код работает, за исключением одного небольшого сбоя. Он зацикливается слишком много раз и считывает длинную пустую строку " " перед повторным циклом, распознавая нулевой токен "" и выходя из цикла while. Я не знаю, почему это может быть.

Любая помощь будет принята с благодарностью.

fgets(line, sizeof(line), some_file);    
while ((line != OPC_NIL) {
    token = strtok(line, "\t"); //Pull the string apart into tokens using the commas
    input = op_prg_list_create();
    while (token != NULL) {
        test_token = strdup(token);
        if (op_prg_list_size(input) == 0)       
            op_prg_list_insert(input,test_token,OPC_LISTPOS_HEAD);  
        else
            op_prg_list_insert(input,test_token,OPC_LISTPOS_TAIL);
        token = strtok (NULL, "\t");
    }
    fgets(line, sizeof(line), some_file);                
}

person user2051005    schedule 07.02.2013    source источник


Ответы (2)


Вы должны использовать правильный список разделителей. Ваш код противоречит комментариям:

token = strtok(line, "\t"); //Pull the string apart into tokens using the commas

Если вы хотите разделить токены запятыми, используйте "," вместо "\t". Кроме того, вы, конечно, не хотите, чтобы токены содержали символ новой строки \n (который появляется в конце каждой строки, считываемой из файла с помощью fgets). Поэтому добавьте символ новой строки в список разделителей:

token = strtok(line, ",\n"); //Pull the string apart into tokens using the commas
...
token = strtok (NULL, ",\n");

Возможно, вы также захотите добавить символ пробела в список разделителей (863.19 1001.05 — это одна лексема или две лексемы? Вы хотите удалить пробелы в конце строки?).

person anatolyg    schedule 07.02.2013

Ваше использование sizeof(line) говорит мне, что line — это массив фиксированного размера, находящийся в стеке. В этом случае (line != OPC_NIL) никогда не будет false. Однако fgets() вернет NULL, когда будет достигнут конец файла или произойдет какая-либо другая ошибка. Ваш внешний цикл while должен быть переписан как:

while(fgets(line, sizeof(line), some_file)) {
...
}

Ваш входной файл, вероятно, также имеет символ новой строки в конце последней входной строки, что приводит к одной пустой строке в конце. В этом разница между этим:

1023.89,863.19 1001.05,861.94 996.44,945.67 1019.28,946.92 1023.89,863.19↵
<blank line>

и это:

1023.89,863.19 1001.05,861.94 996.44,945.67 1019.28,946.92 1023.89,863.19

Первое, что вы должны сделать в цикле while, это проверить, действительно ли строка соответствует ожидаемому формату. Если это не так, сломайте:

while(fgets(line, sizeof(line), some_file)) {
    if(strlen(line) == 0) // or other checks such as "contains tab characters"
        break;
    ...
}
person Dave Rager    schedule 07.02.2013