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

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

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

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

Q&A

解決済

5回答

7744閲覧

int型に文字を入れるとバグが起こることとその対処法

退会済みユーザー

退会済みユーザー

総合スコア0

C

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

0グッド

1クリップ

投稿2019/07/22 01:45

編集2019/07/22 02:14

コンソールアプリケーションを作ったのですが、何かを入力してもらうところで指定した型以外の物を入れるとバグが起こってしまいます。
例えば、

C

1#include <stdio.h> 2 3int main(void) 4{ 5 int a = 0; 6 7 while (a == 0) 8 { 9 10 scanf("%d", &a); 11 12 printf("%d\n", a); 13 } 14 15 return 0; 16}

上のプログラムでaに入力する際、数字以外を入れると無限ループしてしまいます。

これを未然に防ぐために、整数以外の入力を禁止したいのですがどのように実装すれば良いのでしょうか?

追記1

#include <stdio.h> int main(void) { int a = 0; while (a == 0) { if (scanf("%d", &a) == EOF) { break; } printf("%d\n", a); } return 0; }

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

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

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

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

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

guest

回答5

0

ベストアンサー

入力の禁止はできません。

scanfの戻り値は、「入力に成功した変数の数」です。
数字以外を入力した場合は成功がゼロ個つまり0が返り、数字が入力されたかどうかは判断できるので、それらの文字を読み飛ばして、再入力させます。

C

1#include <stdio.h> 2 3int main(void) 4{ 5 int a = 0; 6 int z; 7 8 while (a == 0) 9 { 10 11 z = scanf("%d", &a); 12 if(z==EOF) break; 13 if(z==0){ 14 scanf("%*s"); // 読み飛ばして、ループを繰り返す 15 continue; 16 } 17 printf("%d\n", a); 18 } 19 20 return 0; 21}

投稿2019/07/22 02:19

編集2019/07/22 02:24
otn

総合スコア84533

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

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

退会済みユーザー

退会済みユーザー

2019/07/22 02:27

回答ありがとうございます。 こちらのコードをコンパイルしたところ、思った通りに動作しました。 基礎的な質問で申し訳ないのですが、%*sとはどういう意味でしょうか?
otn

2019/07/22 02:31

(空白以外の)文字列(%s)を入力して、どの変数にも代入しない(%*) ということです。
退会済みユーザー

退会済みユーザー

2019/07/22 02:41

実行結果が (入力)abcde (入力)12345 (出力)12345 となり、入力が1回少ないように思えます。 12345は%*sで入力した物だと思いますが、代入されなければ次のz = scanf("%d", &a);に渡せるのでしょうか?
退会済みユーザー

退会済みユーザー

2019/07/22 02:49

もう一つ質問なのですが、abcdeを入力した際にEOSが返っているはずなのにbreakしないのは何故ですか?
otn

2019/07/22 02:54

> 12345は%*sで入力した物だと思いますが、 いえ。abcdeが%*sで入力した値です。 > もう一つ質問なのですが、abcdeを入力した際にEOSが返っているはずなのに いえ。「数字以外を入力した場合は成功がゼロ個つまり0が返り、」と回答に書いたのですが忘れましたか?
退会済みユーザー

退会済みユーザー

2019/07/22 03:16

理解しました。 abcdeが代入できずスキップされているため%*sでの入力になるのですね。
otn

2019/07/22 03:22

そうですね。abcdeが「入力されたが読み取られていない」という状態のままなので、%d で読みつづけると無限ループです。
guest

0

ちとググれば出てきますが文字列を数値に変換して、変換できた場合だけ出力すればいいだけでは。

投稿2019/07/22 01:55

gentaro

総合スコア8949

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

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

退会済みユーザー

退会済みユーザー

2019/07/22 02:24

回答ありがとうございます。 こんな関数があるんですね。今回は他の方法でやってみますが、機会があれば使ってみようと思います。
guest

0

もう解決しちゃってますけど、ちょっとだけ補足...と思ったら長くなっちゃいました。でも、scanf()を真面目に考えるとこうなっちゃうんです。
scanf()って、「とりあえず」ならともかく、真面目にエラー対応とかを考え出すと相当面倒なことになったりします。なにしろ、入出力装置がテレタイプとかそんなだった時代の産物ですから。そのころは、コンピュータ様に入力するのに間違えるなんて...だったんでしょうね(私も知らない)

