質問をすることでしか得られない、回答やアドバイスがある。

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

新規登録して質問してみよう
ただいま回答率
85.35%
C

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

Q&A

解決済

4回答

3256閲覧

成績処理プログラムの平均点並び替え

yukatii

総合スコア5

C

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

0グッド

0クリップ

投稿2020/06/17 15:46

#作ろうとしてるプログラム
ファイルから何人かの名前と成績を読み取り、それらを構造体配列に格納した後、平均点を計算してソーティングを行う。最終的に平均点の高い順に名前が表示される。

うまくいかない点

ソーティングして順位を決定し、平均点を降順に並べるのはうまくいったが、名前の部分がソーティングされていないため、違う人の点数が当てはまることになる。(語彙力がなくて申し訳ないです。実行例をご覧ください)

ソースコード

※見出し判定されてしまうので文頭#は省略

include <stdio.h>
include <stdlib.h>
define NINZU 3 //入力するデータ人数
define TEN 5 //入力するデータ(点)の数

// 名前とそれ以降のデータ(点数)を格納する配列をメンバにもつ構造体
typedef struct str {
char name[50];
float x_data[TEN];
} data;

int main(void) {
FILE *fp;
char fname[] = "test.txt";
char line[256]; //1行の最大文字数は256字
char name[50];
float x1, x2, x3, x4, x5; //5つのデータ
int i,j,w,max;

struct str pos; float sort[NINZU]; //ソーティング用の配列 float gokei,heikin; data data[NINZU]; //読み込むファイルのデータの行数 //ファイルオープン動作 fp = fopen(fname, "r"); // ファイルを開く。失敗するとNULLを返す。 if(fp == NULL) { printf("%s ファイルが開けん!\n", fname); return -1; } //while開始 while(fgets(line, 256, fp) != NULL) { sscanf(line, "%s %f %f %f %f %f", name, &x1, &x2, &x3, &x4, &x5); //file内データ読み込み for(j = 0; j < sizeof(data[i].name) / sizeof(data[i].name[0]); j++) { data[i].name[j] = name[j]; //ここのfor文でtxtfile内の最初の文字列を構造体配列に代入 } float tmp[] = {x1, x2, x3, x4, x5}; for(j = 0; j < sizeof(data[i].x_data) / sizeof(data[i].x_data[0]); j++) { data[i].x_data[j] = tmp[j]; //ここのfor文でtxtfile内のデータ5つを構造体配列に代入 if(data[i].x_data[j] > 100 || data[i].x_data[j] < 0){ //点数に誤りがないかの例外処理 printf("エラー!点数が正しく入力されていません。0点以上100点以下で入力してください。\n"); return 0; } } //入力データの表示 printf("%s %.0f %.0f %.0f %.0f %.0f\n" ,data[i].name, data[i].x_data[0], data[i].x_data[1], data[i].x_data[2], data[i].x_data[3], data[i].x_data[4]); //合計平均の計算 for(j=0;j<5;j++){ gokei+=data[i].x_data[j]; } heikin=gokei/5; printf("合計=%.0f, 平均=%.1f\n", gokei, heikin); printf("\n"); sort[i]=heikin; //sorting用配列に平均結果を代入 gokei=0; //合計点の初期化 i++; } //while終了。 ループ一周で1行分の出力(i++で次の行へ) //ソーティング for(i=0; i<NINZU; i++){ max=i; for(j=i+1;j<3;j++) if(sort[j]>sort[max]) max=j; w=sort[i]; sort[i] = sort[max]; sort[max]=w; } //合計平均の表示 //printf("\n"); printf("------------------------------\n"); for(i=1;i<=NINZU;i++){ printf("%d. %s %5.1f点\n",i,data[i-1].name,sort[i-1]); } fclose(fp); // ファイルを閉じる return 0;

}

###用いるテキストファイル"test.tex"の中身
yamada 22 44 66 77 36
sato 33 55 77 99 54
honda 23 23 34 34 13

#実行結果
yamada 22 44 66 77 36
合計=245, 平均=49.0

sato 55 77 99 54
合計=318, 平均=63.6

honda 23 23 34 34 13
合計=127, 平均=25.4


  1. yamada 63.6点
  2. sato 49.0点
  3. honda 25.0点

このように、平均点とその点数の人が一致しません。

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

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

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

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

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

ohys

2020/06/17 16:00

> ※見出し判定されてしまうので文頭#は省略 ではなく、「`(バッククォート)」を使って ``` コード ``` と書いてください。断然読みやすくなります
guest

回答4

0

フルスクラッチで書き直してみました。C89でコンパイルできます。思ったより短くならなくてくやしいです。

C

