[Lập trình] Bài 3: Toán tử và cấu trúc điều khiển trong C++

Xin chào tất cả các bạn,

Qua bài học trước tụi mình đã cùng đi qua một loạt những khái niệm rất là căn bản trong C++ như Comments hay Biến (Variables),… Đó là một nguồn vốn để ta tiếp tục đến với những nội dung trong bài viết lần này, vẫn chỉ là những nội dung cực kì cơ bản trong các ngôn ngữ lập trình nói chung cũng như C++ nói riêng, đó là về các Toán tử (Operators)Cấu trúc điều khiển (Flow Controls), bài này sẽ khá dài và cũng là khá khoai nhưng lại cực kỳ thú vị và quan trọng nên các bạn cố gắng nha.

Nội dung

  1. Toán tử và một số loại toán tử thường gặp trong C++

    1. Toán tử (Operators) là gì?

    2. Một số loại toán tử (Operator Types) thường gặp trong C++

  2. Tổng quan về Câu lệnh điều khiển (Flow Controls)

    1. Câu lệnh điều kiện (Conditional Statements)

      1. Câu lệnh if (if Statement)

      2. Câu lệnh if…else (if…else Statement)

      3. Câu lệnh if – else if Ladder (if – else if Ladder Statement)

      4. if lồng if (Nested if Statement)

    2. Vòng lặp (Loops)

      1. Vòng lặp for (for Loop)

      2. Vòng lặp while (while Loop)

      3. Vòng lặp do…while (do…while Loop)

    3. Từ khóa break và continue (break & continue Statements)

    4. Câu lệnh switch…case (switch Statements)

  3. Tổng kết

I. Toán tử và một số loại toán tử thường gặp trong C++

1. Toán tử (Operators) là gì ?

Nguồn ảnh: rawpixel

Toán tử (Operators) trong lập trình là một kí hiệu mà ở đó nó cho phép thực hiện các phép tính toán toán học hay tính toán logic trên các biến. Ví dụ, toán tử + sẽ thực hiện phép cộng 2 biến với nhau:

int x = 10;
int y = 5;

// Gán kết quả của phép cộng 2 số x và y vào z
int z = x + y;

cout << z << endl ; // Kết quả xuất ra mà hình là 15

Ở đây, các biến xy được gọi là các toán hạng (operands), toán tử + sẽ thực hiện thao tác cộng 2 toán hạng đó lại với nhau. Kết quả của phép toán trên đã được mình gán trực tiếp vào khai báo của biến z.

2. Một số loại toán tử (Operator Types) thường gặp trong C++

C++ cung cấp rất nhiều loại toán tử với những công dụng khác nhau nhưng mình sẽ ưu tiên điểm qua những loại toán tử mà chúng ta thường xuyên sử dụng nhất khi làm việc trên C++ nhé.

Toán tử số học (Arithmetic Operators)

Toán tử số học (Arithmetic Operators) là loại toán tử cho phép ta thực hiện các phép tính toán số học bao gồm phép toán cộng, trừ, nhân, chia mà các bạn cũng đã thấy ở ví dụ ban nãy.

Toán tử số học trong C++ có thể được sử dụng như là toán tử một ngôi hoặc toán tử hai ngôi (mình có nói rõ hơn vụ toán tử ngôi thứ này ở phía dưới nha). Cụ thể ở đây với toán tử một ngôi ta sẽ có toán tử tăng ++ (Increment Operator)toán tử giảm -- (Decrement Operator) – chỉ sử dụng trên một biến, còn với kiểu toán tử hai ngôi thì sẽ là các phép tính còn lại được thực hiện trên hai biến, giống với ví dụ mà các bạn đã thấy ở phía trên.

Toán tử Ý nghĩa Ví dụ (với x = 10 và y = 5)
+ Thực hiện phép cộng giá trị 2 biến Kết quả x + y là 15
Thực hiện phép trừ giá trị 2 biến Kết quả x – y là 5
* Thực hiện phép nhân giá trị 2 biến Kết quả x * y là 50
/ Thực hiện phép chia giá trị 2 biến Kết quả x / y là 2
% Thực hiện phép chia lấy phần dư giá trị 2 biến Kết quả x % y là 0
++ Thực hiện tăng giá trị của biến thêm 1 đơn vị Kết quả x++ và ++x là 11
– – Thực hiện giảm giá trị của biến đi 1 đơn vị Kết quả y – – và – – y là 4

Toán tử gán (Assignment Operators)

Toán tử này chắc các bạn cũng khá là quen rồi nè :3 Toán tử gán (Assignment Operators) là loại toán tử cho phép ta thực hiện việc gán một giá trị hoặc một biến cho biến khác, dĩ nhiên giá trị hay biến mà mình sử dụng phải cùng với kiểu dữ liệu của biến được gán đó.

Ngoài ra, toán tử gán còn được kết hợp với toán tử số học, thực hiện việc tính toán và gán giá trị cùng một lúc cho một biến.

Toán tử Ý nghĩa Ví dụ (với x = 10 và y = 5)
= Thực hiện phép gán giá trị cho một biến x = y sẽ cho ta biến x = 5
+= Thực hiện phép toán cộng và gán giá trị cùng lúc cho một biến x += y tương đương với x = x + y
-= Thực hiện phép toán trừ và gán giá trị cùng lúc cho một biến x -= y tương đương với x = x – y
*= Thực hiện phép toán nhân và gán giá trị cùng lúc cho một biến x *= y tương đương với x = x * y
/= Thực hiện phép toán chia và gán giá trị cùng lúc cho một biến x /= y tương đương với x = x / y

Toán tử quan hệ (Relational Operators)

Toán tử quan hệ (Relational Operators) là loại toán tử cho phép ta so sánh giá trị giữa hai biến số như các phép so sánh lớn hơn, nhỏ hơn, lớn hơn hoặc bằng, nhỏ hơn hoặc bằng,… Lưu ý là kết quả của các phép toán so sánh trên sẽ là kiểu luận lý (boolean) nha các bạn, đơn giản sẽ chỉ là đúng (1) hoặc sai (0) thôi.

