ログインしてさらにmixiを楽しもう

コメントを投稿して情報交換!
更新通知を受け取って、最新情報をゲット!

ただいまC・C++勉強中!コミュの8進数を10進数に変換するプログラム

  • mixiチェック
  • このエントリーをはてなブックマークに追加
引数octで指定された文字列が表す8桁の8進数を、10進数に変換する関数
int octtodec(char oct[8])
を作成し、負数が入力されるまで、入力された8進数を10進数に変換して出力するプログラムを作成せよ。入力された文字列が8進数でなかった場合、エラーを出力して再度入力を促すこと。
尚、octtodecは8進数を10進数に変換し、mainに10進数を返すという動作のみ。

実行例)
user>a.out
Input number (Oct) : 1234
oct:1234 → dec:668
Input number (Oct) : 9876
Error: 9876 is NOT an oct number.
Input number (Oct) : -1
bye...
user>

考え方としてmainでoct[8]をchar型で宣言し、for文の中でoct[0]〜oct[7]の中に8以上の数字がないか確認し、1つでもあった場合はError表示、1つもなかった場合はocttodec(char oct[8])にmainのoctを渡して変換しようと考えているのですが、今一プログラムの書き方がわかりません。
どなたかmainかocttodecの中だけでもいいので、アルゴリズムだけでもわかる方がいたら教えてください。

わかりにくいところがあったら遠慮なくコメントで質問してください。

コメント(11)

atoc()関数で数字から文字列に変換できる便利な関数があるので
そいつを使って各桁が8を超えないかを判定、
その次に8→10の基数変換を行えば良いと思います。
atoi()ではないでしょうか?
atoi()を使って文字列を数字に変換してやってみたのですが、文字配列から数字配列に移すことができずに、数字の中から8以上の数字を探すという方法ができないのですが何か方法はありませんか?


最初にchar型で受け取るのが難しくしてる原因なんですかねぇ。
------------------
int tmp;
scanf("%o",&tmp);
------------------
と素直に8進数のデータをint型で受け取ればいいのでは?
oct[8]に8桁入れようというのがなかなか難しくてfgets()だと7桁しか入りません。無念。
終了条件の負数の入力で終了というところで-0でも終了してしまうのは見逃してください。

#include <stdio.h>
#include <string.h>

int main(void)
{
  char oct[8];
  char dec[8];
  for(;;){
    printf("Input number(oct):");
    memset(oct, ' ', sizeof(oct));
    fgets(oct, sizeof(oct), stdin);
    cutstr(oct);
    if(isMinus(oct)){
      break;
    }
    if(!isOctal(oct)){
      printf("Error: %c%c%c%c%c%c%c%c is NOT an oct number.\n",
            oct[0], oct[1], oct[2], oct[3], oct[4], oct[5], oct[6], oct[7]);
      continue;
    }
    octtodec(dec, oct);
    printf("oct %c%c%c%c%c%c%c%c - dec %c%c%c%c%c%c%c%c\n",
          oct[0], oct[1], oct[2], oct[3], oct[4], oct[5], oct[6], oct[7],
          dec[0], dec[1], dec[2], dec[3], dec[4], dec[5], dec[6], dec[7]); 
  }
  return 0;
}

int cutstr(char *str)
{
  int n;
  for (n = 0; n < 8; n++)
    if(str[n] == '\n' || str[n] == '\0')
       for(;n < 8; n++)
         str[n] = ' ';
   return 0;
}

int isMinus(const char *str)
{
  int phase = 0;
  int minus = 0;
  int num = 0;
  int n;

  for (n = 0; n < 8; n++){
    switch(phase){
    case 0:
      if(str[n] != ' '){
       phase++;
      }
      if (str[n] == '-'){
       minus = 1;
       continue;
      }
      /*THRU*/
    case 1:
      if(str[n] == ' '){
       phase++;
      } else if (!(str[n] == '0' || str[n] == '1' || str[n] == '2' || str[n] == '3'
                 || str[n] == '4' || str[n] == '5' || str[n] == '6' || str[n] == '7')) {
       return 0;
      } else {
       num = 1;
      }
      break;
    case 2:
      if(str[n] != ' '){
       return 0;
      }
    }
  }
  return minus & num;
}

