Cộng đồng chia sẻ tri thức Lib24.vn

Bài giảng môn Lập Trình Căn Bản

f86fc6e05bad943b5bebb45ee42591cf
Gửi bởi: Khoa CNTT - HCEM 8 tháng 8 2020 lúc 23:08:16 | Được cập nhật: hôm kia lúc 22:23:02 Kiểu file: DOC | Lượt xem: 444 | Lượt Download: 5 | File size: 0.630784 Mb

Nội dung tài liệu

Tải xuống
Link tài liệu:
Tải xuống

Các tài liệu liên quan


Có thể bạn quan tâm


Thông tin tài liệu

Mục lục

Chương 1. Thuật toán 4

1. Ví dụ 4

2. Khái niệm 4

3. Các đặc trưng của thuật toán 5

4. Phương pháp biểu diễn 5

Bài tập luyện 9

Chương 2. Giới thiệu ngôn ngữ lập trình C++ 10

1. Lịch sử hình thành 10

2. Đặc điểm 11

3. Cấu trúc của một chương trình C++ 12

4. Một số ví dụ mẫu 14

5. Cài đặt chương trình 15

7. Soạn thảo chương trình 19

8. Thoát khỏi chương trình 20

Chương 3. Các thành phần và các kiểu dữ liệu cơ bản 21

1. Các thành phần 21

2. Các kiểu dữ liệu căn bản 21

3. Hằng 23

3.1. Khái niệm 23

3.2. Định nghĩa hằng 23

4. Các phép toán của C++ 24

5. Xuất nhập dữ liệu 25

5.1. Xuất dữ liệu (cout) 25

5.2. Nhập dữ liệu (cin) 27

Chương 4. Các cấu trúc điều khiển 28

1. Lệnh đơn và lệnh phức 28

1.1. Lệnh đơn 28

1.2. Lệnh phức hay khối lệnh 28

2. Cấu trúc điều kiện if..else 28

2.1. Dạng khuyết 28

2.2. Dạng đầy đủ 29

3. Cấu trúc lựa chọn: switch..case 32

4. Các cấu trúc lặp 35

4.1. Cấu trúc lặp while 35

4.2. Cấu trúc lặp do..while 38

4.3. Cấu trúc lặp for 39

5. Câu lệnh break, continue, goto và hàm exit 42

5.1. Câu lệnh break 42

5.2. Câu lệnh continue 42

5.3. Câu lệnh goto 43

5.4. Hàm exit 44

Chương 5. Hàm 45

1. Khái niệm 45

2. Khai báo hàm 45

2.1. Cú pháp khai báo nguyên mẫu hàm 45

2.2. Định nghĩa hàm 45

3. Kết quả trả về của hàm – Lệnh return 46

4. Lời gọi hàm và Cách truyền tham số cho hàm 47

5. Đệ qui 48

5.1. Khái niệm 48

5.2. Ví dụ 48

Bài tập luyện: 49

Chương 6. Mảng 51

1. Khái niệm 51

2. Khai báo mảng 51

2.1. Khai báo mảng 51

2.2. Truy xuất đến các phần tử của mảng 51

3. Khởi tạo mảng 52

4. Dùng mảng làm tham số 54

5. Với mảng hai chiều 57

5.1. Định nghĩa 57

5.2. Truy xuất các phần tử mảng hai chiều 57

5.3. Khởi tạo giá trị mảng hai chiều 58

5.4. Ví dụ 59

Bài tập luyện 60

Chương 7. Con trỏ 62

1. Khái niệm 62

2. Toán tử lấy địa chỉ (&) 62

3. Toán tử tham chiếu (*) 63

4. Khai báo biến kiểu con trỏ. 63

5. Các phép toán 64

5.1. Phép gán 64

5.2. Phép tăng giảm địa chỉ 64

5.3. Phép truy nhập bộ nhớ 65

5.4. Phép so sánh 65

6. Con trỏ hằng 65

7. Con trỏ mảng 66

8. Khởi tạo con trỏ 67

9. Con trỏ trỏ tới con trỏ 68

10. Con trỏ không kiểu 69

11. Con trỏ hàm 70

Chương 8. Cấu trúc 72

1. Khái niệm cấu trúc 72

2. Khai báo cấu trúc 72

2.1. Kiểu cấu trúc 72

2.2. Khai báo thành phần (biến, mảng) kiểu cấu trúc 74

3. Truy cập đến các thành phần của cấu trúc 75

4. Ví dụ cấu trúc 75

Bài tập luyện: 79

Chương 9. File 81

1. Khái niệm File 81

2. Tạo file đọc file 81

2.1. Khai báo con trỏ trỏ đến tập tin 82

2.2. Mở tập tin 82

2.3. Các kiểu xử lý tệp thông dụng 83

2.4. Đóng tập tin 84

2.5. Kiểm tra đến cuối tập tin hay chưa 84

2.6. Các xử lý trên tập tin 84

2.7. Truy cập đến tập tin văn bản (text) 85

3. Tạo file nhị phân 89

4. Đọc file nhị phân 90

4.1. Ghi dữ liệu lên tệp nhị phân 90

4.2. Đọc dữ liệu từ tập tin nhị phân - Hàm fread() 90

4.3. Di chuyển con trỏ tập tin - Hàm fseek() 90

Chương 10. Dữ liệu kiểu chuỗi 93

I. Khai báo 93

1.Mảng: 93

2.Con trỏ: 93

II.NHẬP/XUẤT: 94

1.Xuất: COUT 94

2.Nhập 94

III.MỘT SỐ PHÉP TOÁN TRÊN CHUỖI: 95

1. Truy xuất từng phần tử trong chuỗi thông qua chỉ số. 95

2. Gán chuỗi: 95

3. Hàm thành viên get() 95

IV.Một số hàm thư viện xử lý chuỗi 96

V. Bài tập - Ví dụ 97

Bài tập luyện 105

Tài liệu tham khảo 109

Chương 1. Thuật toán

1. Ví dụ

+ Thuật toán giải phương trình bậc 1, giải phương trình bậc 2.

+ Thuật toán tìm số lớn nhất trong 3 số a, b, c.

+ Thuật toán tính trung bình cộng của 4 số a, b, c, d.

+ Thuật toán tìm đường đi ngắn nhất.

2. Khái niệm

Thuật ngữ thuật toán (Algorithm) là từ viết tắt của tên một nhà toán học ở thế kỷ IX: Abu Ja’fa Mohammed ibn Musa al-Khowarizmi. Đầu tiên, thuật toán được hiểu như là các quy tắc thực hiện các phép toán số học với các con số được viết trong hệ thập phân. Cùng với sự phát triển của máy tính, khái niệm thuật toán được hiểu theo nghĩa rộng hơn. Một định nghĩa hình thức về thuật toán được nhà toán học người Anh là Alanh Turing đưa ra vào năm 1936 thông quá máy Turing. Có thể nói lý thuyết thuật toán được hình thành từ đó.

Lý thuyết thuật toán liên quan đến vấn đề sau:

+ Giải được bằng thuật toán: Thay những thuật toán chưa tốt bằng những thuật toán tốt hơn.

+ Triển khai thuật toán: Xây dựng những ngôn ngữ thực hiện trên máy tính để mã hóa thuật toán.

Vậy, Thuật toán là một dãy hữu hạn các thao tác được bố trí theo một trình tự xác định, được đề ra trước, nhằm giải quyết một bài toán nhất định.

Thao tác hay còn gọi là tác vụ, phép toán (Operation) hay lệnh (Command), chỉ thị (Instruction)… là một hành động cần được thực hiện bởi cơ chế thực hiện thuật toán.

Mỗi thao tác biến đổi bài toán từ một trạng thái trước (hay trạng thái nhập) sang trạng thái sau (hay trạng thái xuất). Thực tế mỗi thao tác thường sử dụng một số đối tượng trong trạng thái nhập (các đối tượng nhập) và sản sinh ra các đối tượng mới trong trạng thái xuất (các đối tượng xuất). Quan hệ giữa 2 trạng thái xuất và nhập cho thấy tác động của thao tác. Dãy các thao tác của thuật toán nối tiếp nhau nhằm biến đổi bài toán từ trạng thái ban đầu đến trạng thái kết quả.

Mỗi thao tác có thể phân tích thành các thao tác đơn giản hơn.

Trình tự thực hiện các thao tác phải được xác định rõ ràng trong thuật toán. Cùng một tập hợp thao tác nhưng xếp đặt theo trình tự khác nhau sẽ cho kết quả khác nhau.

3. Các đặc trưng của thuật toán

+ Tính xác định: Các thao tác, các đối tượng, phương tiện trong thuật toán phải có ý nghĩa rõ ràng, không được gây nhầm lẫn. Nói cách khác, hai cơ chế hoạt động khác nhau cùng thực hiện một thuật toán, sử dụng các đối tượng, phương tiện nhập phải cho cùng một kết quả.

+ Tính dừng: Đòi hỏi thuật toán phải dừng và cho kết quả sau một số hữu hạn các bước.

+ Tính đúng của thuật toán: Thuật toán đúng là thuật toán cho kết quả thỏa mãn đặc tả thuật toán với mọi trường hợp của các đối tượng, phương tiện nhập.

+ Tính phổ dụng: Thuật toán để giải một lớp bài toán gồm nhiều bài cụ thể, lớp đó được xác định bởi đặc tả. Dĩ nhiên là có lớp bài toán chỉ gồm 1 bài. Thuật toán khi đó sẽ không cần sử dụng đối tượng, phương tiện nhập nào cả.

4. Phương pháp biểu diễn

Thuật toán có thể diễn đạt dưới nhiều hình thức, chẳng hạn dưới dạng lưu đồ, dạng ngôn ngữ tự nhiên, dạng mã giả hoặc một ngôn ngữ lập trình nào khác.

a. Dạng ngôn ngữ tự nhiên: Thuật toán có thể trình bày dưới dạng ngôn ngữ tự nhiên theo trình tự các bước thực hiện trong thuật toán.

b. Dạng ngôn ngữ lập trình: Dùng cấu trúc lệnh, dữ liệu của một ngôn ngữ lập trình nào đó để mô tả.

c. Dạng mã giả: Thuật toán trình bày trong dạng văn bản bằng ngôn ngữ tự nhiên tuy dễ hiểu nhưng khó cài đặt. Dùng một ngôn ngữ lập trình nào đó để diễn tả thì phức tạp, khó hiểu. Thông thường thuật toán cũng được trao đổi dưới dạng văn bản – tuy không ràng buộc nhiều vào cú pháp xác định như các ngôn ngữ lập trình, nhưng cũng tuân theo một số quy ước ban đầu – ta gọi là dạng mã giả. Tùy theo việc định hướng cài đặt thuật toán theo ngôn ngữ lập trình nào ta diễn đạt thuật toán gần với ngôn ngữ ấy.

d. Dạng lưu đồ: Trong các phương pháp biểu diễn, chúng ta sẽ chủ yếu nghiên cứu phương pháp biểu diễn theo dạng này.

Dạng lưu đồ dùng các hình vẽ (có quy ước) để diễn đạt thuật toán. Lưu đồ cho hình ảnh trực quan và tổng thể của thuật toán, cho nên thường được sử dụng nhiều nhất.

Các ký hiệu sử dụng trong phương pháp biểu diễn thuật toán bằng lưu đồ:

STT

Ký hiệu

Giải thích

1

Bắt đầu và kết thúc chương trình

2

Điểm nối, đường đi (luồng xử lý)

3

Điều khiển lựa chọn

4

Thao tác nhập, xuất.

5

Thao tác xử lý hoặc tính toán.

6

Trả về giá trị (return)

7

Điểm nối liên kết tiếp theo (sử dụng khi lưu đồ vượt quá trang)

Ví dụ 1: Đọc các thông tin như tên, tuối và lưu lại những người có tuổi trên 50.

Lưu đồ:

Ví dụ 2: dụ: Nhập vào 3 số nguyên a, b, c và xuất ra màn hình với giá trị của mỗi số tăng lên 1.

Chú ý khi vẽ lưu đồ:

+ Trước tiên hãy tập trung vẽ một số đường đi chính của lưu đồ.

+ Thêm vào tất cả các nhánh và vòng lặp.

+ Một lưu đồ chỉ có một điểm Bắt đầu và một điểm kết thúc.

+ Mỗi bước trong chương trình không cần thể hiện trong lưu đồ.

+ Lưu đồ cần phải đáp ứng được yêu cầu: những người lập trình khác có thể hiểu lưu đồ một cách dễ dàng.

Bài tập luyện

Vẽ lưu đồ thuật toán cho các bài toán sau:

Bài 1: Tìm số lớn nhất trong 3 số a, b, c.

Bài 2: Giải phương trình bậc 1: ax + b = 0 (a ≠ 0).

Bài 3: Giải phương trình bậc 2: ax2 + bx + c = 0 (a ≠ 0).

Bài 4: Nhập vào hai số x, y. Xuất ra màn hình tổng, hiệu, tích, thương của hai số trên.

Bài 5: Nhập vào số nguyên n, kiểm tra xem n chẵn hay lẻ và xuất ra màn hình.

Bài 6: Nhập vào ba cạnh a, b, c của tam giác. Xuất ra màn hình tam giác đó thuộc loại tam giác gì? (Thường, cân, vuông, đều hay vuông cân).

Bài 7: Tính n!, với n ≥ 0

Chương 2. Giới thiệu ngôn ngữ lập trình C++

1. Lịch sử hình thành

Ngôn ngữ lập trình C do Dennis Ritchie nghĩ ra khi ông làm việc tại AT&T Bell Laboratories vào năm 1972. Không phải ngẫu nhiên mà Dennis Ritchie nghĩ ra C. Vào thời gian đó ông cùng một vài đồng nghiệp có nhiệm vụ thiết kế một hệ điều hành mới mà ngày nay chúng ta biết đến như là hệ điều hành UNIX. Trong quá trình thiết kế, Dennis Ritchie nhận thấy trong tất cả các ngôn ngữ hiện có lúc đó, không có ngôn ngữ nào thích hợp để họ có thể sử dụng vào đồ án của họ được. Cuối cùng Dennis Ritchie quyết định làm ra một ngôn ngữ mới để giải quyết những vấn đề mà họ gặp phải. Dennis Ritchie đẵ tham khảo rất nhiều các ngôn ngữ có từ trước, và đặc biệt là ngôn ngữ B do Ken Thompson cũng làm việc tại Bell Labs nghĩ ra. Rất nhiều phần của ngôn ngữ này được ông đưa vào C. Chính vì vậy mà Dennis Ritchie đã chọn ngay chữ cái tiếp theo của B (tức là C) để đặt tên cho ngôn ngữ mới này.

Vì C là một ngôn ngữ mạnh và có tính linh hoạt, nó đã nhanh chóng được sử dụng một cách rộng rãi, vượt ra khỏi phạm vi của Bell Labs. Các lập trình viên ở khắp mọi nơi bắt đầu sử dụng nó để viết tất cả các loại chương trình. Tuy nhiên, nhiều tổ chức đã nhanh chóng đưa ra các versions C của riêng họ và những sự khác biệt tinh tế của các phần được bổ sung bắt đầu khiến các lập trình viên đau đầu. Vì vậy vào năm 1983, Viện tiêu chuẩn Quốc gia Hoa Kỳ (the American National Standards Institute - ANSI) đã thành lập một ủy ban để đưa ra một tiêu chuẩn cho C, được biết với cái tên ANSI C. Trừ một vài ngoại lệ,  tất cả các trình dịch C hiện đại đều cố gắng theo sát tiêu chuẩn này.

C++ được biết đến như là ngôn ngữ mới bao trùm lên C và do Bjarne Stroustrup sáng tác năm 1980 cũng tại phòng thí nghiệm Bell tại bang New Jersey, Mỹ. Ban đầu được ông đặt tên cho nó là “C with classes” (C với các lớp). Tuy nhiên đến năm 1983 thì ông đổi tên thành C++, trong đó ++ là toán tử tăng thêm 1 của C.

Mặc dù C là một ngôn ngữ được giới lập trình chuyên nghiệp yêu thích song nó vẫn có những hạn chế của nó. Nếu một khi số dòng lệnh vượt hơn 25000 thì công việc sẽ trở nên rất phức tạp. C++ được tạo ra để xóa bỏ chướng ngại này. Điều cơ bản của C++ là cho phép người lập trình hiểu và quản lý các chương trình lớn, phức tạp hơn.

C++ được biết đến như là ngôn ngữ lập trình hướng sự vật hay hướng đối tượng - OOP (Object Oriented Programming).

2. Đặc điểm

C là một ngôn ngữ mạnh và linh hoạt. “Những gì bạn có thể làm với C chỉ thua có trí tưởng tượng của bạn mà thôi”. Ngôn ngữ không đưa ra các ràng buộc đối với bạn. C được sử dụng trong nhiều dự án khác nhau, như viết hệ điều hành, chương trình xử lý văn bản, đồ hoạ, bảng tính, và thậm chí cả chương trình dịch cho các ngôn ngữ khác.

C là ngôn ngữ được các lập trình viên chuyên nghiệp ưa thích hơn cả. Cũng vì vậy mà có sẵn rất nhiều các trình biên dịch (compiler) và các thư viện được viết sẵn khác.

C là một ngôn ngữ khả chuyển (portable language). ghĩa là một chương trình viết bằng C cho một hệ máy tính (ví dụ như IBM PC) có thể được dịch và chạy trên hệ máy tính khác (chẳng hạn như DEC VAX) chỉ với rất ít các sử đổi. Tính khả chuyển đã được bởi chuẩn ANSI cho C.