Toán tử Ý nghĩa Ví dụ (với x = 10 và y = 5)
== Thực hiện so sánh bằng với 2 giá trị của biến Kết quả x == y là 0
!= Thực hiện so sánh khác bằng với 2 giá trị của biến Kết quả x != y là 1
> Thực hiện phép so sánh lớn hơn với 2 giá trị của biến Kết quả x > y là 1
>= Thực hiện phép so sánh lớn hơn hoặc bằng với 2 giá trị của biến Kết quả x >= y là 1
< Thực hiện phép so sánh nhỏ hơn với 2 giá trị của biến Kết quả x < y là 0
<= Thực hiện phép so sánh nhỏ hơn hoặc bằng với 2 giá trị của biến Kết quả x <= y là 0

Toán tử Logic (Logical Operators)

Nhắc các bạn trước, dạng toán tử này có liên quan đến một chủ đề trong toán học mà tụi mình đã học qua ở lớp 10 (không biết các bạn còn nhớ không taarr :3), đó là Mệnh đề toán học. Dạng toán này thường thấy ở các môn học về máy tính vì vậy vô hình trung sẽ không mấy phổ biến với mọi người, những bạn mới tiếp cận học lập trình có thể sẽ còn bỡ ngỡ nên mình khuyên các bạn nên đọc qua trước bài viết sau đây nha :3 Wikipedia: Mệnh đề toán học

Toán tử logic (Logical Operators) là loại toán tử cho phép ta thực hiện việc đánh giá tính đúng sai của 2 hay nhiều các điều kiện khác nhau. Giá trị trả về của toán tử này, cũng giống như toán tử quan hệ, là giá trị luận lý (boolean), tức sẽ chỉ có đúng (1) hoặc sai (0) (nhắc đi nhắc lại cho các bạn mau nhớ :3).

Bây giờ mình sẽ thay thế 2 biến xy bằng giá trị kiểu luận lý, với x = 1 (true) và y = 0 (false), để thực hiện ví dụ phía dưới nha các bạn.

Toán tử Ý nghĩa Ví dụ (với x = true và y = false)
&& Hay còn gọi là toán tử AND, toán tử sẽ trả về giá trị 1 (true) khi cả 2 điều kiện đều trả về giá trị 1 (true) Kết quả x && y là 0
|| Hay còn gọi là toán tử OR, toán tử này sẽ trả về giá trị 1 (true) nếu một trong 2 điều kiện trả về giá trị 1 (true) Kết quả x || y là 1
! Hay còn gọi là toán tử NOT, toán tử này sẽ trả về giá trị 1 (true) nếu điều kiện cho trước trả về giá trị 0 (false) Kết quả !(x && y) là 1

Vừa rồi là những loại toán tử cơ bản nhất mà các bạn bắt buộc phải nắm vững để có thể sử dụng thành thạo khi học C++ nha, vì thật sự gần như lúc nào ta cũng sẽ luôn phải sử dụng chúng đấy :3 Tuy nhiên, để có thể giúp các bạn có mong muốn hiểu sâu hơn về C++ như việc muốn hiểu crush của mình hơn thì ngay bây giờ chúng ta sẽ đi tiếp về việc phân chia loại toán tử một cách khái quát hóa hơn, đó là phân chia theo ngôi (tức số lượng toán hạng có trong một biểu thức) :3

Toán tử một ngôi (Unary Operators)

Toán tử một ngôi (Unary Operators) là loại toán tử chỉ có thể thực hiện trên một toán hạng duy nhất, tức có nghĩa là mình sẽ sử dụng nó chỉ với một biến khi code, và có một điều rằng mọi người thường luôn sử dụng loại toán tử này trong khi lập trình C++ nhưng lại ít ai chú ý đến khái niệm chung của nó. Sau đây hãy cùng mình xem qua một số toán tử một ngôi mà ta thường hay sử dụng nha:

Toán tử tăng (Increment Operator) & Toán tử giảm (Decrement Operator)

Là hai toán tử mà mình đã có “nhá hàng” ban nãy ở phần Toán tử số học đó các bạn :3 Công dụng của nó là sẽ làm tăng/giảm giá trị của một biến 1 đơn vị. Đặc biệt, vị trí đặt của loại toán tử này so với toán hạng (trước hoặc sau toán hạng) cũng sẽ dẫn đến một chút sự khác biệt KHÔNG HỀ NHẸ – nó sẽ quyết định cách thức thay đổi giá trị của toán hạng. Đây là vấn đề rất nhiều bạn thường không quan tâm, nhưng chỉ với một sự thay đổi nhỏ như vậy thôi vẫn có khả năng ảnh hưởng đến chương trình của chúng ta đó nha:

_ Đặt trước toán hạng (Prefix): giá trị của toán hạng (biến) sẽ thay đổi trước khi nó được sử dụng. Các bạn có thể hiểu đơn giản là nó sẽ ưu tiên cập nhật phép toán +1/-1 trước rồi sau đó mới thực hiện công việc cần làm.

_ Đặt sau toán hạng (Postfix): giá trị của toán hạng (biến) sẽ thay đổi sau khi nó được sử dụng. Ngược lại ở phía trên, nó sẽ ưu tiên thực hiện công việc ngoài lề trước rồi sau đó mới bắt đầu cập nhật phép toán +1/-1 cho biến.

Để dễ hiểu hơn mình có một đoạn code ví dụ dưới đây:

// Khởi tạo 2 biến x = 5 và y = 10
int x = 5, y = 10;

// In giá trị của x trước và sau khi sử dụng toán tử tăng đặt phía sau (Postfix Increment) 
cout << x << endl ; // Kết quả in ra màn hình là 5
cout << x++ << endl ; // Kết quả in ra màn hình là 5
cout << x << endl ; // Kết quả in ra màn hình là 6

// In giá trị của x trước và sau khi sử dụng toán tử tăng đặt phía trước (Prefix Increment)
cout << x << endl ; // Kết quả in ra màn hình là 6
cout << ++x << endl ; // Kết quả in ra màn hình là 7
cout << x << endl ; // Kết quả in ra màn hình là 7

// In ra giá trị của y trước và sau khi sử dụng toán tử giảm đặt phía sau (Postfix Decrement)
cout << y << endl ; // Kết quả in ra màn hình là 10 
cout << y-- << endl ; // Kết quả in ra màn hình là 10
cout << y << endl ; // Kết quả in ra màn hình là 9

