Bài 2.4: Bài tập thực hành rẽ nhánh cơ bản trong C++
Bài 2.4: Bài tập thực hành rẽ nhánh cơ bản trong C++
Chào mừng bạn quay trở lại với hành trình chinh phục C++! Sau khi đã làm quen với việc nhập xuất dữ liệu cơ bản, đã đến lúc chúng ta học cách làm cho chương trình của mình trở nên linh hoạt và thông minh hơn. Đó chính là lúc các cấu trúc rẽ nhánh phát huy tác dụng!
Bài viết này sẽ tập trung vào việc thực hành các câu lệnh rẽ nhánh cơ bản nhất trong C++: if, else if, else, và cả switch. Thông qua các ví dụ bài tập cụ thể, bạn sẽ thấy cách áp dụng chúng để đưa ra các quyết định khác nhau trong luồng thực thi của chương trình.
Không dài dòng nữa, chúng ta hãy cùng bắt tay vào code ngay nào!
Tại sao cần rẽ nhánh?
Hãy tưởng tượng bạn đang viết một chương trình tính tiền vé xem phim. Giá vé có thể khác nhau tùy theo độ tuổi: trẻ em (dưới 12 tuổi) giá X, người lớn (từ 12 đến 60 tuổi) giá Y, và người già (trên 60 tuổi) giá Z. Làm sao chương trình biết áp dụng giá nào? Nó cần kiểm tra tuổi của khách hàng và rẽ nhánh sang các đoạn mã tính giá khác nhau tương ứng. Đó chính là sức mạnh của rẽ nhánh!
Công cụ rẽ nhánh cơ bản trong C++
Chúng ta có các công cụ chính sau để thực hiện rẽ nhánh:
ifStatement: Thực thi một khối lệnh chỉ khi một điều kiện là đúng (true).if...elseStatement: Thực thi khối lệnh này nếu điều kiện đúng, ngược lại thực thi khối lệnh khác.if...else if...elseStatement: Kiểm tra nhiều điều kiện nối tiếp. Thực thi khối lệnh đầu tiên có điều kiện đúng. Nếu không có điều kiện nào đúng, thực thi khối lệnh trongelse(nếu có).switchStatement: Một cách khác để rẽ nhánh khi bạn cần so sánh một biến với nhiều giá trị cố định khác nhau.
Bây giờ, hãy cùng thực hành với các ví dụ cụ thể!
Ví dụ 1: Kiểm tra số dương
Bài toán đơn giản nhất để bắt đầu với if.
Yêu cầu: Viết chương trình nhập vào một số nguyên và kiểm tra xem số đó có phải là số dương hay không. Nếu là số dương, in ra thông báo tương ứng.
Code:
#include <iostream>
int main() {
using namespace std;
int n;
cout << "Nhap so: ";
cin >> n;
if (n > 0) {
cout << n << " la so duong." << endl;
}
cout << "Ket thuc." << endl;
return 0;
}
Output:
Input: 5
Nhap so: 5 la so duong.
Ket thuc.
Input: -3
Nhap so: Ket thuc.
Giải thích:
- Chương trình yêu cầu người dùng nhập một số và lưu vào biến
num. - Câu lệnh
if (num > 0)kiểm tra điều kiệnnum > 0. Đây là một biểu thức logic, kết quả của nó chỉ có thể là true (đúng) hoặc false (sai). - Nếu
numlớn hơn 0 (ví dụ: bạn nhập 5), điều kiệnnum > 0là true. Chương trình sẽ đi vào bên trong khối dấu ngoặc nhọn{}ngay sauifvà thực thi lệnhcout << num << " la so duong." << endl;. - Nếu
numkhông lớn hơn 0 (ví dụ: bạn nhập -3 hoặc 0), điều kiệnnum > 0là false. Chương trình sẽ bỏ qua khối lệnh bên trong{}củaifvà tiếp tục thực thi từ dòng code ngay sau khối đó (ở đây làcout << "Ket thuc chuong trinh." << endl;). - Lưu ý: Dòng "Ket thuc chuong trinh." luôn được in ra, bất kể số bạn nhập là gì, vì nó nằm ngoài khối
if.
Ví dụ 2: Kiểm tra chẵn hay lẻ
Sử dụng cấu trúc if...else để xử lý hai trường hợp đối lập.
Yêu cầu: Viết chương trình nhập vào một số nguyên và kiểm tra xem đó là số chẵn hay số lẻ.
Code:
#include <iostream>
int main() {
using namespace std;
int n;
cout << "Nhap so: ";
cin >> n;
if (n % 2 == 0) {
cout << n << " la so chan." << endl;
} else {
cout << n << " la so le." << endl;
}
return 0;
}
Output:
Input: 4
Nhap so: 4 la so chan.
Input: 7
Nhap so: 7 la so le.
Giải thích:
- Chúng ta sử dụng toán tử modulo
%để lấy số dư.num % 2 == 0nghĩa là "số dư khi chianumcho 2 có bằng 0 không?". Điều này chính xác là cách kiểm tra một số có chẵn hay không. - Nếu điều kiện
num % 2 == 0là true, khối lệnh trongifđược thực thi, in ra "la so chan". - Nếu điều kiện là false (tức là số dư khác 0 khi chia cho 2, chỉ có thể là 1 với số nguyên), chương trình sẽ tự động nhảy đến khối lệnh trong
elsevà thực thi, in ra "la so le". - Với
if...else, chắc chắn một trong hai khối lệnh sẽ được thực thi, không bao giờ cả hai, và không bao giờ không có khối nào được thực thi (trừ khi có lỗi runtime hoặc logic khác ngoàiif-elsenày).
Ví dụ 3: Xếp loại học sinh theo điểm
Bài tập điển hình cho cấu trúc if...else if...else khi có nhiều hơn hai trường hợp.
Yêu cầu: Nhập điểm số (thang 10) của một học sinh và xếp loại:
- Điểm >= 8: Giỏi
- Điểm >= 6.5: Khá
- Điểm >= 5: Trung bình
- Dưới 5: Yếu
Code:
#include <iostream>
int main() {
using namespace std;
double d;
cout << "Nhap diem: ";
cin >> d;
if (d >= 8) {
cout << "Gioi" << endl;
} else if (d >= 6.5) {
cout << "Kha" << endl;
} else if (d >= 5) {
cout << "Trung binh" << endl;
} else {
cout << "Yeu" << endl;
}
return 0;
}
Output:
Input: 8.5
Nhap diem: Gioi
Input: 6.8
Nhap diem: Kha
Input: 5.0
Nhap diem: Trung binh
Input: 4.9
Nhap diem: Yeu
Giải thích:
- Cấu trúc
if...else if...elsecho phép kiểm tra nhiều điều kiện một cách tuần tự. - Chương trình kiểm tra điều kiện
diem >= 8trước.- Nếu đúng, in ra "Gioi" và bỏ qua tất cả các
else ifvàelsecòn lại, kết thúc khối rẽ nhánh.
- Nếu đúng, in ra "Gioi" và bỏ qua tất cả các
- Nếu điều kiện
diem >= 8sai, nó sẽ chuyển sang kiểm tra điều kiện trongelse ifđầu tiên:diem >= 6.5.- Nếu đúng (khi này, ta biết chắc chắn
diem < 8), in ra "Kha" và bỏ qua cácelse if,elsecòn lại.
- Nếu đúng (khi này, ta biết chắc chắn
- Quá trình này tiếp tục cho đến khi gặp một điều kiện đúng hoặc đến cuối.
- Nếu tất cả các điều kiện trong
ifvàelse ifđều sai, khối lệnh trongelsecuối cùng sẽ được thực thi (in ra "Yeu"). - Thứ tự của các điều kiện rất quan trọng trong
if...else if. Bạn nên đặt các điều kiện cụ thể hơn hoặc phạm vi hẹp hơn lên trước.
Ví dụ 4: Kiểm tra năm nhuận
Bài tập này sử dụng kết hợp các toán tử logic (&& - AND, || - OR) trong điều kiện rẽ nhánh.
Yêu cầu: Nhập một năm và kiểm tra xem đó có phải là năm nhuận hay không.
- Năm nhuận là năm chia hết cho 400.
- Hoặc, năm nhuận là năm chia hết cho 4 nhưng không chia hết cho 100.
Code:
#include <iostream>
int main() {
using namespace std;
int nam;
cout << "Nhap nam: ";
cin >> nam;
if ((nam % 400 == 0) || (nam % 4 == 0 && nam % 100 != 0)) {
cout << nam << " la nam nhuan." << endl;
} else {
cout << nam << " khong phai la nam nhuan." << endl;
}
return 0;
}
Output:
Input: 2000
Nhap nam: 2000 la nam nhuan.
Input: 2024
Nhap nam: 2024 la nam nhuan.
Input: 1900
Nhap nam: 1900 khong phai la nam nhuan.
Input: 2023
Nhap nam: 2023 khong phai la nam nhuan.
Giải thích:
- Điều kiện trong
ifsử dụng kết hợp các toán tử logic:year % 400 == 0: Kiểm tra xem năm có chia hết cho 400 không.year % 4 == 0: Kiểm tra xem năm có chia hết cho 4 không.year % 100 != 0: Kiểm tra xem năm có KHÔNG chia hết cho 100 không.&&(AND): Kết hợp hai điều kiện. Biểu thức(year % 4 == 0 && year % 100 != 0)chỉ đúng khi cả hai điều kiện con đều đúng.||(OR): Kết hợp hai biểu thức lớn. Điều kiện tổng thể((year % 400 == 0) || (...))chỉ đúng khi ít nhất một trong hai vế (vế chia hết cho 400, hoặc vế "chia hết cho 4 và không 100") là đúng.
- Dấu ngoặc đơn
()được sử dụng để nhóm các điều kiện con và làm rõ thứ tự ưu tiên của các toán tử logic (mặc dù&&có ưu tiên cao hơn||, việc dùng ngoặc giúp code dễ đọc hơn). - Nếu điều kiện tổng thể là true, khối
ifđược thực thi. Ngược lại, khốielseđược thực thi.
Ví dụ 5: Sử dụng switch cho menu đơn giản
switch rất hữu ích khi bạn có một biến và muốn thực hiện các hành động khác nhau dựa trên giá trị cụ thể của biến đó.
Yêu cầu: Xây dựng một menu đơn giản cho phép người dùng chọn một trong các phép toán cơ bản (+, -, *, /) và thực hiện phép toán đó trên hai số.
Code:
#include <iostream>
int main() {
using namespace std;
char p;
double n1, n2;
cout << "Phep toan (+, -, *, /): ";
cin >> p;
cout << "Nhap 2 so: ";
cin >> n1 >> n2;
switch (p) {
case '+':
cout << n1 << " + " << n2 << " = " << n1 + n2 << endl;
break;
case '-':
cout << n1 << " - " << n2 << " = " << n1 - n2 << endl;
break;
case '*':
cout << n1 << " * " << n2 << " = " << n1 * n2 << endl;
break;
case '/':
if (n2 != 0) {
cout << n1 << " / " << n2 << " = " << n1 / n2 << endl;
} else {
cout << "Loi: Chia 0!" << endl;
}
break;
default:
cout << "Phep toan khong hop le!" << endl;
}
return 0;
}
Output: Input:
+
5 3
Phep toan (+, -, *, /): +
Nhap 2 so: 5 + 3 = 8
Input:
/
10 0
Phep toan (+, -, *, /): /
Nhap 2 so: Loi: Chia 0!
Input:
x
1 2
Phep toan (+, -, *, /): x
Nhap 2 so: Phep toan khong hop le!
Giải thích:
- Lệnh
switch (op)sẽ so sánh giá trị của biếnopvới các giá trị trong cáccase. - Khi giá trị của
opkhớp với mộtcasenào đó (ví dụ, bạn nhập '+'), chương trình sẽ bắt đầu thực thi từ dòng code ngay saucase '+':'. - Lệnh
break;rất quan trọng trongswitch. Nó làm chương trình thoát ra khỏi khốiswitchngay lập tức sau khi thực thi xong case đó. Nếu thiếubreak, chương trình sẽ tiếp tục thực thi cáccasetiếp theo (hiện tượng này gọi là "fall-through"), điều mà thường không mong muốn. - Trường hợp
default:là tùy chọn. Nó sẽ được thực thi nếu giá trị của biếnopkhông khớp với bất kỳcasenào được liệt kê. - Trong
case '/', chúng ta có một câu lệnhiflồng bên trong để xử lý trường hợp người dùng cố gắng chia cho số 0, tránh gây ra lỗi runtime. Điều này cho thấy bạn có thể lồng ghép các cấu trúc điều khiển bên trong nhau.
Lưu ý quan trọng về khối lệnh
Trong C++, khi một câu lệnh rẽ nhánh (if, else, else if, case trong switch) chỉ cần thực thi một dòng code duy nhất, bạn có thể bỏ qua cặp dấu ngoặc nhọn {}. Ví dụ:
if (num > 0)
cout << "So duong." << endl; // Chi mot dong, co the bo ngoac
Tuy nhiên, thực hành tốt được khuyến nghị là luôn sử dụng dấu ngoặc nhọn {} cho khối lệnh, ngay cả khi chỉ có một dòng. Điều này giúp code dễ đọc hơn, tránh sai sót khi bạn muốn thêm nhiều lệnh vào khối đó sau này.
Bài tập ví dụ: C++ Bài 2.A4: Số lớn nhất, số nhỏ nhất
cho 3 số nguyên \(a\), \(b\) và \(c\), hãy tìm xem số nào lớn nhất và số nào nhỏ nhất trong 3 số trên.
INPUT FORMAT
3 số nguyên \(a\), \(b\) và \(c\) cách nhau bởi 1 dấu cách \((-10^6 <= a, b, c <= 10^6)\).
OUTPUT FORMAT
Gồm 2 dòng: dòng đầu in ra số lớn nhất trong 3 số, dòng thứ 2 in ra số nhỏ nhất.
Ví dụ 1:
Input
1 2 3
Ouput
3
1
Ví dụ 2:
Input
3 3 3
Output
3
3
Giải thích ví dụ mẫu:
- Ví dụ 1: Số lớn nhất là 3 và số nhỏ nhất là 1.
- Ví dụ 2: Tất cả các số đều bằng 3, nên cả số lớn nhất và số nhỏ nhất đều là 3.
Hướng dẫn các bước thực hiện:
- Khai báo thư viện: Bạn cần sử dụng các chức năng nhập xuất (đọc từ bàn phím, in ra màn hình) và có thể cần các hàm hỗ trợ tìm max/min. Thư viện cơ bản cho nhập xuất là
<iostream>. Thư viện<algorithm>chứa các hàmmaxvàminrất hữu ích cho bài toán này. - Hàm chính (
main): Mọi chương trình C++ đều bắt đầu từ hàmmain. - Khai báo biến: Cần 3 biến để lưu trữ 3 số nguyên
a,b,cđọc từ input. Sử dụng kiểu dữ liệuintlà đủ vì phạm vi giá trị cho phép (-10^6 <= a, b, c <= 10^6) nằm trong giới hạn củaint. - Đọc dữ liệu: Sử dụng đối tượng
cintừ thư viện<iostream>để đọc 3 số nguyên từ input, chúng được cách nhau bởi dấu cách nên bạn có thể đọc chúng liên tiếp. - Tìm số lớn nhất (maximum):
- Bạn có thể sử dụng hàm
max. Hàm này có thể so sánh hai giá trị. Để so sánh ba giá trị, bạn có thể dùngmaxlồng nhau, ví dụ:max(so_thu_nhat, max(so_thu_hai, so_thu_ba)). - Hoặc, từ C++11 trở lên,
maxcũng hỗ trợ nhận một danh sách khởi tạo (initializer list), cho phép tìm max của nhiều số một cách ngắn gọn:max({so_thu_nhat, so_thu_hai, so_thu_ba}). Cách này rất phù hợp với yêu cầu "code ngắn gọn" và "ưu tiên dùng std".
- Bạn có thể sử dụng hàm
- Tìm số nhỏ nhất (minimum):
- Tương tự như tìm max, bạn có thể sử dụng hàm
minlồng nhau:min(so_thu_nhat, min(so_thu_hai, so_thu_ba)). - Hoặc dùng phiên bản với danh sách khởi tạo:
min({so_thu_nhat, so_thu_hai, so_thu_ba}). Đây cũng là cách ngắn gọn và dùngstd.
- Tương tự như tìm max, bạn có thể sử dụng hàm
- In kết quả: Sử dụng đối tượng
couttừ thư viện<iostream>để in ra kết quả.- In giá trị lớn nhất trước, theo sau là ký tự xuống dòng (
\nhoặcendl). - In giá trị nhỏ nhất sau đó, theo sau là ký tự xuống dòng.
- In giá trị lớn nhất trước, theo sau là ký tự xuống dòng (
- Kết thúc chương trình: Trả về 0 từ hàm
mainđể báo hiệu chương trình kết thúc thành công.
Comments