Biểu
thức (Expressions)
Một biểu
thức là tổ hợp các toán tử và toán hạng. Toán tử thực hiện các thao tác như cộng,
trừ, so sánh v.v... Toán hạng là những biến hay những giá trị mà các phép toán
được thực hiện trên nó. Trong ví dụ a
+ b, “a” và “b” là toán hạng
và “+” là toán tử. Tất cả kết hợp lại là một biểu thức.
Trong
quá trình thực thi chương trình, giá trị thực sự của biến (nếu có) sẽ được sử dụng
cùng với các hằng có mặt trong biểu thức. Việc đánh giá biểu thức được thực hiện
nhờ các toán tử. Vì vậy, mọi biểu thức trong C
đều có một giá trị.
Các ví
dụ về biểu thức là:
2
x
3 + 7
2 × y + 5
2 + 6 × (4 - 2)
z
+ 3 × (8 - z)
Ví dụ 1:
Roland
nặng 70 kilograms, và Mark nặng k kilograms. Viết một biểu thức cho tổng
cân nặng của họ. Tổng cân nặng của hai người tính bằng kilograms là 70 + k.
Ví dụ 2:
Tính giá trị biểu thức 4 × z + 12 với z =
15.
Chúng
ta thay thế mọi z với giá trị 15, và đơn giản hóa biểu thức theo quy tắc: thi
hành phép toán trong dấu ngoặc trước tiên, kế đến lũy thừa, phép nhân và chia rồi
phép cộng và trừ.
4 × z + 12 trở thành
4 × 15 + 12 = (phép
nhân thực hiện trước phép cộng)
60 + 12 =
72
Toán tử gán (Assignment Operator)
Trước
khi nghiên cứu các toán tử khác, ta hãy xét toán tử gán (=). Ðây là toán tử
thông dụng nhất cho mọi ngôn ngữ và mọi người đều biết. Trong C, toán tử gán có
thể được dùng cho bất kỳ biểu thức C hợp lệ. Dạng thức chung cho toán tử gán
là:
Tên biến = biểu thức;
Gán liên tiếp
Nhiều
biến có thể được gán cùng một giá trị trong một câu lệnh đơn. Việc này thực hiện
qua cú pháp gán liên tiếp. Ví dụ:
a = b = c =10;
Dòng mã
trên gán giá trị 10 cho a, b,và c. Tuy nhiên, việc này không thể
thực hiện lúc khai báo biến. Ví dụ,
int a = int b = int c= 0;
Câu
lệnh trên phát sinh lỗi vì sai cú pháp.
Toán tử quan hệ (Relational Operators)
Toán tử
quan hệ được dùng để kiểm tra mối quan hệ giữa hai biến, hay giữa một biến và một
hằng. Ví dụ, việc xét số lớn hơn của hai số, a và b, được thực hiện
thông qua dấu lớn hơn (>) giữa hai toán hạng a và b (a
> b).
Trong
C, true (đúng) là bất cứ giá trị nào khác không (0), và false (sai)
là bất cứ giá trị nào bằng không (0). Biểu thức dùng toán tử quan hệ trả về 0
cho false và 1 cho true. Ví dụ biểu thức sau :
a == 14;
Biểu thức
này kiểm tra xem giá trị của a có bằng 14 hay không. Giá trị của biểu thức sẽ
là 0 (false) nếu a có giá trị khác 14 và 1 (true)
nếu nó là 14.
Bảng
sau mô tả ý nghĩa của các toán tử quan hệ.
Toán tử
|
Ý nghĩa
|
>
|
lớn hơn
|
>=
|
lớn hơn hoặc bằng
|
<
|
nhỏ hơn
|
<=
|
nhỏ hơn hoặc bằng
|
==
|
bằng
|
!=
|
không bằng
|
Bảng 4.1: Toán tử quan hệ và ý nghĩa
Toán
tử luận lý (Logical Operators) và biểu thức
Toán
tử luận lý là các ký
hiệu dùng để kết hợp hay phủ định biểu thức có chứa các toán tử quan hệ.
Những
biểu thức dùng toán tử luận lý trả về 0 cho false và 1 cho
true.
Bảng
sau mô tả ý nghĩa của các toán tử luận lý.
Toán tử
|
Ý nghĩa
|
|
AND: trả về kết quả là true
khi cả 2 toán hạng đều true
|
|
OR
: trả về kết quả là true khi chỉ một
trong hai toán hạng đều true
|
|
NOT:
Chuyển đổi giá trị của toán hạng duy nhất từ true thành false và
ngược lại.
|
Table
4.2: Toán tử luận lý và ý nghĩa
Lưu ý: Bất
cứ toán tử luận lý nào có ký hiệu là hai ký tự thì không được có khoảng trắng giữa
hai ký tự đó, ví dụ : == sẽ không đúng nếu viết là = =.
Giả sử
một chương trình phải thực thi những bước nhất định nếu điều kiện a < 10
và b == 7 được thoả mãn. Ðiều kiện này được viết ra bằng cách dùng toán
tử quan hệ kết hợp với toán tử luận lý AND. Toán tử AND được viết là &&.
Ta sẽ có điều kiện để kiểm tra như sau :
(a < 10) && (b == 7);
Tương tự,
toán tử OR dùng để kiểm tra xem có một trong số các điều kiện kiểm tra
là đúng hay không. Nó có dạng là dấu (||). Cùng ví dụ trên nhưng điều kiện
cần kiểm tra là: chỉ cần một trong hai câu lệnh là đúng thì ta có mã sau :
(a < 10) || (b == 7);
Toán tử
luận lý thứ ba là NOT được biểu diễn bằng ký hiệu dấu chấm than ‘!’.
Toán tử này đảo ngược giá trị luận lý của biểu thức. Ví dụ, để kiểm tra xem biến
s có bé hơn 10 hay không, ta viết đều kiện kiểm tra như sau:
(s < 10);
hay là
(! (s >= 10)) /* s không lớn hơn hay bằng 10 */
Cả
toán tử quan hệ và luận lý có quyền ưu tiên thấp hơn toán tử số học. Ví dụ, 5 > 4 + 3 được tính
tương đương với 5 > (4 + 3), nghĩa là 4+3 sẽ được tính trước và sau
đó toán tử quan hệ sẽ được thực hiện. Kết quả sẽ là false, tức là trả về
0.
Câu lệnh
sau:
printf("%d", 5> 4 + 3);
sẽ cho
ra:
0
vì 5 bé
hơn (4 + 3) .
Các toán tử số học (Arithmetic Operators)
Những toán tử
số học được sử dụng để thực hiện những thao tác mang tính số học. Chúng được
chia thành hai lớp : Toán tử số học một ngôi (unary) và toán tử số học hai ngôi
(binary).
Bảng 2.2 liệt
kê những toán tử số học và chức năng của chúng.
Các toán tử một ngôi
|
Chức năng
|
Các toán tử hai ngôi
|
Chức năng
|
-
|
Lấy đối số
|
+
|
Cộng
|
++
|
Tăng một giá trị
|
-
|
Trừ
|
--
|
Giảm một giá trị
|
*
|
Nhân
|
|
|
%
|
Lấy phần dư
|
|
|
/
|
Chia
|
|
|
^
|
Lấy số mũ
|
Bảng 2.2: Các toán tử số học
và chức năng
Các toán tử hai ngôi
Trong C, các
toán tử hai ngôi có chức năng giống như trong các ngôn ngữ khác. Những toán tử
như +, -, * và / có thể được áp dụng cho hầu hết kiểu dữ liệu có sẵn trong C.
Khi toán tử / được áp dụng cho một số
nguyên hoặc ký tự, bất kỳ phần dư nào sẽ được cắt bỏ. Ví dụ, 5/2 sẽ bằng 2
trong phép chia số nguyên. Toán tử % sẽ cho ra kết quả là số dư của phép chia số
nguyên. Ví dụ: 5%2 sẽ có kết quả là 1.
Tuy nhiên, % không thể được sử dụng với những kiểu có dấu chấm động.
Chúng ta hãy
xem xét một ví dụ của toán tử số mũ.
9^2
Ở đây 9 là cơ
số và 2 là số mũ.
Số bên trái của
‘^’ là cơ số và số bên phải ‘^’ là số
mũ.
Kết quả của
9^2 là 9*9 = 81.
Thêm ví dụ
khác:
5 ^ 3
Có nghĩa là:
5 * 5 * 5
Do đó: 5 ^ 3 = 5 * 5 * 5 = 125.
Ghi chú: Những ngôn ngữ lập trình như
Basic, hỗ trợ toán tử mũ. Tuy nhiên, ANSI C không hỗ trợ ký hiệu ^ cho phép
tính lũy thừa. Ta có thể dùng cách khác tính lũy thừa trong C là dùng hàm pow()
đã được định nghĩa trong math.h. Cú pháp của nó thể hiện qua ví dụ sau:
...
#include<math.h>
void main(void)
{
….
/*
the following function will calculate x to the power y. */
z
= pow(x, y);
….
}
Ví dụ sau
trình bày tất cả toán tử hai ngôi được dùng trong C. Chú ý rằng ta chưa nói về
hàm printf() và getchar(). Chúng ta sẽ bàn trong những phần sau.
Ví dụ 3:
#include<stdio.h>
int main() {
int x,y;
x = 5;
y = 2;
printf("The integers are: %d &
%d\n", x, y);
printf("The addition gives: %d\n",
x + y);
printf("The subtraction gives:%d\n",
x - y);
printf("The multiplication gives: %d\n",
x * y);
printf("The division gives: %d\n",
x / y);
printf("The modulus gives:
%d\n", x % y);
getchar();
}
Kết quả là:
The integers are : 5 & 2
The addition gives : 7
The subtraction gives : 3
The multiplication gives : 10
The division gives : 2
The modulus gives : 1
Các toán tử một ngôi (unary)
Các toán tử một
ngôi là toán tử trừ một ngôi ‘-’, toán tử tăng ‘++’ và toán tử giảm ‘--’
Toán tử trừ một ngôi
Ký hiệu giống
như phép trừ hai ngôi. Lấy đối số để chỉ ra hay thay đổi dấu đại số của một giá
trị. Ví dụ:
a = -75;
b = -a;
Kết quả của
việc gán trên là a được gán giá trị -75 và b được gán cho giá trị 75 (-(- 75)).
Dấu trừ được sử dụng như thế gọi là toán tử một ngôi vì nó chỉ có một toán hạng.
Nói một cách
chính xác, không có toán tử một ngôi + trong C. Vì vậy, một lệnh gán như.
invld_pls = +50;
khi mà
invld_pls là một biến số nguyên là không hợp lệ trong chuẩn của C. Tuy nhiên,
nhiều trình biên dịch không phản đối cách dùng như vậy.
Các toán tử
Tăng và Giảm
C bao chứa
hai toán tử hữu ích mà ta không tìm thấy được trong những ngôn ngữ máy tính
khác. Chúng là ++ và --. Toán tử ++ thêm
vào toán hạng của nó một đơn vị, trong khi toán tử -- giảm đi toán hạng của nó một đơn vị.
Cụ thể:
x
= x + 1;
có thể được
viết là:
x++;
và:
x = x - 1;
có thể được
viết là:
x--;
Cả hai toán tử
này có thể đứng trước hoặc sau toán hạng, chẳng hạn:
x = x + 1;
có thể được
viết lại là
x++ hay ++x;
Và cũng tương
tự cho toán tử --.
Sự khác nhau
giữa việc xử lý trước hay sau trong toán tử một ngôi thật sự có ích khi nó được
dùng trong một biểu thức. Khi toán tử đứng trước toán hạng, C thực hiện việc
tăng hoặc giảm giá trị trước khi sử dụng giá trị của toán hạng. Ðây là tiền xử
lý (pre-fixing). Nếu toán tử đi sau toán
hạng, thì giá trị của toán hạng được sử dụng trước khi tăng hoặc giảm giá trị của
nó. Ðây là hậu xử lý (post-fixing). Xem xét ví dụ sau :
a = 10;
b = 5;
c = a * b++;
Trong biểu thức
trên, giá trị hiện thời của b được sử dụng cho tính toán và sau đó giá trị của
b sẽ tăng sau. Tức là, c được gán 50 và sau đó giá trị của b được tăng lên
thành 6.
Tuy nhiên, nếu
biểu thức trên là:
c = a * ++b;
thì giá trị của
c sẽ là 60, và b sẽ là 6 bởi vì b được tăng 1 trước khi thực hiện phép nhân với
a, sau đó giá trị được gán vào c.
Trong trường
hợp mà tác động của việc tăng hay giảm là riêng lẻ thì toán tử có thể đứng trước
hoặc sau toán hạng đều được.
Hầu hết trình
biên dịch C sinh mã rất nhanh và hiệu quả đối với việc tăng và giảm giá trị. Mã
này sẽ tốt hơn so với khi ta dùng toán tử gán. Vì vậy, các toán tử tăng và giảm
nên được dùng bất cứ khi nào có thể.
Đăng nhận xét