// In ra giá trị của y trước và sau khi sử dụng toán tử giảm đặt phía trước (Prefix Decrement)
cout << y << endl ; // Kết quả in ra màn hình là 9
cout << --y << endl ; // Kết quả in ra màn hình là 8
cout << y << endl ; // Kết quả in ra màn hình là 8

Toán tử sizeof()

Nhiều bạn lầm rằng đây là một hàm (khái niệm về hàm sẽ được đề cập ở bài viết sau) nhưng thật ra đây là một toán tử nha các bạn, và dĩ nhiên, nó là toán tử một ngôi luôn. Toán tử này nhận giá trị truyền vào là một biến và sẽ trả về kích cỡ của kiểu dữ liệu của biến đó, từ những kiểu dữ liệu đơn giản như integer, floating – point,… đến cả những kiểu dữ liệu phức tạp hơn như mảng (array), con trỏ (pointer), cấu trúc (structure), hay union,…

int x = 5 ; // Khởi tạo biến kiểu integer
double y ; // Khởi tạo biến kiểu double
int arr1[100] ; // Khởi tạo mảng một chiều kiểu integer
double arr2[100] ; // Khởi tạo mạng một chiều kiểu double

// In giá trị sizeof() của từng biến trên
cout << sizeof(x) << endl ; // Kết quả in ra màn hình là 4
cout << sizeof(y) << endl ; // Kết quả in ra màn hình là 8
cout << sizeof(arr1) << endl ; // Kết quả in ra màn hình là 400
cout << sizeof(arr2) << endl ; // Kết quả in ra màn hình là 800

Ngoài ba toán tử trên, ta còn có ! (Not Operator) – đã đề cập ở phần Toán tử Logic, - (Minus Operator) – thay đổi dấu của toán hạng (như kiểu nhân -1 vào một số dương), cũng là những kiểu toán tử một ngôi nằm trong những nội dung mà ta đã học nhưng vì nó cũng không quá phức tạp nên mình sẽ chỉ nói sơ như vậy thôi nha.

Nhưng nhiêu đó thôi vẫn chưa hết đâu, trong C++ vẫn còn rất nhiều các loại toán tử một ngôi khác nhưng vì nó có liên quan đến những nội dung mình chưa học nên mình sẽ không đề cập ở đây nha (các bạn nhớ đón xem những số bài viết kế tiếp để cùng mình khám phá hết các toán tử một ngôi còn lại nè :3).

Toán tử hai ngôi (Binary Operators)

Loại toán tử này thì mình tin chắc là các bạn đã quá quen rồi đúng không nè :3 Toán tử hai ngôi (Binary Operators) là loại toán tử được thực hiện với hai toán hạng, dễ thấy ở các phép toán như cộng trừ nhân chia hay phép so sánh mà mình đã nói ở trên.

Mình sẽ không nói chi tiết gì thêm ở phần này vì thật ra là mình cũng đã…nói quá chi tiết ở những phần đầu tiên của phần toán tử với rất nhiều ví dụ đi kèm rồi nha :3

Toán tử ba ngôi (Ternary Operators)

Những bạn chưa có kiến thức gì về Câu lệnh điều kiện thì hãy tạm bỏ qua phần này nha các bạn, vì nó có liên quan đến – hay cũng có thể nói đó là một cách viết câu lệnh điều kiện dưới dạng toán tử nên thành ra sẽ rất khó hiểu. Vì vậy, các bạn chịu khó đọc trước phần Câu lệnh điều kiện (Conditional Statement) giúp mình nha :3 xong xuôi rồi hẳn quay lại đây cũng chưa muộn đâu :33

Toán tử ba ngôi (Ternary Operators) hay còn có tên gọi khác là Toán tử điều kiện (Conditional Operators), là loại toán tử được thực hiện với ba toán hạng, với kí hiệu rất đặc biệt là ? :. À ha, trông cái này kiểu khá là bí hiểm và thú vị phết đúng không :3 Trước tiên, mình hãy cùng nhìn vào cấu trúc của một toán tử ba ngôi xem nó ra sao đã nha:

// Sau đây là cấu trúc của một toán tử ba ngôi
new_var = điều_kiện ? giá_trị_true : giá_trị_false ;

Trong đó:

  • new_var: là một biến dùng để chứa kết quả của toán tử ba ngôi
  • điều_kiện: là nơi để ta đặt một điều kiện – một phép toán quan hệ , trình biên dịch sẽ đánh giá tính đúng sai của biểu thức này để quyết định giá trị được gán vào new_var
  • giá_trị_true: là giá trị mới của biến new_var nếu kết quả của điều_kiện là đúng (true)
  • giá_trị_false: là giá trị mới của biến new_var nếu kết quả của điều_kiện là sai (false)
Nguồn ảnh: geeksforgeeks

Các bạn có thấy một sự tương quan giữa toán tử ba ngôi với lệnh if – else ở đây không?! Đúng là như vậy chứ còn gì nữa :3 chính vì thế mà nó mới có thêm một tên gọi “đỡ ngầu” hơn là toán tử điều kiện đó (gọi toán tử điều kiện nghe dễ hiểu hơn ha) :3 Để có thể thấy rõ điều này hơn, khi ta “tường thuật” lại toán tử điều kiện này dưới dạng câu if – else thì nó sẽ trông như thế này:

// Đây là toán tử ba ngôi khi ta viết lại dưới dạng câu điều kiện if else
if(điều_kiện == true)
{
    new_var = giá_trị_true ;
}
else
{
    new_var = giá_trị_false ;
}

Đó, toán tử ba ngôi nó chỉ có thế thôi đó các bạn, vậy mà cũng được tách riêng ra rồi còn được dành hẳn cả hai tên gọi khác nhau luôn cơ :3 Nếu các bạn có thắc mắc là nên sử dụng toán tử ba ngôi này hay xài if – else như bình thường thì vụ này là tùy các bạn nha! Lợi thế của cách triển khai của toán tử ba ngôi có thể thấy rõ đó là sự ngắn gọn, nhẹ nhàng, chứ không phải cả tảng như if – else (với cả viết thế này nhìn cũng ngầu hẳn chứ nhỉ) :3 Nhưng cá nhân mình thì khuyên các bạn nếu được thì vẫn nên sử dụng if – else, vì dù gì nhìn nó cũng rõ ràng rành mạch hơn, giúp chương trình của các bạn dễ đọc hơn rất nhiều!

