有没有可以将从char数组输入的数字转换为int数组的函数?

时间:2019-01-23 02:30:27

标签: c arrays char

我试图通过重载函数传递数组。数组是一串用空格分隔的数字。我正在尝试将char数组转换为int数组,因为我有另一个函数被指向char的指针调用。

这是我当前的解决方案。我试图将每个元素分别复制到一个int数组,但是当我尝试从该数组读取时,我得到了一堆垃圾数字。 它会传递到我创建的正确的重载函数中。

  char str[100];             //string with inputted ints
int numStr[100];
int i = 0;
int count = 0;

fgets(str, 100, stdin);

while (str[i] != '\0')
{
    if (str[i] == ' ')
    {
        count++;
    }
    i++;
}
if (count >= 1)       //checks if there is more then one int
{
    for (int i = 0; str[i] != '\0'; i++)
    {
        numStr[i] = str[i];
        numStr[i] = numStr[i] - '/0';
    }
    printf("Going into the int array function\n");
    assessGrade(numStr);    //passing int array
}

程序应获取空格之间的每个数字,以一起复制到另一个int数组中。

4 个答案:

答案 0 :(得分:1)

char str[100];
int numStr[100]; 
char *token;
int count = 0;
int spaceCounter = 0;

fgets(str, 100, stdin);

int i = 0;
while (str[i] != '\0')
{
    if (str[i] == ' ')
    {
        spaceCounter++;
    }
    i++;
}
if (spaceCounter >= 1)       //checks if there is more then one int
{
    token = strtok(str, " ");

    while (token != NULL)
    {
        //printf("%s \n", token);
        numStr[count] = atoi(token);
        token = strtok(NULL, " ");
        count++;
    }
 }

答案 1 :(得分:0)

让您简化问题。

首先假设我们有一个保存数字的char数组:char str[100]="1 2 3 4 5 6";,而不是从输入中填充它。

执行此操作,并进行一些小的更改:


代码

char str[100]="1 2 3 4 5 6";             //string with inputted ints
int numStr[100]={0};
int i = 0;
int count = 0;

while (str[i] != '\0')
{
    if (str[i] != ' ')
    {
        numStr[count]=str[i]-'0';
        count++;
    }
    i++;
}   
for (int i = 0; i<count; i++)
{
    printf("%d ", numStr[i]);
}

现在,我们在numStr整数数组中从 [0:count] 索引了数字。

答案 2 :(得分:0)

#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>

long *numbersToArray(const char *str, long *len) {
    const char *pos;
    char *endptr;
    long size, count, *ret, *tmp;
    size = 4;
    count = 0;
    ret = calloc(size, sizeof(long));
    if (!ret) return NULL;
    pos = str;
    while (isspace(pos[0])) ++pos;
    while (pos[0]) {
        if (count == size) {
            size += 4;
            tmp = realloc(ret, size * sizeof(long));
            if (tmp) ret = tmp;
            else {
                free(ret);
                return NULL;
            }
        }
        ret[count] = strtol(pos, &endptr, 0);
        // if (errno) ...
        ++count;
        pos = endptr;
        while (isspace(pos[0])) ++pos;
    }
    if (len) *len = count;
    return ret;
}

int main(int argc, char **argv) {
    if (argc < 2) {
        printf("usage: %s numbers\n", argv[0]);
        return 0;
    }
    long *arr, len, i;
    arr = numbersToArray(argv[1], &len);
    for (i = 0L; i < len; ++i) {
        printf("%ld\n", arr[i]);
    }
    return 0;
}

答案 3 :(得分:0)

从您可以将缓冲区中的任何整数值表示形式转换为整数的评论继续,没有strtol的替代品。虽然您可以使用sscanf%n指定符来获取消耗的字符数,以知道将指针前进多少?为什么?除了成功/失败以外,您的任何scanf转换都几乎没有错误报告功能。 strtol具有内置功能,可以处理缓冲区,随时随地将值转换为long

如何? strtol的原型为:

long int strtol(const char *nptr, char **endptr, int base);

