gets関数と構造体についての質問-プログラムの入力部分で問題が発生

このQ&Aのポイント
  • C言語のプログラムで、gets関数と構造体を使用して名前と点数を入力するプログラムを作成しています。
  • しかし、点数を入力するときにscanf関数を使用すると、入力の終了がスキップされてしまいます。
  • また、入力終了を示すend変数をjに置き換えると、入力はできるもののデータの表示がエラーとなってしまいます。
回答を見る
  • ベストアンサー

gets関数と構造体について

名前を入力して、各教科の点数を入力したあと、それを表示するプログラムを作りました。 完成はしたのですが、分からないところがあるので質問させて頂きます。 #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(初期化したものです)に置き換えると「入力を終わりますか?」の入力はできるのですがデータの表示がエラーでできなくなります。 この部分が分からず、もやもやが残っているので質問させていただきました。 長文で申し訳ないです。 回答よろしくお願いいたします。

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

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

まず。 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); はコンパイル時にエラーにはなりませんが、実行時に問題になります。

eternidad_beyer
質問者

お礼

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

その他の回答 (3)

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

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

  • usa3usa
  • ベストアンサー率33% (20/59)
回答No.3

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
  • Wr5
  • ベストアンサー率53% (2177/4070)
回答No.1

実行して検証はしていませんが… >scanf("%d",tensu[i].kokugo); コールした時、tensu[i].kokugoには何が入っているんでしょうか? ちゃんと「tensu[i].kokugoのアドレス」を値として入れましたか? # まぁ普通はそんなコトしませんけど。 # int型の変数に自分自身のアドレスを予め入れておく。なんてことは。 gets()とsacnf()併用すると、入力ストリームの状態どうなるんでしたっけかね? # http://detail.chiebukuro.yahoo.co.jp/qa/question_detail/q1442167359