II. Tổng quan về Câu lệnh điều khiển (Flow Controls)

Nguồn ảnh : Medium

Trong ngôn ngữ lập trình nói chung, các câu lệnh (Statements) là tập các chỉ thị mà bản thân ta mong muốn chương trình sẽ thực hiện, ví dụ như việc khai báo một biến (Variables Declaration) hay việc sử dụng các toán tử để tính toán,… Các câu lệnh luôn được kết thúc bằng dấu ; và sẽ được trình biên dịch (compiler) thực thi ngay tại vị trí nó được khởi tạo.

Dĩ nhiên, khi đối mặt với một vấn đề phức tạp, rắc rối và lắc léo hơn có thể sẽ đòi hỏi ta cần thực lặp lại một đoạn code nhỏ nào đó, hoặc đưa ra các chỉ thị riêng biệt cho từng trường hợp có thể xảy ra trong vấn đề đó,… Vì vậy mà trong C++ đã cung cấp các Câu lệnh điều khiển (Flow Controls) để thỏa mãn những nhu cầu nói trên, nó sẽ cho phép ta kiểm soát được việc chương trình của mình phải được thực hiện như thế nào, trong trường hợp ra làm sao,…

Các câu lệnh điều khiển trong C++ được chia làm 3 loại:

  • Lệnh lựa chọn (Selection Statements): cho phép ta thể hiện các điều kiện cần để giải quyết bài toán thông qua các phép toán quan hệ, ở đây mình sẽ quan tâm đến các câu lệnh điều kiện (Conditional Statements)
  • Lệnh lặp (Iteration Statements): cho phép ta thể hiện sự lặp đi lặp lại của một công việc trong chương trình, ở đây mình sẽ quan tâm đến các câu lệnh về vòng lặp (Loops)
  • Lệnh “nhảy” (Jump Statements): cho phép ta thể hiện sự thay đổi của một câu lệnh điều khiển, chẳng hạn như dừng việc lặp lại dù lệnh lặp vẫn còn có thể lặp tiếp được, ở đây mình sẽ quan tâm đến hai từ khóa break và continue (break & continue Statements)

1. Câu lệnh điều kiện (Conditional Statements)

Nguồn ảnh: translatemedia

Giả sử nếu ngoài trời đang mưa và bạn lại đang muốn đi ra ngoài, bạn sẽ làm gì tiếp theo trong trường hợp này ?

Sẽ có rất nhiều câu trả lời luôn đúng không :3 Các bạn không thể biết chắc được kết quả sẽ như thế nào, vì có bạn sẽ chọn ở nhà, có bạn sẽ chọn lấy ô rồi đi,… Nhưng có một điều mình chắc chắn, đó là các bạn phải đưa ra quyết định (Decision Making).

Trong cuộc sống thường ngày, các vấn đề luôn nảy sinh và buộc ta phải đưa ra những quyết định. Vấn đề tương tự cũng xảy ra trong việc lập trình, khi viết một chương trình C++ hay bất kì ngôn ngữ khác, gần như ta sẽ luôn gặp các đáp án khác nhau có thể xảy ra với những điều kiện/yếu tố/trường hợp khác nhau.

Vì những lý do đó, ở phần này hãy cùng mình tiếp tục tìm hiểu qua câu lệnh điều kiện (Conditional Statements) trong C++ nhé.

a. Câu lệnh if (if Statement)

Đây là cú pháp cơ bản nhất của câu lệnh rẽ nhánh trong C++. Nó cho phép truyền vào một hoặc nhiều biểu thức logic khác nhau bên trong dấu () và sau đó kiểm tra tính đúng sai của chúng, nếu tất cả các điều kiện bên trong nó đều thỏa mãn (true), khối lệnh bên trong if sẽ được thực thi. Đây là cấu trúc của một câu lệnh if trong C++:

// Đây là cấu trúc của một câu điều kiện if trong C++
if(điều kiện)
{
   // Các dòng lệnh bên trong if
}

Khi trình biên dịch gặp lệnh if, nó sẽ bắt đầu đánh giá xem điều kiện bên trong sẽ cho giá trị 1 (true) hay 0(false). Nếu true nó sẽ tiếp tục biên dịch các câu lệnh nằm bên trong if, ngược lại nó sẽ bỏ qua và tiếp tục biên dịch các dòng lệnh bên dưới dấu }.

Nguồn ảnh: geeksforgeeks

Để giúp các bạn có thể hiểu rõ hơn nữa, mình sẽ viết lại ví dụ trời mưa ban nãy vào trong C++ để xem như thế nào nha :33

bool isRain = true;

if (isRain == 1) 
{
    cout << "Remember to get an umbrella!" << endl ; 
}

Trong đoạn code trên, mình khai báo một biến kiểu bool để check xem trời có mưa hay không, đồng thời gán luôn giá trị true vào (tức mặc định là trời đang mưa). Tiếp theo, trình biên dịch sẽ check dòng if phía dưới – thấy rằng điều kiện isRain == 1 là đúng (1), đồng nghĩa với việc dòng cout bên trong if sẽ được thực thi và ta sẽ thấy dòng Remember to get an umbrella! được xuất ra màn hình.

b. Câu lệnh if…else (if…else Statement)

Lấy lại cái ví dụ trời mưa ban nãy nha, bây giờ nếu ta diễn giải vụ trời mưa này lên chương trình chỉ bằng câu lệnh if đơn thuần, tức ta sẽ chỉ có thể đặt đúng một điều kiện cho nó thôi! Nhưng mà mình lớn rồi, phải lo xa hơn tí chứ đúng không :3 Lỡ giờ trời không mưa thì làm sao? Các bạn có thể nghĩ đến việc viết thêm một dòng lệnh if nữa, nhưng việc làm đó có vẻ như sẽ làm chương trình của tụi mình hơi rối và thừa thải…

Chính vì lẽ đó, C++ đã mở rộng câu lệnh if ra, cho ta thêm một câu lệnh mới đó là if…else (nhà sáng lập tâm lý ghê chưa :3). Câu lệnh if…else sẽ có cấu trúc như sau:

