Mảng hai chiều C/C++

Chào tất cả các bạn đang theo dõi khóa học lập trình trực tuyến ngôn ngữ C++.

Trong các bài học trước, mình đã giới thiệu đến các bạn về mảng một chiều trong ngôn ngữ C/C++.

Mảng một chiều có thể được hiểu là một dãy các phần tử có cùng kiểu dữ liệu được đặt liên tiếp nhau trong một vùng nhớ, chúng ta có thể ngay lập tức truy xuất đến một phần tử của dãy đó thông qua chỉ số của mỗi phần tử.

Bây giờ các bạn thử tưởng tượng nếu kiểu dữ liệu của mảng một chiều là mảng một chiều? Hay nói cách khác, chúng ta có một mảng chứa các mảng một chiều? Lúc này, chúng trở thành mảng 2 chiều.


2D Array

Trước hết, mình cho các bạn xem lại hình ảnh minh họa cho mảng một chiều trên máy tính:

Đây là mảng 1 chiều gồm có 5 phần tử được đánh chỉ số từ 0 đến 4.

Và dưới đây là hình ảnh minh họa cho cách tổ chức dữ liệu mảng hai chiều:

Đây là bảng câu đố của game Sudoku được tạo thành từ 9x9 ô vuông (9 dòng và 9 cột). Giả sử mình tách dòng đầu tiên của bảng game này ra đứng riêng biệt:

Nó lại trở thành mảng 1 chiều có 9 phần tử.

Vậy, mảng một chiều khi mô phỏng nó bằng hình ảnh, chúng ta chỉ thấy được 1 hàng ngang có nhiều cột phân chia thành các ô (tượng trưng cho các ô nhớ trong máy tính). Còn khi chúng ta nhìn vào mảng hai chiều, chúng ta thấy có nhiều hàng, mỗi hàng lại có nhiều cột, đặc biệt hơn là số lượng cột ở mỗi hàng đều bằng nhau.

Ngôn ngữ C/C++ có hổ trợ cho chúng ta tổ chức dữ liệu theo dạng bảng như trên, hay thường gọi là mảng hai chiều. Thế thì khi nào chúng ta cần sử dụng mảng hai chiều trong chương trình máy tính? Trong thực tế, chúng ta gặp rất nhiều thứ được bố trí dưới dạng mảng 2 chiều. Dưới đây là một số ví dụ thực tế:

  • Phòng học:

    Như hình minh họa, chúng ta có một phòng học có 2 dãy bàn hàng ngang, mỗi dãy bàn ngang có thể đủ chổ cho 3 sinh viên. Như vậy mình gọi đây là mảng hai chiều 2x3 (2 hàng, 3 cột).

  • Bàn cờ vua:

    Bàn cờ vua là một bảng hình vuông có 8 hàng, mỗi hàng có 8 cột, tổng cộng có 64 ô vuông, mỗi ô có thể đặt 1 quân cờ. Chúng ta có thể gọi đây là một mảng hai chiều 8x8 (8 dòng, 8 cột).

  • Trò chơi Tic Tac Toe:

    Trò chơi này được chơi trên một bảng 3x3 (3 hàng, 3 cột). Nếu trò chơi này được mô phỏng trên máy tính, chúng ta có thể sử dụng một mảng hai chiều 3x3 để lưu trữ các kí tự ‘x’ hoặc ‘o’.

Qua một số hình ảnh minh họa như trên, hi vọng các bạn đã có thể hình dung được mảng hai chiều là như thế nào. Bây giờ mình sẽ đi vào chi tiết về cách khai báo, khởi tạo giá trị và cách sử dụng mảng hai chiều trong ngôn ngữ C++.

Khai báo mảng hai chiều

Đối với mảng một chiều, chúng ta chỉ cần khai báo số lượng phần tử (số lượng cột) cho một hàng duy nhất, do đó, khai báo mảng một chiều có dạng:

<data_type> <name_of_array>[num_of_columns];

