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

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

ただいまの
回答率

90.53%

  • C

    3657questions

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

C言語でシーザー暗号を復号するプログラム

解決済

回答 5

投稿

  • 評価
  • クリップ 0
  • VIEW 301

retorutoutyu

score 2

 前提・実現したいこと

シーザー暗号を復号するプログラムの課題です
シフトする文字数は指定されていないので1文字、2文字、3文字...25文字
と1文字ずつシフトする文字数を増やして
文字のシフト終了後、strstr関数を用いて「the 」または「The 」(後ろに空白が入って4文字)
を見つけたら解読成功と判定し、解読結果とシフトした文字数を表示するプログラム
を作ろうとしています
(ポインタはまだ習っていないので使っていません)

最終的に以下のように実行することが目標です

解読するメッセージを入力してください:Jura gur png vf njnl gur zvpr cynl.
解読成功:
鍵 = 13, 平文 = When the cat is away the mice play.

書いたコードのおかしい部分を指摘していただけたら幸いです

 発生している問題・エラーメッセージ

文字を入力は出来るのですが、入力後数秒経過してプログラムが終了します

 該当のソースコード

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

int main(void){
  char ct1[80];
  char ct2[80];
  char ct3[80];
  int k,j = 0;
  int key = 1;

  printf("解読するメッセージを入力してください:");
  scanf("%s",ct1);

  for(j = 0; j < 80; j++)
     ct2[j] = ct1[j];

  while(key<=25){
      while(ct2[k] != '\0'){
          if(('a' <= ct2[k]) && (ct2[k] <= 'z')){
              ct2[k] -= key;
              if(ct2[k] < 'a')
                 ct2[k] += 26;
          }else if (('A' <= ct2[k]) && (ct2[k] <= 'Z')){
              ct2[k] -= key;
              if(ct2[k] < 'A')
                 ct2[k] += 26;
          }
          ct3[k] = ct2[k];
          k++;
          key++;
        }
      printf("%s",ct3);

      if((strstr(ct3,"the ") != NULL) || (strstr(ct3,"The ") != NULL))
         break;
   }

   printf("解読成功:\n");
   printf("鍵 = %d, 平文 = %s",key,ct3);

   return 0;
}

 試したこと

どこかで無限ループしているのかなと仮定してwhileをforに変えたり、その逆をしてみたりしました。

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

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

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

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 5

checkベストアンサー

+1

・key++; の位置がおかしい
・一通り1文分のシフト作業が終わったら k を 0 で再初期化しないとそのまま繰り返し続けたら配列枠超過する
・scanfでは空白が区切りになるので「Jura gur」と入力してもこれでは「Jura」しか取れない

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

