fgets и strtok в двойном цикле for

Я пытаюсь извлечь содержимое файла в матрицу, но файл может выглядеть совершенно иначе.

Например, все эти файлы должны давать один и тот же результат: матрица 3x3, содержащая 1,2,3,4,5,6,7,8,9.


1 2 3 
4 5 6
7 8 9

1  2  3 
4 5 6
7         8 9

1 2 3 4
5
6
7   8 
9

1 2 3
$something
$something else
4 5 6
$something else else
7 8 9

Надеюсь, я заранее знаю размеры матрицы, а также символ "$", который указывает, что эти строки следует игнорировать в текущем процессе.

Мой текущий алгоритм с использованием fscanf отлично работает, но он не может работать со строками «$something».

Я решил, что мне следует использовать метод fgets/strtok/sscanf, но есть некоторые проблемы.

// File* file (already assigned)
char line[32]; //assuming 32 is enough
char* token;

fgets(line,32,file);
token = strtok(line," \t");

for (y=0; y<ySize; y++)
{
    for (x=0; x<xSize, x++)
    {
        if (token[0] == '$') //should use a str function
        {
            fgets(line,32,file);
            token = strtok(line," \t")
            x--;
        }
        else
        {
            if (we are at the end of the line)
            {
                fgets(line,32,file);
                token = strtok(line," \t")
            }
            sscanf(token,"%d",&matrix[x][y];
            token = strtok(NULL," \t");
        }
    }
}

По сути, я хотел бы получить некоторую помощь, чтобы написать условие «если (мы находимся в конце строки)» и некоторые данные о моем методе, он безупречен? Я правильно подумал о процессе?

Спасибо.


person Sword22    schedule 17.03.2012    source источник
comment
Взгляните на strtol(). Вы можете использовать второй аргумент для настройки цепочки вызовов, которая проходит через всю строку.   -  person pmg    schedule 17.03.2012
comment
Являются ли комментарии только полными строками или допустима строка типа 1 2 $ignore?   -  person Jerry Coffin    schedule 17.03.2012
comment
1 2 $игнорировать невозможно. Но в основном мне просто нужно было бы каждый раз вызывать «токен == $» (все еще нужно провести некоторое исследование о токене и все такое). 1 $игнорировать 2 тоже нельзя.   -  person Sword22    schedule 17.03.2012


Ответы (2)


Вы должны использовать getline вместо fgets, чтобы упростить задачу. Последнее ненадежно. Условие теста, которое вы ищете:

token == NULL;

Проверьте это: "Как только в вызов strtok, все последующие вызовы этой функции с нулевым указателем в качестве первого аргумента возвращают нулевой указатель».

person Community    schedule 17.03.2012
comment
Что вы считаете ненадежным в fgets? - person Jerry Coffin; 17.03.2012
comment
Для потоков, открытых в текстовом режиме, fseek имеет ограниченное применение, так как перевод каретки с переводом строки может привести к тому, что fseek даст неожиданные результаты. Единственными операциями fseek, гарантированно работающими с потоками, открытыми в текстовом режиме, являются: * Поиск со смещением 0 относительно любого исходного значения. * Поиск с начала файла со значением смещения, возвращаемым вызовом ftell. - person ; 17.03.2012
comment
Вы имеете в виду какое-то время на x и y? Какая разница? Ответ: не требуется ли strtok(NULL, \t) для перехода к следующему элементу строки? - person Sword22; 17.03.2012
comment
Ваш первоначальный комментарий был о fgets, но ваш ответ о fseek и ftell. Это ничего не говорит о ненадежности fgets. - person Jerry Coffin; 17.03.2012
comment
Я думаю, что fgets имеет ту же механику, что и fseek, я ошибаюсь? - person ; 17.03.2012
comment
Кроме того, цикл while может показаться более проблематичным. - person ; 17.03.2012

Вы можете легко выполнить синтаксический анализ без strtok(), используя strspn() / strcspn() и спецификатор "%n" sscanf(). Также: в исходном коде был ',', где ';' должно было.

#include <stdio.h>
#include <string.h>

#define XSIZE 3
#define YSIZE 3

int matrix[XSIZE][YSIZE];

int main(void)
{
char line[200];
int pos,eat,xx,yy, rc;

xx = yy =0;
while ( fgets(line, sizeof line, stdin) ) {
    if (line[0] == '$') continue;
    for(pos=0; line[pos]; pos += eat) {
       pos += strspn(line+pos, " \t\n");
       rc =sscanf(line+pos, "%d%n", &matrix[xx][yy], &eat);
       if (rc < 1) break;
       if (++xx >= XSIZE ) {xx = 0; if(++yy >= YSIZE) goto done; }
       }   
     }
done:
        /* show it to the world ... */
for (yy = 0; yy < YSIZE; yy++) {
    for (xx = 0; xx < XSIZE; xx++) {
        fprintf (stdout, " %d", matrix[xx][yy] );
        }       
    fprintf (stdout, "\n" );
    }   
return 0;
}
person wildplasser    schedule 17.03.2012
comment
это более или менее то, о чем я думал с циклом while, но я думаю, что его легче читать с циклами for, и производительность должна быть примерно такой же. Но за это палец вверх! - person ; 17.03.2012
comment
Исходный код использовал fgets() в трех разных местах (что некрасиво, ИМХО). В большинстве случаев помещение fgets() во внешний цикл дает самый чистый код. Производительность не имеет значения, большая часть времени выполняется внутри sscanf(), и количество вызовов sscanf() такое же. Также: оригинал не проверял код возврата fgets() или sscanf(). - person wildplasser; 17.03.2012
comment
да, действительно, но вы используете ярлык, а это то, что я бы не советовал! - person ; 18.03.2012
comment
Если вы можете переписать программу без перехода, без дополнительных сложностей (таких как повторяющиеся условия или, что еще хуже, индикаторные переменные): будьте моим гостем! - person wildplasser; 18.03.2012
comment
эй, приятель, не обороняйся, goto — допустимое ключевое слово c, так что в его использовании нет ничего плохого. Я просто высказал свое мнение. - person ; 18.03.2012