Mục lục bài viết

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.

Address of elements in array

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];
Con trỏ truy cập các phần tử trong mảng

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:

Địa chỉ của phần tử trong mảng 2 chiều

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]
Tác giả

Vinh Lê

Giảng viên CNTT, chia sẻ tutorial lập trình & phần cứng tại Góc Học IT. Hơn 500 bài viết hướng dẫn từ cơ bản đến nâng cao.

Gợi ý tiếp theo

Kỹ thuật lập trình với kiểu cấu trúc và con trỏ trong C++

Học tiếp