🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

Q&A

解決済

1回答

5645閲覧

ファイルをfscanfで読み込んで構造体に入れて最後のデータを表示したい。

Aru-0

総合スコア5

C

C言語は、1972年にAT&Tベル研究所の、デニス・リッチーが主体となって作成したプログラミング言語です。 B言語の後継言語として開発されたことからC言語と命名。そのため、表記法などはB言語やALGOLに近いとされています。 Cの拡張版であるC++言語とともに、現在世界中でもっとも普及されているプログラミング言語です。

0グッド

0クリップ

投稿2019/12/16 08:50

編集2019/12/16 13:01

前提・実現したいこと

キーボードから指定されたファイル名のデータを読み込ませよ.ファイル名は99文字までとする.またデータは,番号,氏名,数学の点数,英語の点数が空白文字で区切られたデータである.読み込んだ最後のデータの氏名(最大99文字)を表示するプログラムを作成せよ.もしもファイルが存在しない場合にはNGと表示せよ.
という問題あり、自分なりに書いてみたのですが理解が及んでいないところがありどうにも解決できません

発生している問題・エラーメッセージ

出力されない、for分の条件の付け方がわからない
subscripted value is not an array, pointer, or vector
for(i=0;d[i]!=EOF;i++)
と表示される

該当のソースコード

C言語

1#include <stdio.h> 2#include <stdlib.h> 3typedef struct data{ 4 int no; 5 char name[99]; 6 int e; 7 int m; 8} DATA; 9 10int main() 11{ 12int i=0; 13 FILE *fp; 14 char filename[99]; 15 DATA d; 16 scanf("%s",filename); 17 fp=fopen("filename","r"); 18 if(fp==NULL) 19{ 20printf("NG"); 21return -1; 22} 23for(i=0;d[i]!=EOF;i++) 24{ 25fscanf(fp, "%d%s%d%d", &d.no, d.name, &d.e, &d.m ); 26} 27printf("%c",d.name[i]); 28} 29 30

試したこと

whlie分などやってみましたがそれ以前に理解が足りていないようでできませんでした

補足情報(/ツールのバージョンなど)

for分のd[i]の部分には読み出したファイルの最後まで繰り返すようにしたいのですがやり方がわかりません

DATA dはstructで作った構造体の変数だと思っているのですがちがうのかもしれません

初めてC言語でファイルを触るのでほとんど手探りの状態です

気になる質問をクリップする

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

y_waiwai

2019/12/16 09:46

提示のコードではどういう不具合があるんでしょうか。 詳しく説明してください
guest

回答1

0

ベストアンサー

回答用のコードは用意しましたが、その前に説明をご覧ください。

質問にあったエラーを要約しますと、(DATA型の)変数dが、ポインタ、配列、ベクトルのいずれでもないため、d[i]という表記はおかしい、ということです。例えば100人分のデータとしてDATA d[100];のように宣言すればi番目の要素、というものが考えられますが、今回は1人分しか宣言していません。

では、100人分宣言すればよいのか? 答えは違います。必要なのは最後の1人分だけですので、実は1人分で足ります。100人分宣言してもよいのですが、その場合は別の箇所を修正する必要が出てきます。

他の問題点を以下に列挙します。

  1. 点数は、「数学、英語」の順のはずだが、質問者さんの回答では逆になっている。
  2. 「ファイル名」は99文字以下だが、「絶対パス」が99文字以下とは書いていない。
  3. ファイル名に空白が含まれないとは書いていない。
  4. ファイル名、人名ともに99文字入力した場合にバッファオーバーフローを引き起こす。
  5. for文での読み取り終了条件がおかしい。
  6. 開いたファイルをfcloseを用いて閉じていない。

1-6をすべて一度に理解しなさい、というつもりはありませんが、英語のエラーメッセージを日本語に置き換える練習はしてください。ちなみに、Cコンパイラであれば通常、C2440のようにエラー番号を教えてくれるので、それをキーワードにして検索すれば、日本語で解説しているページが見つかります。

C