Ví dụ:

int iArray[100]; //declare an array of integer can hold 100 elements

Bây giờ, khi quản lý mảng hai chiều, chúng ta còn phải quan tâm thêm về số hàng mà mảng hai chiều cần cấp phát:

<data_type> <name_of_array>[num_of_rows][num_of_columns];

Lưu ý, khi khai báo số lượng phần tử của mảng hai chiều, số hàng phải đặt trước số cột.

Ví dụ:

int array2D[3][5]; // 3x5 elements (3 rows, 5 columns)

Có thể nói cách khác, mảng có tên array2D có kiểu dữ liệu int, mảng array2D gồm có 3 mảng một chiều, mỗi mảng một chiều trong đó có thể chứa được tối đa 5 phần tử.

Khởi tạo mảng hai chiều

Mình lấy lại ví dụ về mảng có tên array2D như trên, mình sẽ khởi tạo giá trị cho mảng như sau:

int array2D[3][5] = 
{
	{ 1,  2,  3,  4,  5 },  //row 1
	{ 6,  7,  8,  9,  10 }, //row 2
	{ 11, 12, 13, 14, 15 }  //row 3
};

Do mảng array2D có 3 hàng, mỗi hàng lại là một mảng một chiều khác nhau, nên mình đã sử dụng cách khởi tạo của mảng một chiều, áp dụng cho mỗi hàng trong mảng hai chiều array2D.

Các bạn có thể khởi tạo mảng hai chiều theo cách sau:

int array2D[3][5] = 
{
	1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
};

Nhưng mình vẫn khuyến khích các bạn sử dụng cách mình trình bày ở trước để tránh nhầm lẫn trong việc tổ chức dữ liệu.

Những phần tử chưa được khởi tạo giá trị sẽ được gán bằng giá trị mặc định tùy vào mỗi kiểu dữ liệu khác nhau. Như ví dụ sau mình sử dụng kiểu int để khai báo mảng hai chiều:

int seats[3][5] =
{
	{ 1, 2 },		//row 1 = 1, 2, 0, 0, 0
	{ 6, 7, 8 },	//row 2 = 6, 7, 8, 0, 0
	{ 11 },			//row 3 = 11, 0, 0, 0, 0
};

Tương tự mảng một chiều, nếu các bạn khởi tạo mảng hai chiều ngay khi khai báo, compiler có thể tự xác định số hàng cần cấp phát:

int array2D[][4] = 
{
	{ 1, 2, 3, 4 },
	{ 5, 6, 7, 8 }
};

Các bạn có thể bỏ trống phần khai báo số lượng hàng, nhưng không thể không khai báo số lượng cột.

Truy cập các phần tử trong mảng hai chiều

Lấy ví dụ mình có một mảng hai chiều có 3 hàng và 4 cột tạo thành bảng như sau:

int board[3][4];

Để xác định tọa độ (ví trị) của một phần tử trong một mảng hai chiều, chúng ta cần xác định hai tham số là chỉ số dòng và chỉ số cột. Chúng ta truy cập vào chỉ số dòng trước và chỉ số cột sau. Ví dụ:

board[1][2]; //Access element on row 2 and column 3

Thực hiện truy cập mảng board với chỉ số dòng là 1 và chỉ số cột là 2 sẽ trỏ đến ô nhớ tại dòng thứ 2 và cột thứ 3, do chỉ số của mảng sẽ bắt đầu từ 0. Tương tự, để truy cập phần tử của cùng của mảng hai chiều 3x4, chúng ta truy cập với chỉ số (2, 3).

Để truy cập toàn bộ mảng hai chiều, chúng ta có thể sử dụng 2 vòng lặp: vòng lặp ngoài sẽ truy cập lần lượt các dòng, vòng lặp bên trong sẽ truy cập tất cả các cột của dòng hiện tại mà vòng lặp ngoài đang truy cập đến.

