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

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

詳細はこちら
C

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

Q&A

解決済

3回答

1672閲覧

ファイルの入出力が正しく行われない

katkey

総合スコア15

C

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

0グッド

0クリップ

投稿2020/12/14 22:13

編集2020/12/15 04:49

前提・実現したいこと

csvファイルに保存した学籍番号と、各人の15科目のスコアから、GPTとGPAを求めるプログラムを作成したいです。
前提として、構造体を使ってプログラムを書いていて、エラーは出ないのですが、結果が出力されません。
プログラム自体は単純なものだと思うのですが、構造体のポインタ処理がうまくできていないような気がします。
分かる方いたら回答をお願いします。
###csvファイル
xx268001 - B A B - A D A D D D - B B A
xx268002 S A A A A - - C D C S - D A -
xx268003 B A A B - B A B - A A A C A A
xx268004 A B A A D B B - A C A D - C D
xx268005 A - - A C S A C B A D C C C D
xx268006 A A A A B - A C B D D D B D A
xx268007 A B C A B A D D D D B D B A A
xx268008 A A A D B A B A A B S A A A D
xx268009 - C B A A A B D A - D B C A -
xx268010 - S B - A B - C A C A S B D A
xx268011 S A - - - B A A C B B A D C A
xx268012 C - B A B C B B C A C - A A A
xx268013 A - D A B A B D D B D - A B D
xx268014 - - C A D B B A A A D C - A A
xx268015 A A A - B - - A B A B A B A A
xx268016 B A A D A B B - - - B D - - C
xx268017 C A B D D - B D C D D - C A D
xx268018 S B A - A A - D A A C A C D A
xx268019 C C A - D D - A A C B C - C -
xx268020 A A A A A S - - A B - A - C B
xx268021 B C B - A - A A S B S A - A C
xx268022 D A - A - B D A C A - A B B B
xx268023 B D B C B - D D A B B D A A S
xx268024 C C S A A A S B A - C S S D D
xx268025 B S A C A B D A D S - B A B A
xx268026 A A - D C B A A S D A C B - -
xx268027 - B - A D A D A C - - B - D C
xx268028 D A B - A A C A A D B - D B B
xx268029 A D - D D B C S A - A A B C C
xx268030 A B D A D C B B - C A S C A A

該当のソースコード

c

1#include <stdio.h> 2#include <string.h> 3 4#define NUM_STUDENT 30 5#define MAX_CLASS 15 6#define MAX_ID_LENGTH 8 7 8int GPT[NUM_STUDENT]; 9float GPA[NUM_STUDENT]; 10 11typedef struct { 12 char *StudentID; 13 14 char *Grade; 15} student; 16 17void read_data(student *s, char *fname) { 18 int i, j; 19 char studentID[MAX_ID_LENGTH + 1]; 20 char grade[MAX_CLASS]; 21 FILE *fp = fopen(fname, "r"); 22 23 for (i = 0; i < NUM_STUDENT; i++) 24 { 25 fscanf(fp, "%[^,]", studentID); 26 for (j = 0; j < MAX_CLASS; j++) { 27 fscanf(fp, ",%c", &grade[j]); 28 } 29 fscanf(fp, "\n"); 30 31 s->StudentID=studentID; 32 33 for(j=0;j<MAX_CLASS;j++){ 34 s->Grade[j]=grade[j]; 35 GPT[i] += s->Grade[j]; 36 } 37 GPA[i] = (float)GPT[i]/4.0; 38 } 39 fclose(fp); 40} 41 42int main(int argc, char *argv[]) 43{ 44 int i; 45 student s[NUM_STUDENT]; 46 47 if (argc != 2) { 48 printf("Usage: %s ScoreDataFile(*.csv)\n", argv[0]); 49 return 1; 50 } 51 char *fname = argv[1]; 52 53 read_data(s, fname); 54 55 for (i = 0; i < NUM_STUDENT; i++) { 56 57 printf("%s,GPT:%d,GPA:%.2f\n", s[i].StudentID, GPT[i], GPA[i]); 58 } 59 60 return 0; 61}

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

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

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

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

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

