Tại sao cần phải ép kiểu con trỏ
Trả lời
Ép kiểu con trỏ cho phép ta:
- Đọc một vùng nhớ theo kiểu khác.
- Truy cập phần cứng đúng với kiểu dữ liệu
- ...
Một số ví dụ để bạn có thể hình dung được lỗi xảy ra khi sử dụng con trỏ sai kiểu dữ liệu
Ví dụ 1
#include <stdio.h>
#include <stdint.h>
int main()
{
uint8_t *p;
int arr[3] = {1, 2, 3};
p = arr;
// in ra màn hình các phần tử của mảng
for(int i = 0; i < 3; i++) {
printf("arr[%d] = %d\n", i, *(p++));
}
return 0;
}
Ouput
arr[0] = 1
arr[1] = 0
arr[2] = 0
Chà! Kết quả ở đây là không mong muốn rồi, arr[1] = 2, arr[2] = 3
thì mới chính xác. Vậy lí do ở đây là gì ?
- Nếu để ý kỹ bạn sẽ thấy, kiểu dữ liệu của con trỏ là
uint8_t
(một kiểu dữ liệu8bit
). - Lúc này nếu ta sử dụng các phép toàn cho con trỏ,
p++
hayp--
,... nó sẽ tăng địa chỉ tương ứng với kích thước của con trỏ.Note: kiểu dữ liệu được sắp xếp theo thiểu
little-endian
.
uint8_t *p
thì mỗi lần p++
sẽ tăng địa chỉ tương ứng 1 byte
. Nếu bây giờ ta tiếp tục tăng con trỏ, tới lúc nào đó nó sẽ trỏ tới số 2.
printf("%d\n", *(p++));
printf("%d\n", *(p++));
Thêm 2 đoạn mã này, vào code trên thì ta sẽ được:
arr[0] = 1
arr[1] = 0
arr[2] = 0
0
2 // Đây chính là giá trị phần tử của 2.
Thay vì màu mè như trên bây giờ, ta chỉ việc ép kiểu con trỏ lại thành kiểu int
thì mọi thứ sẽ hoạt động đúng.
#include <stdio.h>
#include <stdint.h>
int main()
{
uint8_t *p;
int arr[3] = {1, 2, 3};
p = arr;
// in ra màn hình các phần tử của mảng
for(int i = 0; i < 3; i++) {
printf("arr[%d] = %d\n", i, *((int *)p));
p += sizeof(int); // cần phải tăng đúng kích thước của kiểu dữ liệu.
}
return 0;
}
Ouput
arr[0] = 1
arr[1] = 2
arr[2] = 3
Đây chỉ là ví dụ đơn giản để mô phỏng lại lỗi xảy ra trong thực tế nếu bạn không ép kiểu chính xác của con trỏ khi xử lí.
Ví dụ 2
Đọc dữ liệu từ việc căng chỉnh con trỏ.
Có một biến data nắm giữ các số từ 1 -> 4. In các số này ra màn hình
#include <stdio.h>
#include <stdint.h>
int main()
{
unsigned int data = 16909060;
int *p;
p = &data;
for(int i = 0; i < 4; i++)
{
printf("%d\n", *(p++));
}
}
Ouput
16909060
1
-1925391180
32765
Đây là kết quả mà ta không mong đợi.
Điều này xảy ra là do ta đã tăng địa chỉ của con trỏ theo kích thước int
- 4 byte
trong 1 lần. Trong khi dữ liệu lại được lưu trữ liên tiếp nhau.
Bây giờ ta cần chính sửa con trỏ lại theo kiểu uint8_t
.
#include <stdio.h>
#include <stdint.h>
int main()
{
unsigned int data = 16909060; // 0x01020304
uint8_t *p;
p = &data;
for(int i = 0; i < 4; i++)
{
printf("%d\n", *(p++));
}
}
Output
4
3
2
1
Tại vì sao nó lại hiện 1 -> 4
mà không phải là 4 -> 1
. Hãy phản hồi bên dưới bài viết.
All rights reserved