int board[3][4] = 
{
	{ 1, 1, 1, 1 },
	{ 2, 2, 2, 2 },
	{ 3, 3, 3, 3}
};

for(int row = 0; row < 3; row++)
{
	for(int col = 0; col < 4; col++)
	{
		cout << board[row][col] << " ";
	}
	cout << endl;
}
Nhập dữ liệu cho mảng hai chiều

Cũng tương tự việc các bạn nhập dữ liệu cho mảng một chiều, chúng ta sử dụng đối tượng cin trong thư viện iostream. Các bạn chỉ cần lưu ý rằng khi thao tác với các phần tử trong mảng hai chiều, chúng ta phải cung cấp đủ 2 chỉ số (hàng và cột) thì mới xác định được địa chỉ phần tử mà chúng ta cần thao tác.

cin >> <name_of_array>[row_index][col_index];

Trong đó, row_index là chỉ số dòng của phần tử, col_index là chỉ số cột của phần tử.

Ví dụ:

int board[3][3];

for(int row = 0; row < 3; row++)
{
	for(int col = 0; col < 3; col++)
	{
		cin >> board[row][col];
	}
}

Tổng kết

Trong bài học này, chúng ta đã cùng tìm hiểu về một cách tổ chức dữ liệu mới trên máy tính. Mảng hai chiều được sử dụng khá phổ biến để giải quyết một số thuật toán yêu cầu tối ưu như Quy Hoạch Động, bài toán đồ thị, … Cũng có thể được sử dụng trong việc thiết kế một số trò chơi đơn giản, ví dụ game Minesweeper. Chúng ta sẽ còn ứng dụng nhiều về mảng hai chiều trong các bài học sau.

Bài tập cơ bản

1/ Viết chương trình nhập dữ liệu cho mảng hai chiều có số dòng, số cột dương (tùy ý bạn). In ra màn hình kết quả là tổng của mỗi dòng trong mảng hai chiều bạn vừa nhập.

Ví dụ mình nhập mảng hai chiều 3x3 như sau:

1 3 4
2 1 6
3 3 5

Kết quả in ra màn hình sẽ là:

8
9
11

Trong đó, 8 là tổng các giá trị trong dòng đầu tiên, 9 là tổng các giá trị của dòng thứ 2, 11 là tổng các giá trị của dòng thứ 3.

2/ Viết chương trình tìm kiếm sự xuất hiện của giá trị X nhập từ bàn phím trong mảng hai chiều.


Hẹn gặp lại các bạn trong bài học tiếp theo trong khóa học lập trình C++ hướng thực hành.

Mọi ý kiến đóng góp hoặc thắc mắc có thể đặt câu hỏi trực tiếp tại diễn đàn.

www.daynhauhoc.com


Link Videos khóa học

https://www.udemy.com/c-co-ban-danh-cho-nguoi-moi-hoc-lap-trinh/learn/v4/overview

5 Likes

ý bác là 3x5 :slight_smile:

#include <iostream>
using namespace std;
int main()
{
	int arr_3d[3][3];
	int count,sum = 0,sum1 = 0 ,sum2 = 0 ;
	for (int row = 0; row < 3; row++)
	{
		for (int col = 0; col < 3; col++)
		{
			cin >> arr_3d[row][col];
			switch (row)
			{
			case 0:
				count = arr_3d[row][col];
				sum = sum + count;
				break;
			case 1:
				count = arr_3d[row][col];
				sum1 = sum1 + count;
				break;
			case 2:
				count = arr_3d[row][col];
				sum2 = sum2 + count;
				break;
			default:
				break;
			}
		}
	}
	system("cls");
	for (int x = 0; x < 3; x++)
	{
		for (int y = 0; y < 3; y++)
		{
			cout << arr_3d[x][y] << "  ";
		}
		cout << endl;
	}

	cout << sum << endl << sum1 << endl << sum2 << endl;
	system("pause");
}

bài tập 1: để output ra kết quả giống như đề bài thì em đã làm như thế này và có vẻ dài dòng quá. Có ai cut-off dùm em đc k ạ. Thanks.

