题目:
分析:
思路:先将十六进制转为二进制,然后将二进制转为八进制
遇到的问题如下:
1、输入格式和输出格式,决定了需要用数组存储十六进制数、二进制数以及八进制数。由于有多个字符串(多位十六进制数),故采用二维数组。
2、十六进制数由数字和字母“A/B/C/D/E/F”组成,在将十六进制转为二进制时,需要先判断十六进制数每一位是数字还是字母,并转化为十进制,再转为二进制(按位转化),并存储到二进制数组中。
3、需要注意是从后往前展开,举例:输入十六进制数:2A(0010 1010),存放到二进制数组的顺序相反:0101 0100,在将二进制转化为八进制的时候,仍然是倒序放入,输出时则从后往前,得出的即为正序。
4、二进制转八进制的过程:把二进制数组中每三位计算出来,依次到八进制数组中。对应的公式:num = 2^0 * A + 2^1 * B +2^2 * C。上述的A、B、C分别为二进制数组字符串中的每一位,即0或1。
5、那么如何判断每三位一组且循环相加呢?部分代码如下:
注意,此处利用每一位相乘的权值来判断是否计算了三位,第三位权值为4,所以用cnt==4来判断。而j==m-1是防止剩余不足三位。求和放到八进制数组中(倒序),由于为倒序,打印时也应该为倒序打印;
6、尽管用的是二维数组,但是由于在整个大循环中,用法和一维数组一样。需要注意的是:定义数组时,每个字符串长度要满足题目条件,每个十六进制数长度不超过100000。
代码如下:
运行环境:Code::Block 20.03
#include <stdio.h>
#include <string.h>
// 基础练习 十六进制转八进制
int main(void)
{
int n, i, j, k;
scanf("%d", &n);
char h[n][100000];
char b[n][400000];
char e[n][400000];
for(i = 0; i < n; i++)
{
scanf("%s",h[i]);
}
for(i = 0; i < n; i++)// 第一层循环:将每个字符串都化为二进制数,存放到b[i][m]中,m用来记录存放了对应字符串的长度
{
int m = 0;
for(j = strlen(h[i]) - 1; j >= 0; j--)
{
int num;
if(h[i][j] >= '0' && h[i][j] <= '9')
{
num = h[i][j] - '0';
}else{
num = h[i][j] - 'A' + 10;
}
for(k = 0; k < 4; k++)
{
b[i][m++] = num % 2 + '0';
num /= 2;
}
b[i][m] = '\0';
}
// //测试是否成功转化为二进制(从后往前展开),并存放到b[i][m]中
// for(j = 0; j < m; j++)
// {
// printf("%c", b[i][j]);
// }
// printf("\n");
//将b[i]中的每个字符串每三位计算出来,存放到e[i][l]数组中
int x = 0, cnt = 1, l = 0;
for(j = 0; j < m; j++)
{
if(cnt == 4 || j == m - 1)
{
x = cnt * ( b[i][j] - '0') + x;
e[i][l] = x + '0'; //由于定义e[][]为字符数组,所以需要+'0'字符转化一下
l++;
cnt = 1;
x = 0;
}else{
x = cnt * ( b[i][j] - '0') + x;
cnt *= 2;
}
}
j = l - 1;
while(j >= 0 && e[i][j] == '0') //题目规定不能有前导0,e[][]数组中是倒序存入,故从后往前判断是否为0
{
j--;
}
if(j < 0) //如果全为0则输出为0
{
printf("0");
}
for(; j >= 0; j--) //否则循环输出(输出为正序)
{
printf("%c", e[i][j]);
}
printf("\n");
}
return 0;
}
//菜鸟一枚,请多指正!
End