整数转字符串和字符串转换为整数

一、编写函数itob(n,s,b),将整数n转换为以b为底的数,并将结果以字符的形式保存到字符串s中。例如,itob(n,s,16)把整数n格式化成十六进制整数保存在s中。
这里我我修改了一下书上提供的答案所使用的do 。。。while循环改为for循环
the c  programming language一书中所给实现源码是:

void itob(int n , char s[], int b)
{
	static char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
	int i = 0;
	int sign = n;

	if(b < 2 || b > 36)
	{
		fprintf(stderr, "EX3_5: Cannot support base %d\n", b);
		exit(1);
	}

	if (sign < 0)
	{
		n = -n;
	}

	do 
	{
		s[i++] = digits[n%b];
	} while ((n /= b) > 0);

	if (sign < 0)
	{
		s[i++]= '-';
	}

	s[i] = '\0';
	reverse(s);
}

我修改所使用的for循环以下:

void itob1(int n , char s[], int b)
{
	static char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
	int i = 0;
	int sign = n;

	if(b < 2 || b > 36)
	{
		fprintf(stderr, "EX3_5: Cannot support base %d\n", b);
		exit(1);
	}

	if (sign < 0)
	{
		n = -n;
	}

	for (;((n/b) > 0)|((n%b) !=0);n/= b)
	{
		s[i++] = digits[n%b];
		
	}


	if (sign < 0)
	{
		s[i++]= '-';
	}

	s[i] = '\0';
	reverse(s);
}

整个源码以及测试代码以下:

#include <iostream>
using namespace std;

void reverse(char s[]);
void itob(int n , char s[], int b);
void itob1(int n , char s[], int b);

int main(int argc ,char **argv)
{
	char buffer[10];
	int i;

	for ( i = 2; i <= 20; ++i ) 
	{
		itob(255, buffer, i);
		printf("Decimal 255 in base %-2d : %s\n", i, buffer);
	}
	return 0;

}


void reverse(char s[])
{
	int i, j;
	char c;
	for (i = 0, j = strlen(s) - 1; i < j;  i++, j--)
	{
		c = s[i];
		s[i] = s[j];
		s[j] =c;
	}
}

/*--------------------------------------
	将整数n转换成底为b的数保存在s中
---------------------------------------*/
void itob(int n , char s[], int b)
{
	static char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
	int i = 0;
	int sign = n;

	if(b < 2 || b > 36)
	{
		fprintf(stderr, "EX3_5: Cannot support base %d\n", b);
		exit(1);
	}

	if (sign < 0)
	{
		n = -n;
	}

	do 
	{
		s[i++] = digits[n%b];
	} while ((n /= b) > 0);

	if (sign < 0)
	{
		s[i++]= '-';
	}

	s[i] = '\0';
	reverse(s);
}

void itob1(int n , char s[], int b)
{
	static char digits[] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
	int i = 0;
	int sign = n;

	if(b < 2 || b > 36)
	{
		fprintf(stderr, "EX3_5: Cannot support base %d\n", b);
		exit(1);
	}

	if (sign < 0)
	{
		n = -n;
	}

	for (;((n/b) > 0)|((n%b) !=0);n/= b)
	{
		s[i++] = digits[n%b];
		
	}


	if (sign < 0)
	{
		s[i++]= '-';
	}

	s[i] = '\0';
	reverse(s);
}


