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:
if
Statement: Thực thi một khối lệnh chỉ khi một điều kiện là đúng (true).if...else
Statement: 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...else
Statement: 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ó).switch
Statement: 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> // Cần cho cin và cout
int main() {
int num;
cout << "Nhap mot so nguyen: ";
cin >> num; // Nhap gia tri vao bien num
// Kiem tra dieu kien: num co lon hon 0 khong?
if (num > 0) {
// Neu dieu kien (num > 0) la true, thuc thi doan code nay
cout << num << " la so duong." << endl;
}
cout << "Ket thuc chuong trinh." << endl; // Dong nay luon duoc thuc thi
return 0;
}
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
num
lớn hơn 0 (ví dụ: bạn nhập 5), điều kiệnnum > 0
là true. Chương trình sẽ đi vào bên trong khối dấu ngoặc nhọn{}
ngay sauif
và thực thi lệnhcout << num << " la so duong." << endl;
. - Nếu
num
không lớn hơn 0 (ví dụ: bạn nhập -3 hoặc 0), điều kiệnnum > 0
là false. Chương trình sẽ bỏ qua khối lệnh bên trong{}
củaif
và 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() {
int num;
cout << "Nhap mot so nguyen: ";
cin >> num;
// Kiem tra dieu kien: so chia het cho 2?
if (num % 2 == 0) {
// Neu dieu kien (num % 2 == 0) la true (so chan)
cout << num << " la so chan." << endl;
} else {
// Neu dieu kien tren la false (so le)
cout << num << " la so le." << endl;
}
return 0;
}
Giải thích:
- Chúng ta sử dụng toán tử modulo
%
để lấy số dư.num % 2 == 0
nghĩa là "số dư khi chianum
cho 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 == 0
là 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
else
và 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-else
nà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() {
double diem; // Diem thuong la so thuc
cout << "Nhap diem so (thang 10): ";
cin >> diem;
// Kiem tra dieu kien lan luot tu tren xuong
if (diem >= 8) {
cout << "Xep loai: Gioi" << endl;
} else if (diem >= 6.5) {
// Neu diem < 8 VA diem >= 6.5
cout << "Xep loai: Kha" << endl;
} else if (diem >= 5) {
// Neu diem < 6.5 VA diem >= 5
cout << "Xep loai: Trung binh" << endl;
} else {
// Neu diem < 5 (tat ca cac dieu kien tren deu sai)
cout << "Xep loai: Yeu" << endl;
}
return 0;
}
Giải thích:
- Cấu trúc
if...else if...else
cho 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 >= 8
trước.- Nếu đúng, in ra "Gioi" và bỏ qua tất cả các
else if
vàelse
cò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 >= 8
sai, 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
,else
cò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
if
vàelse if
đều sai, khối lệnh trongelse
cuố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() {
int year;
cout << "Nhap nam: ";
cin >> year;
// Dieu kien kiem tra nam nhuan:
// (chia het cho 400) HOAC (chia het cho 4 VA khong chia het cho 100)
if ((year % 400 == 0) || (year % 4 == 0 && year % 100 != 0)) {
cout << year << " la nam nhuan." << endl;
} else {
cout << year << " khong phai la nam nhuan." << endl;
}
return 0;
}
Giải thích:
- Điều kiện trong
if
sử 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() {
char op; // Bien luu phep toan (+, -, *, /)
double num1, num2; // Hai so de thuc hien phep toan
cout << "Nhap phep toan (+, -, *, /): ";
cin >> op;
cout << "Nhap hai so: ";
cin >> num1 >> num2;
// Su dung switch de xu ly phep toan
switch (op) {
case '+': // Neu op co gia tri la '+'
cout << num1 << " + " << num2 << " = " << num1 + num2 << endl;
break; // Thoat khoi switch
case '-': // Neu op co gia tri la '-'
cout << num1 << " - " << num2 << " = " << num1 - num2 << endl;
break; // Thoat khoi switch
case '*': // Neu op co gia tri la '*'
cout << num1 << " * " << num2 << " = " << num1 * num2 << endl;
break; // Thoat khoi switch
case '/': // Neu op co gia tri la '/'
if (num2 != 0) { // Kiem tra truoc khi chia de tranh loi chia cho 0
cout << num1 << " / " << num2 << " = " << num1 / num2 << endl;
} else {
cout << "Loi: Chia cho 0!" << endl;
}
break; // Thoat khoi switch
default: // Neu op khong khop voi bat ky case nao
cout << "Phep toan khong hop le!" << endl;
// Khong can break o day vi day la case cuoi
}
return 0;
}
Giải thích:
- Lệnh
switch (op)
sẽ so sánh giá trị của biếnop
với các giá trị trong cáccase
. - Khi giá trị của
op
khớp với mộtcase
nà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ốiswitch
ngay 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áccase
tiế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ếnop
không khớp với bất kỳcase
nào được liệt kê. - Trong
case '/'
, chúng ta có một câu lệnhif
lồ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.
<br>
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àmmax
vàmin
rấ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ệuint
là đủ 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
cin
từ 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ùngmax
lồng nhau, ví dụ:max(so_thu_nhat, max(so_thu_hai, so_thu_ba))
. - Hoặc, từ C++11 trở lên,
max
cũ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
min
lồ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
cout
từ 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 (
\n
hoặ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