完全没有必要使用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 循环解析该行中的 long,由管道字符 | 分隔。 strtol() 忽略前导空格。如果数字和后面的管道字符之间有空格,我们需要明确地跳过它;你也可以只使用while (curr < ends && isspace(*curr)) curr++;。
如果您想将所有 long 收集到单个数组中,而不是每行,只需在内部 while 循环之前省略 numbers = 0;。 (并在外部 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 设置为零。如果字符串为空(或行中有一个杂散的 nul 字符 \0),strtol() 将返回 0 和 next == curr。