Giáo trình Ngôn ngữ lập trình C++ (Phần 1)
Ngôn ngữ lập trình C do Dennis Ritchie và Brian Kernighan xây dựng
năm 1970, thể hiện đ-ợc tất cả các đặc tr-ng của ngôn ngữ lập trình bậc cao
nh-ng cũng có khá đầy đủ các khả năng của ngôn ngữ lập trình bậc thấp.
Cùng với sự phát triển mạnh mẽ của công nghệ thông tin (CNTT), ngôn
ngữ C có rất nhiều phiên bản của các hãng khác nhau nh-C chuẩn, Turbo C,
Microsoft C . Sau ngôn ngữ C là C++ ngoài các tính năng nh-C, C++ còn
đ-ợc bổ sung nhiều tính năng khác, một trong đó làkỹ thuật lập trình h-ớng
đối t-ợng, một h-ớng lập trình rất quan trọng.
ào i”. Câu lệnh (4): j = *p; đ−a vào j nội dung của biến đ−ợc p trỏ tới (* là toán tử chỉ h−ớng). Câu lệnh (5): *p = j + 4; đ−a (nội dung của j) + 4 vào biến đ−ợc p trỏ vào. Ví dụ ch−ơng trình 5.1: Ch−ơng trình hoàn thiện sa giải thích ở trên, nh−ng chú ý là các địa chỉ thực của giả thiết đã nêu trong nhận xét trên. 14 100 p 00 9 i 14 100 p 00 5 i 14 p 00 5 i 14 p 00 5 i 00 i 02 5 j 14 100 p u sẽ minh hoạ cho các i, j , p ở hệ 16 và khác 45 Đại học Thái Nguyên-Tr−ờng ĐHSP. Khoa Toán-Tin Nguyễn Mạnh Đức – Ngôn ngữ lập trình C++ # include # include void main() { int i, j, *p; i = 5; p = &i; j = *p; *p = j + 4; clrscr(); cout << "i = " << i << " dia chi = " << &i << endl; cout << "j = " << j << " dia chi = " << &j << endl; cout << "p tro toi dia chi " << p << endl; cout << "p tro vao gia tri " << *p; getch(); } 5.1.5. Các phép toán con trỏ • Các giá trị con trỏ có thể xuất dữ liệu với toán tử chèn <<. • Các con trỏ không thể nhập dữ liệu. Nếu p là con trỏ thì lệnh nhập sau là sai: cin >> p; // Error • Các con trỏ có thể đ−ợc gán cho những con trỏ khác cùng kiểu. Ví dụ: float *px, *py, x; px = &x; py = px; • Các con trỏ có thể đ−ợc tăng hay giảm. Ví dụ: char st[] = “ABCDEFGH”; char p = &st[3]; // p trỏ tới st[3] cout << “*p = “ << *p << endl; ++p; // p trỏ tới st[4] cout << “*p = “ << *p << endl; p += 3; // p trỏ tới st[7] cout << “*p = “ << *p << endl; p -=6; // p trỏ tới st[1] 46 Đại học Thái Nguyên-Tr−ờng ĐHSP. Khoa Toán-Tin Nguyễn Mạnh Đức – Ngôn ngữ lập trình C++ cout << “*p = “ << *p << endl; --p; // p trỏ tới st[0] cout << “*p = “ << *p << endl; Kết quả của đoạn ch−ơng trình trên sẽ là: *p = D *p = E *p = H *p = B *p = A 5.2. Con trỏ và mảng 5.2.1. Con trỏ và mảng một chiều Con trỏ th−ờng đ−ợc sử dụng khi xử lý các mảng. Chúng ta phân tích ch−ơng trình 5.2 sau đây: void main() { int a[10], *pa, x; a[0] = 11; a[1] = 22; a[2] = 33; a[3] = 44; pa = &a[0]; x = *pa; pa++; x = *pa; x = *pa + 1; x = *(pa + 1); x = *++pa; x = ++*pa; x = *pa++; getch(); } int a[10], *pa, x; Khai báo mảng 10 số nguyên a[0], a[1], ... a[9], con trỏ pa chỉ vào số nguyên và biến nguyên x. a[0] = 1; ... khởi đầu các phần tử của mảng. Các phần tử từ a[4] tới a[9] còn ch−a đ−ợc khởi đầu, chúng tình cờ chứa các giá trị có sẵn trong bộ nhớ. pa = &a[0]; Đ−a địa chỉ của phần tử đầu tiên của mảng a vào pa. Lệnh này có thể đ−ợc viết đơn giản hơn là: pa = a; 47 Đại học Thái Nguyên-Tr−ờng ĐHSP. Khoa Toán-Tin Nguyễn Mạnh Đức – Ngôn ngữ lập trình C++ x = *pa; Lấy nội dung của số nguyên đ−ợc pa trỏ vào (tức là a[0]) gán cho biến x. Do đó x có giá trị bằng 11. pa++; pa đ−ợc tăng một đơn vị, bây giờ nó chứa địa chỉ của phần tử thứ hai, đó là địa chỉ của a[1] tức là pa trỏ vào a[1]. x = *pa; *pa là nội dung của a[1], do đó x có giá trị băng 22. x = *pa + 1; Cho x giá trị a[1] + 1, do đó x có giá trị là 22 + 1 = 23. x = *(pa + 1); Tr−ớc tiên hệ thống thực hiện phép toán: pa + 1 điều đó cho kết quả là địa chỉ của a[2], số nguyên ở địa chỉ này đ−ợc đ−a vào x, do vậy x bằng 33. Chú ý rằng nếu pa tham gia vào phép toán nó không bị thay đổi. x = *++pa; Theo độ −u tiên của các toán tử, phép toán ++pa đ−ợc thực hiện tr−ớc, do đó pa chứa địa chỉ của a[2]. Sau đó thực hiện phép toán *, x chứa địa chỉ a[2] tức là x = 33. x = ++*pa; Đầu tiên thực hiện *pa, pa đang trỏ vào a[2] nên *pa bằng 33, do đó ++*pa bằng 34, do vậy x bằng 34. x = *pa++; Nội dung của *pa đ−ợc đặt vào biến x tr−ớc nên x bằng 34, sau đó pa đ−ợc tăng một đơn vị và bây giờ nó trỏ vào a[3]. Qua phân tích ví dụ trên ta thấy rằng: Nếu con trỏ pa trỏ tới phần tử a[k] nào đó thì: pa + i trỏ tới phần tử thứ i sau a[k], tức là phần tử a[k+i]. pa – i trỏ tới phần tử thứ i tr−ớc a[k], tức là phần tử a[k-i]. *(pa + i) t−ơng đ−ơng với pa[i]. 5.2.2. Con trỏ và mảng hai chiều Trong mảng nhiều chiều nói chung phép toán lấy địa chỉ & không sử dụng đ−ợc, chẳng hạn câu lệnh: 48 Đại học Thái Nguyên-Tr−ờng ĐHSP. Khoa Toán-Tin Nguyễn Mạnh Đức – Ngôn ngữ lập trình C++ &a[i][j]; là không hợp lệ và gây ra lỗi (riêng đối với mảng hai chiều nguyên thì có thể sử dụng đ−ợc câu lệnh trên). Nh− ta đã biết trong bộ nhớ mảng là các ô nhớ xếp theo thứ tự liên tiếp nhau, chẳng hạn nếu khai báo: float a[2][3]; thì sẽ có 6 phần tử đ−ợc xếp thứ tự (theo hàng) nh− sau: phần tử: a[0][0] a[0][1] a[0][2] a[1][0] a[1][1] a[1][2] địa chỉ : 1 2 3 4 5 6 Để lần l−ợt duyệt trên các phần tử của mảng hai chiều, có thể dùng con trỏ theo cách sau: float *pa, a[2][3]; pa = (float*) a; Khi đó: pa + 0 trỏ tới a[0][0] pa + 1 trỏ tới a[0][1] pa + 2 trỏ tới a[0][2] pa + 3 trỏ tới a[1][0] pa + 4 trỏ tới a[1][1] pa + 5 trỏ tới a[1][2] Ví dụ ch−ơng trình 5.3 sau đây sẽ minh hoạ cho các điều trên. # include # include void main() { float *pa, a[2][3] = {{ 1, 3, 5 }, { 2, 4, 6 }}; pa = (float*) a; clrscr(); for (int i=0; i<6; i++) cout << pa+i << " " << *(pa+i) << endl; getch(); } 49 Đại học Thái Nguyên-Tr−ờng ĐHSP. Khoa Toán-Tin Nguyễn Mạnh Đức – Ngôn ngữ lập trình C++ 5.2.3. Mảng con trỏ Mảng con trỏ là sự mở rộng của khái niệm con trỏ. Mảng con trỏ là một mảng mà mỗi phần tử của nó có thể chứa đ−ợc một địa chỉ nào đó. Cũng giống nh− con trỏ, mảng con trỏ có nhiều kiểu, mỗi phần tử của nó chứa đ−ợc các địa chỉ kiểu t−ơng ứng. Mảng con trỏ đ−ợc khai báo nh− sau: type *name[N]; Trong đó type là kiểu có thể là: int, float, double, char ..., name là tên của mảng, N là hằng số nguyên chỉ độ lớn của mảng. Khi gặp khai báo trên, máy sẽ cấp phát N khoảng nhớ liên tiếp cho N phần tử của mảng. Mỗi phần tử name[i] sẽ l−u trữ một địa chỉ theo kiểu đã khai bái. Ví dụ ch−ơng trình 5.4: Tìm tên trên mảng con trỏ. # include # include # include # define max 5 void find(char *name) { char *list[max] = { "Lan", "Nam", "Hung", "Tien", "Van" }; char ok = 0; for (int i=0; i<max; i++) if (strcmp(list[i], name) == 0) ok = 1; if (ok == 1) cout << "\nBan da co trong danh sach."; else cout << "\nBan chua co trong danh sach."; } void main() { char ten[7]; clrscr(); cout > ten; find(ten); getch(); } 50 Đại học Thái Nguyên-Tr−ờng ĐHSP. Khoa Toán-Tin Nguyễn Mạnh Đức – Ngôn ngữ lập trình C++ 5.3. Hàm có đối con trỏ Nếu đối của hàm là con trỏ kiểu int (float, double ...) thì tham số thực t−ơng ứng phải là địa chỉ của biến hoặc địa chỉ của phần tử mảng kiểu int (float, double ...). Ví dụ ch−ơng trình 5.5: Xây dựng ch−ơng trình hoán vị hai số bằng cách sử dụng đối con trỏ. # include # include void hoan_vi(int *x, int *y) { int z; z = *x; *x = *y; *y = z; } void main() { int a =5 ,b = 10; clrscr(); hoan_vi(&a, &b); cout << "\na = " << a ; cout << "\nb = " << b; getch(); } 5.4. Con trỏ tới hàm Con trỏ hàm dùng để chứa địa chỉ của hàm. Muốn vậy ta phải thực hiện phép gán tên hàm cho con trỏ hàm. Để phép gán có nghĩa thì kiểu hàm và kiểu con trỏ phải t−ơng thích nhau. Sau phép gán, ta có thể dùng tên con trỏ thay cho tên hàm. Ví dụ ch−ơng trình 5.6: Xây dựng ch−ơng trình tìm số lớn hơn bằng cách sử dụng con trỏ hàm. # include double fmax(double x, double y) // ham tinh max { return (x>y ? x:y); } // khai bao con tro ham double (*pf)(double, double) = fmax; void main() { cout << "\nmax = " << pf(5.5, 99.75); } 51 Đại học Thái Nguyên-Tr−ờng ĐHSP. Khoa Toán-Tin Nguyễn Mạnh Đức – Ngôn ngữ lập trình C++ 5.5. Con trỏ void Con trỏ void là một dạng đặc biệt của khái niệm con trỏ, đó là con trỏ không có kiểu và nó có thể nhận bất kỳ kiểu địa chỉ nào. Con trỏ void th−ờng đ−ợc dùng để làm đối trong các hàm, để nhận bất kỳ kiểu địa chỉ nào từ tham số thật, vì thế trong thân hàm phải dùng phép quy hồi kiểu để chuyển sang dạng địa chỉ cần xử lý. Ví dụ ch−ơng trình 5.7: Xây dựng ch−ơng trình nhập các ma trận rồi tính tổng của chúng. # include # include # include const N = 50; void NHAP(char name, float *a, int n, int m); void INRA(float *a, int n, int m); void CONG(void *a, void *b, void *c, int n, int m); void FORMAT(int n); // qui dinh so chu so thap phan void main() { float x[N][N], y[N][N], z[N][N]; int n = 3, m = 4; // so hang, cot thuc te cua MT clrscr(); NHAP('x', *x, n, m); NHAP('y', *y, n, m); CONG(*x, *y, *z, n, m); clrscr(); FORMAT(3); cout << "\nMa tran X:"; INRA(*x, n, m); cout << "\nMa tran Y:"; INRA(*y, n, m); cout << "\nMa tran tong X + Y:"; INRA(*z, n, m); getch(); } void NHAP(char name, float *a, int n, int m) { cout << "\n"; for (int i=0; i<n; i++) for (int j=0; j<m; j++) 52 Đại học Thái Nguyên-Tr−ờng ĐHSP. Khoa Toán-Tin Nguyễn Mạnh Đức – Ngôn ngữ lập trình C++ 53 { cout<<name<<"["<<i+1<<"]["<<j+1<<"] = "; cin >> *(a+i*m+j); } } void INRA(float *a, int n, int m) { for (int i=0; i<n; i++) { cout << "\n"; for (int j=0; j<m; j++) cout << setw(12) << *(a+i*m+j); } } void CONG(void *a, void *b, void *c, int n, int m) { float *pa, *pb, *pc; // quy hoi kieu pa=(float*)a; pb=(float*)b; pc=(float*)c; for (int i=0; i<n; i++) for (int j=0; j<m; j++) *(pc+i*m+j) = *(pa+i*m+j) + *(pb+i*m+j); } void FORMAT(int n) { cout << setprecision(n) << setiosflags(ios::fixed); cout.setf(ios::showpoint); }
File đính kèm:
- Giáo trình Ngôn ngữ lập trình C++ (Phần 1).pdf