1#include <stdio.h> 2#include <stdlib.h> 3 4#define PEOPLE 3 /* 入力する人数 */ 5#define SCORES 5 /* 入力するデータ(点)の数 */ 6 7typedef struct tag_DATA { 8 char name[50]; 9 float score[SCORES]; 10 float avg; 11} DATA; 12 13DATA data[PEOPLE]; /* データ本体。でかい。 */ 14DATA *pdata[PEOPLE]; /* データのポインタ。小さいのでソートしやすい。 */ 15const char *filename = "test.txt"; 16 17/* ソート用の比較関数 */ 18int cmp(const void *a, const void *b) { 19 float d = ((DATA*)b)->avg - ((DATA*)a)->avg; 20 if (d > 0.0f) return 1; 21 if (d < 0.0f) return -1; 22 return 0; 23} 24 25int main() { 26 /* ファイルを読む */ 27 { 28 FILE *fp; 29 int i, j; 30 31 /* ファイルオープン */ 32 fp = fopen(filename, "r"); 33 if (fp == NULL) { 34 printf("%s ファイルが開けん!\n", filename); 35 return -1; 36 } 37 38 /* 読み込み */ 39 for (i = 0; i < PEOPLE; ++i) { 40 fscanf(fp, "%s", data[i].name); 41 for (j = 0; j < SCORES; ++j) { 42 fscanf(fp, "%f", &data[i].score[j]); 43 } 44 } 45 46 /* ファイルクローズ */ 47 fclose(fp); 48 } 49 50 /* データの検査、入力データの表示、合計平均の計算 */ 51 { 52 int i, j; 53 float sum; 54 for (i = 0; i < PEOPLE; ++i) { 55 printf("%s", data[i].name); 56 sum = 0.0f; 57 for (j = 0; j < SCORES; ++j) { 58 printf(" %.0f", data[i].score[j]); 59 sum += data[i].score[j]; 60 if (data[i].score[j] > 100.0f || data[i].score[j] < 0.0f) { 61 printf("\nエラー!点数が正しく入力されていません。" 62 "0点以上100点以下で入力してください。\n"); 63 return -1; 64 } 65 } 66 data[i].avg = sum / SCORES; 67 printf("\n合計=%.0f, 平均=%.1f\n\n", sum, data[i].avg); 68 } 69 } 70 71 /* ソーティング */ 72 { 73 int i; 74 /* pdataの初期化 */ 75 for (i = 0; i < PEOPLE; ++i) 76 pdata[i] = &data[i]; 77 /* クイックソート */ 78 qsort(data, PEOPLE, sizeof(DATA), cmp); 79 } 80 81 /* 合計平均の表示 */ 82 { 83 int i; 84 printf("-------------------------\n"); 85 for (i = 0; i < PEOPLE; ++i) { 86 printf("%d. %s %5.1f点\n", i + 1, data[i].name, data[i].avg); 87 } 88 } 89} 90

投稿2020/06/18 07:21

anndonut

総合スコア667

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

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

0

ソートを自前で書くのが目的でないなら:

C

1#include <stdio.h> 2#include <stdlib.h> 3 4#define NINZU 3 //入力するデータ人数 5#define TEN 5 //入力するデータ(点)の数 6// 名前とそれ以降のデータ(点数)を格納する配列をメンバにもつ構造体 7 8typedef struct str { 9 char name[50]; 10 float x_data[TEN]; 11} data; 12 13float mean(const float data[], int n) { 14 float sum = 0.0f; 15 int i; 16 for ( i = 0; i < n; ++i ) { 17 sum += data[i]; 18 } 19 return sum / n; 20} 21 22int data_compare(const void* x, const void* y) { 23 float diff = mean(((const data*)x)->x_data, TEN) - mean(((const data*)y)->x_data, TEN); 24 if ( diff < 0 ) return -1; 25 if ( diff > 0 ) return 1; 26 return 0; 27} 28 29int main(void) { 30 // ファイルからの入力はばっさり省略 31 data data[NINZU] = { 32 { "yamada", 22, 44, 66, 77, 36 }, 33 { "sato", 33, 55, 77, 99, 54 }, 34 { "honda", 23, 23, 34, 34, 13 }, 35 }; 36 int i; 37 38 printf("before sort:\n"); 39 for ( i = 0; i < NINZU; ++i ) { 40 printf("%s %.0f %.0f %.0f %.0f %.0f (%.0f)\n", data[i].name, 41 data[i].x_data[0], data[i].x_data[1], 42 data[i].x_data[2], data[i].x_data[3], 43 data[i].x_data[4], mean(data[i].x_data, TEN)); 44 } 45 printf("\n"); 46 47 qsort(data, NINZU, sizeof(struct str), data_compare); 48 49 printf("after sort:\n"); 50 for (i = 0; i < NINZU; ++i) { 51 printf("%s %.0f %.0f %.0f %.0f %.0f (%.0f)\n", data[i].name, 52 data[i].x_data[0], data[i].x_data[1], 53 data[i].x_data[2], data[i].x_data[3], 54 data[i].x_data[4], mean(data[i].x_data, TEN)); 55 } 56 57 return 0; 58}

投稿2020/06/18 01:57

episteme

総合スコア16612

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

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

0

構造体の中に平均を入れ、ソーティング用の配列を構造体へのポインタにすると
ソートが簡単になります。

C