C chỉ gồm một số ít từ khoá (keywords) làm nền tảng để xây dựng các các chức năng của ngôn ngữ. Có lẽ bạn nghĩ rằng một ngôn ngữ với nhiều từ khoá (đôi khi còn được gọi là từ dành riêng - reserved words) sẽ mạnh hơn. Không phải như vậy. Khi lập trình với C, bạn sẽ thấy rằng nó có thể dùng để lập trình giải quyết bất kỳ bài toán nào.

C là ngôn ngữ lập trình theo modul. Mã chương trình C có thể (và nên) được viết thành các thủ tục gọi là function. Những function này có thể được sử dụng lại trong các ứng dụng (application) và chương trình khác nhau. Tuy nhiên C không cho phép khai báo hàm trong hàm.

Đó là những đặc điểm nổi bật của C, vì C++ bao trùm lên C nên mọi đặc điểm của C đều có trong C++. Ngoài ra, C++ còn có một số đặc điểm khác như:

+ C++ là ngôn ngữ hướng đối tượng.

+ C++ là ngôn ngữ định kiểu rất mạnh.

+ C++ cung cấp cách truyền tham số bằng tham chiếu cho hàm.

+ C++ cung cấp cơ cấu thư viện để người lập trình có thể tự tạo thêm hàm thông dụng vào thư viện và có thể tái sử dụng sau này.

+ C++ cung cấp một cơ chế đa dạng hóa tên hàm và toán tử, cho phép sử dụng cùng một tên hàm hoặc cùng một ký hiệu của toán tử để định nghĩa các chương trình con thực hiện các nhiệm vụ tương tự nhau với tập kiểu dữ liệu tham số khác nhau.

+ C++ cung cấp các class là loại cấu trúc mới đóng gói chung cho cả dữ liệu lẫn các hàm trong một chủ thể được bảo vệ một cách chặt chẽ.

+ C++ Cung cấp các class con trong đó một class có thể kế thừa dữ liệu và hàm của class khác là các class cha mẹ, tạo ra sự di truyền.

3. Cấu trúc của một chương trình C++

Một chương trình C++ nói chung có dạng như sau:

(1): Khai báo thư viện

(2): [Khai báo các nguyên mẫu hàm của người dùng].

(3): [Các định nghĩa kiểu].

(4): [Các định nghĩa Macro].

(5): [Các định nghĩa biến, hằng].

(6): <kiểu hàm> main ([khai báo tham số]).

(7): {

(8): Thân hàm main

(9): }

(10): Các định nghĩa hàm của người dùng.

Chú ý: Các thành phần trong cặp ngoặc vuông [] có thể có hoặc không trong chương trình.

Giải thích cú pháp:

(1): Cú pháp để khai báo thư viện: #include<tên_thư_viên.h>

Ví dụ: #include<iostream.h>; #include<conio.h>;…

(2): Cung cấp tên hàm, kiểu hàm, số đối số và kiểu của từng đối số của hàm.

Cú pháp khai báo nguyên mẫu hàm: <kiểu hàm> <tên hàm> ([Khai báo các đối số]);

Ví dụ: int chanle (int x); Trong đó, kiểu hàm là int, tên hàm là chanle, đối số là x và kiểu của đối số là int.

(3): Định nghĩa kiểu mới: Ngoài những kiểu chuẩn đã được cung cấp sẵn của ngôn ngữ, người lập trình có thể định nghĩa ra các kiểu mới từ những kiểu đã có bằng cách sử dụng từ khóa typedef.

(4): Định nghĩa Macro: Khái niệm macro là gì? Giả sử như bạn có một nội dung (giá trị) nào đó và bạn muốn sử dụng nó nhiều lần trong chương trình, nhưng bạn không muốn viết trực tiếp nó vào chương trình lúc bạn soạn thảo vì một vài lý do nào đó (chẳng hạn như nó sẽ làm chương trình khó đọc, khó hiểu, hoặc khi thay đổi sẽ khó,..). Lúc này bạn hãy gán cho nội dung đó một ‘tên’ và bạn sử dụng ‘tên’ đó để viết trong chương trình nguồn. Khi biên dịch chương trình, chương trình dịch sẽ tự động thay thế nội dung của ‘tên’ vào đúng vị trí của ‘tên’ đó. Thao tác này gọi là phép thế macro và chúng ta gọi ‘tên’ là tên của macro và nội dung của nó được gọi là nội dung của macro.

Một macro được định nghĩa như sau:

#define tên_macro nội_dung

Trong đó tên macro là một tên hợp lệ, nội dung (giá trị) của macro được coi thuần tuý là 1 xâu cần thay thế vào vị trí xuất hiện tên của macro tương ứng, giữa tên và nội dung cách nhau 1 hay nhiều khoảng trống (dấu cách). Nội dung của macro bắt đầu từ kí tự khác dấu trống đầu tiên sau tên macro cho tới hết dòng.

(5): Các định nghĩa biến, hằng: Các biến và hằng được định nghĩa tại đây sẽ trở thành biến và hằng toàn cục. Ý nghĩa về biến, hằng, cú pháp định nghĩa đã được trình bày trong mục biến và hằng.

(6) – (9): Hàm main():Đây là thành phần bắt buộc trong một chương trình C++, thân của hàm main bắt đầu từ sau dấu mở móc { (dòng 7) cho tới dấu đóng móc } (dòng 9).

(10): Các định nghĩa hàm của người dùng: Một định nghĩa hàm bao gồm tiêu đề của hàm, thân hàm với cú pháp như sau:

<Kiểu hàm> <Tên hàm> ([Khai báo các đối])

{

<Thân hàm>

}

Chú ý: Tiêu đề trong định nghĩa hàm phải tương ứng với nguyên mẫu hàm.

Nếu trong chương trình định nghĩa hàm xuất hiện trước khi gặp lời gọi hàm đó thì có thể không nhất thiết phải có dòng khai báo nguyên mẫu hàm.

4. Một số ví dụ mẫu

Ví dụ 1: Chương trình nhập vào điểm 3 môn: Toán, Lý, Hóa và tính điểm trung bình của 3 môn đó.

//Khai báo thư viện

#include<iostream.h>

//Bắt đầu hàm main

int main()

{

//Khai báo 3 biến

double dtb,dt,dl,dh;

//Nhập vào 3 điểm Toán, Lý, Hóa

cout<<"Diem toan la:";

cin>>dt;

cout<<"diem ly la:"; cin>>dl;

cout<<"Diem hoa la:"; cin>>dh;

dtb = (dt+dl+dh)/3;

cout<<"diem trung binh 3 mon la:"<<"="<<dtb<<"\n";

if (dtb<5)

cout<<"Hoc luc yeu";

if (dtb>=5&&dtb<7)

cout<<"Hoc luc trung binh";

if (dtb>=7 && dtb<8)

cout<<"Hoc luc kha";

else

cout<<"Hoc luc gioi";

return 0;

} //Kết thúc hàm main

Ví dụ 2: Viết chương trình có sử dụng hàm tìm số lớn nhất trong 3 số x, y, z;

//Khai báo thư viện

#include<iostream.h>

//Khai báo hàm có tên là maxabc

float maxabc (float a, float b, float c)

{

float max;

max = a>b?a:b;

return (max>c?max:c);

}

//Bắt đầu hàm main

main()

{

//Khai báo 4 biến

float x,y,z,t;

//Nhập giá trị cho các biến

cout<<"x = "; cin>>x;

cout<<"y = "; cin>>y;

cout<<"z = "; cin>>z;

t = maxabc (x,y,z);

cout<<"So lon nhat trong 3 so la: "<<t;

} //Kết thúc hàm main

5. Cài đặt chương trình

Chúng ta sẽ sử dụng Turbo C++ 4.5 trong phần tài liệu này.

Để cài đặt Turbo C++ 4.5 bạn làm theo hướng dẫn sau:

Bước 1: Vào thư mục chứa bộ cài TurboC++ 4.5, chọn file Install.exe, click đúp vào thư mục đó. Xuất hiện hình sau:

Bước 2: Click Continue. Màn hình sau hiện ra:

Bước 3: Tắt màn hình Install.txt. Màn hình sau hiện ra, bạn click Continue:

Bước 4: Click Continue:

Bước 5: Màn hình sau hiện ra, bạn click vào Install:

Bước 6: Quá trình cài đặt bắt đầu chạy. Sau khi quá kết thúc quá trình đó, màn hình sau hiện ra, bạn click Continue:

Bước 7: Màn hình hiển thị Readme.txt. Bạn close cửa sổ đó lại. Click OK.

Bước 8: Màn hình hiển thị đăng ký:

Bước 9: Bạn điền đầy đủ thông tin vào các mục trong hình sau:

Bước 10: Click Continue/Ok.

Các bước cài đặt đã hoàn tất.

6. Khởi động chương trình

Để khởi động chương trình bạn sử dụng một số cách sau:

Cách 1: Start/Program/Turbo C++ 4.5/Turbo C++.

Cách 2: Click đúp vào biểu tượng Turbo C++ trên màn hình.

7. Soạn thảo chương trình

Màn hình soạn thảo của Turbo C++ 4.5 có dạng sau:

8. Thoát khỏi chương trình

Trước khi thoát khỏi chương trình Turbo C++, bạn hãy Save/Save as toàn bộ chương trình.

Để thoát khỏi chương trình có thể sử dụng một số cách sau:

Cách 1: Click menu File/Exit.

Cách 2: Click vào biểu tượng bên phải màn hình.

Chương 3. Các thành phần và các kiểu dữ liệu cơ bản

1. Các thành phần

Các thành phần trong C++ bao gồm:

+ Từ khóa.

+ Các khai báo biến, hằng.

+ Các cấu trúc điều khiển.

+ Biểu thức và các phép toán.

+ Các định nghĩa, khai báo hàm, khai báo kiểu,…

2. Các kiểu dữ liệu căn bản

Một trong mục đích của các chương trình là xử lý, biến đổi thông tin, các thông tin cần xử lý phải được biểu diễn theo một cấu trúc xác định nào đó ta gọi là các kiểu dữ liệu. Các kiểu dữ liệu này được quy định bởi ngôn ngữ lập trình, hay nói khác đi mỗi ngôn ngữ có tập các kiểu dữ liệu khác nhau. Không hoàn toàn giống như khái niệm kiểu dữ liệu trong toán học, trong các ngôn ngữ lập trình nói chung mỗi kiểu dữ liệu chỉ biểu diễn được một miền giá xác định nào đó. Chẳng hạn như số nguyên chúng ta hiểu là các số nguyên từ - ∞ tới + ∞, nhưng trong ngôn ngữ lập trình miền các giá trị này bị giới hạn, sự giới hạn này phụ thuộc vào kích thước của vùng nhớ biểu diễn số đó. Vì vậy khi nói tới một kiểu dữ liệu chúng ta phải đề cập tới 3 thông tin đặc trưng của nó đó là:

- Tên kiểu dữ liệu.

- Kích thước vùng nhớ biểu diễn nó,miền giá trị.

- Các phép toán có thể sử dụng.

Các kiểu dữ liệu đơn giản trong C++ chỉ là các kiểu số, thuộc hai nhóm chính đó là số nguyên và số thực (số dấu phẩy động).

Nhóm các kiểu nguyên gồm có: char, unsigned char, int, unsigned int, short, unsigned short, long, unsigned long được mô tả trong bảng sau:

Kiểu dữ liệu

Tên kiểu

(từ khoá)

Kích thước

Miền giá trị

Kí tự có dấu

char

1 byte

từ -128 tới 127

Kí tự không dấu

unsigned char

1 byte

từ 0 tới 255

Số nguyên có dấu

int

2 byte

từ -32768 tới 32767

Số nguyên không dấu

unsigned int

2 byte

từ 0 tới 65535

Số nguyên ngắn có dấu

short

2 byte

từ -32768 tới 32767

Số nguyên ngắn có dấu

unsigned short

2 byte

từ 0 tới 65535

Số nguyên dài có dấu

long

4 byte

từ -2,147,483,648 tới 2,147,438,647

Số nguyên dài không dấu

unsigned long

4 byte

từ 0 tới 4,294,967,295

Nhóm các kiểu số thực gồm: float, double, long double

Khuôn dạng biểu diễn của số thực không giống như số nguyên. Một số thực nói chung được biểu diễn theo ký pháp khoa học gồm phần định trị và phần mũ viết sau chữ E để biểu diễn số mũ cơ số 10.

Ví dụ: 3.14 = 314*10-2 sẽ được viết theo ký pháp khoa học là: 314E – 2.

Hoặc: 314 = 3.14 *102 sẽ được viết theo ký pháp khoa học là: 3.14E + 2.

Nhóm các kiểu số thực được mô tả trong bảng sau:

Kiểu dữ liệu

Tên kiểu

Kích thước

Miền giá trị

Số thực với độ chính xác đơn

float

4 byte

3.4e-38 -> 3.4e38

Số thực với độ chính xác kép

double

8 byte

1.7e-308 -> 1.7e308

Số thực dài với độ chính xác kép

long double

10 byte

3.4e-4832 -> 1.1e 4932

3. Hằng

3.1. Khái niệm

Hằng là đại lượng có giá trị thuộc một kiểu dữ liệu nhất định, nhưng giá trị của hằng không thể thay đổi trong thời gian tồn tại của nó.

Có hai loại hằng một là các hằng không có tên (chúng ta sẽ gọi là hằng thường) đó là các giá trị cụ thể tức thời như : 8, hay 9.5 hoặc ‘d’.

Loại thứ hai là các hằng có tên ( gọi là hằng ký hiệu). Các hằng ký hiệu cũng phải định nghĩa trước khi sử dụng, tên của hằng được đặt theo quy tắc của tên. Sau đây nếu không có điều gì đặc biệt thì chúng ta gọi chung là hằng.

3.2. Định nghĩa hằng

Các hằng được định nghĩa bằng từ khoá const với cú pháp như sau:

const <kiểu_dữ_liệu> <tên_hằng> = <giá_trị>;

hoặc const <tên_hằng> = <giá_trị>;

Trong dạng thứ hai, chương trình dịch tự động ấn định kiểu của hằng là kiểu ngầm định, chương trình dịch sẽ tự động chuyển kiểu của <giá_trị> về kiểu int.

Ví dụ:

const int a = 5; // định nghĩa hằng a kiểu nguyên, có giá trị là 5

const float x = 4; // hằng x kiểu thực, có giá trị là 4.0

const d = 7; // hằng d kiểu int, giá trị là 7

const c = ‘1’; // hằng c kiểu int giá trị = 49

const char * s = “Ngon ngu C++”;// s là hằng con trỏ, trỏ tới xâu “Ngo ngu C++”

Các hằng số trong C++ được ngầm hiểu là hệ 10, nhưng bạn có thể viết các hằng trong hệ 16 hoặc 8 bằng cú pháp, giá trị số hệ 16 được bắt đầu bằng 0x, ví dụ như 0x24, 0xA, các số hệ 8 bắt đầu bởi số 0, ví dụ 025, 057.

Các hằng kí tự được viết trong cặp dấu nháy đơn ‘’ : ví dụ ‘a’, ‘2’ các giá trị này được C++ hiểu là số nguyên có giá trị bằng mã của kí tự; ‘a’ có giá trị là 97, ‘B’ có giá trị bằng 66.

Các xâu kí tự là dãy các kí tự được viết trong cặp dấu nháy kép “”, ví dụ “Ngon ngu C”, “a” (là kiểu xâu kí tự ).

Chú ý: Các biến, hằng có thể được định nghĩa ngoài mọi hàm, trong hàm hoặc trong một khối lệnh. Với C chuẩn thì khi định nghĩa biến, hằng trong một khối thì dòng định nghĩa phải ở các dòng đầu tiên của khối, tức là trước tất cả các lệnh khác của khối, nhưng trong C++ bạn có thể đặt dòng định nghĩa bất kỳ vị trí nào.

4. Các phép toán của C++

STT

PHÉP TOÁN

Ý NGHĨA

GHI CHÚ

PHÉP TOÁN SỐ HỌC

1

+

Cộng

2

-

Trừ

3

*

Nhân

4

/

Chia lấy phần nguyên

5

%

Chia lấy phần dư

PHÉP TOÁN QUAN HỆ

1

>

Lớn hơn

2

<

Nhỏ hơn

3

>=

Lớn hơn hoặc bằng

4

<=

Nhỏ hơn hoặc bằng

5

= =

Bằng nhau

6

!=

Khác nhau

PHÉP TOÁN LOGIC

1

!

NOT

2

&&

AND

3

||

OR

TOÁN TỬ TĂNG GIẢM

1

++

Tăng 1

Nếu toán tử tăng giảm đặt trước thì tăng giảm trước rồi tính biểu thức hoặc ngược lại.

2

--

Giảm 1

PHÉP TOÁN THAO TÁC TRÊN BIT

1

&

AND

2

|

OR

3

^

XOR

4

<<

Dịch trái

5

>>

Dịch phải

6

~

Lấy phần bù theo bit

5. Xuất nhập dữ liệu

Trong thư viện iostream của C++, các thao tác vào ra cơ bản của một chương trình được hỗ trợ bởi hai dòng dữ liệu: cin để nhập dữ liệu và cout để xuất. Thông thường cout được gán với màn hình còn cin được gán với bàn phím.

5.1. Xuất dữ liệu (cout)

Dòng cout được sử dụng với toán tử đã quá tải << (overloaded - bạn sẽ hiểu rõ hơn về thuật ngữ này trong phần lập trình hướng đối tượng).

cout << "Output sentence"; // Hiển thị Output sentence lên màn hình

