Абсолютно нет необходимости использовать strtok()
, потому что strtol()
устанавливает указатель, указываемый вторым параметром, для указания на символ, следующий за проанализированным числом.
Полный пример программы:
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
int main(void)
{
char *line_ptr = NULL;
size_t line_max = 0;
ssize_t line_len;
long *number = NULL;
size_t numbers = 0;
size_t numbers_max = 0;
char *curr, *next, *ends;
long temp;
size_t i;
while (1) {
line_len = getline(&line_ptr, &line_max, stdin);
if (line_len < 1)
break;
curr = line_ptr;
ends = line_ptr + line_len;
numbers = 0;
while (1) {
/* Parse next long. */
next = curr;
errno = 0;
temp = strtol(curr, &next, 0);
if (errno)
break;
if (next == curr)
break;
/* Need to grow number array first? */
if (numbers >= numbers_max) {
size_t temp_max = (numbers | 1023) + 1025 - 16;
long *temp_ptr;
temp_ptr = realloc(number, temp_max * sizeof number[0]);
if (!temp_ptr) {
fprintf(stderr, "Out of memory.\n");
exit(EXIT_FAILURE);
}
numbers_max = temp_max;
number = temp_ptr;
}
/* Save parsed number. */
number[numbers++] = temp;
/* Skip trailing whitespace, */
curr = next;
while (curr < ends && (*curr == '\t' || *curr == '\n' || *curr == '\v' ||
*curr == '\f' || *curr == '\r' || *curr == ' '))
curr++;
/* Skip separator. */
if (*curr == '|')
curr++;
else
break; /* No separator, so that was the final number. */
}
printf("Parsed %zu longs:", numbers);
for (i = 0; i < numbers; i++)
printf(" %ld", number[i]);
printf("\n");
fflush(stdout);
}
if (ferror(in)) {
fprintf(stderr, "Error reading standard input.\n");
exit(EXIT_FAILURE);
}
free(line_ptr);
line_ptr = NULL;
line_max = 0;
free(number);
number = NULL;
numbers = 0;
numbers_max = 0;
return EXIT_SUCCESS;
}
Эта программа не имеет ограничений, кроме доступной памяти. длина строки или количество чисел, которые она хранит в массиве. Политика роста для массива чисел фанки (просто мой стиль); не стесняйтесь заменить его на что угодно. Просто убедитесь, что temp_max
по крайней мере numbers + 1
. Увеличение его означает, что вы выделяете больше сразу и, следовательно, делаете меньше «медленных» вызовов realloc ().
Внешний цикл while
перебирает строки, считанные со стандартного ввода.
Внутренний цикл while
анализирует длинные строки из этой строки, разделенные символом |
. strtol()
игнорирует начальные пробелы. В случае, если между числом и следующим символом канала есть пробел, мы должны явно пропустить это; Вы также можете использовать только while (curr < ends && isspace(*curr)) curr++;
для этого.
Если вы хотите собрать все длинные значения в один массив, а не в строку, просто пропустите numbers = 0;
перед внутренним циклом while
. (И двигайте печать чисел после внешней петли while
.)
Фактическое преобразование,
next = curr;
errno = 0;
temp = strtol(curr, &next, 0);
if (errno)
break; /* errno == ERANGE; number too large in magnitude! */
if (next == curr)
break; /* end of input, no number */
основывается на том факте, что если преобразуемое число слишком велико по величине, strtol()
установит errno = ERANGE
и вернет LONG_MIN
(если число в строке было отрицательным) или LONG_MAX
(если положительное ). Чтобы обнаружить это, мы должны сначала установить errno
на ноль. Если строка пуста (или в строке указан случайный нулевой символ, \0
), strtol()
вернет 0 с next == curr
.