【问题标题】:Strict atoi/strtol function严格的 atoi/strtol 函数
【发布时间】:2020-07-25 09:43:44
【问题描述】:

当我在 C 中使用时:

int x = 0;
char str[] = " \t123abc";
x = atoi(str);
printf("%d\n", str); //123

123 被打印出来。我想知道如果字符串不完全是整数,是否有一个“严格”的 C 函数返回 0。 (我不关心数字符号(总是正数)和底数(总是 10))。

一些例子:

" \t123abc" -> 0
" 123abc" -> 0
"123abc" -> 0
" 123 " -> 0
"123" -> 123
"123\n" -> 0

目前我创建了一个int sstoi (char *str) 函数来执行此操作:

static const unsigned int pow10[10] = {1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000};

int sstoi (char *str) {
    int result = 0, length = strlen(str);
    char c;
    if (length > 10) return 0;
    for (int i = 0; i < length; i++) {   
        c = str[i];
        if (c < 48 || c > 57) return 0;
        result += (c-48)*pow10[length-i-1];
    }
    return result;
}

我认为应该改进:有人可以帮助我吗?

【问题讨论】:

  • 无需使用 10 的幂。只需转到 result = result * 10 + (c - '0')。最好不要使用幻数,注意我使用了'0'length &gt; 10 约束太松,因为值仍然可以溢出 32 位。
  • 使用strtol()。检查字符串不为空且没有前导空格,然后让strtol() 设置一个指向第一个无效字符的指针——如果它指向终止的 null,则整个字符串是好的。

标签: c type-conversion


【解决方案1】:

您可以先检查字符串中的所有字符是否都是数字,然后使用 atoi:

if(strspn(str, "0123456789") == strlen(str))
{
   x = atoi(str);
}
else
{
  x = 0;
}

【讨论】:

  • 这不会遍历strspnstrlenatoi 的每个字符,在我的方法中针对2 个循环(strlenfor)进行3 个循环吗?对于“大”整数,这种方法不会慢一些吗?只是问,因为我只是想学习如何提高我的代码效率:)
  • str[strspn(str, "0123456789")] == 0 避免使用 strlen
【解决方案2】:

strtol() 可以设置一个指针,指向它扫描的字符串中的第一个无效字符,这将是数字之后的第一个字符。如果你检查第一个字符是否有效,你可以使用这个指针来查看数字后面是否有字符。

int sstoi(char *s) { 
    char *ep; // to point to first char after the number

    if (isdigit(*s)) { // make sure first char is a digit

        // convert, and find first invalid char
        int x = strtol(s, &ep, 10); 

        // return conversion if first invalid char was the
          // terminating null
        if (!(*ep)) 
            return x;
    } 
    return 0; // otherwise return 0
}

【讨论】:

  • 这看起来基本正确,但我建议两个警告。首先,如果 strtol 的结果不适合 int(它返回 long int),您将获得实现定义的行为。其次,如果值超出 long int 的范围,strtol 返回 LONG_MAX 或 LONG_MIN,这可能是也可能不是这里的预期行为。
  • (我还认为sstoi 应该是常量正确的,即取一个const char *
【解决方案3】:

我找不到直接返回0的内置函数,输入错误。

您可以使用内置函数isdigit(char s) 来检查给定的输入是否有效,如果不是,则返回0。

#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdbool.h> 

bool isValidNumber(char digitsArray[]){
    bool isNumber = true;
    for(int i=0; i < strlen(digitsArray); i++){
        if(!isdigit(digitsArray[i])){
            isNumber = false;
            break;
        }
    } 
    return isNumber;
}

int getNumber(char digitsArray[]){
    if(isValidNumber(digitsArray)){
        return atoi(digitsArray);
    }
    return 0;
}

int main()
{
    char str[] = "123\n";
    int number = getNumber(str);
    printf("Number is %d", number);
    return 0;
}

编辑:如果 char[] 数组包含负数,isValidNumber 将不起作用。

【讨论】:

  • isValidNumber 在运行时意外地是二次方的,如果digitsArray 包含任何负值(因为isdigit),则会表现出未定义的行为。
  • 嘿@PaulHankin,感谢您解释代码失败的情况。
猜你喜欢
  • 2021-10-08
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-11-07
  • 2012-05-21
  • 1970-01-01
相关资源
最近更新 更多