cout << 120; // Hiển thị số 120 lên màn hình

cout << x; // Hiển thị nội dung biến x lên màn hình

Toán tử << được gọi là toán tử chèn vì nó chèn dữ liệu đi sau nó vào dòng dữ liệu đứng trước. Trong ví dụ trên nó chèn chuỗi "Output sentence", hằng số 120 và biến x vào dòng dữ liệu ra cout. Chú ý rằng ở dòng đầu tiên chúng ta sử dụng dấu ngoặc kép vì đó là một chuỗi ký tự. Khi chúng ta muốn sử dụng các hằng xâu ký tự ta phải đặt chúng trong cặp dấu ngoặc kép để chúng có thể được phân biệt với các biến. Ví dụ, hai lệnh sau đây là hoàn toàn khác nhau:

cout << "Hello"; // Hiển thị Hello lên màn hình

cout << Hello; // Hiển thị nội dung của biến Hello lên màn hình

Toán tử chèn (<<) có thể được sử dụng nhiều lần trong một câu lệnh:

cout << "Hello, " << "I am " << "a C++ sentence";

Câu lệnh trên sẽ in thông báo Hello, I am a C++ sentence lên màn hình. Sự tiện lợi của việc sử dụng lặp lại toán tử chèn (<<) thể hiện rõ khi chúng ta muốn hiển thị nhiều biến và hằng hơn là chỉ một biến:

cout << "Hello, I am " << age << " years old and my email address is " << email_add;

Cần phải nhấn mạnh rằng cout không nhảy xuống dòng sau khi xuất dữ liệu, vì vậy hai câu lệnh sau:

cout << "This is a sentence."; cout << "This is another sentence.";

sẽ được hiển thị trên màn hình:

This is a sentence.This is another sentence.

Bởi vậy khi muốn xuống dòng chúng ta phải sử dụng ký tự xuống dòng, trong C++ là \n:

cout << "First sentence.\n "; cout << "Second sentence.\nThird sentence.";

sẽ viết ra màn hình như sau:

First sentence. Second sentence. Third sentence.

Thêm vào đó, để xuống dòng bạn có thể sử dụng tham số endl. Ví dụ:

cout << "First sentence." << endl; cout << "Second sentence." << endl;

sẽ in ra màn hình:

First sentence. Second sentence.

Tham số endl có một tác dụng đặc biệt khi nó được dùng với các dòng dữ liệu sử dụng bộ đệm: Các bộ đệm sẽ được flushed (chuyển toàn bộ thông tin từ bộ đệm ra dòng dữ liệu). Tuy nhiên, theo mặc định cout không sử dụng bộ đệm.

Các ký tự điều khiển

Đây là các kí tự đặc biệt, bắt đầu bằng kí tự \ tiếp theo là 1 kí tự dùng để điều khiển: chuyển con trỏ màn hình, vị trí in dữ liệu,..

- \n : chuyển con trỏ màn hình xuống dòng mới

- \t : dấu tab

- \b : (backspace) lùi một kí tự (xoá kí tự trước vị trí con trỏ hiện tại).

5.2. Nhập dữ liệu (cin)

Thao tác vào chuẩn trong C++ được thực hiện bằng cách sử dụng toán tử đã quá tải >> với dòng cin. Theo sau toán tử này là biến sẽ lưu trữ dữ liệu được đọc vào. Ví dụ:

int age; cin >> age;

khai báo biến age có kiểu int và đợi nhập dữ liệu từ cin (bàn phím) để lưu trữ nó trong biến kiểu nguyên này.

cin chỉ bắt đầu xử lý dữ liệu nhập từ bàn phím sau khi phím Enter được gõ. Vì vậy dù bạn chỉ nhập một ký tự thì cin vẫn sẽ kiên nhẫn chờ cho đến khi bạn gõ phím Enter.

Chương 4. Các cấu trúc điều khiển

1. Lệnh đơn và lệnh phức

1.1. Lệnh đơn

Một biểu thức kiểu như: a =5; a+ =6;… trở thành câu lệnh khi có đi kèm theo dấu chấm phẩy (;) phía cuối câu.

Ví dụ:

a = 5;

a+=6;

1.2. Lệnh phức hay khối lệnh

Lệnh phức là một dãy các các câu lệnh được bao bởi cặp dấu ngoặc nhọn {}.

Ví dụ 1:

{

S+=(i*i);

i++;

}

Ví dụ 2:

{

cout<<a[i][j]<<" ";

if (j==i)

cout<<"\n";

}

2. Cấu trúc điều kiện if..else

2.1. Dạng khuyết

If (biểu thức điều kiện)

{

Khối lệnh;

}

Cách hoạt động: Đầu tiên, chương trình kiểm tra biểu thức điều kiện sau if. Nếu biểu thức điều kiện đúng thì các câu lệnh trong khối lệnh trong cấu trúc if được thực hiện. Ngược lại, chương trình sẽ thoát ra khỏi cấu trúc if và thực hiện các lệnh tiếp theo sau cấu trúc if.

Biểu diễn dưới dạng lưu đồ cách hoạt động của cấu trúc if:

2.2. Dạng đầy đủ

if (biểu thức điều kiện)

{

Khối lệnh 1;

}

else

{

Khối lệnh 2;

}

Cách hoạt động: Đầu tiên, chương trình kiểm tra biểu thức điều kiện sau if, nếu biểu thức điều kiện đúng thì thực hiện các câu lệnh trong khối lệnh 1. Ngược lại, nếu biểu thức điều kiện sai sẽ thực hiện các câu lệnh trong khối lệnh 2.

Biểu diễn bằng lưu đồ của cấu trúc if..else:

Ví dụ 1: Sử dụng cấu trúc if và if..else để nhập vào điểm của 3 môn: Toán, lý, hóa và tính điểm trung bình:

#include<iostream.h>

int main()

{

double dtb,dt,dl,dh;

cout<<"Diem toan la:";

cin>>dt;

cout<<"diem ly la:"; cin>>dl;

cout<<"Diem hoa la:"; cin>>dh;

dtb = (dt+dl+dh)/3;

cout<<"diem trung binh 3 mon la:"<<"="<<dtb<<"\n";

if (dtb<5)

cout<<"Hoc luc yeu";

if (dtb>=5&&dtb<7)

cout<<"Hoc luc trung binh";

if (dtb>=7 && dtb<8)

cout<<"Hoc luc kha";

else

cout<<"Hoc luc gioi";

return 0;

}

Ví dụ 2: Giải phương trình bậc 1: ax + b = 0

#include<iostream.h>

#include<math.h>

int main()

{

int a,b;

float x;

cout<<"Nhap a va b:"<<"\n";

cin>>a>>b;

if (a==0 && b==0)

cout<<"Bat phuong trinh co vo so nghiem";

if (a==0 && b!=0)

cout<<"Bat phuong trinh vo nghiem";

if (a!=0)

cout<<"Bat phuong trinh co nghiem x = "<<-b/a;

}

Ví dụ 3: Viết chương trình nhập vào 1 số, tính căn bậc 2 của số đó

//Chuong trinh tinh can bac 2

#include<iostream.h>

#include<math.h>

main()

{

int a;

cout<<"Nhap a = "; cin>>a;

if (a<0)

cout<<"Khong tinh duoc";

if (a>0)

cout<<"Can bac hai cua a la: "<< sqrt(a);

}

3. Cấu trúc lựa chọn: switch..case

Cấu trúc switch..case cho phép lựa chọn một nhánh trong nhiều khả năng tùy vào điều kiện xảy ra.

Cú pháp:

switch (Biểu thức nguyên)

{

case n1: Khối lệnh 1;

case n2: Khối lệnh 2;

case nk: Khối lệnh k;

[default: Khối lệnh; ]

}

Trong đó: ni là các số nguyên, hằng ký tự hoặc biểu thức hằng. Các ni cần có giá trị khác nhau.

Đoạn chương trình nằm trong cặp ngoặc nhọn {} là thân của switch.

default, case là các từ khóa. default là thành phần không bắt buộc.

Cách hoạt động: sự hoạt động của cấu trúc switch..case phụ thuộc vào giá trị của biểu thức nguyên sau switch.

Đầu tiên <biểu thức nguyên> được tính, sau đó lần lượt so sánh giá trị của <bt nguyên> với các biểu thức hằng <n1>, <n2>,..<nk>.

Nếu giá trị của một biểu thức hằng thứ k trong các biểu thức này trùng với giá trị của <biểu thức nguyên> thì chương trình sẽ thực hiện các lệnh bắt đầu từ khối lệnh k và tiếp tục các lệnh phía dưới cho tới khi:

+ Gặp câu lệnh : break (tất nhiên nếu gặp các câu lệnh return, exit thì cũng kết thúc).

+ Gặp dấu đóng móc } hết cấu trúc switch.

Nếu <biểu thức nguyên> không trùng với giá trị nào trong các biểu thức hằng thì khối lệnh (các lệnh sau mệnh đề default nếu có) sẽ được thực hiện, rồi ra khỏi cấu trúc switch.

Ví dụ 1: Sử dụng cấu trúc switch..case, hãy viết chương trình: nếu nhập vào là ‘P’ hoăc ‘p’ thì hiển thị dòng chữ “Cao dang co dien Ha Noi”.

#include<iostream.h>

main()

{

char ch;

cout<<"Nhap vao ky tu P hoac p: "; cin>>ch;

switch (ch)

{

case 'P':

case 'p':

cout<<"Cao dang co dien Ha Noi";

}

}

Ví dụ 2: Viết chương trình sử dụng cấu trúc switch..case, nhập 2 số nguyên x, y từ bàn phím, chương trình đưa ra lựa chọn:

+ Nếu người sử dụng nhập ‘+’: Thực hiện: x + y;

+ Nếu người sử dụng nhập ‘-‘: Thực hiện: x – y;

+ Nếu người sử dụng nhập ‘*’: Thực hiện: x * y;

+ Nếu người sử dụng nhập ‘/‘: Thực hiện: x / y;

Nếu người sử dụng không nhập một trong các toán tử trên thì đưa ra dòng thông báo: “Khong hieu toan tu nay!”.

#include <iostream.h>

int main()

{

int X;

cout<< "Nhap vao so thu nhat:";

cin>>X;

int Y;

cout<< "Nhap vao so thu hai:";

cin>>Y;

char Op;

cout<<"Nhap vao toan tu (+-*/):";

cin>>Op;

switch(Op)

{

case '+':

cout<<"Ket qua:"<<X+Y<<"\n";

break;

case '-':

cout<<"Ket qua:"<<X-Y<<"\n";

break;

case '*':

cout<<"Ket qua:"<<long(X)*Y<<"\n";

break;

case '/':

if (Y)

cout<<"Ket qua:"<<float(X)/Y<<"\n";

else

cout<<"Khong the chia duoc!" <<"\n";

break;

default :

cout<<"Khong hieu toan tu nay!"<<"\n";

}

return 0;

}

4. Các cấu trúc lặp

4.1. Cấu trúc lặp while

Cú pháp:

while(biểu thức)

Khối lệnh; // Hay thân while

Sự hoạt động của vòng lặp while:

Bước 1: tính giá trị của <biểu thức sau while>

Bước 2: nếu giá trị tính được của <biểu thức> là ‘sai’ (==0) thì kết thúc vòng lặp while.

Bước 3: nếu giá trị của <biểu thức> là ‘đúng’ (!=0) thì thực hiện khối lệnh sau while.

Bước 4: quay lại bước 1

Chú ý: Thân while có thể được thực hiện một lần hoặc nhiều lần và cũng có thể không được thực hiện lần nào nếu ngay từ đầu biểu thức sau while đã sai.

Biểu diễn bằng lưu đồ:

Ví dụ 1:

#include<iostream.h>

main()

{

int n;

cout<< "Nhap vao 1 so (hay day so khong cach)"; cin>>n;

while (n>0) {

cout<< n<< ",";

--n;

}

cout<< "Ket thuc";

return 0;

}

Ví dụ 2: Viết chương trình tính và in S = 1 +1/(2!) +1/(3!)+..+1/(n!) với n nhập từ bàn phím, 0<n<10.

#include <iostream.h>

const int Max =10; // gioi han

void main()

{

int n, k ;

float S, pt;

cout<<"\nNhap n = ";

cin>>n;

while((n<=0)||(n>Max))

{

cout<<"\nNhap lai n (0<n<="<<Max;

cin>>n;

}

S=pt=1; k=2;

while(k<=n)

{

pt /=k;

S+=pt;

k++;

}

cout<<"\nGia tri tong S = “<<S;

}

Ví dụ 3: Viết chương trình nhập số nguyên n từ bàn phím, n <=10 và n >0, tính và in giá trị n! (giai thừa của n), với n! = 1*2*…*(n-1)*n

#include <iostream.h>

const int Max =10; // giới hạn giá trị cần tính

void main()

{

int n, i;

long gt;

cout<<"\nNhap n = ";

cin>>n;

while((n<=0)||(n>Max))

{

cout<<"\nNhap lai n (0<n<= : "<< Max;

cin>>n;

}

gt=i=1;

while(i<=n)

{

gt*=i;

i++;

}

cout<<"\nGia tri n = “<<gt;

}

4.2. Cấu trúc lặp do..while

Trong toán tử while việc kiểm tra điều kiện kết thúc đặt ở đầu chu trình. Khác với while, do..while việc kiểm tra điều kiện kết thúc đặt cuối chu trình. Như vậy thân của chu trình bao giờ cũng được thực hiện ít nhất một lần.

Cú pháp:

do

Khối lệnh;

while (biểu thức);

Sự hoạt động của vòng lặp do..while:

Bước 1: thực hiện khối lệnh sau do.

Bước 2: kiểm tra giá trị biểu thức <biểu thức> sau while, nếu có giá trị ‘đúng’ ( khác 0) thì lặp lại bước 1, nếu ‘sai’ (=0) thì kết thúc vòng lặp.

Biểu diễn dưới dạng lưu đồ:

Ví dụ 1:

#include<iostream.h>

main()

{

unsigned long n;

do {

cout<< "Nhap vao 1 day so khong cach"; cin>>n;

cout<< "Ban da nhap so"<<n<<endl;

}

while (n!=0);

return 0;

}

Ví dụ 2:

#include<iostream.h>

int main()

{

unsigned long n;

do

{

cout<<"Nhap vao 1 day so:";

cin>>n;

cout<<" Ban vua nhap day so la:"<<n<< "\n";

}

while (n!=0);

return 0;

}

4.3. Cấu trúc lặp for

Cú pháp:

for (biểu thức 1; biểu thức 2; biểu thức 3)

Khối lệnh;

Trong đó:

Biểu thức 1: biểu thức khởi đầu.

Biểu thức 2: biểu thức điều kiện - điều kiện lặp.

Biểu thức 3: bước nhảy - thường dùng với ý nghĩa là thay đổi bước nhảy.

Cả 3 biểu thức này đều là tuỳ chọn, chúng có thể vắng mặt trong câu lệnh cụ thể nhưng các dấu chấm phẩy vẫn phải có.

Sự hoạt động của vòng lặp for:

Hoạt động của for theo các bước sau:

Bước 1: Thực hiện biểu thức khởi đầu – Biểu thức 1.

Bước 2: Tính giá trị biểu thức 2 để xác định điều kiện lặp.

Nếu biểu thức 2 có giá trị ‘sai’ (==0) thì ra khỏi vòng lặp.

Ngược lại, nếu biểu thức có giá trị ‘đúng’ ( khác 0) thì chuyển tới bước 3.

Bước 3: Thực hiện khối lệnh sau for ( thân của for ), chuyển tới bước 4.

Bước 4: Thực hiện biểu thức, rồi quay về bước 2.

Biểu diễn dưới dạng lưu đồ:

Ví dụ 1:

#include<iostream.h>

main()

{

for (int n = 10; n>0; n--)

{

cout<< n<< ",";

}

cout<< "Ket thuc";

return 0;

}

Ví dụ 2: Nhập vào một dãy số nguyên, tìm số lớn nhất và nhỏ nhất trong dãy.

#include <iostream.h>

void main()

{

int n,a,max,min,i;

do

{

cout<<"Nhap so phan tu cua day : ";

cin>>n;

}while(n<1);

cout<<"Nhap so thu nhat : ";

cin>>a;

max=min=a;

for(i=2; i<=n; i++)

{

cout<<"Nhap so thu nhat : ";

cin>>a;

if(a>max)

max=a;

else

if(a<min)

min =a;

}

cout<<"\nGia tri lon nhat =”<<max<<”\nGia tri nho nhat = "<<min;

}

5. Câu lệnh break, continue, goto và hàm exit

5.1. Câu lệnh break

Câu lệnh break cho phép ra khỏi các chu trình với các toán tử for, while và switch. Khi có nhiều chu trình lồng nhau, câu lệnh break sẽ kết thúc câu lệnh điều khiển đang sử dụng và ra khỏi bên trong nhất chứa nó không cần điều kiện gì. Mọi câu lệnh break có thể thay bằng câu lệnh goto với nhãn thích hợp.

Ví dụ: Cho phép người dùng nhập liên tục giá trị n cho đến khi nhập âm thì dừng.

#include<iostream.h>

void main()

int n;

{

while (1)

{

cout<<“\nNhap n: ”;

cin>>n;

if(n<0)

break;

}

}

5.2. Câu lệnh continue

Trái với câu lệnh break, continue dùng để bắt đầu một vòng mới của chu trình chứa nó. Trong while và do .. while, lệnh continue chuyển điều khiển về thực hiện ngay phần kiểm tra, còn trong vòng lặp for điều khiển được chuyển về bước khởi đầu lại (tức là bước: tính biểu thức 3, sau đó quay lại bước 2 để bắt đầu một vòng mới của chu trình).