1#include <stdio.h> 2#include <stdlib.h> 3 4typedef struct data{ 5 int no; 6 char name[100]; 7 int math; 8 int eng; 9} DATA; 10 11int main() 12{ 13 FILE *fp; 14 char path[200]; 15 DATA d; 16 17 if(scanf("%199[^\n]%*[^\n]", path) < 1) path[0] = '\0'; 18 getchar(); 19 20 fp = fopen(path, "r"); 21 if(fp == NULL){ 22 printf("NG"); 23 return -1; 24 } 25 for(; fscanf(fp, "%d %s %d %d\n", &d.no, d.name, &d.math, &d.eng) == 4;); 26 printf("%s", d.name); 27 fclose(fp); 28 return 0; 29}

投稿2019/12/16 10:13

編集2019/12/16 22:36
majiponi

総合スコア1722

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

Aru-0

2019/12/16 10:41

DATA dで宣言した構造体のi列目だと思っているのですが如何せん構造体もファイルも扱ったのが最近なので勘違いしてるかもしれないです
yumetodo

2019/12/16 12:30

> DATA dで宣言した構造体のi列目だと思っているのですが これは間違いですよね。まずはそこを自分で調べてみてください。私達が回答したのではおそらく身につきません。
Aru-0

2019/12/16 12:53

散々調べているのですが見つけられないのか理解していないから正解が分からないのかで、どうしようも無くなったのでここに投稿しました せめてこれがなんなのか教えて頂けるとまた調べるためのボキャブラリーが増え、自己理解のために繋がるかと思います なのでヒントだけでもいいので助けていただけませんか?
yumetodo

2019/12/16 13:02

うーん、そもそもC言語の入門を間違えている気がしますね。 前橋和弥さんのC言語ポインタをおすすめしたいところです。 ヒントですが int i; iの型はintですよね? int j[3]; jの型はint[3]型ですよね? typedef struct { int foo } foo; foo k; kの型はfooですよね?
Aru-0

2019/12/16 13:09

typedef struct {略}DATAで構造体の中身を作ってDATA dでこれについての変数を宣言したのではないあのですか?
yumetodo

2019/12/16 13:53

そこまではあってます。そこまでは。
Aru-0

2019/12/16 14:05

for分の所の条件に入れるものが違うのが原因だと思っているのですがここには*fp!=EOD なのでしょうか 読み出したファイルを最後までループするようにしたいのでEODを使えばいいのかなとは思うんですがポインターなどに不慣れで特性がうろ覚えです
majiponi

2019/12/16 14:08

仕事が終わって帰宅したので正式な回答を書きます。30分お待ちください。
majiponi

2019/12/16 22:39

ごめんなさい、最後のループ条件、サンプルに誤りがありました。
Aru-0

2019/12/17 01:11

すいませんまだ纏まっていないので後に質問してもよろしいですか?
Aru-0

2019/12/17 02:15

まずif(scanf("%199[^\n]%*[^\n]", path) < 1) path[0] = '\0';についてお伺いしたいのですが"%199[^\n]%*[^\n]"の部分は書式指定子でファイル名の空白対策なのかなとは思うのですがなぜこのような書き方になるのかがわからないです。次にpath[0] = '\0';でpath0になぜ\0をいれるのか入れてなぜ問題ないのかを知りたいです。それとこの下にgetchar();が入る意味はなんでしょうか、次に最後のループ条件は==4で四つのデータが埋まるまで繰り返すものだと思っていたので、初めの一人分のデータを取得して終わってしまうのではないかと思いましたが、これでファイルの最後のデータまで取得されます。 ですがここで==4以外の数(==3など)を打ち込むと先頭の名前が表示されます、これはなぜなのでしょうか。
Aru-0

2019/12/17 02:15

お時間ありましたら申し訳ありませんがお答えいただければとてもありがたいです。
majiponi

2019/12/17 02:58

scanfの書式設定と、getcharについてはこちら https://marycore.jp/prog/c-lang/scanf-string-safely/ を、forの条件指定は、「一人ぶんのデータをすべて読み取れている間はループして、dを上書きせよ」というものです。最後の一人を読んだ後、ファイルの終わりに到達すると、読み取れるデータ数が0になるのでそこでループが終わります。そして読み取りに失敗した場合は上書きされないので、最後の一人のデータがdに残っていますので、それを表示します。
Aru-0

2019/12/17 03:05

本当に助かりました。ありがとうございます!!!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問