330 likes | 412 Views
12/23 計程實習課. Speaker: Wen-Ching Lo Date: 2009/12/23. Outline. 檔案的輸入與輸出 Structure. 檔案的輸入與輸出. C 軟體提供了許多檔案的輸入與輸出函數,這些函數可分成兩大類。 有緩衝區的輸入與輸出 (Buffered I/O) 無緩衝區的輸入與輸出 (Unbuffered file I/O) 有緩衝區的輸入與輸出,是當它在讀取檔案資料或將資料寫入檔案時,一定都先經過一個緩衝區。 沒有緩衝區的輸入與輸出,表示輸入與輸出的動作,是直接在磁碟內執行讀取資料和寫入資料的動作。
E N D
12/23計程實習課 Speaker: Wen-Ching Lo Date: 2009/12/23
Outline • 檔案的輸入與輸出 • Structure
檔案的輸入與輸出 • C軟體提供了許多檔案的輸入與輸出函數,這些函數可分成兩大類。 • 有緩衝區的輸入與輸出(Buffered I/O) • 無緩衝區的輸入與輸出(Unbuffered file I/O) • 有緩衝區的輸入與輸出,是當它在讀取檔案資料或將資料寫入檔案時,一定都先經過一個緩衝區。 • 沒有緩衝區的輸入與輸出,表示輸入與輸出的動作,是直接在磁碟內執行讀取資料和寫入資料的動作。 • 由於有緩衝區的輸入與輸出函數是包含在stdio.h檔案內,所以程式前面,必須要包含下列指令。 # include <stdio.h >
fopen( ) • fopen( )函數主要是用於開啟檔案。檔案在磁碟裡,使用前是需先經過開啟動作的。使用格式如下: FILE *fopen(char *filename, char *mode); • filename:檔案指標,指的是欲開啟的檔案名稱。 • mode:檔案使用模式,指的是檔案被開啟之後,它的使用方式。 • “r”:開啟一個文字檔(text),供程式讀取。 • “w”:開啟一個文字檔,供程式將資料寫入此檔案內。如果磁碟內不包含這個檔案,則系統會自行建立這個檔案。如果磁碟內包含這個檔案,則此檔案內容會被蓋過而消失。 • “a”:開啟一個文字檔,供程式將資料寫入此檔案的末端。如果此檔案不存在,則系統會自行建立此檔案。
fopen( ) • “rb”:開啟一個二元檔(binary),供程式讀取。 • “wb”:開啟一個二元檔,供程式資料寫入此檔案內。如果磁碟內不包含這個檔案,則系統會自行建立這個檔案。如果磁碟內包含這個檔案,則此檔案內容會被蓋過而消失。 • “ab”:開啟一個二元檔,供程式將資料寫入此檔案末端,如果此檔案不存在,則系統會自行建立此檔案。 • 前述的fopen( )函數的使用格式是以指標方式設計,而經常也會直接以字串方式設計此函數: FILE *fopen(“filename”, “mode”);
fclose( ) • fclose( )為關閉檔案的函數。C語言中關閉檔案主要有兩個目的: • 促使檔案在關閉前會將檔案緩衝區資料寫入磁碟檔案內,否則檔案緩衝區資料會遺失。 • 一個C語言程式,在同一時間可開啟的檔案數量有限,一般是20個,如果你的程式很大,要開啟超過20個檔案時,你必須將暫時不用的檔案關閉。 • fclose( )執行失敗,它的傳回值是非零值,如果fclose()執行成功,它的傳回值是零。 使用格式: int fclose(FILE *fname);
fputc( ) • putc( )函數的主要功能是將一個字元,寫入某檔案內,它的使用格式如下: int putc(int ch,FILE * fp); • ch代表所欲輸出的字元。 • fp檔案指標。 • 此函數如果執行成功,它的傳回值是ch字元值。如果執行失敗,它的傳回值是EOF。
getc( ) • getc( )函數的主要目的是從某一個檔案中,讀取一個字元,它的使用格式如下: int getc(FILE *fp); • 當執行getc( )函數成功時,傳回值是所讀取的字元,如果所讀取的是檔案結束字元,則此值是EOF。而在stdio.h內,EOF值是 -1。
範例1(計算此程式的字元數量) #include <stdio.h> int main() { FILE *fp; int count = 0; fp = fopen("13_1.c","r"); if(fp == NULL) { printf("\n******open file error*****"); exit(1); } while ( getc(fp) != EOF ) count++; printf("The number of character for 13_1.c is %d\n", count); fclose(fp); return 0; }
int main( intargc, char *argv[]) • C/C++語言中的main函數,經常帶有參數argc,argv,如下: • int main( int argc, char *argv[]) • argc 是指命令行輸入參數的個數。 • argv是儲存了所有的命令行參數。
範例2(複製檔案到另一檔案) #include <stdio.h> int main( int argc, char *argv[]) { FILE *fp1, *fp2; char chr; if(argc != 3) { printf("\ninput data error"); exit(1); } fp1 = fopen( argv[1], "r"); fp2 = fopen( argv[2], "w"); while ( (chr = getc(fp1) ) != EOF ) fputc (chr, fp2 ) ; fclose(fp1); fclose(fp2); return 0; }
fprintf( ) • fprintf( )主要目的是供你將資料,以格式化方式寫入某檔案內 • fprintf(fp, “資料變數型態”,資料變數名稱 ); • 此函數格式和printf( )使用格式相同. • 兩者唯一的差別是,printf( )會將資料列印在螢幕上,而fprintf( )會將資料列印在某個檔案內。 Example: fprintf(fp,"%d\n",var); fprintf(fp,"\2: The average is %6.2f",average);
fscanf() • fscanf( ) 主要的目的是讓我們從某個檔案讀取資料 • fscanf( fp , "……." , ………); • fscanf( )函數和scanf( )函數兩者之間最大的差別在,scanf( )函數主要用於從鍵盤輸入讀取資料,fscanf( )函數則是從fp檔案指標所指的檔案讀取資料。 Example: fscanf(fp,"%d",&var)
feof( ) / ferror( ) • feof( )主要功能是測試在讀取資料時,是否已經讀到檔案末端位置: int feof(fp); • 若讀取資料的位置是在檔案末端,則傳回非零數值,否則傳回零。 • ferror( )主要用於測試前一個有關檔案指標的操作是否正確: int ferror(fp); • 如果前一個函數對有關檔案指標的操作,有錯誤,則傳回值是非零數值,否則傳回零值。
fwrite( ) / fread( ) • fwrite( )主要目的是將某個資料緩衝區內容,寫入檔案指標所指的二元檔檔案內。 int fwrite(void *buffer, int num_byte, int count, FILE *ftp); • fread( )主要目的是將某二元檔檔案內的資料,讀入資料緩衝區內。 int fread(void *buffer, int num_byte, int count, FILE *fp);
fseek( ) / rewind( ) • fseek( )主要目的是設定所要讀取資料的位置,以達隨機位置讀取檔案資料的目的。 int fseek(fp, long num_byte, int origin); • origin有三種格式: 0:表示從檔案開頭位置 1:表示從目前位置 2:表示從檔案末端位置 • num_byte為與origin的距離。 • rewind( ) 功能在於將檔案指標移至檔案的開頭。
struct • 結構與陣列很類似,因為兩者都是將一些資料連接組合在一起,以下為兩者的比較。 • 陣列 : 相同型態資料之集合. • 結構(struct) :可將不同型態的資料組合在一起 • 結構(struct)為結構(structure)的縮寫 • 結構中的項目通常稱為成員(member)。
Struct • 能夠結合多個彼此相關的變數在一個名稱之下,且可以包含數個不同資料型態的變數。 • 結構是一種使用者自定的型態,它可將不同的資料型態串在一起。 • 舉例:「學生個人資料表」, • 學號(字串型態) • 姓名(字串型態) • 成績(整數型態)
Student • struct 結構名稱標籤 { 資料型態 變數1; 資料型態 變數2; ‧‧‧‧‧‧‧‧ }; • struct 結構名稱 變數1,變數2,…,變數m; • struct Student { char ID[10]; char FirstName[10]; char LastName[10]; int grade; }; • struct Student stu; ID[10] 98753506 FirstName[10] Wendy LastName[10] Lo grade 100
ID LastName Student • 上頁敘述會在記憶體裡配置空間出來讓 student 結構變數使用,記憶體的配置情況如下: 記憶體 FirstName grade
將結構型態與結構變數的宣告寫在同一個敘述 struct 結構名稱 { 資料型態 欄位名稱1; 資料型態 欄位名稱2; . . 資料型態 欄位名稱n; }變數1,變數2,…,變數m;
利用小數點(.)來存取結構變數中的成員。 結構變數名稱.成員名稱 • 例如: • stu.ID = “96753017” • stu.Firstname= “Wendy” • stu.LastName = “Lo”; • stu.grade= 100;
初值的設定 • 範例 : struct Student /* 定義結構mydata */ { char ID[10]; char FirstName[10]; char LastName[10]; int grade; }; struct Student stu={“96753017”,”Wendy”,”Lo”,0 }; /* 宣告結構Student型態之變數stu,並設定結構內欄位的初值 */
結構陣列 結構變數亦可以用宣告陣列,語法如下: struct 結構名稱 結構陣列變數名稱[陣列大小]; • Ex: • struct Student • { • char ID[10]; • char FirstName[10]; • char LastName[10]; • int grade; • }; • struct Student stu[100];/*結構變數的宣告*/
#include<stdio.h> #define MAX 2 int main(void) { int i; struct data /*定義結構data */ { char name[10]; int math; }student[MAX]; for(i=0;i<MAX;i++) /*宣告結構陣列student */ { printf("學生姓名:"); gets(student[i].name); printf("數學成績:"); scanf("%d",&student[i].math); fflush(stdin); /*清空緩衝區內的資料 */ } for(i=0;i<MAX;i++) /*輸出結構陣列的內容*/ printf("%s的數學成績=%d\n",student[i].name,student[i].math); system("pause"); return 0;}
結構指標 • 結構指標 結構變數也是指標的一種,只是它是指向結構的指標,而非指向一般變數。 宣告格式如下: struct 結構名稱 * 結構指標變數名稱; • Ex: • struct student /* 定義結構mydata */ • { • char name[15]; /* 各成員(欄位)的內容 */ • char id[10]; • int math; • int eng; • }; • struct student * prt; /*結構變數的宣告*/ • ptr=&student; /*將指標指向此結構變數 student*/
結構指標變數的使用 • 使用指標來存取結構變數內的成員(欄位)時,要利用「->」來連接欲存取的成員,如下面格式: 結構指標名稱 ->結構變數成員 Ex: 如前一頁所宣告的結構變數student及指標ptr為例, ptr->math即代表了指向結構變數student的math成員。
#include<stdio.h> #include<stdlib.h> int main(void) { struct data { char name[10]; int eng; }student; struct data *ptr; ptr=&student; printf("學生姓名:"); gets(ptr->name); printf("英文成績: "); scanf("%d",&ptr->eng); printf("英文成績=%d",ptr->eng); system("pause"); return 0; }
巢狀結構 • 結構可以存放不同的資料型態,所以在結構中也可以擁有另一個結構,如此就稱為巢狀結構(nested structure). • 格式如下: struct 結構1 { /*結構1的成員*/ }; struct 結構2 { /*結構2的成員*/ struct 結構1 變數名稱; };
#include<stdio.h> #include<stdlib.h> int main(void) { struct date /*define date*/ { int month; int day; }; struct student /*define nested structure---student*/ { char name[10]; int math; struct date birthday; }s1={“David Li",80, {2,10}}; printf("student name:%s\n",s1.name); printf("birthday:%d month, %d day\n",s1.birthday.month,s1.birthday.day); printf("math grade:%d\n",s1.math); return 0; }
習題 • 題目:有一個表示學生國英數成績結構陣列如右所附。請完成二個函數,其原型分別為 void happy_birthday(struct data [], int); int max_grade(struct data []); 其功能可以(1)列印12月份生日的學生姓名; (2)傳回全班平均成績最高的學生的索引值 。 請完成函數,並依題目輸出要求,測試函數,印出結果。 題目輸入:八個學生資料如右所附。 題目輸出:(1)印出本月壽星的學生姓名 (2)印出全班平均成績最高的學生姓名 struct day{int yy, mm, dd; /* 年、月、日 */ };struct data{char name[20]; /* 姓名 */ struct day birthday; /* 生日 */ int chi, math, eng; /* 國文、數學 與 英文成績 */ }; struct data student[8] = {{"Marry Hu", {77, 2, 3}, 89, 90, 79}, {"Tom Chen", {78, 12, 13}, 79, 69, 88}, {"Billy Wu", {77, 1, 30}, 81, 54, 66}, {"John Hsu", {77, 7, 22}, 69, 49, 70}, {"Tim Huang", {77, 12, 8}, 90, 62, 83}, {"Marry Chen", {78, 5, 27}, 78,93, 91}, {"Tomas Chu", {77, 5, 18}, 80, 50, 68}, {"Ann Wang", {77, 9, 21},100,100, 100}};