二、题目:输入一个表示整数的字符串,把该字符串转换成整数并输出。例如输入字符串"345",则输出整数345。 分析:这道题尽管不是很难,学过C/C++语言通常都能实现基本功能,但不一样程序员就这道题写出的代码有很大区别,能够说这道题可以很好地反应出程序员的思惟和编程习惯,所以已经被包括微软在内的多家公司用做面试题。建议读者在往下看以前本身先编写代码,再比较本身写的代码和下面的参考代码有哪些不一样。
首先咱们分析如何完成基本功能,即如何把表示整数的字符串正确地转换成整数。仍是以"345"做为例子。当咱们扫描到字符串的第一个字符'3'时,咱们不知道后面还有多少位,仅仅知道这是第一位,所以此时获得的数字是3。当扫描到第二个数字'4'时,此时咱们已经知道前面已经一个3了,再在后面加上一个数字4,那前面的3至关于30,所以获得的数字是3*10+4=34。接着咱们又扫描到字符'5',咱们已经知道了'5'的前面已经有了34,因为后面要加上一个5,前面的34就至关于340了,所以获得的数字就是34*10+5=345。
分析到这里,咱们不能得出一个转换的思路:每扫描到一个字符,咱们把在以前获得的数字乘以10再加上当前字符表示的数字。这个思路用循环不难实现。
因为整数可能不只仅之含有数字,还有可能以'+'或者'-'开头,表示整数的正负。所以咱们须要把这个字符串的第一个字符作特殊处理。若是第一个字符是'+'号,则不须要作任何操做;若是第一个字符是'-'号,则代表这个整数是个负数,在最后的时候咱们要把获得的数值变成负数。
接着咱们试着处理非法输入。因为输入的是指针,在使用指针以前,咱们要作的第一件是判断这个指针是否是为空。若是试着去访问空指针,将不可避免地致使程序崩溃。另外,输入的字符串中可能含有不是数字的字符。每当碰到这些非法的字符,咱们就没有必要再继续转换。最后一个须要考虑的问题是溢出问题。因为输入的数字是以字符串的形式输入,所以有可能输入一个很大的数字转换以后会超过可以表示的最大的整数而溢出。
如今已经分析的差很少了,开始考虑编写代码。首先咱们考虑如何声明这个函数。因为是把字符串转换成整数,很天然咱们想到:
int StrToInt(const char* str);
这样声明看起来没有问题。但当输入的字符串是一个空指针或者含有非法的字符时,应该返回什么值呢?0怎么样?那怎么区分非法输入和字符串自己就是”0”这两种状况呢?
接下来咱们考虑另一种思路。咱们能够返回一个布尔值来指示输入是否有效,而把转换后的整数放到参数列表中以引用或者指针的形式传入。因而咱们就能够声明以下:
bool StrToInt(const char *str, int& num);
这种思路解决了前面的问题。可是这个函数的用户使用这个函数的时候会以为不是很方便,由于他不能直接把获得的整数赋值给其余整形变脸,显得不够直观。
前面的第一种声明就很直观。如何在保证直观的前提下当碰到非法输入的时候通知用户呢?一种解决方案就是定义一个全局变量,每当碰到非法输入的时候,就标记该全局变量。用户在调用这个函数以后,就能够检验该全局变量来判断转换是否是成功。
下面咱们写出完整的实现代码。参考代码:
enum Status {kValid = 0, kInvalid};
int g_nStatus = kValid;ios

///////////////////////////////////////////////////////////////////////
// Convert a string into an integer
///////////////////////////////////////////////////////////////////////
int StrToInt(const char* str)
{
       g_nStatus = kInvalid;
      long long num = 0;git

      if(str != NULL)
       {
            const char* digit = str;程序员

            // the first char in the string maybe '+' or '-'
            bool minus = false;
            if(*digit == '+')
                   digit ++;
            else if(*digit == '-')
             {
                   digit ++;
                   minus = true;
             }面试

            // the remaining chars in the string
            while(*digit != '\0')
             {
                  if(*digit >= '0' && *digit <= '9')
                   {
                         num = num * 10 + (*digit - '0');编程

                        // overflow 
                        if(num > std::numeric_limits<int>::max())
                         {
                               num = 0;
                               break;
                         }函数

                         digit ++;
                   }
                  // if the char is not a digit, invalid input
                  else
                   {
                         num = 0;
                        break;
                   }
             }测试

            if(*digit == '\0')
             {
                   g_nStatus = kValid;
                  if(minus)
                         num = 0 - num;
             }
       }spa

       return static_cast<int>(num);
}指针

讨论:在参考代码中,我选用的是第一种声明方式。不过在面试时,咱们能够选用任意一种声明方式进行实现。但当面试官问咱们选择的理由时,咱们要对二者的优缺点进行评价。第一种声明方式对用户而言很是直观,但使用了全局变量,不够优雅;而第二种思路是用返回值来代表输入是否合法,在不少API中都用这种方法,但该方法声明的函数使用起来不够直观。
最后值得一提的是,在C语言提供的库函数中,函数atoi可以把字符串转换整数。它的声明是int atoi(const char *str)。该函数就是用一个全局变量来标志输入是否合法的。code