Lập trình nâng cao - Bài 5: Mảng

pdf 51 trang vanle 1940
Bạn đang xem 20 trang mẫu của tài liệu "Lập trình nâng cao - Bài 5: Mảng", để 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:

  • pdflap_trinh_nang_cao_bai_5_mang.pdf

Nội dung text: Lập trình nâng cao - Bài 5: Mảng

  1. Bài 5: Mảng Giảng viên: Hoàng Thị Điệp Khoa Công nghệ Thông tin – ĐH Công Nghệ
  2. Chapter 5 Arrays Copyright © 2010 Pearson Addison-Wesley. All rights reserved
  3. Mục tiêu bài học • Giới thiệu mảng – Khai báo và tham chiếu mảng – Lệnh lặp for và mảng – Mảng trong bộ nhớ • Mảng và hàm – Hàm có đối số là mảng – Hàm có giá trị trả về là mảng • Lập trình với mảng – Mảng chưa đầy (Partially Filled Arrays) – Tìm kiếm, sắp xếp • Mảng nhiều chiều DTH INT2202
  4. Giới thiệu mảng • Định nghĩa mảng: – Tập hợp các phần tử dữ liệu cùng kiểu • Đây là kiểu dữ liệu “nhóm” đầu tiên ta học – int, float, double, char là những kiểu dữ liệu đơn • Dùng biểu diễn danh sách các phần tử giống nhau – Danh sách điểm thi, nhiệt độ, tên, – Tránh khai báo nhiều biến đơn – Có thể thao tác với “danh sách” này như với một thực thể DTH INT2202
  5. Khai báo mảng • Khai báo mảng cấp phát bộ nhớ int score[5]; – Khai báo mảng 5 số nguyên, có tên là "score" – Tương tự như khai báo 5 biến: int score[0], score[1], score[2], score[3], score[4] • Mỗi cá thể trong mảng được gọi bằng rất nhiều tên: – Biến được đánh chỉ mục hoặc chỉ số – “Phần tử" của mảng – Giá trị trong cặp ngoặc vuông gọi là chỉ số • Miền giá trị từ 0 tới size - 1 DTH INT2202
  6. Truy cập mảng • Phép truy cập sử dụng chỉ số – cout << score[3]; • Lưu ý cách dùng cặp ngoặc vuông: – Trong lệnh khai báo, nó chỉ định kích thước của mảng – Ở những nơi khác, nó xác định chỉ số • Kích thước và chỉ số không nhất thiết phải là giá trị hằng – int score[MAX_SCORES]; – score[n+1] = 99; • Nếu n là 2, tương đương với score[3] DTH INT2202
  7. Sử dụng mảng • Cơ chế mạnh dùng cho lưu trữ • Có thể thực hiện những công việc như: – “Làm việc này với biến có chỉ số thứ i" trong đó i được tính bởi chương trình – “Hiển thị tất cả các phần tử của mảng score" – “Điền cho mảng score dữ liệu người dùng nhập vào" – “Tìm giá trị lớn nhất trong mảng score" – “Tìm giá trị nhỏ nhất trong mảng score" DTH INT2202
  8. Ví dụ chương trình dùng mảng: Display 5.1 Chương trình dùng mảng (1/2) DTH INT2202
  9. Ví dụ chương trình dùng mảng: Display 5.1 Chương trình dùng mảng (2/2) DTH INT2202
  10. Lệnh lặp for và mảng • for là lệnh lặp đếm tự nhiên – Có thể khảo sát lần lượt các phần tử trong mảng • Ví dụ: for (idx = 0; idx<5; idx++) { cout << score[idx] << "off by " << max – score[idx] << endl; } – Biến điều khiển vòng lặp (idx) đếm từ 0 – 5 DTH INT2202
  11. Lỗi lớn khi dùng mảng • Các chỉ số của mảng luôn bắt đầu từ 0 • 0 là con số “đầu tiên” với người làm công nghệ thông tin • C++ sẽ “cho phép” bạn vượt ra ngoài miền này – Kết quả là không đoán trước được – Trình biên dịch sẽ không phát hiện ra những lỗi này! • Lập trình viên phải tự kiểm soát “miền” của chỉ số DTH INT2202
  12. Ví dụ về lỗi lớn khi dùng mảng • Miền chỉ số từ 0 tới (array_size – 1) – Ví dụ: double temperature[24]; // cỡ của mảng là 24 // Khai báo mảng 24 giá trị double có tên là temperature • Chúng được đánh chỉ số là: temperature[0], temperature[1] temperature[23] – Lỗi thường gặp: temperature[24] = 5; • Chỉ số 24 nằm ngoài miền! • Không có cảnh báo, kết quả có thể rất tàn khốc DTH INT2202
  13. Dùng hằng có tên chỉ định kích thước mảng • Hãy dùng hằng có tên để chỉ định kích thước mảng • Ví dụ: const int NUMBER_OF_STUDENTS = 5; int score[NUMBER_OF_STUDENTS]; • Dễ đọc hơn • Linh hoạt hơn • Dễ bảo trì hơn DTH INT2202
  14. Dùng hằng có tên • Dùng ở mọi nơi cần tới kích thước của mảng – Khi duyệt vòng lặp for: for (idx = 0; idx < NUMBER_OF_STUDENTS; idx++) { // Thao tác với mảng } – Trong các phép tính liên quan kích thước: lastIndex = (NUMBER_OF_STUDENTS – 1); – Khi truyền mảng vào hàm (sẽ bàn sau) • Nếu kích thước thay đổi chỉ cần sửa mã nguồn ở một nơi trong chương trình! DTH INT2202
  15. Mảng trong bộ nhớ • Nhắc lại: Những biến đơn – được cấp phát bộ nhớ bằng một “địa chỉ” • Khai báo mảng cấp phát bộ nhớ cho toàn bộ mảng • Cấp phát tuần tự – Nghĩa là các địa chỉ được cấp phát liền kề nhau – Có thể làm phép tính trên chỉ số • “Phép cộng” đơn giản từ địa chỉ đầu mảng (chỉ số 0) DTH INT2202
  16. Một mảng trong bộ nhớ DTH INT2202
  17. Khởi tạo mảng • Các biến đơn có thể khởi tạo lúc khai báo: int price = 0; // 0 là giá trị khởi tạo • Cũng có thể làm vậy với mảng: int children[3] = {2, 12, 1}; – Tương đương với: int children[3]; children[0] = 2; children[1] = 12; children[2] = 1; DTH INT2202
  18. Mảng khởi tạo tự động • Nếu số giá trị khởi tạo bạn cung cấp ít hơn kích thước mảng: – Chương trình sẽ điền các giá trị này từ đầu mảng – Điền “phần còn lại” với giá trị 0 của kiểu dữ liệu chỉ định cho mảng • Nếu không chỉ định cỡ của mảng – Khai báo mảng với cỡ đủ để chứa các giá trị khởi tạo – Ví dụ: int b[] = {5, 12, 11}; • Cấp phát mảng b cỡ là 3 DTH INT2202
  19. Mảng và hàm • Mảng là đối số – Các biến được đánh chỉ số • Mỗi phần tử đơn lẻ trong mảng có thể là một tham số hàm – Toàn bộ mảng • Tất cả các phần tử trong mảng có thể được truyền như “một thực thể” • Mảng là giá trị trả về – Có thể làm được việc này xem chương 10 giáo trình DTH INT2202
  20. Biến đánh chỉ số làm đối số • Ta x ử lý biến đánh chỉ số giống như các biến đơn cùng kiểu với mảng • Cho khai báo hàm: void myFunction(double par1); • Và những khai báo: int i; double n, a[10]; • Ta có thể có những lời gọi sau: myFunction(i); // i được chuyển thành kiểu double myFunction(a[3]);// a[3] có kiểu double myFunction(n); // n có kiểu double DTH INT2202
  21. Khéo léo trong việc dùng chỉ số • Xem xét các lời gọi: myFunction(a[i]); – Giá trị của i được xác định trước • Chương trình quyết định xem biến đánh chỉ số nào sẽ được truyền vào hàm myFunction(a[i*5]); – Hoàn toàn hợp lệ từ góc nhìn của trình biên dịch – Lập trình viên chịu trách nhiệm giữ chỉ số trong miền có nghĩa DTH INT2202
  22. Mảng làm đối số • Tham số hình thức có thể là một mảng – Đối số trong lời gọi hàm sẽ là một tên mảng – Gọi là tham số mảng • Hãy truyền cả kích cỡ của mảng – Thường là tham số thứ 2 – Có thể viết đơn giản là tham số hình thức kiểu int DTH INT2202
  23. Ví dụ mảng làm đối số: Display 5.3 Hàm với một tham số mảng DTH INT2202
  24. Ví dụ mảng làm đối số • Xét ví dụ ở slide trước: • Trong định nghĩa main() nào đó, xem xét những lời gọi sau: int score[5], numberOfScores = 5; fillUp(score, numberOfScores); – Đối số thứ nhất là một mảng – Đối số thứ 2 là một giá trị nguyên – Lưu ý không có cặp ngoặc vuông trong đối số mảng! DTH INT2202
  25. Mảng làm đối số: Chi tiết các bước • Cái gì thực sự được truyền vào? • Tưởng tượng mảng có 3 “phần” – Địa chỉ của biến đánh chỉ số đầu tiên (arrName[0]) – Kiểu của mảng – Kích thước của mảng • Chỉ có một “phần” được truyền vào hàm! – Là địa chỉ bắt đầu mảng – Rất giống với việc truyền tham chiếu DTH INT2202
  26. Tham số mảng • Có vẻ khác lạ – Không có ngoặc vuông trong đối số mảng – Phải truyền kích thước riêng biệt • Một tính chất hữu ích: – Có thể dùng cùng một hàm để điền dữ liệu cho bất cứ kích cỡ mảng nào! – Là ví dụ điển hình cho tính chất dùng lại của hàm – Ví dụ: int score[5], time[10]; fillUp(score, 5); fillUp(time, 10); DTH INT2202
  27. Tham số const • Nhắc lại: tham số mảng thực sự truyền địa chỉ của phần tử đầu tiên – Tương tự với việc truyền tham chiếu • Hàm do đó có thể biến đổi dữ liệu trong mảng! – Thường là trong tình huống mong đợi, đôi khi không! • Khi cần bảo vệ nội dung của mảng khỏi việc biến đổi không mong muốn này – Hãy dùng từ khóa "const" trước tham số mảng • Gọi là “tham số mảng hằng” • Báo cho trình biên dịch “ngăn” các biến đổi DTH INT2202
  28. Hàm trả về một mảng • Hàm không thể trả về mảng theo cách thức nó trả về giá trị cho biến đơn • Cần dùng một “con trỏ” • Được thảo luận trong chương 10 giáo trình DTH INT2202
  29. Lập trình với mảng • Nhiều ứng dụng – Mảng không đầy • Phải khai báo “kích thước tối đa” – Sắp xếp – Tìm kiếm DTH INT2202
  30. Mảng không đầy • Rất khó biết chính xác ta cần bao nhiêu phần tử mảng • Phải khai báo một mảng với cỡ lớn nhất có thể cần – Phải theo dõi phần nào của mảng chứa dữ liệu hợp lệ – Cần thêm một biến lưu thông tin này • int numberUsed; • Lưu số phần tử hợp lệ hiện thời trong mảng DTH INT2202
  31. Ví dụ mảng không đầy: Display 5.5 Mảng không đầy (1/5) DTH INT2202
  32. Ví dụ mảng không đầy: Display 5.5 Mảng không đầy (2/5) DTH INT2202
  33. Ví dụ mảng không đầy: Display 5.5 Mảng không đầy (3/5) DTH INT2202
  34. Ví dụ mảng không đầy: Display 5.5 Mảng không đầy (4/5) DTH INT2202
  35. Ví dụ mảng không đầy: Display 5.5 Mảng không đầy (5/5) DTH INT2202
  36. So sánh: Hằng toàn cục và tham số • Hằng thường được khai báo “toàn cục” – Phía trên định nghĩa main() • Do đó, khi bạn khai báo kích thước mảng là hằng toàn cục, hàm có quyền truy cập tới thông tin đó – Liệu có cần truyền thêm tham số kích thước? • Về lý thuyết: có – Vì sao ta vẫn nên có tham số kích thước? • Định nghĩa hàm có thể nằm ở một tệp riêng biệt • Hàm có thể được dùng bởi chương trình khác! DTH INT2202
  37. Tìm kiếm trên mảng • Là ứng dụng rất hay gặp của mảng • Xem Display 5.6 ở slide sau DTH INT2202
  38. Display 5.6 Tìm kiếm trên mảng (1/4) DTH INT2202
  39. Display 5.6 Tìm kiếm trên mảng (2/4) DTH INT2202
  40. Display 5.6 Tìm kiếm trên mảng (3/4) DTH INT2202
  41. Display 5.6 Tìm kiếm trên mảng (4/4) DTH INT2202
  42. Sắp xếp một mảng: Display 5.7 Sắp xếp lựa chọn • Thuật toán sắp xếp lựa chọn DTH INT2202
  43. Ví dụ sắp xếp mảng: Display 5.8 Sắp xếp mảng (1/4) DTH INT2202
  44. Ví dụ sắp xếp mảng: Display 5.8 Sắp xếp mảng (2/4) DTH INT2202
  45. Ví dụ sắp xếp mảng: Display 5.8 Sắp xếp mảng (3/4) DTH INT2202
  46. Ví dụ sắp xếp mảng: Display 5.8 Sắp xếp mảng (4/4) DTH INT2202
  47. Mảng nhiều chiều • Là mảng có nhiều hơn một chỉ số – char page[30][100]; • Hai chỉ số. Đây là một mảng của các mảng một chiều. • Có thể minh họa như sau: page[0][0], page[0][1], , page[0][99] page[1][0], page[1][1], , page[1][99] page[29][0], page[29][1], , page[29][99] • C++ cho phép số lượng chỉ số bất kì – Thường thì không quá hai DTH INT2202
  48. Tham số mảng nhiều chiều • Tương tự với mảng một chiều – Bỏ qua kích thước chiều thứ nhất • Truyền vào dưới dạng một tham số riêng – Chỉ định kích thước chiều thứ hai • Ví dụ: void DisplayPage(const char p[][100], int sizeDimension1) { for (int index1=0; index1<sizeDimension1; index1++) { for (int index2=0; index2 < 100; index2++) cout << p[index1][index2]; cout << endl; } } DTH INT2202
  49. Tóm tắt 1 • Mảng là một tập hợp các phần tử dữ liệu cùng kiểu • Các biến đánh chỉ số hợp thành mảng được dùng như các biến đơn khác • Lệnh lặp for cho ta cách “tự nhiên”để duyệt mảng • Lập trình viên có trách nhiệm kiểm soát miền giá trị của chỉ số • Tham số mảng là “một kiểu mới” – Tương tự như truyền tham chiếu DTH INT2202
  50. Tóm tắt 2 • Các phần tử của mảng được lưu trữ tuần tự – Các phần bộ nhớ cận kề nhau – Chỉ có địa chỉ của phần tử đầu tiên được truyền vào hàm • Hàm không đầy Cần kiểm soát nhiều hơn • Dùng từ khóa const với tham số mảng – Ngăn chặn việc biến đổi nội dung của mảng • Mảng nhiều chiều – Tạo ra mảng của mảng DTH INT2202
  51. Chuẩn bị bài tới • Đọc chương 5 giáo trình: struct và class DTH INT2202