C言語でscanfの動作を確かめる為に、次のプログラムを作成して実行してみました。
#include <stdio.h>
int main(void){
int i;
printf("Input1:");
scanf("%d",&i);
printf("Input2:");
scanf("%d",&i);
printf("Output:%d",i);
return 0;
}
このプログラムは1回目と2回目に数値を入力すると正常に出力します。
例 1回目の入力に10、2回目の入力に20を入力した時の出力結果
Input1:10
Input2:20
Output:20
今度は1回目で数値、2回目で文字を入力してみました。
そしたら2回目の入力が無視されました。
例 1回目の入力に10、2回目の入力にAを入力した時の出力結果
Input1:10
Input2:A
Output:10
今度は1回目で文字を入力してみました。
そしたら2回目の入力は要求せず、いきなりよく分からない数値が出力されました。
例 1回目でAを入力した時の出力結果
Input1:A
Input2:Output:-858993460
どうして文字を入力したら正常に出力しなくなるのでしょうか?
No.10ベストアンサー
- 回答日時:
少し前に私も回答した質問です。
ここで少し詳しいマニュアルを紹介しています。http://oshiete.goo.ne.jp/qa/6721320.html
scanfって、正しく使えば便利だけど、失敗するととんでもない目にあう、という、C言語の特徴をそのまま象徴するような関数です。
一度、詳細なマニュアルや参考書をよく読んだ上で、まだわからなかったら質問するくらいでないと、理解できないかもしれません。
面倒なのでscanfを使わない、というのも有効な一つの解決策です。
有難うございました。参考にします。
ただ、そのサイトの「ヘッダファイル一覧」のscanfの部分をクリックしたら意味不明の文字列が並んでしまいました。
まだ未完成って事かな?
No.8
- 回答日時:
それは「scanf の仕様を確認しろ」で終わりなんだけど, ぶっちゃけていえば
一部の変換 (%c や %[ など) を除いて最初の空白文字は読み飛ばす
という仕様になっているからです. 例えば %d で読み込むときは「空白は読み飛ばす」ことになっています. ですが, %c で読み込むときには「空白も読む」ことになっています.
この回答への補足
%dの時は「空白文字は読み飛ばす」というのは分かりましたが、そうすると[ENTER]は空白と同様に扱われるという事でしょうか?
もしかして、[ENTER]以外の制御文字でも空白と同様に扱われるのでしょうか?
No.7
- 回答日時:
> 1文字入力の時は、たとえ入力待ちの型が同じでも上手くいきませんでした。
> どうして1文字入力の時は上手くいかないのでしょうか?
うまくいってると思いますよ。
あなたは、
A[ENTER]
と入力したのでしょうから、最初のscanfで'A'が、次のscanfで[ENTER]が読みだされているはずです。
この回答への補足
[ENTER]も1文字とみなされる事は分かりましたが、新たな謎が生まれました。
質問した時に記述したソースコードで、1回目に数値と入力したら上手くいきます。
しかし、例えば1回目に10を入力したら標準入力は10[ENTER]になると思います。
そしたら1回目のscanfでiに10が格納されて、2回目のscanfで失敗してしまい次のように出力される気がします。
Input1:10
Input2:Output:10
どうして文字型の時は[ENTER]を文字として扱ったのに、整数型の時は[ENTER]を文字として扱わないのでしょうか?
No.6
- 回答日時:
> どうして文字を入力したら正常に出力しなくなるのでしょうか?
理由はscanf()が正しく動いてないから。
scanf()関数は正しく変換できた値の数を返します。
例えば、
int i1, i2;
scanf( "%d %d", &i1, &i2 );
なら、2つの整数が正しく設定できた場合には2を返します。
もし、お望みの動作が一度目の入力で不正値が入力された場合には、それを読み飛ばして2回目に入力された値を出力するという動作ならそのような手順で処理をプログラムする必要があります。
#include <stdio.h>
int main(void){
int i;
printf("Input1:");
if( 0 == scanf("%d",&i) ) {
char dummy[1024];
scanf( "%s", dummy );
}
printf("Input2:");
if( 1 == scanf("%d",&i) ) {
printf("Output:%d\n",i);
} else {
printf( "2度目の入力値が正しく変換できませんでした。n" );
}
return 0;
}
なるほど、scanfの戻り値は変換に成功した数ですか。
エラー処理には戻り値を使えば良いのですね。
ソースコードまで記述して頂き有難うございました。
No.3
- 回答日時:
scanfの仕様によるものです。
%dを指定しているのに"A"のように整数に変換できない文字列が入力された場合、scanfは読み取れたフィールドの数として0を戻り値として返し、変換できなかった文字列は標準入力に残したままにします。
そうすると、整数に変換できない文字列が標準入力に残ったままの状態で、次のscanfが実行されます。当然、変換できないで終了します。
2つのscanfは失敗しているので、iには何も代入されない状態となり、iの値を表示させても不定な値が表示されるだけです。
scanfを使わないようにといわれるのは、このような仕様がわかりずらいことや、%sで文字列を読み込もうとする場合に、入力しだいで文字列の長さが変わるため、用意した文字列サイズを超えてしまうバッファーオーバーランが起こりやすいためです。特に動作が不安定ということはありません。
この回答への補足
No.2さんとNo.3さんの回答を元に整理してみると、scanfの処理は次のように認識しましたが、この認識で合っているでしょうか?
「入力したデータを標準入力に送り、読み込みに成功するとファイルポインタを進ませて、2回目の読み込みでは次の文字から読み込みを行う。読み込みに失敗するとファイルポインタを進ませずに、2回目の読み込みでは前の文字が残った状態で読み込みを行う。」
読み込みに失敗すると文字列は標準入力に残ったままになるのですね。
scanfっていろんな問題点があるのですね。
回答有難うございました。
No.2
- 回答日時:
scanfの仕様と、C言語の変数の初期値の関係です。
まず、そのプログラムはscanfでエラー処理を行なっていません。
そのため、正常に読めても、失敗しても、とにかく次へ進みます。
> Input1:10
> Input2:A
> Output:10
10がscanfでiに代入される
→「A」では「%d」に対応しないので失敗。
失敗なので、ファイルポインタは移動しない、iの値はもとのまま
→10が表示される
> Input1:A
> Input2:Output:-858993460
一つめのscanfで「A」では「%d」に対応しないので失敗。
失敗なので、ファイルポインタは移動しない、iの値はもとのまま
→2つめのscanfでも、読み込み位置が前のままなので、「A」から読み込もうとして「%d」に対応しないので失敗。
失敗なので、ファイルポインタは移動しない、iの値はもとのまま
→iが表示される。
Cでは、明示的にしない限り、変数を初期化しない。変数iに何が入っているかは不定。今回はたまたま-858993460だった
scanf系を使う場合は、エラー処理を忘れずに。
http://ja.wikipedia.org/wiki/Scanf
4.4 異常な入力が行われた時の処理
あたりも参考に
この回答への補足
今度は次のようにプログラミングして試してみました。
以下のソースコードはNo.1さんの補足にも記述したのですが、改めて記述します。
#include <stdio.h>
int main(void){
char i;
printf("Input1:");
scanf("%c",&i);
printf("Input2:");
scanf("%c",&i);
printf("Output:%c",i);
return 0;
}
ここで、1回目の入力をAとしてみました。
1回目のscanfで「A」は「%c」に対応するので読み込みに成功し、ファイルポインタは移動して再び入力待ちになるはずです。
しかし、実際は2回目の入力が省略されてしまいました。
どうして2回目の入力が省略されたのでしょうか?
No.1
- 回答日時:
scanfの中で使われている「%d」は、整数の入力を待っている状態だからでしょう。
1文字入力したい場合は、scanf("%c", &i)、文字列ならscanf("%s", i)(このiは配列)
などとしないといけません。
それに付随したエラーかと。
また、scanf自体が不安定な命令だからかもしれません。
大学では「scanfはあまり使わないように」と言われました。
もし文字も数値も入力したのなら、文字列を入力する形式にして、
その後、数値に変換する、という手順を踏むのがよいかと思われます。
この回答への補足
今度は、試しに入力待ちの型を同じにしてみました。
#include <stdio.h>
int main(void){
char i;
printf("Input1:");
scanf("%c",&i);
printf("Input2:");
scanf("%c",&i);
printf("Output:%c",i);
return 0;
}
ここで、1回目の入力をAとした時、何故か2回目の入力は省略されて、出力結果は次のようになりました。
Input1:A
Input2:Output:
1文字入力の時は、たとえ入力待ちの型が同じでも上手くいきませんでした。
どうして1文字入力の時は上手くいかないのでしょうか?
お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!
似たような質問が見つかりました
- C言語・C++・C# 至急教えてください。プログラミングの問題です。 最初に正の整数nの入力を受け付け、次に分数の分子と分 1 2022/07/19 17:03
- C言語・C++・C# 至急お願いします。プログラミングの問題です。 最初に正の整数nの入力を受け付け、次に分数の分子と分母 3 2022/07/19 17:09
- C言語・C++・C# C言語(構造体) 3 2022/07/05 20:08
- C言語・C++・C# 至急教えてください。プログラミングの問題です。 malloc関数を使ってください!お願いします! 最 1 2022/07/21 09:28
- C言語・C++・C# 至急教えてください!プログラミングの問題です。 割られる整数と割る整数を受け取って、商と余りを出力す 3 2022/07/05 10:23
- C言語・C++・C# C言語 3 2022/10/04 15:07
- C言語・C++・C# C言語階乗の総和を求める 2 2023/03/04 23:31
- C言語・C++・C# c言語の問題です 3 2023/01/10 16:15
- C言語・C++・C# C言語プログラム変更 2 2022/12/21 15:03
- C言語・C++・C# c言語配列の結合についてです。 なぜうまくいかないのでしょうか。 #include <stdio.h 4 2022/05/30 22:42
関連するカテゴリからQ&Aを探す
おすすめ情報
デイリーランキングこのカテゴリの人気デイリーQ&Aランキング
-
*をユーザーが入力した数字の数...
-
数字以外が入力されたらエラー...
-
正負を反転させて出力するプロ...
-
java初心者です。入力されたの...
-
Eclipseコンソール表示を、リセ...
-
scanf が無視されます
-
プログラミング初心者です。 Py...
-
C言語初心者です。ファイルの読...
-
VisualStudio2019のコードアナ...
-
入力値が1以下、かつ数字以外の...
-
Linuxで入力待ちなしkeyread関...
-
scanfが2回使えない・・・?;
-
enterでループ終了
-
キーボードを押すまで処理を中...
-
C言語 for文をつかって記号を表...
-
C言語・YesNo入力のループで解...
-
IF文で戻ることはできますか?...
-
あるキーを押したら強制終了さ...
-
2進数の1の数を数える問題
-
コマンドプロンプトからのEOFの...
マンスリーランキングこのカテゴリの人気マンスリーQ&Aランキング
-
*をユーザーが入力した数字の数...
-
正負を反転させて出力するプロ...
-
数字以外が入力されたらエラー...
-
プログラミング初心者です。 Py...
-
double型が正常に認識されてい...
-
java初心者です。入力されたの...
-
Eclipseコンソール表示を、リセ...
-
scanfが2回使えない・・・?;
-
C言語scanf_sで何故か2回入力に...
-
if文の条件にscanf関数を使うと…?
-
Linuxで入力待ちなしkeyread関...
-
プログラミングの問題です 「金...
-
ワードで文字を入力する時の変...
-
cout関数を使っているのですが...
-
batプログラム上で文字列を入力...
-
Userformの入力順序をタブオー...
-
scanf が無視されます
-
C言語 逆ピラミッドの作り方
-
gets_sがうまく動かない
-
Excel VBAで、Application.Inpu...
おすすめ情報