在 C 中的 argv[1] 上使用 atoi() 时算术溢出

Posted

技术标签:

【中文标题】在 C 中的 argv[1] 上使用 atoi() 时算术溢出【英文标题】:Arithmetic overflow when using atoi() on argv[1] in C 【发布时间】:2014-02-18 16:59:30 【问题描述】:

我正在使用 atoi(argv[1]) 这是我的代码的 sn-p

void main(int argc, char* argv[])


    int evenOrOdd = 0;
    int inputtedNum = 0;

    pid_t  pid;
    int    i;
    char   buf[BUF_SIZE];

    if (argc != 2)//make sure user has input correctly entered
    
        printf("Please use input: ./a.out #\n");
    
    else
    
        inputtedNum = atoi(argv[1]);
        if(inputtedNum < 0) //make sure number is positive
        
            printf("Please use a positive number.\n");
            return;
        
    
    // ...

代码继续运行等等,但是当输入一些数字时,它有时会认为它们是负数。如果我输入 123456789 它将没有问题并正确运行程序。如果我输入 12345678910 它会认为该数字是负数。我是否在这里遇到了一些缓冲区错误,导致负标志失败?我不太确定如何解决它。

感谢所有帮助!

【问题讨论】:

12345678910 超出了 int32_t 的范围。 您的整数很可能是 32 位,这仅允许它包含最多 2^31-1 的数字。 谢谢约阿希姆。原来这是我的最高数字。 用strtol来检查errno如果你要测试转换结果是否溢出。预计可以输入的范围是多少? 【参考方案1】:

int 是一个比较窄的整数类型,也是一个有符号类型。对inputtedNumstrtoul(argv[1], 0, 0) 使用unsigned long 来解析数字。

【讨论】:

unsigned long 只会将正数范围从2G增加到4G,所以对于12345678910这样的数字并不能解决问题。 尝试更改为 unsigned long 并使用 strtoul,但并没有像 barak manos 所说的那样工作。 然后查阅手册,发现你可以使用unsigned long longstrtoull。如果这不起作用,您的数字对于您计算机上的整数类型来说太大了。【参考方案2】:

在大多数编译器上,C 中支持的最大非负整数类型是 64 位无符号整数。

12345678910 不能存储在您正在使用的int 类型中,即使它是unsigned long

您可以通过将argv[1] 中的输入字符串“分割”为两个字符串来解决此问题,当它超过8 位时,在每个字符串上使用atoi,并将结果组合成一个unsigned long long 变量。

这会将您的正数范围从大约 40 亿扩展到最大的 16 位十进制数字。

来自main,致电readNum(argv[1])

unsigned long long readNum(const char* input)

    int length = strlen(input);
    if (length <= 8)
    
        return atoi(input);
    
    else if (length <= 16)
    
        char str1[8+1] = 0;
        char str2[8+1] = 0;
        memcpy(str1,input,8);
        memcpy(str2,input+8,length-8);
        return 100000000ULL*atoi(str1)+atoi(str2);
    
    return 10000000000000000ULL; // Invalid input

请记住,要打印unsigned long long,您需要使用printf%llu

【讨论】:

您的第一个陈述在大多数当前 CPU 上实际上是正确的,但不是标准的正确表征。我怀疑有些 CPU uintmax_t 是 128 位;如果没有,不难想象这样的机器。 嗯,正确。此外,unsigned long 本身在某些编译器上可能是 64 位...不过,我相信当前问题的主要焦点是实际的字符串到数字的转换,而不是 C 中类型的官方标准。所以我选择专注于转换问题的解决方案,而不是根据 C 编译器的标准来关注每种类型的大小。

以上是关于在 C 中的 argv[1] 上使用 atoi() 时算术溢出的主要内容,如果未能解决你的问题,请参考以下文章

int main(int argc, char* argv[]) 和线程 1: EXC_BAD_ACCESS (code=1, address=0x0) with atoi(argv[1]);在 Xc

argc atoi argv,Opencv,C++ [关闭]

我们可以在c中使用带有字符串的switch-case语句吗? [重复]

代码示例_C提高_main

C - 检查给定参数是不是为自然数

我可以在C ++中的运行时初始化静态const成员吗?