nptr提供包含数字的字符串的情况下,endptr将被设置为成功转换后使用的最后一位数字之后的一个字符,而base提供了转换的次数(例如基数2, 8, 10, 16等。),0的基数将允许从八进制,十进制或十六进制转换,具体取决于字符串表示形式是0(八进制)或0x(十六进制)或1-9(十进制)。

因此,如果给strtol一个包含数字的字符串,则在成功转换后,返回的是一个long值,可以对INT_MIN/INT_MAX进行测试以确定其是否在范围内int中的endptr将设置为转换后的最后一位数字之后的数字(设置为用于下一个值),并且您需要设置的所有内容p = endptr;并继续操作。

此外,您知道转换后是否nptr == endptr -没有数字被转换。 strtol还将errno设置为上溢/下溢,因此您有一种方法可以验证是否成功转换为long。此外,如果要检查接下来要做什么,endptr指向缓冲区中其余内容的开始字符。您知道角色所发生的转换以及剩余的转换。

那么您如何使用它呢?这真的很简单。首先,我们为数组中的整数数和缓冲区中的最大字符数定义几个常量,例如

#include <stdio.h>
#include <stdlib.h> /* for strtol   */
#include <limits.h> /* for INT_MIN/INT_MAX */
#include <errno.h>  /* for errno    */

#define ARSZ  100
#define MAXC 1024

现在声明您的数组,用于保存输入的缓冲区以及用于跟踪转换并存储在数组中的整数值数量的计数器:

    int arr[ARSZ] = {0};
    char buf[MAXC] = "";
    size_t n = 0;

现在让我们打开一个文件,以文件名作为程序的第一个参数(如果没有提供参数,则默认从stdin读取)进行读取,并验证我们是否有有效的打开文件流,例如< / p>

    /* 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;
    }

现在是时候开始阅读输入行并使用long将任何字符引用转换为数字值到strtol了。首先,使用fgets在缓冲区中读取一行输入,并声明nptr(缩写为p),endptr和一个临时long值{{ 1}}来保存tmp的收益,例如

strtol

使用一行输入,您现在开始使用 while (fgets (buf, MAXC, fp)) { /* read each line of input */ char *p = buf, *endptr; /* nptr & endptr for strtol */ long tmp; /* temp long for strtol */ 循环转换值,验证(1)个数字是否已转换,(2)没有上溢/下溢发生(例如,值适合{{1}) }),(3)该值在strtol的范围内,或(4)警告该值超出long的大小。 (我们稍后将讨论int辅助函数):

int

注意nextdigit循环 /* protect array bounds, loop while not end of buf */ while (n < ARSZ && *p && *p != '\n') { errno = 0; /* reset errno each iteration */ tmp = strtol (p, &endptr, 0); /* call strtol, update endptr */ if (p == endptr) /* validate digits converted */ fputs ("error: no digits converted.\n", stderr); else if (errno) /* validate conversion */ fputs ("error: over/underflow occurred.\n", stderr); /* validate tmp is in range of integer */ else if (INT_MIN <= tmp && tmp <= INT_MAX) arr[n++] = tmp; else fputs ("error: value exceeds range of int.\n", stderr); if (!(p = (char *)nextdigit (endptr))) /* get next digit */ break; } 的条件-存储的整数不会超出您的空间,而while(您不能在字符串的末尾(例如 nul-character 或换行符)。您可以省略换行符检查,它将在循环体中无害地处理,但是为什么呢?检查完全避免了循环的主体)

n < ARSZ辅助函数是什么?通过阅读strtol(3) - Linux manual page,您知道*p && *p != '\n'会跳过所有前导空格,直到下一个要转换的数字的开头,但是如果您有逗号分隔的文件或其他字符,该怎么办?你的电话号码?操作非常简单,只需向前扫描缓冲区,边走边检查字符,直到找到下一个nextdigit(),或者找到下一个strtol,并且显式符号后的下一个字符是{{ 1}}。

这就是0-9的全部工作,返回要转换的下一个值的开头的地址,或者如果没有其他要转换的数字,则返回+/-

0-9

注意:,您可以并且应该包含nextdigit并用简单的NULL代替/* scan forward in 'p' to find next valid signed integer beginning */ const char *nextdigit (const char *p) { while (*p) { if (('0' <= *p && *p <= '9') || ((*p == '-' || *p == '+') && '0' <= *(p + 1) && *(p + 1) <= '9')) return p; p++; } return NULL; } 的支票,而用{{ 1}},但出于说明目的显示了完整的手动测试)