int main(void){
    char ct1[80];
    char ct3[80];
    int k, key;

    strcpy(ct1, "Jura gur png vf njnl gur zvpr cynl.");
    for (key = 1; key <= 25; ++key) {
        for (k = 0; ct1[k] != '\0'; ++k) {
            if(('a' <= ct1[k]) && (ct1[k] <= 'z')){
                ct3[k] = ct1[k] - key;
                if(ct3[k] < 'a')
                    ct3[k] += 26;
            }else if (('A' <= ct1[k]) && (ct1[k] <= 'Z')){
                ct3[k] = ct1[k] - key;
                if(ct3[k] < 'A')
                    ct3[k] += 26;
            } else {
                ct3[k] = ct1[k];
            }
        }
        ct3[k] = '\0';
        printf("%s\n",ct3);
        if((strstr(ct3,"the ") != NULL) || (strstr(ct3,"The ") != NULL))
            break;
    }
    printf("Success\n");
    printf("key = %d, str = %s\n",key,ct3);
    return 0;
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/06/27 15:50

    ・key++; をif文の後に移動しました
    ・k = 0; をif文の前に加えました
    ・scanfに変えてgetcharとwhileを使って'\n'が打たれたら入力終了としてみました。
    (それに伴いwhile文の条件式中の'\0'は’\n'に変えました)

    ですが、実行してみると文章入力後、プログラムがまた途中終了しました

    キャンセル

  • 2018/06/27 16:36

    表示したいなら終端は'\0'でなければなりませんよ…

    キャンセル

  • 2018/06/27 16:58

    プログラムの提示ありがとうございます。
    現在、書いているプログラムと比較検討させていただきます

    キャンセル

+1

まずはwhile(key<=25){の次行にprintf("key=%d,k=%d\n",key,k);fflush(NULL);を追加して、意図した値になっているか確認してみてください。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/06/27 15:48

    追加してみたのですが、それが表示される前にプログラムが終了してしまいました

    キャンセル

  • 2018/06/27 15:53 編集

    あ、おそらくバッファリングされて標準出力に出力完了する前に異常終了しているようですね。
    fflush(NULL)追加してください。回答修正しました。
    Visual Studioなどの統合開発環境を利用していれば
    デバッグ実行しコードをステップ実行して値を確認するほうが確実、簡単です。

    キャンセル

+1

while(key<=25){ が意味不明
while(ct2[k] != '\0') のループで、入力文字列を処理したあと、それが25文字以内のとき、もいちどループに突入して同じことを繰り返すが、kが初期化されないため、文字列終端を超えてワケワカラン処理となる。おまけに、2回目のループは文字列終端が見つかるまで繰り返すため、スタックを破壊していくこととなる
おそらくこのせいで異常終了。


  int k,j = 0;

って、k が初期化されてない!!
j は0になるんだけど、k は不定値だ。。
こりゃループ最初から暴走ですねー

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/06/27 16:00

    > int k,j = 0;
    この書き方は駄目なんですね。低レベルで申し訳ないです
    それぞれ別々に宣言しました。

    キャンセル

  • 2018/06/27 16:06

    key=1;
    for(k=0;k<sizeof(ct2) && ct2[k]!='\0';k++){
    ...
    key++;
    if(key>25) key=1;
    }
    こゆかんじでいきましょう、ってむずかしいかな。。

    キャンセル

+1

いろいろやられてますが、単純なシーザー暗号であれば t に変化する文字はかならず一意に定まりますから、先頭の1文字を「t」にシフトできる数を計算してやればよいのです。

  char gap = 't' - ct2[0];


つまり鍵を探すためにループを回す必要はありません。

これがヴィジョネル暗号とかだったら無理ですけど。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

0

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

int main(void){
    char ct1[80];
    char ct3[80];
    int k, key;

    printf("解読するメッセージを入力してください:");
    scanf("%[^\n]", ct1);

    //strcpy(ct1, "Jura gur png vf njnl gur zvpr cynl.");
    for (key = 1; key <= 25; ++key) {
        //printf("key=%d,k=%d\n",key,k);fflush(NULL);
        for (k = 0; ct1[k] != '\0'; ++k) {
            if(('a' <= ct1[k]) && (ct1[k] <= 'z')){
                ct3[k] = ct1[k] - key;
                if(ct3[k] < 'a')
                    ct3[k] += 26;
            }else if (('A' <= ct1[k]) && (ct1[k] <= 'Z')){
                ct3[k] = ct1[k] - key;
                if(ct3[k] < 'A')
                    ct3[k] += 26;
            } else {
                ct3[k] = ct1[k];
            }
        }
        ct3[k] = '\0';
        //printf("%s\n",ct3);
        if((strstr(ct3,"the ") != NULL) || (strstr(ct3,"The ") != NULL))
            break;
    }
    printf("解析成功\n");
    printf("鍵 = %d, 平文 = %s\n",key,ct3);
    return 0;
}


皆様の回答を参考にして、以上のコードでシーザー暗号の解読が出来ました。
入力はgetcharとwhileを使うとコメントしましたが
空白を含んだ文字列を読み込めるscanfの構文を見つけたので、そちらを使いました。

皆様、親切丁寧な回答ありがとうございました

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

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

  • ただいまの回答率 90.53%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • C

    3657questions

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