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

时间:2018-11-20 01:25:51

标签: c arrays string parsing c99

我已经为此苦苦挣扎了一段时间,并认为我最好还是寻求帮助,而不是将自己的头撞到墙上。

因此,假设您有字符串"10 10 10 4 4 4 9 9 9 2" 然后您要遍历,将数字一一取出,然后将其添加到要使用的整数数组中。

我已经制作了很多原型,并继续为自己做更多不必要的工作。起初我使用的是strtok(),但后来人们说那已经过时了,使用strsep()

会更容易

我该怎么做?

任何帮助将不胜感激!

我的函数似乎总是返回一个充满零的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]);
}

4 个答案:

答案 0 :(得分:3)

您有三个主要选择(1)按预期的方式使用strtol,使用*endptr参数将字符串中的当前读取位置前进到转换的最后一位数字之后,或者(2)使用sscanf说明符传递给"%n",以报告在转换为int(或任何类型)中使用的字符数,并使用该值来提高读取位置。同样的方式或(3)用strtok标记字符串,然后使用strtol(因为atoi不能使用,因为它提供了绝对零错误检查)。确实没有必要同时使用strtokstrtol,因为strtol已经提供了一种方法来超越转换后的数字。本质上,您是通过调用strtol复制strtok已经完成的工作,但这是一种有效的方法。

例如,使用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;
}

使用/输出示例

$ 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

使用/输出示例

$ ./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;
}

使用/输出示例

$ 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只是第一个示例中显示的strtol转换的“前端”(它提供了自己的标记数字值的方法)。您只需使用strtok(空格换行符)的分隔符循环调用" \n"的缓冲区,然后使用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 */
        }
    }

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

答案 1 :(得分:0)

我认为这将满足您的要求。

#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

答案 2 :(得分:0)

我喜欢为此使用功能strtol(),因为如果将指针传递给它,它将返回下一个点以继续解析。也有未签名的版本,例如:strtoul()。自C99以来,它们是标准配置。此外,strtol()可以解析十六进制,并且比atoi()之类的旧函数(错误返回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;
}

答案 3 :(得分:-5)

只需使用scanf()在for或while循环中一个一个地获取每个数字即可。

for i = 0 to n
scanf(“%d”, &num);

请通过许多示例向Google或bing在线查询google或bing搜索。