Chú ý: Lệnh continue chỉ áp dụng cho chu trình, không áp dụng cho switch.

Ví dụ: In ra màn hình giá trị từ 10 đến 20 trừ đi số 13 và số 17.

#include<iostream.h>

void main()

{

for(int i=10 ; i<=20; i++)

{

if(i==13||i==17)

continue;

cout<<i<<",";

}

cout<<"Ket thuc;";

}

5.3. Câu lệnh goto

Lệnh goto cho phép nhảy vô điều kiện tới bất kỳ điểm nào trong chương trình.

Ví dụ:

#include <iostream.h>

int main ()

{

int n=10;

loop: ;

cout << n << ", ";

n--;

if (n>0) goto loop;

cout << "Kết thúc!";

return 0;

}

5.4. Hàm exit

Hàm exit() trong C/C++ được sử dụng để thoát khỏi chương trình. Hàm này, khi được triệu gọi sẽ ngay lập tức kết thúc chương trình và chuyển quyền điều khiển cho hệ điều hành.

Cú pháp: exit (int mã_trả_về);

mã_trả_về thường là số 0. Số 0 sẽ xác định việc kết thúc chương trình một cách bình thường. Tuy nhiên có một vài trường hợp mã_trả_về là những số khác 0 để xác định một vài loại lỗi.

Bài tập luyện

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 giải phương trình bậc hai ax2 + bx + c = 0 (a ≠ 0)

Bài 3: Viết chương trình giải phương trình bậc hai ax2 + bx + c = 0 (a bất kỳ)

Bài 4: Viết chương trình nhập vào N, kiểm tra N có phải là số nguyên tố không ?

Bài 5: Viết chương trình nhập vào N, tính tổng và in ra tất cả các số ước số của N.

Ví dụ: N = 20

- Tập các ước số của 20 là: 1, 2, 4, 5, 10, 20

- Tổng các ước số = 42

Bài 6:

Viết chương trình nhập vào số nguyên dương N, tính tổng

a. S1 = 1 + 2 + 3 + 4 +…..+ N

b. S2 = 12 + 22 + 32 + 42 +…..+ N2

Chương 5. Hàm

1. Khái niệm

Hàm là một đoạn chương trình độc lập thực hiện trọn vẹn một công việc nhất định sau đó trả về giá trị cho chương trình gọi nó, hay nói cách khác hàm là sự chia nhỏ của chương trình.

2. Khai báo hàm

2.1. Cú pháp khai báo nguyên mẫu hàm

<Kiểu_hàm> Tên_hàm ([Danh_sách_tham_số]);

Trong đó:

Tên_hàm: là một tên hợp lệ theo quy tắc về tên của ngôn ngữ C/C++. Mỗi hàm có tên duy nhất và không được trùng với các từ khóa. Tên hàm sẽ được dùng để gọi hàm.

Kiểu_hàm: Hàm có thể trả về một giá trị cho nơi gọi, giá trị đó thuộc một kiểu dữ liệu nào đó, kiểu đó được gọi là kiểu hàm. Kiểu hàm có thể là kiểu chuẩn cũng có thể là kiểu do người dùng định nghĩa. Nếu hàm không trả về giá trị thì kiểu hàm là void.

Danh_sách_tham_số: Hàm có thể nhận dữ liệu vào thông qua các tham số của nó (tham số hình thức), các tham số này cũng thuộc kiểu dữ liệu xác định. Có thể có nhiều tham số, các tham số cách nhau bởi dấu phẩy (,). Trong nguyên mẫu không bắt buộc phải có tên tham số nhưng kiểu của nó thì bắt buộc. Nếu hàm không có tham số chúng ta có thể để trống phần này hoặc có thể khai báo là void.

Ví dụ:

int max(int a, int b); // khai báo nguyên mẫu hàm max, có hai tham số kiểu int, kết quả trả về kiểu int.

float f(float, int); // nguyên mẫu hàm f, có hai tham số, tham số thứ nhất kiểu float, tham số thứ 2 kiểu int, kết quả trả về kiểu float.

void nhapmang(int a[], int ); // hàm nhapmang, kiểu void (không có giá trị trả về), tham số thứ nhất là một mảng nguyên, tham số thứ 2 là một số nguyên.

void g(); // hàm g không đối, không kiểu.

2.2. Định nghĩa hàm

Cú pháp:

<kiểu_hàm> <tên_hàm>([khai_báo_tham_số])

{

< thân hàm>

}

Dòng thứ nhất là tiêu đề hàm (dòng tiêu đề) chứa các thông tin về hàm: tên hàm, kiểu của hàm (hai thành phần này giống như trong nguyên mẫu hàm) và khai báo các tham số (tên và kiểu) của hàm, nếu có nhiều hơn một thì các tham số cách nhau bởi dấu phẩy(,).

Thân hàm là các lệnh nằm trong cặp { }, đây là các lệnh thực hiện chức năng của hàm.

Trong hàm có thể có các định nghĩa biến, hằng hoặc kiểu dữ liệu; các thành phần này trở thành các thành phần cục bộ của hàm.

Ví dụ:

unsigned long giaithua (int n)

{

unsigned long ketqua =1;

int i;

for (i =2; i<=n; i++)

ketqua = ketqua*i;

return ketqua;

}

3. Kết quả trả về của hàm – Lệnh return

Nếu hàm có giá trị trả về (kiểu hàm khác void) thì trong thân hàm trước khi kết thúc phải có câu lệnh trả về giá trị:

return <giá trị>;

<giá_trị> sau lệnh return chính là giá trị trả về của hàm, nó phải có kiểu phù hợp với kiểu của hàm được khai báo trong dòng tiêu đề. Trường hợp hàm void chúng ta có thể dùng câu lệnh return (không có giá trị) để kết thúc hàm hoặc khi thực hiện xong lệnh cuối cùng (gặp } cuối cùng) hàm cũng kết thúc.

Ví dụ: Hàm nhập một mảng có n phần tử nguyên:

Tên hàm: nhapmang.

Giá trị trả về: không trả về.

Tham số: có hai tham số là mảng cần nhập A và số phần tử cần nhập N

Nguyên mẫu hàm là: void nhapmang (int [], int);

định nghĩa hàm như sau:

void nhapmang (int A[], int N)

{

int i;

cout<<"\nNhap so phan tu cua mang ";

for(i=0;i<N; i++)

{

cout<<"a[“<<i<< ”]= ";

cin>>a[i];

}

return ;

}

4. Lời gọi hàm và Cách truyền tham số cho hàm

Một hàm có thể gọi thực hiện thông qua tên hàm, với những hàm có tham số thì trong lời gọi phải truyền cho hàm các tham số thực sự (đối số) tương ứng với các tham số hình thức.

Khi hàm được gọi và truyền tham số phù hợp thì các lệnh trong thân hàm được thực hiên bắt đầu từ lệnh đầu tiên sau dấu mở móc { và kết thúc khi gặp lệnh return, exit hay gặp dấu đóng móc } kêt thúc hàm.

Cú pháp:

<tên_hàm> ([danh sách các tham số thực sự]);

Các tham số thực sự phải phù hợp với các tham số hình thức:

Số tham số thực sự phải bằng số tham số hình thức.

Tham số thực sự được truyền cho các tham số hình thức tuần tự từ trái sang phải, tham số thực sự thứ nhất truyền cho tham số hình thức thứ nhất, tham số thực sự thứ 2 truyền cho tham số hình thức thứ 2,.. kiểu của các tham số hình thức phải phù hợp với kiểu của các tham số hình thức. Sự phù hợp ở đây được hiểu là kiểu trùng nhau hoặc kiểu của tham số thực sự có thể ép về kiểu của tham số hình thức.

Với C/C++ việc truyền tham số cho hàm được thực hiện qua cơ chế truyền tham trị. Tức là trong hàm chúng ta sử dụng tham số hình thức như là một bản sao dữ liệu của tham số được truyền cho hàm, do vậy chúng không làm thay đổi giá trị của tham số truyền vào. Hay nói khác đi, các tham số hình thức là các biến cục bộ trong hàm, sự thay đổi của nó trong hàm không ảnh hưởng tới các biến bên ngoài.

5. Đệ qui

5.1. Khái niệm

Một hàm được gọi có tính đệ qui nếu trong thân của hàm đó có lệnh gọi lại chính nó một cách tường minh hay tiềm ẩn.

5.2. Ví dụ

Ví dụ 1: Tính tổng S = 1 + 2 + 3 + … + n (n là số nguyên dương, được nhập từ bàn phím).

Thuật toán giải bằng phương pháp đệ quy như sau:

long TongS (int n)

{

if(n==0)

return 0;

return ( TongS(n-1) + n );

}

Ví dụ 2: Tính giá trị của n! (với n được nhập từ bàn phím)

Thuật toán giải bằng phương pháp đệ quy như sau:

long GiaiThua (int n)

{

if(n==0)

return 1;

return ( GiaiThua(n-1) * n );

}

Bài tập luyện:

Bài 1: Viết chương trình tính diện tích và chu vi của hình chữ nhật với chiều dài và chiều rộng được nhập từ bàn phím.

Bài 2: Viết chương trình tính diện tích và chu vi hình tròn với bán kính được nhập từ bàn phím.

Bài 3: Nhập số nguyên dương n (n>0). Liệt kê tất cả các số nguyên tố nhỏ hơn n.

Bài 4: Viết chương trình tính tiền lương ngày cho công nhân, cho biết trước giờ vào ca, giờ ra ca của mỗi người.

Giả sử rằng:

- Tiền trả cho mỗi giờ trước 12 giờ là 6000đ và sau 12 giờ là 7500đ.

- Giờ vào ca sớm nhất là 6 giờ sáng và giờ ra ca trễ nhất là 18 giờ (Giả sử

giờ nhập vào nguyên).

Bài 5: Nhập vào 3 số thực a, b, c và kiểm tra xem chúng có thành lập thành 3 cạnh của một tam giác hay không? Nếu có hãy tính diện tích, chiều dài mỗi đường cao của tam giác và in kết quả ra màn hình.

Biết rằng:

- Công thức tính diện tích s = sqrt(p*(p-a)*(p-b)*(p-c) )

- Công thức tính các đường cao: ha = 2s/a, hb=2s/b, hc=2s/c.

(Với p là nữa chu vi của tam giác).

Bài 6: Nhập vào 6 số thực a, b, c, d, e, f . Giải hệ phương trình sau :

ax + by = c

dx + ey = f

Bài 7: Viết chương trình nhập 2 số nguyên dương a, b. Tìm USCLN và BSCNN của hai số nguyên đó.

Bài 8: Viết chương trình tính tổng nghịch đảo của n giai thừa.

Bài 9: Viết chương trình nhập số nguyên dương n gồm k chữ số (0<k<=5), tính tổng các ước số dương của n.

Ví dụ: Nhập n=6

Tổng các ước số từ 1 đến n: 1+2+3+6=12.

Chương 6. Mảng

1. Khái niệm

Mảng thực chất là một biến được cấp phát bộ nhớ liên tục và bao gồm nhiều biến thành phần.

Các thành phần của mảng là tập hợp các biến có cùng kiểu dữ liệu và cùng tên. Do đó để truy xuất các biến thành phần, ta dùng cơ chế chỉ mục (chỉ số).

2. Khai báo mảng

2.1. Khai báo mảng

Cú pháp:

< Kiểu_mảng> < Tên_mảng > [ < Số_phần_tử_tối_đa> ] ;

Trong đó:

Kiểu_mảng: đây là kiểu của mảng, là tên một kiểu dữ liệu đã tồn tại, có thể là kiểu chuẩn hoặc kiểu dữ liệu do người lập trình định nghĩa .

Tên_mảng: là tên của mảng, do người lập trình đặt, theo quy tắc về tên của C/C++.

Số_phần_tử: là hằng (hoặc biểu thức hằng) nguyên, dương là số phần tử của mảng.

Ví dụ:

int a[10]; // Khai báo mảng a, có số phần tử tối đa là 10, kiểu dữ liệu của mảng a là int.

float MT[20]; //Khai báo mảng MT, có số phần tử tối đa là 20, kiểu dữ liệu của mảng MT là float.

2.2. Truy xuất đến các phần tử của mảng

Cú pháp :

tên_mảng [chỉ_số]

ví dụ a[1], MT[3];

chỉ_số là số thứ tự của phần tử trong mảng, các phần tử của mảng được đánh chỉ số bắt đầu từ 0. Với mảng có n phần tử thì các phần tử của nó có chỉ số là 0, 1,..,n-1.

3. Khởi tạo mảng

Các phần tử của mảng cũng như các biến đơn, chúng ta có thể khởi tạo giá trị ban đầu cho chúng trên dòng định nghĩa mảng (gọi là khởi đầu) với cú pháp sau:

Kiểu_mảng tên_mảng [ số_phần_tử ] = {gt_0, gt_1,..,gt_k};

hoặc

Kiểu_mảng tên_mảng [ ] = {gt_0, gt_1,..,gt_k};

Trong đó các thành phần Kiểu_mảng , tên_mảng, số_phần_tử như trong phần khai báo mảng. gt_0, gt_1,.., gt_k là các giá trị khởi đầu (gọi là bộ khởi đầu) cho các phần tử tương ứng của mảng, tức là gán tuần tự các giá trị trong bộ khởi đầu cho các phần tử của mảng từ trái qua phải.

Trong dạng thứ nhất, số giá trị trong bôn khởi đầu chỉ có thể <= số phần tử của mảng (k ≤ số_phần_tử). Khi đó những phần tử mảng thừa ra (không có giá trị khởi đầu) sẽ tự động được gán bằng 0 (trong trường hợp mảng số, nếu là con trỏ sẽ là NULL (rỗng) ).

Ví dụ:

int a[3] ={ 1, 3, 4}; thì giá trị của a[0] là 1, a[1] là 3, a[2] là 4.

int b[5] ={1,2}; thì giá trị của b[0] là 1, b[1] là 2, b[3]=b[4] là 0.

với mảng các ký tự hoặc xâu ký tự thì có hai cách khởi đầu như sau:

char c[4] ={‘a’,’b’,’c’ }; // c[0] là ‘a’, c[1] là ‘b’, c[2] là ‘c’, c[3] là ‘\0’

char s[10] =”ABC”; // tương đương với char s[10] ={‘A’,’B’,’C’,’\0’}

(nếu số giá trị trong bộ khởi đầu > số phần tử mảng chương trình dịch sẽ báo lỗi)

Trong dạng thứ hai, chúng ta không xác định số phần tử của mảng, trong trường hợp này chương trình biên dịch sẽ tự động xác định kích thước (số phần tử) của mảng theo số giá trị trong bộ khởi đầu.

Ví dụ:

int a[] ={1,3,4};

thì a là mảng có 3 phần tử, giá trị của a[0] là 1, a[1] là 3, a[2] là 4.

Ví dụ 1: Viết chương trình nhập vào một mảng A có n phần tử kiểu nguyên, n<=20, n được nhập từ bàn phím. In các phần tử của mảng theo trật tự xuôi, ngược (theo trật tự chỉ số).

#include<iostream.h>

main()

{

const max = 20;

int n, i, a[max];

do {

cout<<"Nhap vao so phan tu cua mang: "; cin>>n;

}

while (n < 1 || n > max);

cout<<"Nhap vao mang a: "<<endl;

for (i = 0; i<n; i++)

cin>>a[i];

cout<<"Cac phan tu mang theo TT xuoi la: ";

for (i = 0; i<n; i++)

cout<<a[i]<<"\t";

cout<<endl;

cout<<"Cac phan tu mang theo TT nguoc la: ";

for (i = n-1;i>=0; i--)

cout<<a[i]<<"\t";

return 0;

}

Ví dụ 2: Nhập vào 2 mảng A và B, có số phần tử tối đa là 10. Tính tổng của A và B.

//Tinh tong cua C = A + B

#include<iostream.h>

main()

{

const max = 10;

int n, i, a[max], b[max], c[max];

do {

cout<<"Nhap vao so phan tu cua mang: "; cin>>n;

}

while (n < 1 || n > max);

cout<<"Nhap vao so PT mang a: "<<endl;

for (i = 0; i<n; i++)

cin>>a[i];

cout<<"Nhap vao so PT mang b: "<<endl;

for (i = 0; i<n; i++)

cin>>b[i];

cout<<"Tong C = A + B = ";

for (i = 0; i< n; i++)

c[i] = a[i] + b[i];

for (i = 0; i<n; i++)

cout<<c[i]<<"\t";

return 0;

}

4. Dùng mảng làm tham số

Vào một lúc nào đó có thể chúng ta cần phải truyền một mảng tới một hàm như là một tham số. Trong C++, việc truyền theo tham số giá trị một khối nhớ là không hợp lệ, ngay cả khi nó được tổ chức thành một mảng. Tuy nhiên chúng ta lại được phép truyền địa chỉ của nó, việc này cũng tạo ra kết quả thực tế giống thao tác ở trên nhưng lại nhanh hơn nhiều và hiệu quả hơn.

Để có thể nhận mảng là tham số thì điều duy nhất chúng ta phải làm khi khai báo hàm là chỉ định trong phần tham số kiểu dữ liệu cơ bản của mảng, tên mảng và cặp ngoặc vuông trống. Ví dụ, hàm sau:

void procedure (int arg[])

nhận vào một tham số có kiểu "mảng của char" và có tên arg. Để truyền tham số cho hàm này một mảng được khai báo:

int myarray [40];

