Bài giảng Kỹ thuật lập trình - Chương 07: Con trỏ - Nguyễn Thanh Tùng

nTổ chức bộ nhớ thực thi

nỨng dụng của con trỏ

nMô hình của con trỏ

nToán tử &

nKhai báo trỏ

nToán tử *

nCác phép toán trên con trỏ

nCon trỏ và mảng

nCấp phát bộ nhớ động

nCon trỏ và cấu trúc, toán tử ->

nCác chủ đề nâng cao với con trỏ

nThứ tự đánh giá * và ++, --

nCon trỏ và const

nCon trỏ đến con trỏ

nCon trỏ void

pptx 52 trang xuanthi 27/12/2022 1480
Bạn đang xem 20 trang mẫu của tài liệu "Bài giảng Kỹ thuật lập trình - Chương 07: Con trỏ - Nguyễn Thanh Tùng", để tải tài liệu gốc về máy hãy click vào nút Download ở trên.

File đính kèm:

  • pptxbai_giang_ky_thuat_lap_trinh_chuong_07_con_tro_nguyen_thanh.pptx

Nội dung text: Bài giảng Kỹ thuật lập trình - Chương 07: Con trỏ - Nguyễn Thanh Tùng

  1. Trường Đại Học Bách Khoa Lập trình C/C++ Trung Tâm Kỹ Thuật Điện Toán 2 © 2016
  2. Tổ chức bộ nhớ thực thi ◼ Khi chương trình được lên bộ nhớ để thực thi, hệ thống tổ chức bộ nhớ như hình vẽ (Nguồn: Trường Đại Học Bách Khoa Lập trình C/C++ Trung Tâm Kỹ Thuật Điện Toán 4 © 2016
  3. Tổ chức bộ nhớ thực thi ◼ Vùng “Data” ◼ Gồm: ◼ Dữ liệu được khởi động (bởi người lập trình) ◼ Dữ liệu không được khởi động (bởi người lập trình) (Nguồn: Trường Đại Học Bách Khoa Lập trình C/C++ Trung Tâm Kỹ Thuật Điện Toán 6 © 2016
  4. Tổ chức bộ nhớ thực thi ◼ Vùng “Data” ◼ Gồm: ◼ Dữ liệu được khởi động ◼ Dữ liệu không khởi động bởi người lập trình ◼ Biến toàn cục ◼ Biến tĩnh (static) ◼ Hệ thống khởi động về 0 (số) cho các biến không được người lập trình chủ động khởi động (Nguồn: Trường Đại Học Bách Khoa Lập trình C/C++ Trung Tâm Kỹ Thuật Điện Toán 8 © 2016
  5. Tổ chức bộ nhớ thực thi ◼ Vùng “STACK” ◼ Chứa ◼ Các biến được khai báo trong chương trình ◼ Thông tin mỗi lần gọi hàm (Nguồn: Trường Đại Học Bách Khoa Lập trình C/C++ Trung Tâm Kỹ Thuật Điện Toán 10 © 2016
  6. Ứng dụng của con trỏ ◼ Mảng trong C ◼ Khi thêm vào và lấy ra 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 ◼ => Sử dụng danh sách liên kết ◼ => Cần đến con trỏ Trường Đại Học Bách Khoa Lập trình C/C++ Trung Tâm Kỹ Thuật Điện Toán 12 © 2016
  7. Mô hình của con trỏ Biến a: là biến có kiểu nào đó bất kỳ Ô nhớ bắt đầu của a có địa chỉ là: (ví dụ) 0x1234 FFFF Biến p: là con trỏ Chứa địa chỉ của biến x, nghĩa là giá trị 0x1234 FFFF Minh hoạ con trỏ bởi tên từ ô nhớ biến p CHỈ ĐẾN (point to) ô nhớ biến x Trường Đại Học Bách Khoa Lập trình C/C++ Trung Tâm Kỹ Thuật Điện Toán 14 © 2016
  8. Toán tử & ◼ Con trỏ lưu trữ địa chỉ của một ô nhớ (biến) khác ➔ Bằng cách nào lấy địa chỉ của một biến hay ô nhớ để gán cho biến con trỏ ◼ Cách 1: Dùng toán tử & để lấy địa chỉ của một biến đang có ◼ Cách 2: Xin cấp phát bộ nhớ động (phần sau) Trường Đại Học Bách Khoa Lập trình C/C++ Trung Tâm Kỹ Thuật Điện Toán 16 © 2016
  9. Toán tử & ◼ Toán tử & trả về địa chỉ của một biến ◼ Ví dụ #include #include typedef struct sPoint3D{float x, y, z;} Point3D; int main(){ Point3D p1 = {1.0f, 2.0f, 3.0f}; printf("%-5.1f\n", p1.x); In ra giá trị của p1.x printf("%p\n", &p1); printf("%p\n", &p1.x); In ra địa chỉ của p1 printf("%p\n", &p1.y); In ra địa chỉ của p1.x printf("%p\n", &p1.z); system("pause"); In ra địa chỉ của p1.y return 0; In ra địa chỉ của p1.z } Trường Đại Học Bách Khoa Lập trình C/C++ Trung Tâm Kỹ Thuật Điện Toán 18 © 2016
  10. Khai báo con trỏ Cú pháp a: là số nguyên int a; p1: con trỏ đến số nguyên, giá trị chưa xác định int *p1; p2: con trỏ đến số nguyên, giá trị là NULL int *p2 = 0; p3: con trỏ đến số nguyên, giá trị chính là địa chỉ int *p3 = &a; của số nhớ a double d; double *pd1; double *pd2 = 0; double *pd3 = &d; f: là số float float f; pf1: con trỏ đến số float, giá trị chưa xác định float *pf1; pf2: con trỏ đến số float, giá trị là NULL float *pf2 = 0; pf3: con trỏ đến số float, giá trị chính là địa chỉ float *pf3 = &d; của số nhớ f Point3D p1 = {1.0f, 2.0f, 3.0f}; Point3D *pp1; Point3D *pp2 = 0; Point3D *pp3 = &p1; Trường Đại Học Bách Khoa Lập trình C/C++ Trung Tâm Kỹ Thuật Điện Toán 20 © 2016
  11. Toán tử * #include #include int main(){ int a = 100; printf("a=%d\n", a); printf("*&a=%d\n", *&a); printf("*&*&a=%d\n", *&*&a); printf("*&*&*&a=%d\n", *&*&*&a); system("pause"); return 0; } Trường Đại Học Bách Khoa Lập trình C/C++ Trung Tâm Kỹ Thuật Điện Toán 22 © 2016
  12. Con trỏ và mảng ◼ Con trỏ và mảng có nhiều điểm giống nhau ◼ Con trỏ & mảng: giữ địa chỉ của ô nhớ ◼ Con trỏ: giữa địa chỉ của ô nhớ nào đó (của biến khác, của bộ nhớ động) ◼ Mảng: giữ địa chỉ của phần tử đầu tiên ◼ => có thể gán mảng vào con trỏ ◼ Tuy nhiên, gán con trỏ vào mảng là không được Trường Đại Học Bách Khoa Lập trình C/C++ Trung Tâm Kỹ Thuật Điện Toán 24 © 2016
  13. Con trỏ và mảng ◼ Con trỏ và mảng có nhiều điểm giống nhau ◼ Có cùng cách truỳ 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; Giống nhau p[id] = 100; *(a + id) = 100; *(p + id) = 100; Trường Đại Học Bách Khoa Lập trình C/C++ Trung Tâm Kỹ Thuật Điện Toán 26 © 2016
  14. 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 Mỗi khi xin cấp phát bộ nhớ CẦN PHẢI giải phóng vùng nhớ xin được khi dùng xong Trường Đại Học Bách Khoa Lập trình C/C++ Trung Tâm Kỹ Thuật Điện Toán 28 © 2016
  15. Cấp phát bộ nhớ động malloc #include #include typedef struct sPoint3D{float x, y, z;} Point3D; int main(){ int *p1; float *p2; Các biến con trỏ Point3D *p3; int num = 100; Xin cấp bộ nhớ p1 = (int*)malloc(num*sizeof(int)); p2 = (float*)malloc(num*sizeof(float)); p3 = (Point3D*)malloc(num*sizeof(Point3D)); free(p1); free(p2); free(p3); Giải phóng bộ nhớ return 0; } Trường Đại Học Bách Khoa Lập trình C/C++ Trung Tâm Kỹ Thuật Điện Toán 30 © 2016
  16. Cấp phát bộ nhớ động malloc p1 = (int*)malloc(num*sizeof(int)); Hàm malloc trả về kiểu void* (kiểu vô định). Cần ép vào kiểu của bên tay trái p1: kiểu int* ➔ ép vào int* bằng (int*) Trường Đại Học Bách Khoa Lập trình C/C++ Trung Tâm Kỹ Thuật Điện Toán 32 © 2016
  17. 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 Trường Đại Học Bách Khoa Lập trình C/C++ Trung Tâm Kỹ Thuật Điện Toán 34 © 2016
  18. Con trỏ và cấu trúc Khai báo typedef struct{ float x, y, z; (1) Định nghĩa kiểu cấu trúc: Point3D } Point3D; Point3D *p_ptr = (Point3D*)malloc(sizeof(Point3D)); // (4) Sử dụng free(p_ptr); (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 (5) Giải phóng vùng nhớ vùng được cấp Trường Đại Học Bách Khoa Lập trình C/C++ Trung Tâm Kỹ Thuật Điện Toán 36 © 2016
  19. Con trỏ và cấu trúc Truy cập biến thành viên cấu trúc qua con trỏ Ví dụ: gán các biến thành viên của cấu trúc Point3D (*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; Tổng quát: -> Như: p_ptr->x Trường Đại Học Bách Khoa Lập trình C/C++ Trung Tâm Kỹ Thuật Điện Toán 38 © 2016
  20. Thứ tự các phép toán *, ++ và ❖*p++ // *(p++) ❖*++p // *(++p) ❖++*p // ++(*p) ❖(*p)++ // Tăng vùng nhớ do con trỏ p chỉ đến Khi nghi ngờ, hoặc không nhớ hãy dùng toán tử () để phân giải độ ưu tiên Trường Đại Học Bách Khoa Lập trình C/C++ Trung Tâm Kỹ Thuật Điện Toán 40 © 2016
  21. Con trỏ và const int a = 20, b = 30, c = 40; ptr2: Không thể thay đổi được giá trị của ptr2 = không thể làm ptr2 chỉ đến ô nhớ nào khác sau const int * ptr1 = &a; dòng này. int* const ptr2 = &b; Giá trị mà ptr2 chỉ đến có thể thay đổi được qua tr. Ô nhớ ptr2 chỉ đến (Không thể thay ptr2: đổi được ptr2) Trường Đại Học Bách Khoa Lập trình C/C++ Trung Tâm Kỹ Thuật Điện Toán 42 © 2016
  22. Con trỏ và const Các lỗi thông dụng Giá trị mà ptr1 chỉ đến không thay đổi được qua con trỏ ptr1. Do đó, nó không thể nằm bên trái biểu thức gán Trường Đại Học Bách Khoa Lập trình C/C++ Trung Tâm Kỹ Thuật Điện Toán 44 © 2016
  23. Con trỏ và const Các lỗi thông dụng ptr3: con trỏ bình thường, thay đổi được nó và giá trị nó chỉ đến Gán con trỏ ptr1 vào ptr3: khiến cho giá trị mà ptr1 chỉ đến có thể thay đổi được → bộ biên dich không cho phép. Vì nếu cho phép thì ý nghĩa của ptr1 không còn. Người lập trình luôn luôn có thể thay đổi nội dung mà ptr1 chỉ đến, bằng cáhch dùng con trỏ phụ. Trường Đại Học Bách Khoa Lập trình C/C++ Trung Tâm Kỹ Thuật Điện Toán 46 © 2016
  24. Con trỏ và const Các lỗi thông dụng -> LỖI -> OK ptr2: không thể thay đổi giá trị được Trường Đại Học Bách Khoa Lập trình C/C++ Trung Tâm Kỹ Thuật Điện Toán 48 © 2016
  25. Con trỏ đến con trỏ int x; 10 x = 10; int* px = &x; *px = 10; int ppx = &px; ppx = 10; int ppx = &ppx; pppx = 10; Trường Đại Học Bách Khoa Lập trình C/C++ Trung Tâm Kỹ Thuật Điện Toán 50 © 2016
  26. Bài tập ◼ Hiện thực lại các bài tập về array nhưng dữ liệu các array nằm trên bộ nhớ HEAP Trường Đại Học Bách Khoa Lập trình C/C++ Trung Tâm Kỹ Thuật Điện Toán 52 © 2016