Chương 4 Hàm
6.7. Truyền tham số là con trỏ
Ngoài hai phương pháp truyền dữ liệu vào trong hàm đã được giới thiệu trong Mục 4.5, truyền tham số là giá trị và truyền tham số là tham chiếu tới đối số, C++ còn cho phép ta sử dụng phương pháp thứ ba: truyền tham số là con trỏ. Trong Hình 6.7, biến con trỏ courses được truyền vào hàm getMark và
calculateMark. Dẫn đến tham số hình thức của hàm getMark và
#include <iostream> using namespace std;
void getMark (int *courses, int numberCourses) {
for (int count = 0; count < numberCourses; count++) {
cout << "Enter the mark of course # " << count << ": "; cin >> courses[count];
} }
int calculateMark (const int *courses, int numberCourses) {
int totalMark = 0;
for (int count = 0; count < numberCourses; count++) totalMark += courses[count];
return totalMark; }
int main(int argc, char *argv[]) {
int numberCourses;
cout << "Enter the number of courses: "; cin >> numberCourses;
int *courses;
courses = new int[numberCourses]; getMark (courses, numberCourses);
int totalMark = calculateMark (courses, numberCourses); cout << "Total mark: " << totalMark << endl;
delete courses; return 0; }
Hình 6.7: Tham số của hàm là con trỏ.
Trong những trường hợp ta muốn dùng con trỏ để truyền lượng lớn dữ liệu vào hàm nhưng lại không muốn cho hàm sửa đổi dữ liệu, ta có thể dùng từ khóa
const để thiết lập quyền của hàm đối với tham số. Xem ví dụ hàm
int calculateMark (const int *courses, int numberCourses)
quy định rằng hàm calculate phải coi dữ liệu int mà courses trỏ tới là hằng và không được phép sửa đổi.
Về cách sử dụng từ khóa const khi khai báo một biến con trỏ, ta có 4 lựa chọn: 1. không quy định con trỏ hay dữ liệu được trỏ tới là hằng
float * ptr;
2. quy định dữ liệu được trỏ tới là hằng, con trỏ thì được sửa đổi. const float * const ptr;
3. quy định dữ liệu trỏ tới không phải là hằng, nhưng biến con trỏ thì là hằng
float * const ptr;
4. quy định cả con trỏ lẫn dữ liệu nó trỏ tới đều là hằng. const float * const ptr;
Sử dụng const cho những hồn cảnh thích hợp là một phần của phong cách lập trình tốt. Nó giúp giảm quyền hạn của hàm xuống tới mức vừa đủ, chẳng hạn một hàm chỉ có chức năng đọc và tính tốn dữ liệu thì khơng nên có quyền sửa dữ liệu, từ đó giảm nguy cơ của hiệu ứng phụ không mong muốn.
Một điểm quan trọng cần lưu ý là tình trạng con trỏ có giá trị null hoặc khơng xác định do chưa gán bằng địa chỉ của biến nào. Nếu con trỏ ptr có giá trị null hoặc khơng xác định thì việc truy nhập *ptr sẽ dẫn đến lỗi run-time hoặc lỗi lơ- gic cho chương trình. Ta cần chú ý khởi tạo giá trị của các biến con trỏ và kiểm tra giá trị trước khi truy nhập. Ngồi ra, cịn có một lời khuyên là nên sử dụng tham chiếu thay cho con trỏ bất cứ khi nào có thể.
Bài tập
1. Trình bày sự khác biệt, ưu điểm, nhược điểm giữa biến tĩnh và biến động. 2. Tính giá trị của apples, *ptrApp, *ptrApp2 của đoạn mã sau:
int apples;
int *ptrApp = &apples; int *ptrApp2 = ptrApp; apples += 2;
*ptrApp --; *ptrApp2 += 3;
3. Xác định kết quả của đoạn mã sau:
int *p1 = new int; int *p2; *p1 = 5; p2 = p1; cout << "*p1 = " << *p1 << endl; cout << "*p2 = " << *p2 << endl; *p2 = 10; cout << "*p1 = " << *p1 << endl; cout << "*p2 = " << *p2 << endl; p1 = new int; *p1 = 20; cout << "*p1 = " << *p1 << endl; cout << "*p2 = " << *p2 << endl;
4. Nhập từ bàn phím vào một danh sách các số nguyên. Hãy sử dụng cấu trúc mảng động để lưu giữ dãy số nguyên này và tìm số lượng số nguyên chia hết cho số nguyên đầu tiên trong dãy.
5. Trình bày mối quan hệ giữa mảng và con trỏ.
6. Phân tích sự khác biệt, nhược điểm, ưu điểm của việc sử dụng mảng động và mảng tĩnh.
7. Sử dụng cấu trúc mảng động để lưu giữ một danh sách tên các sinh viên nhập vào từ bàn phím. Hãy sắp xếp danh sách tên sinh viên tăng dần theo
8. Một bàn cờ có kích thước m*n ô vuông. Trạng thái trên mỗi ô vuông được biểu diễn bởi một kí tự in thường từ ‘A’ đến ‘Z’. Sử dụng mạng động hai chiều để lưu giữ trạng thái của bàn cờ nhập từ bàn phím. Tìm và hiện ra màn hình:
• Các hàng thỏa mãn điều kiện tất cả các ô cùng một trạng thái • Các cột thỏa mãn điều kiện tất cả các ô cùng một trạng thái