chỉ cần gọi hàm như sau:

procedure (myarray);

Ví dụ 1:

#include <iostream.h>

 void printarray (int arg[], int length) {

for (int n=0; n<length; n++)

cout << arg[n] << " ";

cout << "\n";

}

 int main ()

{

int firstarray[] = {5, 10, 15};

int secondarray[] = {2, 4, 6, 8, 10};

printarray (firstarray,3);

printarray (secondarray,5);

return 0;

}

Ví dụ 2: Tính tổng C = A + B

#include <iostream.h>

void nhapmang(int a[], int n);

void inmang(int a[], int n);

void tong(int A[],int B[],int C[],int n);

void main(){

const int max = 20;

int A[max], B[max],C[max];

int n;

do{

cout<<"\nNhap so phan tu mang = ";

cin>>n;

} while(n<1 || n>max);

cout<<"\nNhap A \n";

nhapmang(A,n);

cout<<"\nNhap B \n";

nhapmang(B,n);

tong(A,B,C,n);

cout<<"\nmang A: ";

inmang(A,n);

cout<<"\nmang B: ";

inmang(B,n);

cout<<"\nmang C: ";

inmang(C,n);

}

void nhapmang(int a[], int n){

int i;

cout<<"\nNhap mang co so phan tu: "<<n;

for(i=0; i<n; i++)

{

cout<<"\nPhan tu thu"<<"["<<i<<"]";

cin>>a[i];

}

}

void inmang(int a[], int n){

int i;

for(i=0; i<n; i++)

cout<<a[i];

}

void tong(int A[],int B[],int C[],int n){

int i;

for (i = 0; i<n; i++)

C[i]=A[i]+B[i];

}

5. Với mảng hai chiều

5.1. Định nghĩa

Mảng hai chiều có thể hiểu như bảng gồm các dòng các cột, các phần tử thuộc cùng một kiểu dữ liệu nào đó. Mảng hai chiều được định nghĩa như sau.

Cú pháp:

Kiểu_mảng tên_mảng [sd][sc];

Trong đó:

- Kiểu_mảng: đây là kiểu của mảng, là tên một kiểu dữ liệu đã tồn tại, có thể là kiểu chuẩn hoặc kiểu dữ liệu do người lập trình định nghĩa.

- tên_mảng: là tên của mảng, do người lập trình đặt, theo quy tắc về tên của C/C++.

- sd, sc: là hằng (hoặc biểu thức hằng) nguyên, dương tương ứng là số dòng và số cột mảng, số phần tử của mảng sẽ là sd*sc.

Ví dụ:

int a[2][5]; // a là mảng số nguyên có 2 dòng, 5 cột (có 10 phần tử).

float D[3][10]; // D là mảng số thực có 3 dòng, 10 cột (có 30 phần tử).

char DS[5][30]; // DS là mảng kí tự có 5 dòng, 30 cột.

5.2. Truy xuất các phần tử mảng hai chiều

Một phần tử của mảng 2 chiều được xác định qua tên (tên của mảng) và chỉ số dòng, chỉ số cột của nó trong mảng theo cú pháp sau:

tên_mảng [csd][csc]

Với csd là số nguyên xác định chỉ số dòng và csc là số hiệu cột cũng như trong mảng 1 chiều các chỉ số được tính từ 0. Tức là 0 ≤csd ≤sd-1 và 0≤csc≤sc-1.

5.3. Khởi tạo giá trị mảng hai chiều

Các phần tử mảng hai chiều cũng có thể được khởi đầu giá trị theo cú pháp (4 dạng sau):

+ Kiểu_mảng tên_mảng [sd][sc]={{kđ_dòng_1},{ kđ_dòng_2},..,{ kđ_dòng_k}};

+ Kiểu_mảng tên_mảng [ ][sc] = {{kđ_dòng_1},{ kđ_dòng_2},..,{ kđ_dòng_k}};

+ Kiểu_mảng tên_mảng [sd][sc] = { gt_1, gt_2,...,gt_n };

+ Kiểu_mảng tên_mảng [ ][sc] = { gt_1, gt_2,...,gt_n };

Cú pháp trên có thể giải thích như sau:

Dạng 1: có k bộ giá trị sẽ được gán cho k dòng đầu tiên của mảng (k ≤ sd ), với mỗi dòng (được coi như mảng một chiều) được khởi tạo giá trị như mảng một chiều:

dòng thứ nhất được khởi đầu bởi {kđ_dòng_1}, dòng thứ hai được khởi đầu bởi {kđ_dòng_1},.., dòng thứ k được khởi đầu bởi {kđ_dòng_k}. Yêu cầu k ≤ sd, ngược lại chương trình sẽ báo lỗi.

Các dòng cuối của mảng nếu không có bộ khởi đầu tương ứng thì sẽ được tự động gán giá trị 0 (hoặc NULL nếu là con trỏ).

Dạng 2: (không xác định số dòng) chương trình dịch sẽ tự động ấn định số dòng của mảng bằng số bộ khởi đầu ( = k), sau đó thực hiện khởi đầu như dạng 1.

Dạng 3: n giá trị trong bộ khởi đầu được gán cho các phần tử mảng theo cách: sc giá trị đầu tiên trong các giá trị khởi đầu (gt_1,..,gt_sc) được gán tuần tự cho các phần tử của dòng thứ nhất trong mảng, sc phần tử kế tiếp sẽ gán cho các phần tử ở dòng thứ 2,... nếu phần tử nào của mảng không có giá trị khởi đầu sẽ được gán 0 (con trỏ là NULL) - với điều kiện n ≤ sd*sc, ngược lại là lỗi.

Dạng 4: số dòng của mảng sẽ được chương trình tự tính theo số giá trị trong bộ khởi đầu theo công thức sd = (n/sc) +1, và khởi đầu như dạng 3.

Ví dụ 1: int a[3][2] = {{1,2},{3},{4,5}}; thì các phần tử của a như sau:

a[0][0]=1, a[0][1]=2, a[1][0]=3, a[1][1]= 0, a[2][0]=4,a[2][1]=5;

Ví dụ 2: int b[ ][2] = {{1,2},{3},{4,5}};

thì là mảng 3 dòng, 2 cột các phần tử của b như sau:

b[0][0]=1, b[0][1]=2, b[1][0]=3,b[1][1]= 0, b[2][0]=4,b[2][1]=5;

Ví dụ 3: int c[ ][2] = {1,2,3,4,5};

thì số dòng của c là mảng 5/2 +1 =3 dòng, các phần tử của a như sau:

c[0][0]=1, c[0][1]=2, c[1][0]=3,c[1][1]= 4, b[2][0]=5,b[2][1]=0;

5.4. Ví dụ

Viết chương trình nhập vào mảng A(n, m) với 1<=n,m<=5 các số nguyên.

Yêu cầu:

+ In mảng A ra màn hình.

+ In ra màn hình các phần tử chẵn của mảng.

+ In ra màn hình các phần tử lẻ của mảng.

#include<iostream.h>

main()

{

const max = 5;//Kich thuoc toi da

int a[max][max];

int n,m,i,j;

do {

cout<<"Nhap so dong cua mang = ";cin>>n;

cout<<"Nhap so cot cua mang = "; cin>>m;

}

while (n<1 || n>max || m<1 || m>max);

cout<<"Nhap cac gia tri cua mang: "<<endl;

for (i = 0; i<n; i++)

for (j = 0; j<m; j++)

{

cin>>a[i][j];

}

cout<<"Cac PT cua mang la: "<<" ";

for (i = 0; i<n; i++)

{

cout<<endl;

for (j = 0; j<m; j++)

cout<<a[i][j]<<" ";

}

cout<<"\n Cac PT chan cua mang la: ";

for (i = 0; i<n; i++)

for (j = 0; j<m; j++)

{if (a[i][j] % 2 == 0)

cout<<a[i][j]<<"\t";}

cout<<"\n Cac PT le cua mang la: ";

for (i = 0; i<n; i++)

for (j = 0; j<m; j++)

{if (a[i][j] % 2 != 0)

cout<<a[i][j]<<"\t";}

}

Bài tập luyện

Bài 1: Viết chương trình nhập vào mảng N số nguyên (N<100)

+ In các phần tử trong mảng

+ Đếm và in số phần tử chẵn trong mảng

+ Đếm và in số phần tử lẻ trong mảng

Bài 2: Viết chương trình nhập vào mảng N số nguyên (N<100)

+ Tính tổng và in tất cả các phần tử chẵn trong mảng

+ Tính tổng và in tất cả các phần tử lẻ trong mảng

+ Tính tổng và in tất cả các phần tử âm trong mảng

+ Tính tổng và in tất cả các phần tử lẻ không âm trong mảng

Bài 3:Viết chương trình nhập vào mảng N số nguyên (N<100)

+ Kiểm tra mảng có sắp thứ tự tăng không ?

+ Kiểm tra mảng có sắp thứ tự giảm không ?

+ Sắp xếp mảng theo thứ tự tăng (nếu mảng chưa được sắp tăng)

+ Sắp xếp mảng theo thứ tự giảm (nếu mảng chưa được sắp thứ tự giảm)

Chương 7. Con trỏ

1. Khái niệm

Con trỏ là một biến dùng để chứa địa chỉ. Vì có nhiều loại địa chỉ nên cũng có nhiều kiểu con trỏ tương ứng. Kiểu con trỏ int dùng để chứa địa chỉ biến kiểu int. Tương tự ta có con trỏ kiểu float, kiểu double,…

Cũng như với 1 biến bất kỳ nào khác, con trỏ cần được khai báo trước khi sử dụng.

2. Toán tử lấy địa chỉ (&)

Địa chỉ: Khi khai báo biến, máy sẽ cấp phát cho biến một khoảng nhớ. Đị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 (các byte được đánh số từ 0).

Máy phân biệt các loại địa chỉ như các biến. Ví dụ như: địa chỉ kiểu int, kiểu float,…

Vào thời điểm mà chúng ta khai báo một biến thì nó phải được lưu trữ trong một vị trí cụ thể trong bộ nhớ. Chúng ta không quyết định nơi nào biến đó được đặt, điều đó làm tự động bởi trình biên dịch và hệ điều hành. Nhưng khi hệ điều hành đã gán một địa chỉ cho biến thì chúng ta cần biết biến đó được lưu trữ ở đâu. Điều này được thực hiện bằng cách đặt trước tên biến một dấu và (&).

Ví dụ: x = &y;

Giải thích: Gán cho biến x địa chỉ của biến y vì khi đặt trước tên biến y dấu & ta không nói đến nội dung của biến nữa mà chỉ nói đến địa chỉ của nó trong bộ nhớ.

Giả sử biến y được đặt trọng ô nhớ có địa chỉ là 1202 và có các câu lệnh như sau:

y = 30;

z = y;

x = &y;

Kết quả: z = 30; x = 1202;

Chú ý: Có thể định nghĩa con trỏ như sau: Những biến lưu trữ địa chỉ của biến khác được gọi là con trỏ. Ở ví dụ trên, biến x là con trỏ.

3. Toán tử tham chiếu (*)

Bằng cách sử dụng con trỏ chúng ta có thể truy xuất trực tiếp đến giá trị được lưu trữ trong biến được trỏ bởi nó bằng cách đặt trước tên biến con trỏ một dấu (*).

Ví dụ: Giả sử biến y được đặt trong ô nhớ có địa chỉ là 1202 và có các câu lệnh như sau:

y = 30;

z = y;

x = &y;

t = *y;

Kết quả: biến t sẽ mang giá trị là 30.

4. Khai báo biến kiểu con trỏ.

Vì con trỏ có khả năng tham chiếu trực tiếp đến giá trị mà chúng trỏ tới nên cần thiết phải chỉ rõ kiểu dữ liệu nào mà một biến con trỏ trỏ tới khi khai báo.

Cấu trúc khai báo:

Kiểu_dữ_liệu *Tên_con_trỏ;

Chú ý: kiểu dữ liệu ở đây là kiểu dữ liệu được trở tới, không phải là kiểu của bản thân con trỏ.

Ví dụ:

int *x; //Khai báo con trỏ x kiểu int

float *t; //Khai báo con trỏ t kiểu float

Chú ý: dấu (*) khi khai báo biến kiểu con trỏ chỉ có nghĩa rằng đó là một con trỏ, không liên quan đến toán tử tham chiếu.

Ví dụ đơn giản về sử dụng con trỏ: khai báo, sử dụng toán tử tham chiếu, toán tử lấy địa chỉ:

#include<iostream.h>

main()

{

int x1 = 5, x2 = 15;

int *y;

y = &x1;

*y = 10;

y = &x2;

*y = 20;

cout<<“Gia tri 1 = “<<x1<<“\n Gia tri 2 = “<<x2;

return 0;

}

Kết quả: x1 = 10; x2 = 20;

5. Các phép toán

Có bốn nhóm phép toán liên quan đến con trỏ và địa chỉ là: phép gán, phép tăng giảm địa chỉ, phép truy nhập bộ nhớ và phép so sánh. Kiểu con trỏ và kiểu địa chỉ có vai trò quan trọng trong các phép toán nói trên.

5.1. Phép gán

phép gán chỉ nên thực hiện phép gán cho con trỏ cùng kiểu. Muốn gán các con trỏ khác kiểu phải dùng phép ép kiểu như ví dụ sau:

int x;

char *pc;

pc = (char*)(&x); //ép kiểu

5.2. Phép tăng giảm địa chỉ

//Giải thích phép tăng giảm địa chỉ qua các ví dụ.

Ví dụ 1: Các câu lệnh: float x[30], *px;

px = &x[10];

Cho biết px là con trỏ float trỏ tới phần tử x[10]. Kiểu địa chỉ float là kiểu địa chỉ 4 byte (mỗi giá trị float chứa trong 4 byte), nên các phép tăng giảm địa chỉ được thực hiện trên 4 byte. Nói cách khác:

px + i trỏ tới phần tử x[10+i];

px – i trỏ tới phần tử x[10-i];

Ví dụ 2: float b[40][50];

