如何将一串数字解析为整数数组?

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 不应该使用,因为它提供绝对零错误检查)。确实没有必要同时使用 strtokstrtol,因为 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 */
        }
    }

检查一下,如果您还有其他问题,请告诉我。