質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

Q&A

解決済

1回答

20195閲覧

C言語 16進数→10進数への変換方法

ichitarou

総合スコア7

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

C++

C++はC言語をもとにしてつくられた最もよく使われるマルチパラダイムプログラミング言語の1つです。オブジェクト指向、ジェネリック、命令型など広く対応しており、多目的に使用されています。

0グッド

0クリップ

投稿2015/08/13 16:55

編集2015/08/13 17:04

プログラミング未経験、今月就職し1週間ほどC言語を勉強しています。

研修を受けている会社からの練習問題で6桁までの16進数を入力し、10進数に変えて出力する…という問題が出たのですが、
pow関数というのを見つけそれを使用したところ、「シフト演算(?)を使った方が早い」と言われてしまいました。

C言語で16進数をシフト演算を使用し、10進数に変換したいです。

ヒントを教えていただけないでしょうか。

また、powを使って書いたものは以下になります。
これとはまったく別物になるのでしょうか?
あと、書き方等のアドバイスが有ればお願いします。
研修中に出来るだけ知識をつけたいです。
よろしくおねがいします。

C

1#include<stdio.h> 2#include<math.h> 3#include <string.h> 4 5long HexToBin(char *str) 6{ 7 long tmp; 8 int i; 9 long sum=0; 10 11 for(i=0;i<strlen(str);i++) 12 { 13 if(*(str+i)>='0' && *(str+i)<='9') 14 { 15 tmp=*(str+i)-'0'; 16 sum=(tmp*pow(16,strlen(str)-i-1))+sum; 17 } 18 else if(*(str+i)>='A' && *(str+i)<='F') 19 { 20 tmp=*(str+i)-'A'+10; 21 sum=(tmp*pow(16,strlen(str)-i-1))+sum; 22 } 23 else if(*(str+i)>='a' && *(str+i)<='f') 24 { 25 tmp=*(str+i)-'a'+10; 26 sum=(tmp*pow(16,strlen(str)-i-1))+sum; 27 } 28 else 29 { 30 sum=-1; 31 break; 32 } 33 } 34 return (sum); 35} 36 37int main() 38{ 39 char hex[50]; 40 long dec; 41 42 printf("16進数を入力:"); 43 scanf("%s",&hex[0]); 44 45 dec=HexToBin(&hex[0]); 46 47 if(dec==-1) 48 printf("入力された値が不正です。\n\n"); 49 else 50 printf("結果:%ld\n\n",dec); 51 52 return 0; 53}

*returnの中を書き換え忘れていたので修正しました。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

16進数がお分かりだということは、2進数もきっとバッチリですね。
ヒント: 16と2の関係はなんでしょう?がんばってください。
シフト演算について解説されているページを共有します。

投稿2015/08/13 17:30

退会済みユーザー

退会済みユーザー

総合スコア0

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

ichitarou

2015/08/13 17:46

リンクありがとうございます!16進数だと2進数を4ビットずつずらしていけば良いのでしょうか…多分これはchar型の16進数の状態で使って良いんですよね。 16進数→10進数の流ればかり考えてましたが、 16進数→2進数→10進数の流れなのでしょうか…難しい!がんばってみます!
ichitarou

2015/08/13 18:27

#include<stdio.h> #include <string.h> long HexToBin(char *str) { char tmp; int i; long sum=0; for(i=0;i<strlen(str);i++) { if(*(str+i)>='0' && *(str+i)<='9') { tmp=*(str+i)-'0'; sum=(tmp<<4*(strlen(str)-i-1))+sum; } else if(*(str+i)>='A' && *(str+i)<='F') { tmp=*(str+i)-'A'+10; sum=(tmp<<4*(strlen(str)-i-1))+sum; } else if(*(str+i)>='a' && *(str+i)<='f') { tmp=*(str+i)-'a'+10; sum=(tmp<<4*(strlen(str)-i-1))+sum; } else { sum=-1; break; } } return (sum); } int main() { char hex[50]; long dec; printf("16進数を入力:"); scanf("%s",&hex[0]); dec=HexToBin(&hex[0]); if(dec==-1) printf("入力された値が不正です。\n\n"); else printf("結果:%ld\n\n",dec); return 0; } powの部分を書き換えてできました! ありがとうございました!
rubato6809

2015/08/24 22:53 編集

