蓝桥杯基础3:BASIC-12试题 十六进制转八进制(c语言)

【注意】
  先将十六进制数转换成某进制数,再由某进制数转换成八进制。

这道题首先应该想到的是先将十六进制数转化成二进制数,然后再转化成八进制数。而且都得用字符类型,因为转化成二进制后肯定都超出int、long、long long 的数据范围,所以整型类型绝对是不能用的。

使用十进制作为中转

笔者一开始看到这个题目想的就是先将十六进制转为十进制,再将十进制转为八进制。可能是脑袋瓜子不灵活,也可能是因为学过C语言做过类型的题目,像什么十进制转八进制,八进制转十进制之类的。
代码如下:

#include<stdio.h>
#include<string.h>
int main()
{
    int n,t,num_ten,num_eight;
    char str[10][100000];
    scanf("%d",&n);
    for(int i=0;i<n;i++)
        scanf("%s",str[i]);
    for(int i=0;i<n;i++)
    {
        int len = strlen(str[i])-1;         
        t=1;
        num_ten=0;
        while(len>=0)               //将16进制转为10进制
        {
            if(str[i][len]>='0'&&str[i][len]<='9')
                num_ten+=(str[i][len]-'0')*t;
            else
                num_ten+=(str[i][len]-'A'+10)*t;
            t=t*16;
            len--;
        }
        t=1;
        num_eight=0;
        while(num_ten)      //将10进制转为8进制
        {
            num_eight+=num_ten%8*t;
            t=t*10;
            num_ten/=8;
        }
        printf("%d\n",num_eight);
    }
    return 0;
}

笔者很单纯的将测试样例带入程序,结果显示是正确的,但是,将代码提交却是说编译结果不正确😭😭😭。后面仔细分析题目,每个十六进制数长度不超过100000。这肯定是不能用十进制整型类型来做的。因为肯定会超过int,long,long long的范围。C语言int的取值范围在32/64位系统中都是32位,范围为-2147483648到+2147483647,无符号情况下表示为0到4294967295。(PS:之前学习C语言以为这个范围没什么用,但现在深刻体会到该范围的限制性)
接着看了大佬们的作品,思路发生转变,内心不禁感叹。
链接: https://blog.csdn.net/try_fei_ge/article/details/53239501.

使用二进制作为中转

本来是想将大佬的第二种方法细化的分析下的,可是我将他的第一个没改进前的代码提交了下,发现结果显示正确,且提交没有超时,结果如下图,就干脆将这个一起分析下算了。
在这里插入图片描述

先上代码,我将大佬代码的格式规范化了一下其实很简单,只要右击鼠标,然后点击format this file即可 ,还加了一点点注释,代码虽长,但很好理解。
先简单介绍下代码的思路:在进制转换中,可以直接将1位十六进制的数转换为4位二进制的数,1位八进制的数转换位3位二进制的数,因为此题一个十六进制的数最大有100000位,那么就需要400000位二进制作为中转站,为了节约运行时间和内存,采用同时将3位十六进制转为12位二进制,接着将这十二位二进制转为4位八进制的思路解决问题。

在看代码前先介绍一下各个变量的含义:

  1. n:代表输入十六进制数的个数
  2. s:二维数组,用来存放十六进制数
  3. a:用来表示某一个十六进制数的位数距离能被3整除还差几位
  4. ok:用于判断12位二进制转为八进制时,最前面的四位是否为0
  5. z:一维数组,用来暂存某个十六进制的某三位转为的12位二进制数
  6. i,j,k,cur只是作为循环的中间变量

下面看代码应该会很好理解了,请大家一定不要心躁,心平气和的来看代码,一遍不懂就再看多看几遍,坚持下去总归会弄明白的,加油💪。

