Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống
1
/ 21 trang
THÔNG TIN TÀI LIỆU
Thông tin cơ bản
Định dạng
Số trang
21
Dung lượng
145,27 KB
Nội dung
KỸ THUẬT LẬP TRÌNH C/C++ Chương 3: Mảng trỏ Con trỏ Biến trỏ biến có chứa địa vùng nhớ có kiểu xác định Kích thước trỏ tương đương int, nhiên kích thước vùng nhớ trỏ tới không xác định (con trỏ khơng chứa thơng tin kích thước) Khai báo cách thêm dấu * trước tên biến: ● int *pInt; ● char *pChar; ● struct SinhVien *pSV; Truy xuất giá trị thông qua trỏ dùng toán tử *: ● int aInt = *pInt; (*pInt hiểu biến int mà pInt trỏ tới) ● *pChar = 'A'; ● printf("Gia tri: %d", *pInt); int* int 10 Thay đổi địa trỏ tới Vì giá trị trỏ địa chỉ, nên thay đổi giá trị đó, biến trỏ trỏ tới vùng nhớ khác Gán địa cho trỏ phép gán thông thường ● int *pInt2; pInt2 = pInt; Toán tử địa &: tạo trỏ việc lấy địa biến ● int a; int* pA = &a; ● /* pA trỏ tới a */ pA a & toán tử ngược với *, với biến a *&a tương đương với a, p trỏ &*p tương đương với p 10 Minh hoạ char c = 'A'; Địa biến nhớ theo thứ tự tăng dần int *pInt; có tính chất minh hoạ Trong thực tế, stack cấp short s = 50; phát từ cao xuống thấp biến khai báo sau có địa int a = 10; nhỏ pInt = &a; *pInt = 100; Địa 1500 Biến char c int* pInt short s int a … 'A' 1507 50 100 … Giá trị pInt: 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1507 *pInt: 100 &a: 1507 a: 100 Con trỏ void* Là trỏ không mang thông tin kiểu Có thể chuyển kiểu ngầm định sang kiểu trỏ khác, ngược lại (nhưng C++ khơng) ▼ void* pVoid; int *pInt; char *pChar; pInt = pVoid; /* OK */ pChar = pVoid; /* OK */ pVoid = pInt; /* OK */ pVoid = pChar; /* OK */ pChar = pInt; /* lỗi */ pChar = (char*)pInt; /* OK */ Khơng dùng tốn tử * với trỏ void* ▼ *pVoid /* lỗi */ Con trỏ void* dùng để làm việc với nhớ tuý để thao tác với biến chưa xác định kiểu ▼ memcpy(void* dest, const void* src, int size); Con trỏ NULL Là trỏ chứa địa 0, kiểu (void*), mang ý nghĩa đặc biệt không trỏ tới địa nhớ Bản chất macro khai báo: ● #define NULL ((void*)0) Không gán giá trị cho trỏ NULL ● int *pInt = NULL *pInt = 100; /* lỗi */ Cần phân biệt trỏ NULL trỏ chưa khởi tạo (trỏ đến địa ngẫu nhiên) Con trỏ NULL thường dùng để xác định tính hợp lệ biến trỏ để tránh lỗi, gán trỏ NULL chưa tạm thời không dùng tới Vì NULL có giá trị nên so sánh trỏ với NULL bỏ qua biểu thức logic: ● if (p != NULL) … if (p) … Các phép toán với trỏ Tăng giảm: để thay đổi trỏ trỏ tới vị trí (tương ứng với kích thước kiểu trỏ tới) Địa 1500 1501 1502 1503 1504 1505 1506 p short *p p++ (1502) (1504) (1506) 1507 1508 1509 1510 1511 1507 1508 1509 1510 1511 Cộng địa chỉ: tương ứng với kiểu trỏ tới Địa 1500 1501 1502 1503 1504 1505 1506 p-2 short *p p+3 (1500) (1504) (1510) So sánh: trỏ kiểu so sánh địa với số nguyên (lớn, nhỏ, bằng) Hai trỏ kiểu trừ cho để số phần tử sai khác Con trỏ mảng Mảng trỏ tĩnh (không thể thay đổi địa chỉ), chứa địa (trỏ) tới phần tử ● Có thể thao tác với biến kiểu mảng thao tác với trỏ, trừ việc gán địa cho ● int arr[] = {1, 2, 3, 4, 5}; int x; *arr = 10; printf("%d", *(arr+2)); /* arr[2] */ arr = &x; /* lỗi */ Con trỏ hiểu mảng thao tác mảng ● int *p = arr; p[2] = 20; /* như: arr[0] = 10; */ /* như: arr[2] = 20; */ p = arr+2; /* như: p = &arr[2]; */ p[0] = 30; /* như: arr[2] = 30; hoặc: *p = 30; */ Kết luận: trỏ mảng dùng thay cho nhau, tuỳ trường hợp mà dùng cho thuận tiện Con trỏ mảng (tiếp) Khác biệt: ● Không gán địa cho biến kiểu mảng ● Biến kiểu mảng cấp phát nhớ cho phần tử (trong stack) từ khai báo ● Toán tử sizeof() với mảng cho biết kích thước thực mảng (tổng phần tử), dùng với trỏ cho biết kích thước thân (chứa địa chỉ) ▼ float arr[5]; ▼ float* p = arr; sizeof(arr) trả 20 (5*4) sizeof(p) trả với hệ thống 32 bit ▼ sizeof(arr)/sizeof(arr[0]) số phần tử mảng Với chất trỏ, dùng số âm với mảng: ▼ int arr[] = {1, 2, 3, 4, 5}; int *p = arr + 2; p[-1] = 10; /* như: arr[1] = 10; */ Con trỏ tới trỏ Con trỏ trỏ tới trỏ khác: ● float x = 1.5; float *pX = &x; float **ppX = &pX; printf("%f", **ppX); ppX /* in giá trị 1.5 */ pX x 1.5 **ppX = 2.3; ppX pX x 2.3 Tương tự mảng chiều (hay mảng mảng, trỏ tới mảng, mảng trỏ) 10 Kiểu chuỗi ký tự Là mảng ký tự, kết thúc ký tự '\0' ● char ten[10] = "Tung"; ● char ten[10] = {'T', 'u', 'n', 'g', '\0' }; (bằng mảng) ● char *ten = "Tung"; ● char *ten = {'T', 'u', 'n', 'g', '\0' }; /* sai */ (khởi tạo trỏ trỏ) Ví dụ tính độ dài chuỗi: ● (khởi tạo mảng trỏ) for (n=0; *s; n++, s++) ; Một số hàm xử lý chuỗi thông dụng ● #include ● int strlen(s) ● char *strcpy(dst, src) copy chuỗi src sang chuỗi dst ● char *strcat(dst, src) nối thêm chuỗi src vào chuỗi dst ● int strcmp(str1, str2) so sánh chuỗi, kết quả: 1, 0, -1 ● char *strstr(s1, s2) tính độ dài chuỗi s tìm vị trí chuỗi s2 s1 11 Xử lý dịng lệnh Tham số truyền cho chương trình từ dịng lệnh ● C:\>movefile abc.txt Documents Khai báo hàm main() ● int main(int argc, char* argv[]) { … } ▼ argc: số tham số từ dòng lệnh (argc ≥ 1) ▼ argv: mảng tham số dạng chuỗi ký tự ● Đường dẫn tên chương trình ln tham số Trong ví dụ trên: ● argc: ● argv: [ "movefile", "abc.txt", "Documents" ] 12 Cấp phát nhớ động Các biến khai báo tạo cấp phát nhớ khai báo (trong stack) Có cần cấp phát theo nhu cầu sử dụng mà khơng biết từ viết chương trình cấp phát động (trong heap) Cấp phát nhớ: ● #include ● void* malloc(int size) /* size: số byte cần cấp */ ● int *p = (int*)malloc(10*sizeof(int)); /*cấp 10 int*/ ● void* calloc(int num_elem, int elem_size) ● void* realloc(void* ptr, int size) ● Việc cấp phát khơng thành cơng trả NULL cần kiểm tra Huỷ (trả lại) vùng nhớ cấp phát: ● void free(void* p); ● free(p); 13 Con trỏ tới struct, union Với trỏ tới struct union, dùng tốn tử “->” để truy xuất biến thành phần thay dùng “*” “.” ● p->member tương đương với (*p).member Ví dụ: ● typedef struct { int x, y; } Point; Point *pP = (Point*)malloc(sizeof(Point)); pP->x = 5; /* như: (*pP).x = 5; */ (*pP).y = 7; /* như: pP->y = 7; */ 14 Lỗi sử dụng trỏ Trong ứng dụng thơng thường, chương trình khơng truy xuất ngồi vùng nhớ cấp cho Phải kiểm soát địa mà trỏ trỏ tới Hệ quả: ● Không dùng trỏ chưa khởi tạo nên có thói quen gán trỏ NULL chưa khơng dùng, để sau kiểm tra khởi tạo hay chưa ● Chỉ gán địa biến tạo (biến tĩnh nhớ cấp phát) cho trỏ để đảm bảo trỏ trỏ tới vùng nhớ hợp lệ ● Phải kiểm tra độ dài vùng nhớ mà trỏ trỏ tới để không bị truy xuất vượt (lỗi buffer overflow) ● Khi vùng nhớ cấp phát khơng cịn dùng đến nữa, phải huỷ bỏ để sử dụng lại 15 Kết luận Con trỏ đặc trưng quan trọng tạo nên sức mạnh C so với ngơn ngữ khác, dao hai lưỡi sử dụng sai việc gỡ lỗi khó khăn cần nắm vững sử dụng trỏ cách linh hoạt Con trỏ dùng nhiều trường hợp sau: ● Truyền giá trị từ hàm qua tham số ● Con trỏ hàm ● Cấu trúc liệu: chuỗi liên kết, hàng đợi, mảng động,… trở lại có liên quan 16 Bài tập Viết chương trình: • Nhập số ngun N • Cấp phát mảng N số nguyên nhập liệu cho • In hình mảng theo thứ tự xi ngược Viết chương trình nhập mảng số thực chưa biết trước số phần tử, không nhập số phần tử từ đầu (nhập đến đâu mở rộng mảng tới đó) Viết chương trình nhập chuỗi s1, sau copy s1 vào chuỗi s2 Viết chương trình nhập chuỗi s1 s2, sau so sánh xem s1 s2 có giống khơng Viết chương trình nhận chuỗi từ tham số dịng lệnh, sau tách thành mảng từ tương ứng Khai báo hai mảng float có giá trị tăng dần, viết chương trình trộn hai mảng thành mảng thứ theo thứ tự tăng dần 17 Mảng TT Yêu cầu Mẫu Viết hàm in mảng số nguyên có n phần tử void Print(const int *, int) Viết hàm tính tổng mảng số ngun có n phần int Sum(const int *, int) tử Viết hàm tính trung bình cộng mảng số double Averange(const int *, int) nguyên có n phần tử Viết hàm tìm giá trị đa thức bậc n x (hệ số double Polynorm(const double *, int đa thức mảng số thực) n, double) Viết hàm đổi xâu ký tự sang số double Number(const char *) Viết hàm chuẩn hóa họ tên tiếng Việt char * Viet(char *) Viết lại hàm … theo phương pháp duyệt mảng trỏ 18 Cấp phát nhớ động TT Yêu cầu Mẫu Ví dụ Viết hàm cho dãy n số Fibonacci int * FS(int) int * A = FS(5); Cho A = {1, 2, 3, 5, 8} Viết hàm tạo mảng n phần tử từ mảng số int * Clone(const int *) nguyên Viết hàm tạo xâu chuyển chữ char * ToUpper(const char *) thường thành chữ viết hoa từ xâu đầu vào Viết hàm chuyển đổi số nguyên thành xâu ký char * Dec2Bin(int) tự nhị phân Viết hàm tìm tần suất ký tự int * Freq(const char *) xâu 19 Danh sách liên kết (Linked list) typedef struct node ◗ { ◗ int data; // will store information ◗ node *next; // the reference to the next node ◗ }; ● node *temp1; ● temp1=(node*)malloc(sizeof(node)) ● temp1 = new node; 20 Bài tập Tạo danh sách liên kết (linked list) thực thao tác sau đây: ● Chèn N phần tử (người dùng đưa vào) vào danh sách Với phần tử, chèn vào đầu danh sách ● Duyệt danh sách ● Chèn phần tử vào cuối danh sách ● Chèn phần tử vào vị trí định ● Xóa phần tử ● Xóa phần tử cuối ● Xóa phần tử vị trí định ● Sắp xếp phần tử danh sách theo thứ tự tăng giảm dần 21 ... động,… trở lại có liên quan 16 Bài tập Viết chương trình: • Nhập số ngun N • Cấp phát mảng N số nguyên nhập liệu cho • In hình mảng theo thứ tự xi ngược Viết chương trình nhập mảng số thực chưa... rộng mảng tới đó) Viết chương trình nhập chuỗi s1, sau copy s1 vào chuỗi s2 Viết chương trình nhập chuỗi s1 s2, sau so sánh xem s1 s2 có giống khơng Viết chương trình nhận chuỗi từ tham số dịng... nhớ khai báo (trong stack) Có cần cấp phát theo nhu cầu sử dụng mà khơng biết từ viết chương trình cấp phát động (trong heap) Cấp phát nhớ: ● #include ● void* malloc(int size)