既に解決済みですが、この課題はまだまだやりようがありますので、三点修正案を出させていただきます。 1. HexToBin()関数を見て、ごちゃごちゃした感じがしませんか。一番の理由は、ほぼ同じコードが三回繰り返されているからです。 16進数に使われる文字は'0'~'9', 'A'~'F', 'a'~'f'です。これらはそれぞれ '0'~'9' → 0 ~ 9 'A'~'F' → 10 ~ 15 'a'~'f' → 10 ~ 15 という値を意味しますから、文字を数値に変換する関数を作りましょう。仮にAscToBin()とすると、 int AscToBin(char ch) {    if (ch >= '0' && ch <= '9') {       return ch - '0';    } else if (ch >= 'A' && ch <= 'F') {       return ch - 'A' + 10;    } else if (ch >= 'a' && ch <= 'f') {       return ch - 'a' + 10;    } else {       return -1;    } } この関数は、toupper()(又はtolower())、isdigit(), isxdigit()などのライブラリ関数を使えば、さらに簡潔に書けます。考えてみて下さい。 AscToBin()は各文字を0~15の値で返してくれるので、HexToBin() の本体部分は    for (i = 0; i < strlen(str); i++) {       tmp = AscToBin(*(str + i));       if (tmp == -1) {          return -1L;       }       sum = (tmp << 4 * (strlen(str) - i - 1)) + sum;    }    return (sum); だけで済んでしまいます! 2. お作りになったコードは、入力した16進数文字列が例えば "31A" だったら、'3' という文字を 3 << 4 * 2 という値として、sum に足しこんでいます。即ち sum の値は 0(初期値)→0x300→0x310→0x31Aと変化しますね。 このやり方では16進数の中の「桁位置」を計算しなくてはなりません。しかし、文字列というものは、大抵先頭から順に処理できるものです(そして、そうしたやり方のほうが汎用性がある)から、桁位置がわからなくても構わない事が多いのです。 入力した16進数文字列が、例えば "31A"なら、スタートは先頭の'3'を数値3に変換する事です。 次に '1' に差し掛かった時点で、先ほどの 3 は、実は "31" という16進数の'3'だった、のだから、それを16倍して48 (== 0x30)にし、これに 1 を足して 49 (== 0x31)にします。 さらに'A'に差し掛かった時点で、また一桁大きくなるのだから 0x310 == 784 (== 49 * 16) に 'A'(== 10) を足す…。 このやり方だと sum の値は 0→0x3→0x31→0x31Aと変化します。 ここで、16倍する事を「4ビット左にシフト」する事で実現するのはお分かりですね。同様に、16倍する代りに10倍すれば10進数文字列を数値に変換できます。何進数でも基本的な手順は同じです。 つまり、先ほどの for 文は、    for (i = 0; i < strlen(str); i++) {       tmp = AscToBin(*(str + i));       if (tmp == -1) 省略;       sum = (sum << 4) + tmp;    } と書き換えられます。いかがですか。 3. この for ループは、繰り返しの条件判定で strlen() を毎回呼び出す事が気になります。HexToBin()が呼ばれた時点で、入力された文字列が変化する事は無いのだから、呼び出すにしても関数の先頭で一度呼べば十分です。即ち    len = strlen(str);    for (i = 0; i < len; i++) { とするのも手ですが、、、 C言語の文字列はヌル文字('\0')で終端する(最後にヌル文字がある)事をご存知ですか。入力した16進数の文字列も例外ではありません。この事を活かせば、上記のループは    for (i = 0; *(str + i) != '\0'; i++) { で回すことができます。strlen()を呼び出す必要がありません。 さらに、変数 i は配列の添字として働く(「*(str + i)」は「str[i]」と書き換えられる)が、str はポインタ「変数」なのだから、それを最大限活かすと、もはや変数 i も不要となり    while (*str) { /* ←「while (*str != '\0') {」と同じ */       tmp = AscToBin(*str++);       ... のような書き方ができます。これはC言語らしい簡潔な書き方ですから、少しずつ慣れる事をお奨めします。
ichitarou

2015/08/21 11:09 編集

返信が遅くなってしまい申し訳ありません! やりようでこんなに短くなるのですね… 別の問題でもfor、ifを入れ子だらけ状態になってしまったり、 本当に「ぐちゃぐちゃ」状態で自分の知識、発想力不足に大変悔しい思いをしております…(;_;) 早速、ご紹介いただいた方法で試してみたいと思います! 少しでも短くわかりやすく綺麗に済ませられるよう、訓練、精進したいと思います! お時間を割いてこんなにも詳しく説明して下さり、本当にありがとうございます!!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問