Xin chào mọi người!
Mấy mùa này thời tiết thật bất thường, sáng vừa ra thì trời nắng, loay hoay cái chiều lại mưa (!?!?), làm mình nhớ tới câu nói “sáng nắng chiều mưa” của mấy cô con gái vậy :v. Thời tiết bất thường dễ bệnh quá @@
Trở lại vấn đề, bài trước mình đã giới thiệu về Mảng trong C++, nhưng chỉ là phần 1. Ở phần này, mình sẽ đề cập chi tiết hơn về mảng + con trỏ (bạn nào chưa học về con trỏ thì quay về học đi nhé, lướt nhanh dễ tẩu hoả nhập ma lắm)

1. Con trỏ hằng và hằng con trỏ

Ở bài con trỏ mình chưa đề cập đến phần này, bởi vì nếu mà mình viết gộp vào bài đó sẽ có bạn không mường tượng được 2 thằng trên là gì. Nếu bạn dịch ra tiếng anh thì con trỏ hằng (pointer to const) và hằng con trỏ (const pointer) có sự khác nhau rõ ràng:
  • Con trỏ hằng: con trỏ trỏ tới 1 vùng nhớ cố định, nó chỉ có việc chỉ trỏ thôi, còn thay đổi giá trị thì KHÔNG.
  • Hằng con trỏ: con trỏ trỏ cố định tới 1 vùng nhớ, 1 khi đã trỏ vào vùng nhớ rồi thì “mãi không rời xa”, không có khả năng trỏ tới vùng nhớ khác.
  • Ta có thể kết hợp con trỏ hằng và hằng con trỏ lại. Tất nhiên lúc này “lưỡng long nhập thể”, 2 đặc tính của từng đứa sẽ được trộn vào nhau 😀
Ví dụ
Mã nguồn:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
int arr[5] = { 1, 2, 3, 4, 5 };
int* const p1 = arr; // Đây là hằng con trỏ
int const* p2 = arr; // Còn đây là con trỏ hằng
p1++; // Báo lỗi. Không thể tăng địa chỉ của hằng con trỏ
p1[1]++; // OK. Kết quả { 1, 3, 3, 4, 5 };
// Nên reset mảng lại giá trị ban đầu để ví dụ cụ thể hơn
(*p2)++; // Báo lỗi, nhưng chỉ trong runtime. Không thể thay đổi giá trị của mảng
p2[1]++; // Tất nhiên, cũng giống trên
p2++; // Nhưng lại OK. Kết quả { 2, 3, 4, 5 }
// Ta có thể kết hợp con trỏ hằng và hằng con trỏ
int const * const p3 = arr;
// Nên cả 2 biểu thức dưới đều báo lỗi
p3++;
p3[1]++;
Đến đây, não của bạn vẫn còn hoạt động chứ :D? Nếu còn thì tiếp tục nhé, mình cũng bị hack não rồi :v
Ta thấy con trỏ hằng “hơi bị” vô dụng trong tình huống trên phải không? Ứng dụng lớn nhất của nó mà mình biết được là với những hàm trả vềhằng số, thì khi ta trỏ tới phải dùng con trỏ hằng (biết thêm thôi, không cần hiểu đâu :v, những bài sau mình sẽ giải thích thêm)

2. Con trỏ trong mảng

“Nãy giờ mình nói lan man mà chả ăn nhập với mảng gì hết vậy hả” sẽ là câu hỏi trong đầu rất nhiều bạn. Thật ra là có đấy!
Mảng chính là con trỏ. Cụ thể hơn, nó là hằng con trỏ. Và địa chỉ của con trỏ chính là phần tử đầu tiên của mảng.
Ở bài trước, ta đã biết mảng chính là tập hợp phần tử cùng kiểu, tất nhiên địa chỉ của nó trong bộ nhớ RAM sẽ nằm kề nhau. Với *arr là lấy vị trí đầu tiên của mảng, thì *(arr + i) chính là lấy vị trí thứ i của mảng.
Mã nguồn:
1
2
3
4
5
int arr[5] = { 1, 2, 3, 4, 5 };
arr++; // Không được
(*arr)++; // OK
(*(arr + 2))++; // OK. Tương đương arr[2]++
Tất nhiên, với mảng nhiều chiều cũng vậy. Mình sẽ nói về mảng 2 chiều nhé, nó chính là mảng của các hằng con trỏ. Và phần tử đầu tiên (arr[0][0]) chính là con trỏ cấp 2. Từ đó ta có thể suy ra cho mảng 3 chiều, 4 chiều, tá lả chiều,…
Mã nguồn:
1
2
int a[3][3] = { { 1, 2, 3}, { 4, 5, 6 }, { 7, 8, 9 } };
*(*(a + 1) + 2) += 5; // Tương đương a[1][2] += 5
Vậy là đã kết thúc bài Mảng trong C++. Mình hi vọng sau bài học này bạn sẽ hiểu sâu hơn về mảng + con trỏ vì nó khá là “hack não” (ngày xưa mình cũng thế huhu). Cảm ơn các bạn đã theo dõi!
Axact

Administrator:

Xin chào, tôi là Nguyễn Quý Quang Huy. Tôi 14 tuổi và sinh sống tại Hoài Đức, Hà Nội. Tôi lập ra Rinne-IT Blog này nhằm chia sẻ những kiến thức mình có và những bài viết hay trên mạng do tôi tổng hợp. Blog đang trong giai đoạn phát triển nên nếu có lỗi mong các bạn bỏ qua. Tôi luôn chào đón những ý kiến phát triển từ từ các bạn. Giờ thì hãy khám phá blog của tôi nào ^_^

Bình Luận:

0 bình luận: