Con trỏ
Con trỏ là địa chỉ của ô nhớ. Ô nhớ này cũng chính là biến chúng ta sử dụng. Khai báo con trỏ như sau Kiểu dữ liệu nó trỏ tới * <tên con trỏ>;
. Toán tử một ngôi &
đặt trước một biến sẽ lấy địa chỉ của biến đó.
Ví dụ khai báo và gán địa chỉ cho con trỏ:
1
2
3
|
int a = 5;
int* pointer_a = &a; // lưu con trỏ trỏ đến địa chỉ biến a
printf("%p", pointer_a); // in địa chỉ của biến a trên bộ nhớ
|
Để lấy giá trị của dữ liệu con trỏ trỏ tới, ta sử dụng toán tử một ngôi *
.
1
2
3
4
5
6
7
8
|
int a = 5;
int* pointer_a = &a; // lưu con trỏ trỏ đến địa chỉ biến a
(*pointer_a) = 10; // tương tương với a = 10;
printf("%d", a); // in 10
printf("%d", *pointer_a); // in 10
printf("%p", pointer_a); // in địa chỉ của biến a
|
Độ lớn của con trỏ
Giá trị của con trỏ là địa chỉ của một biến khác. Địa chỉ này thường chỉ chiếm 8 bytes với hệ máy 64 bit. Vì 8 bytes tương đương với 64bit, vậy nên hệ máy 64 bit có nhiều nhất 264 địa chỉ. Mỗi địa chỉ tương ứng với 1 byte bộ nhớ.
1
2
3
4
5
6
7
8
9
|
typedef LargeStruct {
int arr[100];
} LargeStruct;
sizeof(int*); // -> 8
sizeof(void*); // -> 8
sizeof(char*); // -> 8
sizeof(long*); // -> 8
sizeof(LargeStruct*); // -> 8
|
Con trỏ và mảng
Con trỏ có thể trỏ vào phần tử đầu tiên của mảng.
1
2
3
|
int arr[] = {1, 2, 3, 4, 5};
int* pointer_arr1 = arr; // trỏ vào phần tử đầu tiên của mảng
int* pointer_arr2 = &(arr[0]); // tương đương với câu lệnh trước
|
Có thể sử dụng con trỏ như mảng:
1
2
3
4
|
int arr[] = {1, 2, 3, 4, 5};
int* pointer_arr1 = arr;
printf("%d", *pointer_arr1); // in phần tử đầu tiên
printf("%d", pointer_arr1[0]); // tương tự câu lệnh trên
|
Di chuyển con trỏ
Di chuyển con trỏ tới các phần tử tiếp theo bằng cách cộng con trỏ với một số nguyên. Cũng có thể sử dụng toán tử ++
hoặc --
để dịch chuyển con trỏ.
1
2
3
4
5
6
7
8
|
int arr[] = {1, 2, 3, 4, 5};
int* pointer_arr = arr;
printf("%d", *(pointer_arr1)); // in phần tử đầu tiên
printf("%d", pointer_arr1[0])); // in phần tử đầu tiên, tương tự câu lệnh trước
printf("%d", *(pointer_arr1 + 1)); // in phần tử thứ 2
printf("%d", pointer_arr1[1])); // in phần tử thứ 2, tương tự câu lệnh trước
|
Cộng con trỏ lên một sẽ thì con trỏ sẽ trỏ tới byte cách đó bằng kích thước kiểu dữ liệu nó trỏ tới.
1
2
3
4
5
6
7
8
|
int arr[] = {1, 2, 3, 4, 5};
int* pointer_arr = arr;
printf("%ld\n", sizeof(int)); // in kích cỡ kiểu dữ liệu kiểu int
printf("%p\n", pointer_arr); // in địa chỉ của con trỏ
// in địa chỉ của phần tử tiếp theo,
// bằng với kết quả trước + sizeof(int)
printf("%p\n", pointer_arr + 1);
|
Con trỏ với string
Có thể khai báo và gán luôn giá trị cho con trỏ với string. Tuy nhiên không thể gán như vậy với kiểu mảng.
1
2
3
|
char* str = "Hello C program";
// char* str2 = { 'a', 'b', 'c', '\0' }; // không làm được kiểu này
printf("%s", str);
|
Con trỏ nhiều cấp
Con trỏ cấp hai thì lưu địa chỉ của địa chỉ, tương tự với con trỏ cấp cao hơn.
1
2
3
4
5
6
7
8
|
int a = 10;
int* pointer = &a; // pointer lưu địa chỉ của biến a
int** pointer_lever_2 = &pointer; // pointer_lever_2 lưu địa chỉ của biến pointer
printf("%d", *pointer); // in 10
printf("%p", pointer); // in địa chỉ của a
printf("%p", *pointer_lever_2); // in địa chỉ của a, tương tự dòng lệnh trên
printf("%d", **pointer_lever_2); // in 10
|