// Đây là cấu trúc của lệnh if else trong C++
if(điều kiện)
{
   // Các dòng lệnh bên trong if
}
else 
{
   // Các dòng lệnh bên trong else
}

Sự khác biệt rõ ràng nhất ở đây là có thêm sự hiện diện của khối else nữa đúng không các bạn :3 Thật vậy, giờ mình chỉ cần phải viết thêm khối else vào là xong, một cấu trúc if else được tạo ra. Việc thực thi ở phần if sẽ tương tự như câu lệnh if, nhưng nếu điều kiện ở if sai thì thay vì bỏ qua nó, trình biên dịch sẽ thực thi đoạn code bên trong else rồi mới tiếp tục đến với các dòng code sau dấu }.

Nguồn ảnh: geeksforgeeks

Giờ mình lại quay trở lại với ví dụ trời mưa nữa đi, ban nãy mình chỉ mới viết hành động sẽ làm nếu trời mưa thôi, vậy còn lỡ trời không mưa thì sao? Rất may, giờ mình đã có công cụ if else ở đây rồi nên…còn chần chờ gì nữa mà không thêm mắm thêm muối vô đoạn code này nào :3

bool isRain = true;

if (isRain == 1)
{
    cout << "Remember to get an umbrella!" << endl ; 
}
else 
{
    cout << "Nothing to worry right now! Just get off your seat and have some fun outside <3" << endl;
}

Trong đoạn code trên, mình chỉ thêm đúng 3 dòng dành cho khối else. Giả sử nếu trời không mưa, tức điều kiện ở if của mình sẽ sai, thì khi đó trình biên dịch sẽ thực hiện dòng lệnh cout ở else. Giờ thì rõ ràng rành mạch hơn rồi đúng không nè :3

c. Câu lệnh if – else if Ladder (if – else if Ladder Statement)

Dĩ nhiên không phải lúc nào các vấn đề trong cuộc sống cũng chỉ đơn giản sẽ là “nếu không cái này thì cái khác”, mà đa phần mình sẽ phải gặp các trường hợp “nếu không cái này thì cái khác và nếu không cái khác thì còn nhiều cái khác nữa” (khó ở thiệt sự ><) Trong lập trình cũng vậy, một bài toán phức tạp sẽ đặt ra rất rất nhiều các trường hợp và điều kiện khác nhau để có thể ra được kết quả cuối cùng, vì vậy mà ta cần phải làm quen với một câu lệnh if phức tạp hơn đó là if – else if Ladder (mình tạm dịch là “cầu thang if else if”) để giải quyết vấn đề nói trên.

Một cấu trúc if else if Ladder sẽ được biểu diễn như sau:

if (điều kiện 1)
{
   // Các lệnh ở khối if 1
}
else if (điều kiện 2)
{
   // Các lệnh ở khối if 2
}
else if (điều kiện 3)
{
   // Các lệnh ở khối if 3
}
... // Có thể có thêm nhiều else if 
else
{
   // Các lệnh ở khối else
}

Trình biên dịch sẽ lần lượt check các điều kiện có trong các khối if ở trên, theo thứ tự từ trên xuống, nếu có một điều kiện nào thỏa mãn, chương trình sẽ thực thi code trong khối if đó và thoát ra khỏi cả khối if bự đó luôn, tức sẽ không xét các điều kiện if khác nếu vẫn còn.

Nguồn ảnh: geeksforgeeks

Mình sẽ lấy ví dụ cụ thể cho các bạn và dĩ nhiên… vẫn là bài toán trời mưa của mình đây hihi. Bây giờ mình nhận thấy chỉ yếu tối trời mưa hay không thôi thì cũng chưa đủ, vì dù là trời mưa nhưng nếu đó là chuyện quan trọng thì mình vẫn sẽ phải đi chứ đúng không (như nay crush hẹn qua nhà chơi chẳng hạn :3), vì vậy mà giờ ta phát sinh thêm một yếu tố có việc bận hay không ở đây rồi, cùng mình bổ sung tiếp đoạn code này nha:

bool isRain = true;
bool isImportant = 1;

if (isRain == 1 &amp;&amp; isImportant == 1)
{ 
   cout << "Get a raincoat and go right now! We have no time left!!" << endl ;
}
else if (isRain == 1)
{
    cout << "Remember to get an umbrella!" << endl ; 
}
else 
{
    cout << "Nothing to worry right now! Just get off your seat and have some fun outside <3" << endl;
}

Mình đã khai báo thêm một biến kiểu bool isImportant để thể check xem nếu việc ra ngoài có phải là việc quan trọng hay không. Các bạn có thể thấy hai sự thay đổi ở đây:

Đầu tiên dễ thấy nhất mình đã thêm vào một đoạn else if vào trong code, nhưng điểm đặc biệt thứ hai ở đây, và cũng là một điều rất quan trọng về mặt logic khi ta sử dụng if – else if này – đó là thứ tự của các điều kiện. Ở các ví dụ trên mình tại vòng if thứ nhất mình chỉ check mỗi isRain, nhưng qua đến if else lần này mình đã thay đổi, để nó xuống vị trí thứ 2 và cho dòng if có thêm isImportant lên đầu. Vì sao lại phải làm như vậy? Như đã nói ở ban đầu, trong quá trình đọc code của khối lệnh if từ trên xuống, nếu if nào thỏa mãn đúng điều kiện thì sẽ thực thi code bên trong nó và bỏ qua hết các điều kiện còn lại nếu có. Chính vì lẽ đó mà khi mình không đổi chỗ hai điều kiện if trên, thì chương trình sẽ chạy lệnh của khối if(isRain == 1) chứ không chạy khối if có thêm isImportant mặc dù rằng khối này vẫn đúng, vì nó sẽ bị sai về mặt logic cũng như yêu cầu của bài toán mình đặt ra.

=> Luôn phải tính toán đặt các điều kiện ở những vị trí hợp lý, luôn ưu tiên các khối if có nhiều điều kiện phức tạp, chi tiết và mang tính khái quát nhất.

d. if lồng if (Nested if Statement)

