十六进制转二进制与二进制转八进制
问题
问题描述
给定n个十六进制正整数,输出它们对应的八进制数。
输入格式
输入的第一行为一个正整数n (1<=n<=10)。
接下来n行,每行一个由09、大写字母AF组成的字符串,表示要转换的十六进制正整数,每个十六进制数长度不超过100000。
输出格式
输出n行,每行为输入对应的八进制正整数。
【注意】
输入的十六进制数不会有前导0,比如012A。
输出的八进制数也不能有前导0。
样例输入
2
39
123ABC
样例输出
71
4435274
【提示】
先将十六进制数转换成某进制数,再由某进制数转换成八进制。
思路还是比较明显的,先把十六进制的字符一个一个转换为4位的二进制,再将二进制以三位为单位转换为八进制,感觉很简单,但是当我实际做的时候才发现并非如此,许多细节都需要注意,说来惭愧,实现这两个函数花了我今天大半天的时间,一开始只是为了做这个题,后来我觉得也许以后也会用到,所以考虑了更多参数输入的情况,使其更加兼容。
程序在C++环境下编译运行成功,主要是因为函数返回值设置为bool类型,修改为int后应该是可以在C语言环境下编译通过的,不过我没有去尝试罢了
将十六进制的字符串转换为二进制字符串
对于参数:
S为十六进制串的首地址,slength为要转换的串长度,为什么不直接使用strlen(S)呢,考虑到只想将一个十六进制串的部分转换为二进制的情况,所以采用了额外指定串的长度。
B为存放二进制串的地址,blength为B可使用的长度,对于十六进制串,处了第一位以外,其他的每一个都必然会转换为4个二进制字符,所以blength的理想长度应大于slength*4,为了以防万一,B因该在传入之前初始化。
//十六进制字符串转二进制字符串
bool StoB(char *S,int slength,char *B,int blength)
{
//判断非法输入返回 false
if((S == NULL) || (B == NULL) || (blength < slength * 4))return false;
//针对于十六进制的第一位如果小于8,那么转换为四位二进制后首位会为0,所以需要特殊处理
char k1[16][5] = {
"0" , "1" , "10" , "11" ,
"100" , "101" , "110" , "111" ,
"1000", "1001", "1010", "1011",
"1100", "1101", "1110", "1111"
};
char k [16][5] = {
"0000", "0001", "0010", "0011",
"0100", "0101", "0110", "0111",
"1000", "1001", "1010", "1011",
"1100", "1101", "1110", "1111"
};
//tmp 存放单个16进制字符的十进制值
//position 二进制标志位
int i=0,tmp=0,position=0;
//首位为零标志
bool zero = true;
for(;i<slength;i++)
{
if((*(S+i) >= '0') && (*(S+i) <= '9'))
tmp = *(S+i) - '0';
else if((*(S+i) >= 'A') && (*(S+i) <= 'Z'))
tmp = *(S+i) - 'A' + 10;
else if((*(S+i) >= 'a') && (*(S+i) <= 'z'))
tmp = *(S+i) - 'a' + 10;
else
return false;
if(tmp != 0) zero = false;
if(zero == true) continue;//如果首位为零,则跳过
if(position == 0)
{
strcpy(B+position,k1[tmp]);
position = position + strlen(k1[tmp]);
}
else
{
strcpy(B+position,k[tmp]);
position = position + 4;
}
}
return true;
}
将二进制的字符串转换为八进制的字符串
//二进制字符串转八进制字符串
bool BtoE(char *B,int blength,char *E,int elength)
{
if((B == NULL) || (E == NULL) || (elength < (blength+3)/2)) return false;
char k [8][4] = { "000", "001", "010", "011", "100", "101", "110", "111" };
char k1[8][4] = { "0", "1", "10", "11", "100", "101", "110", "111" };
int i = 0,position = blength/3 - 1;
if((blength%3) != 0) position++;
char tmp[4];
for(i = blength - 3;i >= 0;i = i-3)
{
memset(tmp,0,sizeof(tmp));
strncpy(tmp,B+i,3);
for(int j = 0;j < 8;j++)
{
if(strcmp(tmp,k[j]) == 0)
{
E[position--] = j + '0';
}
}
}
if(i > -3)
{
memset(tmp,0,sizeof(tmp));
strncpy(tmp,B,3+i);
for(int j = 0;j < 8;j++)
{
if(strcmp(tmp,k1[j]) == 0)
{![请添加图片描述](https://img-blog.csdnimg.cn/17444a428430421d9710d725aeeab09a.png?x-oss-process=image/watermark,type_ZHJvaWRzYW5zZmFsbGJhY2s,shadow_50,text_Q1NETiBAZ2Z5Znk=,size_20,color_FFFFFF,t_70,g_se,x_16)
E[position--] = j + '0';
}
}
}
return true;
}
运行效果图
运行的具体代码就是上面的两个函数在主函数中调用,避免重复我就不贴出来了
来看结果
输出分析:第一行为原输入,第二行为转换的二进制串,第三行为转换的的八进制串
可以看到,不断是大写字符,小写字符,还是多个首位为零,都能输出理想结果
对于非法的输入,超出范围的字母和毫无关系的符号,在判断到非法字符时 StoB 函数将返回 false
那么来试试超长的字符!!!!!
更长的!!!!!
不过到此我们已经无法通过肉眼来判断输出结果的正确与否了,不过它至少没有报错,不是吗?
完结
以上,对于十六进制转二进制,与二进制转八进制的介绍就结束了,实际上,在明白与完成了十六进制转二进制后,二进制转十六进制应该就是理所应当了,一个十六进制字符转换为二进制,同样的将四个二进制字符转为一个十六进制字符就完成了,八进制转二进制也是同理。
由十六进制转二进制来得出八进制转二进制也是可以的,一个十六进制转为4个二进制字符,同理一个八进制转为3个二进制字符,也许这么想更容易理解?
另外你可以发现我所有的段落都没有在前面空两格,不是不想,而是搞了半天也不知道怎么弄
对于标题
我原本的标题为十六进制字符串转换为二进制字符串与二进制字符串转换为八进制字符串,这个标题是十分准确的,因为我在文章中的确只实现了十六进制字符串向二进制字符串,二进制字符串向八进制字符串的转换,但是写到末尾我认为,当理解这两个了之后,你应该可以在十六进制,八进制与二进制之间转换自如了,所以我修改了标题,不知道是否合理。