Bài giảng Lập trình hướng đối tượng - Đặng Ngọc Hoàng Thành

pdf 208 trang phuongnguyen 5840
Bạn đang xem 20 trang mẫu của tài liệu "Bài giảng Lập trình hướng đối tượng - Đặng Ngọc Hoàng Thành", để tải tài liệu gốc về máy bạn click vào nút DOWNLOAD ở trên

Tài liệu đính kèm:

  • pdfbai_giang_lap_trinh_huong_doi_tuong_dang_ngoc_hoang_thanh.pdf

Nội dung text: Bài giảng Lập trình hướng đối tượng - Đặng Ngọc Hoàng Thành

  1. ĐẶNG NGỌC HỒNG THÀNH C++ LẬP TRÌNH HƯỚNG ĐỐI TƯỢNG Tài liệu học tập
  2. Đặng Ngọc Hoàng Thành PHỤ LỤC GIỚI THIỆU 7 MƠI TRƯỜNG PHÁT TRIỂN TÍCH HỢP IDE 10 CHƯƠNG 1. CƠ BẢN VỀ C++ 23 CHƯƠNG 2. BIẾN VÀ CÁC KIỂU DỮ LIỆU 26 Từ khĩa 26 Kiểu dữ liệu nguyên thủy 27 Khai báo biến 28 Phạm vi tác dụng của biến 29 Khởi tạo giá trị cho biến 31 Khởi tạo giá trị cho biến tĩnh static 32 Giới thiệu về xâu kí tự 32 CHƯƠNG 3. HẰNG 34 Hằng số nguyên 34 Hằng số thực cĩ dấu chấm động 34 Hằng kí tự và hằng xâu kí tự 35 Hằng logic 36 Định nghĩa một hằng #define 36 Khai báo hằng const 37 CHƯƠNG 4. TỐN TỬ 38 Tốn tử gán 38 Tốn tử thực hiện phép tốn số học 39 Tốn tử gán hợp nhất 40 Tốn tử tăng v{ giảm 40 Tốn tử so sánh 41 Tốn tử logic 42 Tốn tử điều kiện 43 Tốn tử phân tách 45 C++ T r a n g | 2
  3. Đặng Ngọc Hoàng Thành Tốn tử dịch bit 45 Tốn tử chuyển đổi kiểu dữ liệu 48 Các tốn tử khác 49 Thứ tự ưu tiên của các tốn tử 49 CHƯƠNG 5. XUẤT NHẬP CƠ BẢN 52 Xuất dữ liệu chuẩn cout 52 Nhập dữ liệu chuẩn cin 53 Nhập dữ liệu nhờ lớp stringstream 54 CHƯƠNG 6. CÁC CẤU TRÚC LỆNH ĐIỀU KHIỂN 57 Cấu trúc lệnh cĩ điều kiện: if và else 57 Cấu trúc lặp 59 Cấu trúc lựa chọn: switch 66 CHƯƠNG 7. HÀM 70 Khai báo và sử dụng hàm 71 Phạm vi tác dụng của biến 75 Hàm khơng trả về giá trị - Hàm void. 76 Tham biến và tham trị 77 Giá trị mặc định của tham số hình thức 80 Chồng chất hàm 81 Hàm nội tuyến 82 H{m đệ quy 83 Hàm mẫu – Template Function 84 CHƯƠNG 8. CÁC KIỂU DỮ LIỆU CĨ CẤU TRÚC 86 Mảng 86 Xâu kí tự 90 CHƯƠNG 9. CON TRỎ 91 Tốn tử tham chiếu & 91 Tốn tử tham chiếu ngược * 92 Khai báo biến con trỏ 94 C++ T r a n g | 3
  4. Đặng Ngọc Hoàng Thành Con trỏ, mảng và xâu kí tự 96 Các phép tốn số học trên con trỏ 98 Con trỏ trỏ vào con trỏ 100 Con trỏ void 102 Con trỏ null 103 Con trỏ hàm 103 CHƯƠNG 10. BỘ NHỚ ĐỘNG 105 Tốn tử new và new[] 105 Tốn tử delete và delete[] 107 CHƯƠNG 11. KIỂU DỮ LIỆU STRUCT VÀ CON TRỎ STRUCT 108 Struct 108 Con trỏ struct 112 Struct lồng nhau 113 Kích thước bộ nhớ của struct 113 CHƯƠNG 12. CÁC KIỂU DỮ LIỆU KHÁC 115 Kiểu dữ liệu tự định nghĩa 115 Kiểu dữ liệu union thường 115 Kiểu dữ liệu union ẩn danh 116 Kiểu dữ liệu enum 116 CHƯƠNG 13. LẬP TRÌNH HƯỚNG ĐỐI TƯỢNG 118 Lịch sử hình thành 118 Lớp v{ đối tượng 124 Hàm tạo và hàm hủy 128 Chồng chất hàm tạo 130 Sao chép hàm tạo 131 Tính đĩng gĩi – Encapsulation 137 Con trỏ đối tượng 138 Lớp được khai báo nhờ từ khĩa struct và union 139 Con trỏ this 139 C++ T r a n g | 4
  5. Đặng Ngọc Hoàng Thành Th{nh viên tĩnh – Từ khĩa static 141 Hàm bạn và lớp bạn 142 Chồng chất tốn tử 145 Tính kế thừa - Inheritance 151 Các mức truy cập 154 Tính đa kế thừa – Multiple Inheritance 157 Tính đa hình – Polymorphism 159 Tính trìu tượng hĩa - Abstraction 164 Lớp Template 165 CHƯƠNG 14. NAMESPACE 167 Từ khĩa namespace 167 Từ khĩa using 168 Phạm vi của namespace 169 Biệt danh cho namespace 170 Namespace std 170 CHƯƠNG 15. NGOẠI LỆ 171 Mệnh đề try catch 171 Mệnh đề throw 171 Thư viện chuẩn exception 172 CHƯƠNG 16. LÀM VIỆC VỚI FILE 173 Mở file 173 Đĩng file 175 File văn bản 175 Kiểm tra trạng thái của các cờ hiệu 176 Con trỏ get và put 177 File nhị phân 179 Bộ đệm v{ Đồng bộ hĩa 180 CHƯƠNG 17. CÁC LỚP THƯ VIỆN 181 1. Lớp số phức complex 181 C++ T r a n g | 5
  6. Đặng Ngọc Hoàng Thành 2. Lớp ngăn xếp stack 183 3. Lớp h{ng đợi queue 184 3. Lớp vector 185 4. Lớp string 187 5. Lớp list 190 6. Lớp map 190 7. Lớp set 191 HƯỚNG DẪN THỰC HÀNH 192 BÀI THỰC HÀNH SỐ 1 192 BÀI THỰC HÀNH SỐ 2 193 BÀI THỰC HÀNH SỐ 3 194 BÀI THỰC HÀNH SỐ 4 194 BÀI THỰC HÀNH SỐ 5 195 BÀI THỰC HÀNH SỐ 6 195 BÀI TẬP NÂNG CAO 197 BÀI TẬP LỚN 204 DANH SÁCH HÌNH 206 TRA CỨU TỪ KHĨA 207 C++ T r a n g | 6
  7. Đặng Ngọc Hoàng Thành GIỚI THIỆU 1. Cấu trúc của giáo trình Gi|o trình được chia ra làm 17 chương và mỗi chương được chia làm các mục khác nhau. C|c chương được sắp xếp theo trình tự từ lập trình hướng thủ tục trên C++ đến lập trình hướng đối tượng và các lớp thư viện cơ bản. Bạn cĩ thể truy cập vào mục bất kì từ phần phụ lục nằm đầu sách. Nhiều mục bao gồm các ví dụ để mơ tả cách sử dụng. Tơi khuyên các bạn nên đọc các ví dụ này và cĩ thể hiểu mỗi đoạn m~ chương trình trước khi đọc chương tiếp theo. Một cách thức tốt để tăng lượng kiến thức mà bạn nhận được đĩ l{ hãy chỉnh sửa, bổ sung các chức năng mới trên ví dụ mẫu, theo hướng tư duy của bạn, để từ đĩ bạn cĩ thể hiểu một c|ch đầy đủ về nội dung mà bạn đ~ đọc. Đừng lo sợ điều đĩ, nĩ chỉ tốt cho bạn mà thơi. Sau khi đọc xong giáo trình, tơi cịn cung cấp một số bài tập thực hành đề nghị để bạn cĩ thể thử nghiệm. Tơi khuyên bạn nên giải những bài tập này, chúng sẽ rất hữu ích và giúp bạn cũng cố lại kiến thức mơn học cũng như hiểu sâu sắc hơn phần lý thuyết. Một điều nữa mà bạn cần lưu ý, bạn h~y đọc trang cuối cùng của cuốn s|ch, để nắm được một số thuật ngữ anh-việt tương ứng được sử dụng trong giáo trình này. Tơi cũng cĩ gắng sử dụng tên gọi phù hợp nhất với đại đa số các giáo trình hiện hành. Tuy nhiên, bạn cũng nên nắm các thuật ngữ tiếng anh tương ứng, để cĩ thể tham khảo thêm các tài liệu chuyên mơn tiếng anh. Khi viết giáo trình này, tơi khơng thể tránh khỏi sai sĩt. Rất mong sự đĩng gĩp ý kiến quý báu của các bạn độc giả cũng như c|c bạn đồng nghiệp. Mọi sự đĩng gĩp xin liên hệ theo địa chỉ email: dnhthanh@hueic.edu.vn. Hi vọng với các ý kiến đĩng gĩp của các bạn, giáo trình này sẽ ngày càng hồn thiện hơn. 2. Một vài chú ý về sự tương thích của C và C++ Chuẩn ANSI-C++ được một tổ chức tiêu chuẩn quốc tế thống nhất đưa ra. Nĩ được chính thức ra mắt v{o th|ng 11 năm 1997 v{ duyệt lại vào C++ T r a n g | 7
  8. Đặng Ngọc Hoàng Thành năm 2003. Tuy nhiên, ngơn ngữ C++ đ~ tồn tại trước đĩ một thời gian kh| d{i (v{o năm 1980). Trước đĩ, cĩ rất nhiều trình dịch khơng hỗ trợ c|c tính năng mới bao gồm cả chuẩn ANSI-C++. Giáo trình này được xây dựng trên c|c chương trình dịch hiện đại hỗ trợ đầy đủ chuẩn ANSI-C++. Tơi đảm bảo với bạn rằng các ví dụ sẽ hoạt động tốt nếu bạn sử dụng một trình dịch hỗ trợ ANSI-C++. Cĩ nhiều sự chọn lựa cho bạn, cĩ thể là miễn phí hoặc các phần mềm thương mại. Trong giáo trình này, chúng tơi giới thiệu đến bạn hai cơng cụ biên dịch C++ là GCC MinGW – miễn phí và Visual C++ - thương mại. 3. Trình biên dịch Các ví dụ trong cuốn giáo trình này là các ví dụ chạy trên màn hình console (m{n hình DOS). Điều đĩ cĩ nghĩa l{ nĩ sử dụng chế độ văn bản để hiển thị các kết quả. Mọi trình dịch C++ đều hỗ trợ chế độ dịch console. Bạn hãy kiểm tra trình dịch của mình để biết thêm thơng tin về cách biên dịch một chương trình C++. Với một mơi trường phát triển tích hợp IDE cho C++ miễn phí, bạn cĩ thể sử dụng chương trình Codeblocks hoặc Eclipse. Chúng là các chương trình dịch hỗ trợ chế độ console lẫn chế độ windows form. Chúng hỗ trợ mơi trường GCC để biên dịch cả C và C++. Với CodeBlocks, bạn cĩ thể download phần mềm tại địa chỉ Đối với Eclipse, nĩ là một trình soạn thảo và biên dịch ngơn ngữ lập trình chuyên nghiệp nhất nhưng hồn tồn miễn phí (vì ta cĩ thể cấu hình kết hợp với các cơng cụ biên dịch được tích hợp). Bạn cĩ thể dùng nĩ để soạn thảo và biên dịch Java, PHP, JSP, Python v{ hiển nhiên là cả C/C++. Đ}y l{ một dự án mã nguồn mở, tiêu tốn hàng triệu đơla của IBM. Bạn cĩ thể tải về bản mới nhất cho đến thời điểm n{y (năm 2010) l{ Eclipse Helios tại địa chỉ: helios/R/eclipse-cpp-helios-win32.zip. Nhưng bạn cần tải thêm một dự án mở GCC để biên dịch các dự án của bạn. Tơi khuyên bạn nên sử dụng MinGW, nĩ cũng l{ một dự án mở. Bạn cĩ thể tải về tại địa chỉ: %20Installer/mingw-get-inst/mingw-get-inst-20100831/mingw-get- inst-20100831.exe. Với Eclipse, thì cơng việc cấu hình ban đầu tương đối phức tạp (nhưng bạn hồn tồn cĩ thể thực hiện trong 5 phút). Nếu bạn cấu hình thành cơng, bạn sẽ thấy quả thật khơng lãng phí thời gian của bạn chút nào. Bởi nĩ là một trình IDE (mơi trường phát triển tích hợp) C++ T r a n g | 8
  9. Đặng Ngọc Hoàng Thành quá chuyên nghiệp với một dự án mã nguồn mở. Nếu bạn cần sử dụng nĩ để lập trình ngơn ngữ gì, bạn chỉ việc tải thêm plugin hỗ trợ cho nĩ. Nhiều nhà phát triển đ~ sử dụng Eclipse làm nền tải cho việc phát triển các ứng dụng của mình: Embarcadero sử dụng nĩ để phát triển JBuider, Adobe sử dụng nĩ để phát triển Flash Buider và rất nhiều các hãng phần mềm nổi tiếng khác. Thêm một nguyên nhân nữa để tơi giới thiệu cho bạn trình IDE Eclipse tuyệt vời này – đĩ l{ rất nhiều hãng phần mềm trên thị trường hiện nay rất quan t}m đến nĩ. Nếu bạn là một lập trình viên Java, Eclipse là một sự lựa chọn khơng thể bỏ qua. Nếu bạn phát triển Flash theo dự án mã nguồn mở từ Adobe, Eclipse cũng l{ sự lựa chọn hồn hảo. Nếu bạn phát triển C/C++, với các trình soạn thảo thì Eclipse cũng l{ sự lựa chọn khá hồn. Nếu bạn sử dụng Eclipse để soạn thảo và biên dịch C/C++ (nhờ vào cơng cụ hỗ trợ MinGW), bạn sẽ cĩ nhiều kinh nghiệm sử dụng nĩ. Việc sử dụng thành thạo Eclipse sẽ là một lợi thế khi bạn tiến hành nghiên cứu Java, lập trình Web, Flex, Python sau này. Bên cạnh đĩ, chúng tơi cũng giới thiệu đến bạn mơi trường phát triển tích hợp IDE Microsoft Visual Studio 2010. Đ}y l{ trình biên dịch thương mại. Bạn cĩ thể sử dụng để phát triển các ứng dụng trên nền NET hoặc các ứng dụng Win32. Nếu bạn muốn phát triển các ứng dụng theo hướng của Microsoft, bạn nên sử dụng Visual Studio. Phiên bản mới nhất đến thời điểm này là VS 2010. Nhưng bạn lưu ý rằng, khi nghiên cứu Visual C++, bạn cần chọn lựa phiên bản dành cho Win32 chứ khơng phải là ứng dụng CLR (common language runtime) bởi nĩ được phát triển trên nền NET. Và Visual C++ for NET cĩ một số khác biệt so với Visual C++ for Win32 v{ nĩ cũng khơng hồn tồn tuân theo các chuẩn mực của ANSI C++. C++ T r a n g | 9
  10. Đặng Ngọc Hoàng Thành MƠI TRƯỜNG PHÁT TRIỂN TÍCH HỢP IDE 1. CodeBlocks Tơi sẽ hướng dẫn cho bạn cách sử dụng codeblocks để viết và biên dịch chương trình. Bạn cần lưu ý rằng, chương trình codeblocks làm việc theo từng dự |n, nghĩa l{ bạn cĩ thể biên dịch một chương trình C++ khi nĩ nằm trong một dự án của codeblocks. Đầu tiên bạn khởi động codeblocks, sau đĩ bạn vào File > New > Project. Trong hộp thoại hiện ra, bạn chọn console application (Hình 1). Và nhấp Go, sau đĩ nhấp Next. Trong hộp thoại tiếp theo, bạn chọn C++ và nhấp Next. Hình 1 – Tạo mới dự án trong CodeBlocks Hộp thoại yêu cầu bạn điền thơng tin về dự án sẽ xuất hiện. Bạn h~y điền tên dự án, vị trí lưu trữ dự |n. Sau đĩ nhấp Next. Cuối cùng nhấp Finish. Trong cửa sổ quản lý dự án, bạn nhấp đơi v{o tệp main.cpp, bạn hãy soạn thảo nội dung chương trình v{o trong tập tin này. Chạy chương trình: + Bạn hãy vào Build > Build and Run. C++ T r a n g | 10
  11. Đặng Ngọc Hoàng Thành + Hoặc nhấp phím F9. Tự động định dạng mã. Nếu bạn viết một chương trình C++ hay bất kì một chương trình trên một ngơn ngữ lập trình nào khác, bạn cần tuân thủ quy phạm định dạng mã nguồn. Cĩ nhiều chuẩn mực cho c|c định dạng mã nguồn này. Dù rằng, chúng khơng ảnh hưởng đến việc biên dịch chương trình, nhưng chúng giúp người đọc cĩ thể dễ hiểu chương trình của bạn hơn. Nếu bạn khơng nắm vững các quy phạm này, bạn cĩ thể sử dụng chức năng định dạng mã nguồn tự động của CodeBlocks. Để thực hiện điều này, bạn hãy kích chuột phải vào vùng soạn thảo, sau đĩ chọn Format this file (Astyle). Tự động khởi tạo phần thân các phương thức của lớp. Để hỗ trợ cho việc soạn thảo, CodeBlocks cũng hỗ trợ chức năng khởi tạo nhanh mã nguồn. Để khởi tạo nhanh phần khai b|o th}n phương thức của lớp từ khai báo prototype của nĩ, chúng ta đặt trỏ chuột vào sau khai báo lớp (tức vị trí sẽ chèn khai b|o th}n phương thức), sau đĩ, kích chuột phải, chọn Insert > All class methods without implementation. Trong hộp thoại hiện ra, bạn hãy chọn những phương thức mà bạn muốn khởi tạo phần th}n tương ứng, sau đĩ, nh}p Ok. Hình 2 – Khởi tạo th}n phương thức 2. Eclipse Helios C++ T r a n g | 11
  12. Đặng Ngọc Hoàng Thành Sau khi tải xong Eclipe Helios về máy, bạn tiến hành giải nén tập tin. Chương trình Eclipse khơng yêu cầu bạn phải tiến h{nh c{i đặt, nhưng nĩ cĩ thể làm việc nếu bạn đ~ c{i một máy ảo Java. Nếu bạn khơng cài máy ảo Java, bạn vẫn cĩ thể chạy nĩ nếu nĩ đ~ tích hợp sẵn máy ảo Java bên trong nĩ (nếu khơng, bạn hãy copy một thư mục jre đ~ được c{i đặt sẵn v{ đặt nĩ v{o trong thư mục eclipse). Nhưng lúc n{y, bạn cần đặt nĩ vào ổ đĩa C. Mỗi lần khởi động, bạn chọn tệp eclipsec.exe. Bạn chỉ chạy tệp eclipse.exe nếu máy bạn đ~ c{i đặt máy ảo Java. Bạn cĩ thể tải về máy ảo Java ở địa chỉ sau: Để xây dựng một chương trình C/C++ trên Eclipse, chúng ta cần: - Eclipse Helios for C/C++ (nếu bạn tải về một phiên bản dành cho Java, bạn cần phải c{i đặt thêm plugin hỗ trợ) hoặc một ấn bản cũ hơn (Galileo, Europa ). - Cơng cụ biên dịch GCC – MingW. - Máy ảo Java JVM. Các bước cấu hình trên Eclipse Helios Bước 1. C{i đặt máy ảo Java. Bước 2. Cài MinGW. Bước 3. Giải nén Eclipse Helios, sau đĩ khởi động nĩ (nhấp vào tập tin eclipse.exe). Thơng thường, Eclipse sẽ tự động cấu hình MinGW giúp bạn. Nếu khơng bạn hãy thực hiện bước 4. Bước 4. Vào menu Project > Properties. Trong hộp thoại xuất hiện, bạn chọn C/C++ Build > Settings. Hình 3 – Cấu hình MinGW trong Eclipse Helios Trong thẻ Tool Settings, bạn chọn GCC Assembler > General. Sau đĩ, bạn nhấp vào biểu tượng cĩ dấu cộng mầu xanh. Hộp thoại sau sẽ hiện ra: C++ T r a n g | 12
  13. Đặng Ngọc Hoàng Thành Hình 4 – Chọn đường dẫn đến thư mục bin của MinGW Bạn hãy nhập tên đường dẫn đến thư mục bin của MinGW (hoặc nhấp vào nút File system để duyệt đến thư mục này). Mặc định khi c{i đặt, thư mục này sẽ là C:\MinGW\bin. Sau đĩ nhấp Ok. Vậy là cơng việc cấu hình đ~ ho{n tất. Bắt tay xây dựng dự án đầu tiên trên Eclipse Cũng giống như CodeBlocks, Eclipse cũng tổ chức chương trình theo dự án. Để tạo mới một dự án trong Eclipse, chúng ta cĩ ba cách: - Vào File > New > C++ Project. - Vào biểu tượng tạo mới dự án trên thanh cơng cụ, chọn C++ Project. - Kích chuột phải vào cửa sổ Project Explorer > chọn New > C++ Project. Tiếp đến, hộp thoại sau đ}y sẽ xuất hiện. Trong hộp thoại này, nếu bạn chọn một dự án khả thi (executable) bạn hãy chọn executable. Bạn cũng cĩ thể chọn thư viện dll (static library) Tương ứng với dự án khả thi, bạn cĩ thể chọn Empty Project hoặc Hello World C++ Project. Đối với Empty Project, nĩ sẽ tạo cho bạn một dự án trống. Ngược lại với Hello World C++ Project, bạn sẽ nhận được một file cpp chứa nội dung mà chúng ta sẽ thảo luận trong chương tiếp theo. Hình 5 - Tạo mới dự án Sau đĩ, bạn nhập vào tên dự án và nhấp Next (nếu bạn chưa cấu hình MinGW), hoặc nhấp Finish (nếu bạn đ~ thực hiện cấu hình). C++ T r a n g | 13
  14. Đặng Ngọc Hoàng Thành Tạo mới một file nội dung trong Eclipse. Một chương trình trong C++ thường chia làm hai loại tệp: .cpp và .h. Tệp .cpp thường chứa nội dung chương trình, tệp .h thường chứa các khai báo. Lời khuyên trước khi tạo mới các file: bạn hãy tạo một thư mục chung để chứa tồn bộ nội dung sau này, tơi tạm gọi thư mục n{y l{ thư mục src. Trong thư mục src, bạn hãy tạo hai thư mục, một thư mục cpps và một thư mục headers. Thư mục cpps sẽ chứa tồn bộ tệp .cpp, thư mục headers sẽ chứa tồn bộ tệp .h. Tệp Main.cpp chứa hàm main sẽ được đặt trong thư mục src. Nghĩa l{ bạn sẽ cĩ cấu trúc tương tự như sau Hiển nhiên bạn hồn tồn khơng nhất src thiết phải thực hiện theo như cấu trúc thư mục n{y. Tuy nhiên điều này sẽ làm cho dự án của bạn trở nên sáng sủa hơn rất cpps nhiều. Bạn cĩ thể bổ sung thêm c|c thư mục phụ kh|c, nhưng bạn nên tuân thủ headers cấu trúc cây này (ví dụ bạn cần phân biệt các tập tin cpp thành nhiều loại khác nhau, thì trong thư mục cpps, bạn hãy tạo thêm Main.cpp c|c thư mục con kh|c ) Hình 6 - Cấu trúc thư mục của một dự án Biên dịch một dự án Để biên dịch một dự án, bạn nhấp vào biểu tượng sau đ}y trên thay cơng cụ của Eclipse. Hình 7 - Biên dịch một dự án Chọn Run As > Local C/C++ Application. Một số thủ thuật giúp soạn thảo nhanh C++ T r a n g | 14
  15. Đặng Ngọc Hoàng Thành Eclipse chứa đựng một tập các tiện ích giúp bạn soạn thảo nhanh hơn, ít lỗi hơn. Sau đ}y, tơi xin giới thiệu đến bạn một vài tính năng giúp bạn soạn thảo nhanh hơn gấp nhiều lần. Tạo mới một lớp Bạn vào New > Class. Hộp thoại sau đ}y sẽ hiện ra Hình 8 - Hộp thoại tạo mới class Trong hộp thoại này, bạn cần lưu ý: source folder – thư mục chứa tập tin sẽ tạo mới (thường sẽ được phân tách thành tệp .h và .cpp), namespace – phạm vi tác dụng của nĩ trong namespace được chỉ định, class name – tên của lớp sẽ tạo mới, base class – tên của lớp cha mà nĩ sẽ thừa kế (bấm vào nút add để chọn các lớp tồn tại), constructor và destructor – cho phép khởi tạo hàm tạo và hàm hủy. Những khái niệm này, bạn sẽ được tìm hiểu chi tiết hơn khi l{m quen với lập trình hướng đối tượng. Tạo nhanh các phương thức Getter và Setter Nếu bạn đ~ khai b|o một lớp, cùng với các thuộc tính của nĩ, khi đĩ, thay vì sử dụng hàm tạo để thiết lập giá trị ban đầu, ta cĩ thể dùng hàm setter; hoặc để tiếp nhận giá trị từ các thuộc tính, ta cĩ thể dùng các hàm getter. Tơi sẽ giới thiệu chi tiết hơn về c|c phương thức này trong phần lập trình hướng đối tượng. Trong phần này, tơi sẽ hướng dẫn cho bạn cách tạo chúng bằng thao tác nhấp chuột. Bạn vào Source, chọn Generate Getters and Setter. C++ T r a n g | 15
  16. Đặng Ngọc Hoàng Thành Trong hộp thoại hiện ra, bạn hãy chọn các thuộc tính mà bạn cần tạo phương thức getter v{ setter, sau đĩ nhấp Ok. Một số phím tắt khác Phím tắt Cơng dụng Ctrl+Space Bật chế độ gợi nhắc lệnh. main – Ctrl+Space Khởi tạo nhanh hàm main. Ctrl+Shift+F Định dạng nhanh mã nguồn. Ctrl+/ Comment vùng m~ đ~ được bơi đen, nếu vùng bơi đen đ~ ở chế độ comment, thì dấu comment sẽ bị hủy bỏ. Tab Dịch tồn bộ nội dung bị bơi đen sang phải một tab. Shift+Tab Dịch tồn bộ nội dung bị bơi đen sang tr|i một tab. Ctrl+1 Chỉnh sửa nhanh tồn bộ các từ giống với từ đang được bơi đen. Sau khi chỉnh sửa xong, bạn nhấp Enter để kết thúc. Ctrl+Shift+/ Tạo một khối comment cho vùng văn bản đ~ bị bơi đen. Ctrl+Shift+\ Hủy bỏ vùng văn bản bị comment bởi khối comment. Trên đ}y, tơi đ~ giới thiệu sơ qua hai chương trình soạn thảo miễn phí để lập trình C/C++: CodeBlocks và Eclipse. Với CodeBlocks, bạn chỉ cần tải và c{i đặt. Mơi trường hỗ trợ biên dịch GCC đ~ được tích hợp sẵn. Với Eclipse, bạn phải thực hiện cấu hình GCC. Nếu bạn là một người cĩ nhiều trải nghiệm về máy tính, bạn nên chọn Eclipse bởi nĩ l{ chương trình soạn thảo rất chuyên nghiệp. Nếu bạn l{ người mới tiếp xúc máy tính, bạn nên chọn CodeBlock vì khơng mất thời gian để cấu hình, nhưng nếu bạn cấu hình thành cơng trên Eclipse, thì bạn sẽ đỡ vất vả hơn nhiều khi học lập trình C++. Nĩ sẽ giúp ích cho bạn rất nhiều, giúp bạn tránh những lỗi sai sĩt khơng đ|ng cĩ. 3. Visual Studio 2010 dành cho Visual C++ Visual Studio 2010 là một mơi trường biên dịch tích hợp của Microsoft. Bạn cĩ thể sử dụng nĩ để biên dịch C++, C#, Visual Basic, J# Chúng ta sẽ tìm hiểu Visual Studio trong khía cạnh biên dịch C++. Bạn cũng cần lưu ý rằng, với phiên bản 2010 này, Visual Studio cĩ hai phiên bản dành cho C++: C++ C++ T r a n g | 16
  17. Đặng Ngọc Hoàng Thành for Net và C++ for Win32. Chúng ta tìm hiểu về tính năng C++ for Win32. Bạn cũng cần lưu ý rằng, MFC cũng l{ một thư viện xây dựng trên nền Win32. Trong nội dung của giáo trình này, ta sẽ tìm hiểu về ứng dụng Console trên nền Win32 mà khơng thảo luận thêm về Visual C++ for Net bởi lẽ nĩ thuộc một phạm trù tương đối khác so với Visual C++ for Win32. Khởi động Visual Studio 2010. Kích chọn biểu tượng VS 2010 trên nền Desktop. Vào Start > All Programs > Microsoft Visual Studio 2010, chọn biểu tượng VS 2010. Hình 9 - Giao diện tổng thể của Visual Studio 2010 Tạo mới dự án trong VS 2010. Vào File > New Project (hoặc tổ hợp phím tắt Ctrl+Shift+N). Trong hộp thoại xuất hiện, bạn hãy chọn Win32 Console Application. C++ T r a n g | 17
  18. Đặng Ngọc Hoàng Thành Hình 10 - Tạo dự án Win32 Console Mục name: hãy nhập tên dự án mà bạn muốn tạo. Mục Location: nhấp v{o nút Browse để chọn vị trí lưu trữ. Mặc định, Visual Studio sẽ lưu trữ dự án ở thư mục Documents. Mục Solution name: tạo một thư mục con trong thư mục dự án, hay tạo trực tiếp trong thư mục dự án. Trong hộp thoại xuất hiện, chọn Next. Hình 11 - Win32 Application Wizard C++ T r a n g | 18
  19. Đặng Ngọc Hoàng Thành Nhĩm Application Type + Windows application: tạo ứng dụng winform. + Console application: tạo ứng dụng chạy trên DOS. + Dll: tạo thư viện dll. + Static library: tạo thư viện tĩnh. Nhĩm Add common header file + Alt: tạo header từ lớp thư viện Alt. + MFC: tạo header từ lớp thư viện MFC. Nhĩm Additional options + Empty project: tạo dự án rỗng khơng cĩ tập tin. + Export symbols: xuất bản các biểu tượng. + Precompiled header: tạo tập tin tiêu đề tiền biên dịch. Chọn Console Application và chọn Empty Project. Sau đĩ, bạn hãy nhấp Finish. Tạo các tập tin trong dự án. Trong cửa sổ Solution Explorer, bạn hãy kích chuột phải và chọn Add: - Nếu tập tin đ~ tồn tại, hãy chọn Add Existing Items. Sau đĩ, bạn hãy duyệt đến vị trí tồn tại tập tin. - Nếu tập tin chưa tồn tại, hãy chọn Add New Items. Trong cửa sổ xuất hiện, tùy thuộc vào tập tin mà bạn cần, hãy chọn loại tương ứng. Thơng thường, trong dự án của C++, chúng ta thường sử dụng hai tập tin l{ tiêu đề .h và th}n chương trình .cpp. Sau đĩ, h~y nhập tên của tập tin và nhấp Ok. Tệp tin tiêu đề .h thường chứa các khai báo prototype của hàm hoặc lớp. Ngồi ra, nĩ cĩ thể chứa các hàm macro, các khai báo hằng và biến tồn cục được sử dụng trong tồn bộ chương trình. Tập tin .cpp thường chứa phần thân của các hàm hoặc lớp. Khi làm việc với các dự án trong C++, bạn nên tách chương trình th{nh nhiều phần và nên sử dụng các tệp tiêu đề để làm cho chương trình dễ hiểu hơn. C++ T r a n g | 19
  20. Đặng Ngọc Hoàng Thành Hình 12 - Bổ sung thêm một tập tin - Add Class: bổ sung các lớp đối tượng cho dự án. Ở đ}y, chúng ta chọn C++ class. Hình 13 - Bổ sung thêm lớp đối tượng Nhập Add. Cửa sổ sau đ}y sẽ xuất hiện C++ T r a n g | 20
  21. Đặng Ngọc Hoàng Thành Hình 14 - Tạo lớp bằng Class Wizard - Class name: tên của lớp. - .h file: tên của tiêu đề lớp cũng l{ tên của tập tin tiêu đề. - .cpp file: tên của tập tin .cpp tương ứng với lớp. - Base class: nếu lớp mới tạo ra thừa kế từ một lớp khác, bạn hãy nhập tên của lớp cơ sở v{o đ}y. - Access: mức thừa kế của lớp đang tạo từ lớp cơ sở. - Virtual destructor: tạo một phương thức hủy ảo. - Inline: tạo một phương thức inline. Tuy bạn cĩ thể sử dụng từ khĩa này, nhưng cơ chế làm việc của Visual C++ là tự động bổ sung inline khi biên dịch nếu phương thức được cho là phù hợp để sử dụng inline. Điều đĩ cĩ nghĩa l{ bạn khơng cần dùng đến từ khĩa này. Biên dịch dự án. - Để biên dịch và thực thi một dự án, bạn vào Debug > Start Debugging (hoặc Start without Debugging). - Để biên dịch tồn bộ dự án mà khơng thực thi dự án, bạn vào Build, chọn Build Solution. C++ T r a n g | 21
  22. Đặng Ngọc Hoàng Thành Một số phím tắt trong Visual Studio 2010. - Tạo vùng comment (chú thích): bơi đen vùng m~ cần tạo chú thích, nhấn tổ hợp Ctrl+K, Ctrl+C. - Hủy bỏ vùng comment: bơi đen vùng m~ đ~ comment, nhấn tổ hợp Ctrl+K, Ctrl+U. - Định dạng mã nguồn: bơi đen vùng m~ cần định dạng, nhấn tổ hợp Ctrl+K, Ctrl+F. - Tự động hồn tất mã và gợi nhắc lệnh: tổ hợp Ctrl+Space. Visual Studio 2010 khơng hỗ trợ c|c tính năng mạnh mẽ cho việc khởi tạo mã nguồn. Tuy nhiên, nếu bạn mong muốn làm việc đơn giản và hiệu quả hơn, bạn cĩ thể sử dụng tiện ích bổ trợ. Một trong những tiện ích làm việc khá hiệu quả là Visual Assist. Phiên bản cho đến thời điểm n{y (năm 2010) là 10.6. Xem biểu đồ lớp. Để quan sát biểu đồ lớp trong VS 2010, ta nhấp chuột phải vào tên dự án (trong cửa sổ Solution Explorer), chọn Show class diagram. Sau đĩ, bạn hãy kéo thả các lớp đối tượng vào vùng biểu đồ. Hình 15 - Xem biểu đồ lớp C++ T r a n g | 22
  23. Đặng Ngọc Hoàng Thành CHƯƠNG 1. CƠ BẢN VỀ C++ Cấu trúc của một chương trình C++ Một cách thức tốt nhất để học lập trình đĩ l{ h~y thử viết một chương trình đầu tiên. Nếu bạn đ~ từng làm quen với một ngơn ngữ lập trình nào đĩ, thì chắc hẳn bạn đ~ biết đến ví dụ kinh điển của một ngơn ngữ lập trình đĩ l{ chương trình “Hello, world !”. Mã chương trình Kết quả [1.] //my first program Hello, world ! [2.] #include [3.] using namespace std; [4.] int main() [5.] { [6.] cout . Nĩ chứa các hàm xuất nhập cơ bản. Hàm này là một phần của namespace std. [3.] Trong C++, các thành phần của thư viện chuẩn được khai báo trong namespace. Ở đ}y l{ namespace std. Để cĩ thể truy xuất đến các tính năng của nĩ, chúng ta mơ tả nĩ bằng từ khĩa using. Trong thư viện chuẩn của C++, đối tượng cout được tổ chức trong namespace std. [4.] Bất kì một chương trình C++ n{o cũng phải cĩ một h{m main để thực thi chương trình. Một hàm sẽ được khai báo theo cấu trúc như bạn đ~ thấy. Từ khĩa int mơ tả kiểu dữ liệu mà hàm trả về là integer. Bạn cũng lưu ý rằng, trong chương trình C thì bạn cĩ thể tùy ý khai báo là void hoặc int, C++ T r a n g | 23
  24. Đặng Ngọc Hoàng Thành nhưng trong C++ thì bắt buộc bạn phải khai báo là int. Vậy chắc hẳn bạn sẽ thắc mắc l{ int hay void thì cĩ nghĩa gì. Tơi khuyên bạn nên sử dụng int, dù l{ chương trình của bạn cĩ l{ C đi nữa. Sở dĩ, khi h{m main trả về kiểu int thì theo quy ước, nếu chương trình cĩ lỗi, nĩ sẽ trả về một mã int kh|c 0 v{ ngược lại, nếu chương trình khơng cĩ lỗi, nĩ sẽ trả về mã int 0. Bạn cũng lưu ý rằng, lỗi ở đ}y l{ lỗi chương trình liên quan đến quá trình biên dịch, chứ khơng phải là lỗi liên quan đến cú pháp. Bạn sẽ nhận thấy mã mà nĩ trả về trong dịng thơng báo cuối cùng khi biên dịch: process returned 0 (0x0). Tên hàm là main. Tiếp theo là cặp dấu ngoặc đơn dùng để chứa tham số đính kèm. Thơng thường một chương trình ứng dụng sẽ chứa hai tham số trong hàm main là int argc và char* args[]. Các tham số này gọi là tham số dịng lệnh. Tiếp theo là dấu {}. Bên trong cặp dấu n{y l{ chương trình chính. [5.] Dấu mở khối. [6.] Đối tượng cout (đọc là C-out) là chuẩn dùng để xuất dữ liệu ra màn hình. Bạn lưu ý, bạn vẫn cĩ thể dùng hàm printf. Nếu bạn dùng hàm printf thì bạn khơng cần khai b|o thư viện và namespace std ở trên. Nếu bạn sử dụng đối tượng cout, bạn cũng cĩ thể bỏ dịng lệnh [3.] nếu viết std::cout. Bạn cũng cần lưu ý rằng, khi sử dụng đối tượng cout, thì bạn cĩ thêm một cách thức để xuống dịng thay vì dùng \n, đĩ l{ endl. Đối tượng cout thường đi với tốn tử xuất <<. Bạn cĩ thể sử dùng nhiều tốn tử này khi muốn xuất nhiều phần tử riêng biệt: cout<<string1<<string2<< .<<endl. [7.] H{m return dùng để trả về giá trị của hàm. Nếu hàm cĩ kiểu dữ liệu trả về, thì cần return biến cĩ kiểu dữ liệu mà hàm trả về. Nếu hàm là void, thì khơng cần return. [8.] Dấu đĩng khối tương ứng với mở khối [5]. Mách nước: Cũng như C, C++ l{ ngơn ngữ phân biệt chữ hoa và chữ thường. Kết thúc một dịng lệnh trong C++ bao giờ cũng phải cĩ dấu ; Một dấu ngoặc đơn (), dấu ngoặc nhọn {} bao giờ cũng song h{nh. Điều đĩ cĩ nghĩa l{ nếu bạn dùng dấu mở thì phải cĩ dấu đĩng tương ứng. Dấu ngoặc đơn thường dùng sau tên hàm, và bên trong nĩ là tham số hình thức C++ T r a n g | 24
  25. Đặng Ngọc Hoàng Thành hoặc trong các lệnh cĩ cấu trúc. Dấu ngoặc nhọn thường dùng để quy định phạm vi của một khối lệnh (scope). Một cách thức giúp bạn chuyên nghiệp hơn khi lập trình, là sau dấu mở, bạn nên sử dụng tiếp dấu đĩng. Sau đĩ bạn hãy gõ nội dung cần thiết vào bên trong cặp dấu n{y. Điều đĩ sẽ giúp bạn tránh khỏi sự nhầm lẫn khi chương trình cĩ qu| nhiều dấu đĩng mở. Một cách thức nữa giúp bạn dễ nhận biết được phạm vi tác dụng của các khối lệnh đĩ l{ h~y sử dụng phím tab để tạo ra sự lồi lõm khi viết m~ chương trình. Như bạn thấy trong ví dụ, đối tượng cout và hàm return sẽ thụt vào một tab so với dấu khối lệnh tương ứng. Bạn đừng nên tiết kiệm sử dụng phím tab và phím enter. Nếu sử dụng hợp lí, chương trình của bạn cũng sẽ rất sáng sủa và dễ đọc. Bài tập 1. 1. Hãy viết chương trình in ra dịng chữ “Chao ban, ban co khoe khong”. 2. Hãy viết chương trình in ra hai dịng chữ trên hai dịng phân biệt “Vietnam” v{ “Hoa ky”. 3. Hãy viết chương trình in ra tam gi|c đều với c|c đỉnh là các dấu *. * * * C++ T r a n g | 25
  26. Đặng Ngọc Hoàng Thành CHƯƠNG 2. BIẾN VÀ CÁC KIỂU DỮ LIỆU Tương ứng với chương trình “Hello world”, chúng ta cần thảo luận một vài chi tiết. Chúng ta cĩ một vài dịng lệnh, biên dịch chúng v{ sau đĩ chạy chương trình để thu kết quả. Dĩ nhiên ta cĩ thể l{m nhanh hơn, tuy nhiên việc lập trình khơng chỉ đơn thuần l{ in ra c|c dịng thơng b|o đơn giản lên màn hình. Để đi xa hơn, chúng ta sẽ viết một chương trình thực thi một tác vụ hữu ích là giúp chúng ta tìm hiểu về khái niệm biến. Giả sử bạn cĩ hai giá trị 5 và 2. Bạn cần lưu hai gi| trị này vào bộ nhớ. Bây giờ, nếu tơi muốn cộng thêm 1 vào số thứ nhất v{ lưu lại giá trị này cho nĩ, tiếp theo tơi muốn lấy hiệu của số thứ nhất sau khi thay đổi với số thứ hai. Tiến trình xử lý cơng việc trên cĩ thể được viết trên C++ như sau: Chương trình int a = 5; int b = 2; a = a + 1; // a=6 int result = a – b; //result = 4 Như vậy, chắc hẳn bạn đ~ cĩ thể hiểu biến được sử dụng để làm gì. Biến được dùng để lưu giá trị và nĩ cĩ thể thay đổi được. Một biến sẽ được quy định bởi một kiểu dữ liệu nào đĩ. Trong trường hợp ví dụ của chúng ta, biến cĩ kiểu dữ liệu là int. Kiểu dữ liệu thường cĩ hai loại: kiểu dữ liệu nguyên thủy (primitive data type) và kiểu dữ liệu tham chiếu (reference data type). Chúng ta sẽ thảo luận chi tiết về chúng trong phần tiếp theo. Nhưng bạn cĩ thể hiểu rằng, một kiểu dữ liệu đơn giản và cĩ cấu trúc trong C là kiểu dữ liệu nguyên thủy. Kiểu dữ liệu tham chiếu bạn sẽ được làm quen khi học về tính hướng đối tượng trong C++. Từ khĩa Từ khĩa trong C++ cĩ thể cĩ một hoặc nhiều từ. Nếu từ khĩa cĩ nhiều từ, thì giữa các từ cĩ dấu gạch chân (_). Kí tự trắng và các kí tự đặc biệt khơng được phép sử dụng trong từ khĩa, tên hàm, tên biến. Tên của chúng khơng được bắt đầu bằng kí tự số. C++ T r a n g | 26
  27. Đặng Ngọc Hoàng Thành Bảng từ khĩa chuẩn trong C++ asm, auto, bool, break, case, catch, char, class, const, const_cast, continue, default, delete, do, double, dynamic_cast, else, enum, explicit, export, extern, false, float, for, friend, goto, if, inline, int ,long, mutable, namespace, new, operator, private, protected, public, register, reinterpret_cast, return, short, signed, sizeof, static, static_cast, struct, switch, template, this, throw, true, try, typedef, typeid, typename, union, unsigned, using, virtual, void, volatile, wchar_t, while Bảng từ khĩa bổ sung trong C++ and, and_eq, bitand, bitor, compl, not, not_eq, or, or_eq, xor, xor_eq Kiểu dữ liệu nguyên thủy Khi lập trình, chúng ta lưu c|c biến trong bộ nhớ m|y tính, nhưng máy tính cần phải biết loại dữ liệu mà chúng ta muốn lưu chúng, khi đĩ chúng sẽ được cung cấp một số lượng ơ nhớ cần thiết để lưu dữ liệu. Trong máy tính, bộ nhớ được tổ chức theo các byte. Một byte là một đơn vị đo lường tối thiểu mà chúng ta cĩ thể quản lý trong C++. Một byte cĩ thể lưu một biến char. Thêm v{o đĩ, m|y tính cũng quản lý những kiểu dữ liệu phức tạp hơn. Bảng sau đ}y liệt kê các kiểu dữ liệu v{ kích thước tương ứng. Tên Mơ tả Kích thước Vùng giá trị char Kí tự hoặc số nguyên bé 1 byte signed: -128 ->127 unsigned: 0 -> 255 short Số nguyên ngắn 2 byte signed: -215 -> 215-1 unsigned: 0 -> 216-1 int Số nguyên 4 byte signed: -231 -> 231-1 unsigned: 0 -> 232-1 long Số nguyên dài 4 byte signed: -231 -> 231-1 unsigned: 0 -> 232-1 long long Số nguyên cực dài 8 byte signed: -263 -> 263-1 unsigned: 0 -> 264-1 bool Giá trị logic – true/false 1 byte true và false float Số thập phân 4 byte 7 số thập phân double Số thập phân chấm động 8 byte 15 số thập phân long Số thập phân chấm động 8 byte 15 số thập phân C++ T r a n g | 27
  28. Đặng Ngọc Hoàng Thành double dài wchar_t Kí tự dài 2/4 byte Kích thước trong bộ nhớ và miền giá trị của các kiểu dữ liệu cịn phụ thuộc vào hệ thống v{ chương trình dịch tương ứng. Giá trị được đưa ra ở đ}y l{ trên hệ thống Windows 32 bit và trình dịch GCC MinGW. Nhưng đối với hệ thống khác, các giá trị này cĩ thể thay đổi (ví dụ kiểu int và long trên Windows 32 bit v{ 64 bit l{ 4 byte, nhưng trên Linux 32 bit l{ 4 byte v{ trên Linux 64 bit là 8 byte). Khai báo biến Như ví dụ trên, ta thấy rằng, muốn sử dụng một biến trong C++, ta cần khai báo biến với kiểu dữ liệu mà ta mong muốn. Cấu trúc khai báo ; Ví dụ int a; //Khai báo biến a kiểu nguyên float mynumber; //Khai báo biến mynumber kiểu float bool istrue; //Khai báo biến istrue kiểu bool long num1, num2, num3; //Khai báo ba biến num1, num2, num3 cùng kiểu long Nếu khi khai báo biến thuộc các kiểu nguyên mà ta khơng sử dụng khai báo cĩ dấu (signed) hoặc khơng dấu (unsigned), thì chương trình dịch mặc định sẽ quy định là kiểu nguyên khơng dấu. Khai báo biến nguyên int mynum; //tương đương unsigned int mynum; Chú ý: Đối với kiểu char thì cĩ ngoại lệ. Bạn nên khai b|o tường minh là signed char hoặc unsigned char. C++ T r a n g | 28
  29. Đặng Ngọc Hoàng Thành Đối với signed int và unsigned int cĩ thể viết đơn giản là signed hoặc unsigned. Mách nước: Nếu bạn muốn chắc chắn về kích thước của kiểu dữ liệu mà bạn cần sử dụng, bạn cĩ thể sử dụng h{m sizeof để x|c định kích thước bộ nhớ của kiểu dữ liệu. Hàm sizeof(tên biến) hoặc sizeof(kiểu dữ liệu). Hàm trả về kiểu dữ liệu nguyên. Chương trình Kết quả #include 4 (trên windows 32 bit) using namespace std; int main() { int a; cout [2.] using namespace std; C++ T r a n g | 29
  30. Đặng Ngọc Hoàng Thành [3.] int a; [4.] char c; [5.] unsigned int d; [6.] int main() [7.] {//Khối lệnh 1 [8.] signed long m; [9.] float n; [10.] {//Khối lệnh 2 [11.] double x; [12.] x = 1; [13.] cout<<x; [14.] } [15.] } Giải thích: Các biến khai báo ở c|c dịng [3.], [4.] v{ [5.] được khai báo ngồi mọi khối lệnh, nĩ cĩ tác dụng trong tồn bộ chương trình v{ nĩ được gọi là biến tồn cục (global variable). Các biến được khai báo trong khối lệnh 1 (tương ứng [8.] và [9.]) và khối lệnh 2 (tương ứng [11.] và [12.]) gọi là biến cục bộ (local variable), nĩ cĩ tác dụng trong khối lệnh trực tiếp chứa nĩ. Cĩ nghĩa là biến x chỉ cĩ tác dụng trong khối lệnh 2; biến m, n cĩ tác dụng trong khối lệnh 1. Các biến tồn cục cĩ thể được sử dụng trong tồn bộ chương trình, nĩ cĩ thể được gọi trong các hàm, trong hàm chính main. Cịn biến cục bộ được khai báo trong khối lệnh nào, thì nĩ chỉ cĩ thể được sử dụng trong khối lệnh đĩ m{ thơi. Thỉnh thoảng, biến cĩ thể được khai báo trong dấu ngoặc đơn (bạn cĩ thể gặp tình huống này khi nghiên cứu các lệnh cĩ cấu trúc), thì biến này cũng gọi là biến cục bộ (for (int a = 0; i<10; i++){ nhập nội dung .}). Lúc này, biến sẽ cĩ tác dụng trong khối lệnh tương ứng (khối lệnh nằm trong vịng lặp for). C++ T r a n g | 30
  31. Đặng Ngọc Hoàng Thành Khởi tạo giá trị cho biến Khi một biến cục bộ được khởi tạo, giá trị mặc định của nĩ sẽ khơng được tạo ra. Vì vậy, muốn sử dụng được biến, bạn cần phải khởi tạo giá trị cho biến. Cĩ hai c|ch để khởi tạo giá trị của biến trong C++. Cú pháp Ví dụ type tên_biến = giá_trị_khởi_tạo; int a = 0; type tên_biến (giá_trị_khởi_tạo); int a (0); Bây giờ, bạn cĩ thể viết lại đoạn chương trình tính to|n gi| trị của các biến ở trên, bằng cách sử dụng giá trị khởi tạo mặc định này. Khởi tạo theo cách 1 Khởi tạo theo cách 2 #include #include using namespace std; using namespace std; int main() int main() { { int a = 5; int a (5); int b = 2; int b (2); a = a + 1; // a=6 a = a + 1; // a=6 int result = a – b; //result = 4 int result (a – b); //result = 4 cout<<result<<endl; cout<<result<<endl; result 0; result 0; } } Bài tập 2. 1. Bạn hãy viết một chương trình tương đương, sử dụng cả hai kiểu khởi tạo trên. 2. Bạn hãy chọn một cách khởi tạo tùy ý, hãy viết chương trình tính gi| trị của biểu thức delta = b*b-4*a*c, với a, b, c lần lượt nhận các giá trị 1, 5, 3. C++ T r a n g | 31
  32. Đặng Ngọc Hoàng Thành Khởi tạo giá trị cho biến tĩnh static Một biến được khai báo bằng từ khĩa static thì nĩ chỉ khởi tạo giá trị đúng một lần khi biến được tạo ra. Thơng thường những biến n{y được đặt vào trong một tệp tiêu đề .h để sử dụng cho tồn bộ chương trình. Ví dụ sau đ}y minh họa cho giá trị của biến static sẽ khơng khởi tạo lần thứ hai trong vịng lặp. Chương trình Kết quả #include 3 4 using namespace std; 5 6 int main() 7 { for (int i=0; i<5; i++) { static int x = 2; x++; cout<<x<<endl; } } Giải thích: biến x được khởi tạo trong vịng lặp for, nếu khơng cĩ từ khĩa static, thì trong mỗi lần lặp, biến này sẽ được khởi tạo lại và giá trị in ra sẽ luơn l{ 2. Tuy nhiên, trong trường hợp này, ta sử dụng từ khĩa static, do đĩ, giá trị của biến x chỉ được khởi tạo một lần duy nhất. Trong những lần lặp tiếp theo, giá trị của x vẫn được lưu lại. Kết quả ta nhận được như trên. Giới thiệu về xâu kí tự Một biến cĩ thể dùng để lưu một loại dữ liệu khơng phải số, nhưng nĩ lại chứa nhiều kí tự (khơng như kiểu char) mà chúng ta sẽ gọi nĩ là kiểu xâu kí tự. Trong thư viện ngơn ngữ lập trình C++, nĩ cung cấp cho chúng ta kiểu xâu nằm trong lớp string. Bạn cần lưu ý rằng, để biểu diễn một biến thuộc kiểu xâu, chúng ta cĩ thể sử dụng khai báo mảng kí tự, hoặc con trỏ kí tự như trong ngơn ngữ C, khi đĩ, c|c biến này thuộc kiểu dữ liệu nguyên thủy, nếu bạn muốn sử dụng khai báo string thì bạn đang sử dụng kiểu dữ liệu C++ T r a n g | 32
  33. Đặng Ngọc Hoàng Thành tham chiếu. Khi sử dụng kiểu khai báo tham chiếu của lớp string, bạn cần cĩ khai báo tệp tiêu đề là string. Khai báo nguyên thủy Khai báo tham chiếu #include #include using namespace std; #include int main() using namespace std; { int main() char a[] = “abc”; { char* b = “abc”; string a = “abc”; return 0; return 0; } } Bạn cũng lưu ý rằng, dù là một biến thuộc kiểu dữ liệu tham chiếu string, thì bạn vẫn cĩ thể sử dụng hai kiểu khởi tạo như trên. Điều này chỉ cĩ thể áp dụng cho kiểu string mà thơi. Các kiểu dữ liệu tham chiếu khác khơng thể sử dụng hai cách khởi tạo này. Để biết thêm thơng tin về kiểu string, bạn nên tham khảo thêm thơng tin về lớp string. C++ T r a n g | 33
  34. Đặng Ngọc Hoàng Thành CHƯƠNG 3. HẰNG Hằng: là một phần tử cĩ giá trị cố định. Giá trị của nĩ được khởi tạo ngay khi hằng được tạo ra. Thơng thường, người ta cũng sử dụng các chữ c|i để đặt tên cho hằng. Tên hằng khơng chứa các kí tự đặt biệt, kí tự trắng hay bắt đầu bằng số. Trong C++, tên hằng thường được viết hoa tồn bộ. Hằng thường được chia ra làm: hằng số nguyên, hằng số thực, hằng kí tự, hằng xâu và hằng logic. Hằng số nguyên Hằng số nguyên là các hằng cĩ giá trị là số nguyên. Hằng số nguyên cĩ thể được biểu diễn dưới dạng thập phân, bát phân, hoặc thập lục phân. Nếu hằng số nguyên dưới dạng thập phân thì cĩ giá trị như số thập ph}n bình thường. Nếu là hằng số nguyên bát phân, thì nĩ bắt đầu bằng số 0 (ví dụ 011). Nếu là hằng số nguyên thập lục phân, thì nĩ bắt đầu bằng 0x (ví dụ 0x1b). Quy tắc chuyển đổi số qua lại giữa các hệ, bạn đ~ nghiên cứu trong học phần “Nhập mơn tin học”. Nếu hằng số là số nguyên cĩ dấu hoặc khơng dấu. Bạn cĩ thể cĩ một v{i c|ch khai b|o tương ứng. Hằng nguyên cĩ dấu và khơng dấu 75 //int 75u //unsigned int 75l //long 75ul //unsigned long Các tiền tố và hậu tố trong hai cách sử dụng ở trên cĩ thể viết thường hoặc viết hoa (0x12 hay 0X12 l{ như nhau; hoặc 75ul hay 75UL l{ như nhau). Hằng số thực cĩ dấu chấm động Chúng ta khảo sát số thực dưới dạng số thập phân dấu chấm động hoặc dưới dạng khoa học (hay cịn gọi là dạng lũy thừa dạng E – tương ứng với lũy thừa 10). Ví dụ 314.159e-2 tương ứng với 3.14159 hay 6.02e23 tương ứng với 6.02*1023 C++ T r a n g | 34
  35. Đặng Ngọc Hoàng Thành Một hằng số thực mặc định là double. Nếu bạn muốn chỉ định kiểu dữ liệu cho nĩ, bạn cĩ thể sử dụng cú ph|p tương tự như đối với hằng số nguyên (3.1415L tương ứng long double, 3.1415F tương ứng với float). Các kí tự e, f, l cĩ thể biểu diễn dưới dạng chữ hoa hoặc chữ thường. Hằng kí tự và hằng xâu kí tự Hằng kí tự được sử dụng trong dấu nh|y đơn, cịn hằng xâu kí tự được sử dụng trong dấu nháy kép. x Tên biến ‘x’ Kí tự x “x” Xâu kí tự x Trong hằng xâu kí tự, cĩ thể chứa các kí tự đặc biệt như kí tự xuống dịng, đặt tab Sau đ}y l{ một vài kí tự đặc biệt đĩ v{ ý nghĩa của chúng. Kí hiệu Ý nghĩa \n Xuống dịng \r Di chuyển tồn bộ kí tự sau dấu \r đè lên c|c kí tự trước đĩ. Nếu số kí tự sau nhiều hơn số kí tự trước dấu \r, thì kết quả in ra sẽ là tồn bộ kí tự nằm sau. Ví dụ “abc\r1234” -> sẽ in ra 1234, nếu “abc\r12” -> sẽ in ra 12c. \t Đặt tab \v Đặt tab dọc \b Đặt backspace \f Đặt dấu form feed \a Tạo âm thanh beep \’, \”, \?, Tạo các kí tự ‘, “, ?, \ \\ Một hằng xâu kí tự cĩ thể chứa nội dung trên nhiều dịng. Khi đĩ, để viết nội dung ở dịng mới, thì cuối dịng trước đĩ, bạn bổ sung thêm kí tự \. Các xâu kí tự cĩ thể được ghép với nhau nhờ vào kí tự trắng. Ví dụ “Hom nay toi di hoc\ Xâu kí tự viết trên nhiều dịng Ngay mai toi o nha” “Toi “ “yeu “ “lap trinh” Xâu kí tự ghép C++ T r a n g | 35
  36. Đặng Ngọc Hoàng Thành Khi sử dụng hằng xâu kí tự với kiểu dữ liệu là wchar_t, bạn cần thêm tiền tố L bên trước xâu kí tự đĩ. Ví dụ L”Xau ki tu wchar_t”. Các quy tắc ở trên cĩ thể áp dụng cho bất kì hằng xâu kí tự thuộc kiểu dữ liệu nào (char*, wchar_t*, string hoặc mảng kí tự tương ứng). Hằng logic Hằng logic cĩ hai giá trị là true (đúng) và false (sai). Một biểu thức logic sẽ cĩ kiểu dữ liệu là bool. Nĩ chỉ cĩ thể nhận một trong hai giá trị true và false. Trong C bạn chỉ cĩ thể sử dụng kiểu số nguyên (short, int, long ) để quy định giá trị của biểu thức logic: nếu giá trị nhận được là 0 – tương ứng với giá trị sai; ngược lại, nếu giá trị nhận được là khác 0 – tương ứng với giá trị đúng. C|ch quy định này vẫn cịn hoạt động tốt trên C++. Tuy nhiên, trong C++, người ta đ~ định nghĩa hai hằng số true và false và kiểu dữ liệu bool. Hằng số true tương ứng với giá trị 1 và hằng số false tương ứng với giá trị 0. Bạn cĩ thể sử dụng giá trị true (hay 1) và false (hay 0). Định nghĩa một hằng #define Bạn cĩ thể định nghĩa một tên gọi cho hằng để cĩ thể sử dụng nĩ thường xuyên mà khơng cần phải sắp xếp lại các biến chi phối bộ nhớ. Khi đĩ, bạn chỉ cần sử dụng từ khĩa define. Cú pháp Ví dụ #define PI 3.14 #define tên_hằng giá_trị #define NewLine ‘\n’ Trong ví dụ trên, tơi đ~ định nghĩa hai hằng PI và Newline. Trong chương trình, tơi chỉ cần gọi nĩ để sử dụng, mà khơng cần sử dụng đến giá trị cụ thể của nĩ. Chương trình tính diện tích hình trịn Kết quả #include 3.14 using namespace std; #define PI 3.14 int main() C++ T r a n g | 36
  37. Đặng Ngọc Hoàng Thành { double r = 1; double s; s = PI*r*r; cout<<s; return 0; } Thực chất, #define khơng phải là một câu lệnh trong C++, nĩ chỉ là một định hướng tiền xử lý (directive for the preprocessor). Cho nên, bạn lưu ý rằng, kết thúc phần khai báo này, khơng cĩ dấu chấm phẩy (;). Khai báo hằng const Bạn cĩ thể khai báo một hằng bằng cách sử dụng từ khĩa const. Cấu trúc khai b|o như sau: Cú pháp Ví dụ const int a = 10; const kiểu_dữ_liệu tên_hằng = giá_trị; const char x = ‘\t’; Các bạn cĩ thể thấy c|ch khai b|o tương tự như khai b|o biến, chỉ khác một điểm là bạn bổ sung từ khĩa const v{o trước. Hằng và biến cũng tương tự nhau. Chúng chỉ khác nhau một điểm duy nhất là giá trị của hằng khơng thể thay đổi, cịn biến thì cĩ thể. C++ T r a n g | 37
  38. Đặng Ngọc Hoàng Thành CHƯƠNG 4. TỐN TỬ Chúng ta đ~ l{m quen với biến và hằng, bây giờ chúng ta cĩ thể tính tốn giá trị của chúng. Các phép tốn thực thi trên các biến hoặc hằng gọi là các tốn tử. V{ khi đĩ, c|c biến hoặc hằng đĩ gọi là các tốn hạng. Tốn tử gán Tốn tử g|n dùng để gán giá trị cho một biến. Ví dụ a = 5; Câu lệnh gán sẽ thực hiện gán giá trị ở bên phải cho biến ở bên trái. Bạn cũng cĩ thể gán giá trị của hai biến cho nhau. Ví dụ a = b; Sau đ}y, bạn hãy quan sát và suy ngẫm đoạn chương trình sau Chương trình [1.] #include [2.] using namespace std; [3.] int main() [4.] { [5.] int a, b; [6.] a = 10; [7.] b = 4; [8.] a = b; [9.] b = 7; [10.] cout<<”a=”<<a<<”, b=”<<b<<endl; [11.] return 0; [12.] } Giải thích: Dịng lệnh [5.] khai báo hai biến nguyên a, b. Khi đĩ gi| trị của chúng chưa được khởi tạo. Dịng lệnh [6.] khởi tạo giá trị cho biến a là 10, biến b chưa được khở tạo. Dịng lệnh [7.] khởi tạo giá trị cho biến b là 4, biến a vẫn khơng thay đổi (10). Dịng lệnh [8.] thực hiện việc gán giá trị của biến b cho biến a, khi đĩ b vẫn khơng thay đổi; a nhận giá trị của b, tức là 4. Dịng lệnh C++ T r a n g | 38
  39. Đặng Ngọc Hoàng Thành [9.] gán giá trị của biến b là 7, biến a khơng thay đổi. Do đĩ, gi| trị cuối cùng của a là 4, b là 7. Output của chương trình sẽ là a=4, b=7. Bạn cần luơn chú ý rằng, tốn tử gán thực hiện theo nguyên tắc phải- sang-tr|i. Nghĩa l{ luơn lấy giá trị ở vế phải để gán cho vế tr|i. Khi đĩ, gi| trị của biến ở vế tr|i thay đổi, cịn ở vế phải khơng thay đổi. Tốn tử gán cĩ thể thực hiện trong các biểu thức phức tạp hơn. a = b + 2; Giá trị của a bằng giá trị của b cộng thêm 2 a = a + 1; Tăng gi| trị của a lên 1 a = b = c = 5; G|n đồng thời nhiều giá trị. Nĩ tương ứng với tập các lệnh sau: c = 5; b = c; a = b; Tốn tử thực hiện phép tốn số học Ngơn ngữ lập trình C++ hỗ trợ các tốn tử sau Tốn tử Ý nghĩa + Phép cộng - Phép trừ * Phép nhân / Phép chia (chia nguyên đối với số nguyên) % Chia lấy dư (chỉ với số nguyên) Bạn lưu ý rằng, phép chia cĩ thể thực hiện trên số nguyên hoặc số thực. Nếu thực hiện phép chia trên hai số nguyên thì đ}y chính l{ kết quả của phép chia lấy phần nguyên. Cịn nếu nĩ thực hiện trên hai số thực, thì nĩ là kết quả của phép chia bình thường. Như vậy, theo mặc định, hai số nguyên (hoặc thực) thực hiện phép to|n tương ứng thì nĩ sẽ trả về kết quả nguyên (hoặc thực). Nếu phép tốn thực hiện trên một số nguyên và một số thực, nĩ sẽ tự động chuyển đổi về kiểu cao hơn (th{nh số thực). Vậy làm thế n{o để thực hiện phép chia 3 cho 2, nếu ta muốn nhận được kết quả là 1.5. Ta biết rằng 3 và 2 là hai số nguyên, nếu ta thực hiện phép chia 3/2 thì ta thu được số nguyên – là kết quả của phép chia nguyên 3/2, tức là 1. Muốn thu được kết quả 1.5, bạn cần chuyển đổi 3 và 2 về dạng số thực bằng một trong các cách sau: C++ T r a n g | 39
  40. Đặng Ngọc Hoàng Thành Khai báo 3 và 2 là các số thực (bằng c|ch quy định kiểu dữ liệu như float a = 3, float b = 2 hoặc 3.0, 2.0). Chuyển đổi kiểu dữ liệu (Xem thêm phần tốn tử chuyển đổi kiểu dữ liệu). Tốn tử gán hợp nhất Khi muốn thay đổi giá trị của một biến, chúng ta cĩ thể sử dụng cách viết thơng thường, nhưng trong C++ nĩ hỗ trợ các tốn tử viết tắt. Tốn tử Ví dụ Ý nghĩa Phạm vi += a+=b a=a+b Phép tốn số học -= a-=b a=a-b Phép tốn số học *= a*=b a=a*b Phép tốn số học /= a/=b a=a/b Phép tốn số học %= a%=b a=a%b Phép tốn số học &= a&=b a=a&b Phép tốn bit |= a|=b a=a|b Phép tốn bit ^= a^=b a=a^b Phép tốn bit >>= a>>=b a=a>>b Phép tốn bit <<= a<<=b a=a<<b Phép tốn bit Tốn tử tăng và giảm Một cách viết thu gọn hơn nữa, đĩ l{ sử dụng tốn tử tăng v{ giảm. Nếu trong biểu thức a+=b, với b = 1 thì ta cĩ thể viết th{nh a++. Tương tự, nếu a-=b, b = 1 thì ta cĩ thể viết a . Chúng ta cũng lưu ý rằng, tốn tử này cĩ chút khác biệt. Nĩ cĩ thể nằm trước hoặc nằm sau tốn hạng. Cĩ nghĩa l{ cĩ thể cĩ a++ hoặc ++a (tương ứng a hoặc a). Phép tốn Ý nghĩa a++; Thực hiện phép to|n trước, sau đĩ mới thực hiện tốn tử ++a; Thực hiện tốn tử trước, sau đĩ mới thực hiện phép tốn a ; Tương tự a++; a; Tương tự ++a; Ví dụ Cách thực thi int a = 1; a = 1, b chưa khởi tạo C++ T r a n g | 40
  41. Đặng Ngọc Hoàng Thành int b = 1; a = 1, b = 1 a+=b++; Thực hiện phép to|n a+=b trước, sau đĩ mới thực hiện phép tốn b++. Tức là a=2, b=2. Thực hiện phép to|n ++b trước, a+=++b; sau đĩ mới thực hiện phép tốn a+=b. Tức là b=2, a=3. Tốn tử so sánh Để thực hiện việc so sánh giá trị của hai biến, biểu thức; ta cĩ thể sử dụng tốn tử so sánh. Giá trị của phép tốn so sánh trả về kiểu bool. Tốn tử Tên gọi Giá trị biểu thức a Tốn tử b Đúng Sai == Bằng Nếu a bằng b Nếu a khác b != Khác Nếu a khác b Nếu a bằng b > Lớn hơn Nếu a lớn hơn b Nếu a nhỏ hơn hoặc bằng b = Lớn hơn hoặc Nếu a lớn hơn hoặc Nếu a nhỏ hơn b bằng bằng b Kết quả 1: 1 using namespace std; Kết quả 2: 0 int main() Kết quả 3: 1 { int a = 1; C++ T r a n g | 41
  42. Đặng Ngọc Hoàng Thành int b =2; cout =b); cout Kết quả 1: 1 using namespace std; Kết quả 2: 0 C++ T r a n g | 42
  43. Đặng Ngọc Hoàng Thành int main() Kết quả 3: 0 { int a = true; int b =false; cout Max là: 2 using namespace std; int main() { int a = 1; int b = 2; int max = (a>b)?a:b; C++ T r a n g | 43
  44. Đặng Ngọc Hoàng Thành cout b, vì a=1, b=2, nên giá trị của nĩ là false. Chính vì vậy, biểu thức điều kiện sẽ nhận kết quả tương ứng với kết quả 2, tức là b. Tốn tử điều kiện luơn trả về một giá trị cụ thể. Như trong ví dụ trên, ta thấy nếu biểu thức a>b đúng, thì gi| trị max nhận được là số a; ngược lại là số b. Tuy nhiên, khơng nhất thiết cần phải cĩ một giá trị x|c định cho tốn tử điều kiện. Ví dụ sau đ}y sẽ minh họa điều này Chương trình Kết quả #include 2 lon hon using namespace std; int main() { int a = 1; int b = 2; (a>b)?(cout b đúng, nĩ sẽ in ra câu a lớn hơn, ngược lại nĩ sẽ in ra câu b lớn hơn. Bạn cũng cần lưu ý rằng, khi các câu lệnh nằm trong cặp dấu ngoặc của tốn tử điều kiện, thì kết thúc câu lệnh khơng bao giờ cĩ dấu chấm phẩy (;). Nếu bạn muốn sử dụng một tập các câu lệnh trong cặp dấu ngoặc này, bạn cĩ thể sử dụng tốn tử phân tách mà tơi đề cập bên dưới. Ví dụ sau đ}y sẽ cho thấy việc sử dụng tập các câu lệnh bên trong cặp dấu ngoặc của tốn tử điều kiện. Chương trình Kết quả #include |a-b|=1 using namespace std; int main() { int a = 1; int b = 2; C++ T r a n g | 44
  45. Đặng Ngọc Hoàng Thành int c; (a>b)?(c = a-b,cout b, thì giá trị tuyệt đối |a-b| = a-b; ngược lại nếu a<b, thì giá trị tuyệt đối |a-b| = b-a. Trong cặp dấu ngoặc đơn của tốn tử điều kiện, câu lệnh gán c=a-b (hoặc c=b-a) v{ cout được phân tách bằng dấu phẩy (,). Một điều mà bạn cần lưu ý rằng, bạn khơng được phép khai báo biến trong cặp dấu ngoặc đơn n{y. Việc khai báo biến trong dấu ngoặc đơn, chỉ áp dụng duy nhất cho câu lệnh lặp for. Tốn tử phân tách Tốn tử này kí hiệu là dấu phẩy. Nĩ dùng để phân tách hai hay nhiều biểu thức chứa trong một biểu thức phức hợp tương ứng. Ví dụ Kết quả 3 int a; int b; int c; c = (a=1, b=2, a+b); cout<<c; Giải thích: trong biểu thức phức hợp, bên trong dấu ngoặc đơn l{ c|c biểu thức đơn được phân tách bằng tốn tử phân tách. Trong một dãy các tốn tử phân tách, nĩ sẽ ưu tiên thực hiện từ trái sang phải (xem thêm phần độ ưu tiên của tốn tử được trình bày trong mục sau của chương n{y), nghĩa l{ a=1, sau đĩ b=2 và cuối cùng là c=a+b=1+2=3. Tốn tử dịch bit Các tốn tử n{y được sử dụng đến tính tốn trên các số nguyên bằng cách tính tốn trên các bit. Tốn tử Kết quả Tốn tử phủ định bit. Các bit 1 sẽ chuyển th{nh 0 v{ ngược lại. ~ Ví dụ ~101=010. & Tốn tử hội bit. Hội của hai bit 1 bằng 1. Trong mọi trường hợp cịn C++ T r a n g | 45
  46. Đặng Ngọc Hoàng Thành lại, ta nhận được 0. Ví dụ. 1 0 1 1 (tương ứng 11 trong hệ thập phân) & 0 1 0 1 (tương ứng với 5 trong hệ thập phân) 0 0 0 1 (tương ứng với 1 trong hệ thập phân) Nghĩa l{ 11&5=1. Tốn tử tuyển bit. Tuyển của hai bit 0 bằng 0. Trong mọi trường hợp cịn lại, ta nhận được 1. Ví dụ. | 1 0 1 1 (tương ứng 11 trong hệ thập phân) | 0 0 0 1 (tương ứng với 1 trong hệ thập phân) 1 0 1 1 (tương ứng với 11 trong hệ thập phân) Nghĩa l{ 11|1=11. Tốn tử tuyển loại bit. Tuyển loại của hai bit khác nhau bằng 1. Trong mọi trường hợp cịn lại, ta nhận được 0. Ví dụ. ^ 1 0 1 1 (tương ứng 11 trong hệ thập phân) ^ 0 0 0 1 (tương ứng với 1 trong hệ thập phân) 1 0 1 0 (tương ứng với 10 trong hệ thập phân) Nghĩa l{ 11^1=10. Tốn tử dịch bit sang phải. Dịch chuyển tồn bộ dãy bit sang phải theo số bit được chỉ định. Nếu là số dương, ta bổ sung các bit 0 vào đầu. Nếu là số âm, ta bổ sung các số 1 v{o đầu. >> Ví dụ. Đối với số dương 0 1 0 1 1 (tương ứng 11 trong hệ thập phân) C++ T r a n g | 46
  47. Đặng Ngọc Hoàng Thành > 1 dịch sang phải 1 bit > 0 0 1 0 1 (tương ứng với 5 trong hệ thập phân) Nghĩa l{ 11>>1=5. Đối với số âm 1 1 1 0 1 1 (tương ứng -11 trong hệ thập phân) > 2 dịch sang phải 2 bit > 1 1 1 1 1 0 (tương ứng -3 trong hệ thập phân) Nghĩa l{ -11>>2=-3. Các bạn cũng cần lưu ý rằng, trong các biểu diễn ở trên, nếu hệ thống được chọn là 32 bit, thì chúng ta cần lấp đầy số bit này: - Nếu số dương thì c|c bit cịn lại sẽ được bổ sung 0 v{o phía trước. - Nếu số âm thì các bit cịn lại sẽ được bổ sung 1 v{o phía trước. Trong các ví dụ trên, phần d~y bit để trắng tương ứng với bit dấu – 1 tương ứng với – v{ 0 tương ứng với +. Tốn tử dịch bit sang trái. Dịch chuyển tồn bộ dãy bit sang trái theo số bit được chỉ định. Ví dụ. Đối với số dương + 0 0 1 0 1 1 (tương ứng 11 trong hệ thập << phân) < 2 dịch sang trái 2 bit < 1 0 1 1 0 0 (tương ứng 44 trong hệ thập phân) Nghĩa l{ 11<<2=44. C++ T r a n g | 47
  48. Đặng Ngọc Hoàng Thành &= Các phép tốn gán hợp nhất trên bit. |= ^= >>= > nếu thực hiện trực tiếp trên số nguyên hệ thập phân, sẽ được tính như sau: a >b=a/2b. Tốn tử chuyển đổi kiểu dữ liệu Tốn tử n{y dùng để chuyển đổi một biến hay hằng thuộc kiểu dữ liệu này sang kiểu dữ liệu khác. Giả sử bạn cĩ biến int a = 3, int b = 2. Khi thực hiện phép chia để nhận được kết quả thực, bạn chỉ cần viết như sau: (float)3/2. Bạn phải lưu ý rằng số 3 ở đ}y đ~ bị chuyển thành kiểu thực, và việc thực hiện phép chia một số thực cho số nguyên sẽ trả về kiểu thực 1.5. Nếu bạn viết 3/(float)2, kết quả cũng tương tự. Ngược lại, nếu bạn viết (float)(3/2) thì kết quả lại khác. Sở dĩ như vậy là vì, nĩ sẽ thực hiện phép chia nguyên 3/2 (kết quả l{ 1), sau đĩ nĩ sẽ chuyển giá trị 1 nguyên này sang 1 thực. Do đĩ, gi| trị bạn thu được vẫn l{ 1, nhưng thuộc kiểu số thực. Cách biểu diễn sự chuyển đổi một biến thuộc kiểu dữ liệu này, sang kiểu khác chỉ cĩ thể thực hiện nếu kiểu của chúng tương đương. Bạn cĩ thể chuyển số thành số (sau này khi học về hướng đối tượng, bạn cĩ thể chuyển C++ T r a n g | 48
  49. Đặng Ngọc Hoàng Thành giữa c|c đối tượng theo cây thừa kế). Bạn khơng thể chuyển đổi từ số thành x}u, hay ngược lại (bằng cách thực hiện phép tốn chuyển đổi kiểu).Bạn cĩ thể chuyển đổi một xâu số thành số và một số thành xâu số bằng nhiều cách kh|c nhau, nhưng việc sử dụng tốn tử chuyển đổi kiểu l{ khơng được phép. Khi chuyển đổi, bạn sử dụng một trong các cú pháp sau: (kiểu_dữ_liệu)biến hoặc (kiểu_dữ_liệu)(biến) hoặc kiểu_dữ_liệu(biến). Tơi khuyên bạn nên sử dụng kiểu thứ 2 hoặc 3 để tránh các nhầm lẫn đ|ng tiếc khi biểu thức phức tạp. Các tốn tử khác Trong phần lập trình hướng đối tượng, chúng ta sẽ làm quen thêm nhiều tốn tử khác. Theo trình tự trình bày trong cuốn sách này, tơi khơng đưa ra c|c to|n tử này ở đ}y. Bạn sẽ được giảng giải chi tiết trong phần hướng đối tượng trong cuốn giáo trình này. Thứ tự ưu tiên của các tốn tử Trong tốn học, chúng ta biết rằng khi tính giá trị của một biểu thức, thì luơn cĩ sự ưu tiên của các tốn tử như: phép nh}n thực hiện trước phép cộng, phép chia và nhân thực hiện đồng thời, ưu tiên từ trái sang phải Trong các ngơn ngữ lập trình nĩi chung cũng như C++ nĩi riêng, các tốn tử cũng cĩ những độ ưu tiên nhất định. Trong một biểu thức phức tạp, bạn nên chú ý đến độ ưu tiên của các tốn tử, điều này rất dễ gây ra sai sĩt. Trong bảng sau đ}y, tơi xin đưa ra thứ tự ưu tiên của các tốn tử trong lập trình C++. Mức ưu tiên Tốn tử Độ ưu tiên cùng loại 1 :: Trái-sang-phải 2 () [] . -> ++ (hậu tố) dynamic_cast Trái-sang-phải static_cast reinterpret_cast const_cast typeid 3 ++ (tiền tố) ~ ! sizeof new delete Phải-sang-trái * & + - (dấu dương âm) 4 (type) (chuyển đổi kiểu) Phải-sang-trái 5 .* ->* Trái-sang-phải 6 * / % Trái-sang-phải 7 + - (phép tốn cơng, trừ) Trái-sang-phải 8 > Trái-sang-phải 9 = Trái-sang-phải C++ T r a n g | 49
  50. Đặng Ngọc Hoàng Thành 10 == != Trái-sang-phải 11 & Trái-sang-phải 12 ^ Trái-sang-phải 13 | Trái-sang-phải 14 && Trái-sang-phải 15 || Trái-sang-phải 16 ?: Phải-sang-trái 17 = *= /= %= += -= >>= <<= &= ^= |= Phải-sang-trái 18 , Trái-sang-phải Các tốn tử được thực hiện theo mức ưu tiên từ trên xuống. Nếu các tốn tử cùng mức, nĩ sẽ được thực hiện theo độ ưu tiên cùng loại. Ví dụ: o a = (b=0, c=0, b+c). Tốn tử g|n = cĩ độ ưu tiên 17, c|c tốn tử cộng + cĩ độ ưu tiên 7, to|n tử () cĩ độ ưu tiên 2 v{ to|n tử , cĩ độ ưu tiên 18. Do đĩ, to|n tử () sẽ được thực hiện trước. Bây giờ ta xét các tốn tử trong dấu (), ta chú ý rằng các biểu thức b=0, c=0, b+c là các biểu thức riêng biệt, chúng được phân tách bởi tốn tử ,. Theo thứ tự ưu tiên của tốn tử phẩy, nĩ sẽ thực hiện từ trái-sang-phải. Nghĩa l{ b=0, c=0 sau đĩ là b+c. Cuối cùng nĩ sẽ thực hiện tốn tử gán giá trị của biểu thức phức hợp bên phải cho bên trái. Kết quả là 0. o a = (1+2)*3/2++. Tốn tử g|n (độ ưu tiên 17), to|n tử + (độ ưu tiên 7), tốn tử * (độ ưu tiên 6), to|n tử / (độ ưu tiên 6), to|n tử ++ hậu tố (độ ưu tiên 2) v{ to|n tử () (độ ưu tiên 2). Như vậy tốn tử hậu tố ++ và tốn tử () sẽ thực hiện trước. Theo độ ưu tiên cùng loại, nĩ sẽ thực thi từ trái- sang-phải. Như vậy, tốn tử () sẽ được thực hiện đầu tiên. Nghĩa l{ ta nhận được biểu thức a = 3*3/2++. Tiếp theo, nĩ thực hiện tốn tử hậu tố ++, tuy nhiên tốn tử này chỉ tăng gi| trị của 2 lên 1 sau khi thực hiện xong các phép tốn trong biểu thức. Đến thời điểm này, ta nhận được biểu thức a=3*3/2. Tốn tử * v{ / cĩ cùng độ ưu tiên, nĩ sẽ được thực hiện theo thứ trự từ trái sang phải, nghĩa l{ a=9/2=4. Kết quả 4. Lưu ý. Trong ví dụ thứ hai, việc sử dụng phép tốn 2++ là khơng hợp lệ. Ở đ}y, chỉ cĩ tác dụng minh họa trực quan. Cịn 2 là một hằng số, ta khơng thể thực hiện phép to|n 2++ để l{m thay đổi giá trị của hằng. Trong C++, chúng ta cần thực hiện phép g|n b = 2; sau đĩ l{ b++. Nghĩa l{ ta cần biểu diễn biểu thức như sau để thu được một kết quả chính xác cĩ thể bảo đảm trong C++. C++ T r a n g | 50
  51. Đặng Ngọc Hoàng Thành a = (b=2, (1+2)*3/b++) Bài tập 4. Tính tốn các biểu thức sau, dựa v{o độ ưu tiên của tốn tử, sau đĩ, viết chương trình trên C++ để kiểm tra kết quả. a. 2+2*4%3+ ++2; b. 2++ + ++2*(3 - 2) c. 5++ - 3== 2-(4+2%3) d. 5>>2^3*(1+2) C++ T r a n g | 51
  52. Đặng Ngọc Hoàng Thành CHƯƠNG 5. XUẤT NHẬP CƠ BẢN Đến thời điểm n{y, chúng ta đ~ biết hai cách thức để xuất dữ liệu ra màn hình nhờ vào việc sử dụng đối tượng cout và hàm printf. Trong chương n{y, chúng ta sẽ tìm hiểu cụ thể hơn về cách xuất-nhập dữ liệu nhờ vào thiết bị nhập dữ liệu là bàn phím, và thiết bị hiển thị dữ liệu xuất ra là màn hình máy tính. Trong thư viện chuẩn của C++, các hàm xuất nhập cơ bản nằm trong tệp header là iostream. Đối với thư viện này bạn cần lưu ý một số điểm. Cĩ hai lớp thư viện cĩ chức năng hỗ trợ các hàm xuất nhập cơ bản đĩ l{ iostream v{ iostream.h. Về bản chất, cách thức sử dụng chúng thì khơng cĩ nhiều sự khác biệt. Tuy nhiên việc sử dụng thư viện iostream cĩ nhiều ưu điểm hơn hẳn so với thư viện iostream.h. Thư viện iostream.h đ~ ra đời c|ch đ}y qu| l}u (trên 15 năm) trong khi thư viện iostream mới hơn rất nhiều. Việc sử dụng một thư viện mới, chuẩn mực hơn bao giờ cũng tốt hơn. Thư viện iostream hỗ trợ cả kiểu char lẫn kiểu w_char. Thư viện iostream được đặc tả trong namespace std, trong khi thư viện iostream.h được khai báo tồn cục. Việc khai báo tồn cục bao giờ cũng chiếm dụng khơng gian bộ nhớ lớn hơn. Vì vậy, nếu bạn muốn thực hiện việc nhập xuất dữ liệu cơ bản trong C++, ta nên sử dụng thư viện iostream thay vì sử dụng iostream.h. Tổng quát hĩa, nếu các lớp thư viện cĩ hai dạng tồn tại song song là .h và khơng cĩ .h (string và string.h, new v{ new.h ), thì bạn nên sử dụng thư viện khơng cĩ .h. Trong trường hợp khơng cĩ dạng tương ứng, bạn bắt buộc phải sử dụng thư viện .h (ví dụ math.h). Xuất dữ liệu chuẩn cout Đầu tiên, ta khảo sát việc xuất dữ liệu ra màn hình nhờ đối tượng cout. Nĩ được sử dụng kết hợp với tốn tử chèn dữ liệu >> (kí hiệu giống tốn tử dịch bit phải). cout<<”Hello, world !”;//In c}u Hello, world ! ra màn hình cout<<120;//In số 120 ra màn hình cout<<x;//In giá trị của biến x ra màn hình Đối tượng cout kết hợp với tốn tử << cĩ thể được ghép nhiều lần. cout<<”Chao ban”<<” ban may tuoi”; C++ T r a n g | 52
  53. Đặng Ngọc Hoàng Thành cout >age; float f; cin>>f; string s; cin>>s; Bạn cần lưu ý về kiểu dữ liệu của biến được sử dụng trong đối tượng cin này. Nếu cĩ một sự vi phạm nào về kiểu dữ liệu (ví dụ biến l{ int, nhưng khi nhập vào lại nhập vào một kí tự khơng phải là số) thì chương trình dịch sẽ bỏ qua việc khởi tạo giá trị cho biến đĩ. Chương trình ho{n to{n khơng cĩ lỗi (process returned 0). Khi sử dụng đối tượng cout và cin, ta cần khai báo khơng gian sử dụng namespace là std. Hoặc, bạn cĩ thể viết ngắn gọn hơn std:: Chương trình 1 Chương trình 2 #include #include using namespace std; int main(){ int main(){ std::cout<<”Hello”; cout<<”Hello”; } } Đối tượng cin và xâu kí tự: trong ví dụ trên, tơi đ~ sử dụng đối tượng cin để tách một xâu kí tự và gán cho biến xâu kí tự s. Khi sử dụng đối tượng cin với xâu kí tự, bạn cần lưu ý một điểm là đối tượng cin sẽ dừng việc trích tách nếu nĩ đọc thấy một kí tự trắng trong xâu kí tự đĩ (cĩ nghĩa, nếu xâu bạn nhập v{o l{ “Toi di hoc” – thì nĩ chỉ t|ch được x}u “Toi” v{ g|n cho biến C++ T r a n g | 53
  54. Đặng Ngọc Hoàng Thành s m{ thơi). Để khắc phục nhược điểm này của đối tượng cin, C++ cung cấp cho chúng ta một hàm khác là hàm getline, cĩ chức năng tương tự. Cấu trúc gọi h{m getline như sau: getline(cin, tên_biến_xâu). Khi nhập xuất dữ liệu từ bàn phím và màn hình, bạn luơn sử dụng tham số thứ nhất là cin. Chúng ta sẽ tìm hiểu tiếp trong chương 16 của giáo trình này, khi làm việc với file. Chương trình #include #include using namespace std; int main() { string s; cout . Lớp này cho phép một đối tượng dựa trên cơ sở của xâu cĩ thể được chuyển đổi như một luồng. Trong thư viện sstream, ta cĩ ba lớp đối tượng luồng x}u cơ bản: stringstream, istringstream và ostringstream. Cách thức này chúng ta cĩ thể tách hoặc chèn x}u, nĩ đặc biệt hữu dụng khi chuyển một xâu thành số v{ ngược lại. Ví dụ, nếu bạn muốn tách một số integer từ một x}u “1201”, ta cĩ thể viết như sau: string mystr = “1201”; int mynum; C++ T r a n g | 54
  55. Đặng Ngọc Hoàng Thành stringstream(mystr)>>mynum; Đ}y khơng phải là cách thức duy nhất giúp ta chuyển đổi một xâu thành số. Trong thư viện string, cung cấp cho chúng ta các h{m để thực thi cơng việc đĩ như h{m atof (x}u số thực thành số thực), atoll (xâu thành số nguyên dài thành số nguyên dài), Sau đ}y, tơi sẽ giới thiệu cho các bạn cách sử dụng lớp stringstream để nhập dữ liệu từ bàn phím. Chương trình #include #include using namespace std; int main() { string mystr; int mynum; getline(cin,mystr); stringstream(mystr)>>mynum; cout 1:2:3:4:5 #include Sum = 15 C++ T r a n g | 55
  56. Đặng Ngọc Hoàng Thành using namespace std; int main() { string temp, s; getline(cin, s); istringstream ss(s); double sum = 0; while (getline(ss, temp, ':') ) { float a; stringstream(temp)>>a; sum+=a; } cout<<”Sum = “<<sum; return 0; } Như bạn thấy, h{m getline trong trường hợp này cĩ hai biến thể. Nĩ cĩ tất cả 4 dạng biến thể. Phương ph|p n{y, thường được sử dụng khi dữ liệu nhập vào quá nhiều. Chúng ta cĩ thể cho người dùng nhập vào thành một x}u, khi đĩ ta sẽ tiến hành xử lý nhờ lớp istringstream này. Chúng ta sẽ thảo luận chi tiết hơn về ba lớp đối tượng này sau khi tìm hiểu kĩ về lập trình hướng đối tượng. C++ T r a n g | 56
  57. Đặng Ngọc Hoàng Thành CHƯƠNG 6. CÁC CẤU TRÚC LỆNH ĐIỀU KHIỂN Một chương trình khi thực thi, nĩ khơng chỉ đơn thuần là một dãy các câu lệnh tuần tự. Trong quá trình xử lý, nĩ cĩ thể kiểm tra điều kiện rồi thực thi đoạn mã, lặp đi lặp lại một đoạn m~ n{o đĩ Với mục đích đĩ, C++ cung cấp cho chúng ta các cấu trúc điều khiển. Với các cấu trúc điều khiển mà chúng ta sẽ l{m quen trong chương này, chúng ta cần làm quen với hai khái niệm: mệnh đề (câu lệnh) và khối lệnh. Câu lệnh: là một lệnh được kết thúc bằng dấu chấm phẩy ; Khối lệnh: là một dãy các câu lệnh, được đặt trong dấu {} Một câu lệnh cĩ thể l{ đơn hoặc cĩ cấu trúc. Các lệnh gán, xuất nhập l{ c|c lệnh đơn. C|c lệnh điều kiện, lựa chọn, lặp là các lệnh cĩ cấu trúc. Cấu trúc lệnh cĩ điều kiện: if và else Từ khĩa if thường được sử dụng khi muốn thực thi một đoạn chương trình với một điều kiện n{o đĩ. Cấu trúc của câu lệnh if trong trường hợp này if (biểu_thức_điều_kiện_đúng) { Các_lệnh; } Giải thích: kiểm tra giá trị của biểu thức điều kiện, nếu đúng thì c|c lệnh bên trong sẽ được thực hiện; ngược lại, lệnh sẽ khơng được thực hiện. Ví dụ if (x>0) cout 0)&&(y>0)) C++ T r a n g | 57
  58. Đặng Ngọc Hoàng Thành { cout 0) cout<<x<<” la so duong”; else if(x<0) cout<<x<<” la so am”; else C++ T r a n g | 58
  59. Đặng Ngọc Hoàng Thành cout Nhap n:5 using namespace std; 5 int main() 4 { 3 int n; 2 C++ T r a n g | 59
  60. Đặng Ngọc Hoàng Thành cout >n; while (n>0){ cout 0. Điều kiện n{y đúng, nên c|c lệnh trong vịng lặp sẽ được thực hiện. Nĩ sẽ in ra giá trị của n l{ 5. Sau đĩ, gi| trị của n giảm đi 1, tức là n = 4. Vịng lặp lại tiếp tục thực hiện, vì n>0 cịn đúng. Qu| trình này cứ tiếp tục, cho đến khi n=0. Khi đĩ, điều kiện n>0 l{ sai. Do đĩ, vịng lặp sẽ dừng lại. Giá trị in ra màn hình là các số từ 5 giảm đến 1. Lưu ý: khi sử dụng vịng lặp while cần lưu ý c|c điểm sau đ}y: o Vịng lặp phải cĩ tính dừng. Nghĩa l{ biểu_thức_điều_kiện phải cĩ trường hợp sai. o Nếu cĩ nhiều lệnh chịu sự chi phối của while, thì chúng cần được đặt trong dấu khối lệnh. 2. Vịng lặp do while Cấu trúc khai báo của vịng lặp do while như sau do { . }while (biểu_thức_điều_kiện_đúng); Giải thích: Thực hiện các lệnh trong vịng lặp, sau đĩ kiểm tra biểu_thức_điều_kiện. Nếu biểu_thức_điều_kiện cịn đúng, thì tiếp tục lặp. Ví dụ Kết quả #include Nhap n:5 C++ T r a n g | 60
  61. Đặng Ngọc Hoàng Thành using namespace std; 5 int main(){ 4 int n; 3 cout >n; 1 do { 0 cout 0); return 0; } Giải thích: đầu tiên nhập vào giá trị cho biến n. Giá trị n nhập vào ở đ}y l{ 5. Vịng lặp do while sẽ thực thi các lệnh bên trong nĩ. Nĩ sẽ in ra giá trị của n l{ 5. Sau đĩ, gi| trị của n giảm đi 1, tức là n = 4. Vịng lặp kiểm tra giá trị của biểu thức n>0. Vì biểu thức n{y đúng, nên nĩ tiếp tục lặp. Quá trình này cứ tiếp tục cho đến khi n=0. Giá trị n=0 vẫn được in ra, sau khi kiểm tra n>0 khơng cịn đúng nữa, vịng lặp kết thúc. Khác với vịng lặp while ở trên, nĩ sẽ in ra giá trị từ 5 giảm đến 0. Lưu ý: khi sử dụng vịng lặp do while cần lưu ý c|c điểm sau đ}y: o Vịng lặp phải cĩ tính dừng. Nghĩa là biểu_thức_điều_kiện phải cĩ trường hợp sai. o Nếu cĩ nhiều lệnh chịu sự chi phối của do while, thì chúng cần được đặt trong dấu khối lệnh. o Vịng lặp do while luơn thực hiện các lệnh bên trong nĩ, ít nhất 1 lần. 3. Vịng lặp for Cấu trúc khai báo của vịng lặp for như sau for (biểu_thức_khởi_tạo; biểu_thức_giới_hạn; biểu_thức_tăng_giảm) { . C++ T r a n g | 61
  62. Đặng Ngọc Hoàng Thành } Giải thích: Thực hiện vịng lặp, với số vịng lặp từ biểu_thức_khởi_tạo cho đến biểu_thức_giới_hạn theo mức tăng l{ biểu_thức_tăng_giảm. Ví dụ Kết quả #include Nhap n:5 using namespace std; 0 int main() 1 { 2 int n, i; 3 cout >n; 5 for (i=0; i<=n;i++) { cout<<i<<endl; }; return 0; } Giải thích: đầu tiên nhập vào giá trị cho biến n. Giá trị n nhập vào ở đ}y l{ 5. Vịng lặp for sẽ thực thi các lệnh bên trong với số vịng lặp là từ 0 đến 5, theo bước nhảy là 1 – tương ứng với i++. Lưu ý: khi sử dụng vịng lặp for cần lưu ý c|c điểm sau đ}y o Các tham số trong vịng lặp for cĩ thể khuyết một hoặc vài (thậm chí là tất cả) tham số. Tuy nhiên, dấu chấm phẩy là luơn bắt buộc. Số bước lặp của vịng lặp for sẽ được tính như sau: o Nếu cĩ nhiều lệnh chịu sự chi phối của for, thì chúng cần được đặt trong dấu khối lệnh. C++ T r a n g | 62
  63. Đặng Ngọc Hoàng Thành o Ta cĩ thể thực hiện việc khai báo biến trực tiếp bên trong dấu ngoặc đơn của vịng lặp for. Ví dụ Kết quả #include Nhap n:5 using namespace std; 0 int main() 1 { 2 int n; 3 cout >n; 5 for (int i=0; i 2 using namespace std; 1 int main() 0 { int n = 2; for(;;){ C++ T r a n g | 63
  64. Đặng Ngọc Hoàng Thành cout 0 using namespace std; 2 int main() 4 { 6 for(int i=0;i<10;i++){ 8 if (i%2!=0) continue; cout<<i<<endl; } return 0; } Giải thích: Vịng lặp for sẽ thực thi các lệnh bên trong nĩ. Biến i chạy từ 0 đến 9, kiểm tra điều kiện i cĩ phải là số chẵn hay khơng. Nếu i là số lẻ, thì câu lệnh continue sẽ được thực hiện v{ bước lặp hiện tại sẽ bị bỏ qua. Nếu i là số chẵn, thì lệnh continue sẽ khơng được gọi v{ bước lặp hiện tại vẫn được thực hiện. Do đĩ, lệnh cout chỉ được thực hiện trong trường hợp biến i là chẵn. Như vậy, mỗi khi giá trị i là chẵn, nĩ sẽ in kết quả. Nếu giá trị của i là lẻ, thì kết quả sẽ khơng được in ra. C++ T r a n g | 64
  65. Đặng Ngọc Hoàng Thành c. Lệnh goto Lệnh goto cho phép tạo ra một bước nhảy đến một nh~n được ấn định sẵn. Tên nhãn sẽ được đặt như sau tên_nhãn: và lệnh goto sẽ nhảy đến tên nhãn. Một lời khuyên cho chúng ta là nên hạn chế tối đa việc sử dụng lệnh goto. Bởi vì lệnh goto thường làm phá vỡ cấu trúc của lập trình hiện đại. Chương trình Kết quả #include 5 using namespace std; 4 int main() 3 { 2 int n = 5; 1 loop://Tên nhãn cout 0) goto loop; return 0; } Giải thích: Giá trị khởi tạo của biến n l{ 5. Nh~n được đặt tên là loop. Nhãn cĩ thể hiểu như một vị trí được đ|nh dấu (bookmark). Chương trình tiến hành in giá trị của biến n. Sau đĩ, giảm giá trị của n đi. C}u lệnh điều kiện, kiểm tra giá trị của biểu thức n>0, nếu đúng thi lệnh goto được gọi và nĩ sẽ được chuyển đến vị trí đ~ được đ|nh dấu là loop. Chương trình lại thực thi thêm lần nữa kể từ vị trí loop đĩ. Nếu n<=0, lệnh goto khơng được gọi. Chương trình kết thúc. d. Lệnh exit Lệnh exit dùng để thốt khỏi chương trình v{ trả về một m~ được chỉ định. Mã chỉ định này tùy thuộc vào hệ điều hành, nĩ cĩ thể sử dụng trong chương trình theo quy ước như sau: nếu chương trình kết thúc bình thường, thì m~ chương trình l{ 0; nếu cĩ một sự cố khơng mong muốn xảy ra, m~ chương trình l{ một giá trị khác 0. void exit(int mã_chỉ_định); Nếu tham số mã_chỉ_định khơng được cấp vào, tức là exit (khơng cĩ dấu ngoặc đơn), thì nĩ sẽ tiến hành theo mặc định – tức giá trị 0. Hàm exit nằm C++ T r a n g | 65
  66. Đặng Ngọc Hoàng Thành trong thư viện stdlib.h. Đ}y l{ một h{m tương đối cũ nằm trong thư viện .h. Bạn chỉ cĩ thể sử dụng lệnh exit nếu khai b|o thư viện stdlib.h mà khơng cĩ thư viện tương ứng là stdlib. Cấu trúc lựa chọn: switch Câu lệnh lựa chọn cĩ cấu trúc như sau: Cú pháp switch(biểu_thức){ case hằng_1: nhĩm_các_lệnh; break; case hằng_2: nhĩm_các_lệnh; break; default: nhĩm_các_lệnh; } Giải thích: kiểm tra giá trị của biểu thức, nếu giá trị của biểu thức rơi v{o danh sách hằng, thì nĩ sẽ thực hiện các lệnh tương ứng trong từng trường hợp case (nếu là hằng_1 – các lệnh trong trường hợp case hằng_1, .). Nếu biểu thức khơng thuộc vào danh sách hằng, thì nĩ sẽ thực hiện lệnh trong trường hợp default. Chương trình Kết quả #include Ban la nam hay nu b/g:b using namespace std; Nam int main() C++ T r a n g | 66
  67. Đặng Ngọc Hoàng Thành { char n; cout >n; switch(n) { case ‘b’: cout<<”Nam”; break; case ‘g’: cout<<”Nu”; break; default: cout<<”Khong xac dinh”; } return 0; } Giải thích: chương trình buộc người dùng nhập vào một kí tự (b – boy) hay (g – girl). Nếu người dùng nhập vào một kí tự kh|c, chương trình vẫn tính đến trường hợp này. Kí tự m{ người dùng nhập v{o được lưu trong biến n. Câu lệnh switch sẽ kiểm tra biến nhập v{o đĩ cĩ nằm trong danh sách hằng hay khơng (danh sách hằng ở đ}y l{ ‘b’ v{ ‘g’). Nếu cĩ, thì tương ứng với ‘b’ nĩ sẽ thực hiện trường hợp case ’b’, nếu l{ ‘g’ nĩ sẽ thực hiện trường hợp case ‘g’. Lệnh break trong mỗi trường hợp cĩ tác dụng là thốt ra khỏi câu lệnh lựa chọn (cũng mang tính lặp), nếu khơng cĩ lệnh break, tất cả các trường hợp đều được xét duyệt và nếu rơi v{o trường hợp nào thì các lệnh tương ứng sẽ được thực thi, đồng thời lệnh ở trường hợp bên dưới nĩ cũng được thực thi. Trong trường hợp, kí tự nhập v{o khơng tương ứng trong C++ T r a n g | 67
  68. Đặng Ngọc Hoàng Thành danh sách hằng, nĩ sẽ thực thi trường hợp default. Vì default l{ trường hợp cuối cùng, nên nĩ khơng cần lệnh break. Chú ý: Lệnh switch chỉ được lựa chọn để sử dụng khi cần kiểm tra giá trị của một biểu thức cĩ tương ứng với một tập các hằng số nào đĩ hay khơng (sự tương ứng ở đ}y cĩ thể là thuộc hoặc khơng thuộc tương ứng với khái niệm trong tập hợp). Các hằng_1, hằng_2, cĩ thể là một vùng liên tục, hoặc gián đoạn (như c|c số từ 0 1, ‘a’ ’d’, ). Nhưng nhất thiết các giá trị tương ứng với c|c trường hợp case phải là hằng số (hoặc khoảng hằng). Biểu thức trong lệnh switch nhất thiết khơng phải là một kiểu cĩ cấu trúc (mảng, xâu, tập hợp ). Ví dụ sau đ}y sẽ phát sinh lỗi khi biên dịch, do biểu thức tương ứng với một xâu. string s = “abc”; Error switch(s) { case “a”: case “ab”: case “abc”: default: } Trong hầu hết các ngơn ngữ lập trình, đại đa số đều khơng cho phép tham số trong switch là một x}u (cũng như lệnh case of trong họ Pascal – Delphi). Tuy nhiên, ngơn ngữ C# vẫn hỗ trợ xâu kí tự trong tham số của switch dù nĩ là một dẫn xuất của C++. Một điều bạn cần lưu ý, về bản chất thì câu lệnh switch sẽ tương ứng với một dãy các câu lệnh if. Chúng hồn tồn cĩ thể thay thế cho nhau. Cũng tương tự, các câu lệnh lặp while, do while v{ for cũng cĩ thể thay thế cho nhau. Tuy nhiên, chúng vẫn được sử dụng trong c|c trường hợp mang tính đặc trưng của chúng. Bảng sau đ}y tổng hợp các cách sử dụng của các lệnh cĩ cấu trúc thường được sử dụng. Tên lệnh Cách dùng if else Khi cần kiểm tra một hoặc một v{i điều kiện mang tính chất logic. switch Khi cần kiểm tra điều kiện tương ứng hoặc thuộc vào của một biến số trong một danh sách hằng C++ T r a n g | 68
  69. Đặng Ngọc Hoàng Thành tương ứng. for Lặp cĩ số vịng lặp x|c định while Cần kiểm tra điều kiện lặp trước khi thực hiện lệnh, lặp khơng xác định số vịng lặp. do while Kiểm tra điều kiện lặp sau khi thực hiện lệnh, lặp khơng x|c định số vịng lặp. break Cần thốt khỏi vịng lặp. continue Bỏ qua vịng lặp hiện tại. goto Nhảy đến một nh~n được chỉ đinh. Nên tr|nh sử dụng, chỉ sử dụng trong những trường hợp thực sự cần thiết. Bài tập 6. 1. Sử dụng các cấu trúc lặp for, while, do while, goto để xây dựng các chương trình tính tích ph}n sau (với mỗi cấu trúc xây dựng mỗi chương trình) bằng phương ph|p hình chữ nhật (trái, phải hoặc trung tọa). ∫ ( ) 2. Lựa chọn cấu trúc lệnh phù hợp, để tính giá trị của chuỗi hữu hạn sau đ}y ∑ 3. Tính các tổng sau đ}y ( ) ( ) ( ) với n, x nhập vào từ bàn phím. Yêu cầu xây dựng hàm. C++ T r a n g | 69
  70. Đặng Ngọc Hoàng Thành CHƯƠNG 7. HÀM Hàm là một tập hợp các câu lệnh, nĩ được thực thi khi được gọi từ một vị trí kh|c trong chương trình. Bạn cĩ thể quan s|t lược đồ bên dưới đ}y. Thư viện 2 Thư viện 1 Hàm 1 Hàm 1 Hàm 2 Hàm 2 Hàm 3 Hàm 3 Chương trình chính Hàm 1 Thư viện n Hàm main{ Hàm 1 Gọi H{m 1 (Thư viện 1); Hàm 2 Gọi H{m 2 (Thư viện 2); Hàm 3 Gọi H{m 3 (Thư viện n); Gọi H{m 1 (chương trình chính) Hình 16 – Sơ đồ minh họa việc sử dụng hàm Trong lược đồ n{y, c|c h{m được viết trong c|c thư viện khác nhau. Trong chương trình chính, chúng ta cĩ thể gọi c|c h{m trong c|c thư viện, lẫn c|c h{m được khai báo trong chương trình chính. Nhờ vào việc sử dụng hàm, chúng ta cĩ thể ph}n chia chương trình thành các modul nhỏ. Đơi lúc, người ta gọi c|ch ph}n chia chương trình th{nh c|c h{m như thế này là cách giải quyết b{i to|n theo phương ph|p “chia để trị”. Cách phân chia này cĩ rất nhiều ưu điểm: C++ T r a n g | 70
  71. Đặng Ngọc Hoàng Thành . Làm cho chương trình trở nên gọn gàng dễ đọc hơn. . Dễ cải biên chương trình. . Dễ kiểm tra theo các modul. Đĩ l{ ý tưởng để xây dựng hàm. Vậy h{m được khai báo và sử dụng như thế nào. Chúng ta sẽ tìm hiểu trong chương n{y. Khai báo và sử dụng hàm H{m được khai b|o theo cú ph|p sau đ}y: kiểu_dữ_liệu tên_hàm(danh_sách_tham_số) { Thân hàm; } Trong đĩ, o kiểu_dữ_liệu: là kiểu dữ liệu mà hàm trả về. o tên_hàm: là tên của h{m, do người lập trình đặt. Tên h{m khơng được chứa kí tự đặc biệt, khơng được bắt đầu bằng số, khơng chứa kí tự trắng, khơng trùng với từ khĩa. o danh_sách_tham_số: là danh sách các tham số dùng như c|c biến cục bộ. Nếu cĩ nhiều tham số, thì chúng sẽ được phân tách theo các dấu phẩy. o Thân hàm: là nội dung m{ người lập trình xây dựng nên. Nếu hàm trả về kiểu dữ liệu khác void, bạn cần sử dụng lệnh return để trả về biến chứa kết quả và cĩ cùng kiểu dữ liệu với kiểu dữ liệu của hàm. Nếu hàm trả về kiểu dữ liệu void thì điều này là khơng cần thiết. Ví dụ Kết quả #include 3 using namespace std; int add(int a, int b) { return a+b; } C++ T r a n g | 71
  72. Đặng Ngọc Hoàng Thành int main() { cout 3 using namespace std; int add(int a, int b); int main() { cout<<add(1, 2); return 0; } int add(int a, int b) C++ T r a n g | 72
  73. Đặng Ngọc Hoàng Thành { return a+b; } Trong khai báo hàm dạng này, cấu trúc khai báo hàm khuyết phần thân hàm. Chỉ cĩ khai báo phần tên của hàm theo cú pháp chuẩn. Vị trí đặt hàm xây dựng hồn chỉnh là bất kì vị trí nào. Cách khai báo hàm prototype cĩ nhiều ưu điểm: - Bạn cĩ thể khơng quan t}m đến thứ tự khai báo hàm. Nếu bạn khơng sử dụng khai báo prototype, thì hàm khai báo sau mới được phép gọi hàm khai b|o trước nĩ. Điều ngược lại l{ khơng được phép. Nhưng đối với khai báo prototype thì bạn hồn tồn khơng cần quan t}m đến điều này. - Bạn cĩ thể tách phần khai b|o prototype v{ đặt nĩ vào trong một tập tin mới, thường là tập tin tiêu đề .h (mà bạn tự đặt tên), phần thân hàm lại chứa trong một tệp kh|c, thường là .cpp hoặc trong chính tệp chứa chương trình chính. C|ch l{m n{y giúp chương trình của bạn sáng sủa hơn rất nhiều. Trong các dự án lập trình lớn, người ta thường phân tách theo dạng này. Chúng ta sẽ xét ví dụ minh họa sau. Trong ví dụ minh họa này, dự án của tơi gồm cĩ hai tệp: tieude.h để chứa khai b|o prototype v{ main.cpp để chứa thân hàm và hàm main. Đối với Codeblocks, bạn hãy thực hiện theo c|c bước sau: - Tạo mới một dự |n C++ v{ lưu lại. Trong dự án này, mặc định Codeblocks sẽ tạo cho bạn một tệp main.cpp. - Vào New > File > chọn C/C++ header. Sau đĩ, bạn hãy chọn vị trí để lưu trữ tệp tiêu đề (thơng thường, bạn nên tạo các cấu trúc thư mục khác nhau để lưu tệp .h cũng như tệp .cpp như tơi đ~ trình b{y ở trên). Đối với Eclipse, bạn thực hiện như sau: - Kích chuột phải v{o thư mục cần đặt tệp .h, chọn New > Header File. - Kích chuột phải v{o thư mục cần đặt tệp .cpp, chọn New > Source File. Đối với Visual Studio 2010, bạn kích chuột phải vào tên dự án, chọn Add New Item. Sau đĩ chọn header file .h. C++ T r a n g | 73
  74. Đặng Ngọc Hoàng Thành Tệp tieude.h Tệp main.cpp #ifndef TIEUDE_H_INCLUDED #include #define TIEUDE_H_INCLUDED #include "tieude.h" using namespace std; int sum(int, int); int main() void showmsg(void); { showmsg(); #endif // TIEUDE_H_INCLUDED return 0; } void showmsg(){ cout . Các hàm trong chương trình chính cĩ thể sử dụng mà khơng cần quan t}m đến thứ tự khai b|o. Như bạn thấy, các hàm khai b|o sau h{m main (điều này chỉ cĩ thể được phép đối với khai báo prototype). H{m showmsg khai b|o trước h{m sum nhưng cĩ thể gọi được hàm sum. Thứ tự tiêu đề của hàm trong tệp tiêu đề hồn tồn khơng quan trọng và nĩ khơng ảnh hưởng việc sử dụng các hàm theo thứ tự trước sau. Lưu ý: - Khi sử dụng khai báo prototype trên các tập tin .h, bạn cần lưu ý, nếu dự án của bạn cĩ sử dụng namespace, ví dụ std, bạn chỉ cĩ thể sử dụng cú pháp truy cập std:: m{ khơng được sử dụng using namespace std trong tệp .h này. - Nếu tệp .cpp và tệp .h nằm trong cùng thư mục, thì phần #include trong tệp cpp cĩ thể viết tên tệp tiêu đề trong dấu “”. Nếu chúng khơng nằm trong cùng thư mục, bạn cần chỉ đường dẫn tương đối cho nĩ. Ví dụ tệp headers.h nằm trong thư mục headers và tệp Main.cpp nằm trong thư mục cpps. Nếu tệp headers.h là tệp tiêu đề của tệp Main.cpp, bạn cần include nĩ trong Main.cpp. Giả sử headers và cpps nằm trong cùng thư mục src. Khi đĩ, trong tệp Main.cpp, bạn khai b|o include như sau: #include” /headers/headers.h”. Trong đĩ, dấu / để dịch lùi một mức trong C++ T r a n g | 74
  75. Đặng Ngọc Hoàng Thành cấu trúc c}y thư mục (dịch lùi từ thư mục headers một mức chính l{ thư mục src), sau đĩ l{ headers/headers.h. Phạm vi tác dụng của biến Như tơi đ~ giới thiệu ở trên, biến tồn cục là những biến được khai báo ngồi tất cả các hàm (hay khơng bao trong bất kì dấu {} nào). Các biến này cĩ tác dụng trong tồn bộ chương trình. Bạn cĩ thể gọi nĩ trong hàm main, hay trong các hàm mà bạn khai b|o. Ngược lại, những biến cịn lại gọi là các biến cục bộ. Những biến cục bộ được khai báo trong phạm vi nào (được x|c định nhờ dấu {}) thì chỉ cĩ tác dụng trong phạm vi đĩ m{ thơi. Ví dụ Giải thích #include - Biến global là biến tồn cục, nĩ cĩ tác dụng trong tồn bộ using namespace std; chương trình. Bạn cĩ thể sử dụng int global; nĩ trong h{m main, h{m add int add(int a, int b) - Biến local, local1, local2 là các biến cục bộ. Biến local được khai { báo trong hàm add, nĩ cĩ phạm local result = a + b; vi tác dụng trong phạm vi của hàm này. Biến cục bộ local1 được return result; khai báo trong hàm main. Nĩ } cũng chỉ cĩ tác dụng trong hàm main. Biến local2 được khai báo int main() trong phạm vi tác dụng của câu { lệnh if, nĩ chỉ cĩ tác dụng trong khối lệnh này. Nếu ta gọi biến int local1; này ngồi khối lệnh của if, if(local1>0) chương trình dịch sẽ báo lỗi. { int local2; } return 0; C++ T r a n g | 75
  76. Đặng Ngọc Hoàng Thành } Hàm khơng trả về giá trị - Hàm void. Như chúng ta đ~ thấy trong các ví dụ trên, các hàm mà chúng ta sử dụng là các hàm cĩ kiểu dữ liệu trả về. Đối với các loại h{m n{y, để hàm trả về một giá trị n{o đĩ, ta sử dụng từ khĩa return. Giá trị hàm trả về phải cĩ kiểu dữ liệu cùng loại với kiểu dữ liệu mà ta quy định khi khai báo hàm. Chúng ta cũng bắt gặp tình huống: nhiều lúc hàm mà ta xây dựng khơng trả về một giá trị nào, hoặc trả về nhiều hơn một giá trị. Khi đĩ, chúng ta sử dụng khai báo hàm void. Đối với hàm dạng này, ta cĩ thể tham khảo ví dụ sau. Cịn đối với hàm trả về nhiều hơn một giá trị, chúng ta sẽ thảo luận kĩ hơn trong phần tham biến. Ví dụ Kết quả #include Hello, world ! using namespace std; void showMsg() { cout<<”Hello, world !”; } int main() { showMsg(); return 0; } Chú ý: Vì hàm cĩ kiểu dữ liệu trả về luơn trả về một giá trị cụ thể, nên chúng ta cĩ thể sử dụng trực tiếp loại hàm này trong các biểu thức tính tốn (ví dụ a=b+sin(x)). Điều này là khơng thể đối với hàm void. C++ T r a n g | 76
  77. Đặng Ngọc Hoàng Thành Khi sử dụng các hàm khơng cĩ tham số hình thức, nếu bạn gọi hàm theo cách sau: tên_hàm(); là cách gọi h{m đúng. Nếu bạn gọi hàm theo cách: tên_hàm;, thì dù chương trình dịch khơng báo lỗi, nhưng kết quả nhiều khi khơng chính xác. Vì vậy, bạn nên gọi hàm theo cách đầu tiên. Tham biến và tham trị Cho đến thời điểm n{y, c|c h{m m{ chúng ta đ~ nghiên cứu đều truyền tham số theo tham trị. Điều n{y cĩ nghĩa l{, với các tham số này, khi truyền vào hàm, chúng sẽ sao chép giá trị vào cho các tham số này (trong lời gọi hàm), các tham số đĩ chỉ đĩng vai trị l{ c|c tham số hình thức, chúng khơng lưu lại giá trị của chúng, mà các giá trị đĩ đ~ bị các lệnh trong hàm l{m thay đổi. Ví dụ Giải thích #include Nếu tham số a trong hàm setNum được sử dụng như trên (đơn thuần using namespace std; l{ int a) thì nĩ được quy định là void setNum(int a) truyền theo tham trị. { Khi truyền theo tham trị, giá trị của biến xuất hiện trong lời gọi hàm này, a = 0; sẽ khơng thay đổi sau khi thốt ra } khỏi hàm. Điều n{y cĩ nghĩa l{ gi| trị của biến b trước khi gọi hàm là 1, int main() sau khi gọi hàm, nĩ vẫn nhận giá trị { là 1. int b = 1; setNum(b); cout<<b; return 0; } Nếu muốn thay đổi giá trị của biến khi truyền tham số trong hàm, ta sử dụng khai báo tham biến. Với việc quy định các tham số truyền theo tham biến, thì khi khai báo ta chỉ bổ sung vào dấu & ở trước tên tham số đĩ. C++ T r a n g | 77
  78. Đặng Ngọc Hoàng Thành Bằng cách này, các biến được sử dụng trong lời gọi hàm, sẽ bị l{m thay đổi giá trị sau khi lời gọi hàm kết thúc. Ví dụ Giải thích #include Nếu tham số a trong hàm setNum được sử dụng như trên (int &a) thì using namespace std; nĩ được quy định là truyền theo void setNum(int &a) tham biến. { Khi truyền theo tham biến, giá trị của biến xuất hiện trong lời gọi hàm a = 0; này, sẽ thay đổi sau khi thốt ra khỏi } h{m. Điều n{y cĩ nghĩa l{ gi| trị của biến b trước khi gọi hàm là 1, sau khi int main() gọi hàm, nĩ vẫn nhận giá trị là 0. { int b = 1; setNum(b); cout m= 2, n=1 using namespace std; void swap(int &a, int &b) C++ T r a n g | 78
  79. Đặng Ngọc Hoàng Thành { int c = a; a = b; b = c; } int main() { int m = 1; int n = 2; swap(m, n); cout m= 2, n=1 using namespace std; void swap(int *a, int *b) C++ T r a n g | 79
  80. Đặng Ngọc Hoàng Thành { int *c;//hoặc đơn thuần chỉ là c *c = *a; *a = *b; *b = *c; } int main() { int m = 1; int n = 2; swap(&m, &n); cout 1 using namespace std; 3 int add(int a, int b=0, int c=0) 6 { C++ T r a n g | 80
  81. Đặng Ngọc Hoàng Thành return a+b+c; } int main() { cout 3 #include abcd using namespace std; int add(int a, int b) C++ T r a n g | 81
  82. Đặng Ngọc Hoàng Thành { return a+b; } string add(string a, string b) { return a+b; } int main() { cout<<add(1,2)<<endl; cout<<add(“ab”,”cd”)<<endl; return 0; } Giải thích: Hai hàm mà ta xây dựng cĩ cùng tên l{ add. H{m add đầu tiên cĩ chức năng cộng hai số. Hàm add thứ hai cĩ chức năng cộng hai xâu kí tự. Kiểu dữ liệu trả về và tham số hình thức của chúng cũng kh|c nhau. Hàm nội tuyến Chỉ định inline trước khai báo một hàm sẽ giúp trình dịch nhận biết h{m n{y được khai báo là nội tuyến. Khơng cĩ một sự thay đổi n{o đ|ng kể giữa h{m bình thường với hàm nội tuyến. Chỉ cĩ một điểm khác biệt duy nhất đĩ l{: với hàm nội tuyến, trình biên dịch sẽ khởi tạo một thân hàm và chèn nĩ vào vị trí được gọi tại mỗi thời điểm m{ h{m đĩ được gọi, thay vì nĩ chỉ chèn lời gọi hàm. Việc làm này sẽ cải thiện đ|ng kể tốc độ biên dịch chương trình. inline type tên_hàm(danh_sách_tham_số) { Thân hàm; } C++ T r a n g | 82
  83. Đặng Ngọc Hoàng Thành Trong hầu hết các trình biên dịch hiện đại, việc quy định hàm là inline là khơng cần thiết. Nếu một hàm cĩ thể sử dụng khai b|o inline, thì chương trình dịch sẽ tự động tối ưu m~ nguồn để cĩ thể sử dụng nĩ. Ngược lại, nếu một hàm khơng thể sử dụng khai báo inline, thì chương trình dịch sẽ bỏ qua khai báo này. Chỉ định inline chỉ cĩ tác dụng định hướng cho chương trình dịch. Hàm đệ quy H{m đệ quy là những hàm gọi lại chính nĩ. Nĩ hữu dụng trong các tác vụ như sắp xếp (Quicksort) hoặc tính tốn các biểu thức truy hồi, giải các bài tồn bằng giải thuật cùng tên H{m đệ quy tương ứng với khái niệm quy nạp trong tốn học. Ta cĩ thể sử dụng định nghĩa giai thừa theo quy nạp tốn học như sau { ( ) Và chúng ta cĩ thể xây dựng h{m đệ quy tương ứng với phép tính giai thừa n{y như sau Ví dụ Kết quả #include 6 using namespace std; long Fac(long a) { if(a>0) return a*Fac(a-1); else return 1; } int main() { C++ T r a n g | 83