tatsu99

2020/12/15 02:09

ファイルの内容は、どのようになってますか。
katkey

2020/12/15 04:29 編集

画像になりますが、追加したのでご確認ください。
katkey

2020/12/15 04:29

自分でも今気づいたのですが、csvファイルにはS~Dまでの文字、 または「ー」(その科目を履修していないことを示す、つまりその値を無視する)が格納されています。 そのため、プログラム内で一回読み込んだ文字を数字(4~1)に変換する必要があります。
dodox86

2020/12/15 04:31

CSVファイルに関して、画像が絶対ダメとは言いませんが、普通のテキスト形式で示した方がよいです。Excelやその他、表計算ソフトで表示すると加工される場合がありますし、テキストでないと閲覧者、回答者は試しづらいです。
katkey

2020/12/15 04:32

分かりました、修正します。
dodox86

2020/12/15 04:58

[2020/12/15 13:49]の質問編集を見て: 細かいこと(だけど重要)を書くと、これはCSVファイルではありませんね。CSVファイルとは名前の通り、データ項目がカンマ(',')で区切られているものを指します。貼り付けられた見た目、スペース(' ')で区切られていますが、提示されたコードではカンマを意識しているように思います。どちらが正しいのでしょうか。こういう場合、素のデータを提示しないと誤解を受けます。一応指摘しておきます。
katkey

2020/12/15 05:08

このCSVファイルはExcelとして与えられたものなのですが、Excelの変換機能を使ってテキストファイルに変換したところ、このような表示になりました。なので、これは素のデータとして与えています。
guest

回答3

0

とりあえず修正しました。
gradeの読み込みは%sでおこなっています。gradeが1文字の前提です。2文字以上の場合は、読み込みバッファが破壊され、正しい結果は保障されません。
gradeはSが4、Aが3、Bが2、Cが1、Dが0、先以外は0で計算しています。

C

1#include <stdio.h> 2#include <string.h> 3 4#define NUM_STUDENT 30 5#define MAX_CLASS 15 6#define MAX_ID_LENGTH 8 7 8int GPT[NUM_STUDENT]; 9float GPA[NUM_STUDENT]; 10 11typedef struct { 12 char StudentID[MAX_ID_LENGTH + 1]; 13 14 int Grade[MAX_CLASS]; 15} student; 16int convert_grade(char grade) 17{ 18 if (grade == 'S') return 4; 19 if (grade == 'A') return 3; 20 if (grade == 'B') return 2; 21 if (grade == 'C') return 1; 22 if (grade == 'D') return 0; 23 return 0; 24} 25void read_data(student * s, char *fname) 26{ 27 int i, j; 28 char studentID[MAX_ID_LENGTH + 1]; 29 char grade[MAX_CLASS+1]; 30 student *ws = s; 31 FILE *fp = fopen(fname, "r"); 32 for (i = 0; i < NUM_STUDENT; i++,ws++) { 33 fscanf(fp,"%s",studentID); 34 for (j = 0; j < MAX_CLASS; j++) { 35 fscanf(fp, "%s", &grade[j]); 36 } 37 fscanf(fp, "%*%c"); //改行の読み捨て 38 strcpy(ws->StudentID,studentID); 39 GPT[i] = 0; 40 for (j = 0; j < MAX_CLASS; j++) { 41 ws->Grade[j] = convert_grade(grade[j]); 42 GPT[i] += ws->Grade[j]; 43 } 44 GPA[i] = (float) GPT[i] / 4.0; 45 } 46 fclose(fp); 47} 48 49int main(int argc, char *argv[]) 50{ 51 int i; 52 student s[NUM_STUDENT]; 53 54 if (argc != 2) { 55 printf("Usage: %s ScoreDataFile(*.csv)\n", argv[0]); 56 return 1; 57 } 58 char *fname = argv[1]; 59 60 read_data(s, fname); 61 62 for (i = 0; i < NUM_STUDENT; i++) { 63 64 printf("%s,GPT:%d,GPA:%.2f\n", s[i].StudentID, GPT[i], GPA[i]); 65 } 66 67 return 0; 68} 69

