面试题--位操作--将十进制数转换为16进制字符串输出

这是一道面试题:
编程实现将十进制数转换为16进制输出,不得使用任何已定义的库函数,比如string,math等。

char * get16String(long num)
{
int i = 0;
char * buffer = (char *)malloc(11);
char * temp = buffer+2;
buffer[0] = '0';
buffer[1] = 'x';
buffer[10] = '\0';
 for(i=0;i<8;i++){
        temp[i] = (char)(num << 4 * i >> 28);               /*乘法优先级高于移位符, 移位符左结合,然后再右结合*/
        temp[i] = temp[i] >= 0 ? temp[i] : temp[i] + 16;    /*之所以会出现负数是因为:左移之后,若最高位为1,则编译器认为该数为负数,执行右移操作(该编译器执行算术移位)时,移入位均用1补齐*/
        temp[i] = temp[i] < 10 ? temp[i] + '0' : temp[i] - 10 + 'A' ;
// temp[i] = temp[i] < 10 ? temp[i] + 48 : temp[i] + 55; //等同于上一句0的ASCII码的十进制值是48,A是65
 }                                        /*从高位开始,每一次循环都取出num的二进制码中的四位,并转换成一个16进制的数值。*/
return buffer;
}
实际上你这题目的算法用到位运算 整数是32个bit
16进制实际上 是4个bit 4个比特一组 一共8组
每次把4个bit取出来做成一个整数 输出就行了
temp[i] = (char)(num<<4*i>>28); 
temp[i] = temp[i] >= 0 ? temp[i] : temp[i] + 16; 
temp[i] = temp[i] < 10 ? temp[i] + 48 : temp[i] + 55;
回答
temp[i] = (char)(num<<4*i>>28); 左移4i位 去掉高位的4i 右移28位 去掉右边的 这就获得4个bit
第一次是最高位32-29 4个bit 第二次 28-25 4个bit
temp[i] = temp[i] >= 0 ? temp[i] : temp[i] + 16; 
然后因为它可能是个有符号的数 所以加上16 吧这个数变成0~15之间的正数
temp[i] = temp[i] < 10 ? temp[i] + 48 : temp[i] + 55;
然后<10 就是变成字符‘0’~‘9’ 所以加上48, 如果>=10 那就要用 'A'~'F'来表示

所以加上55, 因为'A'变成整数正好是65


同理,可应用于二进制的转换

1:循环对数字1左移31-i(i={0,31})位(从高位开始的),再与把num作位与操作,

 2:再把刚才的结果通过右移31-i (i={0,31}) 位得出每一位是否为0还是1,

  这样就得到了每一位的二进制位,再把这些二进制位拼成字符串就OK了!


char * get2String(long num)
{
	int i = 0;
	char * buffer = NULL;
	char * temp = NULL;

	buffer = (char *)malloc(33);
	temp = buffer;

	for(i=0; i<32; i++)             
	{
		temp[i] = num & (1 << (31 - i));		
		temp[i] = temp[i] >> (31 - i);
		temp[i] = (temp[i] == 0) ? '0' : '1';
	}
	buffer[32] = '\0';

	return buffer;
}

上面这个是别人写的,其实这个是错的,因为它没有考虑负数的情况,负数移位,符合位是被补上的。比如1000 0000 0000 0000 0000 0000 0000 0000>>31 =1000 0000 0000 0000 0000 0000 0000 0001=-2147483647而不是等于1.所以必需清除符号位。对于指定位的置1和清0操作可以用下面的宏定义,比较直观简单。

#define   setbit(x,y)    x|=(1<<y) //将X的第Y位置1
#define   clrbit(x,y)     x&=~(1<<y) //将X的第Y位清0

修改后的函数如下:

char * get2String(long num)
{
	int i = 0;
	char * buffer = NULL;
	char * temp = NULL;
    
	long t;
	buffer = (char *)malloc(33);
	temp = buffer;

	for(i=0; i<32; i++)               //(+3)在32位系统中的存储为二进制 0000 0000 0000 0000 0000 0000 0000 0011 
	{                                  //(-3)在32位系统中的存储为二进制1111 1111 1111 1111 1111 1111 1111 1101
		t = num & (1 << (31 - i));//1111 1111 1111 1111 1111 1111 1111 1101 & 1000 0000 0000 0000 0000 0000 0000 0000	=1000 0000 0000 0000 0000 0000 0000 0000=-2147483648	    
		t= t >> (31 - i);//1000 0000 0000 0000 0000 0000 0000 0000>>31 =1000 0000 0000 0000 0000 0000 0000 0001=-2147483647 
		clrbit(t,31);//将最高位清零	
		temp[i] = (t == 0) ? '0' : '1';
	}
	buffer[32] = '\0';

	return buffer;
}

3.通常的,十六进制和二进制的输出都将前面的0去掉,添加去掉0的代码如下:

char * get2String(long num)
{
	int i = 0,j=0;
	char * buffer = NULL;

	long t;
	buffer = (char *)malloc(33);

	for(i=0; i<32; i++)              
	{                               
		t = num & (1 << (31 - i));    
		t= t >> (31 - i);
		clrbit(t,31);//将最高位清零	
		buffer[i] = (t == 0) ? '0' : '1';
	}
	for(i=0; i<32; i++)  //去掉前面的0
       if(buffer[i] !='0')
			   break;
    for(j=0; j<32-i; j++)  //非0值开始往前移
            buffer[j]=buffer[i+j];
	buffer[j] = '\0';
	return buffer;
}
char * get16String(long num)
{
	int i = 0,j=0;
	char * buffer = (char *)malloc(11);
	char * temp = buffer+2;

	buffer[0] = '0';
	buffer[1] = 'x';

	for(i=0; i<8; i++)
	{															//
		temp[i] = (char)( (num << (4 * i)) >> 28);
		temp[i] = temp[i] >= 0 ? temp[i] : temp[i] + 16;
		temp[i] = temp[i] < 10 ? temp[i] + 48 : temp[i] + 55;
	} 
	for(i=0; i<8; i++)   //去掉前面的0
       if(temp[i]!='0')
		   break;
    for(j=0; j<8-i; j++) //非0值开始往前移
		buffer[2+j]=temp[i+j];
	buffer[2+j] = '\0';
	return buffer;
}

4.其实用取模再求余的方法也可以实现,只是需要将得到的余数序列倒序,才行。而且对于负数不行,负数的话该怎么办呢?

char* exchange2(int n) //适用于正数
//void exchange2(int n)
{    
	int j,temp;    
    char *d;   
	d = (char *)malloc(sizeof(char)*2);    
	for (j = 0;; j++)    
	{        
		temp = n % 2;        
		d[j] =temp + '0';       
		n /= 2;        
		if (n == 0) 
			break;        
		else            
			d = (char *)realloc(d, strlen(d)+1);///这样改    
	}   
	j++;   
	d[j] = '\0';    //倒序    
	int i=0;    
	char a;    
	while(i<j-1)    
	{       
		a=d[i];        
		d[i]=d[j-1];        
		d[j-1]=a;       
		++i;        
		--j;    
} 
//	free(d);
	return d;
}


char* exchange16(int n)  //适用于正数
{    
	int j,temp; 
	char * buffer = (char *)malloc(11);
//	char  buffer[12]={'\0'}; 
/*这里不能用这个,因为这相当于定义了一个局部变量---数组buffer[],而返回的是一个指针,
	是这个内存块的首地址,然后这个这个局部变量的生存期到了,也就是内存被回收了,然后这个buffer指针指向哪里呢?所以运行的时候程序就会崩溃。
	*/
    buffer[0] = '0';
	buffer[1] = 'x';
    j=2;
	while(n)
	{
		temp = n % 16;    
		if(temp>=0&&temp<=9)
	     	buffer[j] =temp + '0';    //0~9字符  
		else 
			buffer[j] =temp -10+ 'A'; //A~F字符
		n /= 16; 
		j++;	
	}   
   //倒序    
	int i=2;    
	char a;    
	while(i<j-1)    
	{       
		a=buffer[i];        
		buffer[i]=buffer[j-1];        
		buffer[j-1]=a;       
		++i;        
		--j;    
} 
  	buffer[i+1] = '\0'; 
	//	free(buffer); //这个应该怎么在哪里free()呢?
	return buffer;
}

