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

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

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

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

Q&A

解決済

5回答

1965閲覧

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

retorutoutyu

総合スコア10

C

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

0グッド

0クリップ

投稿2018/06/27 04:55

前提・実現したいこと

シーザー暗号を復号するプログラムの課題です
シフトする文字数は指定されていないので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.

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

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

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

該当のソースコード

C

1#include <stdio.h> 2#include <string.h> 3 4int main(void){ 5 char ct1[80]; 6 char ct2[80]; 7 char ct3[80]; 8 int k,j = 0; 9 int key = 1; 10 11 printf("解読するメッセージを入力してください:"); 12 scanf("%s",ct1); 13 14 for(j = 0; j < 80; j++) 15 ct2[j] = ct1[j]; 16 17 while(key<=25){ 18 while(ct2[k] != '\0'){ 19 if(('a' <= ct2[k]) && (ct2[k] <= 'z')){ 20 ct2[k] -= key; 21 if(ct2[k] < 'a') 22 ct2[k] += 26; 23 }else if (('A' <= ct2[k]) && (ct2[k] <= 'Z')){ 24 ct2[k] -= key; 25 if(ct2[k] < 'A') 26 ct2[k] += 26; 27 } 28 ct3[k] = ct2[k]; 29 k++; 30 key++; 31 } 32 printf("%s",ct3); 33 34 if((strstr(ct3,"the ") != NULL) || (strstr(ct3,"The ") != NULL)) 35 break; 36 } 37 38 printf("解読成功:\n"); 39 printf("鍵 = %d, 平文 = %s",key,ct3); 40 41 return 0; 42} 43

試したこと

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

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

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

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

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

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

guest

回答5

0

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

C

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

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

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

投稿2018/06/27 08:24

tacsheaven

総合スコア13703

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

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

0

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


int k,j = 0;

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

投稿2018/06/27 06:11

編集2018/06/27 06:55
y_waiwai

総合スコア87749

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

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

retorutoutyu

2018/06/27 07:00

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

2018/06/27 07:06

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

0

ベストアンサー

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

c

1#include <stdio.h> 2#include <string.h> 3 4int main(void){ 5 char ct1[80]; 6 char ct3[80]; 7 int k, key; 8 9 strcpy(ct1, "Jura gur png vf njnl gur zvpr cynl."); 10 for (key = 1; key <= 25; ++key) { 11 for (k = 0; ct1[k] != '\0'; ++k) { 12 if(('a' <= ct1[k]) && (ct1[k] <= 'z')){ 13 ct3[k] = ct1[k] - key; 14 if(ct3[k] < 'a') 15 ct3[k] += 26; 16 }else if (('A' <= ct1[k]) && (ct1[k] <= 'Z')){ 17 ct3[k] = ct1[k] - key; 18 if(ct3[k] < 'A') 19 ct3[k] += 26; 20 } else { 21 ct3[k] = ct1[k]; 22 } 23 } 24 ct3[k] = '\0'; 25 printf("%s\n",ct3); 26 if((strstr(ct3,"the ") != NULL) || (strstr(ct3,"The ") != NULL)) 27 break; 28 } 29 printf("Success\n"); 30 printf("key = %d, str = %s\n",key,ct3); 31 return 0; 32} 33

投稿2018/06/27 05:16

編集2018/06/27 07:35
HiroshiWatanabe

総合スコア2160

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

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

retorutoutyu

2018/06/27 06:50

・key++; をif文の後に移動しました ・k = 0; をif文の前に加えました ・scanfに変えてgetcharとwhileを使って'\n'が打たれたら入力終了としてみました。 (それに伴いwhile文の条件式中の'\0'は’\n'に変えました) ですが、実行してみると文章入力後、プログラムがまた途中終了しました
HiroshiWatanabe

2018/06/27 07:36

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

2018/06/27 07:58

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

0

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

投稿2018/06/27 05:14

編集2018/06/27 06:51
can110

総合スコア38262

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

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

retorutoutyu

2018/06/27 06:48

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

2018/06/27 06:55 編集

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

0

c

1#include <stdio.h> 2#include <string.h> 3 4int main(void){ 5 char ct1[80]; 6 char ct3[80]; 7 int k, key; 8 9 printf("解読するメッセージを入力してください:"); 10 scanf("%[^\n]", ct1); 11 12 //strcpy(ct1, "Jura gur png vf njnl gur zvpr cynl."); 13 for (key = 1; key <= 25; ++key) { 14 //printf("key=%d,k=%d\n",key,k);fflush(NULL); 15 for (k = 0; ct1[k] != '\0'; ++k) { 16 if(('a' <= ct1[k]) && (ct1[k] <= 'z')){ 17 ct3[k] = ct1[k] - key; 18 if(ct3[k] < 'a') 19 ct3[k] += 26; 20 }else if (('A' <= ct1[k]) && (ct1[k] <= 'Z')){ 21 ct3[k] = ct1[k] - key; 22 if(ct3[k] < 'A') 23 ct3[k] += 26; 24 } else { 25 ct3[k] = ct1[k]; 26 } 27 } 28 ct3[k] = '\0'; 29 //printf("%s\n",ct3); 30 if((strstr(ct3,"the ") != NULL) || (strstr(ct3,"The ") != NULL)) 31 break; 32 } 33 printf("解析成功\n"); 34 printf("鍵 = %d, 平文 = %s\n",key,ct3); 35 return 0; 36} 37 38 39

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

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

投稿2018/06/27 12:46

retorutoutyu

総合スコア10

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問