Bài giảng Kỹ thuật lập trình - Chương 7: Con trỏ - Trần Quang

Ứng dụng của con trỏ  Mảng trong C  Phải biết trước số lượng phần tử tại thời điểm viết chương trình  Do đó, cần phải khai báo một số lượng lớn các ô nhớ để sẵn. Tuy nhiên, tại một thời điểm nào đó, chương trình có thể sẽ sử dụng ít hơn rất nhiều  lãng phí  Yêu cầu: có thể nào dùng mảng với số lượng phần tử chỉ cần biết lúc chương trình đang chạy? => Dùng con trỏ

pdf28 trang | Chia sẻ: thanhle95 | Lượt xem: 508 | Lượt tải: 1download
Bạn đang xem trước 20 trang tài liệu Bài giảng Kỹ thuật lập trình - Chương 7: Con trỏ - Trần Quang, để xem tài liệu hoàn chỉnh bạn click vào nút DOWNLOAD ở trên
Trần Quang © 2016 Kỹ thuật lập trình 1 Chương 06: Con trỏ Chương 07 CON TRỎ CuuDuongThanCong.com https://fb.com/tailieudientucntt Trần Quang © 2016 Kỹ thuật lập trình 2 Chương 06: Con trỏ Nội dung  Tổ chức bộ nhớ  Ứng dụng của con trỏ  Mô hình của con trỏ  Toán tử &  Khai báo trỏ  Toán tử *  Các phép toán  Con trỏ và mảng  Cấp phát bộ nhớ động  Con trỏ và cấu trúc, toán tử ->  Các chủ đề nâng cao với con trỏ  Thứ tự đánh giá * và ++, --  Con trỏ và const  Con trỏ đến con trỏ  Con trỏ void CuuDuongThanCong.com https://fb.com/tailieudientucntt Trần Quang © 2016 Kỹ thuật lập trình 3 Chương 06: Con trỏ Tổ chức bộ nhớ thực thi  Tổ chức bộ nhớ khi chương trình nạp vào để thực thi CuuDuongThanCong.com https://fb.com/tailieudientucntt Trần Quang © 2016 Kỹ thuật lập trình 4 Chương 06: Con trỏ Tổ chức bộ nhớ thực thi Vùng TEXT  Chứa mã thực thi của chương trình  Vùng này chỉ đọc  Có thể dùng chung CuuDuongThanCong.com https://fb.com/tailieudientucntt Trần Quang © 2016 Kỹ thuật lập trình 5 Chương 06: Con trỏ Tổ chức bộ nhớ thực thi Vùng DATA  Dữ liệu đã được khởi tạo (initialized)  Dữ liệu không được khởi tạo (uninitialzed) gồm:  Biến toàn cục  Biến tĩnh (static)  Hằng chuỗi (Nguồn: CuuDuongThanCong.com https://fb.com/tailieudientucntt Trần Quang © 2016 Kỹ thuật lập trình 6 Chương 06: Con trỏ Tổ chức bộ nhớ thực thi Vùng HEAP  Chứa bộ nhớ xin cấp phát động bởi người lập trình  Liên quan đến kiểu dữ liệu con trỏ trong chương này (Nguồn: programming.org/) CuuDuongThanCong.com https://fb.com/tailieudientucntt Trần Quang © 2016 Kỹ thuật lập trình 7 Chương 06: Con trỏ Tổ chức bộ nhớ thực thi Vùng STACK  Chứa các biến khai báo trong chương trình  Thông tin các lần gọi hàm CuuDuongThanCong.com https://fb.com/tailieudientucntt Trần Quang © 2016 Kỹ thuật lập trình 8 Chương 06: Con trỏ Ứng dụng của con trỏ  Mảng trong C  Phải biết trước số lượng phần tử tại thời điểm viết chương trình  Do đó, cần phải khai báo một số lượng lớn các ô nhớ để sẵn. Tuy nhiên, tại một thời điểm nào đó, chương trình có thể sẽ sử dụng ít hơn rất nhiều  lãng phí  Yêu cầu: có thể nào dùng mảng với số lượng phần tử chỉ cần biết lúc chương trình đang chạy? => Dùng con trỏ CuuDuongThanCong.com https://fb.com/tailieudientucntt Trần Quang © 2016 Kỹ thuật lập trình 9 Chương 06: Con trỏ Ứng dụng của con trỏ  Mảng trong C  Khi thêm vào và xóa các phần tử trên mảng, cần phải dịch phải và trái nhiều phần tử  tốn nhiều thời gian  Yêu cầu: Có cách tổ chức dữ liệu nào giúp các phép quản lý phần tử nói trên nhanh chóng  Giải pháp:  Sử dụng danh sách liên kết  dùng con trỏ CuuDuongThanCong.com https://fb.com/tailieudientucntt Trần Quang © 2016 Kỹ thuật lập trình 10 Chương 06: Con trỏ Mô hình của con trỏ 0x1234 FFFF Biến p là con trỏ chứa địa chỉ của biến a Biến a có địa chỉ là 0x1234 FFFF CuuDuongThanCong.com https://fb.com/tailieudientucntt Trần Quang © 2016 Kỹ thuật lập trình 11 Chương 06: Con trỏ Toán tử &  Dùng để lấy địa chỉ của một biến  Ví dụ: int a = 100; printf("%d\n", a); printf("%p\n", &a); CuuDuongThanCong.com https://fb.com/tailieudientucntt Trần Quang © 2016 Kỹ thuật lập trình 12 Chương 06: Con trỏ Toán tử & typedef struct sPoint3D{float x, y, z;} Point3D; void main(){ Point3D p1 = {1.0f, 2.0f, 3.0f}; printf("%-5.1f\n", p1.x); printf("%p\n", &p1); printf("%p\n", &p1.x); printf("%p\n", &p1.y); printf("%p\n", &p1.z); } In ra giá trị của p1.x In ra địa chỉ của p1 In ra địa chỉ của p1.y In ra địa chỉ của p1.z CuuDuongThanCong.com https://fb.com/tailieudientucntt Trần Quang © 2016 Kỹ thuật lập trình 13 Chương 06: Con trỏ Khai báo con trỏ *; * = 0; //NULL * = &; Ví dụ: int a; // biến số nguyên int *p1; // con trỏ đến số nguyên, giá trị chưa xác định int *p2 = 0; // con trỏ đến số nguyên, giá trị là NULL int *p3 = &a; // con trỏ đến số nguyên, giá trị là địa chỉ của biến a CuuDuongThanCong.com https://fb.com/tailieudientucntt Trần Quang © 2016 Kỹ thuật lập trình 14 Chương 06: Con trỏ Toán tử *  Toán tử * lấy giá trị (tham khảo) tại một địa chỉ  Ví dụ: int a = 100; int *p; p = &a; printf("a : %d\n", a); printf("&a : %p\n", &a); printf("p : %p\n", p); printf("*p : %d\n", *p); printf("*&a: %d\n", *&a); CuuDuongThanCong.com https://fb.com/tailieudientucntt Trần Quang © 2016 Kỹ thuật lập trình 15 Chương 06: Con trỏ Các phép toán trên con trỏ  Tăng, giảm: ++, --  Cộng, trừ: +, -  Cộng, trừ kết hợp gán: +=, -=  So sánh: ==, != CuuDuongThanCong.com https://fb.com/tailieudientucntt Trần Quang © 2016 Kỹ thuật lập trình 16 Chương 06: Con trỏ Các phép toán trên con trỏ  Gọi p là con trỏ có kiểu T;  Các phép cộng, trừ: làm con trỏ p tăng hay giảm một bội số của kích thước kiểu T  Ví dụ: int a = 100; int *p = &a; printf("p : %p\n", p); p++; printf("p : %p\n", p); CuuDuongThanCong.com https://fb.com/tailieudientucntt Trần Quang © 2016 Kỹ thuật lập trình 17 Chương 06: Con trỏ Con trỏ và mảng  Con trỏ và mảng có nhiều điểm giống nhau. Cả 2 đều giữ địa chỉ của ô nhớ  Con trỏ: giữ địa chỉ của một ô nhớ nào đó  Mảng: giữ địa chỉ của phần tử đầu tiên Do đó:  Có thể gán mảng vào con trỏ  Nhưng không thể gán con trỏ vào mảng CuuDuongThanCong.com https://fb.com/tailieudientucntt Trần Quang © 2016 Kỹ thuật lập trình 18 Chương 06: Con trỏ Con trỏ và mảng  Ví dụ: int a[5]; int *p = a; printf ("a =%p\n", a); printf ("p =%p\n", p); Gán mảng vào con trỏ  a và p giữ cùng địa chỉ là địa chỉ phần tử đầu tiên của mảng CuuDuongThanCong.com https://fb.com/tailieudientucntt Trần Quang © 2016 Kỹ thuật lập trình 19 Chương 06: Con trỏ Con trỏ và mảng  Con trỏ và mảng có cùng cách truy cập các ô nhớ  Dùng toán tử [ ]  Dùng toán tử * và + int a[5]; int *p = a; int id = 2; a[id] = 100; p[id] = 100; *(a + id) = 100; *(p + id) = 100; Giống nhau CuuDuongThanCong.com https://fb.com/tailieudientucntt Trần Quang © 2016 Kỹ thuật lập trình 20 Chương 06: Con trỏ Con trỏ và mảng Con trỏ và mảng cũng có điểm khác nhau:  Mảng: các phần tử của mảng nằm trên STACK  Con trỏ: Các phần tử mảng con trỏ chỉ đến có thể trên STACK hay HEAP CuuDuongThanCong.com https://fb.com/tailieudientucntt Trần Quang © 2016 Kỹ thuật lập trình 21 Chương 06: Con trỏ Cấp phát bộ nhớ động  Giúp người lập trình tạo ra mảng động, không cần xác định số lượng phần tử của mảng động tại thời điểm biên dịch như mảng tĩnh  Mảng động sẽ được cấp phát trên HEAP  Vùng nhớ xin cấp phát không tự động giải phóng, nên CẦN ra lệnh giải phóng vùng nhớ sau khi dùng xong CuuDuongThanCong.com https://fb.com/tailieudientucntt Trần Quang © 2016 Kỹ thuật lập trình 22 Chương 06: Con trỏ Cấp phát bộ nhớ động  Hàm xin cấp phát bộ nhớ  malloc  calloc  realloc  Hàm giải phóng bộ nhớ  free CuuDuongThanCong.com https://fb.com/tailieudientucntt Trần Quang © 2016 Kỹ thuật lập trình 23 Chương 06: Con trỏ Cấp phát bộ nhớ động p1 = (int*) malloc (num * sizeof(int)); num: số lượng phần tử xin cấp phát sizeof(int): kích thước của mỗi phần tử.  num*sizeof(int): số bytes cần thiết để xin CuuDuongThanCong.com https://fb.com/tailieudientucntt Trần Quang © 2016 Kỹ thuật lập trình 24 Chương 06: Con trỏ Cấp phát bộ nhớ động int *p1; float *p2; int n = 100; p1 = (int*) malloc (n * sizeof(int)); p2 = (float*) malloc (n * sizeof(float)); free(p1); free(p2); xin cấp phát bộ nhớ CuuDuongThanCong.com https://fb.com/tailieudientucntt Trần Quang © 2016 Kỹ thuật lập trình 25 Chương 06: Con trỏ Cấp phát bộ nhớ động malloc int *p1 = (int*)malloc(num*sizeof(int)); if(p1 == NULL){ ...} else { ...} Hàm malloc trả về NULL nếu không xin được. Lúc đó, không thể dùng bộ nhớ được! Do đó, LUÔN LUÔN kiểm tra xem malloc có trả về NULL hay không CuuDuongThanCong.com https://fb.com/tailieudientucntt Trần Quang © 2016 Kỹ thuật lập trình 26 Chương 06: Con trỏ Cấp phát bộ nhớ động  Hàm malloc trả về NULL nếu không cấp phát được vùng nhớ. Do đó, nên kiểm tra bằng lệnh if trước khi xử lý tiếp.  Ví dụ: int n = 100; int *p1 = (int*) malloc (n * sizeof(int)); if (p1 == NULL) { printf ("Khong cap phat duoc!\n"); exit(1); } else { // Tiếp tục xử lý free(p1); } CuuDuongThanCong.com https://fb.com/tailieudientucntt Trần Quang © 2016 Kỹ thuật lập trình 27 Chương 06: Con trỏ Con trỏ và cấu trúc typedef struct{ float x, y, z; } Point3D; Point3D *p_ptr = (Point3D*)malloc(sizeof(Point3D)); // (4) Sử dụng free(p_ptr); (1) Định nghĩa kiểu cấu trúc: Point3D (2) Khai báo con trỏ đến một mảng (3) Xin cấp phát bộ nhớ trên HEAP, p_ptr: giữ địa chỉ của ô nhớ đầu tiên trong vùng được cấp(5) Giải phóng vùng nhớ CuuDuongThanCong.com https://fb.com/tailieudientucntt Trần Quang © 2016 Kỹ thuật lập trình 28 Chương 06: Con trỏ Con trỏ và cấu trúc (*p_ptr).x = 4.5f; (*p_ptr).y = 5.5f; (*p_ptr).z = 6.5f; p_ptr->x = 7.5f; p_ptr->y = 8.5f; p_ptr->z = 9.5f; Truy cập biến thành viên cấu trúc qua con trỏ p_ptr : biến con trỏ chứa địa chỉ của một cấu trúc Point3D (*p_ptr) : Vùng nhớ của cấu trúc Point3D (*p_ptr).x : Vùng nhớ chứa biến x của cấu trúc Point3D p_ptr -> x : Vùng nhớ chứa biến x của cấu trúc Point3D, truy cập thông qua toán tử -> từ con trỏ p_ptr CuuDuongThanCong.com https://fb.com/tailieudientucntt