C言語でscanfを用いた入力の動作確認

このQ&Aのポイント
  • C言語でscanfを用いた入力の動作確認を行ったプログラムの実行結果について説明します。
  • 数値を入力した場合と文字を入力した場合の挙動に違いがあることを確認しました。
  • 文字を入力すると正常に出力されず、意図しない結果が得られることがあります。
回答を見る
  • ベストアンサー

C言語でscanfを用いた入力

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 どうして文字を入力したら正常に出力しなくなるのでしょうか?

質問者が選んだベストアンサー

  • ベストアンサー
  • kmee
  • ベストアンサー率55% (1857/3366)
回答No.10

少し前に私も回答した質問です。ここで少し詳しいマニュアルを紹介しています。 http://okwave.jp/qa/q6721320.html scanfって、正しく使えば便利だけど、失敗するととんでもない目にあう、という、C言語の特徴をそのまま象徴するような関数です。 一度、詳細なマニュアルや参考書をよく読んだ上で、まだわからなかったら質問するくらいでないと、理解できないかもしれません。 面倒なのでscanfを使わない、というのも有効な一つの解決策です。

bururutti-2
質問者

お礼

有難うございました。参考にします。 ただ、そのサイトの「ヘッダファイル一覧」のscanfの部分をクリックしたら意味不明の文字列が並んでしまいました。 まだ未完成って事かな?

その他の回答 (9)

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.9

「空白文字」というのは, isspace が真となる文字のこととなっています. その中には ' ', '\n', '\r', '\f', '\t', '\v' は必ず含まれます. と規格にちゃんと書いてあるので, 人に聞くだけでなく自分でも調べるといいと思うよ.

bururutti-2
質問者

お礼

改行も空白文字に含まれているのですね。 一応ネットで調べたりはしているのですが、なかなか知りたい情報が見つけられなくて・・・ 回答有難うございました。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.8