b trỏ tới đầu dòng thứ nhất (phần tử b[0][0];

b + 1 trỏ tới đầu dòng thứ hai (phần tử b[1][0];

.

5.3. Phép truy nhập bộ nhớ

Có nguyên tắc là con trỏ float truy nhập tới 4 byte, con trỏ int truy nhập 2 byte, chon trỏ char truy nhập 1 byte.

Ví dụ:

float *pf;

int *pi;

char *pc;

Khi đó: Nếu pf trỏ đến byte thứ 10001, thì *pf biểu thị vùng nhớ 4 byte liên tiếp từ byte 10001 đến 10004.

Nếu pi trỏ đến byte thứ 10001, thì *pi biểu thị vùng nhớ 2 byte là 10001 và 10002.

Nếu pc trỏ đến byte thứ 10001, thì *pc biểu thị vùng nhớ 1 byte là byte 10001.

5.4. Phép so sánh

Cho phép so sánh các con trỏ cùng kiểu, ví dụ nếu p1 và p2 là 2 con trỏ float thì:

p1<p2 nếu địa chỉ p1 trỏ tới thấp hơn địa chỉ p2 trỏ tới.

p1=p2 nếu địa chỉ p1 trỏ tới bằng địa chỉ p2 trỏ tới.

p1<p2 nếu địa chỉ p1 trỏ tới cao hơn địa chỉ p2 trỏ tới.

6. Con trỏ hằng

Ví dụ có khai báo sau:

int a[20];

int *p;

Lệnh sau sẽ hợp lệ: p = a;

ở đây p và a là tương đương và chúng có cùng thuộc tính, sự khác biệt duy nhất là chúng ta có thể gán một giá trị khác cho con trỏ p trong khi a luôn trỏ đến phần tử đầu tiên trong số 20 phần tử kiểu int mà nó được định nghĩa. Vì vậy không giống như p – đó là một biến con trỏ bình thường, a, là một con trỏ hằng. Lệnh gán sau đây là không đúng: a = p; bởi vì a là một mảng (con trỏ hằng) và không có giá trị nào có thể được gán cho các hằng.

7. Con trỏ mảng

Trong thực tế, tên của một mảng tương đương với địa chỉ phần tử đầu tiên của nó, giống như một con trỏ tương đương với địa chỉ của phần tử đầu tiên mà nó trỏ tới, vì vậy thực tế chúng hoàn toàn như nhau. Ví dụ, cho hai khai báo sau:

int numbers[20];

int * p;

Lệnh sau sẽ hợp lệ:

p = numbers;

Ở đây p và numbers là tương đương và chúng có cũng thuộc tính, sự khác biệt duy nhất là chúng ta có thể gán một giá trị khác cho con trỏ p trong khi numbers luôn trỏ đến phần tử đầu tiên trong số 20 phần tử kiểu int mà nó được định nghĩa với. Vì vậy, không giống như p - đó là một biến con trỏ bình thường, numbers là một con trỏ hằng. Lệnh gán sau đây là không hợp lệ:

numbers = p;

bởi vì numbers là một mảng (con trỏ hằng) và không có giá trị nào có thể được gán cho các hằng.

Vì con trỏ cũng có mọi tính chất của một biến nên tất cả các biểu thức có con trỏ trong ví dụ dưới đây là hoàn toàn hợp lệ:

#include <iostream.h>

int main ()

{

int a[5];

int * p;

p = a; *p = 10;

p++; *p = 20;

p = &a[2]; *p = 30;

p = a + 3; *p = 40;

p = a; *(p+4) = 50;

for (int n=0; n<5; n++)

cout << a[n] << ", ";

return 0;

}

Bài tập luyện tập:

Bài 1: Tính tổng các phần tử của mảng 1 chiều. Các phần tử được nhập từ bàn phím.

Bài 2:

8. Khởi tạo con trỏ

Khi khai báo con trỏ có thể chúng ta sẽ muốn chỉ định rõ ràng chúng sẽ trỏ tới biến nào:

int number;

int *tommy = &number;

là tương đương với:

int number;

int *tommy;

tommy = &number;

Trong một phép gán con trỏ chúng ta phải luôn luôn gán địa chỉ mà nó trỏ tới chứ không phải là giá trị mà nó trỏ tới. Cần phải nhớ rằng khi khai báo một biến con trỏ, dấu sao (*) được dùng để chỉ ra nó là một con trỏ, và hoàn toàn khác với toán tử tham chiếu. Đó là hai toán tử khác nhau mặc dù chúng được viết với cùng một dấu. Vì vậy, các câu lệnh sau là không hợp lệ:

int number;

int *tommy;

*tommy = &number;

Như đối với mảng, trình biên dịch cho phép chúng ta khởi tạo giá trị mà con trỏ trỏ tới bằng giá trị hằng vào thời điểm khai báo biến con trỏ:

char * terry = "hello";

trong trường hợp này một khối nhớ tĩnh được dành để chứa "hello" và một con trỏ trỏ tới kí tự đầu tiên của khối nhớ này (đó là kí tự h') được gán cho terry. Nếu "hello" được lưu tại địa chỉ 1702, lệnh khai báo trên có thể được hình dung như thế này:

Cần phải nhắc lại rằng terry mang giá trị 1702 chứ không phải là 'h' hay "hello".

Biến con trỏ terry trỏ tới một xâu kí tự và nó có thể được sử dụng như là đối với một mảng (hãy nhớ rằng một mảng chỉ đơn thuần là một con trỏ hằng). Ví dụ, nếu chúng ta muốn thay kí tự 'o' bằng một dấu chấm than, chúng ta có thể thực hiện việc đó bằng hai cách:

terry[4] = ‘!’;

*(terry+4) = '!';

Hãy nhớ rằng viết terry[4] là hoàn toàn giống với viết *(terry+4) mặc dù biểu thức thông dụng nhất là cái đầu tiên. Với một trong hai lệnh trên xâu do terry trỏ đến sẽ có giá trị như sau:

9. Con trỏ trỏ tới con trỏ

C++ cho phép sử dụng các con trỏ trỏ tới các con trỏ khác giống như là trỏ tới dữ liệu. Để làm việc đó chúng ta chỉ cần thêm một dấu sao (*) cho mỗi mức tham chiếu.

char a;

char *b;

char **c;

a = ‘z’;

b = &a;

c = &b;

giả sử rằng a,b,c được lưu ở các ô nhớ 7230, 8092 and 10502, ta có thể mô tả đoạn mã trên như sau:

Điểm mới trong ví dụ này là biến c, chúng ta có thể nói về nó theo 3 cách khác nhau, mỗi cách sẽ tương ứng với một giá trị khác nhau:

c là một biến có kiểu char ** mang giá trị 8092;

*c là một biến có kiểu char * mang giá trị là 7230;

**c là một biến có kiểu char mang giá trị ‘z’;

10. Con trỏ không kiểu

Con trỏ không kiểu là một loại con trỏ đặc biệt. Nó có thể trỏ tới bất kì loại dữ liệu nào, từ giá trị nguyên hoặc thực cho tới một xâu kí tự. Hạn chế duy nhất của nó là dữ liệu được trỏ tới không thể được tham chiếu tới một cách trực tiếp (chúng ta không thể dùng toán tử tham chiếu * với chúng) vì độ dài của nó là không xác định và vì vậy chúng ta phải dùng đến toán tử chuyển kiểu dữ liệu hay phép gán để chuyển con trỏ không kiểu thành một con trỏ trỏ tới một loại dữ liệu cụ thể.

Một trong những tiện ích của nó là cho phép truyền tham số cho hàm mà không cần chỉ rõ kiểu.

Ví dụ:

#include <iostream.h>

void increase (void* data, int type)

{

switch (type)

{

case sizeof(char) : (*((char*)data))++; break;

case sizeof(short):

(*((short*)data))++; break;

case sizeof(long) : (*((long*)data))++; break;

}

}

int main ()

{

char a = 5;

short b = 9;

long c = 12;

increase (&a,sizeof(a));

increase (&b,sizeof(b));

increase (&c,sizeof(c));

cout << (int) a << ", " << b << ", " << c;

return 0;

}

Kết quả: 6, 10, 13

sizeof là một toán tử của ngôn ngữ C++, nó trả về một giá trị hằng là kích thước tính bằng byte của tham số truyền cho nó, ví dụ sizeof(char) bằng 1 vì kích thước của char là 1 byte.

11. Con trỏ hàm

C++ cho phép thao tác với các con trỏ hàm. Tiện ích tuyệt vời này cho phép truyền một hàm như là một tham số đến một hàm khác. Để có thể khai báo một con trỏ trỏ tới một hàm chúng ta phải khai báo nó như là khai báo mẫu của một hàm nhưng phải bao trong một cặp ngoặc đơn () tên của hàm và chèn dấu sao (*) đằng trước. 

Ví dụ:

#include <iostream.h>

int addition (int a, int b)

{ return (a+b); }

int subtraction (int a, int b)

{ return (a-b); }

int (*minus)(int,int) = subtraction;

int operation (int x, int y, int (*functocall)(int,int))

{

int g;

g = (*functocall)(x,y);

return (g);

}

int main ()

{

int m,n;

m = operation (7, 5, &addition);

n = operation (20, m, minus);

cout <<n;

return 0;

}

Trong ví dụ này, minus là một con trỏ toàn cục trỏ tới một hàm có hai tham số kiểu int, con trỏ này được gám để trỏ tới hàm subtraction, tất cả đều trên một dòng:

int (* minus)(int,int) = subtraction;

Chương 8. Cấu trúc

1. Khái niệm cấu trúc

Cấu trúc (struct) thực chất là một kiểu dữ liệu do người dùng định nghĩa bằng cách gom nhóm các kiểu dữ liệu cơ bản có sẵn trong C thành một kiểu dữ liệu phức hợp nhiều thành phần.

Cấu trúc giúp cho việc tổ chức các dữ liệu phức tạp, đặc biệt trong những chương trình lớn vì trong nhiều tình huống chúng cho phép nhóm các biến có liên quan lại để xử lý như một đơn vị thay vì các thực thể tách biệt.

Một ví dụ là cấu trúc Sinh viên, trong đó mỗi sinh viên được mô tả bởi tập hợp các thuộc tính như: Họ tên, Ngày sinh, Địa chỉ, Tên lớp, Điểm,.. một số trong các thuộc tính này lại có thể là cấu trúc bởi trong nó có thể chứa nhiều thành phần như: Họ tên gồm: họ, tên đệm, tên; Địa chỉ: xã (phường, thị trấn), huyện (quận), tỉnh (thành phố)…

2. Khai báo cấu trúc

2.1. Kiểu cấu trúc

Khi xây dựng cấu trúc, ta cần mô tả kiểu của nó. Điều này cũng tương tự như việc phải thiết kế ra một kiểu nhà trước khi đi xây dựng căn nhà thực sự. Công việc định nghĩa một kiểu cấu trúc bao gồm việc nêu ra tên của kiểu cấu trúc và các thành phần của nó theo 2 cách sau:

Cách 1:

struct tên_kiểu_cấu_trúc

{

Khai báo các thành phần của cấu trúc

};

Trong đó:

struct: là từ khóa.

Tên_kiểu_cấu_trúc: là một tên bất kỳ do người lập trình tự đặt theo quy định đặt tên của C/C++.

Thành phần của cấu trúc có thể là: biến, mảng, cấu trúc khác đã được định nghĩa trước đó,…

Ví dụ 1:

struct Sinhvien

{

char Hoten;

float Diem;

char Diachi;

};

Ví dụ trên định nghĩa kiểu cấu trúc có tên là Sinhvien bao gồm 3 thành phần: Hoten có kiểu char, Diem có kiểu float và Diachi có kiểu char.

Ví dụ 2:

struct Ngay

{

int ngaythu;

char thang;

int nam;

};

Định nghĩa cấu trúc lồng nhau:

struct SV

{

char Hoten;

struct Ngay Ngaysinh;

struct Ngaynhaphoc;

float Diem;

};

Cách 2: Định nghĩa cấu trúc bằng typedef

Có thể dùng từ khóa typedef để định nghĩa kiểu cấu trúc của các ví dụ ở trên như sau:

Ví dụ 1:

typedef struct

{

char Hoten;

float Diem;

char Diachi;

} Sinhvien;

Ví dụ 2:

typedef struct

{

int ngaythu;

char thang;

int nam;

} Ngay;

Định nghĩa cấu trúc lồng nhau:

typedef struct

{

char Hoten;

struct Ngay Ngaysinh;

struct Ngaynhaphoc;

float Diem;

}SV;

2.2. Khai báo thành phần (biến, mảng) kiểu cấu trúc

Khi ta định nghĩa kiểu dữ liệu tức là ta có một kiểu dữ liệu mới, muốn sử dụng ta phải khai báo biến hoặc mảng. Cú pháp khai báo kiểu dữ liệu cũng giống như cách khai báo của các kiểu dữ liệu chuẩn.

Cấu trúc khai báo:

+ Nếu đã định nghĩa cấu trúc trước, có thể khai báo biến theo cú pháp sau:

struct < tên cấu trúc > < tên biến > ;

Ví dụ: Theo cấu trúc đã định nghĩa ở trên ta có thể khai báo biến như sau:

struct Sinhvien SV1, SV2;

Ví dụ trên khai báo 2 biến kiểu Sinhvien có tên là: SV1, SV2.

+ Hoặc có thể định nghĩa biến kiểu cấu trúc ngay khi tạo cấu trúc mới:

Ví dụ:

struct Sinhvien

{

char Hoten;

struct Ngay Ngaysinh;

struct Ngaynhaphoc;

float Diem;

}SV1, Sv2;

3. Truy cập đến các thành phần của cấu trúc

Để truy cập đến một thành phần (là biến hoặc mảng) của một cấu trúc ta sử dụng một trong các cách viết sau:

Tên cấu trúc.tên thành phần;

Tên cấu trúc.tên cấu trúc.tên thành phần;

Tên cấu trúc.Tên cấu trúc.tên cấu trúc.tên thành phần;

.

Cách viết thứ nhất được sử dụng khi biến hoặc mảng là thành phần trực tiếp của một cấu trúc. Các cách viết còn lại được sử dụng khi biến hoặc mảng là thành phần trực tiếp của một cấu trúc mà bản thân cấu trúc này lại là thành phần của cấu trúc lớn hơn.

Ví dụ:

cout<<SV1.Hoten; // sẽ in họ tên của sinh viên 1 lên màn hình.

cout<<SV2.Ngaynhaphoc.nam;

4. Ví dụ cấu trúc

Ví dụ 1: Giả sử mỗi giáo viên có các thành phần:

+ Họ tên

+ Năm sinh

+ Nnăm vào ngành

+ mức lương

+ Có gia đình hay chưa?

Yêu cầu viết một chương trình để:

+ Xây dựng cấu trúc cơ sở dữ liệu cho các giáo viên văn và toán.

+ Nhập dữ liệu cho 2 giáo viên đó.

+ Xuất dữ liệu của 2 giáo viên đó ra màn hình.

…………………

#include<iostream.h>

char hoi;

main()

{

struct giaovien

{

char hoten[40];

int namsinh;

int namvaonganh;

float mucluong;

char cogiadinh;

};

giaovien gvtoan;

giaovien gvvan;

cout<<"Nhap ho ten giao vien toan (khong nhap khoang trang): ";

cin>>gvtoan.hoten;

cout<<"Nam sinh: "; cin>>gvtoan.namsinh;

cout<<"Nam vao nganh: "; cin>>gvtoan.namvaonganh;

cout<<"Muc luong: "; cin>>gvtoan.mucluong;

cout<<"co gia dinh c/k: "; cin>>hoi;

if (hoi == 'c')

gvtoan.cogiadinh = 'c';

else

gvtoan.cogiadinh = 'k';

cout<<"Nhap ho ten giao vien van (khong nhap khoang trang): ";

cin>>gvvan.hoten;

cout<<"Nam sinh: "; cin>>gvvan.namsinh;

cout<<"Nam vao nganh: "; cin>>gvvan.namvaonganh;

cout<<"Muc luong: "; cin>>gvvan.mucluong;

cout<<"co gia dinh c/k: "; cin>>hoi;

if (hoi == 'c')

gvvan.cogiadinh = 'c';

else

gvvan.cogiadinh = 'k';

// Xuat ra màn hình

cout<<"\n Danh sách giáo viên";

cout<<"\n Ho tên gv toán: "<<gvtoan.hoten;

cout<<"\n Nam sinh: "<<gvtoan.namsinh;

cout<<"\n Nam vao nganh: "<<gvtoan.namvaonganh;

cout<<"\n Muc luong: "<<gvtoan.mucluong;

cout<<"\n Co gia dinh: "<<gvtoan.cogiadinh;

cout<<"\n __________________________";

cout<<"\n Ho tên giao vien Van: "<<gvvan.hoten;

cout<<"\n Nam sinh: "<<gvvan.namsinh;

cout<<"\n Nam vao nganh: "<<gvvan.namvaonganh;

cout<<"\n Muc luong: "<<gvvan.mucluong;

cout<<"\n Co gia dinh: "<<gvvan.cogiadinh;

return 0;

}

Ví dụ 2: Lập trình quản lý thông tin cán bộ. Biết rằng mỗi cán bộ có các thành phần như sau:

+ Họ tên;

+ Ngày tháng năm sinh;

+ Ngày vào cơ quan;

+ Bậc lương.

Yêu cầu: viết một chương trình để:

+ Vào số liệu của một cán bộ;

+ Đưa số liệu đó lên màn hình.

………...

#include<iostream.h>

typedef struct

{

int ngay;

char thang[10];

int nam;

} date;

typedef struct

{

char hoten[30];

date ngaysinh;

date ngayvaocq;

float luong;

} canbo;

main()

{

canbo p;

cout<<"\n Ho va ten: "; cin>>p.hoten;

cout<<"\n Sinh ngay : "; cin>>p.ngaysinh.ngay;

cout<<"\n Thang : "; cin>>p.ngaysinh.thang;

cout<<"\n Nam : "; cin>>p.ngaysinh.nam;

cout<<"\n Vao co quan ngay : "; cin>>p.ngayvaocq.ngay;

cout<<"\n Thang : "; cin>>p.ngayvaocq.thang;

cout<<"\n Nam : "; cin>>p.ngayvaocq.nam;

cout<<"\n Luong : "; cin>>p.luong;

cout<<"\n Ngay sinh:"<<p.ngaysinh.ngay<<"/"<<p.ngaysinh.thang<<"/"<<p.ngaysinh.nam;

cout<<"\n Ngay vao co quan:"<<p.ngayvaocq.ngay<<"/"<<p.ngayvaocq.thang<<"/"<<p.ngayvaocq.nam;

cout<<"\n Luong : "<<p.luong;

}

Bài tập luyện:

Bài 1: Tổ chức dữ liệu để quản lí sinh viên bằng cấu trúc mẫu tin trong một mảng N phần tử, mỗi phần tử có cấu trúc như sau:

- Mã sinh viên.

- Tên.

- Năm sinh.

- Điểm toán, lý, hoá, điểm trung bình.

Viết chương trình thực hiện những công việc sau:

Nhập danh sách các sinh viên cho một lớp học.

Xuất danh sách sinh viên ra màn hình.

Tìm sinh viên có điểm trung bình cao nhất.

Sắp xếp danh sách lớp theo thứ tự tăng dần của điểm trung bình.

Sắp xếp danh sách lớp theo thứ tự giảm dần của điểm toán.

Tìm kiếm và in ra các sinh viên có điểm trung bình lớn hơn 5 và không có môn nào dưới 3.

Tìm sinh viên có tuổi lớn nhất.

Nhập vào tên của một sinh viên. Tìm và in ra các thông tin liên quan đến sinh viên đó (nếu có).

Bài 2: Tổ chức dữ liệu quản lí danh mục các bộ phim VIDEO, các thông tin liên quan đến bộ phim này như sau:

- Tên phim (tựa phim).

- Thể loại (3 loại : hình sự, tình cảm, hài).

- Tên đạo diễn.

- Tên điễn viên nam chính.

- Tên diễn viên nữ chính.

- Năm sản xuất.

- Hãng sản xuất

Viết chương trình thực hiện những công việc sau :

Nhập vào bộ phim mới cùng với các thông tin liên quan đến bộ phim này.

Nhập một thể loại: In ra danh sách các bộ phim thuộc thể loại này.

Nhập một tên nam diễn viên. In ra các bộ phim có diễn viên này đóng.

Nhập tên đạo diễn. In ra danh sách các bộ phim do đạo diễn này dàn dựng.

Bài 3: Một thư viện cần quản lý thông tin về các đầu sách. Mỗi đầu sách bao gồm các thông tin sau : MaSSach (mã số sách), TenSach (tên sách), TacGia (tác giả), SL (số lượng các cuốn sách của đầu sách). Viết chương trình thực hiện các chức năng sau:

Nhập vào một danh sách các đầu sách (tối đa là 100 đầu sách).

Nhập vào tên của quyển sách. In ra thông tin đầy đủ về các sách có tên đó, nếu không có thì tên của quyển sách đó thì báo là :Không Tìm Thấy.

Tính tổng số sách có trong thư viện.

Chương 9. File

1. Khái niệm File

Tệp tin hay tệp dữ liệu là một tập hợp các dữ liệu có liên quan với nhau và có cùng một kiểu được nhóm lại thành một dãy. Chúng thường được chứa trong một thiết bị nhớ ngoài của máy tính (đĩa mềm, đĩa cứng,…) dưới một cái tên nào đó.

Tệp là một kiểu dữ liệu có cấu trúc. Định nghĩa của tệp có phần nào giống mảng ở chỗ chúng đều là tập hợp của các phần tử dữ liệu có cùng kiểu. Song mảng được định nghĩa và khai báo trong chương trình với số phần tử đã được xác định còn số phần tử của tệp không được xác định khi định nghĩa.

Tệp được chứa trong bộ nhớ ngoài, điều đó có nghĩa là tệp được lưu trữ để dùng nhiều lần và tồn tại ngay cả khi chương trình kết thúc hoặc mất điện.

Có 2 loại tập tin:

+ Tập tin văn bản: là tập tin dùng để ghi các ký tự lên đĩa theo các dòng.

Tệp tin văn bản là tệp chứa các phần tử ký tự là các chữ cái (viết hoa, viết thường); chữ số: ;0’, ‘1’, …, ‘9’; các dấu chấm câu, không kể các ký tự điều khiển. Các ký tự này được tổ chức thành từng dòng với dấu kết thúc dòng là CR ( Carriage Return - Về đầu dòng, mã Ascii là 13 )= ‘\r’ và LF (Line Feed - Xuống dòng, mã Ascii là 10) = ‘\n’, tệp văn bản dùng ký tự ^Z (xác định bởi tổ hợp phím Ctrl_Z) có mã ASCII là 26 để làm ký hiệu kết thúc tệp. Vì vậy, tệp văn bản có thể đọc được trên màn hình, có thể soạn thảo với các phần mềm soạn thảo văn bản.

+ Tập tin nhị phân: là tập tin dùng để ghi các cấu trúc dạng nhị phân (được mã hóa).

Tệp tin nhị phân chứa khá nhiều dữ liệu có mã điều khiển là các ký tự có mã ASCII từ 0 đến 31. Nếu một xâu ký tự được ghi ra tệp nhị phân thì kí hiệu hết dòng của nó chỉ còn có LF = ‘\n’, không có ký tự CR = ‘\r’.

2. Tạo file đọc file

Quá trình thao tác trên tập tin thông qua 4 bước:

Bước 1: Khai báo con trỏ trỏ đến tập tin.

Bước 2: Mở tập tin.

Bước 3: Các xử lý trên tập tin.

Bước 4: Đóng tập tin.

2.1. Khai báo con trỏ trỏ đến tập tin

Cú pháp: FILE *Tên_biến;

Ví dụ: FILE *f; //Khai báo biến con trỏ file f;

FILE *vb,*np; //Khai báo 2 biến con trỏ tệp.

Chú ý: + Trước khi khai báo con trỏ trỏ đến tập tin, cần khai báo thư viện: stdio.h.

+ Mỗi tệp đều được kết thúc bằng một dấu hiệu đặc biệt để báo hiệu hết tệp, hay gọi là EOF (End of File). Giá trị EOF trong UNIX được định nghĩa là -1, trong chương trình dịch C/C++ khác có thể có các giá trị khác.

+ C/C++ có một hàm chuẩn feof, theo kiểu Boolean, với tham số là một biến tệp để thử xem cửa sổ đã đặt vào vị trí kết thúc tệp đó chưa. Nếu cửa sổ còn chưa trỏ vào phần tử cuối tệp thì feof có giá trị là False, tức là bằng 0. Sử dụng hàm feof() sẽ an toàn và chính xác hơn.

2.2. Mở tập tin

Cấu trúc: Biến_tệp = fopen (<đường dẫn của tập tin>,<kiểu truy nhập>);

Ví dụ 1:

FILE *f; //Khai báo biến con trỏ f

f = fopen (“C:\\VD1.txt”, “rt”);

Ví dụ 2: Mở một tập tin tên TEST.txt để ghi.

FILE *f;

f = fopen(“TEST.txt”, “w”);

if (f!=NULL)

{

/* Các câu lệnh để thao tác với tập tin*/

/* Đóng tập tin*/

}

Trong ví dụ trên, ta có sử dụng câu lệnh kiểm tra điều kiện để xác định mở tập tin có thành công hay không?.

Nếu mở tập tin để ghi, nếu tập tin đã tồn tại rồi thì tập tin sẽ bị xóa và một tập tin mới được tạo ra. Nếu ta muốn ghi nối dữ liệu, ta phải sử dụng chế độ “a”. Khi mở với chế độ đọc, tập tin phải tồn tại rồi, nếu không một lỗi sẽ xuất hiện.

2.3. Các kiểu xử lý tệp thông dụng

+ Cho tệp văn bản:

STT

Kiểu

Ý nghĩa

r, rt

Mở một tệp để đọc theo kiểu văn bản. Tệp cần phải tồn tại.

w, wt

Mở một tệp để ghi theo kiểu văn bản. Nếu tệp đã tồn tại thì nó sẽ bị xóa.

a, at

Mở một tệp để ghi bổ sung theo kiểu văn bản. Nếu tệp chưa tồn tại thì tạo tệp mới.

r+

Mở một tệp để đọc theo kiểu văn bản. Tệp phải tồn tại.

w+

Mở một tệp để ghi theo kiểu văn bản. Tệp phải tồn tại.

a+

Mở một tệp để đọc/ghi bổ sung theo kiểu văn bản. Nếu tệp chưa tồn tại thì tạo tệp mới.

+ Cho tệp nhị phân:

STT

Kiểu

Ý nghĩa

rb

Mở một tệp để đọc theo kiểu nhị phân. Tệp cần phải tồn tại.

wb

Mở một tệp mới để ghi theo kiểu nhị phân. Nếu tệp đã tồn tại thì nó sẽ bị xóa.

ab

Mở một tệp để ghi bổ sung theo kiểu nhị phân. Nếu tệp chưa tồn tại thì tạo tệp mới.

r+ b

Mở một tệp để đọc theo kiểu văn bản. Tệp phải tồn tại.

w+ b

Mở một tệp để ghi theo kiểu văn bản. Tệp phải tồn tại.

a+ b

Mở một tệp để đọc/ghi bổ sung theo kiểu văn bản. Nếu tệp chưa tồn tại thì tạo tệp mới.

2.4. Đóng tập tin

Hàm fclose() được dùng để đóng tập tin được mở bởi hàm fopen(). Hàm này sẽ ghi dữ liệu còn lại trong vùng đệm vào tập tin và đóng lại tập tin.

Cú pháp: int fclose(FILE *f)

Trong đó f là con trỏ tập tin được mở bởi hàm fopen(). Giá trị trả về của hàm là 0 báo rằng việc đóng tập tin thành công. Hàm trả về EOF nếu có xuất hiện lỗi.

Ngoài ra, ta còn có thể sử dụng hàm fcloseall() để đóng tất cả các tập tin lại.

Cú pháp: int fcloseall()

Kết quả trả về của hàm là tổng số các tập tin được đóng lại. Nếu không thành công, kết quả trả về là EOF.

2.5. Kiểm tra đến cuối tập tin hay chưa

Cú pháp: int feof(FILE *f)

Ý nghĩa: Kiểm tra xem đã chạm tới cuối tập tin hay chưa và trả về EOF nếu cuối tập tin được chạm tới, ngược lại trả về 0.

2.6. Các xử lý trên tập tin

+ Các hàm để đọc tập tin văn bản

STT

Tên hàm

Ý nghĩa

1

fscanf(FILE *tên_CT,các tham biến)

Đọc dữ liệu từ một tập tin.

2

fgets(vùng nhớ,kích thước tối đa, FILE *tên_CT)

Đọc một chuỗi ký tự từ một tập tin với kích thước tối đa cho phép hoặc gặp ký tự xuống dòng.

3

getc(FILE *tên_CT)

Đọc một ký tự từ tập tin đang mở.

+ Các hàm để ghi tập tin văn bản

STT

Tên hàm

Ý nghĩa

1

fprintf(FILE *tên_CT,các tham biến)

Ghi dữ liệu vào tập tin.

2

fputs(chuỗi ký tự, FILE *tên_CT)

Ghi một chuỗi ký tự vào tập tin đang mở.

+ Các hàm để đọc tập tin nhị phân

STT

Tên hàm

Ý nghĩa

1

fread(ptr,sizeof,len, FILE *tên_CT)

ptr: vùng nhớ để lưu trữ dữ liệu đọc

sizeof: kích thước mỗi ô nhớ, tính bằng byte.

len: độ dài dữ liệu cần đọc.

FILE: đọc từ tập tin nhị phân nào

+ Các hàm để ghi tập tin nhị phân

STT

Tên hàm

Ý nghĩa

1

fwirte(&ptr,sizeof,len, FILE *tên_CT)

ptr: vùng nhớ để lưu trữ dữ liệu đọc

sizeof: kích thước mỗi ô nhớ, tính bằng byte.

len: độ dài dữ liệu cần đọc.

FILE: đọc từ tập tin nhị phân nào

Ở các phần tiếp theo, sẽ đề cập kỹ hơn đến các hàm trên qua ví dụ.

2.7. Truy cập đến tập tin văn bản (text)

Ghi dữ liệu lên tập tin văn bản

+ Hàm putc()

Hàm này được dùng để ghi một ký tự lên một tập tin văn bản đang được mở để làm việc.

Cú pháp: int putc(int c, FILE *f)

Trong đó, tham số c chứa mã Ascii của một ký tự nào đó. Mã này được ghi lên tập tin liên kết với con trỏ f. Hàm này trả về EOF nếu gặp lỗi.

+ Hàm fputs()

Hàm này dùng để ghi một chuỗi ký tự chứa trong vùng đệm lên tập tin văn bản.

Cú pháp:int puts(const char *buffer, FILE *f)

Trong đó, buffer là con trỏ có kiểu char chỉ đến vị trí đầu tiên của chuỗi ký tự được ghi vào. Hàm này trả về giá trị 0 nếu buffer chứa chuỗi rỗng và trả về EOF nếu gặp lỗi.

+ Hàm fprintf()

Hàm này dùng để ghi dữ liệu có định dạng lên tập tin văn bản.

Cú pháp: fprintf(FILE *f, const char *format, varexpr)

Trong đó:format: chuỗi định dạng, varexpr: danh sách các biểu thức, mỗi biểu thức cách nhau dấu phẩy (,).

Ví dụ: Viết chương trình ghi chuỗi ký tự lên tập tin văn bản D:\\Baihat.txt

#include<stdio.h>

#include<conio.h>

int main()

{

FILE *f;

clrscr();

f=fopen("D:\\Baihat.txt","r+");

if (f!=NULL)

{

fputs("Em oi Ha Noi pho.\n",f);

fputs("Ta con em, mui hoang lan; ta con em, mui hoa sua.",f);

fclose(f);

}

getch();

return 0;

}

Nội dung tập tin Baihat.txt khi được mở bằng trình soạn thảo văn bản Notepad:

Đọc dữ liệu từ tập tin văn bản

+ Hàm getc()

Hàm này dùng để đọc dữ liệu từ tập tin văn bản đang được mở để làm việc.

Cú pháp: int getc(FILE *f)

Hàm này trả về mã Ascii của một ký tự nào đó (kể cả EOF) trong tập tin liên kết với con trỏ f.

+ Hàm fgets()

Cú pháp: char *fgets(char *buffer, int n, FILE *f)

Hàm này được dùng để đọc một chuỗi ký tự từ tập tin văn bản đang được mở ra và liên kết với con trỏ f cho đến khi đọc đủ n ký tự hoặc gặp ký tự xuống dòng ‘\n’ (ký tự này cũng được đưa vào chuỗi kết quả) hay gặp ký tự kết thúc EOF (ký tự này không được đưa vào chuỗi kết quả).

Trong đó:

- buffer (vùng đệm): con trỏ có kiểu char chỉ đến cùng nhớ đủ lớn chứa các ký tự nhận được.

- n: giá trị nguyên chỉ độ dài lớn nhất của chuỗi ký tự nhận được.

- f: con trỏ liên kết với một tập tin nào đó.

- Ký tự NULL (‘\0’) tự động được thêm vào cuối chuỗi kết quả lưu trong vùng đêm.

- Hàm trả về địa chỉ đầu tiên của vùng đệm khi không gặp lỗi và chưa gặp ký tự kết thúc EOF. Ngược lại, hàm trả về giá trị NULL.

+ Hàm fscanf()

Hàm này dùng để đọc dữ liệu từ tập tin văn bản vào danh sách các biến theo định dạng.

Cú pháp:fscanf(FILE *f, const char *format, varlist)

Trong đó: format: chuỗi định dạng (giống hàm scanf()); varlist: danh sách các biến mỗi biến cách nhau dấu phẩy (,).

Ví dụ: Viết chương trình chép tập tin D:\Baihat.txt ở trên sang tập tin D:\Baica.txt.

#include<stdio.h>

#include<conio.h>

int main()

{

FILE *f1,*f2;

clrscr();

f1=fopen("D:\\Baihat.txt","rt");

f2=fopen("D:\\Baica.txt","wt");

if (f1!=NULL && f2!=NULL)

{

int ch=fgetc(f1);

while (! feof(f1))

{

fputc(ch,f2);

ch=fgetc(f1);

}

fcloseall();

}

getch();

return 0;

}

Nội dung tập tin Baica.txt khi được mở bằng trình soạn thảo văn bản Notepad:

Chú ý: Hai tệp “Baihat.txt”“Baica.txt” đều đã có trên ổ D:

3. Tạo file nhị phân

Sau khi mở tệp mới xong với chế độ xử lý là w (writing), tệp sẽ rỗng vì chưa có phần tử nào, cửa sổ tệp sẽ không có giá trị xác định vì nó trỏ vào cuối tệp (EOF). Đồng thời cần lưu ý khi mở tệp nếu trên bộ nhớ ngoài mà đã có sẵn tệp có tên trùng với tên tệp được mở thì tệp cũ sẽ bị xóa đi.

Ví dụ: Tạo ra tệp tin có 100 phần tử có giá trị từ 1 đến 100:

#include<stdio.h>

main()

{

char filename[21];

int i;

long num;

FILE *f;

printf (“Tên tập tin cần tạo ra là: “);

scanf (“%20s”, filename);

f = fopen (filename,”wb”);

for (i = 1; i<=100; i++)

fwrite(&i, sizeof(int),i,f);

fclose(f);

}

4. Đọc file nhị phân

4.1. Ghi dữ liệu lên tệp nhị phân

Ghi dữ liệu lên tập tin nhị phân - Hàm fwrite()

Cú pháp:size_t fwrite(const void *ptr, size_t size, size_t n, FILE *f)

Trong đó:

- ptr: con trỏ chỉ đến vùng nhớ chứa thông tin cần ghi lên tập tin.

- n: số phần tử sẽ ghi lên tập tin.

- size: kích thước của mỗi phần tử.

- f: con trỏ tập tin đã được mở.

- Giá trị trả về của hàm này là số phần tử được ghi lên tập tin. Giá trị này bằng n trừ khi xuất hiện lỗi.

4.2. Đọc dữ liệu từ tập tin nhị phân - Hàm fread()

Cú pháp:size_t fread(const void *ptr, size_t size, size_t n, FILE *f)

Trong đó:

- ptr: con trỏ chỉ đến vùng nhớ sẽ nhận dữ liệu từ tập tin.

- n: số phần tử được đọc từ tập tin.

- size: kích thước của mỗi phần tử.

- f: con trỏ tập tin đã được mở.

- Giá trị trả về của hàm này là số phần tử đã đọc được từ tập tin. Giá trị này bằng n hay nhỏ hơn n nếu đã chạm đến cuối tập tin hoặc có lỗi xuất hiện.

4.3. Di chuyển con trỏ tập tin - Hàm fseek()

Việc ghi hay đọc dữ liệu từ tập tin sẽ làm cho con trỏ tập tin dịch chuyển một số byte, đây chính là kích thước của kiểu dữ liệu của mỗi phần tử của tập tin.

Khi đóng tập tin rồi mở lại nó, con trỏ luôn ở vị trí ngay đầu tập tin. Nhưng nếu ta sử dụng kiểu mở tập tin là “a” để ghi nối dữ liệu, con trỏ tập tin sẽ di chuyển đến vị trí cuối cùng của tập tin này.

Ta cũng có thể điều khiển việc di chuyển con trỏ tập tin đến vị trí chỉ định bằng hàm fseek().

Cú pháp:int fseek(FILE *f, long offset, int whence)

Trong đó:

+ f: con trỏ tập tin đang thao tác.

+ offset: số byte cần dịch chuyển con trỏ tập tin kể từ vị trí trước đó. Phần tử đầu tiên là vị trí 0.

+ whence: vị trí bắt đầu để tính offset, ta có thể chọn điểm xuất phát là:

+ Kết quả trả về của hàm là 0 nếu việc di chuyển thành công. Nếu không thành công, 1 giá trị khác 0 (đó là 1 mã lỗi) được trả về.

Ví dụ:

Viết chương trình ghi lên tập tin “CacSo.Dat” 3 giá trị số (thực, nguyên, nguyên dài). Sau đó đọc các số từ tập tin vừa ghi và hiển thị lên màn hình.

#include<stdio.h>

#include<conio.h>

int main()

{

FILE *f;

clrscr();

f=fopen("D:\\CacSo.txt","wb");

if (f!=NULL)

{

double d=3.14;

int i=101;

long l=54321;

fwrite(&d,sizeof(double),1,f);

fwrite(&i,sizeof(int),1,f);

fwrite(&l,sizeof(long),1,f);

/* Doc tu tap tin*/

rewind(f);

fread(&d,sizeof(double),1,f);

fread(&i,sizeof(int),1,f);

fread(&l,sizeof(long),1,f);

printf("Cac ket qua la: %f%d%ld",d,i,l);

fclose(f);

}

getch();

return 0;

}

Chương 10. Dữ liệu kiểu chuỗi

I. Khai báo

1.Mảng:

_Tổng quát :          char  string_Name[CAPACITY];

trong đó:          string_Name là tên mảng ký tự đang định nghĩa

                        CAPACITY là số phần tử mảng có thể chứa bao gồm NULL (‘ \ 0’ )

_Mọi chuỗi trong C++ đều được kết thúc bằng NULL( ‘\ 0’ )

_Một mảng ký tự có thể được khởi tạo bằng hằng chuỗi.

VD:

            char color[]   = ”blue” ;

            char color[]   = {“blue”} ;

            char color[5] = “blue” ;

            char color[5] = {“blue”};

_Hoặc bằng hằng ký tự

VD:

            char color[] = {‘b’,’l’,’u’,’e’,’\ 0’};

2.Con trỏ:

_Tổng quát:           char*string_Pointer;

trong đó:          string_Pointer là tên con trỏ đến chuỗi

VD:

char *colorPtr;

            colorPtr = “blue”;        <=>     char *colorPtr = “blue” ;

Ở trên, con trỏ colorPtr trỏ đến chuỗi “blue” ở đâu đó trong bộ nhớ, phép gán gán địa chỉ chuỗi “blue” đến con trỏ.

Cách này không làm được với mảng ký tự:

VD:    

            char color[5];

            color = “blue”; //Lỗi

vì color là tên của mảng, là con trỏ hằng trỏ đến địa chỉ phần tử đầu của mảng. Việc gán giá trị cho hằng là không thể.

II.NHẬP/XUẤT:

1.Xuất: COUT

            _Cả mảng và con trỏ đều dùng được toán tử chèn << và đối tượng cout

               VD:              cout << color;

                                    cout << colorPtr;

            Cả hai đều được xuất ra đến khi gặp ký tự null.

2.Nhập

a)CIN

            _Toán tử  >> và cin, sẽ đọc các ký tự khác ký tự khoảng trắng (trắng,tab và enter) từ luồng nhập.

VD:

            char name[10];

            cin >> name;

khi nhập : “A B C” thì chỉ có A được truyền vào mảng,”B C” còn lại trên luồng nhập.Cần chú ý chuỗi nhập vào phải = kích thước mảng – 1, vì có ký tự kết thúc.

b)CIN.GETLINE()

            _Đọc toàn bộ chuỗi văn bản được nhập vào.Cấu trúc:

cin.getline(char *charPtr, int n, char delim = ‘\n’);

Trong đó:

+ charPtr là con trỏ trỏ đến mảng ký tự (tên mảng cũng là con trỏ, nhưng là con trỏ hằng).

+ n là số ký tự tối đa được chứa trong mảng, kể cả ký tự ‘’

+delim là ký tự phân cách (delimiter character), mặc định là ký tự ‘\n’

_Hàm getline đọc chuỗi cho đến khi gặp ký tự phân cách, hoặc ký hiệu kết thúc tập tin (ctrl – z), hoặc khi số ký tự đã đọc nhỏ hơn một so với giá trị n trong đối số thứ 2. Nếu ký tự phân cách được gặp, nó đượclấy ra khỏi istream và bỏ đi.

VD:

            char name[10];

            cin.getline(name, 10, ‘.’);

Nếu nhập : A B. C

Mảng name sẽ là : A B

            _Con trỏ thì phải cấp phát mới dùng được.

III.MỘT SỐ PHÉP TOÁN TRÊN CHUỖI:

1. Truy xuất từng phần tử trong chuỗi thông qua chỉ số.

VD: cout << name[0];

Đếm chiều dài chuỗi với strlen() : đọc thêm ở (IV)

2. Gán chuỗi:

            _Mảng ký tự có thể được gán lúc khởi tạo

                        char name[] = “abc”;

            _Nhưng phép gán sau khai báo là 1 lỗi

                        char name[5] ;

name = “abc”;//lỗi

            _Với con trỏ thì mọi phép gán đều hợp lệ

3. Hàm thành viên get()

int cin.get();

cin.get(char &cRef);// cRef là tham chiếu đến biến kiểu char

cin.get(char *charPtr, int n, char delim = ‘\n’); 

 

  1. Hàm get() không đối số, đọc một ký tự từ luồng nhập(kể cả ký tự trắng) và trả về ký tự này. Nếu là ký tự kết thúc tập tin thì hàm trả về EOF (EOF có giá trị khác nhau trên những hệ thống khác nhau).

            VD:

                        while( ( c = cin.get() ) != EOF)

                                    cout << c;

Đoạn chương trình trên sẽ đọc từng ký tự của chuỗi nhập vào truyền vào biến c và xuất ra màn hình. Nếu người dùng nhập vào ký hiệu kết thúc tập tin (end-of-file) là tổ hợp phím ctrl-z thì vòng lặp kết thúc.

  1. Hàm thành viên get() với một đối số kiểu char đọc một ký tự từ luồng nhập (kể cả ký tự trắng) và chứa trong đối số đó. Trả vế 0 khi ký hiệu kết thúc tập tin được gặp. ngược lại trả về tham chiếu đến đối tượng istream.

  2. Hàm thành viên get() dạng thứ 3 hoạt động tương tự như hàm thành viên getline(), nhưng ký tự phân cách không được lấy ra mà  còn trên luồng nhập. Vì thế hàm get() kế tiếp sẽ là dòng trống. Để loại bỏ có thể dùng dạng 1 hoặc 2 của hàm get(), hoặc hàm thành viên ignore().

  1. Hàm thành viên ignore()

cin.ignore(int n = 1, int delim = EOF);

Bỏ qua một số ký tự được chỉ định (mặc định là một ký tự) trong luồng nhập hoặc bỏ qua cho đến khi ký tự phân cách (mặc định là EOF) được gặp.Mục đích là không làm ảnh hưởng các lệnh nhập tiếp theo.

IV.Một số hàm thư viện xử lý chuỗi

  • char *strcat(char *s1, const char *s2)

Thêm chuỗi s2 vào mảng ký tự s1 (mảng phải đủ lớn). Ký tự đầu tiên của chuỗi s2 ghi đè lên ký tự null kết thúc của s1.Giá trị s1 được trả về.

  • char *strncat(char *s1, const char * s2, size_t n)

Thêm n ký tự s2 vào s1

  • char *strchr(const char *s, int c)

  Vị trí xuất hiện đầu tiên của ký tự c trong chuỗi s. c được tìm thấy thì trả về con trỏ đến c trong s, không thì trả về NULL.

  • char *strrchr(char *s1, int c)

  Vị trí xuất hiện cuối cùng của kí tự c trong chuỗi

  • int *strcmp(const char *s1,const char *s2)

  So sánh chuỗi s1 với chuỗi s2: bằng trả về 0, < trả về < 0, > trả về >0

  • int *strncmp(const char *s1,const char *s2, size_t n)

So sánh đến n ký tự của chuỗi s1 với chuỗi s2.

  • char *strcpy(char *s1,const char *s2)

Sao chép chuỗi s2 vào mảng ký tự s1(mảng phải đủ lớn). Giá trị s1 được trả về.

  • char *strncpy(char *s1, const char *s2, size_t n)

Sao chép n ký tự chuỗi s2 vào s1

  • size_t strlen(const char *s)

Xác định chiều dài của chuỗi s. Tính số ký tự đứng trước null.

  • char *strstr(const char *s1,const char *s2)

  Vị trí xuất hiện đầu tiên của chuỗi s2 trong chuỗi s1. Tìm thấy thì trả về con trỏ tới chỗ xuất hiện, không thì trả về null

V. Bài tập - Ví dụ

1) Nhập vào 1 chuỗi và xuất chuỗi đó ra theo chiều ngược lại: VD Nhập vào tran van thoa xuất ra aoht nav nart

