結構、檔案處理(Structure, File) C/C++基礎程式設計班 結構、檔案處理(Structure, File) 講師:林業峻 CSIE, NTU 3/21, 2015
課程大綱 結構 檔案 作業
結構 (structure) 結構是一種由程式設計師自訂之資料型態 用途:自訂一個新的資料型態, 將相同或不同型態 的資料儲存一起 使用時機:資料的群組化管理 常用:搭配指標做資料的管理 (進階班 - 資料結構) int struct 70 double 70 int a a 2.12 2.12 b double b char ‘A’ char c ‘A’ c
結構的定義 定義一個結構之語法 結構的標籤名稱(tag) 結構的成員(member) struct 結構名稱標籤 { 資料型態 資料變數成員1; 資料型態 資料變數成員2; ‧‧‧‧‧‧‧‧ }; 結構的標籤名稱(tag) 可看成是一個程式設計師自訂的新型態。 結構的成員(member) 其資料型態可以使用 int, float 及 char。也可用陣列與指標 或是另外一個結構
結構的宣告與使用 宣告一個結構實體之語法 結構中成員的使用之語法 struct 結構名稱標籤 結構實體名稱; 結構實體之成員的直接存取 結構實體.成員名稱 結構指標之成員的間接存取 結構指標->成員名稱
結構 範例: P struct Person { char name[80]; int height; int weight; }; struct Person p; Person: 88 bytes name[0] name[1] … name[79] height weight 80 bytes int : 4 bytes int : 4 bytes P
結構 在C語言中, 有提供一個比較好的方法來自己定義 出一群變數的組合. #include <stdio.h> struct Person { char name[80]; int height; int weight; }; int main() struct Person p1; struct Person p2; scanf("%s",&p1.name); scanf("%d",&p1.height); scanf("%d",&p1.weight); printf("Name:%s\nHeight:%d cm\nWeight:%d kg\n",p1.name,p1.height,p1.weight); scanf("%s",&p2.name); scanf("%d",&p2.height); scanf("%d",&p2.weight); printf("Name:%s\nHeight:%d cm\nWeight:%d kg\n",p2.name,p2.height,p2.weight); return 0; }
結構陣列 結構也可宣告成陣列,方便做重覆控制 #include <stdio.h> #define PEOPLE 2 struct Person { char name[80]; int height; int weight; }; int main() struct Person p[PEOPLE]; int i; for (i=0; i < PEOPLE; i++ ) scanf("%s", &p[i].name ); scanf("%d", &p[i].height ); scanf("%d", &p[i].weight ); printf("Name:%s\nHeight:%d\nWeight:%d\n", p[i].name, p[i].height, p[i].weight); } return 0;
結構的指標 範例: 使用結構指標存取另一個結構的資料. struct Person* p2 struct Person char[80] #include <stdio.h> struct Person { char name[80]; int height; int weight; }; int main() struct Person p1; struct Person *p2; p2 = &p1; gets(p2->name); scanf("%d",&p2->height); scanf("%d",&p2->weight); return 0; } p2 struct Person char[80] name int height int weight p1
typedef 用“typedef”來自訂一個型態, 常用在結構上 語法: typedef 既有的資料型態 自訂型態名稱; #include <stdio.h> #define PEOPLE 2 struct Person { char name[80]; int height; int weight; }; typedef struct Person Person; //自訂 Person 型態用來取代原本冗長的 struct Person型態 int main() Person p[PEOPLE]; //之後宣告結構就不用在打 struct了, 只要打Person就好 int i; for (i=0; i < PEOPLE; i++ ) scanf("%s", &p[i].name ); scanf("%d", &p[i].height); scanf("%d", &p[i].weight ); printf("Name:%s\nHeight:%d\nWeight:%d\n", p[i].name, p[i].height, p[i].weight); } return 0;
typedef typedef可以把所有C語言中的型態改用程式設計 師自己取的名字來取代. #include <stdio.h> typedef unsigned char UINT8; typedef unsigned short UINT16; typedef unsigned long UINT32; int main() { UINT8 a=1; UINT16 b=2; UINT32 c=3; return 0; }
課程大綱 結構 檔案 文字檔 二進位檔 作業
檔案處理 從檔案讀進資料或將結果存入檔案之中 fscanf 從檔案讀進資料 fprintf 將結果存入檔案
檔案處理 範例:從input.txt讀一字串到str, 再把字串從str寫 到output.txt 檔案處理 範例:從input.txt讀一字串到str, 再把字串從str寫 到output.txt #include <stdio.h> int main() { FILE *in, *out; //in, out為檔案指標 char str[80]; in = fopen("input.txt", "r"); // 開啟input.txt out = fopen("output.txt", "w"); // 開啟output.txt fscanf(in, "%s", &str); // 讀檔 fprintf(out, "%s", str); // 寫檔 fclose(in); // 關閉input.txt fclose(out); //關閉output.txt return 0; }
fopen(): 開檔 檔案使用前需要先開啟,開檔結果需要檔案指標 FILE紀錄相關資訊,之後即可使用該指標讀寫檔 使用格式: 檔名:檔案指標,指的是欲開啟的檔案名稱。 模式:檔案使用模式,指的是檔案被開啟之後,它的使用方式。 模式 “r” 開啟一個文字檔(text),供程式讀取。 "w" 開啟一個文字檔(text),供程式將資料寫入此檔案內。如果磁碟內不包含這個檔案,則系統會自行建立這個檔案。如果磁碟內包含這個檔案,則此檔案內容會被蓋過而消失。 "a" 開啟一個文字檔(text),供程式將資料寫入此檔案的末端。如果此檔案不存在,則系統會自行建立此檔案。 "rb" 開啟一個二元檔(binary),供程式讀取。 "wb" 開啟一個二元檔,供程式將資料寫入此檔案內。如果磁碟內不包含這個檔案,則系統會自行建立這個檔案。如果磁碟內包含這個檔案,此檔案內容會被蓋過而消失。 "ab" 開啟一個二元檔(binary),供程式將資料寫入此檔案末端,如果此檔案不存在,則系統會自行建立此檔案。
判斷檔案開啟是否正確 使用fopen若開檔失敗,會回傳一個NULL結果 常用來判斷檔案是否存在! #include <stdio.h> int main() { FILE *in, *out; char str[80]; in = fopen("input.txt", "r"); if(in == NULL) printf("failed to open file!\n"); return 0; } out = fopen("output.txt", "w"); fscanf(in, "%s", &str); fprintf(out, "%s", str); fclose(in); fclose(out);
fclose(): 關檔 用於關閉檔案,如果fclose( )執行失敗,它的傳回 值是非零值。 使用格式: 檔案在關閉前會將檔案緩衝區資料寫入磁碟檔案內,否則檔 案緩衝區資料會遺失。 檔案需要換個模式開啟時 (例:先寫後讀)。
關檔時檔案才真正寫入 通常, 在呼叫fclose之前, 檔案的內容不會真正的被 寫到磁碟機上. 若要強迫馬上寫入, 可以呼叫 fflush(FILE *)來做到. #include <stdio.h> #include <stdlib.h> int main() { FILE *output; int i; output=fopen("test.txt", "w"); for (i=0; i<10; i++ ) fprintf( output, "%d\n",i); //fflush(output); } fclose(output); return 0;
fprintf(): 寫檔 將資料,以格式化方式寫入某檔案內。 使用格式: fprintf(檔案指標,"格式化輸出內容", 參數1,參數2, ...參數n); 格式化輸出內容: 可加入列印格式、控制字元、修飾子 參數: 為對應格式之變數 此格式化輸出內容與參數的使用,格式和printf( )使 用格式相同。
fprintf():寫檔 範例:將不同型態資料寫入指定名稱之檔案 #include <stdio.h> int main() { fprintf():寫檔 範例:將不同型態資料寫入指定名稱之檔案 #include <stdio.h> int main() { int a = 100; double b = 12.5; char c = 'A'; char d[] = "Hello"; char file_name[80]; FILE *file; //開檔 printf("File name: "); scanf("%s", &file_name); file = fopen(file_name, "w"); //寫檔 fprintf(file, "%d\n", a); fprintf(file, "%lf\n", b); fprintf(file, "%c\n", c); fprintf(file, "%s\n", d); //關檔 fclose(file); return 0; }
fscanf(): 讀檔 從某個檔案讀取資料。 使用格式: 此格式化輸入內容與參數的使用,格式和scanf( )使用 格式相同。 fscanf(檔案指標, "格式化輸入內容", &參數1, &參數2, ...&參數n); 格式化輸入內容: 可加入列印格式、控制字元、修飾子 參數: 對應格式之變數 此格式化輸入內容與參數的使用,格式和scanf( )使用 格式相同。
fscanf(): 讀檔 範例:將指定名稱之檔案中不同型態資料讀出 #include <stdio.h> int main() fscanf(): 讀檔 範例:將指定名稱之檔案中不同型態資料讀出 #include <stdio.h> int main() { int a; double b; char c; char d[80]; char file_name[80]; FILE *file; //開檔 printf("File name: "); scanf("%s", &file_name); file = fopen(file_name, "r"); //讀檔 fscanf(file, "%d\n", &a); fscanf(file, "%lf\n", &b); fscanf(file, "%c\n", &c); fscanf(file, "%s\n", &d); //關檔 fclose(file); return 0; }
判斷檔案是否結束 feof(檔案指標); 範例:寫作一個讀檔程式將檔案內容印到螢幕上 #include <stdio.h> int main() { FILE *input; char str[80]; char ch; scanf("%s", &str); input=fopen(str,"r"); if ( input==NULL ) printf("open input.txt fail!\n"); return 0; } while(1) fscanf(input, "%c", &ch); if( feof(input) ) break; printf("%c", ch);
練習 請將下面p中三人資料寫入people.txt people.txt #include <stdio.h> Name:Andy Height:170 Weight:70 Name:Joe Height:180 Weight:80 Name:Amy Height:160 Weight:60 #include <stdio.h> #define PEOPLE 3 struct _Person { char name[80]; int height; int weight; }; typedef struct _Person Person; int main() Person p[PEOPLE]={ {"Andy",170,70} , {"Joe",180,80} , {"Amy",160,60} }; //請實作寫檔功能 return 0; }
練習 請將people.txt中三人資料讀入p people.txt #include <stdio.h> Name:Andy Height:170 Weight:70 Name:Joe Height:180 Weight:80 Name:Amy Height:160 Weight:60 #include <stdio.h> #define PEOPLE 3 struct _Person { char name[80]; int height; int weight; }; typedef struct _Person Person; int main() Person p[PEOPLE]; //請實作讀檔功能 return 0; }
二進位檔 檔案的儲存方式通常分成兩種. “文字檔”和“二 進位檔” 文字檔中存放的東西都是肉眼可視的英文字母或 數字符號等. 二進位檔是把數值的內容原封不動使用它的二進 位方式直接儲存下來 舉例: int a=100000 若用文字檔來存, 存下來的會是"100000"這個 字串, 佔6個byte 若用二進位檔來存, 存下來的是0x186A0的的二進位值, 固定 佔4個byte. 因為int型態就是占4個byte.
fread/fwrite: 二進位讀寫檔 fread ( 變數位置, size大小, 數目, 檔案指標); fwrite ( 變數位置, size大小, 數目, 檔案指標); 寫入檔案某size大小的變數之某個
二進位檔 範例: 使用二進位檔方式將一個整數, 小數, 字元, 字串寫到檔案中 #include <stdio.h> 範例: 使用二進位檔方式將一個整數, 小數, 字元, 字串寫到檔案中 #include <stdio.h> int main() { FILE *output; int a=100000; double b=12.5; char c='A'; char d[6]="Hello"; output=fopen("test.bin","wb"); fwrite( &a, sizeof(int), 1, output ); fwrite( &b, sizeof(double), 1, output ); fwrite( &c, sizeof(char), 1, output ); fwrite( &d, sizeof(char), 6, output ); fclose(output); return 0; }
二進位檔 範例: 將上一範例之檔案讀到一個整數, 小數, 字元, 字串寫到變數中 #include <stdio.h> 範例: 將上一範例之檔案讀到一個整數, 小數, 字元, 字串寫到變數中 #include <stdio.h> #include <stdlib.h> int main() { FILE *input; int a; double b; char c; char d[6]; input=fopen("test.bin","rb"); if ( input==NULL ) printf("open input file fail!\n"); exit(0); } fread( &a, sizeof(int), 1, input ); fread( &b, sizeof(double), 1, input ); fread( &c, sizeof(char), 1, input ); fread( &d, sizeof(char), 6, input ); fclose(input); return 0;
二進位檔 範例:用二進位檔將結構陣列資料快速寫入檔案, 再 將該資料讀回到記憶體中 #include <stdio.h> #define PEOPLE 2 struct _Person { char name[80]; int height; int weight; }; typedef struct _Person Person; int main() Person p[PEOPLE]={ {"Andy",170,70} , {"Joe",180,80} }; Person p2[PEOPLE]; FILE *file; file=fopen("people.bin","wb"); fwrite(&p, sizeof(Person), 2, file); fclose(file); file=fopen("people.bin","rb"); fread(&p2, sizeof(Person), 2, file); return 0; }
課程大綱 結構 檔案 作業
作業 製作一個通訊錄程式 輸入格式 參考範例: 新增資料: 輸入'i', 再輸入姓名, 電話, email (文字不含空白鍵) 使用函式: void InsertPerson(Person *p, int n, Person x) p: 通訊錄結構陣列 n: 目前通訊錄人數 x: 新增資料 列出資料: 輸入'l', 印出目前輸入所有人員之內容 使用函式: void ListPerson(Person *p, int n) 輸入’q’離開程式 輸入格式 輸入輸出介面與下面範例相同 參考範例: http://www.csie.ntu.edu.tw/~d95027/train/download/ContactBook.exe
繳交 使用FTP上傳 請使用FileZilla上傳作業至指定FTP主機 繳交期限:2015. 3/28(六) 主機: 使用者名稱: 密碼: 連接埠: 將程式存到自己學號之資料夾 (請自行新增) 檔名: 251XX_hw3_##.c XX為學號, ##為版本編號 Ex: 25100_hw3_01.c (25100號同學 作業3 第1版) 請使用FileZilla上傳作業至指定FTP主機 繳交期限:2015. 3/28(六) 公佈解答後,不再收作業