アプリ版:「スタンプのみでお礼する」機能のリリースについて

名前を入力して、各教科の点数を入力したあと、それを表示するプログラムを作りました。
完成はしたのですが、分からないところがあるので質問させて頂きます。

#include <stdio.h>
#include <string.h>

typedef struct {
char name[32];
int kokugo;
int rika;
} siken;

int main() {
siken tensu[5]; // = {"三村",80,45,"大竹",90,85,"松本",75,60,"狩野",100,100,"大江",95,90};
char name[32],point[16],end[6];
int i=0;
do {
printf("名前を入力してください。 : ");
gets(tensu[i].name);
//tensu[i].name = name;
printf("国語 : ");
gets(point);
tensu[i].kokugo = atoi(point);
printf("理科 : ");
gets(point);
tensu[i].rika = atoi(point);
i++;
printf("入力を終わりますか?(YES=0,NO=1) : ");
gets(end);
} while (atoi(end));

i=0;

do {
printf("氏名を入力して下さい。 : ");
gets(name);
while (strcmp(name,tensu[i].name))
i++;
printf("氏名 : %s\n国語 : %d\n理科 : %d\n",tensu[i].name,tensu[i].kokugo,tensu[i].rika);
printf("終わりますか?(YES=0,NO=1) : ");
gets(end);
if (atoi(end)==0)
break;
else if(atoi(end)!=1) {
printf("入力に誤りがあります。もう一度入力して下さい。 : ");
gets(end);
continue;
}
} while (atoi(end));
return 0;
}

このプログラムの

printf("名前を入力してください。 : ");
gets(tensu[i].name);
//tensu[i].name = name;
printf("国語 : ");
gets(point);
tensu[i].kokugo = atoi(point);
printf("理科 : ");
gets(point);
tensu[i].rika = atoi(point);
i++;
printf("入力を終わりますか?(YES=0,NO=1) : ");
gets(end);

の部分で、点数を入力するとき、

scanf("%d",tensu[i].kokugo);

とすると、入力を終了するための入力が飛ばされ、いきなり表示に行きます。(入力を終わりますか?の表示のだけですぐデータ表示のための「氏名を入力してください」が表示される感じです。)
また、この部分の最後のendをint型のj(初期化したものです)に置き換えると「入力を終わりますか?」の入力はできるのですがデータの表示がエラーでできなくなります。
この部分が分からず、もやもやが残っているので質問させていただきました。
長文で申し訳ないです。
回答よろしくお願いいたします。

A 回答 (4件)

まず。


scanfとかgetsとかで「キーボード」から入力、と習ったかと思いますが、正確には違います。
「標準入力」からの入力です。
この標準入力が、端末からの入力に割り当てられているので「キーボードからの入力」に見えるのです。

gets等が実行された時点でキー入力を受け付けるわけではなく、
端末は端末で勝手にキー入力を受け付け送信してくるし、
受け取ったOS側もOS側で、勝手に蓄えておいて、要求されたら要求されただけの文字を送ります。

国語 :
と表示されたから
95リターン
と入力したら、次へ実行が移った
...かのように見えますが、実際は、入力(gets,scanf)が実行された時点で、「溜め込んだ入力が無い」ので「入力が溜るまで待っていた」ためで。
逆に言えば、「溜め込んだ入力」が既にあるのなら、それから読み出され、キーボード入力など待たないのです。


scanf("%d",tensu[i].kokugo); では、数値だけを読み込みます。
数値を入力するとき
95リターン
というようにキーを入力しているかと思います。
scanf("%d"では、数値だけしか読み込まないので、「95」だけが読み込まれ、「リターン」は「溜め込んだ入力」に残ったままになります。
続いてscanf("%d",tensu[i].rika); とすると
あなたは「87リターン」と入力したつもりかもしれませんが、プログラムは
(残っている)リターン87
までを読み込み、その後のリターンは残ったままです。

gets(end)ですが、getsはリターンまでを読み込みます。
ここで、先程のリターンが残っているので、その(残っている)リターンを読み込み、getsの処理は終了です。
この場所でキーボード入力を待つ必要なく、getsを終了させることができます。


・溜め込んだ物を使わないようにする
・scanfを使わない
・endの 入力内容をatoiに頼らずに、ちゃんと値が入っているか確認する
等、対処方法はたくさんあります。


なお、 scanf("%d",tensu[i].kokugo); はコンパイル時にエラーにはなりませんが、実行時に問題になります。
    • good
    • 0
この回答へのお礼

なるほど、scanfとgetsにはそういう違いがあるのですね。
入力が溜まるというのは以前参考書で読みましたが、よく分からなかったので覚えていませんでした…
ありがとうございます。

お礼日時:2014/07/16 08:44

ついでだけど, 今さら gets もなんだかなぁと思う.

    • good
    • 0

2点、scanfの使い方に、勘違いがありそうです。



・scanfでは、格納場所のポインタを指定しますので、
scanf("%d",tensu[i].kokugo);

scanf("%d",&tensu[i].kokugo);
ですね。

・scanfでは、改行文字が残ること、忘れていませんか?


http://www9.plala.or.jp/sgwr-t/c/sec05.html#s5-3

参考URL:http://www9.plala.or.jp/sgwr-t/c/sec05.html#s5-3
    • good
    • 0

実行して検証はしていませんが…



>scanf("%d",tensu[i].kokugo);

コールした時、tensu[i].kokugoには何が入っているんでしょうか?
ちゃんと「tensu[i].kokugoのアドレス」を値として入れましたか?
# まぁ普通はそんなコトしませんけど。
# int型の変数に自分自身のアドレスを予め入れておく。なんてことは。

gets()とsacnf()併用すると、入力ストリームの状態どうなるんでしたっけかね?
# http://detail.chiebukuro.yahoo.co.jp/qa/question …
    • good
    • 0

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!