关于atoi和strtol函数

提示:文章

文章目录

前言

前期疑问:
本文目标:


一、背景

最近在牛课题HJ33 整数与IP地址间的转换题目时,涉及到大量的字符串和整型数值的转换,重新看一下字符和整型转换的函数

二、

2.1 ​

避免使用atoi、atol、atoll、atof函数

字符串中可能不含数字、含有其他字符或含有超出表示范围的数字,因
此,将字符串转换为数值时,必须检测并解决这些错误情况。
如果使用C标准库函数做字符串到数值的转换,应当使用 strtol()、strtoll()、
strtod()等函数,代替atoi()、atol()、atoll()、atof()等函数,主要原因如下:
atoi()、atol()、atoll()、atof()系列函数。当字符串转换的结果无法表示成相
应的数值时,会导致程序产生未定义行为,并且未提供足够的出错信息;
strtol()、strtoll()、strtod()系列函数。这些函数能够完成与上一组函数相同
的功能,函数行为是确定的,并且提供了更多的错误检测能力。

int main()
{
    /*case1*/
    char str[1] = {'\0'};
    char *ptr = NULL;
    int num = 102;
    ptr = itoa(num, str, 10);
    printf("%s\n", str);      //打印102   //但是这边已经数据越界了,申请的字符串数组长度不够          
                                         //str[0]:1  str[1]:0 ...  之所以可以打印是因为        
                                         //没有其他数据在申请这段内存,
                                         //或者这里数组越界更改这段内存会导致系统崩溃
    printf("%s\n", ptr);     //打印102

    
    /*case2*/
    char str2[] = "50Y";
    int numStr2 = atoi(str2);
    printf("%d\n", numStr2);        //打印50

    char str3[] = "Y50Y";
    int numStr3 = atoi(str3);    
    printf("%d\n", numStr3);        //打印0

    char str4[] = "Y50Y";
    char *ptr4 = NULL;
    int numStr4 = strtol(str4, &ptr4, 10);    

    if(ptr4 == str4 )
    {
        if(*ptr4 != '\0')
        {
            int a = 0;
        }
        int h = 0;
        //
    }
    printf("%d\n", numStr4);        //打印Y50Y
    printf("%s\n", ptr4);

    char str5[] = "1234This stopped it";
    char *ptr5 = NULL;
    int numStr5 = strtol(str5, &ptr5, 10);

    if(ptr5 == str5 )
    {
        if(*ptr5 != '\0')
        {
            int a = 0;
        }
        int h = 0;
        //
    }
    printf("%d\n", numStr5);
    printf("%s\n", ptr5);


    return 0;
}

2023年6月1日20:23:46

在数值翻转的题目中

int main()
{
    int x = 123;
    int x2 = 123;
    char charx[] = {'\0'};
    char charx2[] = {'\0'};
    //char* p = itoa(x, charx, 10);
    sprintf(charx2, "%d", x2);
//    printf("%s\n",charx);
//    printf("%s\n",p);
    printf("%s\n",charx2);
    getchar();

    return 0;
}

这边需要补充的是,itoa是windows独有的函数,如果要跨平台,可以使用sprintf。

即:itoa并不是一个标准的C函数,它是Windows特有的,如果要写跨平台的程序,需要用sprintf。C标准库中有sprintf,功能比这个更强,用法跟printf类似

2023年9月28日16:59:09更新

itoa 是一些编译器支持的非标准函数。根据错误,您的编译器不支持它。最好的选择是使用 snprintf() 来代替。
char str[255];
sprintf(str, “%x”, 100); //将100转为16进制表示的字符串。

2.2

三、# C 库函数 - strtol()

C 标准库

描述

C 库函数 *long int strtol(const char *str, char *endptr, int base) 把参数 str 所指向的字符串根据给定的 base 转换为一个长整数(类型为 long int 型),base 必须介于 2 和 36(包含)之间,或者是特殊值 0。

声明

下面是 strtol() 函数的声明。

long int strtol(const char *str, char **endptr, int base)

参数

  • str – 要转换为长整数的字符串。
  • endptr – 对类型为 char* 的对象的引用,其值由函数设置为 str 中数值后的下一个字符。
  • base – 基数,必须介于 2 和 36(包含)之间,或者是特殊值 0。如果 base 为 0,则会根据字符串的前缀来判断进制:如果字符串以 ‘0x’ 或 ‘0X’ 开头,则将其视为十六进制;如果字符串以 ‘0’ 开头,则将其视为八进制;否则将其视为十进制。

返回值

函数返回被转换的长整型整数值。如果输入字符串不符合数字格式,strtol() 将返回 0。如果转换结果超出了 long 整数的表示范围,那么将产生溢出,并设置 errno 为 ERANGE。你可以使用 <errno.h> 头文件中的 errno 变量来检查是否有溢出发生。

