🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C

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

Q&A

解決済

4回答

1443閲覧

正しい出力が得られない

progokina8

総合スコア4

C

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

0グッド

0クリップ

投稿2021/02/07 17:16

前提・実現したいこと

現在、モールス信号をアルファベットに直すプログラムを作成中です。
モールス信号のアルファベットを以下のように数字に対応させ、「・」を読み取ると変数numを2倍、「-」を読み取るとnumを2倍して1を足すことで、ファイルから1文字ずつ読み取り復号させることを考えました。
しかし、何も出力されずにプログラムが終了してしまいます。
理由が見当たらないため、分かる方にご教授頂きたいです。
イメージ説明
イメージ説明

該当のソースコード

C

1#include <stdio.h> 2 3int main(){ 4 int num = 1; 5 char *s; 6 char *alphabet = "**etianmsurwdkgohvf*l*pjbxcyzq**"; 7 8 while(scanf("%[^\n]%*c", s) != EOF){ 9 while(*s){ 10 if(*s == '.') num = num * 2; 11 else if(*s == '-') num = num * 2 + 1; 12 else if(*s == ' '){ 13 printf("%c", alphabet[num]); 14 num = 1; 15 } 16 else if(*s == '/') printf(" "); 17 s++; 18 } 19 printf("%c\n", alphabet[num]); 20 num = 1; 21 } 22 return 0; 23} 24

###input.txtの内容

-- --- .-. ... . / -.-. --- -.. .

###出力
期待される出力

morse code

実際の出力

(何も表示されずプログラム終了)

試したこと

ファイル入力を用いず、標準入力のときも出力されませんでした。

補足情報

Windows, VSCodeでプログラムを記述し、gccでコンパイルしました。

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

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

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

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

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

guest

回答4

0

char *s;
これでは、sの値が不定なため、文字列を格納するバッファが保障されません。
char buff[4096];
char *s = buff;
のようにして、文字列を格納できる十分な領域を確保してください。
kazuma-sさんの提示されている実行結果がうまくいっているのは、たまたまです。

投稿2021/02/07 23:29

tatsu99

総合スコア5493

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

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

progokina8

2021/02/07 23:45

回答有り難うございます。 領域が保証されないのが原因だったのですね。 もう一度基礎的な部分を学習しようと思います。
guest

0

ベストアンサー

char *s; //略 while(scanf("%[^\n]%*c", s) != EOF){

C/C++では、ローカル変数の初期値は「不定」です。不定というのは、ソースコードからは値が決まらず、実行してみるまでどうなるかわからない、ということです。sはポインタですから、全メモリ空間のどこかを指しているのですが、それがどこかわかりません。もしかしたらプログラムの動作に必要なデータを指しているのかも。
そういうsが指している先に、データを保管しようとしています。正常な動作に必要なデータを勝手に上書きされてしまったら...さてなにがおこるかわかりません。
もしかしたら期待する動作をしちゃうかも知れないし、パソコンが爆発するかも知れません(しないけど)。「未定義」の動作というやつです。

データを格納する領域を確保してやりましょう。
文字のデータだけなら、数字までいれて長点短点あわせて5コまで。普通に(普通の人はモールス符号使わないか?)使う範囲では訂正符号の/HH(短点8コ)が最長でしょうか。
例えば、

char s0[8+1];//長点短点+終了記号のデータを格納する領域を確保 char* s=s0;//ポインタが確保した領域を指すように初期化 //略 else if(*s == ' '){ printf("%c", alphabet[num]); num = 1; s=s0; //格納場所の頭に再設定 }

としてやればとりあえず動くのでは。

あるいは、あえてそこでポインタを使わずに

