Использование fscanf для чтения построчно из входного файла - PullRequest
0 голосов
/ 24 апреля 2019

Я читаю из файла, который имеет 15 функций, разделенных '|' условное обозначение. Я использую: while(fscanf(file, "%*d|%s|%*s|%s|%*d|%*s|%*d|%*s|%*s|%*f|%*f|%*s|%*s|%*f|%*f", &name, &state)==2), но когда я запустил на нем gdb, я понял, что он никогда не входил в цикл. Я использовал %*d/s, потому что он говорит fscanf, чтобы пропустить эти значения правильно? Я хочу прочитать только 2 значения всей строки из входных данных, два% s в начале. Любые предложения о том, как исправить? Извините за неоптимальное форматирование.

1 Ответ

1 голос
/ 24 апреля 2019

Если вы все еще застряли, может помочь короткий пример.Глядя на вашу строку формата, например

"%*d|%s|%*s|%s|%*d|%*s|%*d|%*s|%*s|%*f|%*f|%*s|%*s|%*f|%*f"

Вы, похоже, хотите сохранить 2-е и 4-е поля в виде строковых значений в name и state.

. Сразу подозреваю, что выиспользование &name, &state неверно, поскольку, если вы объявили name и state как массивы символов, достаточно большого размера для хранения данных во 2-м и 4-м полях, name и state уже являются указателями (см .: Стандарт C11 - 6.3.2.1 Другие операнды - L-значения, массивы и указатели функций (p3) ), поэтому нет необходимости в '&' перед именами переменных.Если они не были объявлены как символьные массивы (или как указатели на массивы и выделены достаточные объемы памяти), ваш анализ все равно не будет выполнен из-за несовместимых типов.

Далее, почему так важно прочитать всю строку с помощью fgets() или POSIX getline(), а затем анализировать с sscanf() вместо использования fscanf():

  1. Ваше чтение не будет выполнено, если есть какой-либо соответствующий или вход ошибка с любым из 15 полей;и
  2. вы заботитесь только о 2-м и 4-м полях - нет необходимости делать ваше чтение зависимым от успешного разбора 15 полей, когда вы заботитесь только о двух из них.

Таким образом, вместо того, чтобы беспокоиться о правильном сопоставлении 15 полей, вам нужно беспокоиться только о 4 - вас не волнует остальная часть строки после 4-го поля.

В качестве небольшого примеравместе со случайно сгенерированными данными (отрегулируйте размеры буфера, необходимые для ваших данных), вы можете сделать что-то вроде следующего, чтобы проанализировать 2-е и 4-е поля как строки:

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

#define FLDW   32   /* max field width */
#define MAXC 1024   /* max chars in line */

int main (int argc, char **argv) {

    char buf[MAXC],     /* line buffer */
        name[FLDW],     /* storage for name */
        state[FLDW];    /* storage for state */

    /* use filename provided as 1st argument (stdin by default) */
    FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;

    if (!fp) {  /* validate file open for reading */
        perror ("file open failed");
        return 1;
    }

    while (fgets (buf, MAXC, fp)) { /* read each line of input */
        /* parse 2nd & 4th fields as strings - you don't care about rest */
        if (sscanf (buf, "%*d|%31[^|]|%*[^|]|%31[^|]", name, state) == 2) {
            buf[strcspn (buf, "\n")] = 0;   /* trim \n from buf */
            /* output line with parsed name and state to right */
            printf ("%s  =>  name: %s, state: %s\n", buf, name, state);
        }
    }
    if (fp != stdin) fclose (fp);   /* close file if not stdin */

    return 0;
}

( note: использование модификатора field-width для защиты границ массивов name и state с %31[^|]. Использование strcspn было просто для обрезки '\n' отконец buf, поэтому значения name и state будут напечатаны в одной строке после вывода buf. Если вы не печатаете buf, то этот вызов вообще не нужен для анализа)

Пример использования / Output

Минимальное количество сгенерированных данных соответствует вашей строке формата.Парсинг 2-го и 4-го значений приведет к получению желаемых строк в name и state, например,

$ ./bin/fgetssscanf dat/field15pipes.txt
01|8a|0b|6c|82|1d|33|5e|4f|7.|0.|4g|3h|7.|5.  =>  name: 8a, state: 6c
01|9a|5b|0c|42|1d|93|3e|9f|8.|0.|5g|4h|6.|5.  =>  name: 9a, state: 0c
01|4a|5b|7c|22|0d|23|1e|1f|7.|2.|1g|5h|7.|7.  =>  name: 4a, state: 7c
01|8a|2b|5c|72|1d|53|6e|2f|1.|1.|8g|0h|7.|6.  =>  name: 8a, state: 5c
11|4a|6b|5c|92|2d|73|0e|6f|4.|2.|2g|7h|2.|4.  =>  name: 4a, state: 5c
01|2a|6b|0c|02|1d|83|0e|2f|5.|2.|9g|4h|3.|8.  =>  name: 2a, state: 0c
31|1a|0b|0c|72|2d|13|3e|3f|9.|0.|2g|5h|6.|9.  =>  name: 1a, state: 0c
01|8a|3b|7c|92|1d|93|3e|9f|6.|1.|4g|4h|8.|3.  =>  name: 8a, state: 7c
11|1a|4b|7c|42|2d|73|0e|5f|7.|0.|0g|5h|1.|7.  =>  name: 1a, state: 7c
21|8a|6b|9c|22|2d|23|2e|1f|9.|0.|1g|6h|6.|8.  =>  name: 8a, state: 9c

Посмотрите вещи и дайте мне знать, если у вас есть вопросы.

...