int isOctal(const char *str)
{
  int n;
  int phase = 0;
  int ok = 0;

  for (n = 0; n < 8; n++){
    switch(phase){
    case 0:
      if(str[n] != ' '){
       phase++;
      }
      /*THRU*/

    case 1:
      if(str[n] == ' '){
       phase++;
      } else if (!(str[n] == '0' || str[n] == '1' || str[n] == '2' || str[n] == '3'
                 || str[n] == '4' || str[n] == '5' || str[n] == '6' || str[n] == '7')) {
       return 0;
      } else {
       ok = 1;
      }
      break;

    case 2:
      if(str[n] != ' '){
       return 0;
      }
    }
  }
  return ok;
}

int octtodec(char *dec, const char *oct)
{
  int n;
  int i;
  int rad;
  int tmp;
  int calc[8];
  int zero;

  for (n = 0; n < 8; n++){
    if ((oct[n] == '0' || oct[n] == '1' || oct[n] == '2' || oct[n] == '3'
        || oct[n] == '4' || oct[n] == '5' || oct[n] == '6' || oct[n] == '7')) {
      i = n;
    }
  }

  rad = 1;
  memset(calc, 0, sizeof(calc));
  while(0 <= i){
    if(oct[i] == '0') {
      tmp = 0;
    }else if(oct[i] == '1'){
      tmp = 1;
    }else if(oct[i] == '2'){
      tmp = 2;
    }else if(oct[i] == '3'){
      tmp = 3;
    }else if(oct[i] == '4'){
      tmp = 4;
    }else if(oct[i] == '5'){
      tmp = 5;
    }else if(oct[i] == '6'){
      tmp = 6;
    }else if(oct[i] == '7'){
      tmp = 7;
    }
    tmp *= rad;
    n = 7;
    while(0 < tmp){
      int m;
      m = tmp % 10;
      calc[n] += m;
      if(10 <= calc[n]){
       calc[n] -= 10;
       tmp += 10;
      }
      tmp /= 10;
      n--;
    }
    rad *= 8;
    i--;
  }

  zero = 0;
  for (i = 0; i < 8; i++) {
    if(calc[i] == 0) {
      dec[i] = zero ? '0' : ' ';
    }else if(calc[i] == 1){
      dec[i] = '1';
      zero = 1;
    }else if(calc[i] == 2){
      dec[i] = '2';
      zero = 1;
    }else if(calc[i] == 3){
      dec[i] = '3';
      zero = 1;
    }else if(calc[i] == 4){
      dec[i] = '4';
      zero = 1;
    }else if(calc[i] == 5){
      dec[i] = '5';
      zero = 1;
    }else if(calc[i] == 6){
      dec[i] = '6';
      zero = 1;
    }else if(calc[i] == 7){
      dec[i] = '7';
      zero = 1;
    }
  }
}
すまん、話の内容を誤読してた。文字列から整数ね。

なればstrlenで文字列数取得したあとループ使って
符号・基数チェック、
その後に基数変換ですね。文字列からの8→10基数変換
だと
int length;//文字列長
int dec=0;//基数変換後の数値
int cnt;//ループカウント

length = strlen(&oct);
for(cnt = 0;cnt<length;cnt++)
{
dec += pow(8,length-cnt)*(oct[cnt]-0x30);//文字から数字に変換
}

で基数変換おわっちゃうのでatoi()いらないですね

ってocttodecの中身かいちゃtt
返事遅れました。

>ネキさん
引数をchar型で渡さないと行けないのでintで受け取ると渡すときに変換しないとならないので二度手間になると思ってその手段は使ってません。

>びいさん
すみません説明不足でした。
mainとocttodec以外の関数は作ることは許可されてません。
関数の中身を直接書いてちょっといじればいいだけですけど

>ダテさん
これから試してみます。
#include <stdio.h>
#include <math.h>

int main(void)
{
 int  i, j, dec;
 char oct[8];

 while(1)
 {
  printf("Input number (Oct) : ");
  scanf("%s", oct);
  for(i=0; i<8; i++)
  {
   if(oct[i]>7)
   {
    printf("Error: ");
    for(j=0; j<8; j++)
    {
     printf("%c", oct[j]);
    }
    printf(" is NOT an oct number.\n");
    main();
   }
  }
  dec = octtodec(oct);
 }

 return 0;
}