実行結果
xx268001,GPT:20,GPA:5.00
xx268002,GPT:25,GPA:6.25
xx268003,GPT:33,GPA:8.25
xx268004,GPT:23,GPA:5.75
xx268005,GPT:23,GPA:5.75
xx268006,GPT:25,GPA:6.25
xx268007,GPT:24,GPA:6.00
xx268008,GPT:37,GPA:9.25
xx268009,GPT:23,GPA:5.75
xx268010,GPT:28,GPA:7.00
xx268011,GPT:27,GPA:6.75
xx268012,GPT:27,GPA:6.75
xx268013,GPT:20,GPA:5.00
xx268014,GPT:24,GPA:6.00
xx268015,GPT:32,GPA:8.00
xx268016,GPT:18,GPA:4.50
xx268017,GPT:13,GPA:3.25
xx268018,GPT:29,GPA:7.25
xx268019,GPT:16,GPA:4.00
xx268020,GPT:30,GPA:7.50
xx268021,GPT:31,GPA:7.75
xx268022,GPT:24,GPA:6.00
xx268023,GPT:24,GPA:6.00
xx268024,GPT:33,GPA:8.25
xx268025,GPT:32,GPA:8.00
xx268026,GPT:25,GPA:6.25
xx268027,GPT:15,GPA:3.75
xx268028,GPT:24,GPA:6.00
xx268029,GPT:23,GPA:5.75
xx268030,GPT:28,GPA:7.00

投稿2020/12/15 08:54

tatsu99

総合スコア5493

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

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

katkey

2020/12/21 06:05

これってwsを新しく構造体のポインタとして定義しているのは何か意図があるのですか?
tatsu99

2020/12/21 06:48

パラメータのsを直接更新したくなかった為です。 今回は直接更新しても、問題ありませんが、処理の途中で、パラメータの最初の値が 必要になるようなケースもあります。その為、パラメータは直接更新しないように(個人的には) しています。
katkey

2020/12/21 10:11

分かりました、ありがとうございます。
guest

0

ベストアンサー

まず構造体の作りがダメです。
char型のポインタでは、アドレス値しか持てません。
しかもその代入しているアドレス値がread_data関数内のローカル変数なので常に同じアドレス値が格納されます。
以下のように実体を持つように構造体を修正しましょう。

c

1typedef struct { 2 char StudentID[MAX_ID_LENGTH + 1]; 3 char Grade[MAX_CLASS]; 4} student;

あとはファイルから読み込んだ値をこの構造体にコピーするように実装すればOKです。
そこの部分は書かないので自分で考えてみてください。

ちなみにGradeですが、質問内容には「15科目のスコア」と書かれています。
15バイトの文字列で良いのですか?
int型などの数値型で15個の配列が必要ではないですか?
scanfで%cで読み込んでいますが正しいですか?
スコアは0~9の値ですか?

投稿2020/12/15 02:25

ttyp03

総合スコア17000

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

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

katkey

2020/12/15 04:23

自分でも今気づいたのですが、csvファイルにはS~Dまでの文字、 または「ー」(その科目を履修していないことを示す、つまりその値を無視する)が格納されています。 そのため、プログラム内で一回読み込んだ文字を数字(4~1)に変換する必要があります。
guest

0

char studentID[MAX_ID_LENGTH + 1];
s->StudentID=studentID;

ローカル変数のアドレスを保存していますが、ローカル変数が有効なのはどのくらいの期間だと理解されてます?
きっと、全学生の情報でほぼ同じアドレスを保持しているので、データが無事だったとしても皆同じ結果になるかと思われます。
アドレス自体は有意なアドレスですが、そこに格納されているデータについては保証されませんね。
その為のローカル変数です。

投稿2020/12/14 22:27

setoppu

総合スコア311

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

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

katkey

2020/12/14 22:50

学生ごとに保存するアドレスを分ける方法はありますか?
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問