Mảng một chiều là một lưu trữ chứa những giá trị có cùng kiểu với nhau. Các phần tử của mảng được lưu trữ trong các vị trí liền kề nhau.
Giả sử tôi có một mảng a
gồm 5 phần tử sẽ là:
#include int main() { int a[5] = {0,1,2,3,4}; }
Ta tưởng tượng các phần tử được lưu trữ trong mảng như sau:
Dòng trên cùng chính là phần truy cập vào vị trí trong mảng, dòng ở giữa chính là giá trị tại các vị trí mà dòng trên đang truy cập, dòng cuối cùng chính là địa chỉ của từng vị trí.
Nhận xét: Địa chỉ của các phần tử trong mảng là liền kề nhau. Ban đầu là địa chỉ 1000 khi truy cập vào phần tử sau đó (phần tử thứ 2) là 1004, truy cập vào phần tử thứ 3 là 1008 …. Truy cập vào phần tử cuối là 1016.
Vì kiểu int
có kích thước là 4 byte nên mỗi lần truy cập vào địa chỉ phần tử liền kề trong mảng thì vị trí tăng lên 4 đơn vị (4 byte).
Như vậy ta có thể kết luận rằng các phần tử của một mảng được lưu trữ trong các vị trí bộ nhớ liền nhau.
2.1 Địa chỉ ô nhớ các phần tử mảng một chiều
Mảng một chiều, thực chất cũng tồn tại là một con trỏ. Trong đó, tên mảng chứa chính địa chỉ của mảng đó. Con trỏ đến phần tử đầu tiên của mảng cũng mang lại chính địa chỉ của mảng đó.
Để làm rõ hơn về điều này tôi có một ví dụ dưới đây, tôi khai báo một mảng a
gồm 5 phần tử, tôi sẽ kiểm tra địa chỉ của mảng tại tên mảng và địa chỉ của con trỏ phần tử đầu tiên của mảng như sau:
#include int main() { //khai bao mang a gom 5 phan tu int a[5] = {0,1,2,3,4}; //khai bao con tro p va gan p bang dia chi cua phan tu dau tien trong mang int *p; p = &a[0]; //hien thi ket qua printf("dia chi ten mang %x\n", &a); printf("dia chi cua con tro phan tu dau tien %x", p); }
Kết quả:
dia chi ten mang 62fe00 dia chi cua con tro phan tu dau tien 62fe00
Chú ý: Địa chỉ ô nhớ trên mỗi máy tính khi thực thi chương trình trên là khác nhau. Kết quả 62fe00 chỉ là kết quả minh họa.
Thực thi chương trình ta nhận thấy rằng, địa chỉ của tên mảng và địa chỉ của con trỏ phần tử đầu tiên trong mảng là như nhau.
Hiểu được địa chỉ ô nhớ của mảng để dễ dàng sử dụng con trỏ tương tác với mảng hơn.
2.2 Sử dụng con trỏ truy cập giá trị và địa chỉ của phần tử mảng một chiều
Sử dụng khái niệm đỉa chỉ ô nhớ của mảng một chiều ở phần trên, bây giờ ta có thể thao tác dễ dàng để truy cập vào giá trị và địa chỉ của mảng bằng các phép toán con trỏ.
Địa chỉ của một phần tử mảng có thể được biểu diễn theo hai cách:
- Sử dụng
&
trước phần tử mảng, ví dụ&a[i]
- Sử dụng biểu thức
(a+i)
Xét ví dụ dưới đây tôi có mảng a
gồm 5 phần tử, tôi sẽ lấy địa chỉ của từng phần tử trong mảng bằng &a[i]
và vòng lặp for
:
#include int main() { //khai bao mang a gom 5 phan tu int a[5] = {0,1,2,3,4}; //lay dia chi cua tung phan tu for(int i = 0; i < 5; i++){ printf("Dia chi cua a[%d]: %x\n", i, &a[i]); } }
Kết quả:
Dia chi cua a[0]: 62fe00 Dia chi cua a[1]: 62fe04 Dia chi cua a[2]: 62fe08 Dia chi cua a[3]: 62fe0c Dia chi cua a[4]: 62fe10
Chú ý: Địa chỉ ô nhớ trên mỗi máy tính khi thực thi chương trình trên là khác nhau. Kết quả trên chỉ là minh họa.
Ví dụ lần này tôi sẽ dùng (a+i)
thay cho &a[i]
, kết quả thu được là tương tự:
#include int main() { //khai bao mang a gom 5 phan tu int a[5] = {0,1,2,3,4}; //lay dia chi cua tung phan tu for(int i = 0; i < 5; i++){ printf("Dia chi cua a[%d]: %x\n", i, (a + i)); } }
Kết quả:
Dia chi cua a[0]: 62fe00 Dia chi cua a[1]: 62fe04 Dia chi cua a[2]: 62fe08 Dia chi cua a[3]: 62fe0c Dia chi cua a[4]: 62fe10
Qua 2 ví dụ trên ta đã biết cách lấy địa chỉ của từng phần tử có trong mảng, bây giờ ta có thể lấy giá trị của phần tử bằng cách khai báo con trỏ mảng và đặt biểu thức *
trước địa chỉ cần lấy giá trị. (Nếu quên khái niệm này bạn đọc vui lòng đọc lại bài trước tôi đã giải thích về dấu *
)
Chương trình dưới đây, tôi sẽ sử dụng con trỏ p
gán bằng mảng a
sau đó dùng con trỏ p
để lấy ra các giá trị tại các địa chỉ của mỗi phần tử có trong mảng a
:
#include int main() { //khai bao mang a gom 5 phan tu int a[5] = {0,1,2,3,4}; //gan con tro p bang mang a int *p; p = a; // p = &a[0] cung giong nhu p = a //lay gia tri va dia chi cua tung phan tu for(int i = 0; i < 5; i++){ printf("Gia tri cua a[%d] = %d ", i, *(p + i)); printf("Dia chi cua a[%d] = %x\n", i, (p + i)); } }
Kết quả:
Gia tri cua a[0] = 0 Dia chi cua a[0] = 62fdf0 Gia tri cua a[1] = 1 Dia chi cua a[1] = 62fdf4 Gia tri cua a[2] = 2 Dia chi cua a[2] = 62fdf8 Gia tri cua a[3] = 3 Dia chi cua a[3] = 62fdfc Gia tri cua a[4] = 4 Dia chi cua a[4] = 62fe00
Giải thích nhanh ví dụ trên:
- Gán con trỏ
p = a
hoặc có thể gánp = &a[0]
hai điều này là giống nhau (xem lại phần Địa chỉ ô nhớ của mảng một chiều) - Sử dụng toán tử
*(p+i)
để lấy giá trị của phần tử mảng tại vị trí thứi
- Sử dụng biểu thức
(p+i)
để lấy địa chỉ của phần tử mảng tại vị tríi
Ví dụ tiếp theo tôi sử dụng con trỏ p
để lấy ra địa chỉ các phần tử trong mảng a
có giá trị là số chẵn:
#include int main(){ //khai bao mang a gom 5 phan tu int a[5] = {0,1,2,3,4}; //gan con tro p bang mang a int *p; p = a; // p = &a[0] cung giong nhu p = a //lay gia tri va dia chi cua tung phan tu printf("Gia tri va dia chi cac phan tu chan la: \n"); for(int i = 0; i < 5; i++){ //kiem tra dieu kien neu gia tri *(p+i) % 2 ==0 thi hien thi ra dia chi va gia tri if(*(p + i) % 2 == 0){ printf("Gia tri cua a[%d] = %d ", i, *(p + i)); printf("Dia chi cua a[%d] = %x\n", i, (p + i)); } } }
Kết quả:
Gia tri va dia chi cua cac phan tu chan la: Gia tri cua a[0] = 0 Dia chi cua a[0] = 62fdf0 Gia tri cua a[2] = 2 Dia chi cua a[2] = 62fdf8 Gia tri cua a[4] = 4 Dia chi cua a[4] = 62fe00
Ta nhận thấy rằng trong mảng a
có các giá trị chẵn tại các chỉ số lần lượt là a[0]
, a[2]
, a[4]
, cách lấy giá trị theo con trỏ là *(p+0)
, *(p+2)
, *(p + 4)
và cách lấy địa chỉ là (p + 0)
, (p + 2)
, (p + 4)
.