如何将一串数字解析为整数数组?
How do I parse a string of numbers into a array of integers?
我已经为此苦苦挣扎了一段时间,我想我还不如寻求帮助,而不是用头撞墙。
假设您有字符串 "10 10 10 4 4 4 9 9 9 2"
并且你想通过它,一个一个地取出数字并将其添加到一个整数数组中以供使用。
我制作了很多原型,并继续为自己做不必要的工作。起初我使用的是 strtok()
但后来人们说它已被弃用,使用 strsep()
会更容易
我该怎么做?
如有任何帮助,我们将不胜感激!
我的函数似乎总是 return 一个全为零的 int 数组。这是为什么?
int *parse_line(char *line){
char sNumArray[MAX];
strcpy(sNumArray, line);
char *tokens = NULL;
int *numbers = malloc(sizeof(int) * MAX);
tokens = strtok(sNumArray, " ");
for(int i = 0; ; i++) {
numbers[i] = atoi(tokens);
printf("%d \n", atoi(tokens));
tokens = strtok(NULL, " ");
if (tokens == NULL)
break;
}
return numbers;
}
这些是我在 main 中定义并调用我的函数的变量...
int *skyline;
skyline = parse_line(line);
for (int j = 0; j < 100 ; ++j) {
printf("%d \n", skyline[j]);
}
只需使用 scanf() 在 for 或 while 循环中一一获取每个数字。
for i = 0 to n
scanf(“%d”, &num);
请参阅 google 或 bing 在线搜索它是如何完成的,并提供许多可用示例。
我想这会做你想要的。
#include "stdafx.h"
#include <stdio.h>
#include <iostream>
#include <math.h>
#include <stdlib.h>
using namespace std;
#define MAX 100
int *parse_line(char *line, int *numInts) {
char sNumArray[MAX];
strcpy(sNumArray, line);
int *numbers = (int *) malloc(sizeof(int) * MAX);
char *tokens = strtok(sNumArray, " ");
for (int i = 0; ; i++) {
numbers[i] = atoi(tokens);
tokens = strtok(NULL, " ");
if (tokens == NULL) {
*numInts = i+1;
break;
}
}
return numbers;
}
int main() {
char *line = "10 10 10 4 4 4 9 9 9 2";
int numIntsExtracted = 0;
int *skyline = parse_line(line, &numIntsExtracted);
for (int j = 0; j < numIntsExtracted; ++j) {
printf("%d \n", skyline[j]);
}
return 0;
}
我在 运行 之后得到的输出。
10
10
10
4
4
4
9
9
9
2
我喜欢用函数strtol()
来做这个,因为如果你给它传递一个指针,它会return下一个点继续解析。还有未签名的版本,例如:strtoul()
。它们是 C99 以来的标准。 strtol()
还可以解析十六进制,并且比 atoi()
等旧函数(return 错误时为 0)等旧函数更好地处理错误。
下面代码的重要部分是 strtol()
的结果。当 next_number
在调用后未更改时,没有更多的输入(或发生错误)。变量 ptr
用于跟踪字符串中解析的位置。它被赋予 strtol()
,它改变 next_number
以指向下一个元素,因此 ptr
向前跳转 - 分配给 next_number
(经过刚刚解析的元素),并且过程重复。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char *number_str = "10 10 10 4 4 4 9 9 9 2";
char *ptr;
char *next_number;
int numbers[1000];
int number_count = 0;
long num;
next_number = number_str;
do
{
ptr = next_number;
num = strtol(ptr, &next_number, 10);
if (ptr != next_number) // found one
{
numbers[number_count] = (int)num;
printf("Stored %3d into numbers[%d]\n", numbers[number_count], number_count);
number_count += 1;
}
} while(ptr != next_number);
return 0;
}
您有三个主要选项 (1) 按预期方式使用 strtol
,使用 *endptr
参数将字符串中的当前读取位置推进到转换的最后一位数字之后, 或 (2) 使用 "%n"
说明符传递给 sscanf
以报告转换为 int
(或任何类型)时使用的字符数,并使用该值推进读取位置以相同的方式;或 (3) 使用 strtok
标记字符串,然后使用 strtol
(因为 atoi
不应该使用,因为它提供绝对零错误检查)。确实没有必要同时使用 strtok
和 strtol
,因为 strtol
已经提供了一种超越转换后数字的方法。您实质上是通过调用 strtok
来复制 strtol
已经完成的工作——但这是一种有效的方法。
例如使用 strtol
你可以做如下的事情:
#include <stdio.h>
#include <stdlib.h> /* for strtol */
#include <string.h> /* for strncpy */
#include <errno.h> /* for errno */
#define MAXC 1024 /* constant - max chars in line */
int main (void) {
char str[MAXC] = ""; /* str to hold line, initialized all zero */
while (fgets (str, MAXC, stdin)) { /* read each line of input */
char *p = str, /* pointer for strtol */
*endptr = NULL; /* end pointer for strtol */
while (*p) { /* work down str parsing integer or hex values */
long val = strtol (p, &endptr, 0); /* convert from p */
/* validate conversion */
if (p != endptr) { /* were digits converted? */
if (!errno) { /* if errno 0, successful conversion */
char ascii[MAXC] = ""; /* for string converted */
strncpy (ascii, p, endptr - p); /* copy to ascii */
ascii[endptr-p] = 0; /* nul-terminate ascii */
/* test whether string begins "0x" or "0X", output */
if (*p == '0' && (*(p + 1) == 'x' || *(p + 1) == 'X'))
printf ("hex conversion: %-10s %10lu 0x%lx\n",
ascii, val, val);
else
printf ("int conversion: %-10s % ld\n",
ascii, val);
}
p = endptr; /* advance p to 1-past end of converted string */
}
/* find start of next valid number in str, including (+/-) */
for (; *p; p++) {
if ('0' <= *p && *p <= '9') /* positive value */
break; /* explicitly signed value */
if ((*p == '+' || *p == '-') && '0' <= *(p+1) && *(p+1) <= '9')
break;
}
}
}
return 0;
}
例子Use/Output
$ echo "10 10 10 4 4 4 9 9 9 2" | ./bin/fgets_strtol_any
int conversion: 10 10
int conversion: 10 10
int conversion: 10 10
int conversion: 4 4
int conversion: 4 4
int conversion: 4 4
int conversion: 9 9
int conversion: 9 9
int conversion: 9 9
int conversion: 2 2
或将所有整数转换成一个杂乱的文件,例如
示例输入文件
$ cat dat/10intmess.txt
8572,;a -2213,;--a 6434,;
a- 16330,;a
- The Quick
Brown%3034 Fox
12346Jumps Over
A
4855,;*;Lazy 16985/,;a
Dog.
11250
1495
例子Use/Output
$ ./bin/fgets_strtol_any <dat/10intmess.txt
int conversion: 8572 8572
int conversion: -2213 -2213
int conversion: 6434 6434
int conversion: 16330 16330
int conversion: 3034 3034
int conversion: 12346 12346
int conversion: 4855 4855
int conversion: 16985 16985
int conversion: 11250 11250
int conversion: 1495 1495
使用sscanf
同样,您可以使用 sscanf
,但请注意,它不提供错误处理的级别或程度——这意味着您只能知道它是成功转换文本还是失败。没有中间,没有通过 errno
报告溢出或下溢。但是,它与 strtok
一起仍然是从一行文本中解析整数的其他有效方法,例如
#include <stdio.h>
#include <stdlib.h>
#define MAXC 1024
int main (int argc, char **argv) {
char buf[MAXC] = ""; /* buffer to hold MAXC chars at a time */
int nval = 0; /* total number of integers found */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
while (fgets (buf, MAXC, fp)) {
char *p = buf; /* pointer to line */
int val, /* int val parsed */
nchars = 0; /* number of chars read */
/* while chars remain in buf and a valid conversion to int takes place
* output the integer found and update p to point to the start of the
* next digit.
*/
while (*p) {
if (sscanf (p, "%d%n", &val, &nchars) == 1) {
printf (" %d", val);
if (++nval % 10 == 0) /* output 10 int per line */
putchar ('\n');
}
p += nchars; /* move p nchars forward in buf */
/* find next number in buf */
for (; *p; p++) {
if (*p >= '0' && *p <= '9') /* positive value */
break;
if (*p == '-' && *(p+1) >= '0' && *(p+1) <= '9') /* negative */
break;
}
}
}
printf ("\n %d integers found.\n", nval);
if (fp != stdin) fclose (fp); /* close file if not stdin */
return 0;
}
例子Use/Output
$ echo "10 10 10 4 4 4 9 9 9 2" | ./bin/fgets_sscanf_int_any_ex
10 10 10 4 4 4 9 9 9 2
10 integers found.
或输入混乱
$ echo "1, 2 buckle my shoe, 3, 4..." | ./bin/fgets_sscanf_int_any_ex
1 2 3 4
4 integers found.
使用 strtok
只是 "front-end" 到第一个示例中显示的 strtol
的转换(它提供了自己的方式来标记数值)。您只需使用 " \n"
分隔符(space 换行符)循环调用 strtok
缓冲区,然后使用 strtol
转换指向的字符串。 (在这里,您只是使用 endptr
来验证数字是否已转换,而忽略了它用于超越转换后的数字。本质上,strtok
重复了 strtok
已经完成的工作,但如果它使它更容易理解,你可以接受重复的调用,没关系。你可以像下面这样做。
while (fgets (buf, MAXC, fp)) {
char *p = buf; /* pointer to buf to use with strtok */
/* 1st call using buffer, all remaining calls using NULL */
for (p = strtok (p, " \n"); p; p = strtok (NULL, " \n")) {
errno = 0; /* reset errno */
char *endptr; /* end pointer */
long tmp = strtol (p, &endptr, 0); /* convert using long */
if (p != endptr) { /* validate digits converted */
/* now validate value within range of int */
if (!errno && INT_MIN <= tmp && tmp <= INT_MAX)
/* you have an integer! */
}
else if (tmp == 0)
/* no digits were converted */
}
}
检查一下,如果您还有其他问题,请告诉我。
我已经为此苦苦挣扎了一段时间,我想我还不如寻求帮助,而不是用头撞墙。
假设您有字符串 "10 10 10 4 4 4 9 9 9 2"
并且你想通过它,一个一个地取出数字并将其添加到一个整数数组中以供使用。
我制作了很多原型,并继续为自己做不必要的工作。起初我使用的是 strtok()
但后来人们说它已被弃用,使用 strsep()
我该怎么做?
如有任何帮助,我们将不胜感激!
我的函数似乎总是 return 一个全为零的 int 数组。这是为什么?
int *parse_line(char *line){
char sNumArray[MAX];
strcpy(sNumArray, line);
char *tokens = NULL;
int *numbers = malloc(sizeof(int) * MAX);
tokens = strtok(sNumArray, " ");
for(int i = 0; ; i++) {
numbers[i] = atoi(tokens);
printf("%d \n", atoi(tokens));
tokens = strtok(NULL, " ");
if (tokens == NULL)
break;
}
return numbers;
}
这些是我在 main 中定义并调用我的函数的变量...
int *skyline;
skyline = parse_line(line);
for (int j = 0; j < 100 ; ++j) {
printf("%d \n", skyline[j]);
}
只需使用 scanf() 在 for 或 while 循环中一一获取每个数字。
for i = 0 to n
scanf(“%d”, &num);
请参阅 google 或 bing 在线搜索它是如何完成的,并提供许多可用示例。
我想这会做你想要的。
#include "stdafx.h"
#include <stdio.h>
#include <iostream>
#include <math.h>
#include <stdlib.h>
using namespace std;
#define MAX 100
int *parse_line(char *line, int *numInts) {
char sNumArray[MAX];
strcpy(sNumArray, line);
int *numbers = (int *) malloc(sizeof(int) * MAX);
char *tokens = strtok(sNumArray, " ");
for (int i = 0; ; i++) {
numbers[i] = atoi(tokens);
tokens = strtok(NULL, " ");
if (tokens == NULL) {
*numInts = i+1;
break;
}
}
return numbers;
}
int main() {
char *line = "10 10 10 4 4 4 9 9 9 2";
int numIntsExtracted = 0;
int *skyline = parse_line(line, &numIntsExtracted);
for (int j = 0; j < numIntsExtracted; ++j) {
printf("%d \n", skyline[j]);
}
return 0;
}
我在 运行 之后得到的输出。
10
10
10
4
4
4
9
9
9
2
我喜欢用函数strtol()
来做这个,因为如果你给它传递一个指针,它会return下一个点继续解析。还有未签名的版本,例如:strtoul()
。它们是 C99 以来的标准。 strtol()
还可以解析十六进制,并且比 atoi()
等旧函数(return 错误时为 0)等旧函数更好地处理错误。
下面代码的重要部分是 strtol()
的结果。当 next_number
在调用后未更改时,没有更多的输入(或发生错误)。变量 ptr
用于跟踪字符串中解析的位置。它被赋予 strtol()
,它改变 next_number
以指向下一个元素,因此 ptr
向前跳转 - 分配给 next_number
(经过刚刚解析的元素),并且过程重复。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
char *number_str = "10 10 10 4 4 4 9 9 9 2";
char *ptr;
char *next_number;
int numbers[1000];
int number_count = 0;
long num;
next_number = number_str;
do
{
ptr = next_number;
num = strtol(ptr, &next_number, 10);
if (ptr != next_number) // found one
{
numbers[number_count] = (int)num;
printf("Stored %3d into numbers[%d]\n", numbers[number_count], number_count);
number_count += 1;
}
} while(ptr != next_number);
return 0;
}
您有三个主要选项 (1) 按预期方式使用 strtol
,使用 *endptr
参数将字符串中的当前读取位置推进到转换的最后一位数字之后, 或 (2) 使用 "%n"
说明符传递给 sscanf
以报告转换为 int
(或任何类型)时使用的字符数,并使用该值推进读取位置以相同的方式;或 (3) 使用 strtok
标记字符串,然后使用 strtol
(因为 atoi
不应该使用,因为它提供绝对零错误检查)。确实没有必要同时使用 strtok
和 strtol
,因为 strtol
已经提供了一种超越转换后数字的方法。您实质上是通过调用 strtok
来复制 strtol
已经完成的工作——但这是一种有效的方法。
例如使用 strtol
你可以做如下的事情:
#include <stdio.h>
#include <stdlib.h> /* for strtol */
#include <string.h> /* for strncpy */
#include <errno.h> /* for errno */
#define MAXC 1024 /* constant - max chars in line */
int main (void) {
char str[MAXC] = ""; /* str to hold line, initialized all zero */
while (fgets (str, MAXC, stdin)) { /* read each line of input */
char *p = str, /* pointer for strtol */
*endptr = NULL; /* end pointer for strtol */
while (*p) { /* work down str parsing integer or hex values */
long val = strtol (p, &endptr, 0); /* convert from p */
/* validate conversion */
if (p != endptr) { /* were digits converted? */
if (!errno) { /* if errno 0, successful conversion */
char ascii[MAXC] = ""; /* for string converted */
strncpy (ascii, p, endptr - p); /* copy to ascii */
ascii[endptr-p] = 0; /* nul-terminate ascii */
/* test whether string begins "0x" or "0X", output */
if (*p == '0' && (*(p + 1) == 'x' || *(p + 1) == 'X'))
printf ("hex conversion: %-10s %10lu 0x%lx\n",
ascii, val, val);
else
printf ("int conversion: %-10s % ld\n",
ascii, val);
}
p = endptr; /* advance p to 1-past end of converted string */
}
/* find start of next valid number in str, including (+/-) */
for (; *p; p++) {
if ('0' <= *p && *p <= '9') /* positive value */
break; /* explicitly signed value */
if ((*p == '+' || *p == '-') && '0' <= *(p+1) && *(p+1) <= '9')
break;
}
}
}
return 0;
}
例子Use/Output
$ echo "10 10 10 4 4 4 9 9 9 2" | ./bin/fgets_strtol_any
int conversion: 10 10
int conversion: 10 10
int conversion: 10 10
int conversion: 4 4
int conversion: 4 4
int conversion: 4 4
int conversion: 9 9
int conversion: 9 9
int conversion: 9 9
int conversion: 2 2
或将所有整数转换成一个杂乱的文件,例如
示例输入文件
$ cat dat/10intmess.txt
8572,;a -2213,;--a 6434,;
a- 16330,;a
- The Quick
Brown%3034 Fox
12346Jumps Over
A
4855,;*;Lazy 16985/,;a
Dog.
11250
1495
例子Use/Output
$ ./bin/fgets_strtol_any <dat/10intmess.txt
int conversion: 8572 8572
int conversion: -2213 -2213
int conversion: 6434 6434
int conversion: 16330 16330
int conversion: 3034 3034
int conversion: 12346 12346
int conversion: 4855 4855
int conversion: 16985 16985
int conversion: 11250 11250
int conversion: 1495 1495
使用sscanf
同样,您可以使用 sscanf
,但请注意,它不提供错误处理的级别或程度——这意味着您只能知道它是成功转换文本还是失败。没有中间,没有通过 errno
报告溢出或下溢。但是,它与 strtok
一起仍然是从一行文本中解析整数的其他有效方法,例如
#include <stdio.h>
#include <stdlib.h>
#define MAXC 1024
int main (int argc, char **argv) {
char buf[MAXC] = ""; /* buffer to hold MAXC chars at a time */
int nval = 0; /* total number of integers found */
FILE *fp = argc > 1 ? fopen (argv[1], "r") : stdin;
if (!fp) { /* validate file open for reading */
fprintf (stderr, "error: file open failed '%s'.\n", argv[1]);
return 1;
}
while (fgets (buf, MAXC, fp)) {
char *p = buf; /* pointer to line */
int val, /* int val parsed */
nchars = 0; /* number of chars read */
/* while chars remain in buf and a valid conversion to int takes place
* output the integer found and update p to point to the start of the
* next digit.
*/
while (*p) {
if (sscanf (p, "%d%n", &val, &nchars) == 1) {
printf (" %d", val);
if (++nval % 10 == 0) /* output 10 int per line */
putchar ('\n');
}
p += nchars; /* move p nchars forward in buf */
/* find next number in buf */
for (; *p; p++) {
if (*p >= '0' && *p <= '9') /* positive value */
break;
if (*p == '-' && *(p+1) >= '0' && *(p+1) <= '9') /* negative */
break;
}
}
}
printf ("\n %d integers found.\n", nval);
if (fp != stdin) fclose (fp); /* close file if not stdin */
return 0;
}
例子Use/Output
$ echo "10 10 10 4 4 4 9 9 9 2" | ./bin/fgets_sscanf_int_any_ex
10 10 10 4 4 4 9 9 9 2
10 integers found.
或输入混乱
$ echo "1, 2 buckle my shoe, 3, 4..." | ./bin/fgets_sscanf_int_any_ex
1 2 3 4
4 integers found.
使用 strtok
只是 "front-end" 到第一个示例中显示的 strtol
的转换(它提供了自己的方式来标记数值)。您只需使用 " \n"
分隔符(space 换行符)循环调用 strtok
缓冲区,然后使用 strtol
转换指向的字符串。 (在这里,您只是使用 endptr
来验证数字是否已转换,而忽略了它用于超越转换后的数字。本质上,strtok
重复了 strtok
已经完成的工作,但如果它使它更容易理解,你可以接受重复的调用,没关系。你可以像下面这样做。
while (fgets (buf, MAXC, fp)) {
char *p = buf; /* pointer to buf to use with strtok */
/* 1st call using buffer, all remaining calls using NULL */
for (p = strtok (p, " \n"); p; p = strtok (NULL, " \n")) {
errno = 0; /* reset errno */
char *endptr; /* end pointer */
long tmp = strtol (p, &endptr, 0); /* convert using long */
if (p != endptr) { /* validate digits converted */
/* now validate value within range of int */
if (!errno && INT_MIN <= tmp && tmp <= INT_MAX)
/* you have an integer! */
}
else if (tmp == 0)
/* no digits were converted */
}
}
检查一下,如果您还有其他问题,请告诉我。