Các bạn cứ tưởng việc viết code bên trong khối if cũng giống như việc các bạn đang viết ở một cái main() khác vậy, vì thế mà việc có thể sử dụng thêm các “if con” bên trong đó là điều hiển nhiên rồi đúng không. Cấu trúc của một “if lồng if” (Nested if) trong C++ như sau:

if(điều kiện 1)
{
    if (điều kiện 2)
    {
        // Lệnh của khối if nằm bên trong (if con)
    }
}

Việc viết thêm bao nhiêu “if con” bên trong cũng không thành vấn đề gì, miễn là các bạn vẫn luôn đảm bảo đúng cú pháp, có dấu {}đầy đủ là ok rồi nha :3 Cái này mình sẽ không đi sâu chi tiết vì thật ra nó cũng không quá phức tạp đâu mà đúng không nè:3

Nguồn ảnh: geeksforgeeks

2. Vòng lặp (Loops)

Nguồn ảnh: wikimediacommons

Vòng lặp (Loops) là một trong những khái niệm cơ bản trong bất kì ngôn ngữ lập trình nào, nó là một cú pháp giúp ta lặp đi lặp lại một quá trình (dĩ nhiên ở đây sẽ là một đoạn code) với một số lần lặp cố định hoặc với một điều kiện dừng cho trước.

Ví dụ, giả sử bây giờ bạn muốn in ra màn hình tầm 100 dòng hehe boiz. Nếu không có vòng lặp, bạn sẽ phải ngồi viết 100 dòng cout ra đúng không, nhưng giờ với vòng lặp ta sẽ chỉ cần 3 dòng code là có thể thực hiện công việc tưởng chừng mệt nhọc này rồi.

Giờ mình thực tế hơn tí nha, mình sẽ cho bạn một file excel chứa hàng trăm hàng triệu thông tin người dùng, và mình cần bạn giúp mình in tên từng người một trong danh sách đó ra màn hình. Nếu thông thường, ta sẽ ngồi gõ từng cout cho từng cái biến chứa tên người dùng một, việc làm đó có thể sẽ là một thảm họa với hầu hết tất cả mọi người >< NHƯNG, bây giờ với việc đã học về vòng lặp, ta sẽ chỉ cần ghi đúng một dòng cout bên trong câu lệnh vòng lặp với một số lần lặp ở đây sẽ là số thứ tự của người cuối cùng trong file excel là ngon lành cành đào liền luôn :3

a. Vòng lặp for (for Loop)

Vòng lặp for (for Loop) là một vòng lặp cho phép lặp một quá trình với một số lần lặp nhất định. Cấu trúc của vòng lặp for trong C++ như sau:

for(khởi tạo biến lặp;điều kiện dừng của biến lặp;cập nhật biến lặp)
{
     // Phần code bên trong 
}

Trong đó:

  • Khởi tạo biến lặp: là nơi để ta khai báo một biến lặp với một giá trị bất kì, nhiệm vụ của nó sẽ như là một máy đếm để đếm số lần đã lặp của vòng lặp, giá trị của nó sẽ thay đổi khi một lần lặp được hoàn thành.
  • Điều kiện dừng của biến lặp: là nơi để ta đặt một điều kiện dừng vòng lặp này lại thông qua việc sử dụng toán tử quan hệ cho biến lặp, nếu điều kiện không còn đúng nữa thì vòng lặp sẽ dừng lại.
  • Cập nhật biến lặp: là nơi để ta cập nhật giá trị cho biến lặp sau mỗi lần hoàn tất một lần lặp bằng các toán tử gán.

Wow, cả một mớ kiến thức mới luôn, mình đảm bảo đọc suông như vậy chắc chắn sẽ rất khó hiểu nên mình sẽ đi ngay tiếp đến ví dụ, cụ thể sẽ là ví dụ lặp việc in dòng chữ hehe boiz ra màn hình nha các bạn:

// Dòng lệnh sau sẽ in một 100 dòng chữ hehe boiz ra màn hình
for(int i = 1; i <= 100; ++i)
{
    cout << "hehe boiz" << endl ;
}

Mình lắp đúng cấu trúc ở trên nha, ở phần khai báo biến lặp, mình đã khai báo một biến kiểu int là i và gán cho nó giá trị bằng 1. Ở phần đặt điều kiện cho biến lặp, theo yêu cầu đề bài, mình cần in ra 100 dòng chữ nên điều kiện dừng cho biến lặp này đơn giản sẽ là <= 100. Cuối cùng, để có thể in ra 100 lần như vậy thì ta sẽ cần đặt phép toán ++i (toán tử tăng) cho phần cập nhật biến lặp – tức sau mỗi lần lặp i sẽ được tăng lên 1 đơn vị.

Nguồn ảnh: programiz

b. Vòng lặp while (while Loop)

Vòng lặp while (while Loop) là một vòng lặp cho phép lặp một quá trình dựa vào điều kiện lặp cho trước. Với vòng lặp for, ta dùng để lặp một quá trình với số lần lặp đã biết trước, còn với vòng while này, ta sẽ dùng để lặp một quá trình mà ở đó ta không biết trước được số lần lặp cụ thể của đoạn code phía trong nó. Cấu trúc của một vòng lặp while trong C++ như sau:

// Đây là cấu trúc của một vòng lặp while
while(điều kiện lặp)
{
    // Lệnh bên trong khối while
}

Vòng while này nhìn có vẻ đỡ rắc rối hơn vòng for ban nãy ha các bạn ^^ Ở đây ta sẽ chỉ cần định nghĩa một điều kiện bất kì, có thể là dành cho biến lặp ta tạo sẵn bên ngoài hay bất kì một mô tả nào mà các bạn muốn, vòng while sẽ không ràng buộc phải là điều kiện của biến lặp như ở vòng for. Việc thực thi vòng while cũng sẽ khá dễ hiểu, đầu tiên trình biên dịch sẽ check điều kiện lặp ở vòng while trước, nếu đúng thì sẽ thực thi khối code bên trong và sau khi hoàn thành, nó lại tiếp tục check điều kiện cho đến khi điều kiện không còn đúng nữa thì dừng.

Để ví dụ cho vòng while này mình sẽ viết lại bài in ra 100 dòng “hehe boiz” như sau:

// Khởi tạo một biến lặp
int i = 1;

