Чтение с линейно-ориентированной функцией ввода, такой как fgets()
или POSIX getline()
, гарантирует, что при каждом вызове используется полная строка ввода. (не экономьте на размере буфера). strtol
было создано для преобразования неизвестного количества значений в строке в long
. Вы перемещаетесь по вашему буферу, используя параметр endptr
, заполненный strtol
после успешного преобразования, чтобы указать следующий символ после последней преобразованной цифры.
Это позволяет простому методу использовать пару указателей, p
ваш начальный указатель и ep
ваш конечный указатель для работы по всей строке, конвертируя значения по мере продвижения. Основной подход заключается в том, чтобы позвонить strtol
, , чтобы подтвердить , что это успешно, и затем установить p = ep;
, чтобы перейти к началу вашего следующего преобразования. strtol
игнорирует начальные пробелы.
В целом, вы можете сделать:
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <limits.h>
#define MAXC 1024 /* if you need a constant, #define one (or more) */
/* (don't skimp on buffer-size) */
int main (int argc, char **argv) {
char buf[MAXC]; /* buffer to hold each line read */
size_t n = 0; /* line-counter */
/* 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 */
char *p = buf, *ep = p; /* pointer and end-pointer */
int sum = 0; /* variable to hold sum */
if (*buf == '\n') /* ignore empty lines */
continue;
while (*p && *p != '\n') {
errno = 0;
long tmp = strtol (p, &ep, 0); /* convert to temp long */
if (p == ep) { /* validate digits were converted */
fputs ("error: no digits extracted.\n", stderr);
break;
}
else if (errno) { /* validate no under/overflow occurred */
fputs ("error: underflow/overflow occurred.\n", stderr);
break;
}
else if (tmp < INT_MIN || INT_MAX < tmp) { /* validate in range */
fputs ("error: tmp exceeds range of int.\n", stderr);
break;
}
sum += tmp; /* add tmp to sum */
p = ep; /* set p to end-ptr (one past last digit used) */
}
n++; /* advance line counter */
printf ("sum line [%2zu] : %d\n", n, sum); /* output sum */
}
if (fp != stdin) fclose (fp); /* close file if not stdin */
return 0;
}
( note: if (*buf == '\n')
, который проверяет, является ли первый символ в строке символом новой строки и просто переходит на следующую строку, не нужно беспокоиться о преобразовании значений в пустой строке)
Пример использования / Вывод
Использование ваших данных в dat/sumlines.txt
дает ожидаемые результаты.
$ ./bin/sumline dat/sumlines.txt
sum line [ 1] : 6
sum line [ 2] : 6
Дайте мне знать, если у вас есть дополнительные вопросы.