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

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

ただいまの
回答率

89.13%

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

解決済

回答 5

投稿 編集

  • 評価
  • クリップ 1
  • VIEW 1,218

Re_TKW

score 31

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

#include <stdio.h>

int main(void)
{
    int a = 0;

    while (a == 0)
    {

        scanf("%d", &a);

        printf("%d\n", a);
    }

    return 0;
}

上のプログラムで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;
}
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 5

checkベストアンサー

+2

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

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

#include <stdio.h>

int main(void)
{
    int a = 0;
    int z;

    while (a == 0)
    {

        z = scanf("%d", &a);
        if(z==EOF) break;
        if(z==0){
            scanf("%*s"); // 読み飛ばして、ループを繰り返す
            continue;
        }
        printf("%d\n", a);
    }

    return 0;
}

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/07/22 11:54

    > 12345は%*sで入力した物だと思いますが、

    いえ。abcdeが%*sで入力した値です。

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

    いえ。「数字以外を入力した場合は成功がゼロ個つまり0が返り、」と回答に書いたのですが忘れましたか?

    キャンセル

  • 2019/07/22 12:16

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

    キャンセル

  • 2019/07/22 12:22

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

    キャンセル

+2

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

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/07/22 11:24

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

    キャンセル

+1

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

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

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/07/22 11:16

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

    キャンセル

+1

もう解決しちゃってますけど、ちょっとだけ補足...と思ったら長くなっちゃいました。でも、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 22:58

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

    キャンセル

0

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

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

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/07/22 11:31

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

    キャンセル

  • 2019/07/22 11:42 編集

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

    キャンセル

  • 2019/07/22 11:45

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

    キャンセル

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

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