Giáo trình Ngôn ngữ lập trình - Nghề kỹ thuật sửa chữa và lắp ráp máy tính Đà Lạt

pdf 50 trang Gia Huy 17/05/2022 2310
Bạn đang xem 20 trang mẫu của tài liệu "Giáo trình Ngôn ngữ lập trình - Nghề kỹ thuật sửa chữa và lắp ráp máy tính Đà Lạt", để 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:

  • pdfgiao_trinh_ngon_ngu_lap_trinh_nghe_ky_thuat_sua_chua_va_lap.pdf

Nội dung text: Giáo trình Ngôn ngữ lập trình - Nghề kỹ thuật sửa chữa và lắp ráp máy tính Đà Lạt

  1. LỜI TỰA Đây là tài liệu được xây dựng theo chương trình khung chương trình đào tạo trung cấp nghề Kỹ thuật Sửa chữa và lắp ráp máy tính Trong giai đoạn viết giáo trình chúng tôi cũng đã có những sự điều chỉnh để giáo trình có tính thiết thực và phù hợp hơn với sự phát triển của lĩnh vực công nghệ thông tin. Ngôn ngữ lập trình là một môn học đào tạo nghề Kỹ thuật Sửa chữa và lắp ráp máy tính trình độ trung cấp nghề trong lĩnh vực Công nghệ thông tin. Ngày nay, chúng ta có thể sản xuất ra các hệ thống phần mềm lớn và hữu ích là nhờ phần lớn vào sự phát triển của các ngôn ngừ lập trình. Trong phạm vi giáo trình Ngôn ngữ lập trình này, chúng tôi giới thiệu sơ lược về ngôn ngữ lập trình C++ cho các học sinh sinh viên đã có kiến thức căn bản về công nghệ thông tin. Giới thiệu những vấn đề cơ bản nhất về ngôn ngữ C++. Giới thiệu cho người đọc hiểu được công dụng của ngôn ngữ lập trình, hiểu cú pháp, công dụng của các câu lệnh dùng trong ngôn ngữ lập trình. Phân tích được chương trình: xác định nhiệm vụ chương trình (phải làm gì).Vận dụng điều kiện, trợ giúp môi trường của ngôn ngữ lập trình, chẳng hạn: các thao tác biên tập chương trình, các công cụ, điều khiển, thực đơn lệnh trợ giúp, gỡ rối, bẫy lỗi,v.v.Viết chương trình và thực hiện chương trình trong máy tính. Trong quá trình biên soạn, mặc dù đã cố gắng tham khảo nhiều tài liệu và giáo trình khác nhưng tác giả không tránh khỏi được những thiếu sót và hạn chế. Tác giả chân thành mong đợi những nhận xét, đánh giá và góp ý để cuốn giáo trình ngày một hoàn thiện hơn. Mọi thông tin đóng góp xin gửi thư điện tử về địa chỉ ngothienhoang@cdndalat.edu.vn Tài liệu này được thiết kế theo từng mô đun/ môn học thuộc hệ thống mô đun/môn học của một chương trình, để đào tạo hoàn chỉnh nghề Kỹ thuật Sửa chữa và lắp ráp máy tính ở cấp trình độ trung cấp nghề và được dùng làm Giáo trình cho học sinh sinh viên trong các khóa đào tạo, cũng có thể được sử dụng cho đào tạo ngắn hạn hoặc cho đào tạo công nhân kỹ thuật, các nhà quản lý và lập trình viên tham khảo. Đà lạt Tháng 06 năm 2012 Tác giả 1
  2. MỤC LỤC TRANG MỤC LỤC 2 BÀI 1 TỔNG QUAN VỀ NGÔN NGỮ LẬP TRÌNH 4 1.1 Giới thiệu 4 1.2 Thuật toán 5 1.3 Diễn đạt thuật toán 5 1.4 Chương trình 7 1.5 Giới thiệu C/C++ 7 1.6 Khởi động và thoát khỏi C++ 8 Bài tập 11 BÀI 2 CÁC THÀNH PHẦN CƠ BẢN 12 2.1 Hệ thống ký hiệu và từ khóa 12 2.2 Các Kiểu Dữ Liệu Cơ Bản Trong C++ 13 2.3 Biến, hằng, biểu thức 14 2.4 Các phép toán 18 2.5 Lệnh, khối lệnh 20 2.6 Câu lệnh gán, lệnh xuất nhập 21 2.7 Cách chạy chương trình 21 Bài tập 22 BÀI 3 CÁC LỆNH CẤU TRÚC 24 3.1 Câu lệnh if 24 3.2 Câu lệnh switch 25 3.3 Câu lệnh for 26 3.4 Câu lệnh while ( Lặp với điều kiện được kiểm tra trước ) 27 3.5 Câu lệnh do while ( Lặp với điều kiện được kiểm tra sau ) 28 3.6 Câu lệnh goto và nhãn 29 3.7 Các câu lệnh break, continue 29 3.8 Câu lệnh rỗng 29 3.9 Vòng lặp vô hạn 30 Bài tập 30 BÀI 4 HÀM 31 4.1 Khái niệm 31 4.2 Quy tắc xây dựng một hàm 31 4.3 Sử dụng hàm 32 4.4 Nguyên tắc hoạt động của hàm 33 4.5 Cánh truyền tham số 33 4.6 Câu lệnh return 34 4.7 Một số thư viện trong C++ 34 Bài tập 35 BÀI 5 KIỂU MẢNG 36 5.1 Khai báo mảng 36 5.2 Mảng và tham số 37 5.3 Sắp xếp mảng 37 5.4 Gán giá trị cho mảng 38 Bài tập 39 BÀI 6 CHUỖI KÝ TỰ 40 6.1 Khái niệm 40 6.2 Khai báo biến chuỗi 40 6.3 Nhập xuất xâu ký tự 40 6.4 Các phép toán chuỗi ký tự 41 6.5 Các thao tác trên chuỗi ký tự 41 2
  3. Bài tập 42 BÀI 7 BIẾN CON TRỎ 43 7.1 Biến con trỏ 43 7.2 Con trỏ và mảng 1 chiều 44 7.3 Con trỏ và xâu ký tự 45 7.4 Con trỏ và mảng nhiều chiều 46 Bài tập 47 TÀI LIỆU THAM KHẢO 50 3
  4. BÀI 1 TỔNG QUAN VỀ NGÔN NGỮ LẬP TRÌNH Mã bài : MH 13.1 Mục tiêu của bài: - Hiểu được lịch sử phát triển của ngôn ngữ - Biết được ngữ này có những ứng dụng thực tế như thế nào - Biết cách khởi động được và thoát khỏi chương trình. - Sử dụng được hệ thống trợ giúp từ help file 1.1 Giới thiệu Lập trình thực chất là điều khiển - bằng một ngôn ngữ lập trình cụ thể - các xử lý thông tin trên máy tính điện tử theo yêu cầu của bài toán đặt ra. Kết quả của lập trình là chương trình được hợp thức hóa. Thông tin gửi đến CT, CT xử lý, kết quả sẽ được gửi đi. Nhập Chương Trình Xuất Để lập trình phải biết cách tổ chức dữ liệu (cấu trúc dữ liệu) và cách thức xử lý dữ liệu( thuật toán ) để tạo ra chương trình mong muốn. K. Wirth đã đưa ra công thức : CHƯƠNG TRÌNH = CẤU TRÚC DỮ LIỆU + THUẬT TOÁN Có nhiều cách tổ chức dữ liệu cũng như có nhiều thuật toán để giải một bài toán . Đưa ra cách tổ chức dữ liệu tốt nhất và chỉ ra thuật toán tốt nhất là công việc của người lập trình. Các phương pháp lập trình thường được sử dụng là lập trình có cấu trúc và lập trình theo hướng đối tượng. Các phương pháp lập trình này phản ánh quan niệm lập trình là một hoạt động khoa học và có phương pháp chứ không phải là một công việc ngẫu hứng. Đặc trưng của lập trình có cấu trúc là chương trình phải có cấu trúc. Tính cấu trúc của chương trình thể hiện trên các mặt sau : Cấu trúc về mặt dữ liệu : Từ những dữ liệu đã có , có thể xây dựng những dữ liệu có cấu trúc phức tạp hơn. Cấu trúc về mặt lệnh : Từ những lệnh đơn giản đã có, có thể xây dựng được những lệnh có cấu trúc phức tạp hơn. Cấu trúc về mặt chương trình : Một chương trình lớn có thể phân rã thành nhiều modul (hay các chương trình con ) độc lập, mỗi chương trình con lại có thể chia ra thành các chương trình con khác nên chương trình được tổ chức thành một hệ phân cấp. Nhờ vậy mà một chương trình lớn, phức tạp được phân thành những modul chương trình đơn giản, dễ viết, dễ đọc, dễ sửa 4
  5. 1.2 Thuật toán 1.2.1 Định nghĩa trực quan thuật toán Thuật toán là dãy hữu hạn các thao tác, sắp xếp theo trình tự xác định, được đề ra nhằm giải quyết một lớp bài toán nhất định. Các thao tác sẽ biến đổi trạng thái bài toán trước khi thực hiện tháo tác thành trạng thái kết quả. Dãy tuần tự các thao tác trong thuật toán biến đổi trạng thái ban đầu của thuật toán thành trạng thái cuối cùng của bài toán. 1.2.2 Các đặc trưng của thuật toán Tính xác định. Tính dừng ( hữu hạn ). Tính đúng đắn. 1.2.3 Đặc tả thuật toán Đặc tả thuật toán ( hay đặc tả bài toán ) là định rõ lớp bài toán mà một thuật toán giải quyết, do đó nó cần chỉ ra các đặc điểm sau : 1. Các đối tượng và phương tiện của Thuật toán cần sử dụng (nhập). 2. Điều kiện ràng buộc (nếu có) trên các đối tượng và phương tiện đó. 3. Các sản phẩm, kết quả (xuất). 4. Các yêu cầu trên sản phẩm kết quả. Thường xuất hiện dưới dạng quan hệ giữa sản phẩm kết quả và các đối tượng, phương tiện sử dụng. Ta viết : INPUT : (1) và (2); OUTPUT : (3) và (4); 1.2.4 Độ phức tạp của Thuật toán Mỗi Thuật toán đều cần thời gian và các nguồn lực khác để giải quyết một bài toán cụ thể. Các tiêu hao đó đặc trưng độ phức tạp của thuật toán. Có nhiều thuật toán cùng giải một lớp bài toán, ta mong muốn có được thuật toán hiệu quả hơn, tức tiêu hao ít hơn một trong các loại nguồn lực. Đối với máy tính, ta quan tâm đến thời gian và kích thước bộ nhớ mà thuật toán sử dụng. 1.3 Diễn đạt thuật toán 1.3.1. Ngôn ngữ tự nhiên Mô tả các bước thực hiện của thuật toán dưới dạng văn bản bằng ngôn ngữ tự nhiên như tiếng Việt, Anh,. . . 5
  6. 1.3.2. Lưu đồ Sơ đồ toàn cảnh có cấu trúc biểu diễn các bước thực hiện của thuật toán, trong đó sử dụng các hình vẽ có quy ước sau: Mũi tên chỉ luồng lưu chuyển của dữ liệu. Bắt đầu, kết thúc Điểm bắt đầu, kết thúc Xử lý Hình chữ nhật biểu diễn các bước xử lý Nhập, Xuất Hình bình hành biểu thị nhập xuất Điều kiện Hình thoi biểu thị thời điểm ra quyết định Hình tròn biểu thị điểm ghép nối 1.3.3. Mã giả Dựa vào cú pháp và ngữ nghĩa của một ngôn ngữ lập trình nào đó (chẳng hạn C, Pascal, ). Cho nên mã giả cũng dựa trên các cơ sở sau đây: Ký tự Các từ Các xâu ký tự (Chuỗi) Hằng Biến Kiểu dữ liệu Lệnh gán Khối lệnh Các cấu trúc điểu khiên Câu lệnh trả về . . . 6
  7. 1.3.4. Ngôn ngữ lập trình 1.4 Chương trình 1.4.1. Khái quát về chương trình. Thuật toán phải được diễn đạt sao cho máy tính có thể hiểu và thi hành được. Ngôn ngữ lập trình ( programming language ) được sử dụng vào mục đích này. Ngôn ngữ lập trình là tập hợp các qui tắc chặt chẻ về cú pháp (syntax), về ngữ nghĩa (semantic) cho phép tạo ra các văn bản để diễn đạt thuật toán . Một văn bản như vậy gọi là chương trình ( program ). Chương trình viết bằng ngôn ngữ lập trình cấp cao gọi là chương trình nguồn (Source program ) Chương trình viết bằng ngôn ngữ máy gọi là chương trình đích (Target program ). Máy chỉ có thể thi hành chương trình dưới dạng ngôn ngữ máy, vì vậy chương trình nguồn muốn được khai thác phải được chuyển đổi thành chương trình đích tương đương. Chương trình có nhiệm vụ chuyển đổi chương trình nguồn thành chương trình đích tương đương được gọi là chương trình dịch. Có 2 loại dịch khác nhau : biên dịch ( Complier ) và thông dịch ( Interpreter). 1.4.2. Mã và dữ liệu Một chương trình bất kỳ bao gồm hai phần : mã và dữ liệu. Khi nạp một chương trình đã được dịch sang mã máy vào RAM, phần RAM chứa đọan mã máy là các lệnh thể hiện thao tác được gọi là code segment. Trong code segment chứa phần mã của chương trình. Phần RAM chứa các dữ liệu là đối tượng của các thao tác được gọi là data segment. Trong data segment chứa phần dữ liệu của chương trình. Trong các lần chạy khác nhau, chỉ có phần dữ liệu của chương trình là thay đổi, còn phần mã là không đổi. Data Biến toàn cục, Segment dữ liệu chương trình Code Mã chương trình Segment 1.5 Giới thiệu C/C++ Ý tưởng quan trọng nhất của C xuất phát từ ngôn ngữ BCPL do Martin Richards thiết kế. Anh hưởng của BCPL lên C gián tiếp thông qua ngôn ngữ B do Ken Thompson viết năm 1970 cho hệ thống UNIX đầu tiên trên máy PDP-7. 7
  8. Từ ngôn ngữ B, Dennish Ritchie và Brian Kernighan phát triển thành ngôn ngữ C vào những năm 1970 tại phòng thí nghiệm của hãng AT & T để phát triển cốt lõi của hệ điều hành UNIX. Trong nhiều năm, chuẩn cho C trên thực tế là một phiên bản được cung cấp cùng với hệ điều hành Unix version 5. Nó được mô tả lần đầu tiên trong cuốn : ” The C programming language “ của Dennish Ritchie và Brian Kernighan. Năm 1983 một hội đồng được thành lập để tạo ra một chuẩn cho C, gọi là chuẩn ANSI (American National Standards Institute : Viện định chuẩn Quốc gia Mỹ). Sau 6 năm, chuẩn cuối cùng ANSI C được đề nghị vào tháng 12/1989, và bản đầu tiên được dùng vào năm 1990. Ngày nay các trình biên dịch C chính đều giữ đúng theo ANSI chuẩn. C là một ngôn ngữ có khả năng tổ hợp những thành phần tốt nhất của ngôn ngữ bậc cao và sự điều khiển linh hoạt của ngôn ngữ assembly . Năm 1987 hãng Borland đã đưa ngôn ngữ C vào thị trường của IBM-PC thông qua Turbo C. Vào những năm 1980, Bjarne Stroustrup đã cho ra đời ngôn ngữ C++ bằng cách cài vào ngôn ngữ C khái niệm lập trình hướng đối tượng. Năm 1988, hãng Zortech giới thiệu một trình biên dịch C++ cho các máy tính MS-DOS. Cho tới nay đã xuất hiện nhiều phiên bản C++ trong môi trường Microsoft Windows: Borland C++, Turbo C++ của hãng Borland; Visual C++ của Microsoft. Hiện nay có nhiều chương trình lớn được viết hay được viết lại bằng C/C++: Hệ điều hành UNIX. Hệ điều hành Windows. Hệ quản trị cơ sở dữ liệu Dbase. Các chương trình soạn thảo văn bản. Các bảng tính điện tử. . . . 1.6 Khởi động và thoát khỏi C++ Sử dụng Turbo C++ 3.0 để thực hiện việc cài đặt. Ta thực hiện việc chuyển thư mục đến thư mục chứa tập tin cài đặt. Chẳng hạn E:\SOFT\TC30. Và gõ lệnh Install Ví dụ: CD E:\SOFT\TC30 Install Sau khi cài đặt TC xong sẽ nằm trong thư mục C:\TC Cửa sổ soạn thảo của TC như hình sau 8
  9. Hình 1: Cửa sổ soạn thảo của TC *Menu - Thanh đầu tiên là thanh Menu. Để mở thanh menu ta nhấn phím F10 sau đó dùng phím mũi tên qua lại để đưa đến mục chọn thích hợp nhấn phím Enter; - Dùng phím mũi tên lên xuống để chọn mục chọn thích hợp, xong nhấn Enter. * Cửa sổ soạn thảo Cửa sổ soạn thảo là chứa tiêu đề là tên tập tin như ở hình vẽ là VIDU.CPP. Chúng ta sẽ soạn thảo chương trình vào trong cửa sổ này và nhớ rằng mỗi một chương trình hay mođun chứa trong một tập tin, nghĩa là tập tin không được chứa 2 chương trình mà chỉ được chứa một chương trình. Để phóng to cửa sổ , ta nhấn phím F5. Để chuyển qua lại các cửa sổ, ta gõ F6. Để đóng cửa sổ, ta gõ Alt+F3. * Làm việc với tập tin - Lưu tập tin đang soạn thảo: Khi lưu trữ tập tin lần đầu thì hộp thoại như trên sẽ hiện ra. Gõ vào tên tập tin cần lưu trữ. Mặc định TC C++ 3.0 sẽ tự động thêm vào phần mở rộng .CPP. Sau khi lưu trữ tên tập tin sẽ được đưa và tiêu đề cửa sổ soạn thảo của chương trình. Hãy chú ý đường dẫn cuối hộp thoại, chúng ta có thể chọn lại đường dẫn bằng cách nhấn phím Tab cho thanh sáng ở trong danh sách, dùng mũi tên lên xuống để di chuyển đến thư mục cần chọn. Thư mục có tên \ là thư mục cha, ta có thể di chuyển ra ngoài thư mục cha bằng cách chọn mục này và nhấn phím Enter. Hình 2: Hộp thoại khi lưu trữ tập tin lần đầu Mở tập tin đã lưu trữ: Nhấn phím F3 9
  10. Hình 3: Mở tập tin đã lưu trữ Nhấn phím Tab để điểm sáng nằm bên danh sách và dùng phím mũi tên để chọn tập tin chương trình cần mở. Nhấn Enter. Trong quá trình mở tập tin, chúng ta chú ý đường dẫn ở dưới cùng của hộp thoại. - Có thể tạo thư mục cần lưu trữ tập tin vào thư mục do chúng ta tạo ra. Bằng những thao tác sau: Trong Turbo C++, chọn Menu File/DOS Shell, màn hình DOS sẽ hiện ra, ta tiến hành tạo thư mục. Tạo thư mục xong gõ lệnh Exit để vào lại Turbo C++. Vào Menu File/Change Dir để thay đổi mặc định lưu trữ tập tin và thư mục. Và hộp thoại như sau hiện ra. Nhấn phím Tab để di chuyển điểm sáng sang cây thư mục. Chọn thư mục cần chuyển, nhấn Enter. Nhấn phím Tab để di chuyển điểm sáng đến nút OK và nhấn phím Enter. Công việc này nên được làm lần đầu tiên vào trong Turbo C++ để việc lưu tập tin và mở tập tin cho chính xác. * Các thao tác soạn thảo Copy nội dung: Di chuyển nội dung: * Các tài liệu sẵn có: - Để tra cứu hướng dẫn, nhấn F1. - Để tra cứu hướng dẫn dành cho từ con trỏ đang đứng, ta gõ Ctrl+F1. * Các thao tác biên dịch và chạy chương trình - Biên dịch chương trình ta nhấn: F9. Để chạy chương trình ta nhấn: Ctrl + F9. - Để xem kết quả chương trình ta nhấn Alt + F5. - Nhấn Alt+X hoặc File/Exit để thoát khỏi chương trình. Những tập tin nào chưa được lưu trong quá trình soạn thảo,chương trình sẽ hỏi có lưu tập tin đó không? Nếu muốn lưu trước khi thoát thì chọn Yes, Không thì chọn No. Muốn huỷ việc thoát khỏi TC thì chọn Cancel. Thao tác chọn được thực hiện bằng phím Tab. Hình 4: Hộp thoại hỏi có lưu tập tin hay không? 10
  11. Bài tập 1. Sử dụng sơ đồ khối để thiết kế thuật toán cho bài toán giải phương trình bậc 2: ax2 + bx + c = 0. 2. Sử dụng Turbo C++ 3.0 để thực hiện việc cài đặt và cấu hình 11
  12. BÀI 2 CÁC THÀNH PHẦN CƠ BẢN Mã bài : MH 13.2 Mục tiêu của bài: - Hiểu và sử dụng được hệ thống kí hiệu và từ khóa - Hiểu được các kiểu dữ liệu - Hiểu được và vận dụng được các loại biến, hằng biểu thức cho từng chương trình cụ thể. - Biết, hiểu và so sánh được các lệnh, khối lệnh - Thực hiện được việc chạy chương trình 2.1 Hệ thống ký hiệu và từ khóa 2.1.1 Ký hiệu cơ sở Ngôn ngữ C++ được xây dựng từ bộ ký hiệu cơ sở sau: Bộ 26 chữ cái La-Tinh viết thường (nhỏ): a,b, ,z. Bộ 26 chữ cái La-Tinh viết hoa (lớn): A,B, ,Z. Bộ 10 chữ số hệ thập phân : 0,1, ,9. Bộ dấu các toán tử số học : + - * / Bộ dấu các toán tử so sánh: = Ký tự gạch nối: _ ( Khác dấu trừ - ). Các ký hiệu khác: ' " ; ,.: [ ] # $ & { } % ! . . . Đặc biệt có khoảng trắng dùng để ngăn cách các từ (phím Space). Các ký hiệu cơ sở đều có trên bàn phím. 2.1.2 Các từ Từ trong C++ được xây dựng bởi các ký hiệu cơ sở trên. Có 2 loại từ:Từ khóa và tên. a. Từ khóa (Key Word) Là những từ có ý nghĩa hoàn toàn xác định, chúng thường được dùng để khai báo các kiểu dữ liệu, để viết các toán tử, và các câu lệnh. Sau đây là các từ khóa trong Borland C++ (Turbo C++): Asm auto break Case catch char class const continue Default delete do double else enum Extern float for friend goto if Inline int long new operator private Protected public register return short signed Sizeof static struct switch template this Throw try typedef union unsigned virtual Void volatile while cdecl _cs _ds _es _export far 12
  13. huge interrupt _loadds Near pascal _regparam _saveregs _seg _ss b. Tên hoặc danh hiệu (identifier): Là từ do người sử dụng tự đặt để giải quyết bài toán của mình. Từ tự đặt dùng để đặt tên cho hằng, biến, hàm, tên kiểu dữ liệu mới, Tên được đặt theo quy tắc: phải bắt đầu bằng một chữ cái hoặc dấu gạch nối,sau đó là các chữ cái, chữ số hoặc dấu gạch nối, và không được trùng với từ khóa. Tên có thể viết bằng chữ thường hoặc chữ hoa. Trong C++ có phân biệt chữ thường và chữ hoa. 2.2 Các Kiểu Dữ Liệu Cơ Bản Trong C++ Trong C++ có 5 kiểu dữ liệu cơ bản là: Các kiểu Ký tự. Các kiểu nguyên. Kiểu Số thực dấu chấm động độ chính xác đơn Kiểu Số thực dấu chấm động độ chính xác kép Kiểu void. Các kiểu dữ liệu khác đều dựa vào các kiểu dữ liệu trên. 2.2.1 Ký tự a. Ký tự 8 bit Một giá trị ký tự có kiểu dữ liệu khai báo bằng từ khóa char, được lưu trử trong 8 bit và biểu diễn thông qua bảng mã ASCII . Chẳng hạn : Ký tự Mã ASCII (hệ 10) 0 48 1 49 A 65 a 97 . . . . Có các kiểu ký tự 8 bit tương ứng với các từ khóa : signed char ( như char, có dấu) unsigned char (Không dấu). Sau đây là bảng kích thước, phạm vi biểu diễn của các kiểu ký tự : KIỂU Phạm vi biểu diễn Kích thước Số ký tự Char -128 127 1 byte 256 signed char -128 127 1 byte 256 unsigned char 0 255 1 byte 256 b. Ký tự UNICODE Các ký tự Unicode trong C/C++ được định nghĩa bởi : wchar_t Mỗi ký tự Unicode rộng 16 bit. c. Kiểu TCHAR Dùng chung cho char và wchar_t ( cho ký tự 8 bit hay unicode 16 bit). 13
  14. 2.2.2 Kiểu nguyên Trong C++ cho phép sử dụng các kiểu số nguyên được khai báo bởi từ khóa int, hoặc đi kèm theo int với các từ khóa long, short, unsigned. Số lượng bit được dùng để lưu trử một giá trị int phụ thuộc vào kích thước từ (word) của máy. Thường thì máy 16-bit sẽ dùng 16 bit để lưu trử một giá trị int , trong khi đó máy 32-bit sẽ dùng 32 bit . Kích thước và phạm vi biểu diễn của chúng được cho trong bảng sau : Kiểu Phạm vi biểu diễn Kích thước Int Chiếm 1 từ của máy short int , short -32768 32767 (-215 215 -1) 16 bit unsigned short int 0 65535 (0 216 -1) 16 bit long int , long -2147483648 2147483647 32 bit (-231 231 -1 ) unsigned long int 0 4294967295 ( 0 232 -1) 32 bit unsigned int Số nguyên không âm , chiếm 1 từ của máy. 2.2.3 Kiểu số thực C++ cho phép sử dụng 3 kích thước giá trị thực, tương ứng với 3 từ khóa : float double long double Kích thước và phạm vi biểu diễn của chúng được cho trong bảng sau : Kiểu Ý nghĩa Phạm vi biểu diễn Kích Độ chính thước xác float Số thực chính -3.4E+38 3.4E+38 32 bit 6 số thập xác đơn phân double Số thực chính -1.7E+308 1.7E+308,0 64 bit 10 số thập xác kép phân long Kích thước 96 bit hoặc 128 bit double 2.3 Biến, hằng, biểu thức 2.3.1. Định nghĩa Hằng là các đại lượng mà giá trị của nó không thay đổi trong quá trình tính toán. Ta thường dùng các ký tự hoa để biểu diễn các hằng ký hiệu. 2.3.2 Các loại hằng Trong C++ có các loại hằng sau đây: 1. Hằng số thực Giá trị được lấy là float và double. Viết theo 2 cách : a. Dạng thập phân (dấu chấm cố định) : 14
  15. Bao gồm : Phần nguyên, dấu chấm thập phân, phẩn phân. Phần nguyên Phần phân b. Dạng khoa học hay dạng mũ ( dấu chấm động ) Có 3 thành phần : Phần định trị , ký hiệu E hoặc e , và phần bậc. Phần định trị là một số nguyên hoặc số thực dạng thập phân. Phần bậc là một số nguyên. Hai phần này cách nhau bởi ký tự E hoặc e. Phần định trị E hoặc e Phần bậc Ví dụ : 12.234E-3 // biểu diễn giá trị 0.012234 0.35E4 // biểu diễn giá trị 3500.0 -12.22e-3 // biểu diễn giá trị -0.01222 1e6 // biểu diễn giá trị 1 000 000 2. Hằng nguyên a. Hằng int Là số nguyên có kiểu int . b. Hằng long Biểu diễn : thêm L hoặc l vào sau hằng int. c. Hằng unsigned Biểu diễn : thêm u vào sau hằng int. Có giá trị từ 0 đến 65535. d. Hằng int hệ 8 Hằng int hệ 8 luôn nhận giá trị dương. Dạng biểu diễn : 0c1c2c3 Với : ci là một số nguyên trong khoảng từ 0 đến 7. Ví dụ : Hằng int hệ 8 : 0345 Giá trị của nó trong hệ 10 : 3*8*8 + 4*8 + 5 = 229. e. Hằng int hệ 16 : Trong hệ này sử dụng 16 ký tự : 0,1,2,3,4,5,6,7,8,9, a hoặc A b hoặc B c hoặc C d hoặc D e hoặc E f hoặc F Dạng biểu diễn : 0x c1c2c3 hoặc 0X c1c2c3 Trong đó ci là một chữ số hệ 16. Ví dụ : Các hằng nguyên hệ 16 : 0xa3 ; 0Xa3 ; 0xA3 ; 0XA3 là như nhau. Giá trị của nó trong hệ 10 là : 10*16 + 3 = 163. 15
  16. 2.3.3 Hằng ký tự Là một ký tự được viết trong 2 dấu nháy đơn. Chẳng hạn ‘a’ , ‘A’, ‘3’, ‘+’ . . . Trình biên dịch của C++ sẽ lưu trử các hằng này bằng cách dùng các mã số ASCII (hệ 10) của nó, tương ứng là 97,65, 43, 51 . . . Ký tự có thể biểu diễn bởi hệ 8: Cách viết : ‘\c1c2c3’ , trong đó ci là các ký hiệu trong hệ 8. Ký tự có thể biểu diễn bởi hệ 16: Cách viết : ‘\xc1c2c3’ hoặc ‘\Xc1c2c3’ trong đó ci là các ký hiệu trong hệ 16. Ký tự Hệ 8 Hệ 16 Mã ASCII Mã ASCII Biểu diễn Mã ASCII Biểu diễn hệ 10 ‘a’ 141 ‘\141’ 61 ‘\x61’ 97 ‘A’ 101 ‘\101’ 41 ‘\x41’ 65 Đối với một số hằng ký tự đặc biệt, ta sử dụng cách viết sau (thêm dấu \) : Cách viết Ký tự ‘\’ ’ ‘ ‘\” ‘ “ ‘\\’ \ ‘\n’ \n (chuyển dòng) ‘\0’ \0 (NULL) ‘\t’ Tab ‘\b’ Backspace ‘\r’ CR (Về đầu ‘\f’ LFdòng) (sang trang) Ghi chú : Hằng ký tự có thể tham gia vào các biểu thức như mọi số nguyên khác. Ví dụ : ‘9’ -’0’ = 57 -48 = 9 Cần phân biệt : ‘0’ : là ký số 0 có mã ASCII hệ 10 là 48. ‘\0’ : là ký tự NULL có mã ASCII hệ 10 là 0. 2.3.4 Hằng xâu ký tự ( Chuỗi ) Là một dãy ký tự được bao trong 2 dấu nháy kép. Ví dụ : 16
  17. “Da Lat” “” // Xâu rổng Ghi chú : Xâu ký tự được lưu trử trong máy dưới dạng một mảng các ký tự. Trình biên dịch tự động thêm ký tự NULL ‘\0’ ( được xem là dấu hiệu kết thúc xâu ) vào cuối mỗi xâu. 2.3.5 Biểu thức hằng Biểu thức hằng chỉ bao gồm các hằng. Các biểu thức như vậy được xác định vào lúc biên dịch. 2.3.6 Định nghĩa một hằng Dùng chỉ thị #define ( Có thể định nghĩa lại giá trị hằng ) : Cách viết : #define TÊN-HẰNG GIÁ_TRỊ_HẰNG Tác dụng : TÊN-HẰNG sẽ được thay thế bởi GIÁ_TRỊ_HẰNG cho phần còn lại của văn bản chương trình. Ví dụ : #define MAX 100 // Thay thế MAX bằng 100 Dùng từ khóa const ( Không định nghĩa lại được giá trị hằng ) o Cú pháp : Const kiểu TÊN-HẰNG = GIÁ_TRỊ_HẰNG; o Tác dụng : Cho phép định nghĩa một hằng ký hiệu có tên là TÊN- HẰNG biểu thị một gia trị là GIÁ_TRỊ_HẰNG và sau này không thể sửa đổi GIÁ_TRỊ_HẰNG của TÊN-HẰNG được . Ví dụ : Const double PI = 3.1416; 2.3.7 Biến 2.3.7.1 Định nghĩa Biến là một phần bộ nhớ được đặt tên, được dùng, để giữ một giá trị mà có thể thay đổi trong chương trình. Vậy biến gắn với tên và kiểu dữ liệu, có giá trị thay đổi trong quá trình tính toán. 2.3.7.2 Khai báo biến Mỗi biến phải được khai báo trước khi sử dụng. Cú pháp khai báo như sau: Khai báo một biến: Kdl Bien; Khai báo nhiều biến cùng một kiểu: Kdl Bien1, Bien2, Bien3; Trong đó: - Kdl là kiểu dữ liệu nào đó như char, int, double, - Bien, Bien1, là tên chỉ tên của biến. Giữa Kdl và Tên biến phải cách nhau ít nhất 1 khoảng trắng. Trong phần tên biến, nếu có nhiều biến thì giữa 2 biến phải tách ra bởi dấu phảy (,). 2.3.7.3 Khởi đầu cho các biến Nếu trong khai báo, ngay sau tên biến ta đặt dấu = (phép gán ) và một giá trị dữ liệu tương ứng thì đó chính là cách vừa khai báo vừa khởi đầu cho 1 biến. 17
  18. 2.3.7.4 Lấy địa chỉ cho biến: Mỗi biến được cấp phát một vùng nhớ gồm một số byte liên tiếp. Số hiệu của byte đầu chính là địa chỉ của biến. Để nhận địa chỉ biến ta dùng toán tử & với cú pháp: &Bien. 2.4 Các phép toán Trong C++ có các loại toán tử: phép gán, các toán tử số học, các toán tử quan hệ và logic, các toán tử thao tác trên Bit 2.4.1 Các toán tử số học: C++ có 8 toán tử số học: Toán tử Ý nghĩa Ví dụ Ghi chú - Lấy đối -a ; -(a+b) Toán tử 1 ngôi Tự giảm dần x Toán tử 1 ngôi ++ Tự tăng dần ++x Toán tử 1 ngôi + Cộng a + b Toán tử 2 ngôi - Trừ a –b Toán tử 2 ngôi * Nhân a * b Toán tử 2 ngôi / Chia a /b Toán tử 2 ngôi % Chia lấy phần dư a%b Toán tử 2 ngôi Thứ tự ưu tiên các toán tử số học: Ưu tiên của các toán tử số học được cho trong bảng sau đây theo thứ tự từ trên xuống dưới. Các toán tử cùng độ ưu tiên sẽ được thực hiện từ trên trái sang phải. Ưu tiên Toán tử 1 ++ - 2 * / % 3 + - 2.4.2 Toán tử quan hệ và logic Các toán tử quan hệ và logic thường được sử dụng chung với nhau, được dùng để tạo ra các kết quả đúng, sai. Trong C++, mọi số khác 0 đều được coi là giá trị đúng (true), giá trị duy nhất sai (false) mang hình thức số 0. 2.4.2.1 Các toán tử quan hệ Các toán tử quan hệ được dùng để so sánh 2 giá trị với nhau. Sau đây là bảng các toán tử quan hệ và ý nghĩa của chúng: Toán tử Ý nghĩa Ví dụ > Lớn hơn a > b 3>7 có giá trị 0 >= Lớn hơn hay bằng a >= b 3 >= 7 có gía trị 0 < Nhỏ hơn a < b 3<7 có giá trị 1 <= Nhỏ hơn hay bằng a <= b 3 <= 7 có gía trị 1 == Bằng nhau a == b 3 == 7 có giá trị 0 != Khác nhau a != b 3 != 7 có giá trị 1 2.4.2.2 Các toán tử logic Các toán tử logic được dùng để nối kết hai giá trị, hoặc trong trường hợp phủ định sẽ tạo một giá trị đảo ngược. Các giá trị có thể nguyên hay thực. Trong C++ có 3 toán tử logic: Phép phủ định 1 ngôi: ! 18
  19. Phép và (AND): && - Phép hoặc (OR): || Ý nghĩa của các toán tử được cho trong bảng sau: A B !a a&&b a||b Khác không (1) Khác không (1) 0 1 1 Khác không (1) Bằng không 0 0 1 Bằng không Khác không (1) 1 0 1 Bằng không Bằng không 1 0 0 2.4.2.2.3 Thứ tự ưu tiên của các toán tử quan hệ và logic Ưu tiên Toán tử 1 ! 2 > >= > Dịch phải (Shift right) a>>4 ~ Lấy phần bù theo bit (Not ) ~a 2.4.4 Các toán tử khác 2.4.4.1 Toán tử sizeof Toán tử sizeof cho ta kích thước ( tính theo byte) của 1 kiểu dữ liệu cũng như một đối tượng dữ liệu. Cách viết toán tử như sau: sizeof (kiểu dữ liệu) sizeof (đối tượng dữ liệu) Kiểu dữ liệu có thể là các kiểu chuẩn như int, float hoặc kiểu dữ liệu được định nghĩa bằng từ khóa typedef. Đối tượng dữ liệu có thể là biến, mảng, cấu trúc, (tên của vùng nhớ dữ liệu). 2.4.4.2 Toán tử ( ) Dùng để xác định trình tự ưu tiên các thành phần trong biểu thức. Nếu có nhiều toán tử () lồng nhau thì thực hiện ưu tiên từ trong ra ngoài. Nếu có nhiều toán tử () rời nhau thì thực hiện từ trái sang phải. 2.4.4.3 Toán tử dấu phẩy ‘ , ‘ (Comma operator) Được dùng để tạo sự thi hành tuần tự cho các thao tác, thường dùng trong câu lệnh for hay biểu thức vế phải của câu lệnh gán. Trong vế phải câu lệnh gán, thì giá trị toàn thể biểu thức là giá trị của biểu thức cuối cùng trong danh sách các biểu thức được tách biệt bởi dấu phảy. 19
  20. 2.5 Lệnh, khối lệnh Một chương trình C++ có thể gồm nhiều tập tin chương trình nguồn, mỗi tập tin chương trình là một văn bản chứa một dãy các chỉ thị và các chỉ thị điều khiển biên dịch. Các chỉ thị được phân thành 2 loại: Chỉ thị kiểu: Gồm định nghĩa các kiểu dữ liệu mới, biến, hằng và hàm. Chỉ thị thực hiện (câu lệnh): Được định nghĩa bằng những phép toán hay việc xử lý thực hiện trên các biến của chương trình. Tất cả các chỉ thị đều phải kết thúc bằng dấu ; ( chấm phẩy). Cả 2 loại chỉ thị này có thể hợp với nhau bằng một cú pháp qui định để hình thành một chỉ thị duy nhất được gọi là khối lệnh. Một khối lệnh được đặt trong cặp dấu ngoặc nhọn: { các chỉ thị } Sơ đồ tổng quát của chương trình C++ Dạng thức tổng quát: // Các chỉ thị điều khiển biên dịch // Các định nghĩa toàn cục // Khai báo nguyên mẫu các hàm // Hàm main int main() // void main() { // dãy tuần tự các lệnh } //Phần định nghĩa hàm. KDL Ham(Danh_Sach_Cac_Doi) { // dãy tuần tự các lệnh } . . . . . Một số quy tắc cần nhớ khi viết chương trình Quy tắc 1: Mỗi dòng có thể viết 1 hay nhiều chỉ thị. Quy tắc 2: Mỗi chỉ thị phải kết thúc bằng dấu chấm phẩy (;). Quy tắc 3: Quy tắc viết lời giải thích. Các lời giải thích viết: - Trên nhiều dòng, một dòng hoặc trên 1 phần của dòng phải đặt vào giữa các dấu /* và */. - Trên một dòng hoặc trên phần còn lại của một dòng phải đặt sau // Các lời giải thích được trình biên dịch bỏ qua. Quy tắc 4: Quy tắc sử dụng các hàm chuẩn: Trước khi sử dụng một hàm chuẩn nào cần phải biết nó nằm trong tập tin thư viện nào của C++ để khai báo, và khai báo bằng chỉ thị biên dịch #include: #include // không có dấu chấm phẩy như câu lệnh Chẳng hạn, khi sử dụng hàm cout, cin. Vì các hàm này nằm trong thư viện vào ra chuẩn iostream.h, nên ta cần khai báo: #include 20
  21. 2.6 Câu lệnh gán, lệnh xuất nhập Lệnh gán : Có dạng: b = bt; Trong đó b là biến. bt là một biểu thức ( một công thức toán học nào đó). Trước tiên tính biểu thức bt và sau đó gán giá trị tính được cho biến b. Lệnh xuất nhập : 1. Nhập dữ liệu từ bàn phím : Lệnh nhập có thể mô tả như sau: cin >> Bien; //Nhập giá trị 1 biến cin >> Bien1 >> Bien2 >> >> Bienn;//Nhập giá trị n biến. Trong đó: cin là đối tượng được khai báo trong . >> là toán tử nhập. Biến-i là biến mà đối với loại của nó >> được định nghĩa. 2. Xuất dữ liệu ra màn hình : Lệnh xuất có thể mô tả như sau: cout . int main() { cout<<"Chuong trinh C++ dau tien trong moi truong Windows!\n"; return 0; } Chương trình sẽ xuất ra màn hình chuỗi sau: Chuong trinh C++ dau tien trong moi truong Windows! 21
  22. Bài tập Bài 1: Viết chương trình khai báo 3 biến : x kiểu số thực, c kiểu ký tự, i kiểu số nguyên.Nhập, xuất giá trị cho các biến đó. Bài 2: Viết chương trình nhập vào 2 biến số nguyên x, y. Tính giá trị của x+y, xuất kết quả ra màn hình Hướng dẫn: - Khai báo 3 biến kiểu số nguyên: x,y và z (z: là biến lưu kết quả). - Nhập giá trị cho x,y. - Thực hiện phép gán: z = x+y. - Xuất giá z ra màn hình. Bài 3: Viết chương trình tính chu vi, diện tích của hình chữ nhật với chiều dài, rộng nhập từ bàn phím. Bài 4: Khai báo hằng PI có giá trị 3.14 sử dụng hằng PI để tính diện tích hình tròn với bán kính được nhập từ bàn phím. Bài 5: Khai báo hằng MAX có giá trị 60. Nhập số giây, quy đổi thời gian giây thành giờ, phút, giây. Xuất kết quả ra màn hình dưới dạng: gio:phut:giay Ví dụ: số giây nhập = 3770 - số giờ =(số_giây_nhập)/3600 = 1 - số phút = (số_giây_nhập%3600)/MAX=2 - số giây =( số_giây_nhập %3600)%MAX=50 Xuất ra màn hình dưới dạng: 1:2:50 Hướng dẫn: - Khai báo 4 biến kiểu số nguyên. - Nhập vào số giây. - Thực hiện phép toán quy đổi. - Xuất kết quả ra màn hình. Bài 6: Khai báo biến x, y kiểu số nguyên. Khởi gán x =20, y=6. Thực hiện các câu lệnh sau và xuất kết quả của x, y trước và sau khi thực hiện từng câu lệnh này. x++ x ++x x x=x/y y= x%y x=x*y Bài tập 7: Viết chương trình nhập vào một số nguyên và xuất ra màn hình (Chú ý: bạn hãy nhập số lớn và giải thích kết quả). Bài 8: Viết chương trình tính và xuất ra diện tích tam giác: (Sử dụng hàm tính căn bậc 2: sqrt trong thư viện math.h) Bài 9: Viết chương trình tính x2 + y5 , với x và y là 2 số thực được nhập từ bàn phím. (Sử dụng hàm tính tính mũ: pow trong thư viện math.h) 22
  23. Bài 10: Viết chương trình tính xn , với x là số thực và n là số nguyên được nhập từ bàn phím. (Sử dụng hàm tính tính mũ: pow trong thư viện math.h) 23
  24. BÀI 3 CÁC LỆNH CẤU TRÚC Mã bài: MH 13.3 Mục tiêu của bài: - Hiểu và vận dụng được các lệnh cấu trúc : cấu trúc lựa chọn, cấu trúc lặp xác định và lặp vô định. - Hiểu và vận dụng được các lệnh bẻ vòng lặp 3.1 Câu lệnh if 3.1.1 Cú pháp Dạng 1: if (Bt) Nếu biểu thức Bt đúng Kl thực hiện Kl Dạng 2: if (Bt) Nếu biểu thức Bt đúng Kl1 thực hiện Kl1 else Ngược lại Kl2 thực hiện Kl2 Bt: là biểu thức có giá trị Đ ( khác 0), hay sai (bằng 0). Kl: Khối lệnh. 3.1.2 Hoạt động Trước tiên biểu thức Bt được xác định giá trị. Dạng 1: Nếu Bt đúng (có giá trị khác 0) thì thực hiện Kl. Nếu sai (giá trị bằng 0) thì khối lệnh được bỏ qua. Dạng 2: Nếu Bt đúng (có giá trị khác 0) thì thực hiện Kl1. Nếu sai (giá trị bằng 0) thì thực hiện Kl2. 3.1.3 Lưu đồ: 1 1 0 B B Kl1 Kl2 Kl 0 Ghi chú: 24
  25. Nếu có nhiều cấu trúc if - else lồng nhau, để xác định một "else" là của "if" nào ta theo qui tắc: "else" là của một "if" gần với nó nhất mà không có "else". Tức là: Tương đương với: if (Bt1) if (Bt1) if (Bt2) { if (Bt2) Kl2 Kl2 else else Kl3 Kl3 else } Kl1 else Kl1 3.2 Câu lệnh switch Câu lệnh cho phép chọn một trong nhiều nhánh rẽ. 3.2.1 Cú pháp switch (Bt) { case H1: NL1 [ break;] case H2: NL2 [ break;] case Hn: NLn [ break;] [default: NLn+1] } Trong đó Bt là nguyên, các Hk có thể là hằng nguyên, hằng ký tự, hoặc biểu thức hằng. 3.2.2 Hoạt động của câu lệnh switch Trước tiên biểu thức nguyên được tính trị. Nếu trị biểu thức bằng Hk thì máy sẽ thực hiện NLk. Sau đó: - Nếu không có câu lệnh break thì thực hiện tiếp NL k+1 của nhãn case Hk+1 cho tới khi gặp lệnh break hoặc gặp dấu } cuối cùng thì ra khỏi switch. - Nếu có câu lệnh break thì ra khỏi switch. Khi giá trị biểu thức khác tất cả các Hk thì: - Khi có default thì máy nhảy tới thực hiện NLn+1 trong default. - Khi không có default thì ra khỏi câu lệnh switch. 3.2.3 Lưu đồ: (Có thành phần default) a) Không có câu lệnh break cuối mỗi nhóm lệnh 25
  26. b) Có câu lệnh break cuối mỗi nhóm lệnh: 3.3 Câu lệnh for 3.3.1 Cú pháp Câu lệnh for cho ta một cách xây dựng vòng lặp, có dạng sau: for(bt1 ; bt2 ; bt3) Khối lệnh // Câu lệnh Trong đó: 26
  27. Mỗi thành phần bt là một biểu thức hay là một dãy các biểu thức được phân tách bởi dấu phảy. Bất kỳ một thành phần nào trong 3 thành phần bt cũng có thể vắng mặt, nhưng các dấu chấm phảy (;) luôn luôn có. Chức năng của các thành phần bt thường là: bt1 là một phép gán để tạo ra giá trị ban đầu cho biến điều khiển. bt2 là một một quan hệ logic biểu thị điều kiện để tiếp tục vòng lặp. bt3 là một phép gán dùng để thay đổi giá trị của biến điều khiển. 3.3.2 Hoạt động của câu lệnh for Hoạt động theo các bước: 1. Xác định biểu thức 1. 2. Xác định biểu thức 2. bt1 3. Căn cứ vào giá trị đúng ( khác 0), sai ( bằng 0), sẽ lựa chọn một trong 2 0 bt2 nhánh: - Nếu biểu thức 2 sai , sẽ ra khỏi câu 1 lệnh for và chuyển đến câu lệnh sau KL thân for. - Nếu biểu thức 2 đúng, sẽ thực hiện các bt3 câu lệnh trong thân for.Khi gặp dấu ngoặc nhọn đóng } cuối cùngcủa thân for,hoặc gặp câu lệnh continue máy sẽ chuyển sang bước 4 (khởi đầu lại ). 4. Tính biểu thức 3, sau đó quay trở lại bước 2 để bắt đầu một vòng mới của vòng lặp. 3.4 Câu lệnh while ( Lặp với điều kiện được kiểm tra trước ) 3.4.1 Cú pháp while (Bt) Kl // Thân vòng lặp Trong đó: Bt có thể là 1 biểu thức hay là một dãy các biểu thức được phân tách nhau bởi dấu phảy. Giá trị của Bt là Đúng (khác 0) hoặc sai ( bằng 0). 3.4.2 Lưu đồ 27
  28. Ngữ nghĩa: Trong khi Bt còn đúng Thực hiện Kl 1 Bt 0 Kl 3.4.3 Hoạt động của câu lệnh while Theo trình tự: 1. Xác định giá trị của bt. 2. Tùy thuộc vào tính đúng sai của bt, máy sẽ lựa chọn 1 trong 2 nhánh: a. Nếu bt có giá trị 0 ( sai ) máy sẽ ra khỏi vòng lặp và chuyển tới câu lệnh sau thân while. b. Nếu bt có giá trị khác 0 ( đúng ) máy sẽ thực hiện các câu lệnh trong thân while. Khi gặp dấu ngoặc nhọn } đóng cuối cùng của thân while máy sẽ trở lại bước 1; hoặc gặp câu lệnh continue máy sẽ chuyển đến đầu một vòng lặp mới của vòng lặp, tức là máy sẽ bỏ qua các câu lệnh còn lại trong thân vòng lặp để trở về bước tính và kiểm tra bt. 3.5 Câu lệnh do while ( Lặp với điều kiện được kiểm tra sau ) 3.5.1 Cú pháp do Kl // thân vòng lặp while(bt); Trong đó: Bt có thể là 1 biểu thức hay là một dãy các biểu thức được phân tách bởi dấu phẩy. Giá trị của Bt là Đúng (khác 0) hoặc sai ( bằng 0). 3.5.2 Lưu đồ Ngữ nghĩa: Kl Thực hiện 1 0 Kl trong khi Bt còn đúng Bt 3.5.3 Hoạt động của câu lệnh do Theo trình tự: 1. Thực hiện khối lệnh trong thân do. 2. Khi gặp dấu ngoặc nhọn } đóng cuối cùng của thân do máy sẽ tính và xác định giá trị của Bt sau từ khóa while. 3. Tùy thuộc vào tính đúng sai của bt, máy sẽ lựa chọn 1 trong 2 nhánh: 28
  29. a. Nếu Bt có giá trị bằng 0 ( sai ) máy sẽ ra khỏi vòng lặp và chuyển tới câu lệnh sau thân do. b. Nếu Bt có giá trị khác 0 ( đúng ) máy sẽ trở về bước 1 để tiếp tục thực hiện vòng mới của vòng lặp. 3.6 Câu lệnh goto và nhãn 3.6.1 Nhãn Nhãn là một tên và có dấu hai chấm (:) đứng sau. Nhãn có thể được gán cho bất kỳ câu lệnh nào trong chương trình. Chẳng hạn: tiep_tuc: s + = x; nghĩa là: tiep_tuc là nhãn câu lệnh gán s += x. 3.6.2 Câu lệnh goto 1. Cú pháp: goto nhãn; 2. Tác dụng: chương trình sẽ nhảy tới thực hiện câu lệnh có nhãn viết sau từ khóa goto; Ghi chú: 1. Câu lệnh goto và nhãn chỉ nằm trong 1 hàm. goto chỉ cho phép nhảy từ vị trí này đến vị trí khác trong thân 1 hàm. Nó không thể nhảy từ hàm này sang hàm khác. 2. Không cho phép dùng câu lệnh goto nhảy từ ngoài khối lệnh vào trong khối lệnh. Nhưng ngược lại, tức là nhảy từ trong ra ngoài khối lệnh là hợp lệ. 3. Câu lệnh goto thường được dùng để thoát khỏi các câu lệnh switch, và các vòng lặp hoặc kết hợp với if tạo ra vòng lặp. Ví dụ: nhan: clrscr(); . . . goto nhan; 3.7 Các câu lệnh break, continue 3.7.1 break Break cho phép ra khỏi switch , và các vòng lặp for, while, do mà không cần kiểm tra điều kiện kết thúc của vòng lặp. Lệnh break cho phép thoát ra ngay khỏi vòng lặp bên trong nhất chứa lệnh break; Mọi câu lệnh break có thể thay bằng câu lệnh goto và nhãn thích hợp. 3.7.2 continue Lệnh continue tạo ra việc bắt đầu lặp lại của vòng lặp chứa nó. Trong while và do, lệnh continue chuyển điều khiển về thực hiện ngay phần kiểm tra. Đối với for, điều khiển được chuyển về bước khởi đầu lại. Continue chỉ áp dụng cho vòng lặp, không cho switch. 3.8 Câu lệnh rỗng Lệnh rỗng là lệnh chỉ có dấu chấm phẩy (;) (Lệnh này thường được sử dụng trong thân các vòng lặp mà ở đó không muốn có 1 lệnh nào.) 29
  30. 3.9 Vòng lặp vô hạn Thường có các dạng sau: a) Dạng for: for (; ;) khối lệnh Mệnh đề trong phần thân vòng lặp thường là mệnh đề kép chứa: Những mệnh đề mà nó thực hiện lặp lại để giải quyết bài toán. Một mệnh đề mà nó sẽ kết thúc sự thực hiện vòng lặp khi một điều kiện nào đó được thỏa. Mệnh đề này thường là if kết hợp với break. b) Dạng while: while(1) khối lệnh c) Dạng do while: do khối lệnh while(1); Khi sử dụng vòng lặp ta cần lưu ý đến điều kiện lặp có thể dừng vòng lặp được không. Các vòng lặp dạng trên muốn dừng, cần phải có sự can thiệp của các câu lệnh break, goto, return Bài tập Bài 1:Viết chương trình giải phương trình bậc nhất ax+b=0. Bài 2:Viết chương trình tính giá trị lớn nhất của 4 số nguyên a, b, c, d được nhập từ bàn phím. Bài 3:Viết chương trình giải phương trình bậc hai ax2+bx+c=0 (a≠0). Bài 4: Viết chương trình phân loại tam giác: tam giác thường, tam giác đều, tam giác cân, tam giác vuông, không là ba cạnh của tam giác. Bài 5: Tính tổng n số nguyên dương đầu tiên S=1+2+3 n Bài 6:Viết chương trình thực hiện các phép toán số học. Nhập vào 2 số thực a, bvà ký tự K, Tính: K = ‘*’, ketqua = a*b K = ‘+’, ketqua = a+b K = ‘-‘, ketqua = a-b K = ‘/’, ketqua = a/b Bài 7: viết chương trình tính n!. n!=1*2*3* *n. Bài 8: Viết chương trình bài 6 bằng lệnh if Bài 9: Sử dụng cấu trúc while và do while để viết chương trình tính: Tính tổng n số nguyên dương đầu tiên S=1+2+3 n Tính tổng n! với n là số nguyên n!=1*2*3* *n. 30
  31. BÀI 4 HÀM Mã bài : MH 13.4 Mục tiêu của bài: - Hiểu được khái niệm hàm - Trình bày được qui tắc xây dụng hàm và vận dụng được khi thiết kế xây dựng chương trình. - Hiểu được nguyên tắc xây dựng hàm, thế nào là tham số, tham trị - Biết cách truyền tham số đúng cho hàm Sử dụng được các lệnh kết thúc và lấy giá trị trả về của hàm. 4.1 Khái niệm C/ C++ đưa ra khái niệm hàm và trở thành công cụ mạnh mẽ để hỗ trợ cho phương pháp lập trình có cấu trúc. Hàm có thể xem là một đơn vị độc lập của chương trình. Các hàm có vai trò ngang nhau, vì vậy không cho phép xây dựng một hàm bên trong các hàm khác. Các hàm thường che dấu những chi tiết thực hiện đối với các phần khác trong chương trình, do đó làm chương trình sáng sủa, dễ sửa đổi. Một hàm có thể là: Nằm ngay trong modul văn bản (có các khai báo,các lệnh có trong hàm) hoặc được đưa một cách tự động vào văn bản của chương trình (bằng đường dẫn #include) hay được dịch riêng rẽ (sẽ được nối kết vào chương trình trong giai đoạn liên kết) Được gọi từ chương trình chính, hoặc từ một hàm khác, hoặc từ chính nó (đệ qui). Có hay không có đối (tham số hình thức). Có hay không có giá trị trả về. . . . Một hàm: Chỉ có 1 đầu vào ( { ). Có thể có nhiều điểm ra ( return hay } ). 4.2 Quy tắc xây dựng một hàm 4.2.1 Cấu trúc của 1 hàm Mọi hàm đều có dạng: [Kdl] Ten_Ham ([danh_sách_kiểu_và_Đối]) // Dòng tiêu đề { // Các chỉ thị về kiểu // Các câu lệnh; [return [biểu_thức];] } Trong đó: a) Dòng tiêu đề: 31
  32. Chứa các thông tin: Kdl: Kiểu dữ liệu của hàm, Ten_Ham: Tên của hàm, kiểu và tên đối. Danh_sách_kiểu_và_Đối: Là các đối và kiểu tương ứng của nó. Cuối dòng tiêu đề không có dấu chấm phẩy (;) như kết thúc câu lệnh. 1. Kdl: Có thể có hoặc không. - Trương hợp không: Không có kiểu dữ liệu của hàm, Một cách ngầm định C++ coi đó là kiểu int. - Trường hợp có: Kdl là kiểu dữ liệu của hàm, có thể là bất kỳ kiểu dữ liệu nào ngoại trừ mảng. C++ sẽ dùng từ khóa void để chỉ kiểu dữ liệu của hàm trong trường hợp hàm không trả về giá trị nào cả. Cần lưu ý là: o Nếu hàm trả về kiểu int, ta có thể không khai báo (ngầm định là kiểu int). o Nếu trả về khác kiểu int, ta phải khai báo tường minh Kiểu dữ liệu của hàm. 2. Ten_Ham: Là tên của hàm do người lập trình tự đặt theo quy tắc đặt tên. 3. Danh sách kiểu và đối: Có thể có hoặc không. o Trường hợp không: Nếu không có đối thì vẫn phải giữ các dấu ngoặc tròn ().Trong trường hợp này có thể thay bằng từ khóa void. o Trường hợp có: Đó là các đối của hàm. Trước mỗi đối có kiểu dữ liêu tương ứng của nó, nếu có nhiều đối và kiểu tương ứng của nó, thì chúng phải cách nhau dấu phẩy(,). Thân hàm: Thân hàm bắt đấu bằng dấu ngoặc nhọn mở{, tiếp theo là các chỉ thị về kiểu (nếu có), các câu lệnh trong đó có thể có hay không câu lệnh return và kết thúc bằng dấu ngoặc nhọn đóng. 4.3 Sử dụng hàm Hàm được sử dụng thông qua lời gọi hàm. Lời gọi hàm được viết như sau: Ten_Ham([Danh sách các tham số thực]) Trong đó: - Số tham số thực phải bằng số các đối. - Kiểu của tham số thực phải phù hợp với kiểu của đối tương ứng. Cách sử dụng như sau: - Nếu hàm trả về kiểu void, Viết lời gọi hàm như câu lệnh ( thêm dấu ; cuối cùng), tức là: 32
  33. Ten_Ham([Danh sách các tham số thực]); - Nếu hàm trả về khác kiểu void, lời gọi hàm được sử dụng: . Như một toán hạng trong biểu thức. . Vế phải câu lệnh gán. . In giá trị của hàm. . . . . Khai báo nguyên mẫu của hàm ( prototype). Trước khi sử dụng một hàm, ta có thể khai báo hoặc không khai báo nguyên mẫu của hàm trong chương trình.Vị trí khai báo có thể là ngoài tất cả các hàm, hoặc trong hàm thường là đầu chương trình tại các định nghĩa toàn cục. Dạng khai báo nguyên mẫu hàm là: Kdl tên_hàm (Danh_sách_Kiểu_và _Đối); // Có dấu ; Ví dụ: float max(float a, float b); Đối với C++, Các trường hợp sau nhất thiết phải khai báo nguyên mẫu: Vị trí của hàm đặt sau hàm main(). Các hàm - không phải hàm main() - gọi lẫn nhau. Dù rằng có các trường hợp không nhất thiết phải khai báo nguyên mẫu, nhưng tốt hơn cả là ta vẫn khai báo để trình biên dịch dễ phát hiện lỗi khi gọi hàm. 4.4 Nguyên tắc hoạt động của hàm Khi gặp một lời gọi hàm thì hàm bắt đầu thực hiện. Quá trình diễn ra theo trình tự: a) Cấp phát bộ nhớ cho các đối và các biến địa phương. b) Gán giá trị của các tham số thực cho các đối tương ứng. c) Thực hiện các câu lệnh trong thân hàm. d) Khi gặp câu lệnh return hoặc dấu } cuối cùng của thân hàm thì máy sẽ xóa các đối, các biến địa phương và ra khỏi hàm. 4.5 Cánh truyền tham số Có 2 cách: Truyền bằng trị và truyền bằng biến. Truyền bằng trị: Tham số của hàm luôn được truyền theo tham trị. Điều này có nghĩa là các giá trị thực ( tham số thực ) không bị thay đổi giá trị khi truyền cho các đối. Khi chúng ta gọi hàm với các tham số, những gì chúng ta truyền cho hàm là các giá trị chứ không phải bản thân các biến. Ví dụ, giả sử chúng ta gọi hàm cong như sau: int x=5, y=3, z; z = cong ( x , y ); Truyền bằng biến: Để thay đổi giá trị của biến qua lời gọi hàm, thì chúng ta phải truyền tham số theo dạng tham số biến Ví dụ: // truyền tham số theo dạng tham số biến #include #include 33
  34. void nhan2(int &a, int &b, int c); void main() { int x=4, y =10,c=8; clrscr(); printf("Truoc goi ham x=%d, y=%d, c=%d \n",x,y,c); nhan2(x,y,c); printf("Sau goi ham x=%d, y=%d, c=%d \n",x,y,c); getch(); } 4.6 Câu lệnh return Trong thân hàm có thể có hoặc không có câu lệnh này. Trong trường hợp có, có thể có một câu lệnh return, hoặc nhiều câu lệnh return ở những nơi khác nhau, Nếu không có câu lệnh return thì chương trình sẽ ra khỏi hàm khi gặp dấu ngoặc nhọn đóng cuối cùng } của thân hàm để trở về nơi gọi nó. Nếu có, Câu lệnh "return" là cơ chế chuyển giá trị từ hàm được gọi về nơi gọi. Khi gặp câu lệnh return máy sẽ không thực hiện các câu lệnh sau nó trong hàm chứa câu lệnh này. Dạng tổng quát của câu lệnh này là: return [Bt]; Ý nghĩa của các dạng có thể minh họa như sau: Dạng 1: return; Dùng để thoát ra khỏi 1 hàm và trở về hàm đã gọi nó, mà không trả về một giá trị nào. Trường hợp này khai báo kiểu dữ liệu của hàm là void. Câu lệnh return có thể dùng để ra khỏi thân switch, các vòng lặp. Dạng 2: return Bt; hoặc return (Bt); Giá trị của biểu thức Bt sẽ được chuyển kiểu cho phù hợp với kiểu của hàm trước khi gán cho hàm, và ra khỏi hàm chuyển về nơi gọi nó. Hàm inline Hàm có ưu điểm là được dùng lại chứ không phải viết lại cho các ứng dụng khác, tuy nhiên nó cũng có một nhược điểm là làm chậm chương trình một các đáng kể, ngay cả khi thân hàm chỉ có một vài câu lệnh, vì phải sao các đối, cất giữ trên thanh ghi, chương trình phải nhảy tới một vị trí mới. Hàm inline đưa ra một giải pháp khắc phục tình trạng này, và xác định bởi từ khóa inline. Một hàm được xác định là inline thì sẽ mở rộng “”trên dòng” tại điểm gọi, và làm cho phí tổn của hàm được loại bỏ. Cách viết là chỉ thêm inline trước kiểu trả về của hàm. 4.7 Một số thư viện trong C++ Một trong những tính năng thuận tiện của C++ là cung cấp kèm theo một số lượng lớn các thư viện. Thư viện chứa các hằng, các hàm thực hiện các thao tác chuyên biệt nào đó. Muốn sử dụng thư viện, ta chỉ cần tham chiếu đến tập tin giao diện gọi là tập tin tiêu đề (tập tin header, có đuôi dạng.h) của thư viện đó, bằng cách sử dụng chỉ thị: #include 34
  35. Bài tập Viết chương trình thực hiện các thao tác trên số nguyên dương . Yêu cầu của chương trình là : viết 3 hàm tinhs1, tinhs2, tinhs3 Với: 1. Tính S1 = 1+2+3+4+ + n , n là số nguyên 2. Tính S2 = 1+3+5+ +n (n lẽ) 3. Tính S3 = 2+4+6+8+ +n (n chẳn) 35
  36. BÀI 5 KIỂU MẢNG Mã bài : MH 13.5 Mục tiêu của bài: - Hiểu khái niệm mảng - Khai báo được mảng một chiều, mảng hai chiều, mảng nhiều chiều - Biết cách gán giá trị cho mảng trực tiếp, gián tiếp. - Vận dụng được mảng làm tham số cho hàm. - Sắp xếp được mảng theo thứ tự tăng dần hoặc giảm dần. 5.1 Khai báo mảng 5.1.1 Khái niệm Mảng là một tập các biến cùng kiểu được gọi chung bằng một tên. Các phần tử của mảng được được truy cập đến bởi chỉ số (index) của mảng. Mảng có thể có 1 chiều hay nhiều chiều. Dữ liệu của mảng được chứa trong một vùng nhớ liên tục. 5.1.2 Mảng 1 chiều I) Khai báo: KDL Ten_Mang[KT]; Trong đó: KDL là kiểu dữ liệu của mảng, có thể là char, int, float, Ten_Mang là một tên, chỉ tên của mảng. KT: Là một số nguyên dương chỉ kích thước khai báo của mảng: xác định số các phần tử của mảng. II) Chỉ số của mảng: Mỗi phần tử của mảng được xác định bởi chỉ số của mảng. Chỉ số của mảng phải có giá trị int không vượt quá kích thước của mảng. Chỉ số đầu tiên của mảng luôn là 0. Ký pháp a[i] để chỉ phần tử thứ i của mảng a. Các phần tử của a được đánh số (mặc định) bởi: a[0], a[1], III) Lấy địa chỉ của mảng: Các phần tử của mảng 1 chiều có địa chỉ liên tiếp nhau trong bộ nhớ. Lấy địa chỉ của phần tử mảng 1 chiều bằng phép toán &, với cú pháp: &a[i] // a[i] là phần tử thứ i của mảng a Ghi chú: Địa chỉ đầu của mảng là tên mảng, vậy ta có: a == &a[0] IV) Kích thước bộ nhớ (số bytes) được sử dụng để lưu trử mảng 1 chiều là: Tong (Bytes) = sizeof(KDL)* KT V) Một số thao tác thường gặp trên mảng một chiều: 1. Nhập và xuất dữ liệu cho mảng 1 chiều: Thường liên kết với vòng lặp for. 2. Sắp xếp một mảng theo thứ tự tăng hay giảm. 3. Gán mảng: Hai mảng a, b cùng kiểu, cũng không thể thực hiện trực tiếp việc gán a cho b bằng câu lệnh gán: 36
  37. b = a; Ta chỉ thực hiện được việc gán a cho b bằng cách gán giá trị từng phần tử của a tương ứng cho từng phần tử của b. VI) Hàm và mảng 1 chiều Hàm không thể trả về một trị là mảng 1 chiều. Đối của hàm là tên của mảng 1 chiều: Khi đó tham số thực truyền cho đối tương ứng cũng là tên của mảng 1 chiều, cùng kiểu và cùng kích thước với đối. Tên của tham số thực và tên của đối có thể trùng nhau hoặc khác nhau. Đối Tham số thực Tên mảng 1 chiều Tên mảng 1 chiều ( cùng kiểu, kích thước với đối) 5.1.3 Mảng 2 chiều Trong các mảng nhiều chiều, hình thức đơn giản nhất là mảng 2 chiều. I) Cách tiếp cận và khai báo: Mảng 2 chiều là mảng 1 chiều của mảng 1 chiều. Có thể khai báo như sau: KDL Ten_Mang[KT1][ KT2]; II) Công thức tính số bytes cần thiết trong bộ nhớ lưu trư mảng 2 chiều: Tong (Bytes) = sizeof(KDL)* KT1* KT2. III) Nhập, xuất mảng 2 chiều (ma trận): Thường liên kết với 2 vòng for duyệt theo chỉ số để nhập dữ liệu cho từng phần tử, hoặc xuất dữ liệu của từng phần tử ra màn hình. IV) Hàm và mảng 2 chiều: Hàm không thể trả về giá trị là một mảng 2 chiều. Đối của hàm là tên của mảng 2 chiều: Khi đó tham số thực truyền cho đối tương ứng cũng là tên của mảng 2 chiều, cùng kiểu và cùng kích thước với đối. Tên của tham số thực và tên của đối có thể trùng nhau hoặc khác nhau. Đối Tham số thực Tên mảng 2 chiều Tên mảng 2 chiều ( cùng kiểu, kích thước với đối) 5.2 Mảng và tham số Dùng từ khoá typedef để định nghĩa, bằng cách trước định nghĩa mảng thông thường, ta đặt từ khoá typedef. Ví dụ: a) typedef float Day10[10];// Day10 là kiểu dữ liệu mảng 1 chiều kích thước 10 Day10 a,b; // a,b là 2 biến kiểu mảng 1 chiều có kích thước 10. b) typedef float Mat10_20 [10][20]; // Mat10_20 là kiểu dữ liệu mảng 2 chiều kích thước 10x20 Mat10_20 c,d; // c,d là 2 biến kiểu mảng 2 chiều có kích thước 10x20 5.3 Sắp xếp mảng 1. Kỹ thuật thử và sai Cần xác định Kq khi biết Kq {a1, ,an }: Giả sử Kq = a1; 37
  38. Duyệt các phần tử còn lại để chính xác giá trị Kq. 2. Kỹ thuật duyệt Toàn cục: duyệt tất cả các phần tử của tập hợp. Cục bộ: Chỉ trên một miền con của tập hợp có thể xét. Miền con này xác định từ các giá trị của hàm, hay là lập bảng. 3. Kỹ thuật kiểm tra tính đúng, sai: Dạng 1: Đúng: nếu i, ai phải thỏa mãn. Sai: nếu i, ai không thỏa mãn. Cách thực hiện như sau: Kq = 1; // Đúng Duyệt để tìm điều kiện gán Kq = 0; // Sai Dạng 2: Đúng: nếu i, ai thỏa mãn. Sai: nếu i, ai không thỏa mãn. Cách thực hiện như sau: Kq = 0; //Sai Duyệt để tìm điều kiện gán Kq = 1; // Đúng 5.4 Gán giá trị cho mảng 1. Sử dụng các hằng 2. Khi khởi đầu có thể không cần chỉ ra kích thước của mảng. Khi đó máy sẽ dành cho mảng 1 vùng nhớ đủ để thu nhận danh sách giá trị khởi đầu. Trong trường hợp là mảng 2 chiều thì kích thước chiều 2 phải chỉ ra: 3. Đối với mảng 2 chiều có thể khởi đầu theo cách số giá trị của mỗi hàng có thể khác nhau với điều kiện là: Kích thước chiều 2 phải được chỉ ra. Kích thước chiều 1 hoặc là không được chỉ ra, hoặc có chỉ ra thì giá trị phải lớn hơn kích thước thực sự của mảng Ví dụ: int a[6][3] = { {1,2}, {3}, {4,5,6}, {0,3,1} }; // Thực sự đây là mảng a[3][3] 38
  39. Bài tập Bài1: Viết chương trình theo các hàm sau, cho phép nhập xuất một mảng chứa các số nguyên, tìm một số cho trước có trong mảng hay không, sắp xếp mảng đã nhập thành mảng các số nguyên tăng dần typedef int mangsonguyen[100]; Hàm void nhap(mangsonguyen a,int n); Cho phép nhập vào một mảng các số nguyên void xuat(mangsonguyen a,int n); xuất một mảng chứa các số nguyên đã nhập ra màn hình void tim(mangsonguyen a,int n,int &x); tìm một số cho trước có trong mảng hay không void SapXep(mangsonguyen a, int n); sắp xếp mảng đã nhập thành mảng các số nguyên tăng dần Viết hàm main gọi thực hiện các hàm trên. Bài 2: Viết chương trình theo các hàm sau: Ta có khai báo kiểu dữ liệu ma trân như sau: typedef matran[100][100]; Viết hàm: void nhap(matran x,int m,int n); cho phép nhập vào một ma trận bất kỳ với cấp ma trận được người dùng nhập từ bàn phím void xuat(matran x,int m,int n); Xuất ma trận đã nhập ra màn hình int cong(matran u,matran v,int m,int n); Cộng hai ma trận cùng cấp int tru(matran u,matran v,int m,int n); Trừ hai ma trận cùng cấp int tich(matran u,matran v,int m,int n); tính tích của hai ma trận Bài 3: Viết chương trình thực hiện các thao tác trên dãy a gồm n số nguyên. Yêu cầu của chương trình là : - In ra màn hình menu có các chức năng sau : 1. Đếm số lần xuất hiện của x trong dãy a 2. Tổng các phần tử trong dãy và trung cộng của dãy 3. Tổng các số lẽ 4. Tổng các số chẳn 5. Tổng các số chia hết cho 5 6. Tìm phần tử x có trong dãy hay không? 7. Sắp theo yêu cầu: - Đầu dãy: Các số dương tăng dần - Tiếp theo: Các số âm giảm dần - Cuối cùng: Các số 0 8. Thóat khỏi chương trình - Muốn thực hiện thao tác nào thì chọn chức năng tương ứng của menu. 39
  40. BÀI 6 CHUỖI KÝ TỰ Mã bài : MH 13.6 Mục tiêu của bài: - Hiểu được thế nào là chuỗi kí tự - Khai báo được biến chuỗi - Biết cách nhập vào một chuỗi kí tự cho chương trình trước và sau khi runtime. - Hiểu và áp dụng được các phép toán trên chuỗi. - Vận dụng được các hàm xử lý chuỗi để xử lý. 6.1 Khái niệm Một xâu ký tự (chuỗi) là mảng một chiều các ký tự được kết thúc bởi ký tự NULL (\0). Số lượng các ký tự khác NULL trong xâu gọi là chiều dài của xâu. 6.2 Khai báo biến chuỗi char a[KT]; a là tên, chỉ tên của xâu ký tự. KT là số nguyên dương, chỉ kích thước của xâu ký tự. a[i] là ký tự thứ i của a. Chỉ số đầu tiên luôn là 0. Trong khi khai báo, ta phải khai báo xâu ký tự có chiều dài lớn hơn mảng được sử dụng 1 ký tự để đủ chỗ chứa ký tự NULL. Kiểu xâu ký tự Cách tạo là đặt từ khoá typedef trước khai báo xâu thông thường. 6.3 Nhập xuất xâu ký tự 1. Xuất: cout > a ; Với a là một xâu ký tự không chứa ký tự tách ( khoảng trắng, tab ), vì iostream xem các ký tự đó là ký tự tách chứ không phải dữ liệu. Để nhập một xâu ký tự có chứa ký tự tách thì có thể dùng các cách sau: a) Dùng hàm gets trong tệp tiêu đề hoặc trong : gets(a); b) Dùng hàm thành phần của iostream: Cin.getline(a, so_ky_tu); Hàm này đọc vào tối đa so_ky_tu – 1 ký tự, kể cả ký tự trắng. Các xử lý thường gặp trên xâu ký tự như xác định chiều dài xâu, chép xâu s vào xâu t, nối 2 xâu, 40
  41. 6.4 Các phép toán chuỗi ký tự 6.4.1 Gán giá trị cho xâu kí tự Vế trái của một lệnh gán chỉ có thể là một phần tử của mảng chứ không thể là cả mảng, chúng ta có thể gán một xâu kí tự cho một mảng kiểu char sử dụng một phương pháp như sau: mystring[0] = 'H'; mystring[1] = 'e'; mystring[2] = 'l'; mystring[3] = 'l'; mystring[4] = 'o'; mystring[5] = '\0'; Nhưng rõ ràng đây không phải là một phương pháp thực tế. Để gán giá trị cho một xâu kí tự, chúng ta có thể sử dụng loạt hàm kiểu strcpy (string copy), hàm này được định nghĩa trong string.h và có thể được gọi như sau: strcpy (string1, string2); Lệnh này copy nội dung của string2 sang string1. string2 có thể là một mảng, con trỏ hay một hằng xâu kí tự, bởi vậy lệnh sau đây là một cách đúng để gán xâu hằng "Hello" cho mystring: strcpy (mystring, "Hello"); 6.4.2 Chuyển đổi xâu kí tự sang các kiểu khác. Vì một xâu kí tự có thể biểu diễn nhiều kiểu dữ liệu khác như dạng số nên việc chuyển đổi nội dung như vậy sang dạng số là rất hữu ích. Ví dụ, một xâu có thể mang giá trị "1977"nhưng đó là một chuỗi gồm 5 kí tự (kể cả kí tự null) và không dễ gì chuyển thành một số nguyên. Vì vậy thư viện cstdlib (stdlib.h) đã cung cấp 3 macro/hàm hữu ích sau: atoi: chuyển xâu thành kiểu int. atol: chuyển xâu thành kiểu long. atof: chuyển xâu thành kiểu float. 6.5 Các thao tác trên chuỗi ký tự 6.5.1 Các hàm để thao tác trên chuỗi Thư viện cstring (string.h) không chỉ có hàm strcpy mà còn có nhiều hàm khác để thao tác trên chuỗi. Dưới đây là giới thiệu lướt qua của các hàm thông dụng nhất: strcat: char* strcat (char* dest, const char* src); Gắn thêm chuỗi src vào phía cuối của dest. Trả về dest. strcmp: int strcmp (const char* string1, const char* string2); So sánh hai xâu string1 và string2. Trả về 0 nếu hai xâu là bằng nhau. strcpy: char* strcpy (char* dest, const char* src); Copy nội dung của src cho dest. Trả về dest. strlen: size_t strlen (const char* string); Trả về độ dài của string. Chú ý: char* hoàn toàn tương đương với char[] Cũng theo quy tắc chung của mảng (1 chiều) đã giới thiệu ở trên. Bộ khởi đầu của mảng 1 chiều ký tự có thể là: Danh sách các hằng ký tự, cuối cùng là ký tự ‘\0’. 41
  42. Hoặc là một hằng xâu ký tự. 6.5.2 Hàm và xâu ký tự Hàm không thể trả về một giá trị là xâu ký tự. Đối của hàm có thể là tên xâu ký tự, khi đó tham số thực phải là tên xâu ký tự Đối Tham số thực Xâu ký tự Tên xâu ký tự 6.5.3 Mảng các xâu ký tự Cách tiếp cận như là mảng 2 chiều các ký tự. Khai báo: char a[KT1][KT2]; Nhập hoặc xuất mảng các xâu ký tự là nhập hoặc xuất từng xâu ký tự của mảng. Khởi đầu: Khởi đầu từng xâu ký tự bằng các hằng xâu ký tự. Bài tập Bài 1: Viết Chương trình thực hiện đảo ngược chuỗi ký tự. Ví dụ: Kết quả thực thi chương trình: - Nhap vao 1 chuoi : Khoa Cong Nghe Thong Tin - Chuoi nay co : 13 ky tu ke ca ky tu trong - Dao nguoc chuoi nay thanh niT gnohT ehnN gnoC aohK Bài 2: Viết chương trình: Nhập danh sách có tối đa 100 nhân viên gồm 3 thông tin: họ tên, năm sinh và tuổi. Tính tuổi trung bình của các nhân viên trong công ty và in ra danh sách các nhân viên có tuổi lớn hơn tuổi trung bình. Xuất ra thông tin về những nhân viên có năm sinh nhỏ hơn 1985 Bài 3: Nhập vào danh sách lớp gồm n học viên (nhập vào). Thông tin về mỗi học viên gồm Họ tên, phái , điểm, kết quả. Xét kết quả theo điều kiện sau : nếu Ðiểm>= 5 ( đậu ), điểm <5 : rớt. Sau đó sắp xếp theo điểm và ghi vào tập tin c:\lop.txt. Ðọc lại tập tin c:\lop.txt và xét lại kết quả nếu điểm =4 và phái là nữ sẽ đậu và chép sang tập tin c:\ketqua.txt. HD: xây dựng cấu trúc struct { char ten[20] ; char phai[4] ; int diem ; char kq[4] ; } KieuHV; 42
  43. BÀI 7 BIẾN CON TRỎ Mã bài : MH 13.7 Mục tiêu của bài: - Hiểu được về con trỏ trong ngôn ngữ lập trình - Biết được cách làm việc của biến con trỏ với cấu trúc dữ liệu kiểm mảng - Viết được chương trình sử dụng biến con trỏ với cấu trúc dữ liệu kiểu mảng 7.1 Biến con trỏ 7.1.1 Định nghĩa biến con trỏ (gọi tắt là con trỏ): Con trỏ là biến chứa địa chỉ của biến khác. Vậy là con trỏ không chứa dữ liệu, chỉ chứa địa chỉ của dữ liệu. Kích thước của biến con trỏ không phụ thuộc vào đối tượng mà nó trỏ tới là kiểu gì. Kích thước cố định của biến con trỏ là 2 byte dùng để lưu địa chỉ của biến. Khi nó đang lưu địa chỉ của biến nào, ta nói nó đang trỏ tới biến ấy. Ta cần nhớ điểm cơ bản là: Con trỏ là biến, nên có thể nói đến giá trị của nó. Giá trị của con trỏ là địa chỉ của biến mà nó trỏ tới. Vì có nhiều loại địa chỉ nên cũng có bấy nhiêu kiểu con trỏ tương ứng. Nhắc lại rằng địa chỉ của biến là số thứ tự của byte đầu tiên trong một dãy các byte liên tiếp mà máy dành cho biến. Để lấy địa chỉ của biến, ta dùng phép toán &. & là phép toán 1 ngôi trả về địa chỉ toán hạng của nó. &x trả về địa chỉ của biến x. 7.1.2. Khai báo: Cú pháp: KDL *Ten_Con_Tro; Trong đó: KDL là Kiểu dữ liệu của con trỏ, có thể là char, int, double, cấu trúc Ten_Con_Tro: là tên, chỉ tên của con trỏ. *: là phép toán con trỏ. 7.1.3 Các phép toán trên con trỏ và biểu thức: 1) Phép toán 1 ngôi: Đó là phép toán “ * “ tác dụng lên con trỏ. Phép toán một ngôi * coi toán hạng của nó là địa chỉ cần xét và thâm nhập tới địa chỉ đó để lấy ra nội dung. Tức là: *px là nội dung cuả địa chỉ do px trỏ tới ( nếu px trỏ tới x thì: *px == x). 2) Phép gán: Có thể thực hiện phép gán: Các con trỏ cùng kiểu. Gán địa chỉ của biến cho tên con trỏ. Biến và con trỏ phải cùng kiểu. Cú pháp: Ten_Con_Tro = &bien; 3) Phép tăng, giảm địa chỉ ( Số học địa chỉ ): Các phép toán tự tăng ( ++ ), tự giảm ( ). 43
  44. Phép cộng ( + ) hay trừ ( - ) con trỏ với số nguyên dùng cho kiểu mảng. 4) Nguyên tắc truy nhập bộ nhớ: Con trỏ kiểu Type truy cập tới sizeof(Type) bytes. 5) Phép so sánh: So sánh các con trỏ cùng kiểu. 6) Con trỏ trong biểu thức: Trong biểu thức: Ta có thể sử dụng tên con trỏ, chẳng hạn gán địa chỉ của biến cho tên con trỏ Hoặc là dạng khai báo con trỏ. 7.1.4 Con trỏ kiểu void: Khai báo: void *Ten_Con_Tro; Đây là con trỏ đặc biệt không định kiểu trước, nó có thể nhận bất kỳ địa chỉ của kiểu nào. 7.1.5 Con trỏ NULL: Một con trỏ có thể nhận giá trị hằng đặc biệt: NULL 7.1.6 Cấp phát vùng nhớ, giải phóng vùng nhớ: 1) Cấp phát vùng nhớ để lưu dữ liệu: Để cấp phát vùng nhớ cho biến con trỏ trước khi sử dụng, trong C++ dùng hàm new. Cách viết như sau: Ten_Con_Tro = new KDL; Khi đó con trỏ sẽ trỏ tới địa chỉ đầu của vùng nhớ đã cấp phát cho nó. b) Giải phóng vùng nhớ: Vùng nhớ sau khi sử dụng xong có thể xóa bỏ bằng hàm delete để tiết kiệm bộ nhớ, và tăng tốc độ thực hiện của chương trình. Cú pháp như sau: delete Ten_Con_Tro ; Trong đó, vùng nhớ cần giải phóng tức là tên của biến con trỏ đang chiếm giữ vùng nhớ. 7.1.7 Kiểu con trỏ Dùng từ khóa typedef: Typedef KDL *Ten_Kieu; Tên_Kieu a,b,c; 7.2 Con trỏ và mảng 1 chiều 7.2.1 Địa chỉ của phần tử đầu tiên và tên mảng Với khai báo: float a[10]; i: 0 1 2 3 4 5 6 7 8 9 a[i]: . . . . . . . . . . Máy sẽ cấp cho a một vùng nhớ liên tiếp 40 bytes cho 10 phần tử kiểu float. Địa chỉ phần tử đầu tiên của mảng: &a[0] Theo qui định của C/C++, tên mảng là a chứa địa chỉ phần tử đầu tiên của mảng, nên tên mảng là một hằng địa chỉ: &a[0] tương đương với a (tên44 mảng)
  45. Và trong mọi ngữ cảnh, C/C++ quy định cách viết: &a[i] tương đương với a + i; a[i] tương đương với *(a + i) 7.2.2 Phép cộng (+) hay trừ (-) con trỏ với số nguyên dùng cho kiểu mảng 1 chiều: (Con trỏ trỏ tới phần tử mảng) Giả sử con trỏ px trỏ tới phần tử a[i], khi đó: px + k trỏ tới phần tử thứ k sau a[i], tức là a[i+k]; px -k trỏ tới phần tử thứ k trước a[i], tức là a[i-k]; *(px + i) tương đương với px[i]; ++px trỏ tới phần tử tiép theo là a[i+1] // Tăng trước px++ trỏ tới phần tử tiép theo là a[i+1] // Tăng sau px trỏ tới phần tử kế trước là a[i-1] // giảm trước px trỏ tới phần tử kế trước là a[i+1] // gỉam sau 7.2.3 Cấp phát động cho mảng 1 chiều thông qua con trỏ: Ta có thể dùng con trỏ để cài đặt mảng 1 chiều ( biến động ). 1 Khai báo: KDL *MD; 2. Cấp phát vùng nhớ: MD = new KDL[MAX]; // Mảng có không quá MAX phần tử 3. Thu hồi vùng nhớ: delete [ ]MD; 7.2.4 Đối của hàm là con trỏ: Khi đó, tham số thực có thể là: Địa chỉ của biến có kiểu tương ứng. Con trỏ có kiểu tương ứng. Tên của mảng một chiều có kiểu tương ứng Đối Tham số thực Con trỏ Con trỏ ( cùng kiểu) Tên mảng 1 chiều ( cùng kiểu) 7.3 Con trỏ và xâu ký tự 7.3.1 Tiếp cận: Tương tự như mảng động 1 chiều, xâu ký tự có thể cài đặt bằng con trỏ. Ta có thể khai báo xâu ký tự như sau: char *Chuoi; 45
  46. 7.3.2 Các thao tác trên con trỏ ký tự: 1. Khởi tạo: Chuoi = NULL; //Xâu rổng hoặc: Chuoi[0] = NULL; 2. Cấp phát vùng nhớ: Chuoi = new char[MAX]; 3. Thu hồi vùng nhớ: delete [ ]Chuoi; 4. Phép gán: Gán 2 con trỏ ký tự cho nhau. Gán một hằng xâu ký tự cho con trỏ ký tự. Gán tên một xâu ký tự cho một con trỏ ký tự. 5. Nhập dữ liệu: Có thể dùng: cin>>Chuoi; // Chuoi không có ký tự tách. gets(Chuoi); 6. Xuất dữ liệu: cout<<Chuoi; 7. Tăng giảm địa chỉ cũng giống như mảng 1 chiều. 7.3.3 Đối của hàm là con trỏ ký tự: Tham số thực có thể là: Con trỏ ký tự. Xâu ký tự. Đối Tham số thực Con trỏ ký tự Con trỏ ký tự Tên xâu ký tự 7.4 Con trỏ và mảng nhiều chiều 7.4.1 Phép cộng địa chỉ trong mảng 2 chiều: Xét khai báo: int a[2][3]; Ta có mảng a gồm 6 phần tử được lưu trử kế tiếp trong bộ nhớ, và được xếp theo thứ tự dòng: Dòng 1 Dòng 2 Phần tử a[0][0] a[0][1] a[0][2] a[1][0] a[1][1] a[1][2] Địa chỉ 1 2 3 4 5 6 46
  47. C++ quan niệm: Mảng 2 chiều là mảng 1 chiều của mảng 1 chiều. Nên a chính là mảng 1 chiều 2 dãy, mổi dãy gồm 3 số nguyên. Khi đó kiểu địa chỉ của a là int[3], có kích thước: 2 bytes * 3 = 6 bytes. a trỏ tới đầu dòng đầu tiên (dòng a[0], do đó trỏ tới a[0][0]). 7.4.2. Cài đặt mảng động 2 chiều bằng con trỏ. 1. Khai báo: KDL *pa; 2. Cấp phát vùng nhớ để lưu trử dữ liệu: pa = new KDL[KT1*KT2]; Với khai báo trên, để cấp phát vùng nhớ cho pa ta viết: pa = new int[2*3]; 3. Thu hồi vùng nhớ. delete [ ]pa; 4. Duyệt các phần tử của mảng: Để duyệt các phần tử của mảng, theo cách đã biết là dựa vào chỉ số của các phần tử của mảng ( pa[i][j]), ngoài ra có thể sử dụng con trỏ theo cách sau. Tổng quát: Trong mảng a gồm m dòng và n cột thì: pa + i*n + j trỏ tới phần tử a[i][j] Mối liên hệ giữa i,j,t: t = i * n + j; i = t/n; j = t - i * n; Các công thức trên được sử dụng để điều khiển con trỏ trỏ tới phần tử mảng cần truy xuất. 7.4.3 Đối của hàm là con trỏ: Tham số thực có thể là: con trỏ cùng kiểu, hoặc tên mảng 2 chiều (có ép kiểu) Đối Tham số thực Con trỏ Con trỏ cùng kiểu Tên mảng 2 chiều ( ép kiểu) Bài tập Câu 1: Hãy cho biết kích thước của biến con trỏ kiểu byte và kiểu long # include void main() { byte* a; long* b; cout<<sizeof(a)<<endl; 47
  48. cout void main() { int a; int *aPtr; // aPtr is a pointer to an integer a = 7; aPtr = &a; //aPtr set to address of a cout << “The address of a is “ << &a << “\nThe value of aPtr is “ << aPtr; cout << “\n\nThe value of a is “<< a << “\nThe value of *aPtr is “ << *aPtr << endl; } Chạy thử chương trình trên và giải thích kết quả của chương trình. Câu 4: Cho một hàm như sau: int square(int a) { a = a*a; return a; } a. Viết chương trình C++ nhập vào số nguyên x và gọi hàm square để tính bình phương của x và trình bày kết quả này ra. b. Viết lại hàm square để hàm này trở thành một hàm gọi bằng địa chỉ, đặt tên hàm mới là square2. Viết chương trình C++ nhập vào số nguyên x và gọi hàm square2 để tính bình phương của x và trình bày giá trị của x sau khi gọi hàm. Có nhận xét gì về giá trị của x sau khi gọi hàm? Câu 5: Hãy khai báo mảng động cho ma trận hai chiều có kích thước m x n. Sau đó, kiểm tra có phải ma trận đối xứng không. Câu 6: Viết chương trình nhập số nguyên dương n gồm k chữ số (0 < k ≤ 5) , sắp xếp các chữ số của n theo thứ tự tăng dần. Ví dụ: Nhập n = 1536 Kết quả sau khi sắp xếp: 1356. 48
  49. Bài tập thêm Câu 1: Cho định nghĩa mảng và con trỏ sau: int ara[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; int *ip1, *ip2; Phép gán nào hợp lệ trong các phép gán sau: a. ip1 = ara; b. ip2 = ip1 = &ara[3]; c. ara = 15; d. *(ip2 + 2) = 15; // Assuming ip2 and ara are equal. Câu 2: Hãy chạy đoạn chương trình sau: #include void main() { int num; cout >num; int a = new int [num]; int total = 0; // Holds total of user’s eight numbers. int ctr; for (ctr=0; ctr > a[ctr]; total += a[ctr]; } cout void swap(int a[], int *c1, int *c2, int *d1, int *d2); void main() { int a[2], c1, c2,d1,d2; int *x1, *x2, *y1, *y2; a[0] = 1 ; a[1] =2; c1 = 1; c2 =2; d1 = 1; d2 =2; x1 = &c1; x2 = &c2; y1 = &d1; y2 = &d2; swap(a, x1,x2,y1,y2); cout<<a[0]<<a[1]<<” “ << *x1<<*x2<<” ” <<*y1<<*y2; swap(a, x1,x2,y1,y2); cout<<a[0]<<a[1]<<” “ << *x1<<*x2<<” ” <<*y1<<*y2; 49
  50. } void swap(int a[], int *c1, int *c2, int *d1, int *d2) { a[0] = 2 ; a[1] =1; *c1=2, *c2 =1; int* temp = d1; d1 =d2; d2 = temp; } TÀI LIỆU THAM KHẢO - Giáo trình lý thuyết và bài tập ngôn ngữ C; Tác giả: Nguyễn Đình Tê, Hoàng Đức Hải; Nhà xuất bản giáo dục. - Kỹ thuật lập trình C; Tác giả: GS Phạm Văn Ất; Nhà xuất bản: Khoa học và Kỹ thuật. - [1] Đỗ Xuân Lôi. Cấu trúc dữ liệu và giải thuật. Nhà xuất bản thống kê. 1999. - [2] PGS. TS. HOÀNG NGHĨA TÝ. Cấu trúc dữ liệu và thuật toán. Nhà xuất bản xây dựng. 2006 50