関連するQ&A

  • gets

    struct phone_type { char name[100]; int areacode; char number[100]; } phone[MAX]; char temp; . . . gets(temp); phone[i].areacode = atoi(temp); tempに0000と入力するとareacodeには0しか入りません。 なぜでしょうか?

  • getsの部分がとばされてしまう

    #include<stdio.h> typedef struct Car{ char name[20]; int num; double gas; }Car; int main(void) { Car car[3]; int i; for(i=0;i<3;i++){ printf("ナンバーを入力してください。\n"); scanf("%d",&car[i].num); printf("車の名前を入力してください。\n"); gets(car[i].name); printf("ガソリン量を入力してください。\n"); scanf("%lf",&car[i].gas); } printf("name\tnumber\tfuel\n"); for(i=0;i<3;i++){ printf("%s\t%d\t%f\n",car[i].name,car[i].num,car[i].gas); } return 0; } …上記のようなプログラムを書いたのですが、実行すると、gets(car[i].name);の部分の処理が飛ばされてしまい、入力することができません。 どのようにしたらよいか、教えていただけませんでしょうか。 よろしくお願いいたします。

  • "gets"は危険なのでしょうか?

    以下をコンパイルした際に"gets function is dangerous and should not be used "と警告が出ました。直訳すると"getsは危険だから使わないほうが良い"となるのですが、今私の使用している教本には"'gets'に代わる文字列入力の便利な方法は無く、入力文字数が配列を超えないように"との注意しかなく、それは厳守しています。プログラムがいけないのでしょうか。 #include <stdio.h> int main(void) { char str[80]; int i; printf("文字列を入力してください(80文字以下): "); gets(str); for(i=0; str[i]; i++) printf("%c", str[i]); return 0;

  • c言語 構造体

    大学での内容なのですが,『名前,数学の点数,英語の点数,国語の点数を格納できる(メンバに持つ)構造体を宣言し,この構造体の配列を用いて,3人分の情報をキーボードから入力後,各科目の平均点を画面に表示するプログラムを作成せよ.』という問題で,自分なりに作ってみたのですがうまくいきません.どなたか教えていただけませんか? 一応自分で作ったものを下に載せておきます. ================================================================ #include <stdio.h> #include <string.h> struct test { char name[20]; int sugaku; int eigo; int kokugo; }; int main(void) { struct test suzuki; int (suzuki.sugaku), (suzuki.eigo), (suzuki.kokugo); strcpy(suzuki.name, "Suzuki"); printf("氏名:鈴木 一馬\n"); printf("数学:"); scanf("%d", &suzuki.sugaku); printf("英語:"); scanf("%d", &suzuki.eigo); printf("国語:"); scanf("%d", &suzuki.kokugo); struct test tanaka; int tanaka.sugaku, tanaka.eigo, tanaka.kokugo; strcpy(tanaka.name, "Tanaka"); printf("氏名:田中 二郎\n"); printf("数学:"); scanf("%d", &tanaka.sugaku); printf("英語:"); scanf("%d", &tanaka.eigo); printf("国語:"); scanf("%d", &tanaka.kokugo); struct test yamamoto; int yamamoto.sugaku, yamamoto.eigo, yamamoto.kokugo; strcpy(yamamoto.name, "Yamamoto"); printf("氏名:山本 三弘\n"); printf("数学:"); scanf("%d", &yamamoto.sugaku); printf("英語:"); scanf("%d", &yamamoto.eigo); printf("国語:"); scanf("%d", &yamamoto.kokugo); printf("数学の平均点は%dです。\n", ((suzuki.sugaku + tanaka.sugaku + yamamoto.sugaku) / 3.0)); printf("英語の平均点は%dです。\n", ((suzuki.eigo + tanaka.eigo + yamamoto.eigo) / 3.0)); printf("国語の平均点は%dです。\n", ((suzuki.kokugo, + tanaka.kokugo + yamamoto.kokugo) / 3.0)); return (0); } ================================================================

  • 構造体

    下記プログラムの2次元配列を構造体の配列に作り変え,構造体を利用して生年月日の項目を追加し,形式は日を除いたYYYY/MMで持ち,生年月日の入出力は,YYYY/MM形式で行い,西暦が数字4桁で,西暦と月の間に'/'があり,月が01~12の範囲の数字の2桁になっている7文字の入力のみ受け付け,正しく入力されるまでそれ以外は再入力させたい。あとdo-while文をつかっている箇所をwhile文に直したいです.自力でやったのですが,わかりませんでした. どのようにしたらよいか教えてください. お願いします. include <stdio.h> #define BUFFERSIZE 11 #define MAX_PERSON 10 #define MAX_CHARS 10 int main(void) { char name[10][BUFFERSIZE]; int c; int count = 0; int i; int j; for (i = 0; i < MAX_PERSON; i++) { printf("氏名入力 : "); j = 0; /* 氏名の1文字目が'0'なら入力を終了 */ if ((c= getchar()) == '0'){ break; } if (c == '\n') { /* 改行のみの入力は再入力 */ do { printf( "再入力\n" ); /*再入力*/ printf("氏名入力 : "); } while ((c = getchar()) == '\n'); } name[i][j++] = c; /*1文字目を格納*/ if (name[i][0] == '0') { break; } while ((c = getchar()) != '\n' && c != EOF) { if (j < BUFFERSIZE - 1) { name[i][j++] = c; } } name[i][j] = '\0'; count++; /* 実際に入力した人数を記録*/ printf("累計 : %d \n", count); } /* 氏名と生年月日を出力したいです */ for (i = 0; i < count; i++) { for (j = 0; j < MAX_CHARS; j++) { if (name[i][j] == '\0'){ break; } putchar(name[i][j]); } putchar('\n'); } return 0; }

  • 合計の出し方

    よろしくお願いいたします。 プログラミングの勉強中です。 国語:78 算数:94 理科:68 社会:70 英語:75 合計点は385点です。 と表示されるプログラムを作り、数字は変えられるようにscanfを使用します。 自分で以下のように作ってみたのですが、合計だけがめちゃめちゃな数で出て来てしまいます。 どこが間違っているか教えていただけますか? #include<stdio.h> main() { int kokugo; int sansuu; int rika; int syakai; int eigo ; int sum = kokugo+sansuu+rika+syakai+eigo; printf("国語:"); scanf("%d",&kokugo); printf("算数:"); scanf("%d",&sansuu); printf("理科:"); scanf("%d,&rika"); printf("社会:"); scanf("%d,&syakai"); printf("英語:"); scanf("%d,&eigo"); printf("合計点は%d点です。",sum); }

  • 教えてください!!

    このソースのtensu[5]={0};の意味を詳しくお願いします。宜しくお願いします。tensu[5]では、1~100の範囲で入力してください。が実行したら出てきてしまいますが、tensu[5]={0};とやるとうまくできます。そのことを知りたいです。 宜しくお願いします。 #include <stdio.h> int main(void) { int i; int tensu[5]= {0}; int sum=0; puts("点数を入力してください"); for(i=0; i<5; i++){ printf("%2d番:", i+1); do{ if(tensu[i]<0 || tensu[i]>100){ printf("0~100の範囲で入力してください。\n"); printf("%2d番:", i+1); } scanf("%d", &tensu[i]); }while(tensu[i]<0 || tensu[i]>100); sum+=tensu[i]; } putchar('\n'); for(i=0; i<5; i++) printf("%2d番: %d\n", i+1, tensu[i]); printf("合計点: %d\n", sum); printf("平均点: %f\n", (double)sum/5); return (0); }

  • C言語での構造体

    C言語の構造体で配列を扱うとき、 struct ○○{  char ○○[○] とすれば出来ますが、同じようにして構造体で二次元配列を扱うことは出来ますか? 一度組んでみたのですが、 #include<stdio.h> struct aaa{ int no; char name[128]; char y_name[128]; char n_name[128]; char s_name[128][128]; }; int main(void){ int i; struct aaa iryo[99]; printf("入力前\n"); /* 構造体配列に scanf()でデータを入力 */ for(i = 0; i < 3; i++) { // printf("input...\n"); scanf("%d", &iryo[i].no); scanf("%s", iryo[i].name); scanf("%s", iryo[i].y_name); scanf("%s", iryo[i].n_name); scanf("%s", iryo[i].s_name); } printf("入力後\n"); printf("出力前\n"); /* 入力データの確認 */ for(i = 0; i < 3; i++) { printf("番号:%02d 内容:%s Y分岐:%s N分岐:%s 他分岐:%s\n", iryo[i].no, iryo[i].name, iryo[i].y_name, iryo[i].n_name, iryo[i].s_name); } printf("出力後\n"); printf("%d",sizeof(struct aaa)); return 0; } としたら、エラーは出ませんが、実行すると何も表示されませんでした。

  • 構造体を動的変数とポインタを使い表を作る

    学校の改題で「人数を入力して、その人数分の名前と点数を入力して一覧にしろ」という課題がでたのですが、どこから手を付けていいのか解りません。 内容は「任意の人数を設定して、その分ループして名前と点数をいれ、その構造体を頭からループして一覧を作れ」ということなので以下のようにやってみたのですが、結果が「(null) 0」としかなりません。 手の打ちようがないので助言お願いします。 #include <stdio.h> #include <stdlib.h> struct ty_i{ char *name; int point; }; int main(void){ int n,i; struct ty_i *main_ty,*copy_ty; printf("n = ");scanf("%d",&n); main_ty=(struct ty_i *)malloc(sizeof(struct ty_i)*n); if(main_ty==NULL){ printf("Error\n"); exit(1); } for(i=0;i<n;i++){ printf("%d:",i);scanf("%s,%d",&main_ty++->name,&main_ty++->point); } copy_ty=main_ty; for(i=0;i<n;i++){ printf("%s\t%d\n",copy_ty++->name,copy_ty++->point); } exit(0); }

  • Rubyのgets関数について

    以下のプログラムを実行して、コマンドプロンプトからsと入力してEnterを押すと、differentと表示されます。sameと表示されることを期待しています。何が原因なのでしょうか?環境はWindows2000です。よろしくお願いします。 i = gets t = "s" if i == t print "same" else print "different" end