Giáo trình C++ cơ bản

Trong project HelloWorld, hiện tại chúng ta quan tâm đến 2 phần chính:

• Header Files: dùng để chứa các phần khai báo class, khai báo hàm hoặc phần khai báo một

số hằng số được sử dụng cho chương trình. Các file được chứa trong phần Header thường

có phần đuôi mở rộng là .h, .hpp.

• Source Files: là nơi chứa các file định nghĩa các hàm, các class. Các file được đặt trong này

thường có dạng .cpp.

pdf 123 trang kimcuc 21420
Bạn đang xem 20 trang mẫu của tài liệu "Giáo trình C++ cơ bản", để tải tài liệu gốc về máy hãy click vào nút Download ở trên

Tóm tắt nội dung tài liệu: Giáo trình C++ cơ bản

Giáo trình C++ cơ bản
Ở các bài trước, chúng ta đã biết về quy trình làm việc để tạo ra một chương trình C++, những công 
cụ cần thiết và IDE mà chúng ta sẽ sử dụng để phát triển chương trình. Đến đây chắc các bạn cũng 
đang háo hức muốn bắt tay vào viết một cái gì đó. Trong bài này, chúng ta sẽ cùng viết một chương 
trình mà bất cứ lập trình viên C++ nào cũng từng trải qua. Một chương trình huyền thoại mang 
tên "Hello World". 
Để bắt đầu viết chương trình, chúng ta cùng mở IDE Visual studio 2015 lên và tạo một project. Tại 
giao diện Start Page của Visual studio, các bạn click chọn New Project. 
Cửa sổ tạo project mới hiện ra, các bạn chọn Empty project, đặt tên cho project là HelloWorld. Sau 
đó, ở phần location các bạn có thể chọn đường dẫn thư mục để lưu project này vào. 
Nhấn chọn OK để hoàn tất việc tạo project mới. Ngay khi Visual studio thiết lập project bạn vừa tạo. 
Bạn có thể nhìn vào cửa sổ Solution Explorer (mặc định là bên trái) để xem cấu trúc tổ chức của 
một project như thế nào. 
1.0 Viết chương trình đầu tiên 
PHẦN 1: C++ CƠ BẢN 
Project HelloWorld được Visual studio tổ chức dưới dạng cây thư mục để quản lý mã nguồn và tài 
nguyên. 
Trong project HelloWorld, hiện tại chúng ta quan tâm đến 2 phần chính: 
• Header Files: dùng để chứa các phần khai báo class, khai báo hàm hoặc phần khai báo một 
số hằng số được sử dụng cho chương trình. Các file được chứa trong phần Header thường 
có phần đuôi mở rộng là .h, .hpp. 
• Source Files: là nơi chứa các file định nghĩa các hàm, các class... Các file được đặt trong này 
thường có dạng .cpp. 
Bây giờ chúng ta cùng tạo file chương trình đầu tiên. Các bạn click chuột phải vào tên project ở trong 
khung Solution Explorer, chọn đến dòng Add và click chọn New Item... 
Trong cửa sổ Add New Item, các bạn chọn loại file cần thêm là C++ File (.cpp), đặt tên file ở textbox 
Name phía bên dưới. Để tạo một thói quen tốt, file này các bạn đặt tên là main.cpp sau đó click Add. 
Sau khi add file main.cpp xong, cùng nhìn lại phần tổ chức project trong cửa số Solution 
Explorer xem điều gì đang xảy ra. 
Chúng ta đã có thêm 1 file được đặt sẵn trong phần Source Files. Một file có đuôi mở rộng là .cpp 
luôn được đặt trong phần này. Phía bên phải là phần soạn thảo mã nguồn cho file main.cpp đã được 
mở sẵn. Như đã nói ở trên, file đầu tiên cần tạo cho project nên đặt tên là main.cpp để tạo một thói 
quen tốt, chắc các bạn sẽ thắc mắc và đặt câu hỏi tại sao?
Trước hết, chúng ta cùng viết một ít mã lệnh cho HelloWorld program. 
Nhấn tổ hợp phím Ctrl + S để lưu lại những gì bạn đã viết. Ở mức độ hiện tại, mình chỉ yêu cầu các 
bạn viết theo những gì mình đã viết, chưa yêu cầu các bạn phải hiểu được những dòng mã trên có ý 
nghĩa gì. Sau khi lưu file main.cpp lại, chúng ta đã có được file mã nguồn C++ đầu tiên. Các bạn có 
thể muốn xem thử file main.cpp vừa được lưu đang nằm chổ nào. Để xem thư mục gốc của project, 
các bạn click chuột phải vào tên project HelloWorld trong cửa sổ Solution Explorer rồi chọn Open 
Folder in File Explorer. 
Và chúng ta thấy file main.cpp như trong hình bên dưới. 
Quay lại với màn hình làm việc của Visual studio. Các bạn click chuột vào menu item BUILD trên 
Tool bar, sau đó chọn Build Solution (hoặc nhấn phím F7). 
Thực hiện bước này, Visual studio sẽ biên dịch file main.cpp của bạn để tạo thành file object .obj, 
đồng thời liên kết file main.obj tạo thành file chương trình (có đuôi .exe). Chúng ta chuyển qua thư 
mục gốc của project chứa file main.cpp lúc nãy, double click vào thư mục Debug, chúng ta thấy file 
main.obj là kết quả của quá trình biên dịch mã nguồn. 
Quay lui thư mục chứa file main.cpp ban đầu, cùng chuyển lui một thư mục ngoài nữa. Chúng ta lại 
thấy một thư mục có tên là Debug khác. 
Vào trong thư mục Debug này, các bạn sẽ thấy file .exe đã được Visual studio tạo ra. 
Bây giờ, các bạn mở file HelloWorld.exe này bằng cách double click vào nó. Cùng xem kết quả xuất 
hiện trên màn hình. 
Như các bạn thấy, trong cửa số Console, chúng ta có một dòng chữ xuất hiện: "Hello World.", và một 
dòng gợi ý cho người dùng rằng: Hãy nhấn 1 phím bất kì để kết thúc chương trình. 
Ngoài cách chạy trực tiếp file HelloWorld.exe trong thư mục Debug, các bạn còn có thể chạy chương 
trình ngay trên màn hình làm việc của Visual studio, bằng cách click chuột phải vào tên project trong 
cửa sổ Solution Explorer -> Debug -> Start new instance. 
Và ta được kết quả tương tự khi chạy trực tiếp file HelloWorld.exe 
Vậy là chúng ta đã viết xong chương trình đầu tiên của khóa học lập trình C++. Bây giờ mình muốn 
quay lại vấn đề mình đã nói ở trên, đó là tại sao chúng ta lại nên đặt tên file đầu tiên cho project là 
main.cpp? 
Để giải thích vấn đề này, mình muốn các bạn nhìn lại mã nguồn của file main.cpp mà các bạn đã viết 
cùng mình để có cái nhìn tổng quan về cấu trúc của một chương trình C++ cơ bản. 
Các bạn hãy chú ý đến dòng 6 trong chương trình trên. Chúng ta thấy 
int main() 
Đó là dòng bắt buộc phải có nếu muốn mã nguồn C++ có thể hoạt động được. Main trong tiếng Anh 
khi dịch ra có nghĩa là chính, quan trọng. Trong ngôn ngữ C++, main là điểm khởi đầu cho một 
chương trình. Trong một thời điểm, máy tính của chúng ta chỉ có thể thực hiện 1 dòng lệnh. Và ở thời 
điểm chương trình C++ bắt đầu chạy, nó sẽ tìm tới nơi có khai báo là main để thực hiện mã lệnh ở 
trong đó. 
Mã lệnh mà chương trình thực hiện sẽ được đặt trong cặp ngoặc nhọn { và }. 
Vì thế, cấu trúc chương trình C++ mà bạn cần nhớ sẽ như bên dưới. 
Các bạn cần lưu ý, một chương trình C++ chỉ có duy nhất một hàm main. 
Các bạn sẽ thấy nhiều hàm main có cách khai báo khác nhau. Nhưng với việc 
bạn là người mới bắt đầu học C++, mình khuyến nghị các bạn nên sử dụng theo 
cách trong hình trên. 
int main() 
{ 
} 
Chương trình của C++ sẽ thực hiện từng dòng lệnh trong cặp ngoặc nhọn { } ở phía sau hàm main 
một cách có thứ tựtừ trên xuống dưới. 
Một chương trình C++ bắt buộc phải có 1 hàm main, thế nên mình khuyên các bạn nên đặt tên file 
đầu tiên trong chương trình main.cpp, và file này sẽ chứa mã nguồn C++ có hàm main ở trong đó, 
sau này các bạn làm việc với 1 dự án có nhiều file thì sẽ không bị nhầm lẫn. 
Chào mừng các bạn đến với bài học tiếp theo trong khóa học lập trình C++ hướng thực hành. 
Trong bài trước, Viết chương trình C++ đầu tiên, chúng ta đã cùng nhau tạo 1 project có 
tên HelloWorld. Các bạn lưu ý rằng khi làm việc với Visual studio 2015 thì chúng ta làm việc trên 1 
project chứ không làm việc với file mã nguồn đơn lẻ. Project HelloWorld hiện tại chỉ có một file có 
tên là main.cpp. Kết quả khi thực thi project này (bằng cách nhấn phím F5 để Debug) thì chúng ta 
được như hình bên dưới: 
Kết quả là một dòng chữ Hello World xuất hiện trên console. 
1.1 Cấu trúc cơ bản của một chương trình C++ 
Khi các bạn Debug trên Visual studio 2015, có thể Visual studio sẽ download một số file PDB về làm 
tốn thời gian. Các bạn có thể tắt việc tự động download các file đó bằng cách làm theo các bước 
sau: 
Đưa chuột vào phần DEBUG trên Menu bar -> chọn Options and Settings... 
Chọn Symbols và bỏ dấu tick trong Symbol file (.pdb) locations đi 
Bây giờ chúng ta nhìn lại mã nguồn trong file main.cpp và mình sẽ phân tích chức năng của từng 
dòng code. 
/* HelloWorld program - written by Nguyen Chiem Minh Vu */ 
#include 
using namespace std; 
int main() { 
 // We write some code inside main function. 
 cout << "Hello World." << endl; // The "Hello World" string will be appear on screen. 
 system("pause"); // Pause the program to see the result. 
 return 0; 
} 
• Dòng 6: 
int main() 
Như đã nói ở bài trước, main là một hàm mà đi sau nó là một cặp dấu ngoặc nhọn { }, một điểm 
xuất phát cho một project của ngôn ngữ C++. Không cần biết một project C++ của bạn có bao nhiêu 
file, một khi project đã được build và liên kết các file thành một file thực thi (.exe), hệ điều hành sẽ 
thực thi những dòng lệnh trong phạm vi dấu ngoặc nhọn nằm sau hàm main một cách lần lượt từ 
trên xuống dưới. 
Với những bạn lần đầu viết code C++, các bạn có thể bỏ sót dòng này. Cùng xem thử Visual studio 
sẽ làm gì khi bạn không viết ra dòng int main() bằng cách đổi tên main thành một tên bất kỳ. 
 Visual studio thông báo một lỗi nghiêm trọng LNK1561, và nó còn đưa thêm hướng dẫn để lập trình 
