TAI LIEU THAM KHẢO
Trang 4PHỤ LỤC B Một số hàm thường dùng trong các thư viện
<stdio.h> Standard Input and Output Library rintf() Xuất dữ liệu theo định dạng ra màn hình scanf() Nhập dữ liệu theo định dạng từ bàn phím ets() Nhập chuỗi ký tự từ bàn phím uts() Xuất chuỗi ký tự ra màn hình getchar() Nhập ký tự từ bàn phím putchar() Xuất ký tự ra màn hình filushQ Xóa bộ đệm bàn phím fopen() Mở file
fclose() Dong file
feof() Kiểm tra kết thúc file
fseek() Dịch chuyên con trỏ file
ftell() Lay vi tri hién thời của con trỏ file
freadQ Đọc khôi dữ liệu từ file
fwrite() Ghi khối dữ liệu ra file
fprintf() Xuất dữ liệu theo định dang ra file
fscanf() Ghi đữ liệu theo định dạng từ file
fgets() Đọc chuỗi ký tự từ file
fputs() Ghi chuỗi ký tự ra file
fgetc() Doc ký tự từ file
fputc() Ghi ký tự ra file
<conio.h> Console Input and Output Library getche() Nhập ký tự, hiển thị ký tự nhập
getch() Nhập ký tự, không hiên thị ký tự nhập <stdlib.h> Standard General Utilities Library
abs() Tính giá trị tuyệt đôi
atoi() Đổi từ chuỗi sang sỐ nguyên
itoa() Đôi từ số nguyên sang ¢ chuỗi srand() Khởi tạo bộ sinh số ngẫu nghiên
rand() Sinh sô ngau nhién
calloc() Cấp phát nhiều vùng nhớ
malloc() Câp phát vùng nhớ
freeO Giải phóng vùng nhớ
exit() Thoát khỏi chương trình
<math.h> Mathematics Library
sqrt() Tính căn bậc 2
powQO Tính lũy thừa
exp() Tính lũy thừa cơ số e
Giáo trình môn Kỹ thuật lập trình
Trang 7CHƯƠNG 4: KIỄU DỮ LIỆU DO NGƯỜI DÙNG ĐỊNH NGHĨA
» - Dòng thứ ¡ trong N dòng tiếp theo mỗi dòng có 2 số nguyên Bi và Ci (0 < Bi < Ci)
Trang 8CHƯƠNG 4: KIÊU DỮ LIỆU DO NGƯỜI DÙNG ĐỊNH NGHĨA
Viết chương trình thực hiện các chức năng sau, mỗi chức năng viết một hàm riêng
a Nhập danh sách các sinh viên và lưu vào file b Đọc dữ liệu từ file và lưu vào mảng
c Xuất danh sách các sinh viên (từ máng) theo dạng bảng d Tìm một sinh viên theo mã sinh viên
e Xuất danh sách các sinh viên có điểm <5
£ Đếm xem có bao nhiêu sinh viên có điểm <5
ø Tính điểm trung bình của các sinh viên có năm sinh 1992
k Xuất các sinh viên có điểm lớn nhất
1 Xóa các sinh viên có điểm = 0
4.3
Viết chương trình thực hiện các công việc sau:
a Nhập và ghi vào file 20 số nguyên bắt kỳ
b Đọc đấy số từ file và tách thành 2 day: day gồm các số lẻ và dãy thành số thực Sau đó
ghi trở lại 2 dãy đã tách vào cùng file đó (ghép vào cuôi file băng kiêu mở file "a")
c Tính tổng dãy và ghi trở lại vào file
4.4 (Trích đề thi Olympic Tin học Sinh viên Toàn quốc 2005, khối thi: Cá nhân Cao
đăng)
Ở miền Trung thường năm nào cũng có những đợt hạn hán nên ông Nam có những thùng
dự trữ nước Do mua làm nhiều đợt nên N (1 <N < 1000) thùng chứa nước của ông Nam
có kích thước khác nhau, mỗi thùng có sức chứa Ci (1 < Ci < 10000,
1 <i<N) Dự đoán rằng năm nay sẽ có đợt hạn hán lớn nên ông Nam muốn đồ đầy nước
hết các thùng để dự trữ Sau khi kiểm tra ông Nam thấy rằng có một số thùng vẫn còn đầy, một số khác thì vơi đi một phần, còn một số thì đã hết Ông quyết định các thùng nào chưa đây thi sẽ chớ đi để đỗ đầy nước Nhưng do nơi lấy nước rất xa, và mỗi lần chỉ chở đi được 1 thùng nên ông quyết định sẽ san nước giữa các thùng với nhau đề số thùng
phải chở đi là ít nhất
Yêu cầu: Cho dung lượng nước hiện có của thùng thứ ¡ là Bi (0 < Bi < C¡, 1 <¡ <N), hãy giúp ông Nam xác định số lượng thùng ít nhất phải mang đi
Dữ liệu: vào từ file văn bản WA TER.INP có dạng sau:
+ Dòng thứ nhất ghi một số tự nhiên N là số lượng các thùng nước
Trang 9CHƯƠNG 4: KIỂU DỮ LIỆU DO NGƯỜI DÙNG ĐỊNH NGHĨA BÀI TẬP CHƯƠNG 4 4.1 Cho danh sách lưu thông tin của các mặt hàng, thông tin gồm: Mã mặt hàng (chuỗi 10 ký tự) Tên mặt hàng (chuỗi 50 ký tự) Số lượng mặt hàng (số nguyên)
Đơn giá mặt hàng (số thực, đơn vị 1000 VNĐ)
Viết chương trình thực hiện các chức năng sau, mỗi chức năng viết một hàm riêng a Nhập danh sách các mặt hàng, lưu ý khi nhập cần kiểm tra trùng mã mặt hàng b Xuất danh sách các mặt hàng theo dạng bảng, và tính thành tiền của từng mặt hàng
STT Mãhàn Ténhang Sốlượng Đơngiá Thành tiền
1 TV Tivi 100 2000 200000
2 TL Tu lanh 200 3000 600000
c Tìm một mặt hàng theo mã mặt hang
đ Xuất danh sách các mặt hàng có số lượng lớn hơn hay bằng 100
e Đếm xem có bao nhiêu mặt hàng có số lượng lớn hơn hay bằng 100 f Tính giá trung bình của các mặt có giá >1.000.000 VND g Xuất các mặt hàng có giá lớn nhất h Xuất các mặt hàng có số lượng nhỏ nhất 1 Cập nhật giảm giá các mặt hàng 10% m Xóa các mặt hàng có số lượng = 0 4.2
Cho danh sách lưu thông tin của các sinh viên, thông tin gồm: - Mã sinh viên (chuỗi 10 ký tự)
-_ Tên sinh viên (chuỗi 50 ký tự) - Năm sinh (số nguyên)
- Điểm (số thực)
Trang 11CHƯƠNG 4: KIỂU DỮ LIỆU DO NGƯỜI DÙNG ĐỊNH NGHĨA
Ví dụ 9.14: (Trích đề thi Olympic Tìn học Sinh viên toàn quốc 2008, khối thi: Cá nhân
Cao đăng)
Vị Giám đốc công ty XYZ cần gửi một văn bản quan trọng tới một đối tác của mình Đề bảo mật văn bản, Giám đốc quyết định mã hóa văn bản trước khi gửi Văn bản là một xâu các chữ cái la tỉnh in thường Giám đốc chia văn bản thành 2 xâu liên tiếp Sb va Se Lan
lượt viết 2 xâu Sb và Se nhưng điều theo thứ tự ngược lại ô ¡ông nhận được xâu mã hóa Q Bức thư thứ nhất gửi cho đối tác có nội đung là Q Để đối tác đọc được văn bản, ông gửi
thêm một bức thư thứ 2 trong đó chứa khóa để giải mã: độ dài k xâu Sb
Ví dụ nội dung bức thư S=”programming” được chia thành 2 đoạn: Sb=”progam”, Se=”ming”
Ta nhận được xâu mã hóa Q=”margorpgnim” với khóa k=7
Yêu cầu : cho xâu mã hóa Q và khóa k, hãy xác định xâu S (k >0 và không vượt quá độ
đài xâu S)
Dữ liệu: Vào từ fñile văn bản LETTER.INP, trong đó dòng đầu chứa xâu mã hóa Q có độ đài từ 1 đến 250, dòng thứ 2 chứa khóa k
Kết quả: Ghi ra file văn bản LETTER.OUT xâu S tìm được LETTER.INP LETTER.OUT margorpgnim programming 7 1 #include <stdio.h> 2 #include <string.h>
3 #define input "LETTER.INP"
Trang 12CHƯƠNG 4: KIÊU DỮ LIỆU DO NGƯỜI DÙNG ĐỊNH NGHĨA Ví dụ: IIMAGE INP IIMAGE OUT 3 4 1321 1231 3456 65 4 3 7030 2.503 10 11 12 13 14 15 16 17 18 19 20 21 #include <stdio.h>
#define input "TTMAGE.INP"
#define output "IIMAGE.ouT" int main() FILE* £1, *£2; fl II fopen (input, "r"); £2 = fopen(output, "w"); int a[250] [250]; int n,m;
fscanf (f1,"%d%d", &m, &n);
Trang 13CHƯƠNG 4: KIỂU DỮ LIỆU DO NGƯỜI DÙNG ĐỊNH NGHĨA 8 FILE *f£; 9 char *fname=new char; 10 printf("Ten file: "); 11 scanf("%s", fname) ; 12 if((f=fopen(fname, "r")) == NULL) 13 { 14 printf("Loi: Khong the mo file [%s]\n", fname); 15 return 1; 16 } 17 printf("Tap tin %s co $ld ky tu\n", fname, CharCount (f)); 18 fclose(f); 19 getch(); 20 return 0; 21 |}
Kết quả chạy chương trình:
ifen “file: test.txt
flap tin test.txt co 3@ ky tu
Vi du 9.13: Chuong trinh sau cho phép:
Trang 14CHƯƠNG 4: KIỀU DỮ LIỆU DO NGƯỜI DÙNG ĐỊNH NGHĨA
9.2.7 Lay vị trí hiện thời của con trỏ file
long ftell(<con tré file>);
//Tra vé vi tri hién tai cta con tré file so voi vi tri dau //file Néu cé 16i, hàm trả về giá trị -1L
Lưu ý: Giá trị hàm trả về sẽ không đúng với file được mở ở chế độ văn bản do các ký tự
carriage-return va linfeed Một ứng dụng thông dụng là để xác định kích thước của file
khi con trỏ năm ở cuỗi file
Ví dụ 9.11: Đọc 100 bytes từ file pArA DAT và cho biết vị trí của con trỏ file 1 FILE *f; 2 long position; 3 char list[100];
4 |fseek(f, OL,SEEK_SET); // Vé dau file
5 fread(list, sizeof(char), 100, £); // Dec ra 100 bytes 6 position = ftell(fp); // Vi tri con tré file
Ví dụ 9.12: Nhập tên một file bất kỳ có trên đĩa và dém số ký tự có trong file đó Nếu
thao tác mở file không thành công, cân xuất thông báo lỗi
Trang 15CHƯƠNG 4: KIÊU DỮ LIỆU DO NGƯỜI DÙNG ĐỊNH NGHĨA
SEEK_CUR: Vi tri hién thoi cua con tré file (= 1)
SEEK_END: Vi tri cudi file (= 2)
SEEK_SET: Vi tri dau file (= 0)
Ta thường ứng dụng hàm fseek dé :
Đưa con trỏ file về vị trí cuối file: fseek(fp, 01,SEEK_END) ;
Đưa con trỏ file về vị trí đầu file: fseek(fp, 0L,SEEK SET) ;
Vi du 9.10: Vi du 9.5 duge viết lại dùng hàm £seek (), khi đó ta không cần mở file 2 lần mà chỉ cần mở file 1 lần với chế độ “w+” như sau: 1 int main() 2 if 3 FILE *f;
4 char fname[]="DATA DAT";
5 char s[]=“Ly Tu Trong”;
6 int i=0; float x=3.1;
// Ghi giá trị của các biến vào file
7 if((f=fopen(fname, "wt")) == NULL) return 0;
8 fprintf(f, "$s%c", s, '\n');
9 fprintf(f, "Sdce", i, '\n');
10 fprintf(£, "SE", x);
// Đưa con trỏ file về đầu file
11 fseek(fp, OL, SEEK SET);
// Đọc nội dung file ra các biến
12 fscanf(f, "%s", s); printf("s=\"%s\"\n", s);
13 fscanf(f, "$d", &1); printf("i=sd\n", 1);
Trang 16CHƯƠNG 4: KIÊU DỮ LIỆU DO NGƯỜI DÙNG ĐỊNH NGHĨA 20 scanf ("ss", x.name) ; 21 JÊ (strcmp(x.name,"#") == 0) break; 22 scanf("%d", &x.age); 23 fwrite(&x, sizeof (Person), 1, £); 24 } 25 fclose(f); 26 | } 27 | void DocFile (char fname[]) 28 | { 29 FILE *f; Person x; // Mở file để doc 30 printf("\n\nXuat du lieu tu tap tin ra man hinh:\n\n"); 31 if((f=fopen(fname, "r")) == NULL) 32 { 33 printf("Khong the mo file %s\n", fname); 34 getch(); return ? 35 } // Đọc dữ liệu từ file và in ra màn hình 36 printf("DANH SACH GOM:\n"); 37 printf ("TEN\tTUOI\n");
38 while (fread(&x, sizeof (Person), 1, f)!= 0)
39 printf ("ts\t%d\n", x.name, x.age);
40 fclose(f);
41 |}
9.2.6 Dich chuyén con tré file
Khi mở file, con trỏ file luôn ở vị tri đầu file, trừ trường hợp file được mở để ghi thêm
bang mode "a" hay "at" (append) thi con trỏ file sẽ ở cuối file Hàm £seek () cho
phép dịch chuyển con trỏ file đến vị trí bất kỳ với số byte tương đối so với vị trí trước đó
hay đầu file
int fseek(<Con tré £file>, <Sô byte >, <Vị trí bắt dau>);
<Vi tri bat dau> (origin): sẽ nhận một trong các giá trị sau (định nghĩa trong
header stdio.h):
Trang 17CHƯƠNG 4: KIÊU DỮ LIỆU DO NGƯỜI DÙNG ĐỊNH NGHĨA 6 return; 7 dem = fread(&s, sizeof(int), 10, f); 8 fclose(f);
9 printf("So phan tu da doc: $d\n", dem); 10 | for(int i=0; i<10; i++)
11 Đrintf("%4d", s[i]);
Ví dụ 9.9:
Các hàm DoeF4 1e () ; GhiFile() ở ví dụ 9.6 được viết lại ding ham freadQ, fwrite() Trong đó thông tin mỗi người được thể hiện bằng một struect có tên Person 1 typedef struct Person 2 |f 3 Char name[10]; 4 int age; 5 [hi 6 void GhiFile(char fname[]) 7 { 8 FILE *f£; Person x;
// M& file d& ghi
9 if((f=fopen(fname, "a")) == NULL) 10 { 11 printf ("Khong the mo file %s\n", fname) ; 12 getch(); 13 return ; 14 }
Trang 18CHƯƠNG 4: KIÊU DỮ LIỆU DO NGƯỜI DÙNG ĐỊNH NGHĨA
d Hàm đọc ghi đữ liệu £read() và £write ()
fread (<Ðịa chỉ biến>,<Kích thước>,<Số ptử>,<Con trỗ file>);
// Đọc dữ liệu từ file vào biên
⁄⁄ Trả về số phần tử đọc được, ngược lại trả về 0
fwrite (<Địa chỉ biễn>,<Kích thước>,<Sỗ ptữ>,<Con trỏ file>);
⁄⁄ Ghi d& liéu tz bién vao File
// Trả về số phần tử đọc được, ngược lại trả về 0 <Kích thước> (size): Kích thước mỗi phần tử dữ liệu, được tính bằng byte <số ptử> : Số phần tử được đọc/ghi Ví dụ 9.7: Ghi dãy số nguyên 23, 3, -5, 56, 484, 67, 0, 126, 21 vào file có tên INT.DAT 1 FILE *f; 2 char fname[]="INT.DAT"; 3 int s[{10]=(23, 3, 5, 56, 484, 67, 0, 126, 21, 99}; 4 int dem; |
5 if ( (f=fopen (fname, "wb")) == NULL) return;
Trang 19CHƯƠNG 4: KIÊU DỮ LIỆU DO NGƯỜI DÙNG ĐỊNH NGHĨA 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 } getch(); return ; } // Đọc đỡ liệu từ file và in ra màn hình Đrintf("DANH SACH GOM:\n"); printf ("TEN\tTUOI\n");
while ((fscanf (f£,"%s%d", name, &age)) != EOF)
printf ("ts\t$d\n", name, age); fclose(f); int main() { } char fname[20]; printf ("Nhap ten file muon luu:");gets (fname) ; GhiFile (fname) ; DocFile (fname) ; getch (); return 0; Két qua chay chuong trinh:
cš C:Macuments and Settings\svVAy Eã xị hap ten file muon luu:C:xNSŨỮ.Cx€ al
Trang 20CHƯƠNG 4: KIỀU DỮ LIỆU DO NGƯỜI DÙNG ĐỊNH NGHĨA 1 void GhiFile(char fname[]) 2 |{ 3 FILE *f;char name[50];int age; // Mở file đề ghi 4 if((f=fopen(fname, "“a")) == NULL) 5 { 6 printf("Khong the mo file s\n", fname); 7 getch(); 8 return ; 9 }
// Nhập đữ liệu từ bàn phím và ghi vào file
Trang 21CHƯƠNG 4: KIÊU DỮ LIỆU DO NGƯỜI DÙNG ĐỊNH NGHĨA // Ghi giá trị của các biến vào file 8 if((f=fopen(fname, "w")) == NULL) 9 return 0; 10 fprintf(f, "%s%c", s, "\n'); 11 fprintf(f, "dc", i, ‘\n'); 12 fprintf(£, "Sf", x); 13 fclose(f); // Đọc nội dung file ra các biến 14 1£((f=fopen (fname, "r")) == NULL) 15 return 0; 16 fscanf(f, "%s", s); printf("s=\"Ss\"\n", s);
17 Escanf(f, "$d", &1); printf ("i=$d\n", i);
18 fscanf(f, "ti", &x); printf("f=sf\n", x); 19 fclose(f); 20 getch(); 21 return 0; 22 | } Két qua chay chwong trinh:
Vi du 9.6: Chương trình sau cho phép:
- Nhập đữ liệu gồm tên và tuổi của từng người và lưu vào file (tên file do người dung nhập vào) Nếu file chưa có thì tạo mới, nếu đã có thì ghi thêm dữ liệu vào cuối file Khi nhập tên là dấu "#" sẽ kết thúc nhập đữ liệu
- Đọc lại file và xuất danh sách lên màn hình
Trang 22CHƯƠNG 4: KIỀU DỮ LIỆU DO NGƯỜI DÙNG ĐỊNH NGHĨA 4 Char s[100];int i, ch; 5 1£((f=fopen("C:\NTEXT.TXT", "rt”)) == NULL) 6 return 0; 7 while(!feof (£)) 8 { 9 ch = fgetc(f); // fgets(s, 100,f); 10 printf (“%c”,ch); // printf (“%s",s); 11 } 12 £close (£) ; 13 getch(); 14 return 0; 15 | } c.Ham doc, ghidirligu fscanf() va fprintf ()
int f£scanf(<Con tré file>,<Chuéi dinh dang>,<Dia chi cdc bién>);
⁄⁄ cho phép: đọc đữ liệu từ file và lưu vào các biễn Nếu thành công trả về số phần tử đọc ghi được, ngược lại trả về EOF
int fprintf (<Con trỏ £ile>,<Chuỗi định đạng>,<Danh sách biến>)
⁄⁄ ghi dữ liệu từ các biên bên ngoàii vào file Nếu thành công
Trang 23CHƯƠNG 4: KIÊU DỮ LIỆU DO NGƯỜI DÙNG ĐỊNH NGHĨA 3 char s[]="1Ly Tu Trong”; 4 FILE *f; 5 if ((f=fopen("C:\\TEXT.TXT", "wt")) != NULL) 6 { 7 fputs(s, £); 8 fputc('\n', £); 9 fputs("2011", £); 10 fclose(f); 11 printf("Ghi thanh cong!"); 12 } 13 else printf("Loi mo file"); 14 getch(); 15 return 0; 16 |} }
N6i dung file C\TEXT.TXT duoc tao :
ex C:Wocuments and Settings PEE i { | i b Cac ham doc ky tu va chudi tir file: fgetc() va fgets ()
int fgetc(<con tré file>); //Trad vé mé ASCII cia ky tw doc dugc, //néu không đọc được trả về EOF
| char* fgets (<bién chuéi>,<sé ky ty téi da>,<con tré file>);
Trang 24CHUONG 4: KIEU DỮ LIỆU DO NGƯỜI DÙNG ĐỊNH NGHĨA 3 if(£ != NULL) 4 { 5 printf£("Mo file thanh cong"); 6 //Các xử lý trên file 7 fclose(f); 8 } 9 else printf("Mo file khong thanh cong");
9.2.4 Kiểm tra cuối file:
Khi đọc dữ liệu từ file, để tránh lỗi xảy ra khi con trỏ file đã trỏ vào vị trí cuối file, ta
dùng hàm feof ()
int feof(<con tré file>); //tra vé sé nguyén ¥ 0 néu con tre // file ở cuỗi file, ngược lại trả về 0 Hàm feofQ có thể được sử sụng như sau: whi le (!£eo£ (£p) ) { <Thao tác đọc file>
9.2.5 Đọc và ghi đữ liệu vào file:
a Hàm ghi ký tự và chuỗi vào file: fputc () và fputs ()
int £putc (<Ký tự>, <Con trỏ file>);
int fputs(<Chuéi>, <Con tré file>);
⁄⁄ Trả về một số nguyên không âm nếu việc ghi thành công, ngược ⁄⁄ lại trả về hằng EOF
Vi dy 9.3: Chương trình sau cho phép ghi 2 dòng vào file Texr xT, một dòng là gia trị
Trang 25CHƯƠNG 4: KIÊU DỮ LIỆU DO NGƯỜI DÙNG ĐỊNH NGHĨA
t: Mở file theo kiểu văn bản Trong dé CTRL+Z dugc xem là ký tự kết thúc file
EOF khi ghi dữ liệu vào file
b: Mởfile theo kiểu nhị phân
Vi dy 9.1: Mở file "E:\VANBAN.TXT" để ghi 1 FILE *£; 2 f=fopen (”E: \\VANBAN.,TXT", "ự") 3 if(f!= NULL) 4 { 5 printf£("Mo file thanh cong"); 6 7 } 8 else 9 printf("Mo file khong thanh cong"); 9.2.3 Dong file
Sau khi thực hiện xong các tác vụ trên file, ta cần phải thực hiện thao tác đóng file Thao
tác này có tác dụng ghi toàn bộ các dữ liệu đang nằm trong các bộ nhớ đệm (temporary file buffer) dành cho file lên đĩa, giải phóng vùng nhớ cho bộ đệm, tránh việc mất mát hay hỏng dữ liệu trên file
Để đóng 1 file ta dùng hàm £elose () , để đóng các file hiện đang mở, ta dùng hàm
fcloseall ()
int fclose(<Con tré file>); // Néu thanh céng tra vé tri 0, ⁄⁄ ngược lại trả về trị EOF (=-1)
Trang 26CHƯƠNG 4: KIỄU DỮ LIỆU DO NGƯỜI DÙNG ĐỊNH NGHĨA
9.2 CÁC THAO TÁC TRÊN FILE
Để đọc/ghi file trong C/C++,.có 2 phương pháp: xử lý nhập/xuất cấp thấp (low level)
và xử lý nhập/xuât cap cao (high level) Ưu điểm của xử lý nhap/xuat cap cao là không
phụ thuộc vào hệ điều hành và có nhiều hàm dùng cho nó hơn là xử lý nhập/xuất cập
thập
9.2.1 Khai báo con tré file
Khi muốn xử lý nhập/xuất một file , ta can sit dung một con trỏ file (file pointer) cho
nó Con trỏ file là con trỏ có kiểu cấu trúc E ILE, trỏ đến từng byte trên file , hay nói cách khác nó chứa địa chỉ của từng mẫu tin trong file
Cách khai báo con trỏ file như sau: | FILE *<Con tré file>; | Chẳng hạn khai báo con trỏ file có tên £ : FILE *f; 9.2.2 Mở file
Trước khi đọc/ghi đữ liệu trong file , ta phải thực hiện thao tác mở file
FILE * fopen(<Tén file>, <Kiéu Tnở>) ;
//Nễu mỏ không thành công trả về NULI
<Tén file> Tên file muốn mở
<Kiễu mở> Kiểu mở file (mode), được xác định như sau:
"x": MG file dé doc
"w": Mo file file dé ghi Nếu file đã tồn tại, nội dung trước đó sẽ bị xóa
"a"; Mở file để ghi vào cuối file (append) mà ta không cần phải thực hiện thao tác chuyên con trỏ file đến vị trí kết thúc file (EOF - End Of File marker) Nếu
file không tôn tại, file mới sẽ được tạo
"+" : Mở file đề đọc và ghi, file muốn mở phải tôn tại
"w+" :; Mở một file rỗng cho thao tác đọc và ghi Nếu file đã tồn tại, nội dung có trước đó sẽ bị xóa
"at": Mo file cho thao tác đọc và ghi vào cuối (append) Trước khi thực hiện ghi dữ
liệu, con trỏ sẽ được tự động chuyền đến vị trí dấu EOEF File sé được tạo mới
nêu khơng tơn tại
Ngồii ra, ta có thể viết thêm vào tùy chọn t hoặc b vào chuỗi mode để xác
định file được xử lý theo kiểu văn bán (text) hay nhi phan (binary):
Trang 27CHƯƠNG 4: KIÊU DỮ LIỆU DO NGƯỜI DÙNG ĐỊNH NGHĨA
§9 TAP TIN (FILE) 9.1 KHAI NIEM
Tập tín (file) là tập hợp dữ liệu dưới dang các byte được lưu trữ trên thiết bị lưu trữ
như đĩa cứng (hard disk) , dĩa mềm (floppy disk), CD, DVD, USB Memory Stick, va
được gan cho một tên theo qui ước của hệ điều hành Các file được tạo bởi các chương
trình và chúng được dùng để chứa dữ liệu vào (input) hay dữ liệu xuất (output) của một hay nhiều chương trình
Một cách tông quát về mặt cấu trúc, file là một tập các mẫu tin (record), mỗi mẫu tin là
một tập các byte Thực chất file là một dòng (stream) các byte được bế trí liên tục, việc
đọc/ghi dữ liệu từ/vào file là thao tác trích (extract) hay chén (insert) đữ liệu vào/ra khỏi stream
Xét vé mat truy cập tới các mẫu tin hay phan tir trong file, ta chia chúng ra làm 2 lọai: - File truy cập tuần tự (sequential access files): Với thao tác đọc (read), dé đọc một
mẫu tin thứ ¡, ta cân duyệt qua tât cả các mẫu tin trước đó bắt đầu từ mẫu tin đầu
tiên Với thao tác ghi (write), mẫu tin mới sẽ được thêm vào vị trí cuối file
- File truy cập ngẫu nhiên (random access file): Với thao tác đọc (read), ta có thể đọc
mẫu tin nằm tại vị trí bất kỳ nào đó trong file mà không cần phải duyệt qua các mẫu
tin trước đó, điều này được thực hiện thông qua chỉ mục (ndex) Với thao tác ghi
(write) cũng tương tự như vậy, ta có thể chèn một mẫu tin mới vào vị trí bất kỳ
trong file thông qua chỉ mục
Xét về mặt lưu trữ, có 2 lọai file:
- File văn bản (text file): Mỗi mẫu tin là 1 byte và chúng là các ký tự ASCII, các dòng
được phân cách nhau thông qua ký tự "new line" (Mr, có trị hex là 0x0D0A)
- File nhị phân (binary file): Mỗi mẫu tin có nhiều byte, chẳng hạn với kiểu int thì
mỗi mẫu tin sẽ là 2 byte hay 4 byte (tùy theo bộ vi xử lý 16 bits hay 32 bits và trình biên dịch)
Các thao tác để xử lý dữ liệu trên file được thực hiện thông qua các hàm xuất/nhập file
được định nghĩa sẵn trong file header stdio.h
Tuy nhiên cần lưu ý các bước chính trong một quá trình xử lý file và các hàm liên quan gom:
| M6 file > Xử lý dữ liệu trong file -> Đóng file
- Mở file: fopen () , freopen ()
- Xử lý dữ liệu: fseanf(), £printf() , fread(), fwrite(), £fgetc(),
fgets(), fputc(), fputs(), fseek{), feof ()
- Dong file: fclose(), feloseall ()
Trang 28CHUONG 4: KIEU DỮ LIỆU DO NGƯỜI DÙNG ĐỊNH NGHĨA struct tm {
tm sec Seconds after minute (0 - 59) tm min Minutes after hour (0 — 59)
tm_hour Hours after midnight (0 - 23) tm_mday Day of month (1 - 31)
tm mon Month (0 — 11; January = 0)
tm_year Year (current year minus 1900)
tm_wday Day of week (0 ~ 6; Sunday = 0)
tm_yday Day of year (0 — 365; January 1 = 0) };
Để lấy ngày hiện thời, hàm 1ocaltime (&timer) được gọi, trong đó tham số timer là con trỏ trỏ đến kiểu time t đã được định nghĩa sẵn Hàm localtime () trả về một con trỏ trỏ vào một struet tm,
Trang 29CHƯƠNG 4: KIỄU DỮ LIỆU DO NGƯỜI DÙNG ĐỊNH NGHĨA 15 now = localtime (&timer) ; 16 today.day = now->tm_mday; 17 today.month = now->tm mon+1; 18 today.year = now->tm_year+1900;
19 printf ("Ngay sinh cua ban (dd mm VVVy): ");
20 scanf ("td%d%d", sdob.day, édob.month, &dob.year); 21 if (today.month>dob.month | |
(today.month==dob.month && today.day>=dob day) )
22 age = today.year ~ dob.year;
23 else
24 age = today.year ~- dob.year - 1;
25 printf ("\n\nKet qua:\n");
26 printf ("Ngay sinh cua ban: $d/%d/%d\n", dob.day, dob.month, dob year); 27 printf("Hom nay la ngay : %d/%d/%d\n", today day, today.month, today.year); 28 printf("Tuoi cua ban la : $d", age); 29 getch(); 30 return 0; 31 | }
Két qua chay chuong trinh:
gay sinh cua ban: 18/5/1981
fiom nay la ngay : 29/11/2085
: uoi cua ban la : 24
Trong chương trinh ta str dung cau tric struct tm được xây dựng sẵn trong file header time.h như sau:
Trang 30CHUONG 4: KIEU DU LIEU DO NGUO! DUNG ĐỊNH NGHĨA oa Ten: Phan Khang am sinh : 1992 o Ten: Phan Thi fn jam sinh = 1991 Ten: Nguyen Kin am sinh : 1992 Ma So Ho ten
THOL Phan Khang
THO2 Phan Thi An TH83 Nguyen Ki Vi du 8.7:
Trang 31CHƯƠNG 4: KIỀU DỮ LIỆU DO NGƯỜI DÙNG ĐỊNH NGHĨA 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 } printf("Ma SV: "); £flush (stdin); gets (a[1].ms) ; Đrintf("Ho Ten: "); fflush(stdin); gets(a[i].ten);
printf£("Nam sinh : "); scanf("%d", ga[il.ns); void Output (SV a[],int n)
{
}
printf("\n\nDanh sach sinh vien:\n");
printf ("STT\tMa So\tHo ten\t\tNam sinh\n"); printf (”T~ -~~~~~~~~~~~~~~~~~—~—~~~~—~~~—~ \n");
for(int i=0; i<n; itt)
printf ("sd\t%s\t%s\téd\n", i+1, a[i].ms, a[i].ten, a[i].ns); int main() { SV a[N];int n; Input (a,n); Output (a,n); getch(); return 0;
Kết quả chạy chương trình:
Trang 32CHUONG 4: KIEU DU LIEU DO NGUO! DUNG ĐỊNH NGHĨA Ví dụ 8.5: 1 5V x,*p,a[100]; 2 x.ms=1; 3 strcpy(x.ten , "Phan Khang"); 4 std1.ns=1992; 5 p=(SV*) malloc(sizeof (SV)); 6 p->ms=2; 7 strcpy(p->ten , "Phan Thi An"); 8 p->ns=1991; 9 a[0] ms=3; 10 | strepy(a[0].ten , "Nguyen Kim"); 11 |a[0].ns=1992;
Ví dụ 8.6: Chương trình sau cho phép nhập vào một danh sách sinh viên gồm các thông
tin: mã sinh viên, họ tên , năm sinh Sau đó in danh sách sinh viên theo dang bang 1 #define N 100 2 typedef struct SV 3 { 4 char ms[10]; 5 char ten[50]; 6 int ns; 7 }¿ 8 void Input(SV a[],int &n) 9 {
Trang 33CHƯƠNG 4: KIÊU DỮ LIỆU DO NGƯỜI DÙNG ĐỊNH NGHĨA
8.1.3 Định nghĩa kiểu dữ liệu mới bằng typedef
Ngoài cách khai báo cấu trúc dữ liệu như trên, ta cũng có thể định nghia struct ding
tir khéa typedef
Khi ding typedef ngoài việc định nghĩa một kiểu dữ liệu mới, việc khai báo các biên sẽ không phải viết từ khóa stxuet nữa nên sẽ tự nhiên hơn, như các kiểu đữ liệu cơ sở khác typedef struct <Tên kiểu> { <Mô tả các thành phẩn>; }; Vi du 8.4: 1 typedef struct SV 2 { 3 int ms; 4 char ten[50]; 5 int ns; 6 |}; //Khai báo biến kiểu SV: 7 SV t; 8 SV *p; 9 SV a[100];
8.2 THAM KHAO CAC THANH PHAN CUA STRUCT
Khi các biến struet đã được khai báo, ta có thể truy cập đến từng thành phan/thanh vién (component/member) cia struct băng toán tử thành phần (member operator) với dâu châm "." đối với biến thường hoặc dùng dẫu mũi tên "—»" khi dùng biên con trỏ
<Tên bién>.<Thanh phan>; //Bién thường
<Tén bién> -> <Thanh phan>; // Bién con tré
Giáo trình môn Kỹ thuật lập trình 91
Trang 34
CHƯƠNG 4: KIỀU DỮ LIỆU DO NGƯỜI DÙNG ĐỊNH NGHĨA 1 struct SV 2 { 3 int ms; 4 char ten[50]; 5 int ns; 6 } x, yi 7 struct SV t; 8 struct SV *p; 9 struct SV SinhVien[100]; Ví dụ 8.2: Mô tả struct có tên date để chứa ngày tháng năm 1 struct date 2 { 3 int day; 4 int month; 5 int year; 6 |};
7 struct date today;
8 struct date birthday[100]; 8.1.2 Khai báo và khởi tạo giá trị cho biến struct struct <Tén kiéu> <Tén bién> = ({<Giá tri cia cdc thanh phan>}; Ví dụ 8.3:
1 struct SV x={1, "Phan Khang", 1992};
2 struct SV SinhVien[]={{1,"Phan Khang",1992},
Trang 35CHƯƠNG 4: KIÊU DỮ LIỆU DO NGƯỜI DÙNG ĐỊNH NGHĨA SinhVien[1] SinhVien[0] SinhVien[2] ĐinhVien[3] int ba = ¬———- Đ char + | unsigned int
Hình 4.1: Minh họa một mảng các struct
8.1 KHAI BAO CAU TRÚC DỮ LIỆU
8.1.1 Khai báo struct
Cũng như các biến thông thường, để có thể sử dụng một kiểu đữ liệu mới dùng struct,
ta cần khai báo và mô tả một struct theo cú pháp sau: struct [<Tén kiéu>] { <Mõ tả các thành phẩn>; } [<Danh sách biến>];
<Tén kiéu> Tên của kiểu đữ liệu mới, tên này không được trùng
với kiểu đữ liệu đã có
<Danh sách biến> Danh sách các tên biến có kiểu struct đã mô tả, phân
cách băng dau “,”
<Mô tả các thành phần> Các mô tả cho từng thành phần trong struct
Sau khi một struet đã được mô tả như cú pháp ở trên, ta có thể khai báo các biến có
kiêu đữ liệu mới này theo cách khai báo biến theo cú pháp
| struct <Tén kiéu> <Danh sach bién>;
Vi du 8.1:
M6 ta struct cé tên SV gôm mã sô, họ tên, năm sinh và khai báo 2 biến x và y có kiêu
dữ liệu mới này:
Trang 36CHƯƠNG 4: KIÊU DỮ LIỆU DO NGƯỜI DÙNG ĐỊNH NGHĨA
- CHƯƠNG 4
KIỂU DỮ LIỆU DO NGƯỜI DÙNG ĐỊNH NGHĨA
TÓM TẮT NỘI DUNG:
- _ Kiểu dữ liệu có cấu trúc (struct), cách khai báo, tham khảo các thành phần của biến kiêu struct Các thao tác trên mang struct
- Kiéu file, các thao tác trên file
_ MỤC TIỂU: Sau khi học xong sinh viên thực hiện được
-_ Các thao tác trên biến, mảng có kiểu struct gồm:
© Khai báo biến, mảng kiểu struct
e© Xuất mảng struct theo dạng bảng
e© Xuất, đếm, tính toán , cập nhật theo điều kiện cho trước trên mảng struct
e_ Tìm phần tử lớn nhất nhỏ nhất trên một thành phần của mang struct
- Cac thao tac trên file gồm:
® Mở, đóng file, dịch chuyên con trỏ file
® Đọc, ghi file ding cdc ham fputs(), fputcQ, fzetsQ, fgetc(Q), fscanfQ, fprintfQ,
treadQ, fwriteQ
§8 KIỂU CẤU TRÚC (STRUCT)
Struct (structure) 14 m6t dạng thức mà C/C++ cung cấp cho lập trình viên khả năng
xây dựng một kiêu dữ liệu mới trên cơ sở các kiểu đã được định nghĩa và kết hợp chúng lại với nhau
Chẳng hạn để lưu thông tin của một sinh viên gồm mã số, họ tên, năm sinh, thường thì ta cần 3 biến có kiểu khác nhau Nếu muốn lưu một danh sách sinh viên với các thông tin như trên, ta có thể xây dựng 3 mảng 1 chiều Tuy nhiên, lúc đó sẽ không có sự đồng bộ khi tham khảo đến 1 sinh viên trong danh sách, việc xử lý cũng sẽ trở nên phức tạp hơn
Với cách tiếp cận khác, dùng struet, sẽ làm cho bài tóa trên trở nên đơn giản Lúc đó, mỗi một sinh viên là một cấu trúc với 3 thông tin ràng buộc nhau: MS - Mã số, TEN
- Họ tên, NS — Năm sinh Danh sách sinh viên sẽ là một mảng các cấu trúc đã nêu, được
mô tả như hình vẽ Trong đó, các thành phần (components) hay thành viên (members)
của một struet có kiểu dữ liệu cơ sở, chẳng hạn 1D có kiểu int, TEN có kiểu chuỗi
char*, và NS có kiểu unsigned int Trong những cấu trúc phức tạp khác thì kiểu dữ
liệu của thành phần cũng có thê lại là một struct hay kiéu ditt liệu khác do người dùng
định nghĩa
Trang 37CHƯƠNG 3: CON TRO
Xuất: "83 111 110","78 97 109","84 117 97 110"
3.5
Viết chương trình dùng con trỏ cho phép người dùng nhập vào danh sách các sinh viên
gồm họ tên, năm sinh, điểm sau đó thực hiện các thao tác: a In ra toàn bộ danh sách đã nhập theo dạng bảng như sau:
SIT Hovaten Namsinh Diem
1 Tran Van Tuan 1992 7
2 Nguyễn ThiLan 1993 8
A oA * tA , ok +
c Đêm xem có bao nhiêu sinh viên có điểm nhỏ hơn 5
Trang 38CHƯƠNG 3: CON TRỎ BÀI TẬP CHƯƠNG 3 3.1 Viết chương trình dùng con trỏ thực hiện các chức năng sau (mỗi chức năng viết một hàm riêng):
a Dùng phương pháp cấp phát bộ nhớ động để nhập một dãy gồm n số nguyên In ra màn hình:
b Todan bộ day số theo thứ tự đã nhập
c Tòan bộ dãy số theo thứ tự ngược với thứ tự đã nhập d Day con gồm các số tại các vị trí chỉ mục chẵn
e Dãy con gồm cac sé chin
rh Đêm xem có bao nhiéu sé chan a £ A š + ~ A Tính tông các số chấn của dãy số pm ae Tìm số lớn nhất trong dãy số Tìm số âm lớn nhất trong dãy số me j Xóa tất cả cdc sé chin k Chén một số x vào vị trí k trong day số 3.2 Viết chương trình dùng con trỏ nhập vào một ma trận vuông cấp n>2 Thực hiện: — Inma trận ra màn hình
— Đếm số các phân tử có giá trị lẻ và tính tổng của chúng
— _ Tìm phân tử lớn nhất của từng dòng và nhỏ nhất của từng cột
3.3
Viết chương trình dùng con trỏ nhập vào một danh sách nhiều họ tên sinh viên Nhập vào một họ tên, tìm và cho biết có sinh viên nào trong danh sách trùng với họ tên đã nhập hay không Yêu câu dùng các hàm riêng cho từng chức năng
3.4
Viết chương trình dùng con trỏ nhập vào một danh sách có nhiều tên sinh viên Thay vì in các ký tự trong các chuỗi, in ra màn hình mã ASCII tương ứng với từng ký tự
Vi du:
Nhập: "Son", "Nam", "Tuan"
Trang 39CHUONG 3: CON TRO 18 return 0; 19 |}
Kết quả chạy chương trình:
ong so sinh vien:
en SU thu 1: Le Hang Ten SU thu 2: Do Nam
“Ho Ten thu 3z Tran Tan
“Ho Ten thu 4: Ho Lan
Trang 40CHƯƠNG 3: CON TRO
Tương tự dé khai báo một con trỏ 2 cấp hay còn gọi là con trỏ kép dùng để trỏ đến
chuỗi ký tự, ta viết ** trước tên biến
char **list;
Ta có thể xin cấp phát bộ nhớ cho con trỏ list như sau với n là số dòng:
liat = (char**) malloc (n*sizeof (char) ) ;
// list = new char* [n];
Việc tiếp theo là xin cấp phát cho mỗi chuỗi tên Vì mỗi địa chỉ của list bồm
(1ist+0) , (1ist+1) ;- (List+2) , trỏ vào một chuỗi, do đó để xin cấp phát vùng nhớ
cho n chuỗi ta dùng cấu trúc lặp với n lần lặp: for(int i=0; i<n; i++)
list[i] = (char*) malloc (m*sizeof (char) ) ;
// list[i] = new char [m] ;
với m là độ đài của chuỗi muốn xin cấp phát
Sau đây là toàn bộ chương trình:
1 int main(void)
2 {
3 char **list; int n;
4 printf("Tong so sinh vien: ")? scanf("Sd", &n);
5 if(n>0) list=(char**)malloc(n*sizeof (char) ); 6 elsereturn 0; 7 for(int i=0; i<n; i++) 8 { 9 list [i]=(char*)malloc(50*sizeof (char) ); 10 printf("Ho Ten SV #$d: ", 1+1); 11 fflush (stdin); 12 gets(list[i]); 13 }
14 printf("\nDanh sach sinh vien:\n");
15 for(int i=0; i<n; itt)
16 print£("Sd %s\n",i+1, *(listt+i)); 17 getch();