while(i <= 100)
{
     cout << "hehe boiz" << endl ;
     i += 1;
}

Đầu tiên, mình khởi tạo một biến lặp bên ngoài để làm ‘máy đếm‘ cho điều kiện dừng (mọi người hay đặt tên biến lặp là iiterable). Sau đó, mình sẽ đặt duy nhất một điều kiện dành cho biến lặp là i <= 100, tức là khi i vẫn còn <= 100 thì ta sẽ lặp lại việc in dòng hehe boiz. Ngoài ra còn có dòng i += 1 trong khối while này là để mình có thể cập nhật biến i, nếu không có dòng này thì vòng lặp này sẽ bị lặp vô hạn – tức sẽ gây lỗi cho chương trình của chúng ta ><.

Nguồn ảnh: programiz

c. Vòng lặp do…while (do…while Loop)

Vòng lặp do…while (do…while Loop) là một vòng lặp với bản chất khá giống vòng lặp while, điểm khác ở đây là nó sẽ thực hiện các dòng code bên trong khối do while trước rồi sau đó mới xét đến điều kiện lặp, tức là ta sẽ luôn đảm bảo được rằng đoạn code bên trong sẽ được thực hiện ít nhất một lần! Cấu trúc của một vòng do while như sau:

// Đây là cấu trúc của một vòng lặp do while trong C++
do
{
    // Code bên trong khối do while
} while (điều kiện lặp);

Như mình đã nói ở trên, trình biên dịch sẽ thực hiện các đoạn code bên trong khối do while trước rồi sau đó mới check điều kiện lặp, nếu đúng thì lặp tiếp, không thì sẽ tự động thoát ra. Các bạn nhớ để ý là có dấu ; ngay sau điều kiện lặp nha, mình thấy nhiều bạn thường hay quên vụ này. Đây chỉ như là một cách viết ngược của while nên mình sẽ không làm thêm ví dụ ở đây nha các bạn ^^

Nguồn ảnh: programiz

À, còn một vấn đề mà mình nghĩ nhiều bạn sẽ thắc mắc, đó là nên sử dụng vòng lặp nào trong lúc lập trình ? Cái này thì tùy vào trường hợp cụ thể mà mình sẽ sử dụng nó sao cho phù hợp nha các bạn, mình sẽ không ưu tiên dùng cái nào hết! Sẽ có trường hợp dùng for tối ưu hơn là dùng while hay do while và ngược lại. Mình biết phần này mới đầu sẽ rất khó và các bạn cần phải cố gắng luyện tập thật nhiều các dạng bài khác nhau để lĩnh hội cho mình được cách sử dụng vòng lặp hiệu quả nhé.

3. Từ khóa break và continue (break & continue Statements)

break

Từ khóa break (break statement) được dùng để thoát khỏi vòng lặp ngay cả khi vòng lặp vẫn còn có thể lặp tiếp được. Khi trình biên dịch bắt gặp từ khóa break này, mọi đoạn code vẫn còn bên trong khối sẽ bị bỏ qua“đá” trình biên dịch ra ngoài vòng lặp ngay và luôn. Từ khóa này sẽ đặc biệt phù hợp giúp ta tránh việc bị lặp vô hạn hay phải làm việc với một vòng lặp vô hạn thật sự.

Ban nãy thì mình bảo các bạn là phải tránh việc tạo ra một vòng lặp vô hạn, giờ thì mình lại nói về việc làm việc với một vòng lặp vô hạn :)) (hơi bị mâu thuẫn ha). Nhưng mà thật là như vậy, sẽ có những vòng lặp mà ta cũng sẽ không biết điều kiện để dừng là gì – hay nói đúng hơn là việc dừng đó sẽ không do ta định đoạtphụ thuộc vào các yếu tố khác (có thể hiểu là người dùng chương trình của chúng ta). Đây là cấu trúc của một vòng lặp vô hạn và cách sử dụng break:

int i = 1;
int sum = 0;

// Đây là cách để tạo ra một vòng lặp vô hạn
while(true)
{
    sum += i ;
    i += 1;

    // Vòng lặp sẽ thoát khi tổng lớn hơn hoặc bằng 100
    if (sum >= 100)
    { 
        break;
    } 

}

cout << sum << endl ; // Kết quả là 105

Nói qua một chút về cách triển khai một vòng lặp vô hạn, ở đây mình dùng vòng lặp while với điều kiện là true, rất lạ phải không. Mình sẽ không dùng bất cứ toán tử quan hệ nào để check tính đúng sai của điều kiện mà mình sẽ đặt luôn giá trị là true để điều kiện lặp này luôn đúng – đồng nghĩa vòng lặp này giờ đây sẽ được lặp vô hạn.

Quay lại với break, ở đoạn code trên mình đã dùng nó để làm một điều kiện dừng cho vòng lặp vô hạn này, khi điều kiện bên trong if đúng – tức khi sum >= 100, trình biên dịch sẽ gặp từ khóa break và ngay lập tức thoát khỏi vòng lặp trên, sau đó gặp dòng cout và ra cho ta giá trị của sum – tức 105.

Nguồn ảnh: programiz

continue

Từ khóa continue (continue statement) cũng được dùng khi làm việc với vòng lặp, mục đích của nó dùng để ngay lập tức bỏ qua việc thực thi code của lần lặp hiện tại, nhảy lên check điều kiện lặp và thực hiện lần lặp tiếp theo (nếu có). Đây là ví dụ minh họa cách sử dụng từ khóa continue:

// Đây là chương trình tính tổng các số chẵn trong khoảng từ 1 đến 100
int sum = 0;

for(int i = 1; i <= 100; ++i)
{
    if (i%2 != 0) // Nếu biến lặp là một số lẻ thì chuyển qua lần lặp tiếp theo
    {
       continue ;
    }
    else // Nếu biến lặp là một số chẵn thì cộng vào biến sum
    {
       sum += i ;
    }
}