#include<stdio.h>
#include<string.h>
int main()
{
    int n,i,j,k,a=0,cur,ok;
    char s[10][100000],z[12];
    scanf("%d",&n);
    for(j=0; j<n; j++)
        scanf("%s",s[j]);
    for(j=0; j<n; j++)
    {
        ok=1;
        if(strlen(s[j])%3!=0&&a==0&&(a=(3-(strlen(s[j])%3)))!=0)    //是判断当前的这个十六进制的位数离3的整数还差几位
        {
            for(k=0; k<a*4; k++)    //将三位16进制的转二进制,不足12位的,在前面补全0
                z[k]='0';
        }
        for(i=0; i<strlen(s[j]); i++)   //将每位16进制位数转为四位二进制
        {

            switch(s[j][i])
            {
            case '0':
                z[k]='0';
                z[k+1]='0';
                z[k+2]='0';
                z[k+3]='0';
                break;
            case '1':
                z[k]='0';
                z[k+1]='0';
                z[k+2]='0';
                z[k+3]='1';
                break;
            case '2':
                z[k]='0';
                z[k+1]='0';
                z[k+2]='1';
                z[k+3]='0';
                break;
            case '3':
                z[k]='0';
                z[k+1]='0';
                z[k+2]='1';
                z[k+3]='1';
                break;
            case '4':
                z[k]='0';
                z[k+1]='1';
                z[k+2]='0';
                z[k+3]='0';
                break;
            case '5':
                z[k]='0';
                z[k+1]='1';
                z[k+2]='0';
                z[k+3]='1';
                break;
            case '6':
                z[k]='0';
                z[k+1]='1';
                z[k+2]='1';
                z[k+3]='0';
                break;
            case '7':
                z[k]='0';
                z[k+1]='1';
                z[k+2]='1';
                z[k+3]='1';
                break;
            case '8':
                z[k]='1';
                z[k+1]='0';
                z[k+2]='0';
                z[k+3]='0';
                break;
            case '9':
                z[k]='1';
                z[k+1]='0';
                z[k+2]='0';
                z[k+3]='1';
                break;
            case 'A':
                z[k]='1';
                z[k+1]='0';
                z[k+2]='1';
                z[k+3]='0';
                break;
            case 'B':
                z[k]='1';
                z[k+1]='0';
                z[k+2]='1';
                z[k+3]='1';
                break;
            case 'C':
                z[k]='1';
                z[k+1]='1';
                z[k+2]='0';
                z[k+3]='0';
                break;
            case 'D':
                z[k]='1';
                z[k+1]='1';
                z[k+2]='0';
                z[k+3]='1';
                break;
            case 'E':
                z[k]='1';
                z[k+1]='1';
                z[k+2]='1';
                z[k+3]='0';
                break;
            case 'F':
                z[k]='1';
                z[k+1]='1';
                z[k+2]='1';
                z[k+3]='1';
                break;
            }
            k+=4;
            if(k==12)   //当三位十六进制都转为4为二进制后,开始将12位二进制变为四位八进制
            {
                for(cur=0; cur<12; cur+=3)  //四位体现在cur+=3
                    if(z[cur]=='0'&&z[cur+1]=='0'&&z[cur+2]=='0')if(ok);
                        else putchar('0');
                    else if(z[cur]=='0'&&z[cur+1]=='0'&&z[cur+2]=='1')
                    {
                        putchar('1');
                        ok=0;
                    }
                    else if(z[cur]=='0'&&z[cur+1]=='1'&&z[cur+2]=='0')
                    {
                        putchar('2');
                        ok=0;
                    }
                    else if(z[cur]=='0'&&z[cur+1]=='1'&&z[cur+2]=='1')
                    {
                        putchar('3');
                        ok=0;
                    }
                    else if(z[cur]=='1'&&z[cur+1]=='0'&&z[cur+2]=='0')
                    {
                        putchar('4');
                        ok=0;
                    }
                    else if(z[cur]=='1'&&z[cur+1]=='0'&&z[cur+2]=='1')
                    {
                        putchar('5');
                        ok=0;
                    }
                    else if(z[cur]=='1'&&z[cur+1]=='1'&&z[cur+2]=='0')
                    {
                        putchar('6');
                        ok=0;
                    }
                    else if(z[cur]=='1'&&z[cur+1]=='1'&&z[cur+2]=='1')
                    {
                        putchar('7');
                        ok=0;
                    }
                k=0;//将k置0,开始将下面三位16进制进行转换
            }
        }
        a=0;//假设第j个十六进制数的位数是三的倍数
        putchar('\n');
    }
    return 0;
}

下面解释一下比较难理解代码的含义:

if(strlen(s[j])%3!=0&&a==0&&(a=(3-(strlen(s[j])%3)))!=0)    //是判断当前的这个十六进制的位数离3的整数还差几位
        {
            for(k=0; k<a*4; k++)    //将三位16进制的转二进制,不足12位的,在前面补全0
                z[k]='0';
        }

正如注释中写到的,这段代码的含义就是将长度未满3的倍数的十六进制补全,例如所给的案例输入:39,因为它只有2位十六进制,不能满足上面所说的3位十六进制转为12位二进制,故用此段代码来进行补全,将十六进制39转为二进制0000 0011 1001,这样,所有情况都可以用下面的代码来转为8进制了👍👍👍。
经过我测试,发现这段代码放在ok=1的后面也是可以正确运行的,因为无论怎样,这段代码都只会运行一次,即if里面的条件只会满足一次,因为补全为三只需要一次即可。读者可以自行尝试😁。

优化二进制中转

感受到代码的奇妙之后,咱们再来看看优化之后的算法,怎么来优化呢,首先细细品味咱们上面的那个代码,将1位十六进制转为4位二进制时,每位都要进行判断,然后转换,这实在是太费事了。这可以怎么解决呢?咱们来看,十六进制0对应二进制0000,1对应0001,2对应0010…F对应1111,看出来了吧,我们可以之间建立一个大小为16的字符串数组,也就是二维字符数组,直接将十六进制作为四位二进制的下标,那不就简单了,比如说d16存放0-F的二进制字符串,那么d16[0]就是0000,d16[15]就是1111。
还有就是在进行二进制转八进制的时候,我们可以将十二位二进制之间按位权展开, 然后一起输出,就不必在进行一个一个判断,这又能节约很多时间,不过节约了时间就得多好费点空间,下面会说到空间是为什么会耗费的。
同样,在看代码前来解释下各变量的含义,以上一个大同小异,这里相同的就不再介绍了。
1. ok:是十六进制数的位数否能被3整除。
2. d16:二维数组,存放0-F的四位二进制代码
3. out:一维数组,用来保存某个十六进制数转为八进制数后的结果