viên có thể tự sửa lỗi có nghĩa là điểm khởi đầu cần được định nghĩa. 
Chúng ta quay lại với đoạn mã nguồn có thể chạy được như lúc đầu bằng cách sửa lại tên hàm là 
int main(). 
• Dòng 7: 
// We write some code inside main function. 
Đây không phải là một dòng lệnh. Đây là một dòng comment, mục đích của comment trong code là 
để ghi chú lại những gì mình đang làm. Việc ghi chú này cần được thực hiện thường xuyên đối với 
những người mới học lập trình. Ghi chú giúp bạn ít bị rối và khó hiểu khi nhìn lại những đoạn code cũ 
và những người làm việc cùng nhóm với bạn cũng sẽ hiểu được bạn đang muốn làm gì. 
Một dòng comment bắt đầu với 2 dấu gạch chéo //. 
Bây giờ bạn thử tự viết cho mình vài dòng comment đi nào. Comment bạn có thể đặt ở bất kỳ vị trí 
nào trong mã nguồn (ngoại trừ chèn comment làm ảnh hưởng đến dòng lệnh) mà không bị báo lỗi. Vì 
khi biên dịch, compiler nhìn thấy dòng comment thì nó sẽ bỏ qua và không làm gì cả. 
• Dòng 9: 
cout << "Hello World." << endl; // The "Hello World" string will be appear on screen. 
Đây là một dòng lệnh và đi kèm sau đó là một dòng comment. Dòng lệnh này chính là thứ đã viết lên 
console dòng Hello World mà bạn đã thấy trong kết quả của chương trình. 
Một dòng lệnh phải được kết thúc bằng dấu chấm phẩy ";" 
Lệnh cout có tác dụng viết lên console tất cả những gì nằm trong cặp dấu ngoặc kép " ". Như các 
bạn thấy, chúng ta đặt 2 từ Hello và World bên trong cặp ngoặc kép nên nó đã được in ra màn hình 
console. 
• Dòng 11: 
system("pause"); // Pause the program to see the result. 
Tiếp tục là một dòng lệnh và đi kèm một dòng comment ở phía sau. 
Mục đích của dòng lệnh này là để dừng chương trình và xem kết quả trên màn hình console. Các 
bạn có thể xóa dòng này đi và chạy lại chương trình bằng cách nhấn phím F5 để kiểm chứng kết 
quả. Lúc này màn hình console hiện lên và tắt ngay lập tức. 
• Dòng 12: 
return 0; 
Là giá trị trả về của hàm main. Hàm main của chúng ta có từ khóa int đứng trước, có nghĩa là kiểu 
trả về của hàm main sẽ là một giá trị có kiểu int (integer - số nguyên). Giá trị trả về này do lập trình 
viên tự quy định. Kết quả hàm main sẽ hiển thị trong cửa sổ Output bên trong IDE sau khi bạn tắt 
chương trình HelloWorld đang chạy đi. 
Thông thường, dòng này sẽ đặt cuối cùng trong phạm vi cặp ngoặc nhọn { } phía sau hàm main. Các 
bạn có thể thay bằng một con số bất kì sao cho bạn có thể hiểu được rằng, khi chương trình kết 
thúc, nếu Output xuất hiện con số mà bạn đã chọn, điều đó có nghĩa chương trình của bạn hoạt 
động một cách bình thường. 
• Dòng 3 và 4: 
#include 
using namespace std; 
Đây là những dòng lệnh đặc biệt. Để có thể sử dụng dòng lệnh số 9 trong chương trình thì chúng ta 
cần có dòng lệnh số 3 và số 4 này. Mục đích của 2 dòng lệnh này là thêm thư viện có 
tên iostream và không gian tên std để tích hợp vào chương trình. Hay nói cách khác, vì 
lệnh cout được định nghĩa bên trong thư viện có tên iostream và bên trong không gian tên std nên 
chúng ta cần tích hợp 2 thứ đó vào chương trình. Đến đây các bạn sẽ thắc mắc là "Làm thế nào 
biết được dòng lệnh nào đã được định nghĩa bên trong thư viện nào?" 
Qua quá trình thực hành trong khóa học này, mình sẽ cùng các bạn sử dụng một số chức năng bên 
trong một số thư viện chuẩn do ngôn ngữ C++ đã định nghĩa sẵn và các bạn sẽ quen với việc tìm và 
sử dụng chức năng nào trong thư viện nào. 
Đây cũng là một đặc trưng của ngôn ngữ lập trình bậc cao. Chúng ta sử dụng lại những gì đã được 
định nghĩa sẵn giúp công việc lập trình của chúng ta dễ dàng hơn. 
• Dòng 1: 
/* HelloWorld program - written by Nguyen Chiem Minh Vu */ 
Đây cũng là một đoạn comment. Đoạn comment khác với dòng comment. Đoạn comment được đặt 
giữa cặp dấu /* và */ trong khi dòng comment đứng sau 2 dấu gạch chéo //. Chúng ta có thể có nhiều 
dòng comment trong 1 đoạn comment. Ví dụ: 
/* 
 Đây là một dòng comment. 
 Đây là một dòng comment khác. 
 Các bạn thích viết bao nhiêu dòng comment giữa này cũng được. 
*/ 
Mình đã giải thích xong chức năng và cách hoạt động của mã nguồn file main.cpp trong 
project HelloWorld. Có thể các bạn chưa thể hiểu hết được, nhưng đừng lo lắng về điều đó, chúng 
ta sẽ quen với việc sử dụng ngôn ngữ C++ khi thực hành nhiều và nếu cần thiết các bạn sẽ được 
những người làm khóa học này hỗ trợ trực tiếp. 
Bây giờ là lúc để hình dung về cấu trúc của chương trình C++ cơ bản mà chúng ta đã làm cùng 
nhau. 
Cấu trúc cơ bản của chương trình C++ 
Đâu tiên, chúng ta có hàm main 
int main() 
Sau đó, chúng ta có phần thân của hàm main là cặp dấu ngoặc nhọn đứng sau từ khóa main, cuối 
thân hàm main là giá trị trả về của hàm main. 
int main() 
{ 
 return 0; 
} 
Tiếp đến, chúng ta có những dòng lệnh đặt bên trong thân hàm main 
int main() 
{ 
 cout << "This is a command" << endl; 
 return 0; 
} 
Bên cạnh những dòng lệnh, chúng ta còn có những dòng comment 
// This comment is located outside main function 
/* We can put comment everywhere in a C++ file */ 
int main() 
{ 
 // We are coding inside main function 
 cout << "This is a command" << endl; 
 return 0; 
} 
Và cuối cùng là những thư viện cần thiết để compiler có thể hiểu được những lệnh đã được định 
nghĩa sẵn trong ngôn ngữ lập trình C++ 
#include 
#include 
#include 
using namespace std; 
// This comment is located outside main function 
/* We can put comment everywhere in a C++ file */ 
int main() 
{ 
 // We are coding inside main function 
 cout << "This is a command" << endl; 
 return 0; 
} 
Các bạn lưu ý là không nên include cả đống thư viện chưa cần dùng đến nhé. Cần dùng lệnh gì đã 
được định nghĩa sẵn mới cần include vào. Tất nhiên khi thêm nhiều thư viện vào chương trình thì 
IDE sẽ không báo lỗi vì compiler biết thư viện nào được dùng, nhưng chương trình của chúng ta sau 
khi build ra sẽ nặng hơn. Nếu các bạn sử dụng những lệnh được định nghĩa trong thư viện mà không 
include nó vào thì IDE sẽ báo lỗi ngay. 
Ví dụ mình bỏ dòng #include đi, IDE sẽ báo lỗi như hình bên dưới: 
 Như các bạn thấy, cả lệnh cout, system(""), và endl đều được định nghĩa bên trong thư 