int octtodec(char oct[8])
{
 int length;
 int dec=0;
 int cnt;

 length = strlen(oct);
 for(cnt=0; cnt<length; cnt++)
 {
  dec += pow(8,length-cnt)*(oct[cnt]-0x30);
 }

 return dec;
}

ダテさんのプログラムを基に(というかそのまま引用させて貰って)簡単にエラー表示の形を作ってみたのですが、コンパイルするとpowでなぜかシンボル参照エラーがでてしまいます(gcc使用)。
math.hを宣言しているのですが、なぜでしょうか。
いろいろ調べたり試してみたんですが原因が分からないです。
参考までに。
http://www.curri.miyakyo-u.ac.jp/w3-st/kouza/c-lang/050.html

http://support.microsoft.com/kb/917085/ja

最新版の Visual C++ 2005 では、「double pow(int x, int y);」は ANSI C 準拠に従い削除されています。そのため、プロジェクトのビルド時にコンパイルエラーとして扱うよう仕様が変更されていますので、プロジェクトのアップグレードの際はご注意ください。

と書いてあるのでpow関数を使うのはあまり推奨されてないのかもしれません。

http://www.mk.ecei.tohoku.ac.jp/~masahide/knowhow/C_FAQ_3
14.7: なぜCに、べき乗が組み込み関数で用意されていないのか。

A: べき乗を組み込みの命令として持っているプロセッサが少ないからで
ある。Cにはpow()が用意され、<math.h>で宣言されている。ただし小
さな整数が対象なら、たいていは自分で掛け算で書いたほうがよい。

References: ANSI Sec. 4.5.5.1; ISO Sec. 7.5.5.1; H&S Sec. 17.6
p. 393.

pow関数をばらすってのも手ですね。
あと上に書いただけだと他の符号やら英字やらを判断してないのでなかなかぶっ飛んだ数値が帰ってくる可能性が。

int length;//文字列長
int dec=0;//基数変換後の数値
int cnt;//ループカウント


length = strlen(&oct);

if(oct[0] = '-')return -1;

for(cnt = 0;cnt<length;cnt++)
{
dec += 8^(length-cnt)*(oct[cnt] & 0x0F);//べき乗計算は適当に
}

で一応ぶっ飛んだ数字が帰ってくるってことはないでしょう。
すみません。
8進数の値が欲しいなら。「itoa」を使ってはいけないのでしょうか?


gets()で、受け取った文字列を、int型に入れて、itoa()でまた変換するというのはどうでしょう?受け取る変数は、char型ですが、表示の仕方に、条件がなければ、文字列で表示してみてはどうでしょう。
strtolを参考にするのがいいと思います。
例えば、NetBSDのlibcにあるstrtolの実装はこんな感じです。
http://cvsweb.netbsd.org/bsdweb.cgi/src/lib/libc/stdlib/strtol.c?rev=1.17&content-type=text/x-cvsweb-markup

以下、strtolを使ったサンプル

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <errno.h>

static char *
chomp(char *str)
{
    char *p;

    if ((p = strrchr(str, '\n'))) {
        *p = '\0';
    }
    if ((p = strrchr(str, '\r'))) {
        *p = '\0';
    }
    return str;
}

int
main(int argc, char **argv)
{
    char line[256];
    char *endp;
    int num;

    for (;;) {
        printf("Input number (Oct) : ");
        fflush(stdout);
        if (fgets(line, sizeof(line), stdin) == NULL) {
            printf("bye...\n");
            break;
        }
        chomp(line);
        errno = 0;
        num = strtol(line, &endp, 8);
        if (errno != 0) {
            printf("Error: strtol() failed. %s.\n", strerror(errno));
            continue;
        }
        if (num < 0) {
            printf("bye...\n");
            break;
        }
        if (endp == line) {
            printf("Error: %.32s is NOT an oct number.\n", line);
            continue;
        }
        printf("oct:%o -> dec:%d\n", num, num);
    }
    return EXIT_SUCCESS;
}

ログインすると、みんなのコメントがもっと見れるよ

mixiユーザー
ログインしてコメントしよう!

ただいまC・C++勉強中! 更新情報

ただいまC・C++勉強中!のメンバーはこんなコミュニティにも参加しています

星印の数は、共通して参加しているメンバーが多いほど増えます。