L2. Các Toán Tử và Biểu Thức trong C++¤
Giải đáp bài cũ
double vs long double:
- Phụ thuộc vào trình biên dịch và hệ điều hành
- Kiểu
doubleluôn là 8 bytes - Hệ điều hành x86:
long doublethường là 8 bytes - Hệ điều hành x64:
long doublecó thể là 16 bytes
#define vs const:
#define: Khi biên dịch, tên hằng được thay thế bằng giá trị → Không cần bộ nhớconst: Là biến hằng → Chiếm dung lượng trên bộ nhớ
5. Các Phép Toán¤
5.1. Toán Tử Gán (Assignment Operator)¤
Toán tử gán = dùng để gán giá trị cho một biến.
Truy vết thực thi:
int a, b;
a = 10; // a = 10, b = ?
b = 4; // a = 10, b = 4
a = b; // a = 4, b = 4
b = 7; // a = 4, b = 7
Gán nhiều biến:
int x, y;
y = 2 + (x = 5); // Tương đương: x = 5; y = 2 + x;
int x = y = z = 5; // Gán giá trị 5 cho 3 biến z, y, x
5.2. Toán Tử Toán Học (Arithmetic Operators)¤
| Phép toán | Ý nghĩa | Ví dụ | Kết quả |
|---|---|---|---|
+ |
Cộng | x = 11 + 3 |
14 |
- |
Trừ | x = 11 - 3 |
8 |
* |
Nhân | x = 11 * 3 |
33 |
/ |
Chia | x = 11 / 3.0 |
3.666... |
/ |
Lấy phần nguyên | x = 11 / 3 |
3 |
% |
Lấy phần dư | x = 11 % 3 |
2 |
Phép chia trong C++
Khi nào là phép chia?
- Khi ít nhất một trong các đối số là số thực
Khi nào là phép lấy phần nguyên?
- Khi tất cả các đối số đều là số nguyên
float a = 5 / 2; // a = 2 (chia nguyên, sau đó chuyển sang float)
float b = 5 / 2.; // b = 2.5 (chia thực)
float c = 5. / 2; // c = 2.5 (chia thực)
float d = (float)5/2; // d = 2.5 (ép kiểu, sau đó chia thực)
Vấn đề thường gặp
1. Phép nhân (tràn kiểu dữ liệu):
int a = 123456;
int b = 654321;
std::cout << a * b; // Kết quả sai: 80779853376 (tràn số)
// Giải pháp: Ép kiểu
std::cout << (long long)a * b; // Kết quả đúng
2. Phép chia (sai logic do chia nguyên):
5.3. Toán Tử Tăng/Giảm (+±-)¤
Dùng để tăng hoặc giảm 1 đơn vị:
Sự khác biệt giữa ++x và x++?
Tiền tố (++x - Pre-increment):
int x = 5;
int y = ++x;
// Thực hiện:
// 1. ++x → x = 6
// 2. y = x → y = 6
// Kết quả: x = 6, y = 6
Hậu tố (x++ - Post-increment):
5.4. Toán Tử Phẩy (Comma Operator)¤
Các biểu thức cách nhau bằng dấu , được tính từ trái sang phải, kết quả là giá trị của biểu thức cuối cùng.
int x = 0;
int y = 2;
int z = (++x, ++y);
// Thực hiện:
// 1. ++x → x = 1
// 2. ++y → y = 3
// 3. z = y → z = 3
// Kết quả: x = 1, y = 3, z = 3
5.5. Toán Tử Toán Học & Gán (Compound Assignment)¤
| Toán tử | Ví dụ | Tương đương | Ý nghĩa |
|---|---|---|---|
+= |
x += 5 |
x = x + 5 |
Cộng |
-= |
x -= 5 |
x = x - 5 |
Trừ |
*= |
x *= 5 |
x = x * 5 |
Nhân |
/= |
x /= 5 |
x = x / 5 |
Chia/Lấy phần nguyên |
%= |
x %= 5 |
x = x % 5 |
Lấy phần dư |
<<= |
x <<= 5 |
x = x << 5 |
Dịch trái |
>>= |
x >>= 5 |
x = x >> 5 |
Dịch phải |
&= |
x &= 5 |
x = x & 5 |
AND |
^= |
x ^= 5 |
x = x ^ 5 |
XOR |
|= |
x |= 5 |
x = x | 5 |
OR |
5.6. Toán Tử Bit (Bitwise Operators)¤
Bảng chân trị:
| p | q | p & q (AND) | p ^ q (XOR) | p | q (OR) | ~p (NOT) |
|---|---|---|---|---|---|
| 0 | 0 | 0 | 0 | 0 | 1 |
| 0 | 1 | 0 | 1 | 1 | 1 |
| 1 | 0 | 0 | 1 | 1 | 0 |
| 1 | 1 | 1 | 0 | 1 | 0 |
Toán tử dịch bit:
// Dịch trái (<<)
3 = 0011
3 << 1 = 0110 = 6
3 << 2 = 1100 = 12
3 << 3 = 1000 = 8
// Dịch phải (>>)
12 = 1100
12 >> 1 = 0110 = 6
12 >> 2 = 0011 = 3
12 >> 3 = 0001 = 1
Ví dụ toán tử trên bit:
int main() {
int a = 5; // 0000 0000 0000 0101
int b = 6; // 0000 0000 0000 0110
int z1 = a & b; // 0000 0000 0000 0100 = 4
int z2 = a | b; // 0000 0000 0000 0111 = 7
int z3 = a ^ b; // 0000 0000 0000 0011 = 3
int z4 = ~a; // 1111 1111 1111 1010 = -6
int z5 = a >> 2; // 0000 0000 0000 0001 = 1
int z6 = a << 2; // 0000 0000 0001 0100 = 20
return 0;
}
Ứng dụng của toán tử bit:
1. Kiểm tra chia hết cho 2:
int number = 5;
if (number & 1 == true)
std::cout << "So le\n";
else
std::cout << "So chan\n";
// Tổng quát:
// a & 1 → a % 2
// a & 3 → a % 4
// a & 7 → a % 8
2. Tích và thương cho 2ⁿ:
int a = 2 << 1; // a = 2 * 2¹ → a = 4
int b = 2 << 2; // b = 2 * 2² → b = 8
int c = 8 >> 1; // c = 8 / 2¹ → c = 4
int d = 8 >> 2; // d = 8 / 2² → d = 2
5.7. Toán Tử Điều Kiện (Ternary Operator)¤
Cú pháp:
Ý nghĩa: Nếu điều kiện đúng thì thực hiện biểu_thức_1, ngược lại thực hiện biểu_thức_2.
// Ví dụ 1: Tìm số lớn hơn
int a = 1;
int b = 2;
int c = (a > b) ? a : b; // c = 2
// Ví dụ 2: Định nghĩa hằng có điều kiện
int so_sinh_vien = 55;
const int so_lop = (so_sinh_vien > 50) ? 2 : 1; // so_lop = 2
Ứng dụng
Toán tử điều kiện hữu ích khi cần gán giá trị cho hằng số dựa trên điều kiện, vì câu lệnh if không thể sử dụng trong trường hợp này.
5.8. Toán Tử Quan Hệ (Relational Operators)¤
| Toán tử | Ký hiệu | Ví dụ | Giải thích |
|---|---|---|---|
| Lớn hơn | > |
x > y |
Nếu x lớn hơn y → true (1), ngược lại → false (0) |
| Nhỏ hơn | < |
x < y |
Nếu x nhỏ hơn y → true (1), ngược lại → false (0) |
| Lớn hơn hoặc bằng | >= |
x >= y |
Nếu x ≥ y → true (1), ngược lại → false (0) |
| Nhỏ hơn hoặc bằng | <= |
x <= y |
Nếu x ≤ y → true (1), ngược lại → false (0) |
| Bằng | == |
x == y |
Nếu x = y → true (1), ngược lại → false (0) |
| Khác | != |
x != y |
Nếu x ≠ y → true (1), ngược lại → false (0) |
5.9. Toán Tử Luận Lý (Logical Operators)¤
| Toán tử | Ký hiệu | Ví dụ |
|---|---|---|
| NOT | ! |
!x |
| AND | && |
x && y |
| OR | || |
x || y |
Bảng chân trị:
| Giá trị 1 | Giá trị 2 | OR (||) |
AND (&&) |
|---|---|---|---|
| false | false | false | false |
| false | true | true | false |
| true | false | true | false |
| true | true | true | true |
Bài tập:
1. (true && true) || false // true
2. (false && true) || true // true
3. (false && true) || false || true // true
4. (5 > 6 || 4 > 3) && (7 > 8) // false
5. !(7 > 6 || 3 > 4) // false
5.10. Độ Ưu Tiên Toán Tử (Operator Precedence)¤
| Mức độ | Toán tử | Nhóm ưu tiên |
|---|---|---|
| 1 | :: |
Trái → Phải |
| 2 | ++ -- () [] . -> |
Trái → Phải |
| 3 | ++ -- ~ ! + - & * new delete sizeof (type) |
Phải → Trái |
| 4 | .* ->* |
Trái → Phải |
| 5 | * / % |
Trái → Phải |
| 6 | + - |
Trái → Phải |
| 7 | << >> |
Trái → Phải |
| 8 | < > <= >= |
Trái → Phải |
| 9 | == != |
Trái → Phải |
| 10 | & |
Trái → Phải |
| 11 | ^ |
Trái → Phải |
| 12 | | |
Trái → Phải |
| 13 | && |
Trái → Phải |
| 14 | || |
Trái → Phải |
| 15 | = *= /= %= += -= >>= <<= &= ^= |= ?: |
Phải → Trái |
| 16 | , |
Trái → Phải |
Bài tập:
1. x = 3 + 4 + 5;
// Giải: x = ((3 + 4) + 5);
2. x = y = z;
// Giải: x = (y = z);
3. z *= ++y + 5;
// Giải: z *= (++y) + 5;
4. a || b && c || d;
// Giải: (a || (b && c)) || d;
Bài tập về các phép toán
Bài 1: Tính
(5 > 3 && 4 < 8)→ true(4 > 6 && true)→ false(3 >= 3 || false)→ true(true || false) ? 4 : 5→ 4
Bài 2: Tính
7 / 4→ 1 (chia nguyên)14 % 5→ 4 (phần dư)3 / 0→ Lỗi (chia cho 0)
6. Biểu Thức (Expression)¤
Định nghĩa: Biểu thức được tạo thành từ các toán tử (Operator) và các toán hạng (Operand).
- Toán tử: Tác động lên các giá trị của toán hạng và cho giá trị có kiểu nhất định
- Toán hạng: Hằng, biến, lời gọi hàm...
Ví dụ:
Biểu thức kiểm tra điều kiện:
// Biểu thức này kiểm tra gì?
(x >= 0) ^ (y < 0)
// Kiểm tra x và y có dấu khác nhau (một dương một âm)
int year = 2000;
int month = 29;
if ((year % 4 != 0) || (year % 400 != 0))
return 28;
// Kiểm tra năm nhuận
7. Nhập Xuất Dữ Liệu¤
7.1. Câu Lệnh Xuất¤
Có 2 cách xuất dữ liệu trong C++:
- Cách 1: Sử dụng
cout(C++) - Cách 2: Sử dụng
printf(C)
Lựa chọn tùy thuộc vào lập trình viên.
7.2. Câu Lệnh Xuất cout (C++)¤
Thư viện:
Cú pháp:
Tham số có thể là:
- Văn bản thường (literal text)
- Ký tự điều khiển (escape sequence)
- Biến, hằng số, biểu thức, hàm
Ví dụ:
Output:
7.2.1. Xuất văn bản thường¤
Cú pháp:
Ví dụ:
#include <iostream>
int main() {
std::cout << "Chao ban! Toi co the giup gi khong?";
std::cin.get();
return 0;
}
Output:
7.2.2. Ký tự điều khiển (Escape Sequence)¤
| Ký tự | Ý nghĩa |
|---|---|
\n |
Xuống dòng |
\a |
Phát ra thông báo (beep) |
\b |
Lùi con trỏ 1 vị trí |
\t |
Dấu tab |
\" |
In ký tự " |
\\ |
In ký tự \ |
Ví dụ:
#include <iostream>
int main() {
std::cout << "Chao ban!\nToi co the giup gi khong?";
std::cin.get();
return 0;
}
Output:
7.2.3. Thiết lập độ rộng khi xuất¤
Cú pháp:
Chú ý
Độ rộng quy định chỉ có tác dụng cho một giá trị xuất. Sau đó C++ lại áp dụng độ rộng mặc định bằng 0.
Ví dụ:
#include <iostream>
int main() {
int a = 1706;
std::cout << a << "\n";
std::cout.width(10);
std::cout << a;
std::cin.get();
return 0;
}
Output:
7.2.4. Độ chính xác khi xuất¤
Cú pháp:
Chú ý
Độ chính xác được thiết lập sẽ có hiệu lực cho tới khi gặp một câu lệnh thiết lập độ chính xác mới.
Ví dụ:
#include <iostream>
int main() {
float x = 176.859;
std::cout << x << "\n";
std::cout.precision(5);
std::cout << x << "\n";
std::cin.get();
return 0;
}
Output:
7.3. Câu Lệnh Xuất printf (C)¤
Thư viện:
Cú pháp:
Chuỗi định dạng gồm:
- Văn bản thường (literal text)
- Ký tự điều khiển (escape sequence)
- Đặc tả (conversion specifier)
7.3.1. Đặc tả (Conversion Specifier)¤
| Đặc tả | Ý nghĩa | Kiểu dữ liệu |
|---|---|---|
%c |
Ký tự | char |
%d, %ld |
Số nguyên có dấu | int, short, long |
%f, %lf |
Số thực | float, double |
%s |
Chuỗi ký tự | char[], char* |
%u |
Số nguyên không dấu | unsigned int/short/long |
Ví dụ:
int a = 10, b = 20;
printf("%d", a); // Xuất ra 10
printf("%d", b); // Xuất ra 20
printf("%d %d", a, b); // Xuất ra 10 20
float x = 15.06;
printf("%f", x); // Xuất ra 15.060000
printf("%f", 1.0/3); // Xuất ra 0.333333
7.3.2. Định dạng xuất (printf)¤
Cú pháp:
- Định dạng xuất số nguyên:
%nd - Định dạng xuất số thực:
%n.kf
Ví dụ:
int a = 1706;
float x = 176.85;
printf("%10d", a); // 1706
printf("\n");
printf("%10.2f", x); // 176.85
printf("\n");
printf("%.2f", x); // 176.85
Phối hợp các thành phần:
int a = 1, b = 2;
// Cách dài dòng:
printf("%d", a); // Xuất giá trị của a
printf(" cong "); // Xuất chuỗi " cong "
printf("%d", b); // Xuất giá trị của b
printf(" bang "); // Xuất chuỗi " bang "
printf("%d", a + b); // Xuất giá trị của a + b
printf("\n"); // Xuống dòng
// Cách ngắn gọn (khuyến nghị):
printf("%d cong %d bang %d\n", a, b, a + b);
7.4. Câu Lệnh Nhập¤
Có 2 cách nhập dữ liệu:
- Cách 1: Sử dụng
cin(C++) - Cách 2: Sử dụng
scanf(C)
7.5. Câu Lệnh Nhập std::cin>> (C++)¤
Thư viện:
Cú pháp:
Lưu ý
Tham số không có dạng chuỗi (không có dấu nháy kép).
Ví dụ:
#include <iostream>
int main() {
int nam_sinh = 0; // Bước 1: Khai báo biến
std::cout << "Nam sinh: "; // Bước 2: Thông báo
std::cin >> nam_sinh; // Bước 3: Nhập giá trị
std::cin.get();
return 0;
}
Chương trình cộng 2 số nguyên:
#include <iostream>
int main() {
int a = 0, b = 0;
std::cout << "Chuong trinh cong 2 so a, b" << "\n";
std::cout << "a: ";
std::cin >> a;
std::cout << "b: ";
std::cin >> b;
std::cout << "a + b = " << a + b << "\n";
std::cin.get();
return 0;
}
Output:
7.6. Câu Lệnh Nhập scanf (C)¤
Thư viện:
Cú pháp:
<chuỗi định dạng>: Giống định dạng xuất nhưng chỉ có các đặc tả- Các đối số là tên các biến và bắt buộc đặt trước dấu
&
Ví dụ:
int a, b;
// Cách 1: Nhập từng biến
scanf("%d", &a); // Nhập giá trị cho biến a
scanf("%d", &b); // Nhập giá trị cho biến b
// Cách 2: Nhập nhiều biến (khuyến nghị)
scanf("%d%d", &a, &b);
Các lỗi thường gặp
8. Một Số Hàm Hữu Ích¤
Các Hàm Trong Thư Viện Toán Học¤
Thư viện:
Hàm với 1 đối số đầu vào (double) và trả về double:
| Hàm | Ý nghĩa |
|---|---|
acos, asin, atan |
Hàm lượng giác ngược |
cos, sin, tan |
Hàm lượng giác |
exp |
e mũ x |
log |
Logarit tự nhiên |
log10 |
Logarit cơ số 10 |
sqrt |
Căn bậc 2 |
ceil |
Làm tròn lên |
floor |
Làm tròn xuống |
abs, fabs |
Giá trị tuyệt đối |
Hàm với 2 đối số đầu vào (double) và trả về double:
double pow(double x, double y): x mũ y
Ví dụ:
#include <iostream>
#include <math.h>
int main() {
float x = 2;
std::cout << cos(x) << "\n"; // Hàm cos: -0.416147
std::cout << sin(x) << "\n"; // Hàm sin: 0.909297
std::cout << tan(x) << "\n"; // Hàm tan: -2.18504
std::cout << acos(x) << "\n"; // Hàm arc cos: nan
std::cout << asin(x) << "\n"; // Hàm arc sin: nan
std::cout << atan(x) << "\n"; // Hàm arc tan: 1.10715
std::cout << log(x) << "\n"; // Hàm log: 0.693147
std::cout << log10(x) << "\n"; // Hàm log10: 0.30103
std::cout << sqrt(x) << "\n"; // Căn bậc 2: 1.41421
std::cout << fabs(-x) << "\n"; // Giá trị tuyệt đối: 2
std::cout << pow(x, 2); // Hàm mũ: 4
std::cin.get();
return 0;
}
9. Bài Tập Minh Họa¤
Bài 1: Nhập năm sinh và tính tuổi¤
#include <iostream>
int main() {
int nam_sinh = 0;
std::cout << "Vui long nhap nam sinh: ";
std::cin >> nam_sinh;
std::cout << "Ban " << 2024 - nam_sinh << " tuoi" << "\n";
std::cin.get();
return 0;
}
Bài 2: Tính tổng, hiệu, tích, thương¤
#include <iostream>
int main() {
int a, b;
std::cout << "Nhap a = ";
std::cin >> a;
std::cout << "Nhap b = ";
std::cin >> b;
std::cout << "a + b = " << a + b << "\n";
std::cout << "a - b = " << a - b << "\n";
std::cout << "a * b = " << (long long)a * b << "\n";
std::cout << "a / b = " << (double)a / b << "\n";
std::cin.get();
return 0;
}
Bài 3: Tính tiền và thuế VAT¤
#include <iostream>
int main() {
int so_luong = 0, don_gia = 0;
std::cout << "Vui long nhap so luong: ";
std::cin >> so_luong;
std::cout << "Vui long nhap don gia: ";
std::cin >> don_gia;
std::cout << "Tien: " << so_luong * don_gia << "\n";
std::cout << "VAT: " << so_luong * don_gia * 0.1 << "\n";
std::cin.get();
return 0;
}
Bài 4: Tính chu vi và diện tích hình tròn¤
#include <iostream>
#define PI 3.14
int main() {
float r = 0;
std::cout << "Nhap ban kinh duong tron: ";
std::cin >> r;
std::cout << "Chu vi: " << 2 * PI * r << "\n";
std::cout << "Dien tich: " << PI * r * r << "\n";
return 0;
}
10. Bài Tập Về Nhà¤
Bài 1: Tách chữ số biển xe
Cho số xe gồm 4 chữ số. Tính tổng các chữ số (số nút).
Gợi ý: Sử dụng phép chia và chia lấy dư.
Bài 2: Chuyển đổi chữ hoa - chữ thường
Cho 1 ký tự chữ thường. In ra ký tự chữ hoa tương ứng.
Gợi ý: Sử dụng bảng mã ASCII. Khoảng cách giữa chữ hoa và chữ thường là 32.
Bài 3: Tìm min/max
Cho 3 số nguyên. Tìm số lớn nhất và nhỏ nhất.
Gợi ý: Sử dụng toán tử điều kiện hoặc hàm max, min.
Bài 4: Cộng/trừ giờ
Viết chương trình nhập 2 giờ (giờ, phút, giây) và thực hiện cộng, trừ 2 giờ này.
Gợi ý: - Chuyển đổi sang tổng số giây - Thực hiện phép tính - Chuyển ngược lại sang (giờ, phút, giây)
Bài 5: Tổng bội số của 3 và 5
Tổng các bội số của 3 và 5 nhỏ hơn 10 là 23.
Ví dụ: Ta có các bội số: 3, 5, 6, 9 → Tổng: 23
Tính tổng các bội số của 3 và 5 nhỏ hơn 1000.
Tổng kết Chương Toán Tử
Trong chương này, chúng ta đã học:
- 10 loại toán tử: gán, toán học, tăng/giảm, phẩy, phức hợp, bit, điều kiện, quan hệ, luận lý
- Độ ưu tiên và thứ tự thực hiện của các toán tử
- Biểu thức và cách tính giá trị
- Nhập xuất dữ liệu với
cin/coutvàscanf/printf - Các hàm toán học thông dụng
- Các bài tập thực hành cơ bản
Chương tiếp theo: Cấu trúc điều khiển (if-else, switch-case)