同时,从以上两个程序中学习了
malloc和
realloc的使用,以及他们与数组定义的却别。在下一节讨论总结。
1、realloc函数用法。

指针名=(数据类型*)realloc(要改变内存大小的指针名,新的大小)

malloc动态分配与数组静态分配还有一个最重要的区别:

1.全局

假设数组char a[10]和char*p=(char*)malloc(10)都是全局的

那么数组a[10]在程序运行过程会一直存在,即一直占用10个字节空间.

但动态申请的可以使用free()来释放掉.等到再使用的时候重新申请.

2.局部
局部的数组在超过其作用域范围内会释放掉,但动态申请出来的空间不会.

如.

char *fun()
{
 char p[10];//局部的数组
 return p;//返回一个临时的局部变量,这个函数一结束,p的空间就会释放掉,所以是没有返回成功的.
}





char *fun()
{
 char *p=(char*)malloc(10);//动态申请空间
 return p;//返回动态申请的空间是可以的.
}


void main()


{


char *s=fun();//


strcpy(s,"abc");//如果fun()里是动态申请的,可以拷贝成功,否则不成功,是乱码.


}

5.由此,回头看看前面的malloc函数,使用时没有配对使用free函数,这是很不科学的,也是不应该的。

char * get2String(long num)
{
int i = 0,j=0;
char * buffer = NULL;


long t;
buffer = (char *)malloc(33);


for(i=0; i<32; i++)              
{                               
t = num & (1 << (31 - i));    
t= t >> (31 - i);
clrbit(t,31);//将最高位清零
buffer[i] = (t == 0) ? '0' : '1';
}
for(i=0; i<32; i++)  //去掉前面的0
       if(buffer[i] !='0')
  break;
    for(j=0; j<32-i; j++)  //非0值开始往前移
            buffer[j]=buffer[i+j];
buffer[j] = '\0';
return buffer;
}
char * get16String(long num)
{
int i = 0,j=0;
char * buffer = (char *)malloc(11);
char * temp = buffer+2;


buffer[0] = '0';
buffer[1] = 'x';


for(i=0; i<8; i++)
{ //
temp[i] = (char)( (num << (4 * i)) >> 28);
temp[i] = temp[i] >= 0 ? temp[i] : temp[i] + 16;
temp[i] = temp[i] < 10 ? temp[i] + 48 : temp[i] + 55;

for(i=0; i<8; i++)   //去掉前面的0
       if(temp[i]!='0')
  break;
    for(j=0; j<8-i; j++) //非0值开始往前移
buffer[2+j]=temp[i+j];
buffer[2+j] = '\0';
return buffer;
}




void main()
{
int n;
char str[80];
scanf("%d",&n);
str=get16String(n);
printf("%s\n",str);
        str=get2String(n);
printf("%s\n",p);


}
这样是编译不过的,编译有错
str=get16String(n);
rror C2440: '=' : cannot convert from 'char *' to 'char [80]
修改成这样才行的 
void main()
{
int n;
char str[80];
char*p=str;
scanf("%d",&n);
p=get16String(n);
printf("%s\n",p);
        p=get2String(n);
printf("%s\n",p);


}
这样是能正确输出程序但是程序还是有问题的,用了malloc函数但是没用free释放掉内存,这是很不科学的,面试时这样写的话,你就pass了,尤其是面试嵌入式工程师的,应该这样修改
修改版本一:
void  get2String(long num)
{
int i = 0,j=0;
char * buffer = NULL;


long t;
buffer = (char *)malloc(33);


for(i=0; i<32; i++)              
{                               
t = num & (1 << (31 - i));    
t= t >> (31 - i);
clrbit(t,31);//将最高位清零
buffer[i] = (t == 0) ? '0' : '1';
}
for(i=0; i<32; i++)  //去掉前面的0
       if(buffer[i] !='0')
  break;
    for(j=0; j<32-i; j++)  //非0值开始往前移
            buffer[j]=buffer[i+j];
buffer[j] = '\0';
    printf("%s\n",buffer);
free(buffer);


}
在函数内使用printf();直接打印是不太好也不太方便后面的使用。
修改版本二:
void  get2String(long num,char *buffer)
{
int i = 0,j=0;
long t;
for(i=0; i<32; i++)              
{                               
t = num & (1 << (31 - i));    
t= t >> (31 - i);
clrbit(t,31);//将最高位清零
buffer[i] = (t == 0) ? '0' : '1';
}
for(i=0; i<32; i++)  //去掉前面的0
       if(buffer[i] !='0')
  break;
    for(j=0; j<32-i; j++)  //非0值开始往前移
            buffer[j]=buffer[i+j];
buffer[j] = '\0';
}
void get16String(long num,char* buffer)
{
int i = 0,j=0;
char * temp = buffer+2;


buffer[0] = '0';
buffer[1] = 'x';


for(i=0; i<8; i++)
{ //
temp[i] = (char)( (num << (4 * i)) >> 28);
temp[i] = temp[i] >= 0 ? temp[i] : temp[i] + 16;
temp[i] = temp[i] < 10 ? temp[i] + 48 : temp[i] + 55;

for(i=0; i<8; i++)   //去掉前面的0
       if(temp[i]!='0')
  break;
    for(j=0; j<8-i; j++) //非0值开始往前移
buffer[2+j]=temp[i+j];
buffer[2+j] = '\0'; 
}
void main()
{
int n;
char str[80];
char*p=str;
scanf("%d",&n);
    get16String(n,p);// get16String(n,str);//都可以
printf("%s\n",p);
    get2String(n,str);
printf("%s\n",p);


}


修改版本三:
char*  get2String(long num,char *buffer)
{
int i = 0,j=0;
long t;
char* tmp=buffer;
for(i=0; i<32; i++)              
{                               
t = num & (1 << (31 - i));    
t= t >> (31 - i);
clrbit(t,31);//将最高位清零
buffer[i] = (t == 0) ? '0' : '1';
}
for(i=0; i<32; i++)  //去掉前面的0
       if(buffer[i] !='0')
  break;
    for(j=0; j<32-i; j++)  //非0值开始往前移
            buffer[j]=buffer[i+j];
buffer[j] = '\0';
return tmp;


}


char* get16String(long num,char* buffer)
{
int i = 0,j=0;
        char* retmp=buffer;
char * temp = buffer+2;


buffer[0] = '0';
buffer[1] = 'x';


for(i=0; i<8; i++)
{ //
temp[i] = (char)( (num << (4 * i)) >> 28);
temp[i] = temp[i] >= 0 ? temp[i] : temp[i] + 16;
temp[i] = temp[i] < 10 ? temp[i] + 48 : temp[i] + 55;

for(i=0; i<8; i++)   //去掉前面的0
       if(temp[i]!='0')
  break;
    for(j=0; j<8-i; j++) //非0值开始往前移
buffer[2+j]=temp[i+j];
buffer[2+j] = '\0';
return retmp;
}


void main()
{
int n;
char str[80];
char*p=str;
scanf("%d",&n);
    p=get16String(n,p);// get16String(n,str);
printf("%s\n",p);
    p=get2String(n,str);
printf("%s\n",p);


}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值