Chương 2. Kiểu dữ liệu, biểu thức và câu lệnh IV. PHÉP TOÁN, BIỂU THỨC VÀ CÂU LỆNH 1. Phép toán: C++ có rất nhiều phép toán loại 1 ngôi, 2 ngôi và thậm chí cả 3 ngôi. Để hệ thống, chúng tôi tạm phân chia thành các lớp và trình bày chỉ một số trong chúng. Các phép toán còn lại sẽ được tìm hiểu dần trong các phần sau của giáo trình. Các thành phần tên gọi tham gia trong phép toán được gọi là hạng thức hoặc toán hạng, các kí hiệu phép toán được gọi là toán tử. Ví...
Chương Kiểu liệu, biểu thức câu lệnh ĐẠI HỌC QUỐC GIA HÀ NỘI TRƯỜNG ĐẠI HỌC CÔNG NGHỆ Khoa Công nghệ Thông tin PHẠM HỒNG THÁI Bài giảng NGƠN NGỮ LẬP TRÌNH C/C++ ti p th o ) IV PHÉP TOÁN, BIỂU THỨC VÀ CÂU LỆNH Phép tốn: C++ có nhiều phép tốn loại ngơi, ngơi chí ngơi Để hệ thống, tạm phân chia thành lớp trình bày số chúng Các phép tốn cịn lại tìm hiểu dần phần sau giáo trình Các thành phần tên gọi tham gia phép toán gọi hạng thức tốn hạng, kí hiệu phép tốn gọi tốn tử Ví dụ phép tốn a + b; a, b gọi toán hạng + tốn tử Phép tốn ngơi phép tốn có tốn hạng, ví dụ −a (đổi dấu số a), &x (lấy địa biến x) … Một số kí hiệu phép tốn sử dụng chung cho lẫn (hiển nhiên với ngữ nghĩa khác nhau), ví dụ kí hiệu − sử dụng cho phép tốn trừ ngơi a − b, phép & sử dụng cho phép toán lấy hội bit (a & b) số nguyên a b … a Các phép toán số học: +, -, *, /, % − Các phép toán + (cộng), − (trừ), * (nhân) hiểu theo nghĩa thơng thường số học − Phép tốn a / b (chia) thực theo kiểu toán hạng, tức hai toán hạng số nguyên kết phép chia lấy phần nguyên, ngược lại toán hạng thực kết số thực Ví dụ: 13/5 = 13.0/5 = 13/5.0 = 13.0/5.0 = 2.6 // 13 số nguyên // có tốn hạng thực Chương Kiểu liệu, biểu thức câu lệnh − Phép toán a % b (lấy phần dư) trả lại phần dư phép chia a/b, a b số nguyên Ví dụ: 13%5 = // phần dư 13/5 5%13 = // phần dư 5/13 b Các phép toán tự tăng, giảm: i++, ++i, i , i − Phép toán ++i i++ tăng i lên đơn vị tức tương đương với câu lệnh i = i+1 Tuy nhiên phép toán nằm câu lệnh biểu thức ++i khác với i++ Cụ thể ++i tăng i, sau i tham gia vào tính tốn biểu thức Ngược lại i++ tăng i sau biểu thức tính tốn xong (với giá trị i cũ) Điểm khác biệt minh hoạ thơng qua ví dụ sau, giả sử i = 3, j = 15 Phép toán Tương đương Kết i = ++j ; // tăng trước j=j+1;i=j; i = 16 , j = 16 i = j++ ; // tăng sau i=j;j=j+1; i = 15 , j = 16 j = ++i + ; i=i+1;j=i+5; i = 4, j = j = i++ + ; j = i + 5; i = i + 1; i = 4, j = Ghi chú: Việc kết hợp phép toán tự tăng giảm vào biểu thức câu lệnh (như ví dụ phần sau) làm chương trình gọn khó hiểu c Các phép tốn so sánh lơgic Đây phép toán mà giá trị trả lại sai Nếu giá trị biểu thức nhận giá trị 1, ngược lại sai biểu thức nhận giá trị Nói cách khác giá trị cụ thể khái niệm "đúng", "sai" Mở rộng C++ quan niệm giá trị khác "đúng" giá trị "sai" • Các phép tốn so sánh == (bằng nhau), != (khác nhau), > (lớn hơn), < (nhỏ hơn), >= (lớn bằng), =2 Chú ý: cần phân biệt phép toán gán (=) phép toán so sánh (==) Phép gán vừa gán giá trị cho biến vừa trả lại giá trị (là giá trị toán hạng bên phải), phép so sánh luôn trả lại giá trị • Các phép tốn lơgic: && (và), || (hoặc ), ! (khơng, phủ định) Hai tốn hạng loại phép tốn phải có kiểu lơgic tức nhận hai giá trị "đúng" (được thể số nguyên khác 0) "sai" (thể 0) Khi giá trị trả lại phép tốn cho bảng sau: a b a && b a || b !a 1 1 0 0 1 0 0 Tóm lại: − Phép toán "và" hai toán hạng − Phép toán "hoặc" sai hai toán hạng sai − Phép tốn "khơng" (hoặc "phủ định") tốn hạng sai Ví dụ: && (4 > 5) // = có hạng thức (4>5) sai (3 >= 1) && (7) // = hai hạng thức !1 // = ! (4 + < 7) // = (4+3= 6) // = có hạng thức (5) (5 < !0) || (4 >= 6) // = hai hạng thức sai Chú ý: việc đánh giá biểu thức tiến hành từ trái sang phải dừng biết kết mà không chờ đánh giá hết biểu thức Cách đánh giá cho kết phụ khác biểu thức ta "tranh thủ" đưa thêm vào phép toán tự tăng giảm Ví dụ cho i = 2, j = 3, xét biểu thức sau đây: x = (++i < && ++j > 5) 32 cho kết x = , i = , j = Chương Kiểu liệu, biểu thức câu lệnh y = (++j > && ++i < 4) cho kết y = , i = , j = cách viết hai biểu thức (ngoại trừ hốn đổi vị trí toán hạng phép toán &&) Với giả thiết i = j = ta thấy hai biểu thức nhận giá trị Tuy nhiên giá trị i j sau thực xong hai biểu thức có kết khác Cụ thể với biểu thức đầu ++i < nên chương trình phải tiếp tục tính tiếp ++j > để đánh giá biểu thức Do sau đánh giá xong i j tăng (i=3, j=4) Trong với biểu thức sau ++j > sai nên chương trình kết luận tồn biểu thức sai mà khơng cần tính tiếp ++i < Có nghĩa chương trình sau đánh giá xong ++j > dừng có biến j tăng 1, từ ta có i = 2, j = khác với kết biểu thức Ví dụ lần nhắc ta ý kiểm soát kỹ việc sử dụng phép toán tự tăng giảm biểu thức câu lệnh Các phép gán • Phép gán thơng thường: Đây phép gán trình bày mục trước • Phép gán có điều kiện: biến = (điều_kiện) ? a: b ; điều_kiện biểu thức logic, a, b biểu thức kiểu với kiểu biến Phép toán gán giá trị a cho biến điều kiện b ngược lại Ví dụ: x = (3 + < 7) ? 10: 20 // x = 20 3+4 b) ? a: b // x = số lớn số a, b • Cách viết gọn phép gán: Một phép gán dạng x = x @ a ; viết gọn dạng x @= a @ phép tốn số học, xử lý bit Ví dụ: thay cho viết x = x + viết x += 2; x = x/2 ; x = x*2 viết lại x /= 2; x *= 2; Cách viết gọn có nhiều thuận lợi viết đọc chương trình tên biến dài kèm nhiều số … thay phải viết hai lần tên biến câu lệnh phải viết lần, điều tránh viết lặp lại tên biến dễ gây sai sót Ví dụ thay viết: ngay_quoc_te_lao_dong = ngay_quoc_te_lao_dong + 365; viết gọn bởi: ngay_quoc_te_lao_dong += 365; 33 Chương Kiểu liệu, biểu thức câu lệnh thay cho viết : Luong[Nhanvien[3][2*i+1]] = Luong[Nhanvien[3][2*i+1]] * 290 ; viết lại bởi: Luong[Nhanvien[3][2*i+1]] *= 290; Biểu thức Biểu thức dãy kí hiệu kết hợp toán hạng, phép toán cặp dấu () theo qui tắc định Các toán hạng hằng, biến, hàm Biểu thức cung cấp cách thức để tính giá trị dựa tốn hạng tốn tử biểu thức Ví dụ: (x + y) * - ; - x + sqrt(y) ; (-b + sqrt(delta)) / (2*a) ; a Thứ tự ưu tiên phép tốn Để tính giá trị biểu thức cần có trật tự tính tốn cụ thể thống Ví dụ xét biểu thức x = + * + − tính theo trật tự từ trái sang phải, ta có x = ((3+4) * 2) + = 21, − ưu tiên dấu + thực trước dấu *, x = (3 + 4) * (2 + 7) = 63, − ưu tiên dấu * thực trước dấu +, x = + (4 * 2) + = 18 Như biểu thức tính x cho kết khác theo cách hiểu khác Vì cần có cách hiểu thống dựa thứ tự ưu tiên phép toán, tức phép tốn ưu tiên tính trước phép tốn tính sau C++ qui định trật tự tính tốn theo mức độ ưu tiên sau: Các biểu thức cặp dấu ngoặc () Các phép tốn ngơi (tự tăng, giảm, lấy địa chỉ, lấy nội dung trỏ …) Các phép toán số học Các phép toán quan hệ, logic Các phép gán Nếu có nhiều cặp ngoặc lồng cặp (sâu nhất) tính trước Các phép tốn lớp có độ ưu tiên theo thứ tự: lớp nhân (*, /, &&), lớp cộng (+, −, ||) Nếu phép tốn có thứ tự ưu tiên chương trình thực từ trái sang phải Các phép gán có độ ưu tiên cuối thực từ phải sang trái Ví dụ theo mức ưu tiên qui định, biểu thức tính x ví dụ tính x = + (4 * 2) + = 18 34 Chương Kiểu liệu, biểu thức câu lệnh Phần lớn trường hợp muốn tính tốn theo trật tự ta nên sử dụng cụ thể dấu ngoặc (vì biểu thức dấu ngoặc tính trước) Ví dụ: − Để tính Δ = b2 - 4ac ta viết delta = b * b − * a * c ; −b+ Δ viết : x = −b + sqrt(delta) / 2a 2*a; sai theo mức độ ưu tiên x tính −b + ((sqrt(delta)/2) * a) (thứ tự tính phép tốn ngơi đổi dấu −b, đến phép chia, phép nhân cuối phép cộng) Để tính xác cần phải viết (−b + sqrt(delta)) / (2*a) − Để tính nghiệm phương trình bậc 2: x = − Cho a = 1, b = 2, c = Biểu thức a += b += c cho giá trị c = 3, b = 5, a = Thứ tự tính từ phải sang trái, tức câu lệnh tương đương với câu lệnh sau: a=1;b=2;c=3; b=b+c; // b = a=a+b; // a = Để rõ ràng, tốt nên viết biểu thức cần tính trước dấu ngoặc b Phép chuyển đổi kiểu Khi tính tốn biểu thức phần lớn phép toán yêu cầu toán hạng phải kiểu Ví dụ để phép gán thực giá trị biểu thức phải có kiểu với biến Trong trường hợp kiểu giá trị biểu thức khác với kiểu phép gán chương trình tự động chuyển kiểu giá trị biểu thức thành kiểu biến gán (nếu được) báo lỗi Do cần thiết NSD phải sử dụng câu lệnh để chuyển kiểu biểu thức cho phù hợp với kiểu biến − Chuyển kiểu tự động: mặt nguyên tắc, cần thiết kiểu có giá trị thấp chương trình tự động chuyển lên kiểu cao cho phù hợp với phép tốn Cụ thể phép chuyển kiểu thực theo sơ đồ sau: char ↔ int → long int → float → double Ví dụ: int i = 3; float f ; f = i + 2; ví dụ i có kiểu ngun i+2 có kiểu ngun f có kiểu thực Tuy phép tốn gán hợp lệ chương trình tự động chuyển kiểu 35 Chương Kiểu liệu, biểu thức câu lệnh cuả i+2 (bằng 5) sang kiểu thực (bằng 5.0) gán cho f − Ép kiểu: chuyển kiểu tự động, chương trình chuyển kiểu từ thấp đến cao, nhiên chiều ngược lại thực gây liệu Do cần thiết NSD phải lệnh cho chương trình Ví dụ: int i; float f = ; // tự động chuyển thành 3.0 gán cho f i=f+2; // sai f + = không gán cho i Trong ví dụ để câu lệnh i = f+2 thực ta phải ép kiểu biểu thức f+2 thành kiểu nguyên Cú pháp tổng quát sau: (tên_kiểu)biểu_thức // cú pháp cũ C tên_kiểu(biểu_thức) // cú pháp C++ hoặc: tên_kiểu kiểu cần chuyển sang Như câu lệnh phải viết lại: i = int(f + 2) ; f+2 (bằng 5.0) chuyển thành gán cho i Dưới ta xét số ví dụ lợi ích việc ép kiểu • Phép ép kiểu từ số thực số nguyên cắt bỏ tất phần thập phân số thực, để lại phần nguyên Như để tính phần nguyên số thực x ta cần ép kiểu x thành kiểu nguyên, có nghĩa int(x) phần nguyên số thực x Ví dụ để kiểm tra số ngun n có phải số phương, ta cần tính bậc hai n Nếu bậc hai x n số ngun n số phương, tức int(x) = x x nguyên n phương, ví dụ: int n = 10 ; float x = sqrt(n) ; // hàm sqrt(n) trả lại bậc hai số n if (int(x) == x) cout c ; cout > y ; x = + x ; y = (x = sqrt(x)) + ; cout