#include<stdio.h>
#include<string.h>
int main()
{
    int n,i,j,k,a,cur,ok,m,l;
    char s[10][100001],d16[16][5]= {"0000","0001","0010","0011","0100","0101","0110","0111","1000","1001","1010","1011","1100","1101","1110","1111"},out[140000]= {},z[13]= {};
    scanf("%d",&n);
    for(j=0; j<n; j++)
        scanf("%s",s[j]);
    for(j=0; j<n; j++)
    {
        k=0;
        ok=1;
        m=0;                            /*初始化标记数据*/
        l=strlen(s[j]);                           /* 初始化标记数据*/
        a=3-l%3;                                   /*初始化标记数据*/
        if(a==3)	ok=0;                    /*十六进制数长度刚好为3的倍数时转二进制不需补0,ok标记其是否为3的倍数0是1不是*/
        for(i=0; i<l; i++)                     /*逐位读取十六进制数进行转换*/
        {
            if(65<=s[j][i])
                s[j][i]-=7;
            if(ok)                                     /*十六进制数位数不足转二进制时补0占位*/
                if(a==1)
                {
                    strcat(z,"0000");
                    k=k+4;
                    ok=0;
                }
                else if(a==2)
                {
                    strcat(z,"00000000");
                    k=k+8;
                    ok=0;
                }
            z[k++]=d16[s[j][i]-48][0];                  /*一位十六进制转四位二进制*/
            z[k++]=d16[s[j][i]-48][1];
            z[k++]=d16[s[j][i]-48][2];
            z[k++]=d16[s[j][i]-48][3];
            if(k==12)                                    /*每转三位十六进制数将其转为四位八进制数*/
            {
                for(cur=0; cur<12; m++)
                    out[m]=((z[cur++]-48)*4+(z[cur++]-48)*2+(z[cur++]-48)*1)+48;
                //z[0]='\0';
                k=0;                               /*z[0]='\0' 初始化字符串结束符位置避免溢出*/
            }
        }
        for(; k<3; k++)                                /*输出时忽略前导0*/
            if(out[k]!=48)	break;
        for(; k<m; k++)
            printf("%c",out[k]);
        putchar('\n');
    }
    return 0;
}

该代码和前一个代码的意思是相同的,让我们来详细的一段一段代码的分析下。

        l=strlen(s[j]);                           /* 初始化标记数据*/
        a=3-l%3;                                   /*初始化标记数据*/
        if(a==3)	ok=0;                    /*十六进制数长度刚好为3的倍数时转二进制不需补0,ok标记其是否为3的倍数0是1不是*/

这段代码的意思也是判断十六进制的位数是否是3的倍数,不是的话得补几位

  • 码就是实现将十六进制数对应为四位二进制数的下标,0-9很好对应,直接减去48即可。但是A-F呢?为了将0-F一同对待,同样减去48,我们知道A对应的ASCAII是65,A的十六进制数是10,所以先将A-?=10,?=55,所以A先减去7,在减去48就是对应的十六进制数10。
            if(k==12)                                    /*每转三位十六进制数将其转为四位八进制数*/
            {
                for(cur=0; cur<12; m++)
                    out[m]=((z[cur++]-48)*4+(z[cur++]-48)*2+(z[cur++]-48)*1)+48;
                //z[0]='\0';
                k=0;                               /*z[0]='\0' 初始化字符串结束符位置避免溢出*/
            }

这里和前一个程序的思路不太一样,前一个程序是把每次三位的二进制数转八进制数后直接输出来,但这里是将某个十六进制数的转为八进制后,直接数出来。

z[0]=’\0’ 初始化字符串结束符位置避免溢出*/。这句笔者也不太能理解是做什么用的,不过我将这句去掉判分系统也是判的是正确的。望知道的读者能够解答解答😊。

对比上面两个:

在这里插入图片描述


可以明显看出,cpu的时间是大大减小,不过内存占用稍微大了一点点,是因为加了out[140000]这个一位数组的原因。

在我看来,可以将以上两个程序结合一下,这样内存的使用会不会也大大减小了,先看看结果:

果然,时间和空间都达到了理想效果,下面贴上代码以及解析。

#include<stdio.h>
#include<string.h>
int main()
{
    int n,i,j,k,a,cur,ok,m,l,flag;
    char s[10][100001],d16[16][5]= {"0000","0001","0010","0011","0100","0101","0110","0111","1000","1001","1010","1011","1100","1101","1110","1111"},out[4]= {},z[13]= {};
    scanf("%d",&n);
    for(j=0; j<n; j++)
        scanf("%s",s[j]);
    for(j=0; j<n; j++)
    {
        k=0;
        ok=1;
        flag = 0;
        m=0;                            /*初始化标记数据*/
        l=strlen(s[j]);                           /* 初始化标记数据*/
        a=3-l%3;                                   /*初始化标记数据*/
        if(a==3)	ok=0;                    /*十六进制数长度刚好为3的倍数时转二进制不需补0,ok标记其是否为3的倍数0是1不是*/
        for(i=0; i<l; i++)                     /*逐位读取十六进制数进行转换*/
        {
            if(65<=s[j][i])
                s[j][i]-=7;
            if(ok)                                     /*十六进制数位数不足转二进制时补0占位*/
                if(a==1)
                {
                    strcpy(z,"0000");
                    k=k+4;
                    ok=0;
                    a=0;
                }
                else if(a==2)
                {
                    strcpy(z,"00000000");
                    k=k+8;
                    ok=0;
                }
            z[k++]=d16[s[j][i]-48][0];                  /*一位十六进制转四位二进制*/
            z[k++]=d16[s[j][i]-48][1];
            z[k++]=d16[s[j][i]-48][2];
            z[k++]=d16[s[j][i]-48][3];
            if(k==12)                                    /*每转三位十六进制数将其转为四位八进制数*/
            {
                m=0;
                for(cur=0; cur<12; m++)
                    out[m]=((z[cur++]-48)*4+(z[cur++]-48)*2+(z[cur++]-48)*1)+48;
                cur = 0;
                k=0;
                if(!flag)
                    while(out[cur]=='0'&&cur<m)
                        cur++;
                if(cur==m)
                    flag = 0;
                else
                    flag = 1;
                for(; cur<m; cur++)
                    printf("%c",out[cur]);
            }

        }
        putchar('\n');
    }
    return 0;
}