实例

下面的实例演示了 strtol() 函数的用法。

以下实例我们将字符串 “12345” 转换为长整型整数。strtol() 函数会将这个字符串转换为对应的整数值 12345。因为我们指定了 base 为 10,所以它会按照十进制进行转换。

实例

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

int main() {
  char str[] = "12345";
  char *endptr;
  long int num;

  num = strtol(str, &endptr, 10);

  if (*endptr != '**\0**') {
    printf("转换失败:输入字符串不是一个有效的整数。**\n**");
  } else {
    printf("转换结果:%ld**\n**", num);
  }

  return 0;
}

让我们编译并运行上面的程序,这将产生以下结果:

转换结果:12345

如果输入字符串不能被完全转换为整数,strtol() 函数将返回转换成功的部分,而 endptr 将指向未转换部分的第一个字符。在这个例子中,endptr 是指向字符串末尾的空字符 ‘\0’,表示整个输入字符串都被成功转换为整数。

如果输入字符串包含非数字字符,例如 “12ab”,那么 endptr 将指向 “ab” 的起始位置,指示转换失败。

实例

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

int main() {
  char str[] = "12ab";
  char *endptr;
  long int num;

  num = strtol(str, &endptr, 10);

  if (*endptr != '**\0**') {
    printf("转换失败:输入字符串不是一个有效的整数。未转换部分:%s**\n**", endptr);
  } else {
    printf("转换结果:%ld**\n**", num);
  }

  return 0;
}

以上实例我们将字符串 “12ab” 转换为长整型整数。strtol() 函数会尝试将这个字符串转换为对应的整数值 12,但因为字符串中包含非数字字符 “ab”,转换无法完成。

输出将是:

转换失败:输入字符串不是一个有效的整数。未转换部分:ab

四 遇到的问题

4.1

4.1.1 背景:

在做HJ33整数与IP地址间的转换题目时,其中使用到了atoi但是遇到一个示例,样例是传入字符串3868643487时,出现显示异常转换结果。

4.1.2 问题:

本来以为是逻辑问题,然后调试发现是atoi转换的原因。经过测试,发现atoi转换是有范围的。atoi是将char型字符串转换成int型,3868643487超过int型数据范围-2147483648到2147483647。所以当字符串是3868643487时就出错了。这边之前是不知道的,所以问题就是这个。

4.1.3 解决办法:

找到问题就想办法处理,还查了一篇帖子,但是也是不行,就写了char直接转int的函数。这边还需要注意的是,返回值也不能用int型接收了。因为int的取值范围也是-2147483648到2147483647。所以要使用unsigned int来接收返回值。

下面的是自己写的转换函数

unsigned int atoi_my(char* str)
{
    int len = strlen(str);
    unsigned int ret = 0;
    for(int i = 0; i < len; i++)
    {
        int dat = str[len - i - 1] - '0';
        ret += dat * (unsigned int)(pow(10, i) + 0.5);
    }
    return ret;
}

然后我在main函数中测试这个函数

int main() {
    char tets[] = "3868643487";
    unsigned int ret = atoi_my(tets);
    printf("%ld\n", ret);
    //printf("%u\n", ret);
}

打印结果是

-426323809

以为是自己的函数有问题,经过调试发现,是因为打印的问题。“ld”应该是打印long int的。不过从打印结果来看,long int就是4个字节啊。

是的,以为long int应该是8个字节,不应该异常打印,但是实际我的电脑上long int是4个字节。至于为什么是4个字节下面已经试验过了。

所以不能用“%ld”打印。无符号是“%u”控制符

菜鸟教程printf格式控制符表

4.1.4 补充知识点

ps:补充int 、long int、long long int区别

long int 几个字节

“long int”的字节大小在不同的系统和编译器下有所不同。以下是在不同系统下的具体表现:

  • 在32位系统中,无论是在32位编译系统还是64位编译系统,long int通常都是4个字节。12

  • 在64位系统中,64位编译系统下long int的大小变为了8个字节

    按照上文所述,我在自己x64的电脑上想验证64位机long int是不是8个字节。

    在codeblock上验证sizeof(long int)的长度是4个字节。我以为codeblock上是32位的。然后在vs上验证也是4个字节。我突然想到是不是没有切到x64,切换成x64打印也是4个字节。原因不知。

    查了别人的帖子,同样64位机,long是4个字节

    visual studio上long是几个字节

ps补充16位、32位、64位机数据长度

数据类型16位32位64位备注
char111
short222
int244
指针248(区别)
long448(区别)
long long int88
float44
double48(区别)

总结

未完待续

  • 36
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值