Kiểu con trỏ trong ngôn ngữ lập trình C là một trong những đặc điểm mạnh mẽ và quan trọng nhất của ngôn ngữ này. Con trỏ là một biến đặc biệt chứa địa chỉ của một biến khác trong bộ nhớ. Điều này cho phép bạn truy cập và thay đổi dữ liệu tại địa chỉ bộ nhớ đó. Dưới đây là một số điểm quan trọng về kiểu con trỏ trong C
LẬP TRÌNH CĂN BẢN KIỂU CON TRỎ Giảng viên: TS Trương Quốc Bảo NỘI DUNG CỦA CHƯƠNG Giới thiệu kiểu dữ liệu con trỏ Khai báo và sử dụng biến con trỏ Con trỏ và mảng Con trỏ và tham số hình thức của hàm Thursday, January 15, 2015 Lập trình căn bản 2 GIỚI THIỆU KIỂU CON TRỎ (POINTER) 1 con trỏ là 1 biến được dùng để chứa địa chỉ của ô nhớ trong bộ nhớ Kích thước của biến con trỏ luôn là 2 bytes pointer ptr variable a 3.145 Ví dụ: FFF2 FFF2 (address) float a=3.145; float* ptr; //ptr is a pointer ptr=&a; *ptr=20; Thursday, January 15, 2015 Lập trình căn bản 3 KHAI BÁO BIẾN KIỂU CON TRỎ Cú pháp: *; Ý nghĩa: Khai báo một biến có tên là Tên con trỏ dùng để chứa địa chỉ của các biến có kiểu Kiểu Lưu ý: Kiểu void dùng để khai báo 1 con trỏ tổng quát, chưa chỉ vào bất cứ biến gì Ví dụ: int a, b, *pa, *pb; //pa và pb sẽ chỉ đến biến int float f, *fb; //fb sẽ chỉ đến biến float void *ptr; //ptr sẽ chỉ vào bất kỳ biến kiểu gì Thursday, January 15, 2015 Lập trình căn bản 4 THAO TÁC TRÊN BIẾN CON TRỎ Truy cập địa chỉ và nội dung của biến con trỏ Cấp phát vùng nhớ cho biến con trỏ Cấp phát lại vùng nhớ cho biến con trỏ Giải phóng vùng nhớ cho biến con trỏ Một số phép toán trên con trỏ Thursday, January 15, 2015 Lập trình căn bản 5 GÁN ĐỊA CHỈ BIẾN CHO CON TRỎ Toán tử & dùng để định vị con trỏ đến địa chỉ của một biến đang làm việc Cú pháp: = &; Giải thích: Ta gán địa chỉ của biến cho con trỏ Ví dụ: int a=6; int *c = &a; // &a là địa chỉ bộ nhớ của biến a // Con trỏ c chỉ đến địa chỉ của biến a Thursday, January 15, 2015 Lập trình căn bản 6 TRUY CẬP NỘI DUNG CỦA BIẾN DO CON TRỎ QUẢN LÝ Để truy cập đến nội dung của ô nhớ mà con trỏ chỉ tới, ta sử dụng cú pháp: *; Với cách truy cập này thì * có thể coi là một biến có kiểu được mô tả trong phần khai báo biến con trỏ Ví dụ: int a = 6; int *c = &a; *c = 7; /*Thay đổi nội dung của biến a bằng cách dùng địa chỉ của nó được chứa trong con trỏ c - Tương đương a = 7*/ Thursday, January 15, 2015 Lập trình căn bản 7 TRUY CẬP NỘI DUNG CỦA BIẾN DO CON TRỎ QUẢN LÝ Lưu ý: Sự tương thích kiểu: đoạn chương trình sau có lỗi không tương thích kiểu int Bien_Nguyen; float *Con_Tro_Thuc; Con_Tro_Thuc=&Bien_Nguyen; // Lỗi!!! Khi gán địa chỉ của một biến cho một biến con trỏ, mọi sự thay đổi trên nội dung ô nhớ con trỏ chỉ tới sẽ làm giá trị của biến thay đổi theo Thursday, January 15, 2015 Lập trình căn bản 8 CẤP PHÁT VÙNG NHỚ CHO BIẾN CON TRỎ (1) Có 2 cách để dùng được biến con trỏ 1 Cho nó chứa địa chỉ của 1 vùng nhớ đang tồn tại int a=6; int* c= &a; // &a là địa chỉ bộ nhớ của biến a 2 Cấp phát 1 vùng nhớ mới, rồi cho con trỏ chỉ đến vùng nhớ này pointer ptr Ví dụ: FFFA 6 int* ptr; FFFA (address) ptr = (int*)malloc(sizeof(int)); *ptr=6; Thursday, January 15, 2015 Lập trình căn bản 9 CẤP PHÁT VÙNG NHỚ CHO BIẾN CON TRỎ (2) Hàm void *malloc(size_t size): Cấp phát vùng nhớ có kích thước là size (bytes) Hàm void *calloc(nitems, size): Cấp phát vùng nhớ có kích thước là nitems*size (bytes) Ví dụ: int a, *pa, *pb; pa = (int*)malloc(sizeof(int)); /* Cấp phát vùng nhớ có kích thước bằng với kích thước của một số nguyên */ pb= (int*)calloc(10, sizeof(int)); /* Cấp phát vùng nhớ có thể chứa được 10 số nguyên*/ Thursday, January 15, 2015 Lập trình căn bản 10 CẤP PHÁT LẠI VÙNG NHỚ CHO BIẾN CON TRỎ Hàm void *realloc(void *block, size): Ý nghĩa: Cấp phát lại 1 vùng nhớ do con trỏ block quản lý, vùng nhớ này có kích thước mới là size; khi cấp phát lại thì nội dung vùng nhớ trước đó được copy đến vùng nhớ mới Kết quả trả về của hàm là địa chỉ đầu tiên của vùng nhớ mới Địa chỉ này có thể khác với địa chỉ được chỉ ra khi cấp phát ban đầu Trả về NULL nếu không cấp phát được Ví dụ: int a, *pa; pa = (int*)malloc(sizeof(int)); /*Cấp phát vùng nhớ có kích thước 2 bytes*/ pa = realloc(pa, 6); /*Cấp phát lại vùng nhớ Thursday, January 15, 2015 Lập trình căn bản thước mới là 6 bytes*/ 11 có kích GIẢI PHÓNG VÙNG NHỚ DO BIẾN CON TRỎ QUẢN LÝ Hàm void free(void *block): Giải phóng vùng nhớ được quản lý bởi con trỏ block Ví dụ: free(pa); free(pb); => giải phóng vùng nhớ do 2 biến con trỏ pa và pb đang chỉ đến Thursday, January 15, 2015 Lập trình căn bản 12 MỘT SỐ PHÉP TOÁN TRÊN KIỂU CON TRỎ (1) Phép gán và so sánh p a 10 Ví dụ: Hiện tại ta có: FFF2 FFF2 (address) int a=10, b=15; b int *p, *q; q 15 float *f; FFFA FFFA (address) p=&a; q=&b; p a Bây giờ thì phép so sánh: FFFA 10 (p!=q) => true (1) FFF2 (address) Thực hiện tiếp lệnh gán: p=q; q b Bây giờ thì: (p==q) => true (1) FFFA 15 Lệnh f=p; =>Error, do khác kiểu FFFA (address) ThursdNay,hJanưuanry 1g5, 2l0ệ15nh f=(float*)p; =Lập>trìNnh coăn beảnrror 13 MỘT SỐ PHÉP TOÁN TRÊN KIỂU CON TRỎ (2) Cộng, trừ con trỏ với 1 số nguyên Ta có thể cộng (+), trừ (-) 1 con trỏ với 1 số nguyên N nào đó Kết quả trả về là 1 con trỏ Con trỏ này chỉ đến vùng nhớ cách vùng nhớ của con trỏ hiện tại N phần tử Ví dụ: Cho đoạn chương trình sau: int *pa, *pb, *pc; pa = (int*) malloc(20); /*Cấp phát vùng nhớ 20 bytes*/ pb = pa + 7; pc = pb - 3; Thursday, JaLnuaúryc15,n20à15y hình ảnh của pLaập, trpìnhbcă,npbảcn như sau: 14 MỘT SỐ PHÉP TOÁN TRÊN KIỂU CON TRỎ (3) Cho con trỏ chỉ tới NULL Ví dụ: int x=25; int *ptr; ptr=&x; ptr=NULL; Lệnh gán ptr=NULL => cho con trỏ ptr không trỏ vào (không chứa địa chỉ) vùng nhớ nào cả Thursday, January 15, 2015 Lập trình căn bản 15 CON TRỎ VÀ MẢNG (1) Mảng và con trỏ có mối liên hệ với nhau Thay vì truy cập 1 phần tử mảng bằng chỉ số của nó, ta có thể dùng 1 con trỏ Để truy cập phần tử thứ i của mảng, a[i], ta dùng: y= *(pa+i); Chú ý: pa+1 không phải cộng 1 vào pa Thay vào đó, địa chỉ là pa+sizeof(*pa) Thursday, January 15, 2015 Lập trình căn bản 16 CON TRỎ VÀ MẢNG (2) 1 mảng có thể được xem như một con trỏ Con trỏ này đang chỉ đến phần tử đầu tiên của mảng Do đó: 1 mảng có thể được dùng làm tham số cho 1 hàm: Thursday, January 15, 2015 Lập trình căn bản 17 CON TRỎ VÀ MẢNG (3) x sẽ có giá trị của a[i] nào, tại mỗi lệnh gán sau? Lập trình căn bản 18 CON TRỎ VÀ THAM SỐ HÌNH THỨC CỦA HÀM (1) Ví dụ: Viết hàm hoán đổi nội dung 2 biến : Thursday, January 15, 2015 Lập trình căn bản 19 CON TRỎ VÀ THAM SỐ HÌNH THỨC CỦA HÀM (2) Ví dụ: Viết lại hàm hoán đổi nội dung 2 biến như sau: Thursday, January 15, 2015 Lập trình căn bản 20