C语言实现将字符串转换成整数

 更新时间:2023年04月06日 09:16:29   作者:努力学习游泳的鱼  
这篇文章主要为大家详细介绍了如何用C语言写一个函数,把字符串转换成整数,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教

这是一个很有意思的问题。请不要把这个问题想的太简单了,考虑问题时应该尽可能的全面一些。请先思考并且实现这个函数,再来看讲解。

分析一下:函数名是StrToInt,那么可以这么调用:

int ret = StrToInt("1234");
printf("%d\n", ret);

如果你写的程序能够正确输出1234,然后就觉得这道题就这样了,那么考虑的就不够全面。有没有一种可能:

1.传参时传了NULL指针。

2.传入空字符串。

3.字符串前面有空格,如:" 1234"。

4.有正负号,如:“-1234”。

5.有非法字符,如:“1234abcd”。

6.数字太大了,超出了int的存储范围,如:“1111111111111111111111111111111111111”。

下面我们一个一个解决。

准备工作

由于有可能出现非法字符,或者空字符串等,会有一些情况的转换是非法的。所以,定义一个全局性质的枚举类型来检验转换是否合法:

enum State
{
    VALID,
    INVALID
}s = INVALID;

默认的情况是非法的,只有转换成功才会把s的值置为VALID。

先把函数的框架撘出来:

int StrToInt(const char* str)
{

​​​​​​​}

接下来开始解决以下问题:

1.NULL指针

NULL指针是不能解引用的!所以最好断言一下。

int StrToInt(const char* str)
{
	// 如果str是NULL,不能对其解引用
	assert(str);

	return ret;
}

2.空字符串

如果一上来就遇到了’\0’,那么就是空字符串。

int StrToInt(const char* str)
{
	// 如果str是NULL,不能对其解引用
	assert(str);

	// 空字符串
	if (*str == '\0')
	{
		return 0;
	}
}

3.空格

接下来,有可能会遇到空格,使用isspace函数来判断,把空格跳过去。

int StrToInt(const char* str)
{
	// 如果str是NULL,不能对其解引用
	assert(str);

	// 空字符串
	if (*str == '\0')
	{
		return 0;
	}
	// 空格
	while (isspace(*str))
	{
		++str;
	}
}

4.正负号

接下来有可能遇到正负号,用一个flag来保存。

int StrToInt(const char* str)
{
	// 如果str是NULL,不能对其解引用
	assert(str);

	// 空字符串
	if (*str == '\0')
	{
		return 0;
	}
	// 空格
	while (isspace(*str))
	{
		++str;
	}
	// 正负号
	int flag = 1;
	if (*str == '+')
	{
		flag = 1;
		++str;
	}
	else if (*str == '-')
	{
		flag = -1;
		++str;
	}
}

5.非法字符

下面开始处理数字。但是,有可能会遇到非法字符,所以要先判断一下。

int StrToInt(const char* str)
{
	// 如果str是NULL,不能对其解引用
	assert(str);

	// 空字符串
	if (*str == '\0')
	{
		return 0;
	}
	// 空格
	while (isspace(*str))
	{
		++str;
	}
	// 正负号
	int flag = 1;
	if (*str == '+')
	{
		flag = 1;
		++str;
	}
	else if (*str == '-')
	{
		flag = -1;
		++str;
	}

	// 处理数字
	while (*str)
	{
		if (isdigit(*str))
		{

		}
		else
		{
			return ret;
		}
	}
}

如何处理合法的数字呢?假设是1234,我们可以先定义一个ret,初始化成0。先拿到1,0*10+1,就得到了1。接着拿到2,1*10+2,就得到了12。再拿到3,12*10+3,就得到了123。最后拿到4,123*10+4,就得到了1234。以此类推。

每次ret = ret*10 + 拿到的数字就行了。但是“拿到的数字”是什么呢?就是*str-'0'。想象一下,'1'-'0'就是数字1,'6'-'0'就是数字6。两个字符相减就是对应的ASCII码相减。不过,拿到的数字得乘上flag再加上去,因为有可能是负数。

int StrToInt(const char* str)
{
	// 如果str是NULL,不能对其解引用
	assert(str);

	// 空字符串
	if (*str == '\0')
	{
		return 0;
	}
	// 空格
	while (isspace(*str))
	{
		++str;
	}
	// 正负号
	int flag = 1;
	if (*str == '+')
	{
		flag = 1;
		++str;
	}
	else if (*str == '-')
	{
		flag = -1;
		++str;
	}

	// 处理数字
	int ret = 0;
	while (*str)
	{
		if (isdigit(*str))
		{
			ret = ret * 10 + flag * (*str - '0');
			++str;
		}
		else
		{
			return ret;
		}
	}

	s = VALID;
	return (int)ret;
}

6.越界

这就完了吗?还有一种情况,假设传入的数字过大或过小,导致超出了int的存储范围,此时的转换也是非法的。判断方法,就是用更大的类型,如long long来存储,如果超出了int的存储范围(ret>INT_MAX || ret<INT_MIN),但是不会超出long long的存储范围,就能够识别什么时候越界了。

