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

本文深入解析了如何利用位运算实现十进制数到十六进制和二进制的转换,包括算法原理、代码实现及注意事项。详细介绍了两种不同进制转换的技巧,以及在不同场景下的应用与优化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这是一道面试题:
编程实现将十进制数转换为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);


}

<think>嗯,用户问的是如何在Java中将十进制数转换为十六进制数。首先,我得回想下Java中处理进制转换的方法。记得Java的Integer类有些静态方法可以处理这些转换,比如toHexString,可能还有其他方式,比如使用String的格式化方法,或者自己实现算法。 首先,确认下用户的需求。他们可能是在编程中遇到了需要转换的情况,比如处理颜色代码、内存地址或者其他需要十六进制表示的场合。用户可能希望知道不同的方法,包括内置函数和手动实现,以便根据具体情况选择最合适的方式。 然后,我需要查阅下相关的Java文档或者常见的做法。比如,Integer.toHexString(int)可以直接将十进制整数转为十六进制字符串。另外,String.format("%x", number)也可以实现,还能控制大小写。还有,如果用户需要处理大数,可能需要用到Long.toHexString或者BigInteger的toString(16)方法。 接下来,考虑用户可能的疑问,比如负数怎么处理,转换后的字母是大写还是小写,或者如何处理大数的情况。例如,Integer.toHexString对于负数会返回补码形式的十六进制,而String.format如果使用%X则会输出大写的字母。这些细节需要在回答中说明。 另外,用户提供的引用资料中提到了些方法,比如引用[3]提到了批量转换的情况,但用户现在的问题可能更关注单个数值的转换。不过可以提到如果需要处理数组或批量转换,可能需要循环调用这些方法或者使用更高效的处理方式。 然后,可能还需要考虑手动实现的方法,比如通过除16取余的方式,虽然效率可能不如内置方法,但对于理解原理有帮助。这可能对教学或面试题有帮助,用户可能也需要这方面的知识。 最后,确保回答结构清晰,分点列出不同的方法,每种方法的示例代码,以及注意事项,比如大小写、处理负数等。同时,检查是否需要补充相关问题,比如如何反向转换(十六进制转十进制),或者处理其他进制,但根据用户的问题,当前集中在十进制转十六进制上。</think>在Java中将十进制数转换为十六进制数有以下几种常用方法: ### 方法:使用Integer.toHexString() ```java int decimal = 255; String hex = Integer.toHexString(decimal); System.out.println(hex); // 输出 ff(小写字母) ``` 该方法直接返回小写十六进制字符串,负数会以补码形式输出[^3]。 ### 方法二:String.format() ```java int num = 255; String hex1 = String.format("%x", num); // 小写 String hex2 = String.format("%X", num); // 大写 System.out.println(hex1); // ff System.out.println(hex2); // FF ``` `%x`格式符支持大小写控制,适用于需要特定格式的场景[^3]。 ### 方法三:Long.toHexString() ```java long bigNum = 4294967295L; String hex = Long.toHexString(bigNum); System.out.println(hex); // ffffffff ``` 适用于超过32位的整数转换。 ### 方法四:BigInteger ```java BigInteger bigInt = new BigInteger("123456789"); String hex = bigInt.toString(16); System.out.println(hex); // 75bcd15 ``` 支持超大整数的进制转换。 ### 方法五:手动算法实现 ```java public static String decimalToHex(int num) { char[] hexDigits = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'}; StringBuilder sb = new StringBuilder(); while (num > 0) { sb.insert(0, hexDigits[num % 16]); num /= 16; } return sb.toString(); } ``` 此算法演示了除16取余的核心原理,实际开发建议使用内置方法。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值