首先,此代码和第一个未优化的代码相似,是每次三位的二进制数转八进制数后直接输出来,并且加上了判断开头是否为0的情况。其次,在改写这个代码的时候,笔者发现上面的那个疑问,即z[0]=’\0’ 初始化字符串结束符位置避免溢出*/。一开始编写改代码发现一直报错,但一直找不到原因,后来仔细分析原来是strcat的原因。这句话去掉后,把strcat改成strcpy即可。😃😃😃

最后,接下来会不断更新蓝桥杯有关题目,希望大家共同学习,共同进步,并不是为了奖状而去比赛,是为了自己能够学到真本领,这样才会越学越快乐,越学越有动力哦,加油!!!

上文采用链接:http://t.csdn.cn/keA4G

#include<stdio.h>

#include<string.h>
int main()
{
 int n,i,j,k,a,cur,ok,m,l;
 char s[10][100001],d16[16][5]={"0000","0001","0010","0011","0100","0101","0110","0111","1000","1001","1010","1011","1100","1101","1110","1111"},out[140000]={},z[13]={};
 scanf("%d",&n);                      
 for(j=0;j<n;j++)
  scanf("%s",s[j]);
 for(j=0;j<n;j++)  
  {
   k=0;ok=1;m=0;                            /*初始化标记数据*/ 
   l=strlen(s[j]);                           /* 初始化标记数据*/ 
   a=3-l%3;                                   /*初始化标记数据*/   //求出要将这个十六进制数补足为3的倍数需要补上多少个0
   if(a==3) ok=0;                    /*十六进制数长度刚好为3的倍数时转二进制不需补0,ok标记其是否为3的倍数0是1不是*/ 
   for(i=0;i<l;i++)                       /*逐位读取十六进制数进行转换*/ 
   {
    if(65<=s[j][i])                          
     s[j][i]-=7; //这里不理解请查阅ASCII代码表
    if(ok)                                     /*十六进制数位数不足转二进制时补0占位*/ 
     if(a==1){  //若需补一个十六进制的0,相当于补上四个二进制的0即0000,下面补两位也一样
      strcat(z,"0000");k=k+4;ok=0;
     }else if(a==2){
      strcat(z,"00000000");k=k+8;ok=0;
     }
    z[k++]=d16[s[j][i]-48][0];                  /*一位十六进制转四位二进制*/ 
    z[k++]=d16[s[j][i]-48][1];
    z[k++]=d16[s[j][i]-48][2];
    z[k++]=d16[s[j][i]-48][3];
    if(k==12)                                    /*每转三位十六进制数将其转为四位八进制数*/ 
    {
     for(cur=0;cur<12;m++)
      out[m]=((z[cur++]-48)*4+(z[cur++]-48)*2+(z[cur++]-48)*1)+48;
     z[0]='\0';k=0;                               /*z[0]='\0'初始化字符串结束符位置避免溢出*/ 
    }
   }                                      
   for(;k<3;k++)                                  /*输出时忽略前导0*/ 
    if(out[k]!=48) break; //48是字符‘0’的ASCII值
   for(;k<m;k++)
    printf("%c",out[k]);
   putchar('\n');
  }
 return 0;
 } 

上文采用链接:http://t.csdn.cn/D372y

个人整理及详细解说

 /* 想法: 
 1.数组存储字符串string ,shiliu[10][100000]:这样子表示只能是10个数,一个数占一行 ,100000是表示数值最大值
 *****数组存储 整数 和 数组存储 字符串,表达的形态不太一样。
  数组存储 整数
       s[3][2]表示存储 3行2列个数,也就是 存储6 个数。
  数组存储 字符串
       s[3][2]表示存储 3 个数,一行代表一个数(字符串),2表示字符串的长度最大值,
       也就是可以存99,1,但不可以存 100及以上。所以可以直接用s[i](s[3],可以输入3个数据)来输入数据,
       当满足输入的数据 <= 2 (也就是字符串长度最大值)则存储。 
        
 er[12]。因为是存储字符串,所以要用char 
 2.进制转换,16-> 2-> 8。1 位十六进制 = 4位二进制数,1 位八进制数 = 3位二进制数。
    为了转换方便一次转换 3 位16进制数,转化为 12 位二进制数,再转化为 4位八进制数。 
问题1:不够 3的倍数 。3 位16进制数(例如1234,分为001,234。
    也就是 16进制的 1转化位12位二进制数)转化为 二进制 , 不满12 位二进制数则补0。 
问题2:输出的八进制数也不能有前导 0。设置一个标记,当前导为0;没有语句,也就是
    if(ok) ;  这样子就不会有输出 

/*题目:给定n个十六进制正整数,输出它们对应的八进制数。
看题得:用数组存储字符串(也可以直接采用字符串),进制转换 .1位十六进制的数转换为4位二进制的数,采用 字符串 
         1位八进制的数转换位3位二进制的数
         3*4=12
         将3位十六进制转为12位二进制,接着将这十二位二进制转为4位八进制
         由此,可以用一维数组来存储中间商二进制数 B[12] 
 
输入格式:
  输入的第一行为一个正整数n (1<=n<=10)。
  接下来n行,每行一个由0~9、大写字母A~F组成的字符串,表示要转换的十六进制正整数,每个十六进制数长度不超过100000。
    由此可以设计二维数组为  A[10][100000] 

输出格式:
  输出n行,每行为输入对应的八进制正整数。

  【注意】
  输入的十0六进制数不会有前导0,比如012A。
  输出的八进制数也不能有前导0。
    进制转换:16-> 2-> 8
*/
 