int StrToInt(const char* str)
{
	// 如果str是NULL,不能对其解引用
	assert(str);

	// 空字符串
	if (*str == '\0')
	{
		return 0;
	}
	// 空格
	while (isspace(*str))
	{
		++str;
	}
	// 正负号
	int flag = 1;
	if (*str == '+')
	{
		flag = 1;
		++str;
	}
	else if (*str == '-')
	{
		flag = -1;
		++str;
	}

	// 处理数字
	long long ret = 0;
	while (*str)
	{
		if (isdigit(*str))
		{
			ret = ret * 10 + flag * (*str - '0');
			// 判断有没有超过int的存储范围
			if (ret > INT_MAX || ret < INT_MIN)
			{
				return (int)ret;
			}
			else
			{
				++str;
			}
		}
		else
		{
			return (int)ret;
		}
	} // end of while

	s = VALID;
	return (int)ret;
}

最后如果转换成功,就把s置成VALID,再返回ret即可。注意ret是long long类型,但是返回类型是int,所以需要强制类型转换。

测试

完整的测试代码如下:

#include <stdio.h>
#include <assert.h>
#include <ctype.h>
#include <limits.h>

enum State
{
	VALID,
	INVALID
}s = INVALID;

int StrToInt(const char* str)
{
	// 如果str是NULL,不能对其解引用
	assert(str);

	// 空字符串
	if (*str == '\0')
	{
		return 0;
	}
	// 空格
	while (isspace(*str))
	{
		++str;
	}
	// 正负号
	int flag = 1;
	if (*str == '+')
	{
		flag = 1;
		++str;
	}
	else if (*str == '-')
	{
		flag = -1;
		++str;
	}

	// 处理数字
	long long ret = 0;
	while (*str)
	{
		if (isdigit(*str))
		{
			ret = ret * 10 + flag * (*str - '0');
			// 判断有没有超过int的存储范围
			if (ret > INT_MAX || ret < INT_MIN)
			{
				return (int)ret;
			}
			else
			{
				++str;
			}
		}
		else
		{
			return (int)ret;
		}
	} // end of while

	s = VALID;
	return (int)ret;
}

int main()
{
	int ret = StrToInt("      -1234");
	if (s == VALID)
	{
		printf("转换成功:%d\n", ret);
	}
	else
	{
		printf("转换失败:%d\n", ret);
	}

	return 0;
}

输出结果:

总结

1.每次把旧的数乘10再加上一个数字,就能在这个数后面续上这个数字。如123*10+4=1234,就在123后面续上了4。

2.字符相减,本质是ASCII码相减。

3.考虑问题时,应该全面考虑,不要漏掉一些情况。

到此这篇关于C语言实现将字符串转换成整数的文章就介绍到这了,更多相关C语言字符串转整数内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • 简明的C++函数指针学习教程

    简明的C++函数指针学习教程

    这篇文章主要介绍了C++函数指针的学习教程,讲到了函数指针的定义及把指针作为函数参数进行传递的用法,需要的朋友可以参考下
    2016-04-04
  • C++11中移动构造函数案例代码

    C++11中移动构造函数案例代码

    C++11 标准中为了满足用户使用左值初始化同类对象时也通过移动构造函数完成的需求,新引入了 std::move() 函数,它可以将左值强制转换成对应的右值,由此便可以使用移动构造函数,对C++11移动构造函数相关知识感兴趣的朋友一起看看吧
    2023-01-01
  • 深入理解Qt信号槽机制

    深入理解Qt信号槽机制

    信号槽是 Qt 框架引以为豪的机制之一。本文主要介绍了Qt信号槽机制,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-06-06
  • 如何在程序中判断VS的版本(实现方法详解)

    如何在程序中判断VS的版本(实现方法详解)

    下面小编就为大家带来一篇如何在程序中判断VS的版本(实现方法详解)。小编觉得挺不错的,现在就分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2017-05-05
  • C语言:十进制,BCD码互换详解

    C语言:十进制,BCD码互换详解

    这篇文章主要介绍了C语言十进制,BCD码互换实例,小编觉得这篇文章写的还不错,实例简单明了,需要的朋友可以参考下
    2021-09-09
  • C++ 强制类型转换详解

    C++ 强制类型转换详解

    这篇文章主要介绍的是C++ 强制类型转换详解,C语言中的强制转换主要用于普通数据类型、指针的强制转换,没有类型检查,转换不安全,下面我们来看看其具体语法及详细内容
    2021-11-11
  • C++ 花括号{}初始化小结

    C++ 花括号{}初始化小结

    在C++11及以后的版本中,花括号{}语法在不同语境下有不同的用法,本文就详细的介绍C++ 花括号{}初始化,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2023-06-06
  • c语言经典习题之逆序字符串详解

    c语言经典习题之逆序字符串详解

    这篇文章主要为大家介绍了c语言习题之逆序字符串,具有一定的参考价值,感兴趣的小伙伴们可以参考一下,希望能够给你带来帮助
    2022-01-01
  • C++实现单链表按k值重新排序的方法

    C++实现单链表按k值重新排序的方法

    这篇文章主要介绍了C++实现单链表按k值重新排序的方法,结合实例形式分析了C++单链表中按照给定值进行判断与排序的相关操作技巧,需要的朋友可以参考下
    2017-05-05
  • 详解C++文件读写操作

    详解C++文件读写操作

    这篇文章主要为大家详细介绍了C++文件读写操作,感兴趣的小伙伴们可以参考一下
    2016-03-03

最新评论