Bài giảng Kỹ thuật lập trình - Chương 4: Các kiểu dữ liệu có cấu trúc

pdf 45 trang Gia Huy 17/05/2022 3700
Bạn đang xem 20 trang mẫu của tài liệu "Bài giảng Kỹ thuật lập trình - Chương 4: Các kiểu dữ liệu có cấu trúc", để tải tài liệu gốc về máy bạn click vào nút DOWNLOAD ở trên

Tài liệu đính kèm:

  • pdfbai_giang_ky_thuat_lap_trinh_chuong_4_cac_kieu_du_lieu_co_ca.pdf

Nội dung text: Bài giảng Kỹ thuật lập trình - Chương 4: Các kiểu dữ liệu có cấu trúc

  1. BÀI GIẢNG HỌC PHẦN KỸ THUẬT LẬP TRÌNH CHƯƠNG 4: CÁC KIỂU DỮ LIỆU CÓ CẤU TRÚC
  2. Nội dung 4.1. Kiểu mảng 4.2. Kiểu xâu ký tự 4.3. Kiểu cấu trúc 2
  3. 4.1. Kiểu mảng • Khái niệm mảng • Khai báo và sử dụng mảng • Các thao tác cơ bản trên mảng • Một số chương trình với mảng 3
  4. Khái niệm mảng • Là một kiểu dữ liệu có cấu trúc, bao gồm một tập hữu hạn các phần tử có cùng kiểu dữ liệu, có tên chung, được lưu trữ kế tiếp nhau trong bộ nhớ • Kích thước của mảng được xác định ngay khi khai báo và là cố định • Các phần tử trong mảng có tên chung là tên của mảng và được phân biệt với nhau thông qua chỉ số của chúng • Mảng thường được dùng để lưu một dãy giá trị như: dãy số nguyên, dãy số thực, dãy kí tự, ma trận, 4
  5. Khai báo và sử dụng mảng (1) • Khai báo mảng: kiểu_dữ_liệu tên_mảng[N1][N2] [Nn] trong đó: - kiểu_dữ_liệu: là kiểu dữ liệu của các phần tử mảng - tên_mảng: tên biến mảng - N1, N2, , Nn: kích thước các chiều của mảng Số phần tử của mảng: N1 * N2 * * Nn • Ví dụ: - int a[10], b[20]; - float matran[10][20]; 5
  6. Khai báo và sử dụng mảng (2) • Có thể sử dụng chỉ thị #define để xác định kích thước các chiều của mảng Ví dụ: #define N1 20 #define N2 30 int a[N1]; float b[N1][N2]; 6
  7. Khai báo và sử dụng mảng (3) • Kết hợp khởi tạo giá trị trong khai báo mảng: - Khởi tạo giá trị cho mọi phần tử của mảng Ví dụ: int a[3] = {4,5,9}; float x[2][3] = {{2,1.5,3}, {1,3,4.25}}; - Khởi tạo giá trị cho một số phần tử đầu mảng Ví dụ: int b[5] = {2,6,1}; - Khi không khai báo kích thước, kích thước mảng bằng với số lượng giá trị khởi tạo Ví dụ: int c[] = {15,20,36,54}; 7
  8. Khai báo và sử dụng mảng (4) • Khai báo hằng kiểu mảng: - Cách 1: #define tên_mảng {giá_trị_1, , giá_trị_n} Không truy cập được vào các phần tử của mảng - Cách 2: const kiểu_dữ_liệu tên_mảng[N1] [Nn] = {giá_trị_1, , giá_trị_n} Ví dụ: const int hangmang1[4] = {10,20,25,40}; const float hangmang2[] = {4.5,9.25}; const float hangmang3[5] = {1.5,2,5}; 8
  9. Khai báo và sử dụng mảng (5) • Lưu trữ dữ liệu kiểu mảng: - Các phần tử của mảng được lưu trữ tại các ô nhớ kế tiếp nhau trong bộ nhớ - Kích thước bộ nhớ lưu trữ: N1 * N2 * * Nn * sizeof(kiểu_dữ_liệu) - Các phần tử trong mảng được đánh chỉ số, phần tử đầu tiên có chỉ số là 0, phần tử thứ i có chỉ số là i-1 - Biến mảng lưu trữ địa chỉ của ô nhớ đầu tiên trong vùng nhớ được cấp phát 9
  10. Khai báo và sử dụng mảng (6) • Sử dụng mảng: - Cú pháp truy cập vào các phần tử mảng: tên_mảng[chỉ_số_1][chỉ_số_2] [chỉ_số_n] - Ví dụ: int a[4]; Các truy cập hợp lệ: a[0], a[1], a[2], a[3] Các truy cập không hợp lệ: a[-2], a[-1], a[4], a[5], 10
  11. Khai báo và sử dụng mảng (7) • Sử dụng mảng: (tiếp) - Lấy địa chỉ của phần tử mảng (áp dụng cho mảng 1 chiều): &tên_mảng[chỉ_số]; Ví dụ: &a[1] - Tên mảng biểu thị địa chỉ đầu của mảng, tức là: a = &a[0] 11
  12. Các thao tác cơ bản trên mảng (1) • Phép gán mảng: - Không được thực hiện phép gán thông thường cho một biến mảng - Chỉ có thể thực hiện phép gán giá trị cho các phần tử của mảng - Ví dụ: int a[3] = {4,5,9},b[3],i; Phép gán không hợp lệ: b = a; Phép gán hợp lệ: for(i=0;i<3;i++) b[i] = a[i]; 12
  13. Các thao tác cơ bản trên mảng (2) • Nhập dữ liệu cho mảng từ bàn phím: Sử dụng hàm scanf để nhập dữ liệu cho từng phần tử của mảng Ví dụ: int a[10]; Nhập dữ liệu cho phần tử a[1]: scanf("%d",&a[1]); Nhập dữ liệu cho tất cả các phần tử của mảng: sử dụng cấu trúc lặp for int i; for(i=0;i<10;i++) { printf("a[%d] = ",i); scanf("%d",&a[i]); } 13
  14. Các thao tác cơ bản trên mảng (3) • Nhập dữ liệu cho mảng từ bàn phím (tiếp): Lưu ý: Phép lấy địa chỉ không áp dụng cho các phần tử của mảng nhiều chiều (trừ trường hợp mảng 2 chiều gồm các số nguyên) cần sử dụng biến trung gian khi nhập dữ liệu cho mảng nhiều chiều Ví dụ: float a[10][20]; Nhập dữ liệu cho các phần tử của mảng: int i,j; float x; for(i=0;i<10;i++) for(j=0;j<20;j++) { printf("a[%d][%d] = ",i,j); scanf("%f",&x); a[i][j] = x; } 14
  15. Các thao tác cơ bản trên mảng (4) • Xuất dữ liệu của mảng ra màn hình: Sử dụng hàm printf để xuất dữ liệu từng phần tử của mảng ra màn hình Ví dụ: int a[10]; Xuất dữ liệu của phần tử a[1]: printf("a[1] = %d",a[1]); Xuất dữ liệu của tất cả các phần tử mảng sử dụng cấu trúc lặp for: int i; for(i=0;i<10;i++) { printf("a[%d] = %d\n",i,a[i]); } 15
  16. Ví dụ (1) • Chương trình nhập/xuất dữ liệu cho mảng: #include int main(void) { int a[50]; int n,i; lap: printf("Nhap so phan tu n = "); scanf("%d",&n); if (n 50) { printf("So phan tu khong hop le, hay nhap lai!\n"); goto lap; } 16
  17. Ví dụ (2) • Chương trình nhập/xuất dữ liệu cho mảng: (tiếp) for(i=0;i<n;i++) { printf("a[%d] = ",i); scanf("%d",&a[i]); } printf("Day so vua nhap la:\n"); for(i=0;i<n;i++) printf("%d ",a[i]); return 0; } 17
  18. Một số chương trình với mảng • Viết chương trình tính tổng, trung bình cộng cho dãy số nguyên a1, a2 , , an • Viết chương trình tìm giá trị lớn nhất, nhỏ nhất của dãy số nguyên a1, a2 , , an • Viết chương trình tìm phần tử có giá trị là x trong dãy số nguyên a1, a2 , , an (số nguyên x nhập từ bàn phím) • Viết chương trình sắp xếp dãy số nguyên a1, a2 , , an theo chiều tăng/giảm dần • Viết chương trình nhập vào ma trận số nguyên (aij)mxn, in lại các giá trị vừa nhập theo dạng ma trận, tính tổng các phần tử trong ma trận và thông báo kết quả ra màn hình 18
  19. 4.2. Kiểu xâu ký tự • Khái niệm xâu ký tự • Khai báo và sử dụng xâu ký tự • Các hàm xử lý ký tự • Các hàm xử lý xâu ký tự • Một số chương trình với xâu ký tự 19
  20. Khái niệm xâu ký tự • Là một kiểu dữ liệu có cấu trúc, bao gồm một dãy các ký tự liên tiếp, kết thúc bởi ký tự '\0' (null – mã ASCII là 0) • Mỗi ký tự được lưu trong 1byte • Độ dài xâu là số ký tự có trong xâu • Xâu rỗng là xâu không có ký tự nào • So sánh: - Xâu ký tự & mảng ký tự - 'A' và "A" 20
  21. Khai báo và sử dụng xâu ký tự (1) • Khai báo xâu ký tự: char tên_xâu[n] trong đó: n = số ký tự tối đa + 1 Ví dụ: - char hoten[30]; - char s1[50], s2[100]; • Khởi tạo giá trị trong khai báo xâu ký tự: Xét các ví dụ: char s[4] = {'A', 'B', 'C', '\0'}; char hoten[30] = "Luu Thanh Duyen"; 21
  22. Khai báo và sử dụng xâu ký tự (2) • Khai báo hằng xâu ký tự: - Cách 1: #define tên_xâu giá_trị - Cách 2: const char tên_xâu[n] = giá_trị; Ví dụ: #define s1 "ABC" const char s2[10] = "ABCDE"; 22
  23. Khai báo và sử dụng xâu ký tự (3) • Lưu trữ dữ liệu kiểu xâu ký tự: - Các ký tự được lưu trữ tại các byte nhớ kế tiếp nhau trong bộ nhớ - Kích thước bộ nhớ lưu trữ: Số ký tự tối đa + 1 - Tương tự như dữ liệu kiểu mảng, mỗi ký tự trong xâu được đánh chỉ số, ký tự đầu tiên có chỉ số là 0, ký tự thứ i có chỉ số là i-1 23
  24. Khai báo và sử dụng xâu ký tự (4) • Sử dụng xâu ký tự: - Cú pháp truy cập vào các ký tự trong xâu: tên_xâu[chỉ_số_ký_tự] - Ví dụ: char s[15] = "Tran Ngoc Anh"; s[0] 'T' s[3] 'n' s[5] 'N' 24
  25. Khai báo và sử dụng xâu ký tự (5) • Vào/ra xâu ký tự: - Khai báo tệp tiêu đề: #include - Nhập xâu ký tự từ bàn phím: gets(tên_xâu); scanf("%s",&tên_xâu); - Xuất xâu ký tự ra màn hình: puts(tên_xâu); printf("%s",tên_xâu); • Lưu ý: - Không dùng phép gán giá trị cho xâu - Không sử dụng hàm scanf() để nhập xâu chứa ký tự cách - Trước khi dùng gets() cần dùng hàm fflush(stdin) 25
  26. Các hàm xử lý ký tự (1) • Khai báo tệp tiêu đề: #include • Các hàm: - int toupper(int ch): chuyển ký tự thường thành ký tự hoa Ví dụ: toupper('a') 'A' - int tolower(int ch): chuyển ký tự hoa thành ký tự thường Ví dụ: tolower('A') 'a' 26
  27. Các hàm xử lý ký tự (2) - int isalpha(int ch): kiểm tra xem ký tự có phải là chữ cái hay không - int islower(int ch): kiểm tra xem ký tự có phải là chữ cái in thường hay không - int isupper(int ch): kiểm tra xem ký tự có phải là chữ cái in hoa hay không - int isdigit(int ch): kiểm tra xem ký tự có phải là chữ số hay không - int iscntrl(int ch): kiểm tra xem ký tự có phải là ký tự điều khiển hay không (mã ASCII [0,31]) - int isspace(int ch): kiểm tra xem ký tự có phải là ký tự dấu cách (mã ASCII là 32) hay không • Các ký tự đặc biệt: xuống dòng ('\n' - 10), đầu dòng ('\r' - 13), tab ngang ('\t' - 9), tab dọc ('\v' – 11), 27
  28. Các hàm xử lý xâu ký tự (1) • Khai báo tệp tiêu đề: #include • Các hàm: - int strlen(char[] tên_xâu): trả về độ dài của xâu - char[] strcpy(char[] xâu_đích, char[] xâu_nguồn): sao chép toàn bộ xâu_nguồn sang xâu_đích Để sao chép tối đa n ký tự từ xâu_nguồn sang xâu_đích, sử dụng hàm: char[] strncpy(char[] xâu_đích, char[] xâu_nguồn, int n) - char[] strcat(char[] xâu_đích, char[] xâu_nguồn): ghép nối xâu_nguồn vào ngay sau xâu_đích - char[] strrev(char[] xâu_nguồn) đảo ngược các ký tự trong xâu_nguồn, ký tự đầu về cuối, cuối về đầu 28
  29. Các hàm xử lý xâu ký tự (2) • Các hàm: (tiếp) - int strcmp(char[] xâu_1, char[] xâu_2): so sánh 2 xâu (có phân biệt ký tự in hoa – in thường), hàm trả về giá trị: = 0 nếu 2 xâu bằng nhau 0 nếu xâu_1 > xâu_2 Nếu muốn so sánh 2 xâu, không phân biệt ký tự in hoa – in thường thì sử dụng hàm: int stricmp(char[] xâu_1, char[] xâu_2) - char[] strupr(char[] tên_xâu): trả về xâu chữ in hoa tương ứng - char[] strlwr(char[] tên_xâu): trả về xâu chữ in thường tương ứng 29
  30. Các hàm xử lý xâu ký tự (3) • Khai báo tệp tiêu đề: #include • Các hàm: - int atoi(char[] xâu_ký_tự): chuyển một xâu ký tự thành số nguyên tương ứng kiểu int - int atol(char[] xâu_ký_tự): chuyển một xâu ký tự thành số nguyên tương ứng kiểu long - float atof(char[] xâu_ký_tự): chuyển một xâu ký tự thành số thực tương ứng • Lưu ý: khi việc chuyển đổi không thành công, cả 3 hàm trên trả về giá trị 0 30
  31. Ví dụ (1) Chương trình làm việc với ký tự/xâu ký tự: #include #include #include int main(void) { char c, s[30]; printf("Nhap ky tu c: ");scanf("%c",&c); if(isalpha(c)) { if(isupper(c)) printf("Ky tu vua nhap la ky tu in hoa '%c', ky tu in thuong tuong ung la '%c'!",c,tolower(c)); else printf("Ky tu vua nhap la ky tu in thuong '%c', ky tu in hoa tuong ung la '%c'!",c,toupper(c)); } 31
  32. Ví dụ (2) Chương trình làm việc với ký tự/xâu ký tự (tiếp): else if(isdigit(c)) printf("Ky tu vua nhap la ky tu so '%c'!",c); fflush(stdin); printf("\nNhap xau ky tu s: ");gets(s); printf("Do dai thuc cua xau la %d",strlen(s)); printf("\nXau chu in hoa tuong ung la: %s",strupr(s)); printf("\nXau chu in thuong tuong ung la: %s",strlwr(s)); printf("\nXau dao tuong ung la: %s",strrev(s)); return 0; } 32
  33. Một số chương trình với xâu ký tự • Viết chương trình cho phép người dùng nhập vào một xâu ký tự s, đếm số ký tự 'A' và 'a' có mặt trong s, thay thế các ký tự đó bởi ký tự 'B' rồi đưa xâu mới ra màn hình • Viết chương trình cho phép người dùng nhập vào một xâu ký tự s. Xây dựng xâu s1 gồm toàn các ký tự chữ, s2 gồm toàn các ký tự số có trong s, thông báo kết quả ra màn hình 33
  34. 4.3. Kiểu cấu trúc • Định nghĩa kiểu cấu trúc • Khai báo biến cấu trúc • Truy nhập đến các thành phần của cấu trúc • Mảng cấu trúc • Phép gán cấu trúc 34
  35. Định nghĩa kiểu cấu trúc • Cú pháp: struct tên_kiểu_cấu_trúc { khai_báo_các_thành_phần_trong_cấu_trúc; }; Trong đó: - Việc khai báo các thành phần tuân theo quy tắc khai báo biến thông thường (tên_kiểu tên_thành_phần;) - Kiểu dữ liệu của thành phần có thể là kiểu bất kỳ (nguyên, thực, ký tự, mảng, xâu hay kiểu cấu trúc) Ví dụ: struct ngaythang {int ngay; int thang; int nam;}; 35
  36. Khai báo biến cấu trúc (1) • Cú pháp: struct tên_kiểu_cấu_trúc tên_biến_cấu_trúc; Ví dụ: struct ngaythang ngaysinh; • Khi có nhiều biến cùng kiểu cấu trúc, có thể khai báo gộp với các tên biến viết ngăn cách bởi dấu , Ví dụ: struct ngaythang ngaydi, ngayden; • Có thể kết hợp khai báo và khởi tạo giá trị cho biến cấu trúc Ví dụ: struct ngaythang ngaysinh = {12,10,1988}; 36
  37. Khai báo biến cấu trúc (2) • Có thể kết hợp việc định nghĩa kiểu cấu trúc với khai báo biến cấu trúc theo cú pháp: struct tên_kiểu_cấu_trúc { khai_báo_các_thành_phần_trong_cấu_trúc; } tên_biến_cấu_trúc1, tên_biến_cấu_trúc2, ; Ví dụ: struct ngaythang {int ngay; int thang; int nam;} ngaydi,ngayden; 37
  38. Khai báo biến cấu trúc (3) • Có thể sử dụng cú pháp sau để khai báo các biến cấu trúc: (bỏ tên_kiểu_cấu_trúc) struct { khai_báo_các_thành_phần_trong_cấu_trúc; } tên_biến_cấu_trúc1, tên_biến_cấu_trúc2, ; Chỉ khai báo các biến cấu trúc, không định nghĩa kiểu cấu trúc Ví dụ: struct {int ngay; int thang; int nam;} ngaydi,ngayden; 38
  39. Lưu ý • Có thể sử dụng cú pháp typedef để định nghĩa kiểu cấu trúc: typedef struct { khai_báo_các_thành_phần_trong_cấu_trúc; } tên_kiểu_cấu_trúc; Khi đó, cú pháp khai báo biến cấu trúc sẽ là: tên_kiểu_cấu_trúc tên_biến_cấu_trúc; Ví dụ: typedef struct {int ngay; int thang; int nam;} ngaythang; Khai báo biến ngaysinh: ngaythang ngaysinh; 39
  40. Truy nhập đến các thành phần của cấu trúc • Cú pháp: tên_cấu_trúc.tên_thành_phần Ví dụ: printf("%d",ngaysinh.ngay); ngaydi.ngay = ngayden.ngay+2; ngaydi.thang = 12; 40
  41. Mảng cấu trúc • Có thể khai báo một mảng gồm các phần tử thuộc một kiểu cấu trúc đã được định nghĩa trước đó Ví dụ: struct ngaythang ngaythuephong[10]; ngaythuephong là một mảng có 10 phần tử. Mỗi phần tử là một cấu trúc kiểu ngaythang • Lưu ý: Khi nhập dữ liệu cho mỗi phần tử trong mảng cấu trúc, cần nhập dữ liệu cho từng thành phần trong cấu trúc 41
  42. Phép gán cấu trúc (1) • Khi các biến cấu trúc và các phần tử của mảng cấu trúc là cùng kiểu với nhau, có thể thực hiện các phép gán giá trị: - Gán giá trị của biến cấu trúc này cho một biến cấu trúc khác - Gán giá trị của biến cấu trúc cho phần tử mảng cấu trúc và ngược lại - Gán giá trị của phần tử mảng cấu trúc này cho phần tử mảng cấu trúc khác Mỗi phép gán cấu trúc tương đương với một dãy phép gán các thành phần tương ứng cho nhau 42
  43. Phép gán cấu trúc (2) • Ví dụ: Khai báo: struct ngaythang ngay1,ngay2,ngaythue [10],ngaytra[10]; Các phép gán sau đều là hợp lệ: ngay1 = ngay2; ngaythue[0] = ngay1; ngay2 = ngaytra[0]; ngaythue[0] = ngaytra[0]; 43
  44. Ví dụ (1) • Chương trình nhập/hiển thị danh sách n cán bộ: #include int main(void) { struct canbo { char macb[6]; char hoten[30]; char mapb[6]; }; struct canbo dscb[50]; int i,n; printf("Nhap so can bo n = ");scanf("%d",&n); 44
  45. Ví dụ (2) for(i=0;i<n;i++) { printf("Nhap can bo thu %d\n",i); fflush(stdin); printf("Ma can bo: ");gets(dscb[i].macb); printf("Ho ten: ");gets(dscb[i].hoten); printf("Ma pb: ");gets(dscb[i].mapb); } printf("Danh sach can bo vua nhap la:\n"); for(i=0;i<n;i++) printf("%-6s %-30s %-6s\n", dscb[i].macb,dscb[i].hoten,dscb[i].mapb); return 0; } 45