1#include <stdio.h> 2 3#define NINZU 3 // 入力するデータ人数 4#define TEN 5 // 入力するデータ(点)の数 5 6typedef struct { // 構造体 7 char name[50]; // 名前 8 float x_data[TEN]; // データ(変数) 9 float heikin; // 平均 10} Data; 11 12int main(void) 13{ 14 char fname[] = "test.txt"; 15 FILE *fp = fopen(fname, "r"); // ファイルを開く 16 if (fp == NULL) { 17 printf("%s ファイルが開けん!\n", fname); 18 return -1; 19 } 20 21 Data data[NINZU]; // 読み込むファイルのデータ 22 Data *sort[NINZU]; // ソーティング用の配列 23 char line[256]; // 1行の最大文字数は256字 24 int n = 0; // 読み込んだ人数 25 for (; n < NINZU && fgets(line, 256, fp) != NULL; n++) { 26 Data *p = data + n; 27 sort[n] = p; 28 sscanf(line, "%s%f%f%f%f%f", p->name, 29 p->x_data, p->x_data+1, p->x_data+2, p->x_data+3, p->x_data+4); 30 31 float gokei = 0; 32 for (int i = 0; i < TEN; i++) { 33 if (p->x_data[i] > 100 || p->x_data[i] < 0) { // 点数に誤り 34 puts("エラー!点数が正しく入力されていません。" 35 "0点以上100点以下で入力してください。"); 36 return 1; 37 } 38 gokei += p->x_data[i]; // 合計の計算 39 } 40 p->heikin = gokei / TEN; // 平均の計算 41 42 printf("%s %.0f %.0f %.0f %.0f %.0f\n" "合計=%.0f, 平均=%.1f\n\n", 43 p->name, p->x_data[0], p->x_data[1], p->x_data[2], 44 p->x_data[3], p->x_data[4], gokei, p->heikin); 45 } // for終了。 46 fclose(fp); // ファイルを閉じる 47 48 for (int i = 0; i < n; i++) { // ソートする 49 int max = i; 50 for (int j = i + 1; j < n; j++) 51 if (sort[j]->heikin > sort[max]->heikin) max = j; 52 Data *p = sort[i]; sort[i] = sort[max]; sort[max] = p; 53 } 54 55 puts("------------------------------"); // 名前と平均の表示 56 for (int i = 0; i < n; i++) 57 printf("%d. %-10s %5.1f点\n", i+1, sort[i]->name, sort[i]->heikin); 58 return 0; 59}

投稿2020/06/18 00:54

kazuma-s

総合スコア8224

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

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

0

ベストアンサー

  • gokei0初期化していないため不定値となっており、一人目の平均値が正しく計算されていません。
  • ファイルから読み込んだデータ数がNINZU未満の場合の考慮がされていません。

ソーティングして順位を決定し、平均点を降順に並べるのはうまくいったが、名前の部分がソーティングされていないため、違う人の点数が当てはまることになる。

原因を理解されているのですから、あとはそれをコードにすればよいだけでは…

diff

1+ int data_count = i; // ソート・表示のため読めたデータ数を保存しておく 2 //ソーティング 3- for (i = 0; i < NINZU; i++) { 4+ for (i = 0; i < data_count; i++) { 5 max = i; 6- for (j = i + 1; j < 3; j++) 7+ for (j = i + 1; j < data_count; j++) 8 if (sort[j] > sort[max]) max = j; 9 w = sort[i]; sort[i] = sort[max]; sort[max] = w; 10+ struct str tmp = data[i]; data[i] = data[max]; data[max] = tmp; 11 } 12 13 //合計平均の表示 14 printf("------------------------------\n"); 15- for (i = 1; i <= NINZU; i++) { 16+ for (i = 1; i <= data_count; i++) { 17 printf("%d. %s %5.1f点\n", i, data[i - 1].name, sort[i - 1]); 18 }

  • i0初期化していないため不定値となっており、ファイルから読み取った値がdata[0]data[NINZU-1]に格納されることが保証されません。

投稿2020/06/17 16:27

編集2020/06/18 01:46
SHOMI

総合スコア4079

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

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

yukatii

2020/06/18 01:03

回答ありがとうございます。 コードを変更したところ、順位の出力が 1. sato 63.6点 2. sato 49.0点 3. honda 25.4点 というようになってしまいます。 あと、 struct str tmp = data[i]; data[i] = data[max]; data[max] = tmp; の部分ではどのような処理をしているのでしょうか?
SHOMI

2020/06/18 01:58

>1. sato 63.6点 >2. sato 49.0点 >3. honda 25.4点 >というようになってしまいます。 そうはなりませんが… 質問に貼られているコードは省略なしの実際に動かしているコードですか? >struct str tmp = data[i]; data[i] = data[max]; data[max] = tmp; >の部分ではどのような処理をしているのでしょうか? w = sort[i]; sort[i] = sort[max]; sort[max] = w; と同様にdata[i]とdata[max]の内容を入れ替えているだけです。
yukatii

2020/06/19 15:27

解決しました。ありがとうございました!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問