viện iostream nên khi xóa thư viện đó đi, chương trình gạch chân màu đỏ các từ đó, đồng thời thông 
báo lỗi trong cửa sổ Output. 
Tổng kết 
Trong bài học hôm nay, chúng ta đã biết thêm một số điểm đáng chú ý khi làm việc với chương trình 
C++: 
• Một dòng comment sẽ đứng sau 2 dấu gạch chéo //. 
• Một đoạn comment sẽ nằm giữa cặp /* và */. 
• Một dòng lệnh phải được kết thúc bằng dấu chấm phẩy ";" 
• Cấu trúc của một chương trình C++ cơ bản: 
o Hàm main: (bắt buộc phải có) 
▪ Kiểu trả về của hàm main (int). 
▪ Tên của hàm main (cũng là main luôn). 
▪ Thân của hàm main (cặp dấu ngoặc nhọn { và }). 
▪ Giá trị trả về của hàm main (return 0; //hoặc giá trị bao nhiêu cũng đc). 
o Những dòng lệnh bên trong thân hàm main. (Có thể có hoặc không) 
o Nh ... cout << "Number of elements: " << arr.size() << endl; 
Phương thức empty() trả về giá trị true nếu mảng bên trong đối tượng arr có số lượng phần 
tử là 0. 
• Truy xuất đến phần tử đầu tiên và phần tử cuối cùng của mảng bên trong đối tượng của 
lớp array: 
• cout << "The first element: " << arr.front() << endl; 
cout << "The last element: " << arr.back() << endl; 
Ví dụ mảng một chiều của mình được khởi tạo giá trị là 1 2 3 4 5. Kết quả in ra màn hình sẽ là: 
Phương thức front() sẽ trả về giá trị của phần tử đầu tiên trong mảng, ngược lại, phương 
thức back() sẽ trả về giá trị của phần tử cuối cùng trong mảng. 
Nhập dữ liệu cho đối tượng của lớp array 
Tương tự lúc các bạn nhập dữ liệu cho mảng một chiều thông thường, chúng ta sử dụng đối 
tượng cin để đưa giá trị được nhập từ bàn phím vào trong mỗi phần tử mà đối tượng của 
lớp array đang nắm giữ. 
for (int i = 0; i < arr.size(); i++) { 
 cout << "Enter value to element " << i + 1 << ": "; 
 cin >> arr[i]; 
} 
Lớp array ngăn chặn hành vi truy cập phần tử có chỉ số không phù hợp 
Chúng ta chỉ có thể truy xuất đến các phần tử trong đối tượng của lớp array với chỉ số trong phạm vi 
từ 0 đến (size() - 1). Sau đây là những hành vi truy xuất hợp lệ: 
#define ARRAY_SIZE 10 
array arr; 
arr.assign(10); 
//Access to all of elements of arr object 
for (int32_t index = 0; index <= arr.size() - 1; index++) { 
 cout << arr[index] << " "; 
} 
cout << endl; 
Và dưới đây là một số hành vi truy xuất giá trị của đối tượng arr bằng những chỉ số không hợp lệ: 
//Try to access array with wrong index 
arr[-1]; 
arr[arr.size() + 10]; 
Khi gặp những dòng lệnh này, compiler sẽ đưa ra cảnh báo: 
Vì bên trong lớp array có sử dụng thư viện cassert để đặt ra những Assertion, những Assertion này 
kiểm tra về chỉ số mà bạn đưa vào cho toán tử [ ] và phương thức at() để kiểm tra sự hợp lệ của chỉ 
số trước khi thực hiện lệnh. Mọi hành vì không phù hợp với điều kiện trong Assertion sẽ bị ngăn 
chặn. 
Các bạn cũng có thể tự mình tạo ra những Assertion bằng cách sử dụng thư viện cassert. 
Thư viện cassert 
Thư viện cassert cung cấp cho chúng ta macro có tên là assert(expression) giúp chúng ta tạo ra 
những Assertion trong chương trình. 
Khi gặp macro assert(expression), chương trình sẽ kiểm tra biểu thức expression (là một biểu thức 
điều kiện có thể trả về giá trị true/false) và có hai trường hợp có thể xảy ra: 
• expression trả về giá trị true: 
Chương trình sẽ tiếp tục thực hiện các dòng lệnh phía sau Assertion một cách bình thường. 
Ví dụ: 
float f_value = 1.0; 
assert(typeid(f_value) == typeid(float)); 
f_value++; 
cout << f_value << endl; 
Đoạn chương trình trên có 1 Assertion thực hiện công việc kiểm tra kiểu dữ liệu của 
biến f_value. Vì biểu thức typeid(f_value) == typeid(float) trả về giá trị true, nên chương 
trình vẫn được tiếp tục hoạt động. 
• expression trả về giá trị false: 
Chương trình sẽ dừng lại tại thời điểm phát hiện biểu thức bên trong Assertion cho giá 
trị false. 
#define ARRAY_SIZE 5 
array arr; 
for(int32_t index = 0; index <= arr.size(); index++) { 
 assert(index >= 0 && index <= arr.size() - 1); 
 cin >> arr[index]; 
} 
Đoạn chương trình trên thực hiện nhập dữ liệu cho đối tượng arr có kiểu array. Bên trong 
vòng lặp for, mình đặt 1 Assertion nhằm kiểm tra chỉ số của mảng có được cung cấp chính 
xác hay không. Chỉ số chính xác sẽ nằm trong khoảng từ 0 đến (arr.size() - 1). 
Bây giờ mình sẽ chạy đoạn chương trình trên để xem kết quả: 
4.png?raw=true793x372 
Ngoài việc chương trình đưa ra cửa sổ thông báo lỗi và bắt các bạn Abort chương trình đang 
chạy, trên cửa sổ console còn đưa ra thông báo lỗi tại dòng mình đặt Assertion. 
Trước khi lỗi xảy ra, mình vẫn nhập dữ liệu bình thường. Vì lúc đó chỉ số index của vòng 
lặp for vẫn thõa mãn biểu thức điều kiện bên trong Assertion. Nhưng mà vòng lặp for của 
mình lại lặp với biến index chạy từ 0 đến arr.size(), vì thế, giá trị index tại lần lặp cuối cùng đã 
vi phạm biểu thức trong Assertion mà mình tự đặt ra. 
Tổng kết 
Trong bài học hôm nay, các bạn đã được tìm hiểu thêm thư viện array hổ trợ cho các bạn quản lý 
mảng một chiều một cách hiệu quả và dễ dàng hơn. Mình cũng đã hướng dẫn cho các bạn cách để 
tạo ra những Assertion cho chương trình của các bạn với thư viện cassert. Bất cứ khi nào các bạn 
cần đảm bảo chương trình của các bạn không vi phạm quy tắc nào đó, các bạn có thể dùng 
macro assert(expression) của thư viện cassert để hạn chế những lỗi có thể xảy ra. 
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++. 
5.3 Mảng hai chiều 
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: 
 [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: 
 [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 >> [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. 
Trong bài học này, mình sẽ hướng dẫn các bạn thực hiện một số thao tác cơ bản với mảng hai 
chiều, cũng có thể coi đây là giải một số bài tập mẫu cơ bản, giúp các bạn hình thành tư duy giải các 
bài toán có thể giải quyết được bằng mảng hai chiều cơ bản. 
Tính tổng các phần tử trên đường chéo chính 
Trường hợp mảng hai chiều có đường chéo chính và đường chéo phụ chỉ tồn tại khi số hàng bằng 
số cột (có nghĩa là ma trận vuông). Khi đó, đường chéo chính có dạng: 
Đặc điểm của các phần tử nằm trên đường chéo chính của ma trận vuông là chỉ số hàng luôn bằng 
chỉ số cột. 
{ a[i][i] | 0 <= i <= n-1 } 
5.4 Các thao tác cơ bản với mảng hai chiều 
Giả sử số hàng (hoặc số cột) của ma trận vuông này là N, chúng ta chỉ cần sử dụng vòng lặp for để 
lặp từ giá trị 0 đến N-1, cứ mỗi lần lặp với biến vòng lặp index, chúng ta cộng dồn giá trị của phần 
tử Array[index][index] vào biến tổng nào đó. 
int main() 
{ 
 int myArr[100][100]; 
 int level; 
 cout << "Enter level of squared matrix: "; 
 cin >> level; 
 //input 
 for (int row = 0; row < level; row++) 
 { 
 for (int col = 0; col < level; col++) 
 { 
 cin >> myArr[row][col]; 
 } 
 } 
 //calculate 
 int sum = 0; 
 for (int index = 0; index < level; index++) 
 { 
 sum += myArr[index][index]; 
 } 
 //output 
 cout << "Result: " << sum << endl; 
 system("pause"); 
 return 0; 
} 
Trong chương trình trên, mảng hai chiều myArr chưa được khởi tạo khi khai báo, nên mình phải 
cung cấp thông tin số hàng và số cột cụ thể cho compiler. 
Xóa một dòng trong mảng hai chiều 
Về phần input, chúng ta nhập dữ liệu bao gồm số hàng, số cột và giá trị của mỗi phần tử trong mảng 
hai chiều. 
Trong phần xử lý, chúng ta cần nhập số dòng cần loại bỏ khỏi mảng hai chiều. Mình chưa thiết kế 
phần xử lý trường hợp nhập sai số dòng. Sau đó, tương tự việc xóa một phần tử trong mảng một 
chiều, ở mảng hai chiều, một phần tử chính là một mảng một chiều. Do đó, chúng ta không phải ghi 
đè giá trị sau lên giá trị trước, mà chúng ta cần ghi đè dữ liệu của dòng sau lên dòng trước đó. 
int main() 
{ 
 int myArr[100][100]; 
 int num_of_row, num_of_col; 
 //input 
 cout > num_of_row; 
 cout > num_of_col; 
 for (int row = 0; row < num_of_row; row++) 
 { 
 for (int col = 0; col < num_of_col; col++) 
 { 
 cin >> myArr[row][col]; 
 } 
 } 
 //process 
 int removeRow; 
 cout << "Enter the row you want to remove: "; 
 cin >> removeRow; 
 //Overide the next row onto the previous row 
 for (int row = removeRow; row < num_of_row - 1; row++) 
 { 
 for (int col = 0; col < num_of_col; col++) 
 { 
 myArr[row][col] = myArr[row + 1][col]; 
 } 
 } 
 num_of_row--; 
 //output 
 for (int row = 0; row < num_of_row; row++) 
 { 
 for (int col = 0; col < num_of_col; col++) 
 { 
 cout << myArr[row][col] << " "; 
 } 
 cout << endl; 
 } 
 system("pause"); 
 return 0; 
} 
Tổng kết 
Trên đây chỉ mới là một số thao tác cơ bản khi cần sử dụng đến mảng hai chiều. Hi vọng bài học này 
có thể giúp các bạn hiểu rõ hơn về bản chất của mảng hai chiều khi lưu trữ trong máy tính. 
Bài tập cơ bản 
Dựa trên chương trình xóa một dòng trong mảng hai chiều mà mình đã làm mẫu ở trên, các bạn hãy 
viết chương trình xóa một cột X được nhập từ bàn phím trong mảng hai chiều. 

File đính kèm:

  • pdfgiao_trinh_c_co_ban.pdf