在代码中请注意如何将ctype.h(向前扫描的起始地址)传递到('0' <= *p && *p <= '9'),并将结果分配给isdigit(*p)并未经{{1}验证},直到下一次迭代开始(isdigit(*(p+1))已准备好再次传递到endptr进行下一次转换)之前,请冲洗并重复操作,直到缓冲区中的字符用完为止。

采用这种方式将缓冲区转换为整数值的方法,使您可以选择并转换行中的所有整数值-不管格式如何混乱。

完全将其放入您可以做的事情:

nextdigit()

现在让我们看一下这种方法可以处理的转换为整数值的行,例如

示例输入文件

以空格分隔的值:

p

换行符分隔的值:

NULL

一团糟的整数:

p

使用/输出示例

转换例程如何公平?

以空格分隔:

strtol

换行符分隔:

#include <stdio.h>
#include <stdlib.h> /* for strtol   */
#include <limits.h> /* for INT_MIN/INT_MAX */
#include <errno.h>  /* for errno    */

#define ARSZ  100
#define MAXC 1024

/* scan forward in 'p' to find next valid signed integer beginning */
const char *nextdigit (const char *p)
{
    while (*p) {
        if (('0' <= *p && *p <= '9') || 
            ((*p == '-' || *p == '+') && '0' <= *(p + 1) && *(p + 1) <= '9'))
            return p;
        p++;
    }
    return NULL;
}

int main (int argc, char **argv) {

    int arr[ARSZ] = {0};
    char buf[MAXC] = "";
    size_t n = 0;
    /* 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 of input */
        char *p = buf, *endptr;         /* nptr & endptr for strtol */
        long tmp;                       /* temp long for strtol */

        /* protect array bounds, loop while not end of buf */
        while (n < ARSZ && *p && *p != '\n') {
            errno = 0;                      /* reset errno each iteration */
            tmp = strtol (p, &endptr, 0);   /* call strtol, update endptr */

            if (p == endptr)    /* validate digits converted */
                fputs ("error: no digits converted.\n", stderr);
            else if (errno)     /* validate conversion */
                fputs ("error: over/underflow occurred.\n", stderr);
            /* validate tmp is in range of integer */
            else if (INT_MIN <= tmp && tmp <= INT_MAX)
                arr[n++] = tmp;
            else
                fputs ("error: value exceeds range of int.\n", stderr);

            if (!(p = (char *)nextdigit (endptr)))  /* get next digit */
                break;
        }
    }
    if (fp != stdin) fclose (fp);   /* close file if not stdin */

    for (size_t i = 0; i < n; i++) {    /* output results */
        if (i && i %10 == 0)            /* 10-values per row */
            putchar ('\n');
        printf (" %4d", arr[i]);
    }
    putchar ('\n');     /* tidy up with newline */
}

邪恶的混乱:

$ cat dat/10int_space.txt
8572 -2213 6434 16330 3034 12346 4855 16985 11250 1495

所有值,无论是空格分隔,换行符分隔还是散落在“一只快速的棕色狐狸...”中间,都已正确转换。

花些时间来摘要$ cat dat/10int_nl.txt 8572 -2213 6434 16330 3034 12346 4855 16985 11250 1495 的手册页,然后再摘要上面的实现方法。一旦您掌握了$ 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_fixed <dat/10int_space.txt 8572 -2213 6434 16330 3034 12346 4855 16985 11250 1495 (对于$ ./bin/fgets_strtol_any_fixed <dat/10int_nl.txt 8572 -2213 6434 16330 3034 12346 4855 16985 11250 1495 ),$ ./bin/fgets_strtol_any_fixed <dat/10intmess.txt error: no digits converted. error: no digits converted. error: no digits converted. error: no digits converted. error: no digits converted. 8572 -2213 6434 16330 3034 12346 4855 16985 11250 1495 (对于strtol)等等,它们的工作原理几乎都相同,几乎没有数字转换无法处理。如果您还有其他问题,请告诉我。