Пока вы можете анализировать информацию из каждой строки с помощью указателя и strchr
(или просто перемещая указатель вниз по вашему буферу), когда имеете дело с отформатированным вводом *1003*, используя Функция форматированного ввода , как sscanf
, может очень помочь.
Давайте посмотрим на оба. В вашем вопросе вы хотите прочитать с fgets
(хорошо), а затем найти первую запятую, а затем скопировать оставшуюся часть строки в новый буфер. Пока все хорошо. Единственное предостережение: когда вы найдете первую запятую, вы все равно должны продвигать указатель от запятой, пропуская все пробелы, пока не достигнете первого символа в оставшуюся часть времени (остаток строки).
Простой подход, который просто выводит остаток строки после первой запятой, пропуская любые промежуточные пробелы, может быть:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAXC 1024 /* if you need a constant, define one (or more) */
int main (void) {
char buf[MAXC];
while (fgets (buf, MAXC, stdin)) { /* read with fgets */
char *p;
buf[strcspn (buf, "\r\n")] = 0; /* trim '\n' from end */
if ((p = strchr (buf, ','))) { /* find 1st ',' */
do
p++; /* advance pointer */
while (*p && isspace (*p)); /* to end or 1st non-whitespace */
}
printf ("rest of string: '%s'\n", p); /* output rest of line */
}
}
( примечание: при объявлении констант, не экономить на размере буфера.)
Пример входного файла
$ cat dat/airport_times.txt
KOCH, 01:01, 01:51
KAXX, 03:50, 05:40
KADS, 07:40, 09:30
Пример использования / Вывод
$ ./bin/airport_gettimes <dat/airport_times.txt
rest of string: '01:01, 01:51'
rest of string: '03:50, 05:40'
rest of string: '07:40, 09:30'
Теперь давайте рассмотрим использование fgets
для функции чтения и функции форматированного ввода sscanf
для анализа всех необходимых значений из каждой строки. (или вы можете использовать fscanf
, чтобы сделать это за один вызов, но лучше использовать fgets
, а затем sscanf
, чтобы (1) убедиться, что вы используете всю строку данных, и (2) можете независимо проверить чтение и анализ значений.
Подход аналогичен, читается с fgets
, но затем вместо поиска первой запятой с strchr
просто используйте sscanf
для считывания ИКАО, времени прибытия и времени отправления в отдельные буферы в одном вызове. ВСЕГДА проверяйте ВОЗВРАТ любой из функций scanf
, чтобы обеспечить ожидаемое количество преобразований.
Забегая вперед, давайте не будем просто использовать три отдельных и не связанных буфера. Вместо этого давайте объявим struct
для хранения всех трех буферов icao, ariv & dept
. Таким образом, если вы читаете несколько записей в память, вы можете просто объявить массив struct и прочитать / проанализировать все значения для последующего пользователя. (массив оставлен вам)
Простой пример здесь может быть:
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define MAXC 1024 /* if you need a constant, define one (or more) */
#define ICAO 6 /* will work for ICAO and time buffer lengths */
typedef struct {
char icao[ICAO],
ariv[ICAO],
dept[ICAO];
} flight_t;
int main (void) {
char buf[MAXC];
while (fgets (buf, MAXC, stdin)) { /* read with fgets */
flight_t flt = { .icao = "" }; /* declare struct */
/* separate all value in line into struct, validating return */
if (sscanf (buf, "%5[^,], %5[^,], %5[^,]",
flt.icao, flt.ariv, flt.dept) == 3)
/* if sscanf succeeds, output (or use) the values */
printf ("%s %s (arrival) %s (departure)\n",
flt.icao, flt.ariv, flt.dept);
}
}
( примечание: как используется модификатор field-width перед каждым символьным классом спецификатор преобразования для защиты границ массива для каждого буфера с "%5[^,], %5[^,], %5[^,]"
. Если у вас есть вопросы по поводу строки формата, просто спросите.)
Тот же файл ввода.
Пример использования / Вывод
$ ./bin/airport_parsetimes <dat/airport_times.txt
KOCH 01:01 (arrival) 01:51 (departure)
KAXX 03:50 (arrival) 05:40 (departure)
KADS 07:40 (arrival) 09:30 (departure)
Преимущество здесь в том, что теперь все значения координируются как один объект, но сохраняются независимо, поэтому вы можете получить доступ к любому из значений icao, ariv
или dept
по мере необходимости, в то время как в случае массива struct, сохраняя возможность сортировки массива по любому члену структуры, сохраняя при этом связь icao, времени прибытия и отправления.
Существует множество способов собрать кусочки головоломки вместе. Следующим шагом будет динамическое выделение вашего массива struct и realloc
по мере необходимости, чтобы вы могли читать неизвестное и неограниченное количество записей (вплоть до физической памяти вашего компьютера). Однако два подхода: (1) анализировать буфер с помощью указателя или (2) использовать форматированную функцию ввода, покрывают большинство случаев. Все, что осталось, строится на этом фундаменте по желанию.