在C语言中将字符数组转换为整数

43

我想要将一个char数组[]转换为:

char myarray[4] = {'-','1','2','3'}; //where the - means it is negative

在C语言的标准库中,应该是这个整数:-1234。我找不到任何优雅的方法来实现它。

我可以肯定地添加'\0'。


3
  1. 你缺少了 4
  2. 你的数组是否有空终止符?
- MByD
2
可能存在将额外的 '\0' 添加到数组末尾的可能性吗?那样我们就不用花太多时间了。 - Mr Lister
8
因为没有任何方法可以将字符串转换为整数。但是对于以null结尾的字符串,有一些方法可供使用。atoistrtol是其中的两个选项。例如:char myarray[] = {'-','1','2','3','4',0}; int i = atoi(myarray); - falstro
@roe 你可能会把最后一个变成答案 :) - Eregrith
3
不要显式地加上 '\0',让编译器自己来处理:char myarray[] = "-1234"; - Jerry Coffin
5个回答

95

我个人不太喜欢使用atoi函数。我建议使用sscanf函数:

char myarray[5] = {'-', '1', '2', '3', '\0'};
int i;
sscanf(myarray, "%d", &i);

非常标准,它在stdio.h库中 :)

而且在我看来,与 atoi 相比,它允许您更多的自由度,可以任意格式化数字字符串,并且可能还允许在末尾加入非数字字符。

编辑 我刚刚在这个网站上找到了一个精彩的问题,它解释并比较了3种不同的方法 - atoisscanfstrtol。此外,还有一个关于sscanf(实际上是整个*scanf函数族)的详细见解。

编辑2 看起来并不只是我个人不喜欢atoi函数。这里有一个链接,其中解释了atoi函数已被弃用,不应在新代码中使用。


5
degustibus... sscanf增加了整个不必要的开销到一个微不足道的任务上(变量列表参数,格式字符串解析),而且在我看来更容易出错。对于简单的任务,我更喜欢使用简单的函数(例如atoi就是为此而存在的)。 - BigMike
2
废弃atoi的唯一原因与线程安全有关,对于简单任务,strtol仍然优于sscanf。重点不是使用atoi或int foo(char *)而是使用一个简单的函数来对抗复杂的函数。其余部分只是品味问题。sscanf确实可以完成它的工作,但在这样的简单任务上浪费了。当我学习编程时,节省4/5个时钟周期是必须的。如果更多人坚持这一点,现在的应用程序将以光速运行。 - BigMike
12
你认为 sscanf 如何解析 %d?它调用了 atoi,所以无论如何都是杀鸡焉用牛刀。 - Eregrith
非常好,像“pit_t”类型,sscanf对我来说非常好。atoi不行。 - kangear
4
@BigMike:废弃atoi的原因是它会默默失败。虽然没有静态缓冲区会导致线程安全问题,但在这里使用strtol确实是正确的函数。 - Ben Voigt
显示剩余2条评论

15

为什么不直接使用 atoi 呢?例如:

char myarray[4] = {'-','1','2','3'};

int i = atoi(myarray);

printf("%d\n", i);
给出了我期望的结果:
-123

更新:为什么不行-字符数组没有以空字符结尾。天啊!


7
不是一个好的选择。它只是凭运气成功了。数组没有以空字符结尾,所以使用atoi可能会得出不可预测的结果。 - BigMike
是的。我刚意识到了。;-) - Rich Drummond
谢谢!我漏了 '\0'。我正在使用动态数组,所以我只是添加了一个额外的位置。 - SpcCode

4

不需要把字符数组转换为字符串,直接处理字符数组本身并不难,特别是在已知字符数组长度或可以轻易获取的情况下。使用字符数组时,必须在与数组定义相同的作用域中确定其长度,例如:

size_t len sizeof myarray/sizeof *myarray;

当涉及到字符串时,你当然可以使用strlen函数来计算长度。

一旦确定了长度,无论是字符数组还是字符串,你都可以使用下面类似的简短函数将字符值转换为数字:

/* convert character array to integer */
int char2int (char *array, size_t n)
{    
    int number = 0;
    int mult = 1;

    n = (int)n < 0 ? -n : n;       /* quick absolute value check  */

    /* for each character in array */
    while (n--)
    {
        /* if not digit or '-', check if number > 0, break or continue */
        if ((array[n] < '0' || array[n] > '9') && array[n] != '-') {
            if (number)
                break;
            else
                continue;
        }

        if (array[n] == '-') {      /* if '-' if number, negate, break */
            if (number) {
                number = -number;
                break;
            }
        }
        else {                      /* convert digit to numeric value   */
            number += (array[n] - '0') * mult;
            mult *= 10;
        }
    }

    return number;
}

上面是标准的字符转整数的方法,其中包含一些额外的条件。为了处理杂散的字符,除了数字和'-'之外,唯一的技巧就是在何时开始收集数字以及何时停止时做出明智的选择。
如果你在遇到第一个数字时开始收集数字进行转换,那么当你遇到第一个'-'或非数字时,转换就会结束。这使得转换在像(file_0127.txt)这样的索引中更加方便。
以下是一个简短的使用示例:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int char2int (char *array, size_t n);

int main (void) {

    char myarray[4] = {'-','1','2','3'}; 
    char *string = "some-goofy-string-with-123-inside";
    char *fname = "file-0123.txt";

    size_t mlen = sizeof myarray/sizeof *myarray;
    size_t slen = strlen (string);
    size_t flen = strlen (fname);

    printf ("\n myarray[4] = {'-','1','2','3'};\n\n");
    printf ("   char2int (myarray, mlen):  %d\n\n", char2int (myarray, mlen));

    printf (" string = \"some-goofy-string-with-123-inside\";\n\n");
    printf ("   char2int (string, slen) :  %d\n\n", char2int (string, slen));

    printf (" fname = \"file-0123.txt\";\n\n");
    printf ("   char2int (fname, flen)  :  %d\n\n", char2int (fname, flen));

    return 0;
}

注意:当面对以'-'分隔的文件索引(或类似情况)时,需要您对结果进行否定处理。(例如:file-0123.txtfile_0123.txt进行比较,前者将返回-123,而后者将返回123)。

示例输出

$ ./bin/atoic_array

 myarray[4] = {'-','1','2','3'};

   char2int (myarray, mlen):  -123

 string = "some-goofy-string-with-123-inside";

   char2int (string, slen) :  -123

 fname = "file-0123.txt";

   char2int (fname, flen)  :  -123
注意: 总会有一些特殊情况等问题可能导致程序出现错误。本方法无法在所有字符集中都百分之百地保证有效,但通常情况下可以解决大多数问题,并且可以提供更高的转换灵活性,而不需要像 atoistrtol 那样需要进行初始解析或字符串转换。

2

因此,这个想法是将字符数字(用单引号表示,例如'8')转换为整数表达式。例如 char c = '8'; int i = c - '0' // 将得到整数8;然后按照908=9*100+0*10+8的原则,在循环中将所有转换后的数字相加。

char t[5] = {'-', '9', '0', '8', '\0'}; //Should be terminated properly.

int s = 1;
int i = -1;
int res = 0;

if (c[0] == '-') {
  s = -1;
  i = 0;
}

while (c[++i] != '\0') { //iterate until the array end
  res = res*10 + (c[i] - '0'); //generating the integer according to read parsed numbers.
}

res = res*s; //answer: -908

如果你添加了'\0',最好使用标准库(请参见其他答案)。如果你无法获得终止NUL字节(循环条件已更改),则可以使用此方法。 - hyde
是的,我想出了一种不使用库的方法。 - Otar Magaldadze
当我感到懒惰时,我会使用标准库,当涉及到整数时,我总是采用这种方法。 - milevyo
假设除了{'-','+','0-9',\0}之外没有其他字符; - milevyo

0

这不是问题所问的,但我使用了 @Rich Drummond 的答案来从 stdin 中读取一个以 null 结尾的 char 数组。

char *buff;
size_t buff_size = 100;
int choice;
do{
    buff = (char *)malloc(buff_size *sizeof(char));
    getline(&buff, &buff_size, stdin);
    choice = atoi(buff);
    free(buff);
                    
}while((choice<1)&&(choice>9));

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接