Trong C++, con trỏ (pointer) là những biến lưu trữ địa chỉ của những biến khác. Con trỏ không chỉ lưu trữ địa chỉ của một biến đơn, mà còn lưu trữ địa chỉ của các phần tử trong mảng. Bài này sẽ giới thiệu cách sử dụng con trỏ để thao tác với mảng như thế nào.
1. Con trỏ và mảng 1 chiều
Bản chất của mảng 1 chiều
Có một khai báo mảng:
int arr[5];
Mảng arr có 5 phần tử được đánh vị trí từ 0 đến 4. Các phần tử được lưu trữ trong một dãy các ô nhớ liên tục trên bộ nhớ. Ví dụ như hình bên dưới.
Dễ thấy, chỉ cần xác định được địa chỉ ô nhớ của phần tử đầu tiên sẽ suy ra được các phần tử khác. Bản chất mảng lưu trữ như vậy. Tên mảng arr bản chất là con trỏ lưu địa chỉ của phần tử đầu tiên trong mảng (arr == &arr[0]).
Con trỏ trỏ đến mảng 1 chiều
Có thể sử dụng một biến con trỏ để lưu trữ địa chỉ của phần tử đầu tiên trong mảng để thay cho tên của mảng. Lúc này, biến con trỏ tương đương với mảng 1 chiều.
int arr[5], *parr;
parr = arr; // Cách 1
parr = &arr[0]; // Cách 2
Sử dụng con trỏ để truy xuất các phần tử trong mảng 1 chiều
Truy xuất theo địa chỉ của những phần tử trong mảng:
int arr[5], *parr;
parr = &arr[0];
parr + 1 tương đương &arr[1]
parr + 2 tương đương &arr[2]
parr + 3 tương đương &arr[3]
parr + 4 tương đương &arr[4]
Truy xuất giá trị của những phần tử trong mảng:
int arr[5], *parr;
*ptr == arr[0];
*(ptr + 1) tương đương arr[1];
*(ptr + 2) tương đương arr[2];
*(ptr + 3) tương đương arr[3];
*(ptr + 4) tương đương arr[4];
Nhập xuất mảng 1 chiều với con trỏ
#include <iostream>
using namespace std;
int main() {
int arr[5], *parr;
parr = arr;
cout<<"input array"<<endl;
for(int i=0;i<5;i++){
cout<<"input "<<i<<"th element:";
cin>>parr[i];
}
cout<<endl<<"output array:";
for(int i=0;i<5;i++){
cout<<*(parr + i)<<" ";
}
system("pause");
}
Kết quả
input array
input 0th element:5
input 1th element:9
input 2th element:0
input 3th element:2
input 4th element:1
output array:5 9 0 2 1
Lưu ý:
Địa chỉ: &arr[i] tương đương (arr + i) tương đương (parr + i) tương đương &parr[i]
Giá trị: arr[i] tương đương *(arr + i) tương đương *(parr + i) tương đương parr[i]
Truyền mảng 1 chiều cho hàm
Mảng có thể được truyền vào hàm như là các tham số. Các mảng luôn được truyền con trỏ (pass by pointer) vào hàm. Nó tương tự truyền tham chiếu, có nghĩa là các mảng có thể thay đổi giá trị bởi lời gọi hàm. Các bạn có thể xem ví dụ ở bài Các kỹ thuật lập trình với mảng một chiều và minh họa với C++.
Ở bài này, khi nói về bản chất mảng thì bạn cần lưu ý:
Mảng một chiều truyền cho hàm là truyền địa chỉ của phần tử đầu tiên cho hàm chứ không phải toàn bộ mảng.
void xuat(int a[5], int n)
{
for (int i = 0; i<n; i++){
cout<<*(a + i)<<endl;
}
}
int arr[5]={1,2,5,1,2};
xuat(arr,5);//lời gọi hàm
Khi gọi hàm xuat(arr, 5); bản chất chỉ truyền đối số là arr == &arr[0] cho hàm.
2. Con trỏ và mảng 2 chiều
Bản chất của mảng 2 chiều
Mảng 2 chiều là mảng (1 chiều) của mảng. Các phần tử cũng được cấp phát một dãy các ô nhớ liên tục trên bộ nhớ.
Ví dụ có khai báo mảng 2 chiều: int arr[2][3]={{-1,2,5},{1,7,9}}; thì trong bộ nhớ lưu trữ như sau:
Hình dung, mảng arr có 2 phần tử, mỗi phần tử là một mảng 1 chiều chứa 3 số nguyên. Phần tử đầu tiên arr[0] = {-1, 2, 5}, phần tử thứ hai arr[1] = {1, 7, 9}. Dễ thấy, tên mảng arr chứa địa chỉ của phần tử đầu tiên trong mảng 2 chiều (arr == &a[0][0]).
Con trỏ trỏ đến mảng 2 chiều
Có thể sử dụng một biến con trỏ để lưu trữ mảng 2 chiều để thay cho tên của mảng 2 chiều.
int arr[2][3]={{-1,2,5},{1,7,9}};
int *parr;
parr = (int *)arr;
Chú ý: Tại sao lại phải khai báo parr = (int *)arr? Vì parr là con trỏ kiểu int, arr == &a[0][0], tức là arr lưu địa chỉ phần tử đầu tiên của mảng arr[0]. Nên phải ép kiểu parr = (int *)arr thì mới lấy địa chỉ của arr[0][0] (&arr[0][0]) gán cho con trỏ parr được.
Sử dụng con trỏ để truy xuất các phần tử trong mảng 2 chiều
Truy xuất theo địa chỉ của những phần tử trong mảng:
int arr[2][3]={{-1,2,5},{1,7,9}};
int *parr;
parr = (int *)arr;
parr tương đương với &arr[0][0]
parr + 1 tương đương với &arr[0][1]
parr + 2 tương đương với &arr[0][2]
parr + 3 tương đương với &arr[1][0]
parr + 4 tương đương với &arr[1][1]
parr + 5 tương đương với &arr[1][2]
Truy xuất giá trị của những phần tử trong mảng:
int arr[2][3]={{-1,2,5},{1,7,9}};
int *parr;
parr = (int *)arr;
*parr tương đương với arr[0][0]
*(parr + 1) tương đương với arr[0][1]
*(parr + 2) tương đương với arr[0][2]
*(parr + 3) tương đương với arr[1][0]
*(parr + 4) tương đương với arr[1][1]
*(parr + 5) tương đương với arr[1][2]