#include <iostream>
#include <cstdlib>
#include <ctime>
using namespace std;
int main()
{
	int arr_3d[5][10];
	int x;
	srand(time(NULL));
	cout << "Enter value X: ";
	cin >> x;
	bool condition = false;
	for (int row = 0; row < 5; row++)
	{
		for (int col = 0; col < 10; col++)
		{
			arr_3d[row][col] = rand() % (100 - 1 + 1) + 1;
			cout << arr_3d[row][col] << "  ";
			if (x == arr_3d[row][col])
				condition = true;

		}
		cout << endl;
	}
	if (condition == true)
	{
		cout << "Found X" << endl;
	}
	else
		cout << "Not found X" << endl;
	system("pause");
}

Và đây là bài 2 của em. Cho em xin ý kiến ạ. Thanks

Bạn thêm dòng này để chi thế :neutral_face:

Vì trong vòng for của bạn ấy có dùng hàm rand() , và để mỗi khi F5 thì nó không ra kết quả trùng với lần trước.

2 Likes

Mình xin bổ sung 2 chỗ sau nhé, có thể tham khảo:

Thứ 1: Trong khi duyệt ma trận, nếu bạn đã tìm ra được phần tử trùng với x thì kết luận và break ra luôn, khỏi phải duyệt tiếp chi cho tốn thời gian.

Thứ 2: Không nhất thiết phải cần biến bool cho lắm, trong khi duyệt ma trận, nếu gặp phần tử trùng với x thì printf ra luôn và break, không cần biến bool chi cho dài dòng.

Thế nhé :slight_smile:

2 Likes

Nếu mà làm như bạn đã nói thì nếu chương trình không tìm thấy x thì sẽ in ra ở trong ìf statement đó luôn hay ở ngoài ạ. Cho mình xin ý kiến.

1 Like

Uhm. Cách này mình chỉ tìm x thôi, còn không tìm được thì làm như sau:
Vẫn như ở trên, trong khi duyệt ma trận, nếu gặp phần tử nào trùng với x thì in ra và thoát khỏi chương trình luôn (dùng lệnh exit(0) ) khỏi cần break vì bản chất, break chỉ thoát khỏi vòng lặp chứa nó, còn exit(0) là thoát khỏi chương trình.
Vậy là dưới vòng lặp, bạn để dòng Not found là được.

2 Likes

e mới học code, cả nhà cho e hhỏi vì sao giá trị của các phần tử ko thể nhập vào đc, sau khi nhập vào nó vẫn chỉ hiện ra cái giá trị -858993460

\#include \<iostream \ 
\#include \<array \
using namespace std;
#define MAX_SIZE 100

void Nhapmang2D(int arr[][MAX_SIZE], int &r,int &c)
{
	cout << "Moi nhap gia tri cua mang 2D: " << endl;
	for (int row = 0; row < r; row++)
	{
		for (int col = 0; col < c; col++)
		{
			cout << "arr[" << row << "][" << col << "] = ";
			cin >> arr[r][c];
		}
	}
}

void Inmang2D(int arr[][MAX_SIZE], int r, int c)
{
	cout << "Bang v2D vua nhap: " << endl;
	for (int row = 0; row < r; row++)
	{
		for (int col = 0; col < c; col++)
		{
			cout << arr[row][col] <<" ";
		}
		cout << endl;
	}

}
int main()
{
	int arr[MAX_SIZE][MAX_SIZE];
	int r,c;
	do
	{
		cout << "Nhap so luong hang: ";
		cin >> r;
		cout << "Nhap so luong cot: ";
		cin >> c;
	} while ((r < 0 || r>100) && (c < 0 || c>100));

	Nhapmang2D(arr, r, c);
	Inmang2D(arr, r, c);

	system("pause");
	return 0;
}
#include <iostream>

using namespace std;

