资源描述
第十章 C語言Structure的功能
假設我們有一組學生的資料,包含學生的學號、姓名和體重,我們要如何表示這種資料呢?對很多電腦語言而言,我們必須要有三個陣列。這三個陣列分別表示學生的學號,姓名和體重。舉例而言,假如我們有五位學生,他們的資料如表10-1:
學號
姓名
體重
109
John
79.1
201
Mary
60.3
159
Peter
81.4
163
Kelly
76.6
200
Gloria
62.3
表10-1
我們就需要三個陣列,如表10-2所示:
學號陣列
姓名陣列
體重陣列
109
John
79.1
201
Mary
60.3
159
Peter
81.4
163
Kelly
76.6
200
Gloria
62.3
表10-2
麻煩的是:這三個陣列是互有關聯的。如果我們要將學生的資料按照學號的大小排列,學號陣列當然會改變,但是我們必須跟著同時改變姓名、陣列和體重陣列。改過以後的三個陣列如表10-3。
學號陣列
姓名陣列
體重陣列
109
John
79.1
159
Peter
81.4
163
Kelly
76.6
200
Gloria
62.3
201
Mary
60.3
表10-3
所以,我們只好承認這是一件很複雜的事情。可是,在C語言中,我們有一個簡單的辦法,我們可以利用一種叫做structure的功能,一下子就解決了這個問題。
Structure使我們可以宣告學生的資料有三個欄位:學號、姓名、體重。學號和體重都用整數來代表,姓名用文字來表示,所以我們可以作以下的宣告。
struct student {
int idnum;
char name[20];
float weight;
}
從以上的宣告看來,學生的姓名最長不能超過20個英文字。
一旦對下定義,我們就宣告一個陣列有的結構,這個陣列當然也要有一個名字,我們不妨將它叫做,內容有如表10-1所示。假設我們要找第個的資料,我們只要找即可。如果我們要找第個學生的學號,我們就要指定,他的姓名是,而他的體重則是。有了以後,我們可以根據其中任何一個欄位排列。假設我們用學號排列,就可以得到以下的,如表10-4
學號
姓名
體重
109
John
79.1
159
Peter
81.4
163
Kelly
76.6
200
Gloria
62.3
201
Mary
60.3
表10-4
如果用體重來排列,我們會得到如表10-5所示的資料。
學號
姓名
體重
201
Mary
60.3
200
Gloria
62.3
163
Kelly
76.6
109
John
79.1
159
Peter
81.4
表10-5
至於如何會有資料的?當然是靠讀入的,我們通常應該宣告一個文字檔,用讀檔案的方法可以將資料讀到去。
例題10-1 讀入學生資料檔,根據學號將學生資料排列,並將結果輸出至另一檔案
要使用structure來表示學生資料,我們必需在主程式的外面先註明,所以我們會在主程式的前面,有以下的指令:
struct studentdata {
int idnum;
char name[20];
float weight;
}
主程式的流程圖如圖10-1。
圖10-1
至於排序的副程式,它的流程圖如圖10-2所示。
圖10-2
當然,我們還要有一個輸出結果至文字檔的副程式,這個副程式非常簡單,我們就不再討論它的流程圖了。
以下是這個程式。
程式 10-1
#include <stdio.h>
#define MAX_ARRAY_SIZE 256
#define STUDENT_DATA_FILE_NAME "student.txt"
#define OUTPUT_FILE_NAME "student_output.txt"
struct student
{
int idnum;
char name[20];
float weight;
};
int read_all_student_data(struct student A[MAX_ARRAY_SIZE], FILE *fp);
void output_all_student_data(FILE* output_data_fp, struct student A[MAX_ARRAY_SIZE], int N);
void sort_student_data(struct student A[MAX_ARRAY_SIZE], int N);
int FMIN_student_data(struct student A[MAX_ARRAY_SIZE], int i, int N);
void SWAP_student_data(struct student A[MAX_ARRAY_SIZE], int i, int j);
void main(void)
{
FILE *student_data_fp;
FILE *output_data_fp;
struct student sdata[MAX_ARRAY_SIZE];
int num_of_student;
int i;
student_data_fp = fopen(STUDENT_DATA_FILE_NAME, "r");
output_data_fp = fopen(OUTPUT_FILE_NAME, "w");
/* Read the student data from file to array */
if( student_data_fp != NULL )
{
num_of_student = read_all_student_data(sdata, student_data_fp);
fclose(student_data_fp);
if(num_of_student==0)
{
printf("There is no student data in the input file.");
}
else
{
output_all_student_data(output_data_fp,sdata, num_of_student);
/* Sort student data */
fprintf(output_data_fp,"Start sorting student data.\n");
sort_student_data(sdata, num_of_student);
/* Display sorted student data */
fprintf(output_data_fp,"Sorted student data.\n");
output_all_student_data(output_data_fp,sdata, num_of_student);
}
}
else
{
printf("Student data file doesn't exist.\n");
}
fclose(output_data_fp);
/* Program ends here */
}
int read_all_student_data(struct student A[MAX_ARRAY_SIZE], FILE *fp)
{
int i;
i = 0;
while(i < MAX_ARRAY_SIZE)
{
if( !feof(fp) )
{
fscanf(fp,"%d %s %f", &A[i+1].idnum, A[i+1].name, &A[i+1].weight);
if(A[i+1].idnum!=0)
{
i++;
}
}
else
{
return i;
}
}
return i;
}
void output_all_student_data(FILE* output_data_fp, struct student A[MAX_ARRAY_SIZE], int N)
{
int i;
fprintf(output_data_fp,"ID\t\tName\t\tWeight\n");
for(i = 1; i <= N; i++)
{
fprintf(output_data_fp,"%d\t\t%s\t\t%.1f\n", A[i].idnum, A[i].name, A[i].weight);
}
}
void sort_student_data(struct student A[MAX_ARRAY_SIZE], int N)
{
int i;
int j;
for( i = 1; i <= N; i++ )
{
j = FMIN_student_data(A, i, N);
SWAP_student_data(A, i, j);
}
}
void SWAP_student_data(struct student A[MAX_ARRAY_SIZE], int i, int j)
{
struct student tmp_var;
tmp_var = A[i];
A[i] = A[j];
A[j] = tmp_var;
}
int FMIN_student_data(struct student A[MAX_ARRAY_SIZE], int i, int N)
{
int MIN;
int k;
int j;
k = i;
j = k;
MIN = A[j].idnum;
while( k <= N )
{
if(A[k].idnum < MIN)
{
j = k;
MIN = A[j].idnum;
}
k++;
}
return j;
}
執行範例
ID Name Weight
109 John 79.1
201 Mary 60.3
159 Peter 81.4
163 Kelly 76.6
200 Gloria 62.3
Start sorting student data.
Sorted student data.
ID Name Weight
109 John 79.1
159 Peter 81.4
163 Kelly 76.6
200 Gloria 62.3
201 Mary 60.3
解釋
[資料檔]
資料檔的格式如下:
109 John 79.1
201 Mary 60.3
159 Peter 81.4
163 Kelly 76.6
200 Gloria 62.3
資料檔中,每一行儲存一個學生的資料。每個學生的資料(ID, Name, Weigh)以一個空白(space)當作分隔。
[主程式]
1. 當要存取檔案時,我們需要使用到標準函式庫,在程式的一開始加入#include <stdio.h>。
2. struct student sdata[MAX_ARRAY_SIZE];
這個指令宣告sdata是一個student structure,而student structure的定義在前面有如下的定義:
struct student
{
int idnum;
char name[20];
float weight;
};
3. 讀檔時需要先做打開檔案的動作,因此我們呼叫fopen來打開檔案。而我們所開啟的檔案是student.txt。
4. num_of_student = read_all_student_data(sdata, student_data_fp);
這個指令不僅將檔案中的資料讀入了sdata,也同時算出了一共有多少個學生。學生數目就是num_of_student,也是read_all_student_data副程式所傳回的值。若num_of_student的值為0,則表示檔案中沒有任何一筆學生資料,則印出檔案為空檔案的訊息後就結束程式,不為0則繼續執行程式。
5. 以後我們呼叫另一個副程式,將陣列中的資料依學號做排序。
6. 將排序好的學生資料陣列輸出至檔案student_output.txt中。如果輸出到螢幕上當然也可以,但是如果要再複製結果貼上word檔案,會產生不對齊的問題,現在我們輸出到文字檔案中,再貼到word檔案,就不會有不對齊的問題。
[副程式]
int read_all_student_data(struct student A[MAX_ARRAY_SIZE], FILE *fp);
將打開好的檔案指標傳入,此副程式則會將存在裡面的學生資料,一筆一筆讀至陣列中,而由於我們習慣索引值從1開始使用,所以將讀入的資料存入第i+1個陣列。由於檔案是可能不含任何學生資料的空檔案,而學生的學號的值必定不會是0,因此我們以if(A[i+1].idnum!=0)
來判斷是否已經沒有學生資料,若為0,則表示檔案中讀不到任何學生資料,回傳i值後結束副程式。
void output_all_student_data(struct student A[MAX_ARRAY_SIZE], int N);
1. 將學生資料陣列的資料(學號(id)、姓名(name)、體重(weight)),及裡面的資料的數目(N)輸出至檔案student_output.txt中。
2. fprintf(output_data_fp,"%d\t\t%s\t\t%.1f\n", A[i].idnum, A[i].name, A[i].weight);
這個指令的用意是在輸出學生學號、姓名與體重的資料到檔案中,需要注意的是”\t”個指令,由於每個學生的姓名長度都不相同,而”\t”就相當於我們在打字的過程中,按下了鍵盤上的Tab鍵。當按下Tab鍵後,畫面上不單單只是多出一段空白,而且會自動的進行上下對齊,使得每一筆資料看起來都是對齊的。也因此,當我們在輸出時使用”\t”這個指令,是為了讓每一筆學生資料在輸出時能夠自動對齊。而%.1f的指令,則是因為若不做任何指定的話,%f將會印出小數點後五個位數,但我們的資料只有使用到小數點後1位,因此我們使用%.1f來控制輸出的浮點數格式,使其僅印到小數點後1位的部份。
3. 在此A[i].name前不用加&,這是因為name宣告為一個陣列。
4. 注意return有跳出副程式的功能,一旦程式執行到return,將會結束副程式。
void sort_student_data(struct student A[MAX_ARRAY_SIZE], int N);
根據輸入的學生資料及長度,依學號來做排序。排序的方法與之前相同,只是之前是根據數字大小來做排序,而我們這次則是用學號來對整個學生資料陣列來做排序。
int FMIN_student_data(struct student A[MAX_ARRAY_SIZE], int i, int N);
在學生資料陣列的第個到最後一筆學生資料中找出學號最小的那一筆,並回傳它在陣列中的所在位置。
void SWAP_student_data(struct student A[MAX_ARRAY_SIZE], int i, int j);
將學生資料陣列第與個位置的學生資料互換。
例題10-2 依據學號找出學生資料
假設我們有以下的資料,
學號
姓名
體重
9301
John
65.2
9302
Tom
47.3
9310
Peter
70.5
9303
Mary
67.1
9311
Gloria
42.6
9308
George
70.8
而我們要找學號為9310的資料,我們找出的就是"9310 Peter 70.5"。
這個程式的主程式如圖10-3
圖10-3
Search副程式如10-4所示:
圖10-4
以下是程式
程式 10-2
#include <stdio.h>
#define MAX_ARRAY_SIZE 256
#define STUDENT_DATA_FILE_NAME "student.txt"
struct student
{
int idnum;
char name[20];
float weight;
};
int read_all_student_data(struct student A[MAX_ARRAY_SIZE], FILE *fp);
void display_student_data(struct student x[MAX_ARRAY_SIZE],int i);
void display_all_student_data(struct student A[MAX_ARRAY_SIZE], int N);
void search(struct student A[MAX_ARRAY_SIZE], int target_id_num, int N);
void main(void)
{
FILE *student_data_fp;
struct student sdata[MAX_ARRAY_SIZE];
int num_of_student;
int i;
int target_id_num;
printf("Please enter the ID for searching the student: ");
scanf("%d", &target_id_num);
student_data_fp = fopen(STUDENT_DATA_FILE_NAME, "r");
/* Read the student data from file to array */
if( student_data_fp != NULL )
{
num_of_student = read_all_student_data(sdata, student_data_fp);
fclose(student_data_fp);
if(num_of_student==0)
{
printf("There is no student data in the input file.");
}
else
{
display_all_student_data(sdata, num_of_student);
search(sdata, target_id_num, num_of_student);
}
}
else
{
printf("Student data file doesn't exist.\n");
}
/* Program ends here */
}
int read_all_student_data(struct student A[MAX_ARRAY_SIZE], FILE *fp)
{
int i;
i = 0;
while(i < MAX_ARRAY_SIZE)
{
if( !feof(fp) )
{
fscanf(fp,"%d %s %f", &A[i+1].idnum, A[i+1].name, &A[i+1].weight);
if(A[i+1].idnum!=0)
{
i++;
}
}
else
{
return i;
}
}
return i;
}
void search(struct student A[MAX_ARRAY_SIZE], int target_id_num, int N)
{
int i;
int test = 0; /* 0:false, 1:ture */
for(i = 1; i <= N; i++)
{
if( A[i].idnum == target_id_num )
{
test = 1;
break;
}
}
if( test == 1 )
{
printf("\nData Found.\n");
display_student_data( A,i );
}
else
{
printf("Data Not Found.\n");
}
}
void display_student_data(struct student x[MAX_ARRAY_SIZE],int i)
{
printf("ID\t\tName\t\tWeight\n");
printf("%d\t\t%s\t\t%.1f\n", x[i].idnum, x[i].name, x[i].weight);
}
void display_all_student_data(struct student A[MAX_ARRAY_SIZE], int N)
{
int i;
printf("ID\t\tName\t\tWeight\n");
for(i = 1; i <= N; i++)
{
printf("%d\t\t%s\t\t%.1f\n", A[i].idnum, A[i].name, A[i].weight);
}
}
執行範例
Please enter the ID for searching the student: 159
ID Name Weight
201 Mary 60.4
159 Peter 81.2
163 Kelly 76.6
200 Gloria 62.8
Data Found.
ID Name Weight
159 Peter 81.2
解釋
[主程式]
1. 首先打開學生資料檔案然後呼叫副程式read_all_student_data將資料讀入學生資料陣列中。
2. 讀入所要尋找的學生學號至變數target中。
3. 呼叫副程式search找出學生資料陣列中學號為target的所在位置。
4. 輸出找到的學生資料。如未找到,則顯示學生資料不存在。
5. 因為輸出有關找到或沒有找到,我們僅僅輸出結果到螢幕上。
[副程式]
int read_all_student_data(struct student A[MAX_ARRAY_SIZE], FILE *fp);
同範例10-1,將打開好的檔案指標傳入,此副程式則會將存在裡面的學生資料,一筆一筆讀至陣列中。注意,一旦return,就等於結束副程式。
void display_all_student_data(struct student A[MAX_ARRAY_SIZE], int N);
將所有學生資料陣列的資料(學號(id)、姓名(name)、體重(weight)),及裡面的資料的數目(N)輸出至螢幕上。
void display_student_data(struct student x[MAX_ARRAY_SIZE],int i);
將第i筆學生的資料輸出至螢幕上。
void search(struct student A[MAX_ARRAY_SIZE], int target_id_num, int N);
從學生資料陣列的第1個位置開始檢查,若學號與所要找尋的相符,即列印出該筆學生資料。若搜尋完學生資料陣列而無相符的資料時,則顯示無此資料。
例題10-3 求學生體重的平均值
例題10-2中學生的體重平均值是(79.1+60.3+81.4+76.6+62.3)/6=71.9。
這個程式和例題10-3的主程式非常相似,我們就略去它的流程圖。
副程式的流程圖如圖10-5
圖10-5
以下是程式.。
程式 10-3
#include <stdio.h>
#define MAX_ARRAY_SIZE 256
#define STUDENT_DATA_FILE_NAME "student.txt"
struct student
{
int idnum;
char name[20];
float weight;
};
int read_all_student_data(struct student A[MAX_ARRAY_SIZE], FILE *fp);
void display_all_student_data(struct student A[MAX_ARRAY_SIZE], int N);
void ave(struct student A[MAX_ARRAY_SIZE], int N);
void main(void)
{
FILE *student_data_fp;
struct student sdata[MAX_ARRAY_SIZE];
int num_of_student;
int i;
student_data_fp = fopen(STUDENT_DATA_FILE_NAME, "r");
/* Read the student data from file to array */
if( student_data_fp != NULL )
{
num_of_student = read_all_student_data(sdata, student_data_fp);
fclose(student_data_fp);
if(num_of_student==0)
{
printf("There is no student data in the input file.");
}
else
{
display_all_student_data(sdata, num_of_student);
ave(sdata, num_of_student);
}
}
else
{
printf("Student data file doesn't exist.\n");
}
/* Program ends here */
}
int read_all_student_data(struct student A[MAX_ARRAY_SIZE], FILE *fp)
{
int i;
i = 0;
while(i < MAX_ARRAY_SIZE)
{
if( !feof(fp) )
{
fscanf(fp,"%d %s %f", &A[i+1].idnum, A[i+1].name, &A[i+1].weight);
if(A[i+1].idnum!=0)
{
i++;
}
}
else
{
return i;
}
}
return i;
}
void ave(struct student A[MAX_ARRAY_SIZE], int N)
{
int i;
float x;
float ave;
float sum;
for(sum = 0, i = 1; i <= N; i++)
{
x = A[i].weight;
sum = sum + x;
}
ave = sum / N;
printf("The average weight is %.1f\n", ave);
}
void display_all_student_data(struct student A[MAX_ARRAY_SIZE], int N)
{
int i;
printf("ID\t\tName\t\tWeight\n");
for(i = 1; i <= N; i++)
{
printf("%d\t\t%s\t\t%.1f\n", A[i].idnum, A[i].name, A[i].weight);
}
}
執行範例
ID Name Weight
109 John 79.1
201 Mary 60.3
159 Peter 81.4
163 Kelly 76.6
200 Gloria 62.3
The average weight is 71.9
解釋
[主程式]
1. 首先打開學生資料檔案然後呼叫副程式將資料讀入學生資料陣列中。
2. 呼叫副程式算出學生資料陣列中的平均體重,算出結果後列印至螢幕上。
[副程式]
int read_all_student_data(struct student A[MAX_ARRAY_SIZE], FILE *fp);
void display_all_student_data(struct student A[MAX_ARRAY_SIZE], int N);
請參閱程式10-2的解釋。
void ave(struct student A[MAX_ARRAY_SIZE], int N);
從學生資料陣列的每一筆資料中,將體重取出存放至一臨時變數,之後將加總到變數中。全部做完後,將除以學生資料的筆數,即可以得到學生資料的平均體重。
例題10-4 利用structure新增資料
假設我們仍然利用以上幾個例子中所定義的structure,而要加入一筆學生資料,我們必需先查一下這位學生的學號是否已經存在。如果已經存在,就不能加入。如果存在,就將新增的資料寫入原來的檔案之中。
我們假設原來的資料存在一個叫做student.txt的文字檔案中,新增的資料要放入這個檔案的末端,而新資料是由鍵盤輸入的。
我們的主程式必需要有兩個陣列,兩個都是的資料結構,其中一個addedstudent是為了存放所新增學生的資料,另一個sdata為了存放原來學生的資料。
主程式所呼叫的副程式,叫做,的功能是檢查新增學生的學號有沒有和任何一位原有學生的學號相同,如果有就回傳0,否則,回傳1。
主程式的流程圖如圖10-6
圖10-6
副程式的流程圖如圖10-7。
圖10-7
以下是程式.。
程式 10-4
#include <stdio.h>
#define MAX_ARRAY_SIZE 256
#define STUDENT_DATA_FILE_NAME "student.txt"
struct student
{
int idnum;
char name[20];
float weight;
};
int read_all_student_data(struct student A[MAX_ARRAY_SIZE], FILE *fp);
void read_new_student_data(
展开阅读全文