问题描述
给定n个十六进制正整数,输出它们对应的八进制数。
输入格式
输入的第一行为一个正整数n (1<=n<=10)。
接下来n行,每行一个由0~9、大写字母A~F组成的字符串,表示要转换的十六进制正整数,每个十六进制数长度不超过100000。
输出格式
输出n行,每行为输入对应的八进制正整数。
【注意】
输入的十六进制数不会有前导0,比如012A。
输出的八进制数也不能有前导0。
样例输入
2
39
123ABC
样例输出
71
4435274
【提示】
先将十六进制数转换成某进制数,再由某进制数转换成八进制。
算是一道模拟题吧?(是模拟题吧?因为比较浮躁,理论知识并不扎实,有错的地方还请大家原谅和指出)。
思路是对字符串进行遍历,但因为在二进制转八进制时要判断二进制是否需要前导零,为避免这种判断,我采用倒序遍历。16进制转2进制时,每次遍历1个16进制字符串中的一个字符串,将其转换为10进制数,再用除二取余法求2进制的表示,并倒序保存在2进制表示的数组中。
然后对2进制的数组倒序遍历,每次遍历三个元素,再其8进制表示方法倒序保存在8进制表示的数组中。
PS:看到自己的倒序方法在网上貌似没有,心里偷偷得意。
#include<stdio.h>
#include<string.h>
#include<malloc.h>
#include<math.h>
int* change(char* list, int list_l, int* ret_l){
int *list_2, *list_8;
int list_2_l, list_8_l, i, j, k, flag;
list_2_l = list_l * 4;
/*判断保存8进制数组的长度*/
if(list_2_l % 3 == 0) list_8_l = list_2_l / 3;
else list_8_l = list_2_l / 3 + 1;
list_2 = (int*)malloc(sizeof(int) * list_2_l);
list_8 = (int*)malloc(sizeof(int) * list_8_l);
/*i是16进制数组的下标,j是2进制数组的下标*/
for(i = list_l - 1, j = list_2_l - 1; i >= 0; i--){
//flag用于保存16进制这一位10进制的大小
if(list[i] >= '0' && list[i] <= '9')
flag = list[i] - '0';
else
flag = list[i] - 'A' + 10;
//16进制每一位用2进制表示需要4位,所以循环4次
for(k = 0; k < 4; k++){
list_2[j] = (flag % 2);
j--;
flag = flag / 2;
}
}
i = list_2_l - 1;//2进制数组下标
j = list_8_l - 1;//8进制数组下标
while(i >= 0){
flag = 0;//保存这三位2进制表示的8进制的大小
//8进制每一位用2进制表示需要3位,所以循环3次
for(k = 0; k < 3 && i >= 0; k++){
flag = flag + list_2[i] * pow(2, k);
i--;
}
list_8[j] = flag;
j--;
}
free(list_2);
*ret_l = list_8_l;
return list_8;
}
int main()
{
int n, i, list_l, ret_l, *ret_list;
//ret_l用于保存放回的8进制数组ret_list的长度
char list[100000];
scanf("%d", &n);
//吸收在上面这个scanf回车,否则会影响到下面的gets方法
getchar();
while(n--){
gets(list);
list_l = strlen(list);
ret_list = change(list, list_l, &ret_l);
/*判断第一个数字是否为零(最多只有可能第一个为零,因为我在二进制转换时采用的是倒序)*/
for(i = 0; i < ret_l && ret_list[i] ==0; i++);
for(; i < ret_l; i++) printf("%d", ret_list[i]);
free(ret_list);
ret_list = NULL;
printf("\n");
}
return 0;
}