Đoạn code trên là chương trình tính tổng các số chẵn trong khoảng từ 1 đến 100 nên mình sẽ có 100 lần lặp. Để có thể check số hiện tại là một số lẻ thì mình chỉ cần chia lấy dư số đó cho 2, nếu nó không dư 0 thì tức nó là một số lẻ (kiến thức toán cơ bản nè). Mỗi lần lặp, ta sẽ check xem nếu giá trị của biến lặp là một số lẻ, ta sẽ dùng từ khóa continue để ngay lập tức đẩy đến lần lặp tiếp theo, còn nếu không phải thì cộng dồn vào biến sum – vì không là số lẻ thì chắc chắn là số chẵn nên không nhất thiết phải viết thêm điều kiện đâu nha.

Nguồn ảnh: programiz

4. Câu lệnh switch…case (switch Statements)

Đây cũng là một cấu trúc điều khiển trong C++ và mục đích hoạt động của nó hoàn toàn tương tự như cấu trúc if – else if Ladder – nó cho phép ta check dữ liệu của một biến và ứng với từng giá trị cụ thể (case), ta sẽ có các kết quả trả về khác nhau. Một cấu trúc switch…case trong C++ sẽ được viết như sau:

switch (biến)
{
   case <điều kiện 1>: 
      // Code ở case 1
      break;
   case <điều kiện 2>:
      // Code ở case 2:
      break;
   ...
   case <điều kiện n>:
      // Code ở case n
      break;

   default:
      // Code ở phần không thuộc bất kì case nào (mặc định)
}

Cấu trúc switch…case (switch statement) sẽ check lần lượt các case theo thứ tự từ trên xuống (giống if – else if Ladder), nếu giá trị của biến bằng giá trị của một trong các case trên thì sẽ thực thi đoạn code sau dấu :, nếu không dính bất cứ case nào thì nó sẽ thực hiện code ở default (nếu có). Điểm đặc biệt các bạn cần lưu ý ở switch…case là ta sẽ có từ khóa break sau mỗi cuối phần code bên trong một case (trừ default vì nó đã mặc định nằm sẵn bên dưới cùng của một switch…case), không giống như if – else if Ladder khi chỉ cần đúng một điều kiện là sẽ bỏ qua việc xét các điều kiện còn lại, switch…case sẽ thực thi hết đoạn code của các case đúng mà không tự động thoát ra, vì vậy mà ta luôn cần phải có từ khóa break để thoát khỏi việc check các case còn lại bên trong switch (khá giống vòng lặp).

Việc sử dụng switch…case hay if – else if Ladder là tùy thuộc vào các bạn, vì mục đích sử dụng của nó là như nhau. Nhưng theo một số lời khuyên thì việc sử dụng switch…case sẽ làm cho code của bạn dễ đọc hơn nên các bạn có thể cân nhắc nhé ^^

Nguồn ảnh: programiz

III. Tổng kết

Ui cha, tự mình nhìn lại mới thấy bài lần này quả là rất dài và còn có rất nhiều những khái niệm mới nữa! Tùi mình đã tìm hiểu qua được một số các loại toán tử trong C++ và Cấu trúc điều khiển bao gồm các cấu trúc điều kiện, các vòng lặp for, while, do – while và một phiên bản if – else if Ladder đặc biệt đó là switch…case. Mình biết rằng sẽ rất khó để có thể tiếp thu hết chỉ qua một lần đọc mà các bạn cần phải tự tìm tòi làm thêm nhiều các bài tập lập trình từ nhiều nguồn khác nhau để có thể nhanh chóng làm quen và nhận ra được một chân lý nào đó cho riêng mình nhé ^^ Để tổng kết lại những gì đã học cũng như là “outro” cho bài viết lần này, mình sẽ viết viết một bài code mô phỏng một game nho nhỏ nha :3 nghe hầm hố hoành tráng vậy chứ mình sẽ chỉ code về mặt ý tưởng của việc làm một game, cụ thể là build cách di chuyển của một nhân vật và áp dụng những gì nãy giờ đã học sao cho thực tế nhất nha các bạn :3

#include <iostream>

using namespace std ;

// Đây là chương trình mô phỏng game truy tìm kho báu
// Ở chương trình này sẽ định nghĩa phần di chuyển nhân vật
// Game sẽ chỉ kết thúc (tức thoát khỏi vòng lặp) khi ta nhập 0 (exit)

int main()
{
   cout << "Chào mừng đến với game Truy Tìm Kho Báu" << endl ;
   cout << "Sau đây bảng hướng dẫn tương tác với game!" << endl ;

   // Tạo một vòng lặp vô hạn
   while(true)
   {
       char yourChoice ;

       // Menu tương tác với game của người chơi
       cout << "Để tiến lên một bước hãy nhập 'w' " << endl ;
       cout << "Để lùi xuống một bước hãy nhập 's' "<< endl ;
       cout << "Để rẽ trái một bước hãy nhập 'a' "<< endl ;
       cout << "Để rẽ phải một bước hãy nhập 'd' "<< endl ;
       cout << "Để thoát khỏi game hãy nhập '`' "<< endl ;
    
       // Nhập một trong các lựa chọn ở trên
       cout << "Mời bạn nhập lựa chọn của mình: " ;
       cin >> yourChoice ;

       // Thực hiện kiểm tra sự lựa chọn của người chơi
       if (yourChoice == '`')
       {
           cout << "Game Over! Hẹn gặp bạn lần sau " << endl ;
           break;
       }
       else
       {
           switch(yourChoice)
           {
               case 'w':
                  cout << "Tiến 1 bước" << endl ;
                  break ;
               case 'a':
                  cout << "Qua trái 1 bước" << endl ;
                  break ;
               case 'd':
                  cout << "Qua phải 1 bước" << endl ;
                  break ;
               case 's': 
                  cout << "Lùi 1 bước" << endl ;
                  break ;
            
               default:
                  continue ;
           }
       }
   }
   return 0 ;
}

Cảm ơn các bạn đã theo dõi bài viết của mình, nếu có gì thắc mắc hoặc có những ý kiến đóng góp đừng ngại để lại bình luận bên dưới nha các bạn, hẹn gặp lại các bạn ở các bài viết sau.

Tài liệu tham khảo:

[1] https://www.programiz.com/

[2] https://www.geeksforgeeks.org/

[3] https://www.w3schools.com/cpp/

[4] https://www.cplusplus.com/

Dương Đình Thắng – KHCL2019.3

Leave a Reply

Your email address will not be published. Required fields are marked *