ブルーブリッジカップ基礎練習(十一)十六進法転十進法C言語

19969 ワード

16進数から10進数へのC言語
問題は、キーボードから8ビットを超えない正の16進数文字列を入力し、正の10進数に変換して出力することです.注:16進数の10~15は、それぞれ大文字のアルファベットA、B、C、D、E、Fで表されます.
サンプル入力FFFF
サンプル出力65535
前の問題とは逆に、10進数から16進数に転換する問題で、筆者は最初は難しくないと思っていたが、前の問題の考えを逆にすれば基本的に出てきた.
しかし、現実はまた私の顔をひどく殴った!
まず私のエラーコードを話しましょう.私のコードは次のとおりです.
#include <stdio.h> 
#include <math.h>

int getnum(char a)
{
	switch(a) //    
	{
		case '0':return 0;break;
		case '1':return 1;break;
		case '2':return 2;break;
		case '3':return 3;break;
		case '4':return 4;break;
		case '5':return 5;break;
		case '6':return 6;break;
		case '7':return 7;break;
		case '8':return 8;break;
		case '9':return 9;break;
		case 'A':return 10;break;
		case 'B':return 11;break;
		case 'C':return 12;break;
		case 'D':return 13;break;
		case 'E':return 14;break;
		case 'F':return 15;break;
	}
}

int main() {
	int i,count=0;
	int sum;
	char a[8]={'G','G','G','G','G','G','G','G'};//     
	for(i=0;a[i-1]!='
'
&&i<8;i++)// , i<8, { a[i]=getchar(); } if(a[7]=='G'||a[7]=='
'
) { i--; } for(i-=1;i>=0;i--) // i-=1 , 。 { sum+=getnum(a[i])*pow(16,count++); } printf("%d",sum); return 0; }

enmmm.筆者はもともと私の考えを完全にはっきり書いて、読者の参考にしたいと思っていたが、修正して長い間直して、自分がどうしても分からないことに気づいたので、筆者は自分が考えている間に気づいたいくつかの問題だけを話すことにした.読者はこのいくつかの問題に基づいて、筆者のコードを理解しやすいはずだ.
1、申請した配列は16進数を格納するために用いられ、その中に「A~F」が含まれているので、筆者は配列に初期値「G」を付与し、後の判断を容易にする.もちろん,初期値を付与する際には{}を用いて統一的に値を付与することができるが,筆者が{'G'}を用いたのにコンパイルに失敗したのは,具体的な原因がよくわからず,記号が不要であるためかもしれないが,筆者は試みなかったので,直接最も愚かな方法を用いた.
2、配列の長さは固定(8空間)であるが,我々が入力した16進数は1~8ビットであり,これは部分空間が余分であってもよいことを示し,長さが8ビット未満の場合getchar()は‘’も配列に入れるので,ビット数が8ビット未満の場合,配列が受信したビット数は常に実際のビット数より1多いため,増加し続けるiも1多いので,次のコードが必要である.
if(a[7]=='G'||a[7]=='
'
) { i--; }

筆者は以上のコードで問題の大半を完成させることができたが,intのデータ規模が要求に達しず,「FFFFFFFF」と入力するとエラーが発生するという問題がある.
これが筆者にはわからない問題であり,intをlong longタイプに変更し,出力フォーマットを%I 64 dまたは%lldに変更すればよいと考えていた.
しかし、実際の操作後、すべての出力にエラーが発生しました.具体的には、次のようになります.
入力
ぜんへんこうしゅつりょく
リファクタ出力
じっさいしゅつりょくの16進数
0
0
64
40
F
15
79
4F
FF
255
319
13F
FFF
4095
4159
103F
FFFFFFFF
4294967347
10000003F
ええ、そうです.私はデータ型を変えましたが、出力結果は天差地別でした.最後にこの結果は無理に筆者にいくつかの法則(上図の最後の列のように)を見つけられましたが、筆者は依然として問題がどこにあるか分かりません.だから、筆者は一晩中悩んで降伏を宣言しました.もし通りかかった大物が原因を知っていたら、教えてください.
最後に、筆者は他のブロガーのコードを見るしかありません.コードは以下の通りです.
#include<stdio.h>
#include<string.h>
#include<math.h>
int main()
{
    char a[8];
    int i;
    
	scanf("%s",a);
    int l=strlen(a);//       
    long long ans=0;//      8            ,     ,   long long
    for(i=0; i<l; i++)
    {
        if(a[i]>='0'&&a[i]<='9')
            ans+=(a[i]-'0')*pow(16,l-1-i);//a[i]-'0'          ASCII   ,      ~~
        else
            ans+=(a[i]-'A'+10)*pow(16,l-1-i);
    }
    printf("%lld
"
,ans); return 0; }

この大物の原文リンクを添付します.https://blog.csdn.net/qq_30076791/article/details/50320793
同じ機能なのに、このコードは簡潔で精悍で、筆者は本当に感心した五体投地で、同時に私が入力したのは文字で、テーマが要求しているのは文字列であることを発見しました.
最後に、上記のコードを実行している仲間がいると、筆者は配列空間を8つに変更したが、データ範囲内でどれだけ文字列を入力しても正確な結果が得られ、オーバーフローが発生していないように見えるのはなぜだろうか.
実際には、配列空間を超えるデータを入れると、配列は確かにオーバーフローしていますが、データは次のメモリ空間に格納されます.オーバーフローしたこの部分は、次のコードのように見つけることができます.
#include <stdio.h>
#include <stdlib.h>

int main(int argc, char *argv[]) {
	int a[8];
	int i;
	for(i=0;i<10;i++)
	{
		a[i]=i;
	 } 
	 printf("%d",a[9]);
	return 0;
}

実行後の結果は必ず9で、コンパイルエラーは発生しません.もちろん、コードを書くのは厳粛なことで、このようにコンパイルすることができますが、大規模な工事であれば、このように書くのは絶対にだめで、プログラムの崩壊を招きやすいです.オーバーフローした部分の空間はa配列ではありません.つまり、この部分の空間が変わる可能性があります.コードを叩くには厳密にしなければなりません