int main()
{

    cout << "Moi ban nhap rows and columns cua mang 2 chieu"<< endl;
    int m,n;
    cin >> n >> m;
    int Arr[n][m];
    for(int i=0; i< n; i++)
    {
        for(int t =0 ; t < m ; t ++)
        {
            cin>> Arr[i][t];

        }


    }
      for(int i=0; i< n; i++)
    {   int tong=0;
        for(int t =0 ; t < m ; t ++)
        {

            tong += Arr[i][t];
        }
        cout << tong<< endl;

    }
    return 0;

}

thay bằng cin>>arr[row][col]. Vì row, col chạy nên mới ghi mảng.

#include<iostream>
using namespace std;
int main()
{
	int arr[3][3];
	for(int row =0;row<3;row++)
	{
		for(int col =0;col<3;col++)
		{
              cout<<"arr["<<row <<"]["<<col<<"]:";
              cin>>arr[row][col];
		}
	}
		for(int row =0;row<3;row++)
	{
		int S=0;
		for(int col =0;col<3;col++)
		{
			S+= arr[row][col];
	}
	cout<<S<<endl;
	}
	system("pause");
	return 0;

mình xin đóng góp 1 chút

1 Like

Em làm bài 1 ạ:

#include <iostream>
#include <cmath>
using namespace std;

int main() {
	int32_t arr1[3][4];
	cout << "This array can hold a maximum of " << 3*4 << " numbers." << endl;
	for (int32_t row = 1; row <= 3; row++) {
		for (int32_t col = 1; col <= 4; col++) {
			cout << "Enter value to data cell at row " << row << ", col " << col << " : ";
			cin >> arr1[row][col];
		}
	}
	cout << "Here is your final array: " << endl;
	cout << endl;
	for (int32_t col = 1; col <= 4; col++) {
		cout << "\t col " << col << ":";
	}
	cout << "\n";
	for (int32_t row = 1; row <= 3; row++) {
		cout << "Row " << row << ":";
		for (int32_t col = 1; col <= 4; col++) {
			cout << "\t" << arr1[row][col];
		}
		cout << "\n";
	}
	cout << endl;
	cout << endl;
	for (int32_t row = 1; row <= 3; row++) {
		int32_t col = 1;
		cout << "Sum of all the values in row " << row << ": ";
		cout << arr1[row][col] + arr1[row][col + 1] + arr1[row][col + 2] + arr1[row][col + 3];
		cout << "\n";
	}
	system("pause");
	return 0;
}
2 Likes

Bạn nên chú ý đôi chút chỗ này. arr1[][] được biểu diễn trong máy là từ arr1[0][0] cho đến arr1[2][3] Vậy nên phải sửa lại là arr1[row - 1][col - 1], còn một vài chỗ nữa, bạn tự sửa nốt nha. :slight_smile:


Mà bạn vô đây để học cách dùng markdown để format source code nha. :wink:

2 Likes
// Bài 1:


#include <iostream>
#include <stdio.h>
#include <cstdint>

using namespace std;

int main(int argc, const char * argv[]) {
    
    //khai báo mảng 2 chiều 3x3
    int64_t board[3][3];
    for (int64_t row = 0; row < 3; row++) {
        for (int64_t col = 0; col < 3; col++) {
            cin >> board[row][col]; //nhập hàng và cột
        }
        cout << endl;
    }
    //tính tổng hàng row
        for(int64_t row = 0; row < 3; row++)
        {
            int64_t tong = 0;

            for(int64_t col = 0; col < 3; col++)
            {
                tong += board [row][col];
                
            }
            cout << tong << endl; //xuất tổng
        }
    
    return 0;
}
2 Likes
    int temp = 0;
    for (int rows = 0; rows < 3; rows++)
    {
        for (int columns = 0; columns < 3; columns++)
        {
            temp = arr[rows][columns] + temp;
        }

        cout << temp << " ";
        temp = 0;
    }
83% thành viên diễn đàn không hỏi bài tập, còn bạn thì sao?