char s0[8+1];//長点短点+終了記号のデータを格納する領域を確保 // char *s; 廃止 int index=0; //略 while(scanf("%[^\n]%*c", s0[0]) != EOF){ while(s0[index]){ if(s0[index] == '.') num = num * 2; else if(s0[index] == '-') num = num * 2 + 1; else if(s0[index] == ' '){ printf("%c", alphabet[num]); num = 1; index=0; } else if(s0[index] == '/') printf(" "); index++; } printf("%c\n", alphabet[num]); num = 1; }

としてもよいのでは。

もっとも...ここでちゃぶ台返し。
scanf("%[^\n]%*c", s)でデータを拾おうとすると、100文字入力されたとしたらsの位置から100バイトデータを書き込んでしまいます(バッファオーバーラン)。これでは、確保していない領域に書くつまり「未定義動作」となってしまうでしょう。100文字と決まっているなら先のs0[100]とでもしてやればいいですが、入力されるのが100文字以下という保証があるわけでもありません。入力はn文字以下にしてね、とお願いしたとしても聞いてもらえるとは限りません。

ならば、最低の文字数1で勝負するほうが確実ではないでしょうか。

char c; //char *s; 廃止 //略 while(scanf("%c",&c) != EOF){ if(c == '.') num = num * 2; else if(c == '-') num = num * 2 + 1; else if(c == ' '){ printf("%c", alphabet[num]); num = 1; } if( c== '\n'){ if(num!=1){ printf("%c", alphabet[num]); num = 1; } printf("\n"); } else if(c == '/') printf(" "); }

(scanfでも"%8s"などとして入力を制限してやるとか、fgetsを使って文字列として扱う手もありますが)

投稿2021/02/07 23:22

編集2021/02/07 23:25
thkana

総合スコア7703

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

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

progokina8

2021/02/08 00:01

回答有り難うございます。 バッファオーバーランという言葉を聞いたことはあったのですが、理解しきれないままでいました。 様々な解決策を提案して下さり感謝です。 ベストアンサーにさせて頂きます。
guest

0

text

1$ cat -n a.c 2 1 #include <stdio.h> 3 2 4 3 int main(){ 5 4 int num = 1; 6 5 char *s; 7 6 char *alphabet = "**etianmsurwdkgohvf*l*pjbxcyzq**"; 8 7 9 8 while(scanf("%[^\n]%*c", s) != EOF){ 10 9 while(*s){ 11 10 if(*s == '.') num = num * 2; 12 11 else if(*s == '-') num = num * 2 + 1; 13 12 else if(*s == ' '){ 14 13 printf("%c", alphabet[num]); 15 14 num = 1; 16 15 } 17 16 else if(*s == '/') printf(" "); 18 17 s++; 19 18 } 20 19 printf("%c\n", alphabet[num]); 21 20 num = 1; 22 21 } 23 22 return 0; 24 23 } 25$ gcc a.c 26$ cat input.txt 27-- --- .-. ... . / -.-. --- -.. . 28$ ./a.out <input.txt 29morse *code 30$

標準入力で表示されますよ。
ただし、スペースが 2個連続すると * が出ます。
/ の両端のスペースを連続したものと解釈し、
num=1 を表示しています。

追記
thkanaさんの指摘のように s が未初期化なので、動いていたのは偶然です。
* が表示されてしまうという指摘だけを参考にしてください。

投稿2021/02/07 23:04

編集2021/02/07 23:30
kazuma-s

総合スコア8224

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

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

progokina8

2021/02/07 23:40

追記までして頂き、有り難うございます。 *が表示されてしまうのは気づいていなかったので助かりました。
guest

0

デバッグしましょう
ブレークポイントを設定すれば、コードの任意の場所で実行を止め、変数のナカミを見ることができます。そこから1行づつ実行して、コードの流れを見れるようになります
そうすれば、アテズッポでコードを書かなくて済むようになります。

投稿2021/02/07 22:09

y_waiwai

総合スコア88038

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

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

progokina8

2021/02/07 23:38

まだ初心者のため、ブレークポイントは使ったことが無かったです。 ご指摘有り難うございます。デバッグしてみたいと思います。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問