当您需要从缓冲区中提取数值时,您需要考虑strtoX()(其中X 可以是l、ul、f、d,对于strtol()等。)原因有两个。 (1) 这些函数旨在允许您通过提供指向字符串本身的指针参数以及在最后一个数字成功转换后更新为指向下一个字符的endptr 参数来实现这一点; (2) 这些功能为转换的各个方面提供了完整的错误检测。
由于endptr 参数被更新为最后一位转换后的数字,您只需遍历缓冲区,尝试转换,成功转换后,您只需将初始指针更新为endptr 和重复直到你用完字符。见man 3 strtol
由于endptr 已更新为指向转换后的最后一个数字,因此您可以简单地检查指向endptr 的字符是字符串的nul-terminating 字符还是!isspace(*endptr) 确定该组数字中是否包含非数字。
您的案例的一个简单实现是:
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
#define MAXC 1024
int main (int argc, char **argv) {
char buf[MAXC]; /* buffer to hold each line */
/* 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 into buf */
char *p = buf, *ep = p; /* pointers to use with strtol() */
for (;;) { /* loop continually */
errno = 0; /* reset errno */
long val = strtol (p, &ep, 0); /* attempt conversion to long */
if (p == ep) /* check if no characters converted */
break;
else if (errno) /* check for under/overflow */
break;
else if (*ep && !isspace(*ep)) /* check next char for non-space */
break;
else
printf (" %ld", val); /* good all-digit conversion */
p = ep; /* update pointer to endpointer */
}
putchar ('\n'); /* tidy up with newline */
}
if (fp != stdin) /* close file if not stdin */
fclose (fp);
}
输入文件示例
$ cat dat/numwalpha.txt
1 2 3 4a
1 2 3 a4
1 2 3 a b c 4 5 6 7
使用/输出示例
$ ./bin/strtol_numonly dat/numwalpha.txt
1 2 3
1 2 3
1 2 3
添加错误报告
如果失败,您可以简单地输出以endptr 开头的字符(上面的ep)来查看失败的原因。您可以包含一个预处理器指令,通过使用 DEBUG 定义打开/关闭错误报告,如果您愿意,例如
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <errno.h>
#define MAXC 1024
int main (int argc, char **argv) {
char buf[MAXC]; /* buffer to hold each line */
/* 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 into buf */
char *p = buf, *ep = p; /* pointers to use with strtol() */
for (;;) { /* loop continually */
errno = 0; /* reset errno */
long val = strtol (p, &ep, 0); /* attempt conversion to long */
if (p == ep) { /* check if no characters converted */
#ifdef DEBUG
fprintf (stderr, "error: no digits converted in '%s'.\n", p);
#endif
break;
}
else if (errno) { /* check for under/overflow */
#ifdef DEBUG
fprintf (stderr, "error: over/under-flow in conversion or '%s'.\n", p);
#endif
break;
}
else if (*ep && !isspace(*ep)) { /* check next char for non-space */
#ifdef DEBUG
fprintf (stderr, "error: mixed alphanumeric '%s'.\n", ep);
#endif
break;
}
else
printf (" %ld", val); /* good all-digit conversion */
p = ep; /* update pointer to endpointer */
}
putchar ('\n'); /* tidy up with newline */
}
if (fp != stdin) /* close file if not stdin */
fclose (fp);
}
然后使用-DDEBUG 编译以启用定义,您将拥有:
$ ./bin/strtol_numonly dat/numwalpha.txt
error: mixed alphanumeric 'a
'.
1 2 3
error: no digits converted in ' a4
'.
1 2 3
error: no digits converted in ' a b c 4 5 6 7
'.
1 2 3
其中显示第一个案例失败是由于末尾的'a',第二个是由于"a4" 作为要转换的字符串,最后一个是因为"a b c 4 5 6 7" 是字符串中剩下的所有内容, 'a' 是下一个转换。