/* 構造体 2-3.c */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* 構造体(struct[=structure] 構造)は、幾つかのdataの集まりを一つの纏まりとして扱う
もので、struct 構造体名{変数1,変数2,,,}; の形でmain()の前に書いて定義する。例えば、
dataA1 dataB1 dataC1 dataD1
dataA2 dataB2 dataC2 dataD2
... ... ... ...
... ... ... ...
と続く様なdataの場合、[dataA dataB dataC dataD]を一纏まりとして扱うのが便利である。
この時、dataA, B, C, D を構造体のmember(構成要素)と呼ぶ。
*/
struct st_hw
{
char name[21];
float h;
float w;
};
main()
{
int i,j,n;
char dmy[101],fname[50];
struct st_hw hw[500],temp;
/* 定義した構造体をmain()で扱う際の名前(変数名)を宣言する。文末には当然 ; を付ける。
ここでは、配列として500確保するとともに、同じ構造を持つtempも宣言した(並べ替えに必要)。
構造体本体の名(ここではst_hw)は標識[tag]であり、main()で扱う時は変数名(ここではhw,temp)
を使う。*/
FILE *fin;
printf("* 身長と体重 *\n\nFile名を入力:");
gets(fname);
putchar('\n');
fin=fopen(fname,"r"); // 入力fileを開ける。
if (fin==NULL) {printf("File がありません!\n\nEnd\n"); exit(1);}
/* fileには次の様な形でdataが納まっているとする。nameに空白も可とすると、fscanfでは
読めない。そこで、空白も読める fgets[=file get string]を使う事にする。
name1
h1 w1
name2
h2 w2
.....
*/
i=0;
while (! feof(fin)) {
fgets(dmy,100,fin); dmy[strlen(dmy)-1]='\0';
/* fgetsは改行も文字として取り込むので、終端一つ前の改行文字を終端記号に置換する。*/
if (strlen(dmy)>20) dmy[20]='\0';
/* 入力文字列が指定した長さ以上の場合に切り詰める。いったんdmyで受ける理由。*/
strcpy(hw[i].name,dmy);
/* その後で、読み込んだ文字列を用意したnameに納めている。構造体の各構成要素を指定する
には、[構造体を扱う名前][.][構成要素名]とする。*/
fscanf(fin,"%f %f",&hw[i].h,&hw[i].w);
fgets(dmy,100,fin);
/* fscanfは改行を取り込まず、fgetsは改行を文字として取り込む。両方を混ぜて使うと読み
込みが乱れるので、fscanfの後に残った改行文字をdmyで取り込んでおく。fscanfの後にfgetsで
文字列を読もうとする場合には必要。*/
printf("%-20s %.1f %.1f\n",hw[i].name,hw[i].h,hw[i].w);
i++;
if (i%20==0) gets(dmy); // data数が多い時の表示待ち
}
fclose(fin); // 入力fileを閉じる。
n=i; // iで数えたdata数を nに代入。
//-----------------
printf("\n身長順に並べ替えます。(Enter Keyを押して下さい)\n");
for (i=0;i<n-1;i++) {
for (j=i+1;j<n;j++)
if (hw[i].h>hw[j].h)
{temp=hw[i]; hw[i]=hw[j]; hw[j]=temp;}
}
/* dataの一単位が複数の構成要素からなっている場合(名前、身長、体重の様に)、ある構成要素
を並べ替えれば他の構成要素も並べ替えねばならない。構造体を用いれば、一単位を一変数の様に
扱えるので上の様にすっきりと書ける。*/
for (i=0;i<n;i++) {
if (i%20==0) gets(dmy);
printf("%-20s %.1f %.1f\n",hw[i].name,hw[i].h,hw[i].w);
}
//-----並べ替えたものを表示-------------
printf("\n体重順に並べ替えます。(Enter Keyを押して下さい)\n");
for (i=0;i<n-1;i++) {
for (j=i+1;j<n;j++)
if (hw[i].w>hw[j].w)
{temp=hw[i]; hw[i]=hw[j]; hw[j]=temp;}
}
for (i=0;i<n;i++) {
if (i%20==0) gets(dmy);
printf("%-20s %.1f %.1f\n",hw[i].name,hw[i].h,hw[i].w);
}
//------------------
printf("\n名前順に並べ替えます。(Enter Keyを押して下さい)\n");
for (i=0;i<n-1;i++) {
for (j=i+1;j<n;j++)
if (strcmp(hw[i].name,hw[j].name)>0)
{temp=hw[i]; hw[i]=hw[j]; hw[j]=temp;}
}
/* strcmp[=string comparison, 文字列比較]は文字列の比較関数で、c=strcmp(a,b); の様に
書くと、cに関数値が入る。二つの文字列 a, bを先頭から一字ずつ比較対照して、aの方がalphabet
順で前にあれば(a<b)負の値、後にあれば(a>b)正の値を返す。0の場合、両者は同じ文字列(a=b)で
ある。上では、この関数値が正の時(即ち、bが小さい時)に交換している。*/
for (i=0;i<n;i++) {
if (i%20==0) gets(dmy);
printf("%-20s %.1f %.1f\n",hw[i].name,hw[i].h,hw[i].w);
}
//------------------
printf("\nEnd\n");
return 0;
}