まず、データの入り口。もしかして、scanf()はキーボードからなにか入力する関数、と思ってます? そんな決まりはありません。scanf()は、標準入力ストリームからデータを(取り出せれば)取り出す関数です。標準入力ストリームってなんだ? OSが与えてくる入力文字列です。デフォルトでは、OSはキーボードからのデータを入力文字列として与えてくるので、scanfがキーボードからの入力として使われることが多いのです。「リダイレクト」という機能を使うと、キーボード以外、例えばファイルから標準入力にデータを流し込んだりも出来ます。
ここで気をつけなきゃいけないのはOSが与えてくる、ということ。つまり、C言語の制御の外なんです。キーボードを叩いてコンピュータの中に取り込むまではOSがやっちゃいます。なので、C言語の範囲では「指定文字以外の入力を禁止する」というのは言葉通りには出来ません。入力された文字はとにかくC言語の入り口までは入ってきてしまうのです。不要な文字は、入ってきちゃったのを捨てる/無視することになります。

ここでもう一ついやらしいところ。書式指定子(%dとか%sとか)でデータ形式を指定してデータを取り出すわけですが、それって何をしているのかを把握しないと、今回のような「無限ループ」になっちゃったりします。
基本的な考え方は「指定と一致したデータだけを取り込む」こと。
%dや%sでは、標準入力の先頭から位置文字ずつ取り込み、最初がホワイトスペース(空白、水平タブ、改行)だったら、なにかの文字に出会うまで読み飛ばします。なにかの文字に出会ったら、指定の変換が出来るかどうか試します。成功するなら、次の文字も取り込んで変換出来るかどうか試します。次々と試して、変換出来ない文字に出会ったら、これまでに取り込んだデータで確定して、与えられているアドレスに格納します。そして、変換できなかった文字は、標準入力に戻します

さて。書式指定が"%d"に対して、"s"が入力されたらなにが起こるでしょうか。"s"は数値に変換出来ないので、scanfは一文字も取り込めず変換失敗、ポインタが指しているアドレス内容は変更されません。で、"s"は標準入力に戻してしまいます。質問のプログラムでは、変数aは0に初期化されていたので0のまま。0だともう一度scanfでデータを取り込もうとするのですが...標準入力の先頭は、先程変換に失敗した"s"が戻されています。ので、scanfはまた"s"を取り込んで変換失敗、"s"を標準入力に戻して、次のscanfでまた...これが「無限ループ」の正体です。タイトルの「int型に文字を入れると」は、起こった現象としては「int型に文字を入れられなかったので」ということですね。

ということで、各氏解説されているように、scanf()で何とかしたいなら、まず戻り値で変換に失敗したことを検出し、変換できなかったデータを何らかの方法で捨ててから、(失敗して戻されたのではない)新しい入力データを取り込む、というようなことが必要になるのです。
あるいは、このscanf()の仕組みで細工するくらいなら、標準入力にあるデータを文字列として全部取り出してしまい、自前で解釈したほうがいっそすっきり、という考えも出てくるわけで。

投稿2019/07/22 13:20

thkana

総合スコア7639

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

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

退会済みユーザー

退会済みユーザー

2019/07/22 13:58

詳しい解説ありがとうございます。 そんなに歴史があったんですね... イマイチ仕様がわかっていなかった部分があったので助かります。
guest

0

scanf() の戻り値を判定して下さい。
変換に失敗した時はEOFが返されます。

初めて関数を使う時は、その仕様を確認しましょう。

投稿2019/07/22 01:57

nob.

総合スコア711

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

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

退会済みユーザー

退会済みユーザー

2019/07/22 02:16

回答ありがとうございます。 回答を元に追記1のようにコードを編集しましたが、解決しませんでした。
guest

0

整数以外の入力を禁止したい

1.文字列にfgets()で読む。・・・gets()ではない! 理由は仕様を確認
2.数字かどうか判定する。
3.数字ならintに変換・・・sscanf(),strtol()等
・・・それ以外なら、エラーメッセジを表示して1に戻る。

投稿2019/07/22 02:21

cateye

総合スコア6851

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

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

退会済みユーザー

退会済みユーザー

2019/07/22 02:31

回答ありがとうございます。 できれば入力から数字で扱いたいため、他の方法を試してみます。 どうしても解決できないときに使ってみます。
cateye

2019/07/22 02:43 編集

>入力から数字で扱いたい・・・キーコードをASCII文字に変換するのは、ドライバの分野じゃないですか?
退会済みユーザー

退会済みユーザー

2019/07/22 02:45

すみません。「数値」でした。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問