#include <conio.h> #include <stdio.h> #include <string.h>  //thư viện chuỗi int main() {     char xau[30];     printf("Nhap vao 1 chuoi: ");     gets(xau);     for(int i=strlen(xau)-1;i>=0;i--)  //strlen trả về độ dài của chuỗi     {         printf("%c",xau[i]);     }     getch(); } 2) Nhập vào 1 chuỗi và xuất chuỗi đó ra theo chiều ngược lại: VD Nhập vào tran van thoa xuất ra thoa van tran

#include <stdio.h> #include <conio.h> #include <string.h> int main() {    char xau[50];    printf("Nhap vao mot chuoi: ");    gets(xau);    int a=strlen(xau)-1;    for(int i=strlen(xau)-1;i>=0;i--)    {       if(xau[i]==32 || i==0)       {          if(i==0)          {             printf(" ");          }          for(int j=i;j<=a;j++)          {             printf("%c",xau[j]);          }          a=i-1;       }     }    getch(); } 3) Nhập vào họ và tên tách ra họ, tên; VD Nhập vào tran van thoa xuất ra tran thoa

#include <conio.h> #include <stdio.h> #include <string.h> int main() {     char xau[30];     printf("Nhap vao mot chuoi: ");     gets(xau);     for(int i=0;i<strlen(xau);i++)     {         if(xau[i]!=32)         {             printf("%c",xau[i]);         }         else         {          for(int j=strlen(xau)-1;j>=i;j--)          {             if(xau[j]==32)             {                for(int k=j;k<=strlen(xau)-1;k++)                printf("%c",xau[k]);                break;             }          }          break;       }     }     getch(); } 4) Nhập vào họ và tên xuất ra họ, tên đệm, tên mỗi từ 1 dòng; VD Nhập vào tran van thoa xuất ra  tran  van  thoa

