Báo cáo khoa học: "một số ứng dụng của con trỏ trong c và C++" pps

5 594 2
Báo cáo khoa học: "một số ứng dụng của con trỏ trong c và C++" pps

Đang tải... (xem toàn văn)

Thông tin tài liệu

một số ứng dụng của con trỏ trong c v C++ PGS. TS. Phạm văn ất Khoa Công nghệ thông tin - Trờng ĐH GTVT Tóm tắt: Bi báo ny trình bầy một số ứng dụng của con trỏ trong các vấn đề quan trọng v lý thú sau đây của C/C++: + Xây dựng hm với số đối bất định + Xây dựng toán tử gán cho lớp dẫn xuất + Sử dụng hiệu quả các vùng nhớ Summary: In this paper, we will present some applications of the pointer in the important and interesting problems of C/C++ such as: + Creating functions with variable argument lists. + Creating assignment operator for derived classes. + Using the memories efficiently 1. Hm với đối số bất định Nh đã biết, trong các giáo trình C/C++ thờng chỉ hớng dẫn cách xây dựng hàm với một số cố định các đối. Mỗi đối cần có một tham số (cùng kiểu với nó) trong lời gọi hàm. Tuy nhiên một vài hàm chuẩn của C lại không nh vậy, mà linh hoạt hơn, chẳng hạn khi dùng hàm printf hay scanf thì số tham số mà ta cung cấp cho hàm là không cố định cả về số lợng lẫn kiểu cách. Ví dụ trong câu lệnh: printf(\n Tổng = %d , 3+4+5); có 2 tham số, nhng trong câu lệnh: printf(\n Hà Nội); chỉ có một tham số. Nh vậy cần phân biệt các khái niệm sau: Đối số cố định đợc khai báo trong dòng đầu của hàm, nó có tên và kiểu. Tham số ứng với đối số cố định gọi là tham số cố định. Các đối bất định đợc khai báo bởi ba dấu chấm: bất định cả về số lợng và kiểu. Các tham số bất định (ứng với các đối bất định) là một danh sách giá trị với số lợng và kiểu tuỳ ý (không xác định). Trong các mục 2 - 5 dới đây sẽ trình bầy cách xây dựng các hàm với đối số bất định. Công cụ chủ yếu đợc dùng là con trỏ và danh sách. ii. Biến con trỏ Biến con trỏ (hay con trỏ) dùng để chứa địa chỉ của biến, mảng, hàm, Có nhiều kiểu địa chỉ, vì vậy cũng có nhiều kiểu con trỏ. Biến con trỏ đợc khai báo theo mẫu: Kiểu *Tên_biến_con_trỏ ; Ví dụ: float *px ; /* px là con trỏ thực */ Các phép toán quan trọng trên con trỏ gồm: + Gán địa chỉ một vùng nhớ cho con trỏ (dùng toán tử gán, phép lấy địa chỉ, các hàm cấp phát bộ nhớ). + Truy nhập vào vùng nhớ mà địa chỉ của nó chứa trong con trỏ, dùng phép toán: *Tên_con_trỏ (Để ý ở đây có 2 vùng nhớ: Vùng nhớ của biến con trỏ và vùng nhớ mà địa chỉ đầu của nó chứa trong biến con trỏ). + Cộng địa chỉ để con trỏ chứa địa chỉ của phần tử tiếp theo, dùng phép toán: ++ Tên_con_trỏ hoặc Tên_con_trỏ ++ Chú ý rằng các phép toán trên chỉ có thể thực hiện đối với con trỏ có kiểu. iii. Danh sách không cùng kiểu Dùng con trỏ có kiểu chỉ quản lý đợc danh sách các giá trị cùng kiểu, ví dụ dẫy số thực, dẫy số nguyên, dẫy các cấu trúc, Khi cần quản lý một danh sách các giá trị không cùng kiểu ta phải dùng con trỏ không kiểu (con trỏ void) khai báo nh sau: void * Tên_con_trỏ ; Con trỏ void có thể chứa các địa chỉ có kiểu bất kỳ, và dùng để trỏ đến vùng nhớ chứa danh sách cần quản lý. Một chú ý quan trọng là mỗi khi gửi vào hay lấy ra một giá trị từ vùng nhớ, thì tuỳ theo kiểu giá trị mà ta phải dùng phép chuyển kiểu thích hợp đối với con trỏ. Ví dụ sau minh hoạ cách lập một danh sách gồm một số nguyên, một số thực và một chuỗi ký tự. Chúng ta cần một bộ nhớ để chứa số nguyên, số thực và địa chỉ chuỗi và dùng các con trỏ void để quản lý vùng nhớ này. void *list , *p ; /* Con trỏ list trỏ tới đầu danh sách */ /* p dùng để duyệt qua các phần tử của danh sách */ list = malloc(sizeof(int) + sizeof(float) + + sizef(char*) ); plist; *(int*)p) = 12; /* Đa số nguyên 12 vào danh sách */ ((int*)p)++ ; /* Chuyển sang phần tử tiếp theo */ *((float*)p) = 3.14; /* Đa số thực 3.14 vào danh sách */ ((float*)p)++ ; /* Chuyển sang phần tử tiếp theo */ *((char**)p) = HA NOI; /* Đa địa chỉ chuỗi HA NOI vào danh sách */ /* Nhận các phần tử của danh sách */ p=list; /* Về đầu danh sách */ int a = *((int*)p); /* Nhận phần tử thứ nhất */ ((int*)p)++ ; /* Chuyển sang phần tử tiếp theo */ float x= *((float*)p); /* Nhận phần tử thứ hai */ ((float*)p)++ ; /* Chuyển sang phần tử tiếp theo */ char *str = *((char**)p) ; /* Nhận phần tử thứ ba */ iv. Hm với đối số bất định + Các đối bất định bao giờ cũng đặt sau cùng và đợc khai báo bằng 3 dấu chấm. Ví dụ hàm: void f(int n, char *s, ) ; có 2 đối cố định là n, s và các đối bất định. + Để nhận đợc các tham số bất định trong lời gọi hàm ta cần lu ý các điểm sau: - Các tham số bất định chứa trong một danh sách. Để nhận đợc địa chỉ đầu danh sách ta dùng một con trỏ void và phép gán sau: void *list ; list = ; - Dùng một tham số cố định kiểu chuỗi để quy định số lợng và kiểu của mỗi tham số bất định trong danh sách, ví dụ: 3i hiểu là: danh sách gồm 3 tham số kiểu int. 5f hiểu là: danh sách gồm 5 tham số kiểu float. fissif hiểu là: danh sách gồm 6 tham số có kiểu lần lợt là float, int, char*, char*, int và float. Một khi đã biết đợc địa chỉ đầu danh sách, biết đợc số lợng và kiểu của mỗi tham số, thì dễ dàng nhận đợc giá trị các tham số để sử dụng trong thân hàm. Ví dụ sau đây minh hoạ cách xây dựng và sử dụng các hàm với tham số bất định. Hàm dùng để in các giá trị kiểu int, float và char. Hàm có một tham số cố định để cho biết có bao nhiêu giá trị và kiểu các giá trị cần in. Kiểu quy định nh sau: i là int, f là float, s là char*. Tham số này có 2 cách viết: lặp (gồm một hằng số nguyên và một chữ cái định kiểu) và liệt kê (một dẫy các chữ cái định kiểu). Ví dụ: 4s có nghĩa in 4 chuỗi. siif có nghĩa in một chuỗi, 2 giá trị nguyên và một giá trị thực. #include <stdio.h> #include <ctype.h> #include <string.h> #include <conio.h> #include <stdlib.h> #include <stdarg.h> void InDanhSachGiaTri(char *st, ) { void *list ; int gt_int ; float gt_float; char *gt_str; int n,i ; char kieu; int lap; list = ; /* list trỏ tới vùng nhớ chứa danh sách địa chỉ các tham số */ lap = isdigit(st[0]) ; if (lap) n=st[0] - '0' ; else n=strlen(st); for(i=0;i<n;++i) { if(lap) kieu=st[1]; else kieu = st[i]; switch(kieu) { case 'i' : gt_int = *((int*)list); ((int*)list)++ ; printf("\nGia tri %d = %d",i,gt_int); break; case 'f' : gt_float = (float) (*((double*)list)); ((double*)list)++ ; printf("\nGia tri %d = %0.2f",i,gt_float); break; case 's' : gt_str = *((char**)list) ; ((char**)list)++ ; printf("\nGia tri %d = %s",i,gt_str); } } } void main() { float x=3.14; int a=123, b=456, c=789; char *tp="NHA TRANG"; InDanhSachGiaTri("3i",a,b,c); InDanhSachGiaTri("2s","HANOI","NHA TRANG"); InDanhSachGiaTri("ifsssffii",a,x,tp,tp," QUY NHON",x,6.28,a,246); InDanhSachGiaTri("2f",6.28,x); getch(); } v. Hm không đối v hm với đối bất định Nhiều ngời nghĩ hàm khai báo nh sau: void f(); là hàm không đối trong C. Trong C++ thì hiểu nh thế là đúng, còn trong C thì đó là hàm có đối bất định (hàm không đối trong C khai báo nh sau: f(void) ). Do không có đối cố định nào cho biết về số lợng và kiểu của các tham số bất định, nên giải pháp ở đây là dùng các biến toàn bộ. Rõ ràng giải pháp này không thuận tiện cho ngời dùng vì phải khai báo đúng tên biến toàn bộ và phải khởi gán giá trị cho nó trớc khi gọi hàm. Ví dụ sau trình bầy một hàm chỉ có đối bất định dùng để tính max và min của các giá trị thực. Các tham số bất định đợc đa vào theo trình tự sau: Địa chỉ chứa max, địa chỉ chứa min, các giá trị thực cần tính max, min. Chơng trình dùng biến toàn bộ N để cho biết số giá trị thực cần tính max, min. int N; void maxmin() { void *lt = ; float *max, *min , tg; int i; max = *((float**)lt)++; min = *((float**)lt)++; *max = *min = (float) *((double*)lt)++; for(i=1;i<N;++i) { tg= (float) *((double*)lt)++; if(tg > *max) *max = tg; if(tg < *min) *min = tg; } } Sử dụng hm: Để tính max và min của các giá trị thực x, y, z ta dùng các câu lệnh: float smax, smin ; /* Dùng để chứa các giá trị max và min */ N = 3; /* Số giá trị cần tính max, min là 3 */ maxmin(&smax, &smin, x, y, z) ; /* Lời gọi hàm */ vi. cách xây dựng toán tử gán trong lớp dẫn xuất Trớc hết cần xây dựng toán tử gán cho lớp cơ sở (gọi là lớp A), sau đó để xây dựng toán tử gán cho lớp dẫn xuất (lớp B), có thể tiến hành theo 2 bớc: Bớc 1: Sử dụng phép gán của lớp cơ sở A để thực hiện việc gán trên các thuộc tính thừa kế. Muốn vậy cần sử dụng con trỏ this của lớp B và ép kiểu theo A để nhận đợc một đối tợng kiểu A. Điều này đợc thực hiện theo mẫu: A *p ; p = (A*)this ; *p = A::operator=(b) ; ở đây b (có kiểu B) là đối của toán tử gán của lớp B. Nhận xét: Có thể thay 3 câu lệnh trên bằng một câu lệnh sau: *(A*)this = A::operator=(b) ; Bớc 2: Thực hiện phép gán trên các thuộc tính của lớp dẫn xuất. Sau đây là ví dụ minh hoạ: class A { private: char *strA; public: const A & operator = (const A & a) { if(this->strA!=NULL) delete this->strA; this->strA= strdup(a.strA); return a; } } ; class B : public A { private: char *strB; public: const B & operator = (const B & b) { // Gán các thuộc tính thừa kế từ A *(A*)this = A::operator=(b) ; // Gán các thuộc tính của B if(this->strB!=NULL) delete this->strB; this->strB = strdup( b.strB); return b; } } ; vii. Truy nhập linh hoạt tới các vùng nhớ Để truy nhập tới một vùng nhớ có độ lớn tuỳ ý (giả sử 1000 byte), đầu tiên cần định nghĩa một kiểu con trỏ 1000 byte theo mẫu: typedef struct { char M[1000] ; } *MEM ; Sau đó dùng kiểu MEM để truy nhập tới các vùng nhớ 1000 byte. Ví dụ sau minh hoạ cách gán 2 hàng của ma trận chứa trong mảng 2 chiều: typedef struct { float M[100] ; } *MEM ; float a[100][100] , tg[100]; *(MEM)tg = *(MEM)(a+i) ; /* Gán hàng i vào tg */ *(MEM)(a+i) = *(MEM)(a+j) ; /* Gán hàng j vào hàng i */ *(MEM)(a+j) = *(MEM)tg ; /* Gán tg vào hàng j */ viii. Kết luận Con trỏ trong C/C++ là một công cụ mạnh mẽ và linh hoạt. Để nâng cao kỹ thuật lập trình C/C++ cần biết cách sử dụng con trỏ, các ví dụ trên đã minh hoạ điều này. Tài liệu tham khảo [1]. Peter Norton. Advanced C Programming. Brady Publishing, 1992. [2]. Phạm Văn ất. Kỹ thuật lập trình C cơ sở và nâng cao. NXB Khoa học và Kỹ thuật, Hà Nội, 1999. [3]. Phạm Văn ất. C++ và lập trình hớng đối tợng. NXB Khoa học và Kỹ thuật, Hà Nội, 2000Ă . đầu c a nó chứa trong biến con trỏ) . + C ng địa chỉ để con trỏ chứa địa chỉ c a phần tử tiếp theo, dùng phép toán: ++ Tên _con_ trỏ ho c Tên _con_ trỏ ++ Chú ý rằng c c phép toán trên chỉ c . sách. ii. Biến con trỏ Biến con trỏ (hay con trỏ) dùng để chứa địa chỉ c a biến, mảng, hàm, C nhiều kiểu địa chỉ, vì vậy c ng c nhiều kiểu con trỏ. Biến con trỏ đ c khai báo theo mẫu: . một số ứng dụng c a con trỏ trong c v C+ + PGS. TS. Phạm văn ất Khoa C ng nghệ thông tin - Trờng ĐH GTVT Tóm tắt: Bi báo ny trình bầy một số ứng dụng c a con trỏ trong c c vấn đề

Ngày đăng: 06/08/2014, 05:20

Từ khóa liên quan

Tài liệu cùng người dùng

Tài liệu liên quan