それは「scanf の仕様を確認しろ」で終わりなんだけど, ぶっちゃけていえば 一部の変換 (%c や %[ など) を除いて最初の空白文字は読み飛ばす という仕様になっているからです. 例えば %d で読み込むときは「空白は読み飛ばす」ことになっています. ですが, %c で読み込むときには「空白も読む」ことになっています.

bururutti-2
質問者

お礼

なるほど、[ENTER]を文字として扱わなかったのではなく、その部分を読み飛ばしたのですね。 回答有難うございました。

bururutti-2
質問者

補足

%dの時は「空白文字は読み飛ばす」というのは分かりましたが、そうすると[ENTER]は空白と同様に扱われるという事でしょうか? もしかして、[ENTER]以外の制御文字でも空白と同様に扱われるのでしょうか?

回答No.7

> 1文字入力の時は、たとえ入力待ちの型が同じでも上手くいきませんでした。 > どうして1文字入力の時は上手くいかないのでしょうか? うまくいってると思いますよ。 あなたは、 A[ENTER] と入力したのでしょうから、最初のscanfで'A'が、次のscanfで[ENTER]が読みだされているはずです。

bururutti-2
質問者

お礼

[ENTER]という値が入力されているのですか。 これじゃあ文字で出力しても分かりませんね。 回答有難うございました。

bururutti-2
質問者

補足

[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; }

bururutti-2
質問者

お礼

なるほど、scanfの戻り値は変換に成功した数ですか。 エラー処理には戻り値を使えば良いのですね。 ソースコードまで記述して頂き有難うございました。

  • asuncion
  • ベストアンサー率33% (2126/6286)
回答No.5

>#2さん >Cでは、明示的にしない限り、変数を初期化しない。 ブロック内の自動変数では、というただし書きが必要だったのではないかなぁ、 などと思ったりしてます。

bururutti-2
質問者

お礼

「ブロック内の自動変数では、」ってことは、それ以外では明示的にしなくても良い場面があるって事ですね。 う~ん、一体どういう場面なら明示的にしなくて良いのだろう? 回答有難うございました。

  • Tacosan
  • ベストアンサー率23% (3656/15482)
回答No.4

もちろん「バッファオーバーフローを回避する」こともできるんですけどね>#3. 「ちゃんと使えば使える, でも世の中には『ちゃんと使うことのできない』人が多いだけ」ということもできるかな.

bururutti-2
質問者

お礼

scanfって意外に使いこなすのが難しいのですね。 回答有難うございました。

回答No.3

scanfの仕様によるものです。 %dを指定しているのに"A"のように整数に変換できない文字列が入力された場合、scanfは読み取れたフィールドの数として0を戻り値として返し、変換できなかった文字列は標準入力に残したままにします。 そうすると、整数に変換できない文字列が標準入力に残ったままの状態で、次のscanfが実行されます。当然、変換できないで終了します。 2つのscanfは失敗しているので、iには何も代入されない状態となり、iの値を表示させても不定な値が表示されるだけです。 scanfを使わないようにといわれるのは、このような仕様がわかりずらいことや、%sで文字列を読み込もうとする場合に、入力しだいで文字列の長さが変わるため、用意した文字列サイズを超えてしまうバッファーオーバーランが起こりやすいためです。特に動作が不安定ということはありません。

bururutti-2
質問者

お礼

読み込みに失敗すると文字列は標準入力に残ったままになるのですね。 scanfっていろんな問題点があるのですね。 回答有難うございました。

bururutti-2
質問者

補足

No.2さんとNo.3さんの回答を元に整理してみると、scanfの処理は次のように認識しましたが、この認識で合っているでしょうか? 「入力したデータを標準入力に送り、読み込みに成功するとファイルポインタを進ませて、2回目の読み込みでは次の文字から読み込みを行う。読み込みに失敗するとファイルポインタを進ませずに、2回目の読み込みでは前の文字が残った状態で読み込みを行う。」

  • kmee
  • ベストアンサー率55% (1857/3366)
回答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 異常な入力が行われた時の処理 あたりも参考に

bururutti-2
質問者

お礼

なるほど、scanfはそうやって処理していたのですか。 scanfにはエラー処理が必要なんですね。 回答有難うございました。

bururutti-2
質問者

補足

今度は次のようにプログラミングして試してみました。 以下のソースコードは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回目の入力が省略されたのでしょうか?

  • akr104
  • ベストアンサー率49% (25/51)
回答No.1

scanfの中で使われている「%d」は、整数の入力を待っている状態だからでしょう。 1文字入力したい場合は、scanf("%c", &i)、文字列ならscanf("%s", i)(このiは配列) などとしないといけません。 それに付随したエラーかと。 また、scanf自体が不安定な命令だからかもしれません。 大学では「scanfはあまり使わないように」と言われました。 もし文字も数値も入力したのなら、文字列を入力する形式にして、 その後、数値に変換する、という手順を踏むのがよいかと思われます。

bururutti-2
質問者

お礼

入力待ちの型が違うと上手くいかないのですか。 scanfは多用しない方が良いのですね。 回答有難うございました。

bururutti-2
質問者

補足

今度は、試しに入力待ちの型を同じにしてみました。 #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

  • シーザー暗号(C言語)

    シーザー暗号というものを作ろうとしていますが、文字のずらし方がわからず詰まっています。 手順は一応考えてあります。 (1)入力された文字を配列input[301]に代入 (2)何文字ずらすかを指定してその数値を変数countに代入 (3)入力された文字の長さを変数lenに代入 (4)inputとcountとlenを、文字をずらしてそれをoutputに返す関数shiftに渡す (5)outputを表示する のような感じですが、肝心の文字のずらし方がわかりません。 JISコードを使ってやるといいと聞いたんですが、そのやり方がわかりません。 ソース↓ #include <stdio.h> #include <string.h> int shift_char(char x[], int y, int z) { int i; for(i = 0; i <= z; i++) { x[i] = x[i] + y; } return x; } int main(int argc, char* argv[]) { char input[301]; char output[301]; int count, len, i; printf("文字を入力してください: "); scanf("%s" ,input); printf("何文字ずらしますか: "); scanf("%d" ,count); len = strlen(input); output = shift_char(input, count, len); for(i = 0; i <= len; i++) { printf("%s" ,output[i]); } return 0; } よろしくお願いします。

  • c言語 scanf

    下のソースを実行したらおかしなことになったんですがなんででしょうか?? #include<stdio.h> int main(void){ int i; char c[1000]; for(i=0;;i++){ printf("文字>>>>"); scanf("%c",&c[i]); printf("result = %c \n",c[i]); } } ↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓実行↓↓↓↓↓↓↓↓↓↓↓↓↓↓↓ 文字>>>>a result = a 文字>>>>result = 文字>>>>b result = b 文字>>>>result = 文字>>>>c result = c 文字>>>>result = 文字>>>>d result = d 文字>>>>result = 文字>>>>^C

  • scanf関数について

    scanfで数字を入力し「CTRL+D」で入力終了となるプログラムを考えています. 調べてみると以下の様なプログラムでは入力終了となります. #include <stdio.h> int main(void) { int a[256]; int i = 0; while(1) { printf("Input%d = ", i); if ( scanf("%d", &a[i]) == EOF || i > 255) { break; } i++; } return 0; } しかし,次の様にすると「CTRL+D」では終了しません. #include <stdio.h> int main(void) { int a[256]; int i = 0; while(1) { printf("Input%d = ", i);   scanf("%d", &a[i]); <-----追加 if ( a[i] == EOF || i > 255) {   <-----変更 break; } i++; } return 0; } この場合は,環境がUNIXのため「-1」と入力すると終了します. 2種類の違いが分かりません. 教えてもらえないでしょうか?

  • 【C言語】二重forループ内でscanfを使ってchar型変数に数値(

    【C言語】二重forループ内でscanfを使ってchar型変数に数値(%d)を入力すると、きちんとループ処理されないのはなぜ? プログラムを下に用意しましたのでご覧下さい。 二重forループ内で入力を繰り返すプログラムです。 ついでに i j の値を出力するようにしました。 -----------------プログラム---------------- int main (void){ char input = 0; // 入力値 char型にするとforループでインクリメントエラー(int型にすると問題ない) int i = 0, j = 0; , printf("数値を入力して下さい。('-1' で入力終了)\n"); for( i=0 ; i<3 ; i++ ){ // i がちゃんとインクリメントされない for( j=0 ; j<3 ; j++ ){ scanf("%d", &input); // char 型変数に %d で入力すると、i がきちんとインクリメントされない printf("[i][j] = [%d][%d]\n", i, j); if( input == -1 ){ printf("入力を終了します。\n"); break; } } if( input == -1 ) break; } return 0; } ---------------------------------------- ---------実行結果(入力値はchar型)--------- 数値を入力して下さい。('-1' で入力終了) 1 2 3 4 5 6 7 8 9 [i][j] = [0][0] [i][j] = [0][1] [i][j] = [0][2] [i][j] = [0][0] [i][j] = [0][1] [i][j] = [0][2] [i][j] = [0][0] [i][j] = [0][1] [i][j] = [0][2] -1 [i][j] = [16777215][0] 入力を終了します。 ---------------------------------------- ----------実行結果(入力値はint型)---------- 数値を入力して下さい。('-1' で入力終了) 1 2 3 4 5 6 7 8 9 [i][j] = [0][0] [i][j] = [0][1] [i][j] = [0][2] [i][j] = [1][0] [i][j] = [1][1] [i][j] = [1][2] [i][j] = [2][0] [i][j] = [2][1] [i][j] = [2][2] ---------------------------------------- ご覧の通り、char型変数に値を入力しているために、forループで i がきちんとインクリメントされません。 入力値は -128~127 の値しか想定していないので、メモリの消費を少しでも抑えようと思いchar型で宣言したのですが、思わぬ所でおかしな挙動が起こってしまいました。 int型で宣言すればいいだけなのですが、なぜこんな挙動になるのか知りたいです。 よろしくお願いします。

  • switch文とscanfについて

    ソースコード------------------------------------- #include <stdio.h> void main(){ int i; char s, ch; while(1){ printf("Input 1 or 2\n"); scanf("%c", &s); switch(s){ case '1' : printf("Input a number\n"); scanf("%d", &i); printf("You input '%d'\n", i); break; case '2' : printf("Input a character\n"); scanf("%c", &ch); printf("You input '%c'\n", ch); break; } } } ----------------------------------------------- 実行例----------------------------------------- Input 1 or 2 1 Input a number 4 You input '4' Input 1 or 2 Input 1 or 2 //------(1) 2 Input a character You input ' //------(2) ' Input 1 or 2 ----------------------------------------------- (1)について。 なぜ"Input 1 or 2"が二回繰り返されているのですか。 (2)について。 scanfが呼び出されて入力待ちになることを期待しているのですが、 なぜ(2)のようになってしまうのでしょうか。

  • C言語の無効な値が入力されたときの繰り返しについて

    C言語で最初に入力した整数の5倍になるまで何度も入力を促すプログラムでわからないところがあるのですが #include  "stdio.h" int main() { int a ; do { printf("input a:"); scanf("%d",&a); } while( )     ← printf( ) ←この二つの()内の文字をどうすればよいのか分かりません return 0; } 教えていただけないでしょうか

  • scanf()関数の使い方について

    はじめまして。 質問があります。 まずは、以下のコードを見てください。 ---------------------------------------------------------------- #include<stdio.h> int main(void) { char c; int i; printf("0を入力すると終了します。\n"); while(1) { printf("文字を入力してください=>"); scanf("%c",&c); printf("入力した文字は %c です。\n",c); printf("数字を入力してください=>"); scanf("%d",&i); if(i==0) { break; } printf("入力した数字は %d です。\n",i); } return 0; } ---------------------------------------------------------------- 上のコードを実行すると、初回はscanf()はcharとintの両方とも 入力待ちになってくれるのですが、2回目以降はcharは入力待ちに なってくれません。これは、なぜなのでしょうか? ご教授お願いします。 現在VC++6.0を使用しております。

  • scanfでの可変引数

    こんばんわ。 C言語で簡単な支出計算プログラムみたいなのを作ったのですが、自分の思ったようなプログラムが書けません。 #include<stdio.h> int main(int argc,char *argv[]){ int i; int n1; int a1,a2; int sum=0; puts("計算する日数を入力してください。"); printf("日数:"); scanf("%d",&n1); for(i=1;i<=n1;i++){ printf("%d日目:",i); scanf("%d",&a1); sum+=a1; } printf("【%d日間の支出】:%d円\n",i-1,sum); } 実行結果は以下のようになります。 計算する日数を入力してください。 日数:2 1日目:100 2日目:200 【2日間の支出】:300円 このプログラムだと1日に1つの支出しか計算してくれません。 1日で入力できる支出を複数にしたいのですが、つまり下のように 計算する日数を入力してください。 日数:3 1日目:100,150 2日目:200 3日目:300,150,1000 【3日間の支出】:1900円 のようにscanfで入力した数値を可変個の値にしたいのですが、 どのように実現したらよいでしょうか? scanf("%d,%d"&a1,&a2);のように2つにしてれやば複数にはできますが 必ず2個入力しないとエラーになってしまいます。 調べた所va_listという可変引数リストが使えそうなのですが、 scanfでどのように使えばよいのかわかりません。 ご教授よろしくお願いします。

  • scanfの入力形式確認について

    scanfで入力形式を%dに指定した場合、文字をタ-ミナル上で入力しても読みとばされるようで、結果 printf("please input 0 or 1.\n") while(1){ scanf("%d",&a); if(a==0 || a==1)break; printf("please input 0 or 1!\n") } といったプログラムをかいた場合、while内を永遠さまようプログラムになってしまいました。 入力を%cにしてatoiを使う以外の手法で、入力を%dに固定するかもしくは文字が入力された場合にはエラ-をはくプログラムにしたいのですが、そのような変更は可能でしょうか? 初歩的な質問で申訳ありませんが、ご教授よろしくお願いします。

  • 因数分解プログラム(C言語)について(1)

    ”因数分解を行うプログラムについて”の質問と同じ者です。 みなさんのご回答を参考にして、作ってみたのですが、 ポインタとかの使い方などがわからず、実行すると、 不正な処理を行ったので終了しますとなってしまいます。 どなたか、具体的にどこが悪いのか、 そしてどのように直せば正しく実行されるのか、 教えて下さい。お願いします。 以下↓がプログラムです。 800文字以上のため二つに分割しました。 #include <stdio.h> #include <math.h> #include <process.h> /*関数プロトタイプ宣言*/ int input(int *,int *,int *); int judge(int *,int *,int *); int bunkai1(int *,int *,int *,int *,int *,float *); int bunkai2(int *,int *,int *,int *,int *,float *); int yakubun1(int *,int *,int *,int *,int *,int *,int *); int yakubun2(int *,int *,int *,int *,int *,int *,int *); int output(int *,int *,int *,int *); /*関数の呼び出し*/ int main(void) { int a,b,c,q,n1,m1,min1,flag,i,d,e,m2,n2,min2,f,g; float D; input(&a,&b,&c); judge(&a,&b,&c); bunkai1(&a,&b,&q,&n1,&m1,&D); bunkai2(&a,&b,&q,&n2,&m2,&D); yakubun1(&m1,&n1,&min1,&flag,&i,&d,&e); yakubun2(&m2,&n2,&min2,&flag,&i,&f,&g); output(&d,&e,&f,&g); return (0); } /*数値入力関数*/ int input(int *a,int *b,int *c) { printf("a*x^2+b*x+c=0で,a,b,cを入力して下さい。\n"); printf("a="); scanf("%d",a); printf("b="); scanf("%d",b); printf("c="); scanf("%d",c); if(*a == 0){ printf("a = 0なので因数分解できません。\n"); exit(1); } return 0; } つづく

専門家に質問してみよう