#include <conio.h> #include <stdio.h> #include <string.h> int main() {     char xau[30];     printf("Nhap vao mot chuoi: ");     gets(xau);     for(int i=0;i<=strlen(xau)-1;i++)     {       if(xau[i]!=32)       {           printf("%c",xau[i]);       }         else       {             printf("\n");       }     }     getch(); } 5) Nhập vào 1 dãy số và đọc dãy số đó. VD: 123 đọc là một trăm hai mươi ba

#include <conio.h> #include <stdio.h> #include <string.h> char doc_so[50]; char *docso(int n) {    char doc[10][5]={"","Mot","Hai","Ba","Bon","Nam","Sau","Bay","Tam","Chin"};    doc_so[0]=0;    int donvi=n%10;    n=n/10;    int chuc=n%10;    int tram=n/10;    if(tram>0)    {       strcat(doc_so,doc[tram]);       strcat(doc_so," Tram ");    }    if(chuc>0)    {       if(chuc==1)       strcat(doc_so," Muoi ");       else       {          strcat(doc_so,doc[chuc]);          strcat(doc_so," Muoi ");       }    }    if(donvi>0)    strcat(doc_so,doc[donvi]);    return doc_so; } int main() {    int n;     printf("Nhap vao mot day so: ");     scanf("%d",&n);     if(n==0)     {       printf("Khong");    }    else    {       int tram=n%1000;        n=n/1000;       int ngan=n%1000;       n=n/1000;       int trieu=n%1000;       int ty=n/1000;       if(ty>0)       {          printf("%s Ty",docso(ty));       }       if(trieu>0)       {          printf(" %s Trieu ",docso(trieu));       }       if(ngan>0)       {          printf(" %s Ngan ",docso(ngan));       }       if(tram>0)       {          printf(" %s ",docso(tram));       }    }    getch(); } 6) Nhập vào 1 chuỗi sau đó nhập váo 1 từ và kiểm tra xem từ đó có xuất hiện trong chuỗi trên hay không, nếu có thì xuất hiện bao nhiêu lần. VD Nhập vào tran van thoa. Nhập kí tự t --> có 2 lần

#include <stdio.h> #include <conio.h> #include <string.h> int main() {     char xau[50];     char kitukiemtra;     int dem;     printf("Nhap vao mot chuoi: ");     gets(xau);     printf("Nhap vao ki tu muon kiem tra: ");     scanf("%c",&kitukiemtra);     for(int i=0;i<strlen(xau)-1;i++)     {         if(xau[i]==kitukiemtra)         dem++;     }     if(dem==0)     printf("Ki tu %c khong co trong chuoi",kitukiemtra);     else     printf("Ki tu %c xuat hien %d lan trong chuoi",kitukiemtra,dem);     getch(); }

Bài tập luyện

Bài tập 1: Viết chương trình tạo ra 2 tệp có tên là “LTCB” và “LTNC”. Trong chương trình sử dụng các hàm:

+ fopen để mở tệp.

+ fputc để ghi một ký tự lên tệp.

+ fclose để đóng tệp.

Bài tập 2: Hãy viết chương trình theo yêu cầu sau:

+ Đầu tiên ghi một dãy ký tự từ ‘K’ đến ‘Q’ lên tệp có tên là “Baitap2”.

+ Tạo tệp “BT2.sl” và ghi lên tệp “BT2.sl” 10 ký tự.

Bài tập 3: Hãy tạo một văn bản text gồm 3 dòng với nội dung như sau:

Lap trinh co ban

Turbo C

Pascal

Bài tập 4: + Viết chương trình nhập các dòng ký tự từ bàn phím và ghi lên tệp có tên là “Baitap4”.

+ Viết chương trình đọc các dòng ký tự trên tệp “Baitap4” và in ra màn hình.

Bài tập 5: Mỗi sinh viên cần quản lý ít nhất 2 thông tin: mã sinh viên và họ tên. Viết chương trình cho phép lựa chọn các chức năng: nhập danh sách sinh viên từ bàn phím rồi ghi lên tập tin SinhVien.dat, đọc dữ liệu từ tập tin SinhVien.dat rồi hiển thị danh sách lên màn hình, tìm kiếm họ tên của một sinh viên nào đó dựa vào mã sinh viên nhập từ bàn phím.

Hướng dẫn:

Ta nhận thấy rằng mỗi phần tử của tập tin SinhVien.Dat là một cấu trúc có 2 trường: mã và họ tên. Do đó, ta cần khai báo cấu trúc này và sử dụng các hàm đọc/ghi tập tin nhị phân với kích thước mỗi phần tử của tập tin là chính kích thước cấu trúc đó.

#include<stdio.h>

#include<conio.h>

#include<string.h>

typedef struct

{

char Ma[10];

char HoTen[40];

} SinhVien;

void WriteFile(char *FileName)

{

FILE *f;

int n,i;

SinhVien sv;

f=fopen(FileName,"ab");

printf("Nhap bao nhieu sinh vien? ");scanf("%d",&n);

fflush(stdin);

for(i=1;i<=n;i++)

{

printf("Sinh vien thu %i\n",i);

printf(" - MSSV: ");gets(sv.Ma);

printf(" - Ho ten: ");gets(sv.HoTen);

fwrite(&sv,sizeof(sv),1,f);

fflush(stdin);

}

fclose(f);

printf("Bam phim bat ky de tiep tuc");

getch();

}

void ReadFile(char *FileName)

{

FILE *f;

SinhVien sv;

f=fopen(FileName,"rb");

printf(" MSSV|Ho va ten\n");

fread(&sv,sizeof(sv),1,f);

while (!feof(f))

{

printf("%s| %s\n",sv.Ma,sv.HoTen);

fread(&sv,sizeof(sv),1,f);

}

fclose(f);

printf("Bam phim bat ky de tiep tuc!!!");

getch();

}

void Search(char *FileName)

{

char MSSV[10];

FILE *f;

int Found=0;

SinhVien sv;

fflush(stdin);

printf("Ma so sinh vien can tim: ");gets(MSSV);

f=fopen(FileName,"rb");

while (!feof(f) && Found==0)

{

fread(&sv,sizeof(sv),1,f);

if (strcmp(sv.Ma,MSSV)==0) Found=1;

}

fclose(f);

if (Found == 1)

printf("Tim thay SV co ma %s. Ho ten la: %s",sv.Ma,sv.HoTen);

else

printf("Tim khong thay sinh vien co ma %s",MSSV);

printf("\nBam phim bat ky de tiep tuc!!!");

getch();

}

int main()

{

int c;

for (;;)

{

clrscr();

printf("1. Nhap DSSV\n");

printf("2. In DSSV\n");

printf("3. Tim kiem\n");

printf("4. Thoat\n");

printf("Ban chon 1, 2, 3, 4: "); scanf("%d",&c);

if(c==1)

WriteFile("d:\\SinhVien.Dat");

else if (c==2)

ReadFile("d:\\SinhVien.Dat");

else if (c==3)

Search("d:\\SinhVien.Dat");

else break;

}

return 0;

}

Tài liệu tham khảo

  1. Giáo trình lập trình C và C++

2. Ngôn ngữ lập trình C và C++ Bài giảng – Bài tập – Lời giải mẫu – Ngô Trung Việt - NXB Thống kê.

3. Giáo trình ngôn ngữ lập trình C – Phạm Văn Ất – NXB Thế giới

4. Ngôn ngữ lập trình C++ - Quách Tuấn Ngọc – NXB Thống kê.

5. Giáo trình C++ và lập trình hướng đối tượng – Phạm Văn Ất, Lê Trường Thông – NXB Hồng Đức.

6. Giáo trình Kỹ thuật lập trình C cơ bản và nâng cao – NXB Hồng Đức.

109