Phép toán trên con trỏ trong C, C++
Trong bài học này, bạn sẽ duyệt qua các phần tử của một mảng bằng phép toán trên con trỏ trong C và iterator trong C++.
Giới thiệu
Khi cộng 1 vào một con trỏ, con trỏ không tiến thêm 1 byte mà tiến đến phần tử kế tiếp của mảng, vì trình biên dịch tự tính theo kích thước của kiểu dữ liệu. Nhờ đó, bạn có thể dùng con trỏ để duyệt qua một vùng nhớ liên tục như mảng.
Những điểm quan trọng
- Con trỏ chỉ được trỏ tới đối tượng còn tồn tại, đúng kiểu dữ liệu, hoặc mang giá trị null.
- Mỗi vùng nhớ được cấp phát chỉ được giải phóng đúng một lần.
- Thể hiện rõ hàm nào sở hữu vùng nhớ (ownership) và dữ liệu nào chỉ được đọc (const).
Code ví dụ bằng C và C++
#include <stdio.h>
int main(void) {
int values[] = {10, 20, 30, 40};
int sum = 0;
for (int *p = values; p < values + 4; ++p) sum += *p;
printf("sum=%d distance=%td\n", sum, (values + 4) - values);
return 0;
}
sum=100 distance=4
#include <iostream>
#include <vector>
int main() {
std::vector values{10, 20, 30, 40};
int sum = 0;
for (auto it = values.begin(); it != values.end(); ++it) sum += *it;
std::cout << "sum=" << sum << " distance="
<< std::distance(values.begin(), values.end()) << '\n';
}
sum=100 distance=4
So sánh C và C++
Vòng lặp bắt đầu với con trỏ p trỏ đến phần tử đầu tiên và tăng dần cho đến khi p đến vị trí values + 4. Ở mỗi bước, *p lấy giá trị hiện tại để cộng vào tổng. Phép toán trên con trỏ chỉ hợp lệ trong phạm vi cùng một mảng, hoặc ngay sau phần tử cuối cùng. Trong C++, iterator cho phép duyệt theo cách tương tự với nhiều loại container khác nhau.
Việc sở hữu và giải phóng vùng nhớ hoàn toàn do lập trình viên tự đảm bảo.
Container và RAII tự động giải phóng tài nguyên khi đối tượng hết thời gian tồn tại.
Bài tập mở rộng
Hãy chạy cả hai phiên bản, sau đó thử thay đổi code để quan sát sự khác biệt về mức độ an toàn mà mỗi ngôn ngữ mang lại.
- Thử với con trỏ null và trường hợp cấp phát bộ nhớ thất bại.
- Chạy chương trình với AddressSanitizer và UndefinedBehaviorSanitizer để phát hiện lỗi bộ nhớ.
- Ghi chú rõ con trỏ nào sở hữu vùng nhớ và con trỏ nào chỉ dùng để đọc.
Luyện tập với thử thách
Áp dụng kiến thức của bài học này để giải một bài toán thực tế. Mỗi thử thách chạy ngay trên trình duyệt, có kiểm thử tức thì và AI nhận xét.
- Di chuyển các số 0 Di chuyển tất cả số 0 về cuối danh sách, giữ nguyên thứ tự các phần tử còn lại. Dễ