//头文件 
#include<stdio.h>//标准输入输出 
#include<string.h>/*字符串处理 。string .h 头文件定义了一个变量类型、一个宏和各种操作字
                    符数组的函数。C语言里面关于字符数组的函数定义的头文件,常用函数有
                    strlen(字符串长度)、strcmp、strcpy等等,更详细的可以到include文件夹里面查看该文件。
                   */ 
                   
int main(){
    //定义(不要忘记定义!!!!!!)
     char A[10][100000], z[12];//char类型! 正整数n (1<=n<=10),十六进制数长度不超过100000,12位二进制
     //B:一维数组,用来暂存某个十六进制的某三位转为的12位二进制数
     int n,i,ok,a=0,k,j,cur;
     
    //输入正整数n,表示有n个元素 
     scanf("%d",&n);
     for(i=0;i<n;i++)
         scanf("%s",&A[i]); //输入字符串 ,由于输入的字符串,则字符串就会有长度,采用头文件#include<string.h> 
         //&A[i],此处的 scanf("%s",&A[i]); 可以为scanf("%s",A[i]); 
     for(i=0;i<n;i++)
     {
         ok=1;//ok:用于判断12位二进制转为八进制时,最前面的四位是否为 0
         /*是判断当前的这个十六进制的位数离 3的整数还差几位,如果不足12位,则补0 
         这是因为将一次性把 3位十六进制转为 12位二进制,所以 16进制数的位数要满足 3的倍数 
         这样子转化后方便后方 转化为 八进制。 
         */ 
         if(strlen(A[i])%3!=0)
         {
             a=3-(strlen(A[i])%3); //a:用来表示某一个十六进制数的位数距离能被3整除还差几位
             //以下是将三位16进制的转二进制,不足12位的,在前面补全0
             for(k=0;k<a*4;k++)
                 z[k]='0';//B:一维数组,用来暂存某个十六进制的 某三位 转为的12位二进制数
                 //此处要注意:是z[k]='0';,不是z[k]=0;要单引号!!!!!是字符串 
                 //举例:若是为(1234)16,则对应的 24位。可以把(1234)16 看成(001,234)16 ,所以为24位 
         }     
         /*举个例子 1
           (72)16转化为二进制, 1位十六进制的数转换为4位二进制数。则7转化为 0111,2可以转化为0010.
           所以(72)16转化为二进制为(01110010)2
           由于要转化为八进制,并且1位八进制的数转换为3位二进制数。所以16进制转化的二进制数的位数要为3的倍数
           取最小公倍数,则可知3*4=12.
           
           由于字符串72为2位16进制数,经过运算可知 a=1, k=4-1=3。B[0]~B[3],补充 4个0.
           (72)16= (0111,0010)2=(0000,0111,0010)2 =(000,001,110,010)2 =(162)8
         */
         
         /*举个例子 2
            (1234)16,很明显位数不是 3的倍数,a =2,k =8-1=7. B[0]~B[7],补充 8个0.
            (1234)16=(0001,0010,0011,0100)2 =(0000,0000,0001,0010,0011,0100)2
            而(0000,0000,0001,0010,0011,0100)2=(000,000,000,001,001,000,110,100)2=(11064)8
         */ 
         
         //以下是将每位16进制位数转为四位二进制 
         for(j=0;j<strlen(A[i]);j++)
         {
             switch(A[i][j])//A[i][j]的意思是第 i个数(字符串)的第 j个字符(第 j位数)
             {
            case '0':
                z[k]='0';
                z[k+1]='0';
                z[k+2]='0';
                z[k+3]='0';
                break;
            case '1':
                z[k]='0';
                z[k+1]='0';
                z[k+2]='0';
                z[k+3]='1';
                break;
            case '2':
                z[k]='0';
                z[k+1]='0';
                z[k+2]='1';
                z[k+3]='0';
                break;
            case '3':
                z[k]='0';
                z[k+1]='0';
                z[k+2]='1';
                z[k+3]='1';
                break;
            case '4':
                z[k]='0';
                z[k+1]='1';
                z[k+2]='0';
                z[k+3]='0';
                break;
            case '5':
                z[k]='0';
                z[k+1]='1';
                z[k+2]='0';
                z[k+3]='1';
                break;
            case '6':
                z[k]='0';
                z[k+1]='1';
                z[k+2]='1';
                z[k+3]='0';
                break;
            case '7':
                z[k]='0';
                z[k+1]='1';
                z[k+2]='1';
                z[k+3]='1';
                break;
            case '8':
                z[k]='1';
                z[k+1]='0';
                z[k+2]='0';
                z[k+3]='0';
                break;
            case '9':
                z[k]='1';
                z[k+1]='0';
                z[k+2]='0';
                z[k+3]='1';
                break;
            case 'A':
                z[k]='1';
                z[k+1]='0';
                z[k+2]='1';
                z[k+3]='0';
                break;
            case 'B':
                z[k]='1';
                z[k+1]='0';
                z[k+2]='1';
                z[k+3]='1';
                break;
            case 'C':
                z[k]='1';
                z[k+1]='1';
                z[k+2]='0';
                z[k+3]='0';
                break;
            case 'D':
                z[k]='1';
                z[k+1]='1';
                z[k+2]='0';
                z[k+3]='1';
                break;
            case 'E':
                z[k]='1';
                z[k+1]='1';
                z[k+2]='1';
                z[k+3]='0';
                break;
            case 'F':
                z[k]='1';
                z[k+1]='1';
                z[k+2]='1';
                z[k+3]='1';
                break;
              } 
              k+=4;//每位16进制位数转为四位二进制 ,是故,转化一位16进制数 就要往后挪 4 个空间给下一个使用 
              if(k==12)   //当三位十六进制都转为4为二进制后,开始将12位二进制变为四位八进制
               {
                for(cur=0; cur<12; cur+=3)  //四位体现在cur+=3
                    if(z[cur]=='0'&&z[cur+1]=='0'&&z[cur+2]=='0')if(ok);
                    //ok:用于判断12位二进制转为八进制时,最前面的四位是否为 0
                        else putchar('0');//此时不是最前面四位 
                    else if(z[cur]=='0'&&z[cur+1]=='0'&&z[cur+2]=='1')
                    {
                        putchar('1');// putchar打印输出 
                        ok=0;
                    }
                    else if(z[cur]=='0'&&z[cur+1]=='1'&&z[cur+2]=='0')
                    {
                        putchar('2');
                        ok=0;
                    }
                    else if(z[cur]=='0'&&z[cur+1]=='1'&&z[cur+2]=='1')
                    {
                        putchar('3');
                        ok=0;
                    }
                    else if(z[cur]=='1'&&z[cur+1]=='0'&&z[cur+2]=='0')
                    {
                        putchar('4');
                        ok=0;
                    }
                    else if(z[cur]=='1'&&z[cur+1]=='0'&&z[cur+2]=='1')
                    {
                        putchar('5');
                        ok=0;
                    }
                    else if(z[cur]=='1'&&z[cur+1]=='1'&&z[cur+2]=='0')
                    {
                        putchar('6');
                        ok=0;
                    }
                    else if(z[cur]=='1'&&z[cur+1]=='1'&&z[cur+2]=='1')
                    {
                        putchar('7');
                        ok=0;
                    }
                k=0;//将k置0,继续将下面三位16进制进行转换,也就是转化够 12位二进制就转化为8进制,然后归0,再继续。 
            }
         }
         putchar('\n');//每个数转化成八进制后的输出规范 
     } 
    return 0;

 二次理解

/*题目: 
给定n个十六进制正整数,输出它们对应的八进制数。

输入格式
  输入的第一行为一个正整数n (1<=n<=10)。
  接下来n行,每行一个由0~9、大写字母A~F组成的字符串,表示要转换的十六进制正整数,
    每个十六进制数长度不超过100000。

输出格式
  输出n行,每行为输入对应的八进制正整数。

  【注意】
  输入的十六进制数不会有前导0,比如012A。
  输出的八进制数也不能有前导0。
 */ 
 
 
 /* 想法: 
 1.数组存储字符串string ,shiliu[10][100000]:这样子表示只能是10个数,一个数占一行 ,100000是表示数值最大值
 *****数组存储 整数 和 数组存储 字符串,表达的形态不太一样。
  数组存储 整数
       s[3][2]表示存储 3行2列个数,也就是 存储6 个数。
  数组存储 字符串
       s[3][2]表示存储 3 个数,一行代表一个数(字符串),2表示字符串的长度最大值,
	   也就是可以存99,1,但不可以存 100及以上。所以可以直接用s[i](s[3],可以输入3个数据)来输入数据,
	   当满足输入的数据 <= 2 (也就是字符串长度最大值)则存储。 
	    
 er[12]。因为是存储字符串,所以要用char 
 2.进制转换,16-> 2-> 8。1 位十六进制 = 4位二进制数,1 位八进制数 = 3位二进制数。
    为了转换方便一次转换 3 位16进制数,转化为 12 位二进制数,再转化为 4位八进制数。 
问题1:不够 3的倍数 。3 位16进制数(例如1234,分为001,234。
	也就是 16进制的 1转化位12位二进制数)转化为 二进制 , 不满12 位二进制数则补0。 
问题2:输出的八进制数也不能有前导 0。设置一个标记,当前导为0;没有语句,也就是
	if(ok) ;  这样子就不会有输出 
	 
  总结:想法是好,有点麻烦,需要变动很多地方 
 
 */ 
//头文件(1) 
#include <stdio.h>
#include<string.h> 
int main(){
	//定义(最终要检查是否有漏!!!!!) 
	char shiliu[10][100000],er[12];
	int n,i,j,ok;
	int w=0; 
	//输入(2)
	scanf("%d",&n); 
	for(i=0;i<n;i++)
	    scanf("%s",&shiliu[i]);
	//一个个的字符串数进行转换(3)
	for(i=0;i<n;i++)
	{
		//ok:用于判断12位二进制转为八进制时,最前面的四位是否为 0(7)
		ok=1;
		/*由于二进制换为八进制,二进制的位数是3的倍数更方便转换,所以当不够倍数时,
		在前面补0 补够位数 。为了节省时间空间,一次换:3位16进制数换为 12位二进制
		3位3位一组,所以er[12],探求关系与联系(5) 
			*/ 
		int q=0;//q:用来表示某一个十六进制数的位数距离能被3整除还差几位
		if(strlen(shiliu[i])%3 !=0)
		{
			q=3-(strlen(shiliu[i])%3);
			//不足12位,补0(找q与12位缺的位数关系)
			for(w=0;w<q*4;w++)
			    er[w]='0';			 
		}
		//每个字符串的字符各自一个个转换(4) 
		for(j=0;j<strlen(shiliu[i]);j++)
		{
	   // int w=0;(放前面调整)
	   //定义语句要放在switch外面!!!!因为switch里面是分支语句,不含有其他语句 
		//转换用switch 分支语句进行一一转换,注意是字符,所以要加单引号,数字和字母都要!(5) 
		switch(shiliu[i][j])//此时看每个字符,则要具体存储位置,eg:s[2][2] 是 字符A 
		{ //一位 16进制可以转换为 4 为 二进制 ,转换完一位,er[]空间要往后加四,给下一个字符空间存储 
		//所以设 w=0;做位置标记,最后一位转换完 w+=4;
			case '0': 
			    er[w]='0';
			    er[w+1]='0';
			    er[w+2]='0';
			    er[w+3]='0';
				break;
			case '1':
				er[w]='0';
			    er[w+1]='0';
			    er[w+2]='0';
			    er[w+3]='1';
				break;
			case '2':
				er[w]='0';
			    er[w+1]='0';
			    er[w+2]='1';
			    er[w+3]='0';
				break;
			case '3':
				er[w]='0';
			    er[w+1]='0';
			    er[w+2]='1';
			    er[w+3]='1';
				break;
			case '4':
				er[w]='0';
			    er[w+1]='1';
			    er[w+2]='0';
			    er[w+3]='0';
				break;
			case '5':
				er[w]='0';
			    er[w+1]='1';
			    er[w+2]='0';
			    er[w+3]='1';
				break;
			case '6':
				er[w]='0';
			    er[w+1]='1';
			    er[w+2]='1';
			    er[w+3]='0';
				break;
			case '7':
				er[w]='0';
			    er[w+1]='1';
			    er[w+2]='1';
			    er[w+3]='1';
				break;	
		    case '8':
		    	er[w]='1';
			    er[w+1]='0';
			    er[w+2]='0';
			    er[w+3]='0';
				break;
			case '9':
				er[w]='1';
			    er[w+1]='0';
			    er[w+2]='0';
			    er[w+3]='1';
				break;
			case 'A':
				er[w]='1';
			    er[w+1]='0';
			    er[w+2]='1';
			    er[w+3]='0';
				break;
			case 'B':
				er[w]='1';
			    er[w+1]='0';
			    er[w+2]='1';
			    er[w+3]='1';
				break;
			case 'C':
				er[w]='1';
			    er[w+1]='1';
			    er[w+2]='0';
			    er[w+3]='0';
				break;
			case 'D':
				er[w]='1';
			    er[w+1]='1';
			    er[w+2]='0';
			    er[w+3]='1';
				break;
			case 'E':
				er[w]='1';
			    er[w+1]='1';
			    er[w+2]='1';
			    er[w+3]='0';
				break;
			case 'F':
				er[w]='1';
			    er[w+1]='1';
			    er[w+2]='1';
			    er[w+3]='1';
				break;	
		 }
		 w+=4; 
		 //当 3位 16进制数转换为 12位二进制,也就是er[12]满足够了12位,则先转换为八进制(6)
		 if(w==12)
		 {
		 	int ba;
		 	//3位 二进制可以换一位 8进制,设位置标记 ba;每转换 3位便位置 +3,下三位继续转换,也就是 ba+=3  
			for(ba=0;ba<12;ba+=3)
			{
				//ok:用于判断12位二进制转为八进制时,最前面的四位是否为 0(7)
				if(er[ba]=='0'&& er[ba+1]=='0' && er[ba+2]=='0')
				    if(ok)  ;
				    else putchar('0');
				else if(er[ba]=='0'&& er[ba+1]=='0' && er[ba+2]=='1')
				{
					putchar('1');//输出 printf用于多数 和 putchar用于输出字符 
					ok = 0;
				}
				else if(er[ba]=='0'&& er[ba+1]=='1' && er[ba+2]=='0')
				{
					putchar('2');
					ok = 0;
				}
				else if(er[ba]=='0'&& er[ba+1]=='1' && er[ba+2]=='1')
				{
					putchar('3');
					ok = 0;
				}
				else if(er[ba]=='1'&& er[ba+1]=='0' && er[ba+2]=='0')
				{
					putchar('4');
					ok = 0;
				}
				else if(er[ba]=='1'&& er[ba+1]=='0' && er[ba+2]=='1')
				{
					putchar('5');
					ok = 0;
				}
				else if(er[ba]=='1'&& er[ba+1]=='1' && er[ba+2]=='0')
				{
					putchar('6');
					ok = 0;
				}
				else if(er[ba]=='1'&& er[ba+1]=='1' && er[ba+2]=='1')
				{
					putchar('7');
					ok = 0;
				}
		    } 
			w=0;//将w置0,继续将下面三位16进制进行转换,也就是转化够 12位二进制就转化为8进制,然后归0,再继续。?	
		 }
	   }
	   //测试发现结果都是合在一起 ,为了输出规范(8)
	   putchar('\n');//也可以是printf("\n");
	 }  
	return 0;
} 

个人整理详细解说:采用公式法​​​​​​​

 /*这个是使用ASCLL码字符串所对应的十进制的值进行运算 
'0'的值是48,'9'的值是57,'A'的值是65,'F' 的值是70 
*/
#include<stdio.h>
#include<string.h>
int main()
{
    int n,i,j,k,a,cur,ok,m,l,flag;
    char s[10][100001],d16[16][5]= {"0000","0001","0010","0011","0100","0101","0110","0111","1000","1001","1010","1011","1100","1101","1110","1111"},out[4]= {},z[13]= {};
    scanf("%d",&n);
    for(j=0; j<n; j++)
        scanf("%s",s[j]);
    for(j=0; j<n; j++)
    {
        k=0;
        ok=1;
        flag = 0;
        m=0;                            /*初始化标记数据*/
        l=strlen(s[j]);                           /* 初始化标记数据*/
        a=3-l%3;                                   /*初始化标记数据*/
        if(a==3) ok=0;                    /*十六进制数长度刚好为3的倍数时转二进制不需补0,ok标记其是否为3的倍数0是1不是*/
        for(i=0; i<l; i++)                     /*逐位读取十六进制数进行转换*/
        {
            if(s[j][i]>=65)
                s[j][i]-=7;//查看ASCLL表可知,'9'距离'A',也就是'A'-'9'=7 
            if(ok)                                     /*十六进制数位数不足转二进制时补0占位*/
                if(a==1)//若需补一个十六进制的0,相当于补上四个二进制的0即0000,下面补两位也一样
                {
                    strcpy(z,"0000");
                    k=k+4;
                    ok=0;
                    a=0;
                }
                else if(a==2)
                {
                    strcpy(z,"00000000");
                    k=k+8;
                    ok=0;
                }
            /*一位十六进制转四位二进制*///'0'的值就是48 ,是故减了48后就是十进制的数 
            //举个例子:输入字符串37,先将字符3进行换算 
            z[k++]=d16[s[j][i]-48][0];  //此时z[k+1]=d16['3'-'0'=3][0],d16[3]对应的是 0011,而d16[3][0]指的是0              
            z[k++]=d16[s[j][i]-48][1]; //此时z[k+1+1=k+2]=d16['3'-'0'=3][0],d16[3]对应的是 0011,而d16[3][1]指的是0
            z[k++]=d16[s[j][i]-48][2];//此时z[k+3]=d16['3'-'0'=3][0],d16[3]对应的是 0011,而d16[3][2]指的是1
            z[k++]=d16[s[j][i]-48][3];//此时z[k+4]=d16['3'-'0'=3][0],d16[3]对应的是 0011,而d16[3][0]指的是1
            //这样子便可以把十六进制的 3 转化为二进制的3(0011),一个一个数字存入z[k++]里面
             
              /*每转三位十六进制数将其转为四位八进制数*/
            if(k==12)                                   
            {
                m=0;
                for(cur=0; cur<12; m++)//48就是'0' 
                    out[m]=((z[cur++]-48)*4+(z[cur++]-48)*2+(z[cur++]-48)*1)+48;//3 位二进制数转化为 1 位8进制数 
                    //4=2的平方。  2=2的一次方   1=2的 0次方 (由于3 位二进制数转化为 1 位8进制数 ,所以最高就到2的平方=4) 
                    //可以这么写:out[m]=((z[cur++]-'0')*4+(z[cur++]-'0')*2+(z[cur++]-'0')*1)+'0';
                    /*举个例子:37。经过16进制转化:(37)16 =(0000,0011,0111)2=(000,000,110,111)2=(67)8 
                      在这里是这样子的:out[m=0]=((z[0]-'0')*4+(z[1]-'0')*2+(z[2]-'0')*1)+'0'; 
                                        out[0]=(('0'-'0')*4+('0'-'0')*2+('0'-'0')*1)+'0'='0';
                                        由于后面 m++以及 cur++ 
                                        out[1]=((z[3]-'0')*4+(z[4]-'0')*2+(z[5]-'0')*1)+'0';
                                        out[1]=(('0'-'0')*4+('0'-'0')*2+('0'-'0')*1)+'0'='0';
                                        
                                        out[2]=((z[6]-'0')*4+(z[7]-'0')*2+(z[8]-'0')*1)+'0';
                                        out[2]=(('1'-'0')*4+('1'-'0')*2+('0'-'0')*1)+'0'='6';
                                        
                                        out[3]=((z[9]-'0')*4+(z[10]-'0')*2+(z[11]-'0')*1)+'0';
                                        out[3]=(('1'-'0')*4+('1'-'0')*2+('1'-'0')*1)+'0'='7';
                                        
                                        此时结果为: 0067  ,m=12                 
                    */ 
                cur = 0;//置0,给下一个字符串数使用 
                k=0;//置0,给下一个字符串数使用
                if(!flag)
                    while(out[cur]=='0'&&cur<m)//前面的 0不输出,让结果输出例子的结果:67 
                        cur++;
                if(cur==m)
                    flag = 0;
                else
                    flag = 1;
                for(; cur<m; cur++)
                    printf("%c",out[cur]);
            }
        }
        putchar('\n');
    }
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值