136

Lt giao trinh nhap mon lap trinh c 2015_02_26

Embed Size (px)

Citation preview

Page 1: Lt giao trinh nhap mon lap trinh c 2015_02_26
Page 2: Lt giao trinh nhap mon lap trinh c 2015_02_26

2

Page 3: Lt giao trinh nhap mon lap trinh c 2015_02_26

MỤC LỤC

CHƯƠNG 1. GIỚI THIỆU TỔNG QUAN VỀ LẬP TRÌNH...................................6

1.1. Khái niệm về chương trình máy tính................................................................6

1.1.1. Chương trình (Program).................................................................................6

1.1.2. Giải thuật (Algorithm)....................................................................................6

1.1.3. Ngôn ngữ lập trình (Programming language).................................................7

1.2. Biểu diễn thuật toán............................................................................................7

1.2.1. Sử dụng ngôn ngữ tự nhiên............................................................................8

1.2.2. Sử dụng lưu đồ - Sơ đồ khối...........................................................................9

1.2.3. Sử dụng mã giả.............................................................................................13

1.3. Các bước xây dựng chương trình....................................................................14

1.4. Hệ đếm và biểu diễn số trong hệ đếm.............................................................14

1.4.1. Hệ đếm..........................................................................................................14

1.4.2. Biểu diễn số trong các hệ đếm......................................................................15

1.4.2.1. Hệ đếm thập phân (decimal system)......................................................15

1.4.3. Hệ đếm nhị phân (binary number system)...................................................16

1.4.4. Hệ đếm thập lục phân (hexa-decimal number system).................................17

1.4.5. Đổi một số nguyên từ hệ thập phân sang hệ b..............................................17

CHƯƠNG 2. CÁC THÀNH PHẦN TRONG NGÔN NGỮ C................................18

2.1. Các khái niệm cơ bản.......................................................................................18

2.1.1. Từ khóa.........................................................................................................18

2.1.2. Tên................................................................................................................18

2.1.3. Tập ký tự dùng trong ngôn ngữ C................................................................19

2.1.4. Các kiểu dữ liệu cơ sở..................................................................................20

2.1.5. Cấu trúc một chương trình C........................................................................25

2.2. Biểu thức và các phép toán trong C................................................................27

2.2.1. Biểu thức.......................................................................................................27

2.2.2. Các phép toán...............................................................................................28

2.2.3. Biểu thức điều kiện.......................................................................................35

2.3. Khai báo biến.....................................................................................................35

2.3.1. Khai báo biến................................................................................................35

3

Page 4: Lt giao trinh nhap mon lap trinh c 2015_02_26

2.3.2. Phạm vi của biến..........................................................................................37

2.4. Ghi chú...............................................................................................................37

2.5. Nhập / Xuất dữ liệu trong C.............................................................................38

2.5.1. Hàm printf....................................................................................................38

2.5.2. Hàm scanf.....................................................................................................41

CHƯƠNG 3. CÁC CẤU TRÚC ĐIỀU KHIỂN........................................................43

3.1. Cấu trúc rẽ nhánh.............................................................................................43

3.1.1. Cấu trúc if-else.............................................................................................43

3.1.2. Cấu trúc switch:............................................................................................46

3.2. Cấu trúc lặp.......................................................................................................48

3.2.1. Cấu trúc lặp for.............................................................................................48

3.2.2. Cấu trúc lặp while.........................................................................................51

3.2.3. Cấu trúc lặp do-while...................................................................................52

3.3. Câu lệnh break, continute................................................................................54

3.3.1. Câu lệnh break..............................................................................................54

3.3.2. Câu lệnh continue.........................................................................................55

CHƯƠNG 4. HÀM VÀ TRUYỀN THAM SỐ.........................................................57

4.1. Định nghĩa hàm trong C...................................................................................57

4.1.1. Khai báo hàm................................................................................................57

4.1.2. Phạm vi hoạt động của các biến...................................................................59

4.2. Truyền tham số cho hàm..................................................................................61

4.3. Một số ví dụ minh họa......................................................................................64

CHƯƠNG 5. CÁC KIỂU DỮ LIỆU CÓ CẤU TRÚC.............................................66

5.1. Kiểu dữ liệu mảng.............................................................................................66

5.1.1. Mảng một chiều............................................................................................66

5.1.2. Mảng hai chiều.............................................................................................70

5.2. Chuỗi ký tự........................................................................................................80

5.2.1. Khái niệm.....................................................................................................80

5.2.2. Một số hàm thao tác trên chuỗi ký tự...........................................................81

5.2.3. Một số ví dụ minh họa..................................................................................83

5.3. Dữ liệu structure...............................................................................................83

4

Page 5: Lt giao trinh nhap mon lap trinh c 2015_02_26

5.3.1. Khái niệm.....................................................................................................83

5.3.2. Truy xuất đến các thành phần kiểu cấu trúc.................................................83

5.3.3. Khai báo kiểu cấu trúc..................................................................................83

5.3.4. Cách khai báo biến có kiểu structure............................................................83

CHƯƠNG 6. TẬP TIN................................................................................................88

6.1. Khái niệm về tệp tin..........................................................................................88

6.2. Một số hàm thường dùng khi thao tác trên tệp..............................................89

6.2.1. Khai báo sử dụng tệp....................................................................................89

6.2.2. Mở tệp - hàm fopen......................................................................................89

6.2.3. Đóng tệp - hàm fclose...................................................................................91

6.2.4. Đóng tất cả các tệp đang mở- hàm fcloseall:................................................92

6.2.5. Kiểmtra cuối tệp - hàm feof..........................................................................92

6.2.6. Truy nhập ngẫu nhiên - các hàm di chuyên con trỏ chỉ vị:..........................92

6.2.6.1. Chuyển con trỏ chỉ vị về đầu tệp - Hàm rewind:...................................92

6.2.6.2. Chuyển con trỏ chỉ vị trí cần thiết - Hàm fseek.....................................93

6.2.6.3. Vị trí hiện tại của con trỏ chỉ vị - Hàm ftell:..........................................93

6.2.7. Ghi các mẫu tin lên tệp - hàm fwrite............................................................94

6.2.8. Đọc các mẫu tin từ tệp - hàm fread..............................................................95

6.2.9. Nhập xuất ký tự............................................................................................96

6.2.9.1. Các hàm putc và fputc............................................................................96

6.2.9.2. Các hàm getc và fgettc...........................................................................97

6.2.10. Xoá tệp - hàm unlink:.................................................................................98

6.3. Một số ví dụ.......................................................................................................99

6.3.1. Ghi, đọc mảng..............................................................................................99

6.3.2. Ghi, đọc structure.......................................................................................100

Tài liệu tham khảo.....................................................................................................103

5

Page 6: Lt giao trinh nhap mon lap trinh c 2015_02_26

CHƯƠNG 1. CHƯƠNG 1. GIỚI THIỆU TỔNG QUAN VỀ LẬP TRÌNHGIỚI THIỆU TỔNG QUAN VỀ LẬP TRÌNH

1.1. Khái niệm về chương trình máy tính

Phần này chúng ta sẽ tìm hiểu một số khái niệm căn bản về thuật toán, chương

trình, ngôn ngữ lập trình. Thuật ngữ "thuật giải" và "thuật toán" dĩ nhiên có sự khác

nhau song trong nhiều trường hợp chúng có cùng nghĩa.

1.1.1. Chương trình (Program)

Là một tập hợp các mô tả, các phát biểu, nằm trong một hệ thống qui ước về ý

nghĩa và thứ tự thực hiện, nhằm điều khiển máy tính làm việc. Theo Niklaus Wirth thì:

Chương trình = Thuật toán + Cấu trúc dữ liệu

Các thuật toán và chương trình đều có cấu trúc dựa trên 3 cấu trúc điều khiển cơ

bản:

Tuần tự (Sequential): Các bước thực hiện tuần tự một cách chính xác từ trên

xuống, mỗi bước chỉ thực hiện đúng một lần.

Chọn lọc (Selection): Chọn 1 trong 2 hay nhiều thao tác để thực hiện.

Lặp lại (Repetition): Một hay nhiều bước được thực hiện lặp lại một số lần.

Muốn trở thành lập trình viên chuyên nghiệp bạn hãy làm đúng trình tự để có

thói quen tốt và thuận lợi sau này trên nhiều mặt của một người làm máy tính. Bạn hãy

làm theo các bước sau:

Tìm, xây dựng thuật giải (trên giấy) viết chương trình trên máy

dịch chương trình chạy và thử chương trình

1.1.2. Giải thuật (Algorithm)

Là một dãy các thao tác xác định trên một đối tượng, sao cho sau khi thực hiện

một số hữu hạn các bước thì đạt được mục tiêu. Theo R.A.Kowalski thì bản chất của

thuật giải:

Thuật giải = Logic + Điều khiển

6

Page 7: Lt giao trinh nhap mon lap trinh c 2015_02_26

Logic: Đây là phần khá quan trọng, nó trả lời câu hỏi "Thuật giải làm gì, giải

quyết vấn đề gì?", những yếu tố trong bài toán có quan hệ với nhau như thế nào v.v…

Ở đây bao gồm những kiến thức chuyên môn mà bạn phải biết để có thể tiến hành giải

bài toán.

Ví dụ 1.1: Để giải một bài toán tính diện tích hình cầu, mà bạn không còn nhớ

công thức tính hình cầu thì bạn không thể viết chương trình cho máy để giải bài toán

này được.

Điều khiển: Thành phần này trả lời câu hỏi: giải thuật phải làm như thế nào?.

Chính là cách thức tiến hành áp dụng thành phần logic để giải quyết vấn đề.

1.1.3. Ngôn ngữ lập trình (Programming language)

Ngôn ngữ lập trình là hệ thống các ký hiệu tuân theo các qui ước về ngữ pháp và

ngữ nghĩa, dùng để xây dựng thành các chương trình cho máy tính.

Một chương trình được viết bằng một ngôn ngữ lập trình cụ thể (ví dụ C, …) gọi

là chương trình nguồn, chương trình dịch làm nhiệm vụ dịch chương trình nguồn thành

chương trình thực thi được trên máy tính.

1.2. Biểu diễn thuật toán

Khi chứng minh hoặc giải một bài toán trong toán học, ta thường dùng những

ngôn từ toán học như: "ta có", "điều phải chứng minh", "giả thuyết", ... và sử dụng

những phép suy luận toán học như phép suy ra, tương đương, ...Thuật toán là một

phương pháp thể hiện lời giải bài toán nên cũng phải tuân theo một số quy tắc nhất

định. Ðể có thể truyền đạt thuật toán cho người khác hay chuyển thuật toán thành

chương trình máy tính, ta phải có phương pháp biểu diễn thuật toán.

a) 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ả.

7

Page 8: Lt giao trinh nhap mon lap trinh c 2015_02_26

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ả.

b) 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.

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.

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ả.

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ạ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.

1.2.1. Sử dụng ngôn ngữ tự nhiên

Trong cách biểu diễn thuật toán theo ngôn ngữ tự nhiên, người ta sử dụng ngôn

ngữ thường ngày để liệt kê các bước của thuật toán. Phương pháp biểu diễn này không

8

Page 9: Lt giao trinh nhap mon lap trinh c 2015_02_26

yêu cầu người viết thuật toán cũng như người đọc thuật toán phải nắm các quy tắc.

Tuy vậy, cách biểu diễn này thường dài dòng, không thể hiện rõ cấu trúc của thuật

toán, đôi lúc gây hiểu lầm hoặc khó hiểu cho người đọc. Gần như không có một quy

tắc cố định nào trong việc thể hiện thuật toán bằng ngôn ngữ tự nhiên. Tuy vậy, để dễ

đọc, ta nên viết các bước con lùi vào bên phải và đánh số bước theo quy tắc phân cấp

như 1, 1.1, 1.1.1, ...

Ví dụ 1.2:Ðể tính tổng các số nguyên dương lẻ trong khoảng từ 1 đến n ta có

thuật toán sau:

B1. Hỏi giá trị của n.

B2. S = 0

B3. i = 1

B4. Nếu i = n+1 thì sang bước B8, ngược lại sang bước B5

B5. Cộng thêm i vào S

B6. Cộng thêm 2 vào i

B7. Quay lại bước B4.

B8. Tổng cần tìm chính là S.

Ta chú ý đến bước B4. Ở đây ta muốn kết thúc thuật toán khi giá trị của i vượt

quá n. Thay vì viết là "nếu i lớn hơn n" thì ta thay bằng điều kiện "nếu i bằng n+1" vì

theo toán học "i = n+1" thì suy ra "i lớn hơn n". Nhưng điều kiện "i = n+1" không phải

lúc nào cũng đạt được. Vì ban đầu i = 1 là số lẻ, sau mỗi bước, i được tăng thêm 2 nên

i luôn là số lẻ. Nếu n là số chẵn thì n+1 là một số lẻ nên sau một số bước nhất định, i

sẽ bằng n+1. Tuy nhiên, nếu n là một số lẻ thì n+1 là một số chẵn, do i là số lẻ nên dù

có qua bao nhiêu bước đi chăng nữa, i vẫn khác n+1. Trong trường hợp đó, thuật toán

trên sẽ bị quẩn.

1.2.2. Sử dụng lưu đồ - Sơ đồ khối

Để dễ hơn về quy trình xử lý, các nhà lập trình đưa ra dạng lưu đồ để minh họa

từng bước quá trình xử lý một vấn đề (bài toán).

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 đồ:

9

Page 10: Lt giao trinh nhap mon lap trinh c 2015_02_26

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. 

10

Page 11: Lt giao trinh nhap mon lap trinh c 2015_02_26

Bắt đầu

Kết thúc

Giá trị a, b

Chia –b cho a

Nghiệm x

Bắt đầu

Kết thúc

LCB, ngày công

Nhân LCB với ngày công

Kết quả lương

Bắt đầu

Kết thúc

Cà phê, nước sôi

Hòa cà phê vào nước sôi

Bỏ đường vào

Khuấy đều hỗn hợp

Cà phê đã sẵn sàng

Ví dụ 1.3: Đọ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

Ví dụ 1.4:

Chuẩn bị cà phê Mô tả Ví dụ Mô tả Ví dụ

11

Page 12: Lt giao trinh nhap mon lap trinh c 2015_02_26

Bắt đầu

Kết thúc

Số a, Số b

Số a bằng Số b

Số a có bằngSố b không?

Số a không bằng Số b

Không

Bắt đầu

Kết thúc

a, b

c = a + b

c

Bắt đầu

Kết thúc

Điểm

Điểm hợp lệ

Điểm >=0 vàĐiểm <=10 ?

Điểm không hợp lệ

Không

Bắt đầu

Kết thúc

Thùng = 24 Lon?Chưa

Thùng = 0 Lon

1 Lon

Thêm 1 Lon vào thùng

Bằng

Cộng 2 số So sánh 2 số

Kiểm tra tính hợp lệ của điểm Xếp lon vào thùng

12

Page 13: Lt giao trinh nhap mon lap trinh c 2015_02_26

Bắt đầu

Kết thúc

Số

Số dươngSố > 0 ? Có

Số < 0 ? Số âmCó

Số không

Không

Không

Bắt đầu

Kết thúc

Sai

Điểm

Đúng

Điểm >=0 vàĐiểm <=10 ?

Kiểm tra loại số Kiểm tra tính hợp lệ của điểm

1.2.3. Sử dụng mã giả

Tuy sơ đồ khối thể hiện rõ quá trình xử lý và sự phân cấp các trường hợp của

thuật toán nhưng lại cồng kềnh. Ðể mô tả một thuật toán nhỏ ta phải dùng một không

gian rất lớn. Hơn nữa, lưu đồ chỉ phân biệt hai thao tác là rẽ nhánh (chọn lựa có điều

kiện) và xử lý mà trong thực tế, các thuật toán còn có thêm các thao tác lặp.

Khi thể hiện thuật toán bằng mã giả, ta sẽ vay mượn các cú pháp của một ngôn

ngữ lập trình nào đó để thể hiện thuật toán. Tất nhiên, mọi ngôn ngữ lập trình đều có

những thao tác cơ bản là xử lý, rẽ nhánh và lặp. Dùng mã giả vừa tận dụng được các

khái niệm trong ngôn ngữ lập trình, vừa giúp người cài đặt dễ dàng nắm bắt nội dung

thuật toán. Tất nhiên là trong mã giả ta vẫn dùng một phần ngôn ngữ tự nhiên. Một khi

đã vay mượn cú pháp và khái niệm của ngôn ngữ lập trình thì chắc chắn mã giả sẽ bị

phụ thuộc vào ngôn ngữ lập trình đó. Chính vì lý do này, chúng ta chưa vội tìm hiểu về

mã giả trong bài này (vì chúng ta chưa biết gì về ngôn ngữ lập trình!). Sau khi tìm hiểu

xong bài về thủ tục - hàm bạn sẽ hiểu mã giả là gì !

Một đoạn mã giả của thuật toán giải phương trình bậc hai:

ifdelta > 0 thenbegin

13

Page 14: Lt giao trinh nhap mon lap trinh c 2015_02_26

x1 = (-b-sqrt(delta))/(2*a)

x2 = (-b+sqrt(delta))/(2*a)

xuất kết quả: phương trình có hai nghiệm là x1 và x2

end else

ifdelta = 0 thenxuất kết quả: phương trình có nghiệm kép là

-b/(2*a)

else {trường hợp delta < 0 }xuất kết quả: phương trình vô nghiệm

1.3. Các bước xây dựng chương trình

Bước 1: Phân tích vấn đề và xác định các đặc điểm. (xác định I-P-O)

Bước 2: Lập ra giải pháp. (đưa ra thuật giải)

Bước 3: Cài đặt. (viết chương trình)

Bước 4: Chạy thử chương trình. (dịch chương trình)

Bước 5: Kiểm chứng và hoàn thiện chương trình. (thử nghiệm bằng nhiều số liệu và

đánh giá)

1.4. Hệ đếm và biểu diễn số trong hệ đếm

1.4.1. Hệ đếm

Hệ đếm là tập hợp các ký hiệu và qui tắc sử dụng tập ký hiệu đó để biểu diễn và

xác định các giá trị các số. Mỗi hệ đếm có một số ký số hữu hạn. Tổng số ký số của

mỗi hệ đếm được gọi là cơ số (base hay radix), ký hiệu là b.

Trong ngành toán - tin học hiện nay phổ biến 4 hệ đếm như sau:

Hệ đếm Cơ số Ký số và trị tuyệt đối

Hệ nhị phân

Hệ bát phân

Hệ thập phân

Hệ thập lục phân

2

8

10

16

0, 1

0, 1, 2, 3, 4, 5, 6, 7

0, 1, 2, 3, 4, 5, 6, 7, 8, 9

0, 1, 2, 3, 4, 5, 6, 7, 8, 9, A, B, C, D, E, F  

14

Page 15: Lt giao trinh nhap mon lap trinh c 2015_02_26

Hệ đếm phổ biến hiện nay là hệ đếm thập phân.

1.4.2. Biểu diễn số trong các hệ đếm

1.4.2.1. Hệ đếm thập phân (decimal system)

Hệ đếm thập phân hay hệ đếm cơ số 10 là một trong những phát minh của người

Ả rập cổ, bao gồm 10 ký số theo ký hiệu sau:

0, 1, 2, 3, 4, 5, 6, 7, 8, 9

Qui tắc tính giá trị của hệ đếm này là mỗi đơn vị ở một hàng bất kỳ có giá trị

bằng 10 đơn vị của hàng kế cận bên phải. Ở đây b = 10. Bất kỳ số nguyên dương trong

hệ thập phân có thể thể hiện như là một tổng các chuỗi các ký số thập phân nhân cho

10 lũy thừa, trong đó số mũ lũy thừa được tăng thêm 1 đơn vị kể từ số mũ lũy thừa

phía bên phải nó. Số mũ lũy thừa của hàng đơn vị trong hệ thập phân là 0.

Ví dụ 1.5:Số 2165 có thể được thể hiện như sau:

2165 = 2 x 103 + 1 x 102 + 6 x 101 + 5 x 100

= 2 x 1000 + 1 x 100 + 6 x 10 + 5 x 1

Thể hiện như trên gọi là ký hiệu mở rộng của số nguyên vì:

2165 = 2000+100 +60+5

Như vậy, trong số 2165: ký số 5 trong số nguyên đại diện cho giá trị 5 đơn vị

(1s), ký số 6 đại diện cho giá trị 6 chục (10s), ký số 1 đại diện cho giá trị 1 trăm (100s)

và ký số 2 đại diện cho giá trị 2 nghìn (1000s). Nghĩa là, số lũy thừa của 10 tăng dần 1

đơn vị từ trái sang phải tương ứng với vị trí ký hiệu số,

100 = 1 101 = 10 102 = 100 103 = 1000 104 = 10000 ...

Mỗi ký số ở thứ tự khác nhau trong số sẽ có giá trị khác nhau, ta gọi là giá trị vị

trí (place value).

Phần phân số trong hệ thập phân sau dấu chấm phân cách (theo qui ước của Mỹ)

thể hiện trong ký hiệu mở rộng bởi 10 lũy thừa âm tính từ phải sang trái kể từ dấu

chấm phân cách:  

15

Page 16: Lt giao trinh nhap mon lap trinh c 2015_02_26

Ví dụ 1.6:

2165.37 = 2 x 103 + 1 x 102 + 6 x 101 + 5 x 100 + 3 x 10-1+ 7 x 10-2

= 2 x 1000 + 1 x 100 + 6 x 10 + 5 x 1 +3 x 1

10 + 7 x 1

100

= 2000 + 100 + 60 + 5 + 3

10 + 7

100

Tổng quát, hệ đếm cơ số b (b≥2, b là số nguyên dương) mang tính chất sau:

Có b ký số để thể hiện giá trị số. Ký số nhỏ nhất là 0 và lớn nhất là b-1.

· Giá trị vị trí thứ n trong một số của hệ đếm bằng cơ số b lũy thừa n : b

Số N(b) trong hệ đếm cơ số (b) thể hiện :

N(b)= anan-1an-2 ...a1a0a-1a-2 ...a-m

trong đó, số N(b) có n+1 ký số ở phần nguyên và m ký số ở phần thập phân, sẽ

có giá trị là :  

N(b)= an x bn + an-1xbn-1 + an-2x bn-2...a1 x b1+ a0 x b0+a-1 x b-1 + a-2 x b-2 ...a-m x b-m

Hay: N(b)=∑

i=−m

n

ai bi

1.4.3. Hệ đếm nhị phân (binary number system)

Với b=2, chúng ta có hệ đếm nhị phân. Ðây là hệ đếm đơn giản nhất với 2 chữ số

là 0 và 1. Mỗi chữ số nhị phân gọi là BIT (viết tắt từ chữ BInary digiT). Hệ nhị phân

tương ứng với 2 trạng thái của các linh kiện điện tử trong máy tính chỉ có: đóng (có

điện hay có dòng điện đi qua) ký hiệu là 1 và tắt (không có điện hay không có dòng

điện đi qua) ký hiệu là 0. Vì hệ nhị phân chỉ có 2 trị số là 0 và 1, nên khi muốn diễn tả

một số lớn hơn, hoặc các ký tự phức tạp hơn thì cần kết hợp nhiều bit với nhau.

Ta có thể chuyển đổi hệ nhị phân theo hệ thập phân quen thuộc.

Ví dụ 1.7:Số 1110101 (2) sẽ tương đương với giá trị thập phân là: 117

Số nhị phân 1 1 1 0 1 0 1

16

Page 17: Lt giao trinh nhap mon lap trinh c 2015_02_26

14 2

2

2

7

3

2

0

1

1

0

2

1

Số dư(remainders)

Vị trí 6 5 4 3 2 1 0

Trị vị trí 26 25 24 23 22 21 20

Hệ 10 là 64 32 16 8 4 2 1

Như vậy: 1110101(2) = 1x64 + 1x32 + 1x 16 + 0x8 + 1x4 + 0x2 + 1x1 = 117(10)

1.4.4. Hệ đếm thập lục phân (hexa-decimal number system)

Hệ đếm thập lục phân là hệ cơ số b = 16 =24, tương đương với tập 4 chữ số nhị

phân (4 bit). Khi thể hiện ở dạng hexa-decimal, ta có 16 ký tự gồm 10 chữ số từ 0 đến

9, và 6 chữ in A, B, C, D, E, F để biểu diễn các giá trị số tương ứng là 10, 11, 12, 13,

14, 15. Với hệ thập lục phân, trị vị trí là lũy thừa của 16.

Ví dụ 1.8:

75(16) = 7x161 + 5x160 = 117 (10)

A2B(16)=10x162 + 2x161 + 11x160 = 2603(10)

1.4.5. Đổi một số nguyên từ hệ thập phân sang hệ b

Tổng quát: Lấy số nguyên thập phân N(10) lần lượt chia cho b cho đến khi

thương số bằng 0. Kết quả số chuyển đổi N(b) là các dư số trong phép chia viết ra theo

thứ tự ngược lại.

Ví dụ 1.9:Số 14 trong hệ thập phân sẽ được biểu diễn như thế nào trong hệ nhị

phân (b =2).Dùng phép chia 2 liên tiếp ta có các số dư như sau:

Ta được: 14(10) = 0110(2)

17

Page 18: Lt giao trinh nhap mon lap trinh c 2015_02_26

CHƯƠNG 2. CHƯƠNG 2. CÁC THÀNH PHẦN TRONG NGÔN NGỮCÁC THÀNH PHẦN TRONG NGÔN NGỮ CC

2.1. Các khái niệm cơ bản

2.1.1. Từ khóa

Từ khoá là những từ được sử dụng để khai báo các kiểu dữ liệu, để viết các toán

tử và các câu lệnh. Bảng dưới đây liệt kê các từ khoá của TURBO C:

auto double int struct

break else long switch

case enum register typedef

char extern return union

continue for signed void

do if static while

default goto sizeof volatile

const float short unsigned

Ý nghĩa và cách sử dụng của mỗi từ khoá sẽ được đề cập sau này, ở đây ta cần

Chú ý:

- Không được dùng các từ khoá để đặt tên cho các hằng, biến, mảng, hàm ...

- Từ khoá phải được viết bằng chữ thường, ví dụ: viết từ khoá khai báo kiểu

nguyên là int chứ không phải là INT.

2.1.2. Tên

Tên là một khái niệm rất quan trọng, nó dùng để xác định các đại lượng khác

nhau trong một chương trình. Chúng ta có tên hằng, tên biến, tên mảng, tên hàm, tên

con trỏ, tên tệp, tên cấu trúc, tên nhãn, ...

Tên được đặt theo qui tắc sau:

18

Page 19: Lt giao trinh nhap mon lap trinh c 2015_02_26

Tên là một dãy các ký tự bao gồm chữ cái, số và gạch nối. Ký tự đầu tiên của tên

phải là chữ hoặc gạch nối. Tên không được trùng với khoá. Độ dài cực đại của tên theo

mặc định là 32 và có thể được đặt lại là một trong các giá trị từ 1 tới 32 nhờ chức

năng: Option-Compiler-Source-Identifier length khi dùng TURBO C.

Ví dụ 2.1:

Các tên đúng: a_1 delta x1 _step GAMA

Các tên sai:

3MN Ký tự đầu tiên là số

m#2 Sử dụng ký tự #

f(x) Sử dụng các dấu ()

do Trùng với từ khoá

te ta Sử dụng dấu trắng

Y-3 Sử dụng dấu -

Chú ý:Trong C, tên bằng chữ thường và chữ hoa là khác nhau ví dụ tên AB khác

với ab. Trong C, ta thường dùng chữ hoa để đặt tên cho các hằng và dùng chữ thường

để đặt tên cho hầu hết cho các đại lượng khác như biến, biến mảng, hàm, cấu trúc. Tuy

nhiên đây không phải là điều bắt buộc.

2.1.3. Tập ký tự dùng trong ngôn ngữ C

Mọi ngôn ngữ lập trình đều được xây dựng từ một bộ ký tự nào đó. Các ký tự

được nhóm lại theo nhiều cách khác nhau để tạo nên các từ. Các từ lại được liên kết

với nhau theo một qui tắc nào đó để tạo nên các câu lệnh. Một chương trình bao gồm

nhiều câu lệnh và thể hiện một thuật toán để giải một bài toán nào đó. Ngôn ngữ C

được xây dựng trên bộ ký tự sau:

- 26 chữ cái hoa: A B C .. Z

- 26 chữ cái thường: a b c .. z

- 10 chữ số: 0 1 2 .. 9

- Các ký hiệu toán học: + - * / = ()

- Ký tự gạch nối: _

19

Page 20: Lt giao trinh nhap mon lap trinh c 2015_02_26

- Các ký tự khác: . ,:; [ ] {} ! \ & % # $ ...

Dấu cách (space) dùng để tách các từ. Ví dụ chữ VIET NAM có 8 ký tự, còn

VIETNAM chỉ có 7 ký tự.

Chú ý:

Khi viết chương trình, ta không được sử dụng bất kỳ ký tự nào khác ngoài các ký

tự trên.

Ví dụ như khi lập chương trình giải phương trình bậc hai ax2 +bx+c = 0 , ta cần

tính biệt thức Delta = b2 - 4ac, trong ngôn ngữ C không cho phép dùng ký tự , vì

vậy ta phải dùng ký hiệu khác để thay thế.

2.1.4. Các kiểu dữ liệu cơ sở

Trong C sử dụng các các kiểu dữ liệu sau:

a) Kiểu ký tự(char)

Một giá trị kiểu char chiếm 1 byte (8 bit) và biểu diễn được một ký tự thông qua

bảng mã ASCII. Ví dụ:

Có hai kiểu dữ liệu char: kiểu signed char và unsigned char.

Kiểu Phạm vi biểu diễn Số ký tự Kích thước

Char (Signed char) -128 đến 127 256 1 byte

20

Page 21: Lt giao trinh nhap mon lap trinh c 2015_02_26

Unsigned char 0 đến 255 256 1 byte

Ví dụ sau minh hoạ sự khác nhau giữa hai kiểu dữ liệu trên: Xét đoạn chương

trình sau:

charch1;

unsigned char ch2;

......

ch1 = 200; ch2 = 200;

Khi đó thực chất:

ch1 = -56;

ch2 = 200;

Nhưng cả ch1 và ch2 đều biểu diễn cùng một ký tự có mã 200.

Phân loại ký tự:

Có thể chia 256 ký tự làm ba nhóm:

Nhóm 1: Nhóm các ký tự điều khiển có mã từ 0 đến 31. Chẳng hạn ký tự mã 13

dùng để chuyển con trỏ về đầu dòng, ký tự 10 chuyển con trỏ xuống dòng dưới (trên

cùng một cột). Các ký tự nhóm này nói chung không hiển thị ra màn hình.

Nhóm 2: Nhóm các ký tự văn bản có mã từ 32 đến 126. Các ký tự này có thể

được đưa ra màn hình hoặc máy in.

Nhóm 3: Nhóm các ký tự đồ hoạ có mã số từ 127 đến 255. Các ký tự này có thể

đưa ra màn hình nhưng không in ra được (bằng các lệnh DOS).

b) Kiểu nguyên

Trong C cho phép sử dụng số nguyên kiểu int, số nguyên dài kiểu long và số

nguyên không dấu kiểu unsigned. Kích cỡ và phạm vi biểu diễn của chúng được chỉ ra

trong bảng dưới đây:

Kiểu Phạm vi biểu diễn Kích thước

21

Page 22: Lt giao trinh nhap mon lap trinh c 2015_02_26

int -32768 đến 32767 2 byte

unsigned int 0 đến 65535 2 byte

long -2147483648 đến 2147483647 4 byte

unsigned long 0 đến 4294967295 4 byte

Chú ý:

Kiểu ký tự cũng có thể xem là một dạng của kiểu nguyên.

c) Kiểu dấu phảy động

Trong C cho phép sử dụng ba loại dữ liệu dấu phảy động, đó là float, double và

long double. Kích cỡ và phạm vi biểu diễn của chúng được chỉ ra trong bảng dưới đây:

Kiểu Phạm vi biểu diễn Số chữ số có nghĩa Kích thước

Float 3.4E-38 đến 3.4E+38 7 đến 8 4 byte

Double 1.7E-308 đến 1.7E+308 15 đến 16 8 byte

long double 3.4E-4932 đến 1.1E4932 17 đến 18 10 byte

Giải thích: Máy tính có thể lưu trữ được các số kiểu float có giá trị tuyệt đối từ

3.4E-38 đến 3.4E+38. Các số có giá trị tuyệt đối nhỏ hơn3.4E-38 được xem bằng 0.

Phạm vi biểu diễn của số double được hiểu theo nghĩa tương tự.

d) Định nghĩa kiểu bằng typedef

Công dụng:Từ khoátypedef dùng để đặt tên cho một kiểu dữ liệu. Tên kiểu sẽ

được dùng để khai báo dữ liệu sau này. Nên chọn tên kiểu ngắn và gọn để dễ nhớ. Chỉ

cần thêm từ khoá typedef vào trước một khai báo ta sẽ nhận được một tên kiểu dữ liệu

và có thể dùng tên này để khai báo các biến, mảng, cấu trúc, vv...

Cách viết: Viết từ khoá typedef, sau đó kiểu dữ liệu (một trong các kiểu trên),

rồi đến tên của kiểu.

Ví dụ 2.2:

typedef int nguyen;

sẽ đặt tên một kiểu int là nguyen. Sau này ta có thể dùng kiểu nguyen để khai báo

các biến, các mảng int như ví dụ sau:

22

Page 23: Lt giao trinh nhap mon lap trinh c 2015_02_26

nguyen x, y, a[10], b[20][30];

Tương tự cho các câu lệnh:

typedef float mt50[50];

Đặt tên một kiểu mảng thực một chiều có 50 phần tử tên là mt50.

typedef int m_20_30[20][30];

Đặt tên một kiểu mảng thực hai chiều có 20x30 phần tử tên là m_20_30.

Sau này ta sẽ dùng các kiểu trên khai báo:

mt50 a, b;

m_20_30 x, y;

e) Hằng

Hằng là các đại lượng mà giátrị của nó không thay đổi trong quá trình tính toán.

Tên hằng:

Để đặt tên một hằng, ta dùng dòng lệnh sau:

#define tên hằng giá trị

Ví dụ 2.3:

#define MAX 1000

Lúc này, tất cả các tên MAX trong chương trình xuất hiện sau này đều được thay

bằng 1000. Vì vậy, ta thường gọi MAX là tên hằng, nó biểu diễn số 1000.

Một ví dụ khác:

#define pi 3.141593

Đặt tên cho một hằng float là pi có giá trị là 3.141593.

Các loại hằng:

- Hằng int:Hằng int là số nguyên có giá trị trong khoảng từ -32768 đến 32767.

Ví dụ 2.4:

#definenumber1 -50 //Định nghiã hằng int number1 có giá trị là -50

23

Page 24: Lt giao trinh nhap mon lap trinh c 2015_02_26

#definesodem2732 //Định nghiã hằng int sodem có giá trị là 2732

Chú ý:Cần phân biệt hai hằng 5056 và 5056.0: ở đây 5056 là số nguyên còn

5056.0 là hằng thực.

- Hằng long:Hằng long là số nguyên có giá trị trong khoảng từ -2147483648 đến

2147483647.

Hằng long được viết theo cách:

1234L hoặc 1234l

(thêm L hoặc l vào đuôi)

Một số nguyên vượt ra ngoài miền xác định của int cũng được xem là long.

Ví dụ 2.5:

#definesl 8865056L //Định nghiã hằng longsl có giá trị là 8865056

#definesl8865056 //Định nghiã hằng longsl có giá trị là 8865056

- Hằng ký tự:Hằng ký tự là một ký tự riêng biệt được viết trong hai dấu nháy

đơn, ví dụ 'a'.

Giá trị của 'a' chính là mã ASCII của chữ a. Như vậy giá trị của 'a' là 97. Hằng ký

tự có thể tham gia vào các phép toán như mọi số nguyên khác.

Ví dụ 2.6:

'9'-'0' = 57-48 = 9

#definekt 'a' Định nghiã hằng ký tự kt có giá trị là 97

Đối với một vài hằng ký tự đặc biệt ta cần sử dụng cách viết sau (thêm dấu \):

Cách viết Ký tự'\'' ''\"' "'\\' \'\n' \n (chuyển dòng)'\0' \0 (null)'\t' Tab'\b' Backspace

24

Page 25: Lt giao trinh nhap mon lap trinh c 2015_02_26

'\r' CR (về đầu dòng)'\f' LF (sang trang)

Chú ý:

Cần phân biệt hằng ký tự '0' và '\0'. Hằng '0' ứng với chữ số 0 có mã ASCII là 48,

còn hằng '\0' ứng với kýtự \0 (thường gọi là ký tự null) có mã ASCII là 0.

Hằng ký tự thực sự là một số nguyên, vì vậy có thể dùng các số nguyên hệ 10 để

biểu diễn các ký tự, ví dụ lệnh printf("%c%c", 65, 66) sẽ in ra AB.

- Hằng xâu ký tự:Hằng xâu ký tự là một dãy ký tự bất kỳ đặt trong hai dấu nháy

kép.

Ví dụ 2.7:

#define xau1 "Ha noi"

#define xau2 "My name is Giang"

Xâu ký tự được lưu trữ trong máy dưới dạng một bảng có các phần tử là các ký

tự riêng biệt. Trình biên dịch tự động thêm ký tự null \0 vào cuối mỗi xâu (ký tự \0

được xem là dấu hiệu kết thúc của một xâu ký tự).

Chú ý: Cần phân biệt hai hằng 'a' và "a". 'a' là hằng ký tự được lưu trữ trong 1

byte, còn "a" là hằng xâu ký tự được lưu trữ trong 1 mảng hai phần tử: phần tử thứ

nhất chứa chữ a còn phần tử thứ hai chứa \0.

2.1.5. Cấu trúc một chương trình C

Cấu trúc chương trình và hàm là một trong các vấn đề quan trọng của C.

Hàm là một đơn vị độc lập của chương trình. Tính độc lập của hàm thể hiện ở

hai điểm:

- Không cho phép xây dựng một hàm bên trong các hàm khác.

- Mỗi hàm có các biến, mảng .. riêng của nó và chúng chỉ được sử dụng nội bộ

bên trong hàm. Nói cách khác hàm là đơn vị có tính chất khép kín.

Một chương trình bao gồm một hoặc nhiều hàm. Hàm int main() là thành phần

bắt buộc của chương trình. Chương trình bắt đầu thực hiện các câu lệnh đầu tiên của

25

Page 26: Lt giao trinh nhap mon lap trinh c 2015_02_26

hàm int main() và kết thúc khi gặp dấu } cuối cùng của hàm này. Khi chương trình làm

việc, máy có thể chạy từ hàm này sang hàm khác.

Các chương trình C được tổ chức theo mẫu:

.....

hàm 1

.....

hàm 2

.....

.....

hàm n

Bên ngoài các hàm ở các vị trí (.....) là chỗ đặt: các toán tử #include ... (dùng để

khai báo sử dụng các hàm chuẩn), toán tử #define... (dùng để định nghĩa các hằng),

định nghĩa kiểu dữ liệu bằng typedef, khai báo các biến ngoài, mảng ngoài....

Việc truyền dữ liệu và kết quả từ hàm này sang hàm khác được thực hiện theo

một trong hai cách:

- Sử dụng đối của hàm.

- Sử dụng biến ngoài, mảng ngoài ...

Vậy nói tóm lại cấu truc cơ bản của chương trình như sau:

- Các #include

- Các #define

- Khai báo các đối tượng dữ liệu ngoài (biến, mảng, cấu trúc vv..).

- Khai báo nguyên mẫu các hàm.

- Hàm int main().

- Định nghĩa các hàm (hàm main có thể đặt sau hoặc xen vào giữa các hàm khác).

Ví dụ 2.8:Chương trình tính x lũy thừa y rỗi in ra màn hình kết quả:

/* Chương trình Hello */

#include<stdio.h>

26

Page 27: Lt giao trinh nhap mon lap trinh c 2015_02_26

int main()

{

printf("Hello World");

}

Một số qui tắc cần nhớ khi viết chương trình:

- Qui tắc đầu tiên cần nhớ là: Mỗi câu lệnh có thể viết trên một hay nhiều dòng

nhưng phải kết thúc bằng dấu ;

- Qui tắc thứ hai là: Các lời giải thích cần được đặt giữa các dấu /* và */ và có

thể được viết

Trên một dòng

Trên nhiều dòng

Trên phần còn lại của dòng

Qui tắc thứ ba là: Trong chương trình, khi ta sử dụng các hàm chuẩn, ví dụ như

printf(), getch(), ... mà các hàm này lại chứa trong file stdio.h trong thư mục của C, vì

vậy ở đầu chương trình ta phải khai báo sử dụng ;

#include <stdio.h>

- Qui tắc thứ tư là: Một chương trình có thể chỉ có một hàm chính (hàm int

main()) hoặc có thể có thêm vài hàm khác.

2.2. Biểu thức và các phép toán trong C

2.2.1. Biểu thức

Toán hạng có thể xem là một đại lượng có một giá trị nào đó. Toán hạng bao

gồm hằng, biến, phần tử mảng và hàm.

Biểu thức lập nên từ các toán hạng và các phép tính để tạo nên những giá trị mới.

Biểu thức dùng để diễn đạt một công thức, một qui trình tính toán, vì vậy nó là một

thành phần không thể thiếu trong chương trình.

27

Page 28: Lt giao trinh nhap mon lap trinh c 2015_02_26

Biểu thức là một sự kết hợp giữa các phép toán và các toán hạng để diễn đạt một

công thức toán học nào đó. Mỗi biểu thức có sẽ có một giá trị. Như vậy hằng, biến,

phần tử mảng và hàm cũng được xem là biểu thức.

Trong C, ta có hai khái niệm về biểu thức:

- Biểu thức gán

- Biểu thức điều kiện

Biểu thức được phân loại theo kiểu giá trị: nguyên và thực. Trong các mệnh đề

logic, biểu thức được phân thành đúng (giá trị khác 0) và sai (giá trị bằng 0).

Biểu thức thường được dùng trong:

- Vế phải của câu lệnh gán.

- Làm tham số thực sự của hàm.

- Làm chỉ số.

- Trong các toán tử của các cấu trúc điều khiển.

Tới đây, ta đã có hai khái niệm chính tạo nên biểu thức đó là toán hạng và phép

toán. Toán hạng gồm: hằng, biến, phần tử mảng và hàm trước đây ta đã xét. Dưới đây

ta sẽ nói đến các phép toán.

Lệnh gán và biểu thức:

Biểu thức gán là biểu thức có dạng:

v = e

Trong đó v là một biến (hay phần tử mảng), e là một biểu thức. Giá trị của biểu

thức gán là giá trị của e, kiểu của nó là kiểu của v. Nếu đặt dấu ; vào sau biểu thức gán

ta sẽ thu được phép toán gán có dạng:

v = e;

Biểu thức gán có thể sử dụng trong các phép toán và các câu lệnh như các biểu

thức khác. Ví dụ như khi ta viết

a = b = 5;

28

Page 29: Lt giao trinh nhap mon lap trinh c 2015_02_26

thì điều đó có nghĩa là gán giá trị của biểu thức b = 5 cho biến a. Kết qủa là b = 5

và a = 5.

Hoàn toàn tương tự như:

a = b = c = d = 6; gán 6 cho cả a, b, c và d

Ví dụ 2.9:

z = (y = 2) * (x = 6); //Ở đây * là phép toán nhân

gán 2 cho y, 6 cho x và nhân hai biểu thức lại cho ta z = 12.

2.2.2. Các phép toán

a) Các phép toán số học

Các phép toán hai ngôi số học là

Phép toán ý nghĩa Ví dụ

+ Phép cộng a+b

- Phép trừ a-b

* Phép nhân a * b

/ Phép chiaa/b

(Chia số nguyên sẽ chặt phần thập phân)

% Phép lấy phần dưa%b

(Cho phần dư của phép chia a cho b)

Có phép toán một ngôi - ví du -(a+b) sẽ đảo giá trị của phép cộng (a+b).

Ví dụ 2.10:

11/3 = 3

11%3 = 2

-(2+6) = -8

Các phép toán + và - có cùng thứ tự ưu tiên, có thứ tự ưu tiên nhỏ hơn các phép *

, / , % và cả ba phép này lại có thứ tự ưu tiên nhỏ hơn phép trừ một ngôi.

Các phép toán số học được thực hiện từ trái sang phải. Số ưu tiên và khả năng kết

hợp của phép toán được chỉ ra trong một mục sau này

29

Page 30: Lt giao trinh nhap mon lap trinh c 2015_02_26

b) Các phép toán quan hệ và logic

Phép toán quan hệ và logic cho ta giá trị đúng (1) hoặc giá trị sai (0). Nói cách

khác, khi các điều kiện nêu ra là đúng thì ta nhận được giá trị 1, ngược lại ta nhận giá

trị 0.

Các phép toán quan hệ là:

Phép toán ý nghiã Ví dụ

> So sánh lớn hơna>b

4>5 có giá trị 0

>=So sánh lớn hơn hoặc

bằng

a>=b

6>=2 có giá trị 1

< So sánh nhỏ hơna<b

6<=7 có giá trị 1

<=So sánh nhỏ hơn hoặc

bằng

a<=b

8<=5 có giá trị 0

== So sánh bằng nhaua==b

6==6 có giá trị 1

!= So sánh khác nhaua!=b

9!=9 có giá trị 0

Bốn phép toán đầu có cùng số ưu tiên, hai phép sau có cùng số thứ tự ưu tiên

nhưng thấp hơn số thứ tự của bốn phép đầu.

Các phép toán quan hệ có số thứ tự ưu tiên thấp hơn so với các phép toán số học,

cho nên biểu thức:i<n-1 đượchiểu là i<(n-1).

Các phép toán logic:

Phép phủ định một ngôi !

a !a

khác 0 0

bằng 0 1

30

Page 31: Lt giao trinh nhap mon lap trinh c 2015_02_26

Phép và (AND) &&, phép hoặc (OR) ||

a b a&&b a||b

khác 0 khác 0 1 1

khác 0 bằng 0 0 1

bằng 0 khác 0 0 1

bằng 0 bằng 0 0 0

Các phép quan hệ có số ưu tiên nhỏ hơn so với ! nhưng lớn hơn so với && và ||,

vì vậy biểu thức như:(a<b)&&(c>d) có thể viết lại thành:a<b&&c>d

Chú ý:Cả a và b có thể là nguyên hoặc thực.

c) Phép toán tăng giảm

C đưa ra hai phép toán một ngôi để tăng và giảm các biến (nguyên và thực). Toán

tử tăng là ++ sẽ cộng 1 vào toán hạng của nó, toán tử giảm -- thì sẽ trừ toán hạng đi 1.

Ví dụ 2.11:

n = 5

++n //Cho tan = 6

--n //Cho tan = 4

Ta có thể viết phép toán ++ và -- trước hoặc sau toán hạng như sau: ++n, n++, --

n, n--.

Sự khác nhau của ++n và n++ ở chỗ: trong phép n++ thì tăng sau khi giá trị của

nó đã được sử dụng, còn trong phép ++n thì n được tăng trước khi sử dụng. Sự khác

nhau giữa n-- và --n cũng như vậy.

Ví dụ 2.12:

n = 5

x = ++n //Cho tax = 6 và n = 6

x = n++ //Cho tax = 5 và n = 6

d) Thứ tự ưu tiên các phép toán:

31

Page 32: Lt giao trinh nhap mon lap trinh c 2015_02_26

Các phép toán có độ ưu tiên khác nhau, điều này có ý nghĩa trong cùng một biểu

thức sẽ có một số phép toán này được thực hiện trước một số phép toán khác.

Thứ tự ưu tiên của các phép toán được trình bày trong bảng sau:

TT Phép toán Trình tự kết hợp

1 () [] -> Trái qua phải

2 ! ~ & * - ++ -- (type) sizeof Phải qua trái

3 * (phép nhân) / % Trái qua phải

4 + - Trái qua phải

5 <<>> Trái qua phải

6 <<= >>= Trái qua phải

7 == != Trái qua phải

8 & Trái qua phải

9 ^ Trái qua phải

10 | Trái qua phải

11 && Trái qua phải

12 || Trái qua phải

13 ?: Phải qua trái

14 = + = - = * = / = % = <<= >>= & = ^ = | = Phải qua trái

15 , Trái qua phải

Chú thích:

- Các phép toán tên một dòng có cùng thứ tự ưu tiên, các phép toán ở hàng trên

có số ưu tiên cao hơn các số ở hàng dưới.

- Đối vớicác phép toán cùng mức ưu tiên thì trình tự tính toán có thể từ trái qua

phải hay ngược lại được chỉ ra trong cột trình tự kết hợp.

Ví dụ 2.13:

*--px = *(--px) (Phải qua trái)

8/4*6 = (8/4)*6 (Trái qua phải)

Nên dùng các dấu ngoặc tròn để viết biểu thức một cách chính xác.

32

Page 33: Lt giao trinh nhap mon lap trinh c 2015_02_26

Các phép toán lạ:

Dòng 1:

- [ ] Dùng để biểu diễn phần tử mảng, ví dụ:a[i][j]

- . Dùng để biểu diễn thành phần cấu trúc, ví dụ: ht.ten

- -> Dùng để biểu diễn thành phần cấu trúc thông qua con trỏ

Dòng 2:

- * Dùng để khai báo con trỏ, ví dụ: int *a

- & Phép toán lấy địa chỉ, ví dụ: &x

- (type) là phép chuyển đổi kiểu, ví dụ: (float)(x+y)

Dòng 15:Toán tử , thường dùng để viết một dãy biểu thức trong toán tử for.

e) Chuyển đổi kiểu giá trị

Việc chuyển đổi kiểu giá trị thường diễn ra một cách tự động trong hai trường

hợp sau:

Khi gán biểu thức gồm các toán hạng khác kiểu.

Khi gán một giá trị kiểu này cho một biến (hoặc phần tử mảng) kiểu khác. Điều

này xảy ra trong toán tử gán, trong việc truyền giá trị các tham số thực sự cho các đối.

Ngoài ra, ta có thể chuyển từ một kiểu giá trị sang một kiểu bất kỳ mà ta muốn

bằng phép chuyển sau:

(type)biểu thức

Ví dụ 2.14:

(float) (a+b)

Chuyển đổi kiểu trong biểu thức:

Khi hai toán hạng trong một phép toán có kiểu khác nhau thì kiểu thấp hơn sẽ

được nâng thành kiểu cao hơn trước khi thực hiện phép toán. Kết quả thu được là một

giá trị kiểu cao hơn. Chẳng hạn:

- Giữa int và long thì int chuyển thành long.

33

Page 34: Lt giao trinh nhap mon lap trinh c 2015_02_26

- Giữa int và float thì int chuyển thành float.

- Giữa float và double thì float chuyển thành double.

Ví dụ 2.15:

1.5*(11/3) = 4.5

1.5*11/3 = 5.5

(11/3)*1.5 = 4.5

Chuyển đổi kiểu thông qua phép gán:

Giá trị của vế phải được chuyển sang kiểu vế trái đó là kiểu của kết quả. Kiểu int

có thể được được chuyển thành float. Kiểu float có thể chuyển thành int do chặt đi

phần thập phân.Kiểu double chuyển thành float bằng cách làm tròn. Kiểu long được

chuyển thành int bằng cách cắt bỏ một vài chữ số.

Ví dụ 2.16:

int n;

n = 15.6 giá trị của n là 15

Đổi kiểu dạng (type)biểu thức:

Theo cách này, kiểu của biểu thức được đổi thành kiểu type theo nguyên tắc trên.

Ví dụ 2.17:

Phép toán: (int)a

Cho một giá trị kiểu int. Nếu a là float thì ở đây có sự chuyển đổi từ float sang

int. Chú ý rằng bản thân kiểu của a vẫn không bị thay đổi. Nói cách khác, a vẫn có

kiểu float nhưng (int)a có kiểu int.

Đối với hàm toán học của thư viện chuẩn, thì giá trị của đối và giá trị của hàm

đều có kiểu double, vì vậy để tính căn bậc hai của một biến nguyên n ta phải dùng

phép ép kiểu để chuyển kiểu int sang double như sau:

sqrt((double)n)

Phép ép kiểu có cùng số ưu tiên như các toán tử một ngôi.

34

Page 35: Lt giao trinh nhap mon lap trinh c 2015_02_26

Chú ý:Muốn có giá trị chính xác trong phép chia hai số nguyên cần dùng phép ép

kiểu:

((float)a)/b

Để đổi giá trị thực r sang nguyên, ta dùng:

(int)(r+0.5)

Chú ý thứ tự ưu tiên:

(int)1.4*10 = 1*10 = 10

(int)(1.4*10) = (int)14.0 = 14

2.2.3. Biểu thức điều kiện

Toán tử điều kiện tính toán một biểu thức và trả về một giá trị khác tuỳ thuộc vào

biểu thức đó là đúng hay sai.

Cú pháp:

<điều kiện>?<kết quả 1>: <kết quả 2>

Nếu <Điều kiện> là true thì giá trị trả về sẽ là kết quả 1, nếu không giá trị trả về

là kết quả 1.

7==5?4: 3 //Trả về 3 vì 7 không bằng 5.

7==5+2?4: 3 //Trả về 4 vì 7 bằng 5+2.

5>3?a: b //Trả về a, vì 5 lớn hơn 3.

a>b?a: b //Trả về giá trị lớn hơn, a hoặc b.

2.3. Khai báo biến

2.3.1. Khai báo biến

Mỗi biến cần phải được khai báo trước khi đưa vào sử dụng. Việc khai báo biến

được thực hiện theo mẫu sau:

Kiểu dữ liệu của biếntên biến:

Ví dụ 2.18:

35

Page 36: Lt giao trinh nhap mon lap trinh c 2015_02_26

int a, b, c Khai báo ba biến int là a, b, c

long dai, mn Khai báo hai biến long là dai và mn

char kt1, kt2 Khai báo hai biến ký tự là kt1 và kt2

float x, y Khai báo hai biến float là x và y

double canh1,

canh2Khai báo hai biến double là canh1 và canh2

Biến kiểu int chỉ nhận được các giá trị kiểu int. Các biến khác cũng có ý nghĩa

tương tự. Các biến kiểu char chỉ chứa được một ký tự. Để lưu trữ được một xâu ký tự

cần sử dụng một mảng kiểu char.

Vị trí của khai báo biến:

Các khai báo cần phải được đặt ngay sau dấu { đầu tiên của thân hàm và cần

đứng trước mọi câu lệnh khác. Sau đây là một ví dụ về khai báo biến sai:

(Khái niệm về hàm và cấu trúc chương trình sẽ nghiên cứu sau này)

int main()

{

int a, b, c;

a = 2;

int d; /* Vị trí của khai báo sai */

.....

}

Khởi đầu cho biến:Nếu trong khai báo ngay sau tên biến ta đặt dấu = và một giá

trị nào đó thì đây chính là cách vừa khai báo vừa khởi đầu cho biến.

Ví dụ 2.19:

int a, b = 20, c, d = 40;

float e = -55.2, x = 27.23, y, z, t = 18.98;

36

Page 37: Lt giao trinh nhap mon lap trinh c 2015_02_26

Việc khởi đầu và việc khai báo biến rồi gán giá trị cho nó sau này là hoàn toàn

tương đương.

Lấy địa chỉ của biến:

Mỗi biến được cấp phát một vùng nhớ gồm một số byte liên tiếp. Số hiệu của

byte đầu chính là địa chỉ của biến. Địa chỉ của biến sẽ được sử dụng trong một số hàm

ta sẽ nghiên cứu sau này (ví dụ như hàm scanf).

Để lấy địa chỉ của một biến ta sử dụng phép toán:

& tên biến

2.3.2. Phạm vi của biến

Khi lập trình, bạn phải nắm rõ phạm vi của biến. Nếu khai báo và sử dụng không

đúng, không rõ ràng sẽ dẫn đến sai sót khó kiểm soát được, vì vậy bạn cần phải xác

định đúng vị trí, phạm vi sử dụng biến trước khi sử dụng biến.

- Khai báo biến ngoài (biến toàn cục): Vị trí biến đặt bên ngoài tất cả các hàm,

cấu trúc... Các biến này có ảnh hưởng đến toàn bộ chương trình. Chu trình sống của nó

là bắt đầu chạy chương trình đến lúc kết thúc chương trình.

- Khai báo biến trong (biến cục bộ): Vị trí biến đặt bên trong hàm, cấu trúc….

Chỉ ảnh hưởng nội bộ bên trong hàm, cấu trúc đó…. Chu trình sống của nó bắt đầu từ

lúc hàm, cấu trúc được gọi thực hiện đến lúc thực hiện xong.

2.4. Ghi chú

Trong khi lập trình cần phải ghi chú để giải thích các biến, hằng, thao tác xử lý

giúp cho chương trình rõ ràng dễ hiểu, dễ nhớ, dễ sửa chữa và để người khác đọc vào

dễ hiểu. Trong C có các ghi chú sau: // hoặc /* nội dung ghi chú */

Ví dụ 2.20:

#include <stdio.h>

int main()

{

int a, b; //khai bao bien t kieu int

a = 1; //gan 1 cho a

37

Page 38: Lt giao trinh nhap mon lap trinh c 2015_02_26

b = 3; //gan 3 cho b

/* thuat toan tim so lon nhat la

neu a lon hon b thi a lon nhat

nguoc lai b lon nhat */

if (a > b)

printf("max: %d", a);

else

printf("max: %d", b);

}

Khi biên dịch chương trình, C gặp cặp dấu ghi chú sẽ không dịch ra ngôn ngữ

máy.

Tóm lại, đối với ghi chú dạng // dùng để ghi chú một hàng và dạng /* …. */ có

thể ghi chú một hàng hoặc nhiều hàng.

2.5. Nhập / Xuất dữ liệu trong C

Phần này giới thiệu thư viện vào/ra chuẩn là một tập các hàm được thiết kế để

cung cấp hệ thống vào/ra chuẩn cho các chương trình C. Chúng ta sẽ không mô tả toàn

bộ thư viện vào ra ở đây mà chỉ quan tâm nhiều hơn đến việc nêu ra những điều cơ bản

nhất để viết chương trình C tương tác với môi trường và hệ điều hành.

2.5.1. Hàm printf

Kết xuất dữ liệu được định dạng.

Cú pháp:

printf ("chuỗi định dạng"[, đối mục 1, đối mục 2, …]);

Khi sử dụng hàm phải khai báo tiền xử lý #include <stdio.h>

- printf: tên hàm, phải viết bằng chữ thường.

- đối mục 1, …: là các mục dữ kiện cần in ra màn hình. Các đối mục này có thể

là biến, hằng hoặc biểu thức phải được định trị trước khi in ra.

- chuỗi định dạng: được đặt trong cặp nháy kép (" "), gồm 3 loại:

+ Đối với chuỗi kí tự ghi như thế nào in ra giống như vậy.

38

Page 39: Lt giao trinh nhap mon lap trinh c 2015_02_26

+ Đối với những kí tự chuyển đổi dạng thức cho phép kết xuất giá trị của các đối

mục ra màn hình tạm gọi là mã định dạng. Sau đây là các dấu mô tả định dạng:

%c : Ký tự đơn

%s : Chuỗi

%d : Số nguyên thập phân có dấu

%f : Số chấm động (ký hiệu thập phân)

%e : Số chấm động (ký hiệu có số mũ)

%g : Số chấm động (%f hay %g)

%x : Số nguyên thập phân không dấu

%u : Số nguyên hex không dấu

%o : Số nguyên bát phân không dấu

l : Tiền tố dùng kèm với %d, %u, %x, %o để chỉ số nguyên dài (ví dụ

%ld)

+ Các ký tự điều khiển và ký tự đặc biệt

\n : Nhảy xuống dòng kế tiếp canh về cột đầu tiên.

\t :Canh cột tab ngang.

\r : Nhảy về đầu hàng, không xuống hàng.

\a : Tiếng kêu bip.

\\ : In ra dấu \

\" : In ra dấu "

\' : In ra dấu '

%%: In ra dấu %

Ví dụ 2.21:

39

Page 40: Lt giao trinh nhap mon lap trinh c 2015_02_26

Kết quả in ra màn hình:

Bai hoc C dau tien.

_

printf("Ma dinh dang\\\"in ra dau\".\n");

ký tự điều khiển

ký tự đặc biệt

chuỗi ký tự

Kết quả in ra màn hình

Ma dinh dang \" in ra dau "_

Giả sử biến i có giá trị = 5

Kết quả in ra màn hình

So ban vua nhap la: 5._

Giả sử biến a có giá trị = 7 và b có giá trị = 4

40

Page 41: Lt giao trinh nhap mon lap trinh c 2015_02_26

Kết quả in ra màn hình

Tong cua 2 so 7 va 4 la 11._

Sửa lại Ví dụ

printf("Tong cua 2 so %5d va %3d la %1d . \n", a, b, a+b);

Bề rộng trường

Kết quả in ra màn hình

2.5.2. Hàm scanf

Cú pháp:

scanf ("chuỗi định dạng"[, đối mục 1, đối mục 2, …]);

Khi sử dụng hàm phải khai báo tiền xử lý #include <stdio.h>

- scanf: tên hàm, phải viết bằng chữ thường.

- khung định dạng: được đặt trong cặp nháy kép (" ") là hình ảnh dạng dữ liệu

nhập vào.

- Đối mục 1, …: là danh sách các đối mục cách nhau bởi dấu phẩy, mỗi đối mục

sẽ tiếp nhận giá trị nhập vào.

41

Page 42: Lt giao trinh nhap mon lap trinh c 2015_02_26

Ví dụ 2.22:

scanf("%d", &i);

đối mục 1

mã định dạng

Nhập vào 12abc, biến i chỉ nhận giá trị 12. Nhập 3.4 chỉ nhận giá trị 3.

scanf("%d%d", &a, &b);

Nhập vào 2 số a, b phải cách nhau bằng khoảng trắng hoặc enter.

scanf("%d/%d/%d", &ngay, &thang, &nam);

Nhập vào ngày, tháng, năm theo dạng ngay/thang/nam (20/12/2002)

Ví dụ 2.23: scanf("%d%*c%d%*c%d", &ngay, &thang, &nam);

Nhập vào ngày, tháng, năm với dấu phân cách /, -, …; ngoại trừ số.

scanf("%2d%2d%4d", &ngay, &thang, &nam);

Nhập vào ngày, tháng, năm theo dạng dd/mm/yyyy.

42

Page 43: Lt giao trinh nhap mon lap trinh c 2015_02_26

CHƯƠNG 3. CHƯƠNG 3. CÁC CẤU TRÚC ĐIỀU KHIỂNCÁC CẤU TRÚC ĐIỀU KHIỂN

Một chương trình bao gồm nhiều câu lệnh. Thông thường các câu lệnh được thực

hiện một cách lần lượt theo thứ tự mà chúng được viết ra. Các cấu trúc điều khiển cho

phép thay đổi trật tự nói trên, do đó máy có thể nhảy thực hiện một câu lệnh khác ở

một ví trí trước hoặc sau câu lệnh hiện thời.

Xét về mặt công dụng, có thể chia các cấu trúc điều khiển thành các nhóm chính:

Nhảy không có điều kiện.

Rẽ nhánh.

Tổ chức chu trình.

Ngoài ra còn một số toán tử khác có chức năng bổ trợ như break, continue.

3.1. Cấu trúc rẽ nhánh

3.1.1. Cấu trúc if-else

Toán tử if cho phép lựa chọn chạy theo một trong hai nhánh tuỳ thuộc vào sự

bằng không và khác không của biểu thức. Nó có hai cách viết sau:

if (biểu thức)

khối lệnh 1;

/* Dạng một */

if (biểu thức)

khối lệnh 1;

else

khối lệnh 2 ;

/* Dạng hai */

Hoạt động của biểu thức dạng 1:Máy tính giá trị của biểu thức. Nếu biểu thức

đúng (biểu thức có giá trị khác 0) máy sẽ thực hiện khối lệnh 1 và sau đó sẽ thực hiện

các lệnh tiếp sau lệnh if trong chương trình. Nếu biểu thức sai (biểu thức có giá trị

bằng 0) thì máy bỏ qua khối lệnh 1 mà thực hiện ngay các lệnh tiếp sau lệnh if trong

chương trình.

43

Page 44: Lt giao trinh nhap mon lap trinh c 2015_02_26

Hoạt động của biểu thức dạng 2:Máy tính giá trị của biểu thức. Nếu biểu thức

đúng (biểu thức có giá trị khác 0) máy sẽ thực hiện khối lệnh 1 và sau đó sẽ thực hiện

các lệnh tiếp sau khối lệnh 2 trong chương trình. Nếu biểu thức sai (biểu thức có giá trị

bằng 0) thì máy bỏ qua khối lệnh 1 mà thực hiện khối lệnh 2 sau đó thực hiện tiếp các

lệnh tiếp sau khối lệnh 2 trong chương trình.

Ví dụ 3.1: Chương trình nhập vào hai số a và b, tìm max của hai số rồi in kết quả

lên màn hình. Chương trình có thể viết bằng cả hai cách trên như sau:

Cách 1:

#include <stdio.h>

int main()

{

float a, b, max;

printf("\n Cho a = ");

scanf("%f", &a);

printf("\n Cho b = ");

scanf("%f", &b);

max = a;

if (b>max) max = b;

printf(" \n Max cua hai so a = %8.2f va b = %8.2f la

Max = %8.2f", a, b, max);

}

Cách 2:

#include <stdio.h>

int main()

{

float a, b, max;

printf("\n Cho a = ");

44

Page 45: Lt giao trinh nhap mon lap trinh c 2015_02_26

scanf("%f", &a);

printf("\n Cho b = ");

scanf("%f", &b);

if (a>b) max = a;

else max = b;

printf(" \n Max cua hai so a = %8.2f va b = %8.2f la

Max = %8.2f", a, b, max);

}

Sự lồng nhau của các toán tử if:C cho phép sử dụng các toán tử if lồng nhau có

nghĩa là trong các khối lệnh (1 và 2) ở trên có thể chứa các toán tử if - else khác. Trong

trường hợp này, nếu không sử dụng các dấu đóng mở ngoặc cho các khối thì sẽ có thể

nhầm lẫn giữa các if-else.

Chú ý là máy sẽ gắn toán tử else với toán tử if không có else gần nhất. Chẳng hạn

như đoạn chương trình ví dụ sau:

if (n>0) // if thứ nhất

if (a>b) // if thứ hai

z = a;

else

z = b;

thì else ở đây sẽ đi với if thứ hai.

Đoạn chương trình trên tương đương với:

if (n>0) //if thứ nhất

{

if (a>b) // if thứ hai

z = a;

else

z = b;

45

Page 46: Lt giao trinh nhap mon lap trinh c 2015_02_26

}

Trường hợp ta muốn else đi với if thứ nhất ta viết như sau:

if (n>0) // if thứ nhất

{

if (a>b) // if thứ hai

z = a;

}

else

z = b;

3.1.2. Cấu trúc switch:

Là cấu trúc tạo nhiều nhánh đặc biệt. Nó căn cứ vào giá trị một biểu thức nguyên

để để chọn một trong nhiều cách nhảy.

Cấu trúc tổng quát của nó là:

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 k+1 ]

}

Với 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 giữa các dấu { } gọi là thân của toán tử switch.

default là một thành phần không bắt buộc phải có trong thân của switch.

46

Page 47: Lt giao trinh nhap mon lap trinh c 2015_02_26

Sự hoạt động của toán tử switch phụ thuộc vào giá trị của biểu thức viết trong

dấu ngoặc () như sau:

Khi giá trị của biểu thức này bằng ni, máy sẽ nhảy tới các câu lệnh có nhãn là

case ni.

Khi giá trị biểu thức khác tất cả các ni thì cách làm việc của máy lại phụ thuộc

vào sự có mặt hay không của lệnh default như sau:

Khi có default máy sẽ nhảy tới câu lệnh sau nhãn default.

Khi không có default máy sẽ nhảy ra khỏi cấu trúc switch.

Chú ý:

Máy sẽ nhảy ra khỏi toán tử switch khi nó gặp câu lệnh break hoặc dấu ngoặc

nhọn đóng cuối cùng của thân switch. Ta cũng có thể dùng câu lệnh goto trong thân

của toán tử switch để nhảy tới một câu lệnh bất kỳ bên ngoài switch.

Khi toán tử switch nằm trong thân một hàm nào đó thì ta có thể sử dụng câu lệnh

return trong thân của switch để ra khỏi hàm này (lệnh return sẽ đề cập sau).

Khi máy nhảy tới một câu lệnh nào đó thì sự hoạt động tiếp theo của nó sẽ phụ

thuộc vào các câu lệnh đứng sau câu lệnh này. Như vậy nếu máy nhảy tới câu lệnh có

nhãn case ni thì nó có thể thực hiện tất cả các câu lệnh sau đó cho tới khi nào gặp câu

lệnh break, goto hoặc return. Nói cách khác, máy có thể đi từ nhóm lệnh thuộc case ni

sang nhóm lệnh thuộc case thứ ni+1. Nếu mỗi nhóm lệnh được kết thúc bằng break thì

toán tử switch sẽ thực hiện chỉ một trong các nhóm lệnh này.

Ví dụ 3.2: Lập chương trình phân loại học sinh theo điểm sử dụng cấu trúc

switch:

#include <stdio.h>

int main()

{

int diem;

printf("\nVao du lieu:");

printf("\n Diem = ");

47

Page 48: Lt giao trinh nhap mon lap trinh c 2015_02_26

scanf("%d", &diem);

switch (diem)

{

case 0:

case 1:

case 2:

case 3:

printf("Kem\n");

break;

case 4:

printf("Yeu\n");

break;

case 5:

case 6:

printf("Trung binh\n");

break;

case 7:

case 8:

printf("Kha\n");

break;

case 9:

case 10:

printf("Gioi\n");

break;

default:

printf("Vao sai\n");

}

}

3.2. Cấu trúc lặp

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

Toán tử for dùng để xây dựng cấu trúc lặp có dạng sau:

48

Page 49: Lt giao trinh nhap mon lap trinh c 2015_02_26

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

Lệnh hoặc khối lệnh ;

Toán tử for gồm ba biểu thức và thân for. Thân for là một câu lệnh hoặc một khối

lệnh viết sau từ khoá for. Bất kỳ biểu thức nào trong ba biểu thức trên có thể vắng mặt

nhưng phải giữ dấu ; .

Thông thường biểu thức 1 là toán tử gán để tạo giá trị ban đầu cho biến điều

khiển, biểu thức 2 là một quan hệ logic biểu thị điều kiện để tiếp tục chu trình, biểu

thức ba là một toán tử gán dùng để thay đổi giá trị biến điều khiển.

Hoạt động của toán tử for:

Toán tử for hoạt động theo các bước sau:

Xác định biểu thức 1

Xác định biểu thức 2

Tuỳ thuộc vào tính đúng sai của biểu thức 2 để máy lựa chọn một trong hai

nhánh:

- Nếu biểu thức hai có giá trị 0 (sai), máy sẽ ra khỏi for và chuyển tới câu lệnh

sau thân for.

- Nếu biểu thức hai có giá trị khác 0 (đúng), máy sẽ thực hiện các câu lệnh trong

thân for.

- 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ú ý:Nếu biểu thức 2 vắng mặt thì nó luôn được xem là đúng. Trong trường

hợp này việc ra khỏi chu trình for cần phải được thực hiện nhờ các lệnh break, goto

hoặc return viết trong thân chu trình.

Trong dấu ngoặc tròn sau từ khoá for gồm ba biểu thức phân cách nhau bởi

dấu ; . Trong mỗi biểu thức không những có thể viết một biểu thức mà có quyền viết

một dãy biểu thức phân cách nhau bởi dấu phảy. Khi đó các biểu thức trong mỗi phần

được xác định từ trái sang phải. Tính đúng sai của dãy biểu thức được tính là tính đúng

sai của biểu thức cuối cùng trong dãy này.

49

Page 50: Lt giao trinh nhap mon lap trinh c 2015_02_26

Trong thân của for ta có thể dùng thêm các toán tử for khác, vì thế ta có thể xây

dựng các toán tử for lồng nhau.

Khi gặp câu lệnh break trong thân for, máy ra sẽ ra khỏi toán tử for sâu nhất chứa

câu lệnh này. Trong thân for cũng có thể sử dụng toán tử goto để nhảy đến một ví trí

mong muốn bất kỳ.

Ví dụ 3.3: Nhập một dãy số rồi đảo ngược thứ tự của nó.

#include <stdio.h>

float x[] = {1.3, 2.5, 7.98, 56.9, 7.23};

int n = sizeof(x)/sizeof(float);

int main()

{

int i, j;

float c;

for (i = 0, j = n-1; i<j; ++i, --j)

{

c = x[i]; x[i] = x[j]; x[j] = c;

}

printf("\n Day so dao la \n\n");

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

printf("%8.2f", x[i]);

}

Ví dụ 3.4: Tính tích hai ma trận mxn và nxp.

#include <stdio.h>

float x[3][2], y[2][4], z[3][4], c;

int main()

{

int i, j;

printf("\n nhap gia tri cho ma tran X ");

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

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

50

Page 51: Lt giao trinh nhap mon lap trinh c 2015_02_26

{

printf("\n x[%d][%d] = ", i, j);

scanf("%f", &c);

x[i][j] = c;

}

printf("\n nhap gia tri cho ma tran Y ");

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

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

{

printf("\n y[%d][%d] = ", i, j);

scanf("%f", &c);

y[i][j] = c;

}

}

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

Toán tử while dùng để xây dựng chu trình lặp dạng:

while (biểu thức)

Lệnh hoặc khối lệnh;

Như vậy toán tử while gồm một biểu thức và thân chu trình. Thân chu trình có

thể là một lệnh hoặc một khối lệnh.

Hoạt động của chu trình như sau:

Máy xác định giá trị của biểu thức, tuỳ thuộc giá trị của nó máy sẽ chọn cách

thực hiện như sau:

Nếu biểu thức có giá trị 0 (biểu thức sai), máy sẽ ra khỏi chu trình và chuyển tới

thực hiện câu lệnh tiếp sau chu trình trong chương trình.

Nếu biểu thức có giá trị khác không (biểu thức đúng), máy sẽ thực hiện lệnh hoặc

khối lệnh trong thân của while. Khi máy thực hiện xong khối lệnh này nó lại thực hiện

xác định lại giá trị biểu thức rồi làm tiếp các bước như trên.

Chú ý:

51

Page 52: Lt giao trinh nhap mon lap trinh c 2015_02_26

Trong các dấu ngoặc () sau while chẳng những có thể đặt một biểu thức mà còn

có thể đặt một dãy biểu thức phân cách nhau bởi dấu phảy. Tính đúng sai của dãy biểu

thức được hiểu là tính đúng sai của biểu thức cuối cùng trong dãy.

Bên trong thân của một toán tử while lại có thể sử dụng các toán tử while khác.

bằng cách đó ta đi xây dựng được các chu trình lồng nhau.

Khi gặp câu lệnh break trong thân while, máy sẽ ra khỏi toán tử while sâu nhất

chứa câu lệnh này.

Trong thân while có thể sử dụng toán tử goto để nhảy ra khỏi chu trình đến một

vị trí mong muốn bất kỳ. Ta cũng có thể sử dụng toán tử return trong thân while để ra

khỏi một hàm nào đó.

Ví dụ 3.5:Chương trình tính tích vô hướng của hai véc tơ x và y:

#include <stdio.h>

float x[] = {2, 3.4, 4.6, 21}, y[] = {24, 12.3, 56.8,

32.9};

int main()

{

float s = 0;

int i = -1;

while (++i<4)

s+=x[i]*y[i];

printf("\n Tich vo huong hai vec to x va y la:%8.2f",

s);

}

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

Khác với các toán tử while và for, việc kiểm tra điều kiện kết thúc đặt ở đầu chu

trình, trong chu trình 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.

52

Page 53: Lt giao trinh nhap mon lap trinh c 2015_02_26

Chu trình do while có dạng sau:

do

Lệnh hoặc khối lệnh;

while (biểu thức);

Lệnh hoặc khối lệnh là thân của chu trình có thể là một lệnh riêng lẻ hoặc là một

khối lệnh.

Hoạt động của chu trình như sau:

Máy thực hiện các lệnh trong thân chu trình.

Khi thực hiện xong tất cả các lệnh trong thân của chu trình, máy sẽ xác định giá

trị của biểu thức sau từ khoá while rồi quyết định thực hiện như sau:

Nếu biểu thức đúng (khác 0) máy sẽ thực hiện lặp lại khối lệnh của chu trình lần

thứ hai rồi thực hiện kiểm tra lại biểu thức như trên.

Nếu biểu thức sai (bằng 0) máy sẽ kết thúc chu trình và chuyển tới thực hiện lệnh

đứng sau toán tử while.

Chú ý: Những điều lưu ý với toán tử while ở trên hoàn toàn đúng với do while.

Ví dụ 3.6: Đoạn chương trình xác định phần tử âm đầu tiên trong các phần tử của

mảng x.

#include <stdio.h>

float x[5], c;

int main()

{

int i = 0;

printf("\n nhap gia tri cho ma tran x ");

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

{

printf("\n x[%d] = ", i);

scanf("%f", &c);

53

Page 54: Lt giao trinh nhap mon lap trinh c 2015_02_26

x[i] = c;

}

do

++i;

while (x[i]>=0 && i<=4);

if (i<=4)

printf("\n Phan tu am dau tien = x[%d] = %8.2f",

i, x[i]);

else

printf("\n Mang khong có phan tu am ");

}

3.3. Câu lệnh break, continute

3.3.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ẽ đưa máy ra khỏi chu trình

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ụ 3.7: Biết số nguyên dương n sẽ là số nguyên tố nếu nó không chia hết cho

các số nguyên trong khoảng từ 2 đến căn bậc hai của n. Viết đoạn chương trình đọc

vào số nguyên dương n, xem n có là số nguyên tố.

#include <stdio.h>

#include <math.h>

unsigned int n;

int main()

{

int i, nt = 1;

printf("\n cho n = ");

scanf("%d", &n);

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

if ((n % i)==0)

54

Page 55: Lt giao trinh nhap mon lap trinh c 2015_02_26

{

nt = 0;

break;

}

if (nt)

printf("\n %d la so nguyen to", n);

else

printf("\n %d khong la so nguyen to", n);

}

3.3.2. Câu lệnh continue

Trái với câu lệnh break, lệnh 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 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 chứ không áp dụng cho switch.

Ví dụ 3.8: Viết chương trình để từ một nhập một ma trận a sau đó:

- Tính tổng các phần tử dương của a.

- Xác định số phần tử dương của a.

- Tìm cực đại trong các phần tử dương của a.

#include <stdio.h>

float a[3][4];

int main()

{

int i, j, soptd = 0;

float tongduong = 0, cucdai = 0, phu;

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

for (j = 0; i<4; ++j)

{

printf("\n a[%d][%d] = ", i, j);

55

Page 56: Lt giao trinh nhap mon lap trinh c 2015_02_26

scanf("%f", &phu);

a[i][j] = phu;

if (a[i][j]<=0) continue;

tongduong +=a[i][j];

if (cucdai<a[i][j]) cucdai = a[i][j];

++soptd;

}

printf("\n So phan tu duong la: %d", soptd);

printf("\n Tong cac phan tu duong la: %8.2f",

tongduong);

printf("\n Cuc dai phan tu duong la: %8.2f", cucdai);

}

56

Page 57: Lt giao trinh nhap mon lap trinh c 2015_02_26

CHƯƠNG 4. CHƯƠNG 4. HÀM VÀ TRUYỀN THAM SỐHÀM VÀ TRUYỀN THAM SỐ

4.1. Định nghĩa hàm trong C

4.1.1. Khai báo hàm

Hàm là một khối lệnh được thực hiện khi nó được gọi từ một điểm khác của

chương trình.

Cú pháp:

type <tên hàm> ([tham số 1], [tham số 2], ...)

<khối lệnh>;

Trong đó:

- type là kiểu dữ liệu được trả về của hàm.

- <tên hàm>là tên gọi của hàm.

- [tham số i] là các tham số (có nhiều bao nhiêu cũng được tuỳ theo nhu cầu).

Một tham số bao gồm tên kiểu dữ liệu sau đó là tên của tham số giống như khi

khai báo biến (ví dụ int x) và đóng vai trò bên trong hàm như bất kì biến nào khác.

Chúng dùng để truyền tham số cho hàm khi nó được gọi. Các tham số khác nhau được

ngăn cách bởi các dấu phẩy.

- <khối lệnh> là thân của hàm. Nó có thể là một lệnh đơn hay một khối lệnh.

Ví dụ 4.1: Dưới đây là ví dụ đầu tiên về hàm

#include <stdio.h>

int addition(int a, int b)

{

int r;

r = a+b;

return (r);

}

int main()

57

Page 58: Lt giao trinh nhap mon lap trinh c 2015_02_26

{

int z;

z = addition(5, 3);

printf("\n Z = %d", z);

}

Kết quả: z = 8

Chúng ta có thể thấy hàm main bắt đầu bằng việc khai báo biến z kiểu int. Ngay

sau đó là một lời gọi tới hàm addition. Nếu để ý chúng ta sẽ thấy sự tương tự giữa cấu

trúc của lời gọi hàm với khai báo của hàm:

Các tham số có vai trò thật rõ ràng. Bên trong hàm main chúng ta gọi hàm

addition và truyền hai giá trị: 5 và 3 tương ứng với hai tham số int a và int b được khai

báo cho hàm addition.

Vào thời điểm hàm được gọi từ main, quyền điều khiển được chuyển sang cho

hàm addition. Giá trị của c hai tham số (5 và 3) được copy sang hai biến cục bộ int a

và int b bên trong hàm.

Dòng lệnh sau:

return (r);

Kết thúc hàm addition, và trả lại quyền điều khiển cho hàm nào đã gọi nó (main)

và tiếp tục chương trình ở cái điểm mà nó bị ngắt bởi lời gọi đến addition. Nhưng thêm

vào đó, giá trị được dùng với lệnh return (r) chính là giá trị được trả về của hàm.

Giá trị trả về bởi một hàm chính là giá trị của hàm khi nó được tính toán. Vì vậy

biến z sẽ có có giá trị được trả về bởi addition(5, 3), đó là 8.

58

Page 59: Lt giao trinh nhap mon lap trinh c 2015_02_26

4.1.2. Phạm vi hoạt động của các biến

Bạn cần nhớ rằng phạm vi hoạt động của các biến khai báo trong một hàm hay

bất kì một khối lệnh nào khác chỉ là hàm đó hay khối lệnh đó và không thể sử dụng

bên ngoài chúng. Trong chương trình ví dụ trên, bạn không thể sử dụng trực tiếp các

biến a, b hay r trong hàm main vì chúng là các biến cục bộ của hàm addition. Thêm

vào đó bạn cũng không thể sử dụng biến z trực tiếp bên trong hàm addition vì nó làm

biến cục bộ của hàm main.

Tuy nhiên bạn có thể khai báo các biến toàn cục để có thể sử dụng chúng ở bất kì

đâu, bên trong hay bên ngoài bất kì hàm nào. Để làm việc này bạn cần khai báo chúng

bên ngoài mọi hàm hay các khối lệnh, có nghĩa là ngay trong thân chương trình.

Ví dụ 4.2: Đây là một ví dụ khác về hàm:

#include <stdio.h>

int subtraction(int a, int b)

{

int r;

r = a-b;

return (r);

}

int main()

{

int x = 5, y = 3, z;

z = subtraction(7, 2);

printf("\nKet qua 1: %d", z);

printf("\nKet qua 2: %d", subtraction(7, 2));

printf("\nKet qua 3: %d", subtraction(x, y));

z = 4 + subtraction(x, y);

printf("\nKet qua 4: %d", z);

}

Kết quả:

Ket qua 1: 5

59

Page 60: Lt giao trinh nhap mon lap trinh c 2015_02_26

Ket qua 2: 5

Ket qua 3: 2

Ket qua 4: 6

Trong trường hợp này chúng ta tạo ra hàm subtraction. Chức năng của hàm này

là lấy hiệu của hai tham số rồi trả về kết quả.

Tuy nhiên, nếu phân tích hàm main các bạn sẽ thấy chương trình đã vài lần gọi

đến hàm subtraction. Tôi đã sử dụng vài cách gọi khác nhau để các bạn thấy các cách

khác nhau mà một hàm có thể được gọi.

Để có hiểu cặn kẽ ví dụ này bạn cần nhớ rằng một lời gọi đến một hàm có thể

hoàn toàn được thay thế bởi giá trị của nó. Ví dụ trong lệnh gọi hàm đầu tiên:

z = subtraction(7, 2);

printf("Ket qua 1: %d", z);

Nếu chúng ta thay lời gọi hàm bằng giá trị của nó (đó là 5), chúng ta sẽ có:

z = 5;

printf("Ket qua 1: %d", z);

Tương tự như vậy

printf("Ket qua 2: %d", subtraction(7, 2));

Cũng cho kết quả giống như hai dòng lệnh trên nhưng trong trường hợp này

chúng ta gọi hàm subtraction trực tiếp như là một tham số của printf. Chúng ta cũng có

thể viết:

printf("Ket qua 2: %d", 5);

Vì 5 là kết quả của subtraction(7, 2). Còn với lệnh

printf("Ket qua 3: %d", subtraction(x, y));

Điều mới mẻ duy nhất ở đây là các tham số của subtraction là các biến thay vì

các hằng. Điều này là hoàn toàn hợp lệ. Trong trường hợp này giá trị được truyền cho

hàm subtraction là giá trị của x and y.

60

Page 61: Lt giao trinh nhap mon lap trinh c 2015_02_26

Trường hợp thứ tư cũng hoàn toàn tương tự. Thay vì viết

z = 4 + subtraction(x, y);

chúng ta có thể viết:

z = subtraction(x, y) + 4;

Cũng hoàn toàn cho kết quả tương đương.

4.2. Truyền tham số cho hàm

Cho đến nay, trong tất cả các hàm chúng ta đã biết, tất cả các tham số truyền cho

hàm đều được truyền theo giá trị. Điều này có nghĩa là khi chúng ta gọi hàm với các

tham số, những gì chúng ta truyền cho hàm là các giá trị chứ không phải bản thân các

biến. Ví dụ, giả sử chúng ta gọi hàm addition như sau:

int x = 5, y = 3, z;

z = addition(x, y);

Trong trường hợp này khi chúng ta gọi hàm addition thì các giá trị 5 and 3 được

truyền cho hàm, không phải là bản thân các biến.

Đến đây các bạn có thể hỏi tôi: Như vậy thì sao, có ảnh hưởng gì đâu? Điều đáng

nói ở đây là khi các bạn thay đổi giá trị của các biến a hay b bên trong hàm thì các biến

x và y vẫn không thay đổi vì chúng đâu có được truyền cho hàm chỉ có giá trị của

chúng được truyền mà thôi.

Hãy xét trường hợp bạn cần thao tác với một biến ngoài ở bên trong một hàm. Vì

vậy bạn sẽ phải truyền tham số dưới dạng tham số biến như ở trong hàm duplicate

trong ví dụ dưới đây:

Ví dụ 4.3:

#include <stdio.h>

void duplicate (int& a, int& b, int& c)

{

61

Page 62: Lt giao trinh nhap mon lap trinh c 2015_02_26

a*= 2;

b*= 2;

c*= 2;

}

int main()

{

int x = 1, y = 3, z = 7;

duplicate (x, y, z);

printf("x = %d, y = %d, z = %d", x, y, z);

}

Kết quả:

x = 2, y = 6, z = 14

Điều đầu tiên làm bạn chú ý là trong khai báo của duplicate theo sau tên kiểu của

mỗi tham số đều là dấu và (&), để báo hiệu rằng các tham số này được truyền theo

tham số biến chứ không phải tham số giá trị.

Khi truyền tham số dưới dạng tham số biến chúng ta đang truyền bản thân biến

đó và bất kì sự thay đổi nào mà chúng ta thực hiện với tham số đó bên trong hàm sẽ

ảnh hưởng trực tiếp đến biến đó.

Trong ví dụ trên, chúng ta đã liên kết a, b và c với các tham số khi gọi hàm (x, y

và z) và mọi sự thay đổi với a bên trong hàm sẽ ảnh hưởng đến giá trị của x và hoàn

toàn tương tự với b và y, c và z.

Kiểu khai báo tham số theo dạng tham số biến sử dụng dấu và (&) chỉ có trong

C++. Trong ngôn ngữ C chúng ta phải sử dụng con trỏ để làm việc tương tự như thế.

Truyền tham số dưới dạng tham số biến cho phép một hàm trả về nhiều hơn một

giá trị.

Ví dụ 4.4: Đây là một hàm trả về số liền trước và liền sau của tham số đầu tiên.

62

Page 63: Lt giao trinh nhap mon lap trinh c 2015_02_26

#include <stdio.h>

void prevnext (int x, int& prev, int& next)

{

prev = x-1;

next = x+1;

}

int main()

{

int x = 100, y, z;

prevnext (x, y, z);

printf("Previous = %d, Next = %d", y, z);

}

Kết quả

Previous = 99, Next = 101

Giá trị mặc định của tham số

Khi định nghĩa một hàm chúng ta có thể chỉ định những giá trị mặc định sẽ được

truyền cho các đối số trong trường hợp chúng bị bỏ qua khi hàm được gọi. Để làm việc

này đơn giản chỉ cần gán một giá trị cho đối số khi khai báo hàm. Nếu giá trị của tham

số đó vẫn được chỉ định khi gọi hàm thì giá trị mặc định sẽ bị bỏ qua.

Ví dụ 4.5: Giá trị mặc định trong hàm

#include <stdio.h>

int divide(int a, int b = 2)

{

int r;

r = a/b;

return (r);

}

int main()

{

printf("%d", divide(12));

63

Page 64: Lt giao trinh nhap mon lap trinh c 2015_02_26

printf("\n");

printf("%d", divide(20, 4));

}

Kết quả:

6

5

Nhưng chúng ta thấy trong thân chương trình, có hai lời gọi hàm divide. Trong

lệnh đầu tiên:

divide(12)

Chúng ta chỉ dùng một tham số nhưng hàm divide cho phép đến hai. Bởi vậy

hàm divide sẽ tự cho tham số thứ hai giá trị bằng 2 vì đó là giá trị mặc định của nó

(chú ý phần khai báo hàm được kết thúc bởi int b = 2). Vì vậy kết quả sẽ là 6 (12/2).

Trong lệnh thứ hai:

divide(20, 4)

Có hai tham số, bởi vậy giá trị mặc định sẽ được bỏ qua. Kết quả của hàm sẽ là 5

(20/4).

4.3. Một số ví dụ minh họa

Ví dụ 4.6: Gọi hàm

#include <stdio.h>

/* Khai bao ham */

int max(int num1, int num2);

int main ()

{

/* Khai bao bien cuc bo */

int a = 100;

int b = 200;

64

Page 65: Lt giao trinh nhap mon lap trinh c 2015_02_26

int ret;

/* Goi ham tra ve gia tri lon nhat */

ret = max(a, b);

printf( "Max value is : %d\n", ret );

return 0;

}

/* Ham tra ve gia tri lon nhat cua hai so*/

int max(int num1, int num2)

{

/* Khai bao bien cuc bo */

int result;

if (num1 > num2)

result = num1;

else

result = num2;

return result;

}

4.4.

65

Page 66: Lt giao trinh nhap mon lap trinh c 2015_02_26

CHƯƠNG 5. CHƯƠNG 5. CÁC KIỂU DỮ LIỆU CÓ CẤU TRÚCCÁC KIỂU DỮ LIỆU CÓ CẤU TRÚC

5.1. Kiểu dữ liệu mảng

5.1.1. Mảng một chiều

Là tập hợp các phần tử có cùng dữ liệu. Giả sử bạn muốn lưu n số nguyên để tính

trung bình, bạn không thể khai báo n biến để lưu n giá trị rồi sau đó tính trung bình.

Bạn muốn tính trung bình 10 số nguyên nhập vào từ bàn phím, bạn sẽ khai báo

10 biến: a, b, c, d, e, f, g, h, i, j có kiểu int và lập thao tác nhập cho 10 biến này như

sau:

printf("Nhap vao bien a: ");

scanf("%d", &a);

10 biến bạn sẽ thực hiện 2 lệnh trên 10 lần, sau đó tính trung bình:

(a + b + c + d + e + f + g + h + i + j)/10

Điều này chỉ phù hợp với n nhỏ, còn đối với n lớn thì khó có thể thực hiện được.

Vì vậy khái niệm mảng được sử dụng

a) Cách khai báo mảng

Ví dụ 5.1:

int ia[10];

với int là kiểu mảng, ia là tên mảng, 10 số phần tử mảng

Ý nghĩa: Khai báo một mảng số nguyên gồm 10 phần tử, mỗi phần tử có kiểu int.

Mỗi phần tử trong mảng có kiểu int

ia

10 phần tử

66

Page 67: Lt giao trinh nhap mon lap trinh c 2015_02_26

b) Tham chiếu đến từng phần tử mảng

Sau khi mảng được khai báo, mỗi phần tử trong mảng đều có chỉ số để tham

chiếu. Chỉ số bắt đầu từ 0 đến n-1 (với n là kích thước mảng). Trong ví dụ trên, ta khai

báo mảng 10 phần tử thì chỉ số bắt đầu từ 0 đến 9.

ia[2], ia[7]… là phần tử thứ 3, 8… trong mảng xem như là một biến kiểu int.

c) Nhập dữ liệu cho mảng

Ví dụ 5.2:vòng for có giá trị i chạy từ 0 đến 9

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

{

printf("Nhap vao phan tu thu %d: ", i + 1);

scanf("%d", &ia[i]);

}

d) Đọc dữ liệu từ mảng

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

printf("%3d ", ia[i]);

Ví dụ 5.3: Viết chương trình nhập vào n số nguyên. Tính và in ra trung bình cộng

/* Tinh trung binh cong n so nguyen */

#include <stdio.h>

#include <conio.h>

int main()

{

int ia[50], i, in, isum = 0;

printf("Nhap vao gia tri n: ");

scanf("%d", &in);

67

Page 68: Lt giao trinh nhap mon lap trinh c 2015_02_26

//Nhap du lieu vao mang

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

{

printf("Nhap vao phan tu thu %d: ", i + 1);

scanf("%d", &ia[i]); //Nhap gia tri cho phan

tu thu i

}

//Tinh tong gia tri cac phan tu

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

isum +=ia[i]; //cong don tung phan tu

vao isum

printf("Trung binh cong: %.2f\n", (float) isum/in);

getch();

}

Điều gì sẽ xảy ra cho đoạn chương trình trên nếu bạn nhập n > 50 trong khi bạn

chỉ khai báo mảng ia tối đa là 50 phần tử. Bạn dùng lệnh if để ngăn chặn điều này

trước khi vào thực hiệnlệnh for. Thay dòng 9, 10 bằng đoạn lệnh sau:

do

{

printf("Nhap vao gia tri n: ");

scanf("%d", &in);

} while (in <= 0 || in > 50); //chi chap nhan gia tri

nhap vao trong khoang 1..50

Chạy chương trình và nhập n với các giá trị -6, 0, 51, 6. Quan sát kết quả.

e) Khởi tạo mảng

Ví dụ 5.4: Có 4 loại tiền 1, 5, 10, 25 và 50 đồng. Hãy viết chương trình nhập vào

số tiền sau đó cho biết số số tiền trên gồm mấy loại tiền, mỗi loại bao nhiêu tờ.

68

Page 69: Lt giao trinh nhap mon lap trinh c 2015_02_26

Phác họa lời giải: Số tiền là 246 đồng gồm 4 tờ 50 đồng, 1 tờ 25 đồng, 2 tờ 10

đồng, 0 tờ 5 đồng và 1 tờ 1 đồng, Nghĩa là bạn phải xét loại tiền lớn trước, nếu hết khả

năng mới xét tiếp loại kế tiếp.

/* Nhap vao so tien va doi tien ra cac loai 50, 25, 10, 5,

1 */

#include <stdio.h>

#include <conio.h>

#define MAX 5

int main()

{

int itien[MAX] = {50, 25, 10, 5, 1}; //Khai bao va

khoi tao mang voi 5 phan tu

int i , isotien, ito;

printf("Nhap vao so tien: ");

scanf("%d", &isotien); //Nhap vao so tien

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

{

ito = isotien/itien[i]; //Tim so to cua

loai tien thu i

printf("%4d to %2d dong\n", ito, itien[i]);

//So tien con lai sau khi da loai tru cac loai

tien da co

isotien = isotien%itien[i];

}

getch();

}

Điều gì sẽ xảy nếu số phần tử mảng lớn hơn số mục, số phần tử dôi ra không

được khởi tạo sẽ điền vào số 0. Nếu số phần tử nhỏ hơn số mục khởi tạo trình biên

dịch sẽ báo lỗi.

69

Page 70: Lt giao trinh nhap mon lap trinh c 2015_02_26

int itien[5] = {50, 25}, phần tử itien[0] sẽ có giá trị 50, itien[1] có giá trị 25,

itien[2], itien[3], itien[4] có giá trị 0.

int itien[3] = {50, 25, 10, 5, 1} trình biên dịch báo lỗi

Khởi tạo mảng không bao hàm kích thước:Trong ví dụ trên giả sử ta khai báo

int itien[] = {50, 25, 10, 5, 1}. Khi đó trình biên dịch sẽ đếm số mục trong danh sách

khởi tạo và dùng con số đó làm kích thước mảng.

5.1.2. Mảng hai chiều

a) Tham chiếu đến từng phần tử mảng 2 chiều

Sau khi được khai báo, mỗi phần tử trong mảng 2 chiều đều có 2 chỉ số để tham

chiếu, chỉ số hàng và chỉ số cột. Chỉ số hàng bắt đầu từ 0 đến số hàng – 1 và chỉ số cột

bắt đầu từ 0 đến số cột – 1. Tham chiếu đến một phần tử trong mảng 2 chiều ia: ia[chỉ

số hàng][chỉ số cột]

70

Page 71: Lt giao trinh nhap mon lap trinh c 2015_02_26

ia[3][2] là phần tử tại hàng 3 cột 2 trong mảng 2 chiều xem như là một biến kiểu

int.

b) Nhập dữ liệu cho mảng 2 chiều

Ví dụ 5.5: Nhập mảng hai chiều

for (i = 0; i < 5; i++) //vòng for có giá trị i chạy

từ 0 đến 4 cho hàng

for (j = 0; j < 10; j++) //vòng for có giá trị j

chạy từ 0 đến 9 cho cột

{

printf("Nhap vao phan tu ia[%d][%d]: ", i + 1, j

+ 1);

scanf("%d", &ia[i][j]);

}

c) Đọc dữ liệu từ mảng 2 chiều

Ví dụ 5.6: in giá trị các phần tử mảng 2 chiều ra màn hình.

for (i = 0; i < 5; i++) //vòng for có giá trị i chạy

từ 0 đến 4 cho hàng

{

for (j = 0; j< 10; j++)//vòng for có giá trị j chạy

từ 0 đến 9 cho cột

printf("%3d ", ia[i][j]);

printf("\n"); //xuống dòng để in hàng kế tiếp

}

Ví dụ 5.7: Viết chương trình nhập vào 1 ma trận số nguyên n x n. In ra ma trận

vừa nhập vào và ma trận theo thứ tự ngược lại.

/* Tinh trung binh cong n so nguyen */

#include <stdio.h>

#include <conio.h>

#define MAX 50

71

Page 72: Lt giao trinh nhap mon lap trinh c 2015_02_26

int main()

{

int ia[MAX][MAX], i, j, in;

printf("Nhap vao cap ma tran: ");

scanf("%d", &in);

//Nhap du lieu vao ma tran

for (i = 0; i < in; i++) //vòng for có giá trị i

chạy từ 0 đến in-1 cho hàng

for (j = 0; j< in; j++) //vòng for có giá trị j

chạy từ 0 đến in-1 cho cột

{

printf("Nhap vao phan tu ia[%d][%d]: ", i +

1, j + 1);

scanf("%d", &ia[i][j]);

}

//In ma tran

//Vòng for có giá trị i chạy từ 0 đến in-1 cho hàng

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

{

//vòng for có giá trị j chạy từ 0 đến in-1 cho

cột

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

printf("%3d ", ia[i][j]);

printf("\n"); //xuống dòng để in hàng

kế tiếp

}

printf("\n"); //Tao khoang cach giua 2 ma

tran

72

Page 73: Lt giao trinh nhap mon lap trinh c 2015_02_26

//In ma tran theo thu tu nguoc

for (i = in-1; i >= 0; i--) //vòng for có giá trị i

chạy từ in-1 đến 0 cho hàng

{

//vòng for có giá trị j chạy từ in-1 đến 0 cho

cột

for (j = in-1; j>= 0; j--)

printf("%3d ", ia[i][j]);

printf("\n"); //xuống dòng để in hàng kế

tiếp

}

getch();

}

d) Khởi tạo mảng 2 chiều

Ví dụ 5.8: Khởi tạo mảng hai chiều

/* Chuong trinh ve chu H lon */

#include <stdio.h>

#include <conio.h>

#define MAX 5

int H[MAX][MAX] = {{1, 0, 0, 0, 1},

{1, 0, 0, 0, 1},

{1, 1, 1, 1, 1},

{1, 0, 0, 0, 1},

{1, 0, 0, 0, 1}};

int main()

{

int i , j;

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

{

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

73

Page 74: Lt giao trinh nhap mon lap trinh c 2015_02_26

if (H[i][j])

printf("!");

else

printf(" ");

printf("\n");

}

getch();

}

e) Dùng mảng 1 chiều làm tham số cho hàm

Ví dụ 5.9: Dùng mảng 1 hiều làm tham số cho hàm

/* Chuong trinh tim so lon nhat su dung ham */

#include <stdio.h>

#include <conio.h>

#define MAX 20

//Khai bao prototype

int max(int, int);

//Ham tim so lon nhat trong mang 1 chieu

int max(int ia[], int in)

{

int i, imax;

imax = ia[0]; //cho phan tu dau tien la max

for (i = 1; i < in; i++)

if (imax < ia[i]) //neu so dang xet >

max

imax = ia[i]; //gan so nay cho

max

return imax; //tra ve ket qua so

lon nhat

}

int main()

74

Page 75: Lt giao trinh nhap mon lap trinh c 2015_02_26

{

int ia[MAX];

int i = 0, inum;

do

{

printf("Nhap vao mot so: ");

scanf("%d", &ia[i]);

} while (ia[i++] != 0);

i--;

inum = max(ia, i);

printf("So lon nhat la: %d.\n", inum);

getch();

}

Giải thích chương trình:

Chương trình ban đầu hàm max có hai tham số truyền vào và kết quả trả về là giá

trị max có kiểu nguyên, một tham số là mảng 1 chiều kiểu int và một tham số có kiểu

int. Với chương trình sau khi sửa hàm max chỉ còn một tham số truyền vào nhưng cho

kết quả như nhau. Do sau khi sửa chương trình mảng a[MAX] được khai báo lại là

biến toàn cục nên hàm max không cần truyền tham số mảng vào cũng có thể sử dụng

được. Tuy vậy, khi lập trình bạn nên viết như chương trình ban đầu là truyền tham số

mảng vào (dạng tổng quát) để hàm max có thể thực hiện được trên nhiều mảng khác

nhau. Còn với chương trình sửa lại bạn chỉ sử dụng hàm max được với mảng a mà

thôi.

Bạn khai báo các mảng sau ia[MAX], ib[MAX], ic[MAX]. Để tìm giá trị lớn

nhất của từng mảng. Bạn chỉ cần gọi hàm

- imax_a = max(ia, i);

- imax_b = max(ib, i);

- imax_c = max(ic, i);

Với chương trình sửa lại bạn không thể tìm được số lớn nhất của mảng b và c.

75

Page 76: Lt giao trinh nhap mon lap trinh c 2015_02_26

Bạn lưu ý rằng khi truyền mảng sang hàm, không tạo bản sao mảng mới. Vì vậy

mảng truyền sang hàm có dạng tham biến. Nghĩa là giá trị của các phần tử trong mảng

sẽ bị ảnh hưởng nếu có sự thay đổi trên chúng.

Ví dụ 5.10: Tìm số lớn nhất của 3 mảng a, b, c

/* Chuong trinh tim so lon nhat su dung ham */

#include <stdio.h>

#include <conio.h>

#define MAX 20

//Khai bao prototype

int max(int, int);

int input(int);

//Ham tim phan tu lon nhat trong mang 1 chieu

int max(int ia[], int in)

{

int i, imax;

imax = ia[0]; //cho phan tu dau tien la

max

for (i = 1; i < in; i++)

if (imax < ia[i]) //neu so dang xet > max

imax = ia[i]; //gan so nay cho max

return imax; //tra ve ket qua so lon nhat

}

//Ham nhap lieu vao mang 1 chieu

int input(int ia[])

{

int i = 0;

do

{

printf("Nhap vao mot so: ");

scanf("%d", &ia[i]);

76

Page 77: Lt giao trinh nhap mon lap trinh c 2015_02_26

} while (ia[i++] != 0);

i--;

return i;

}

int main()

{

int ia[MAX], ib[MAX], ic[MAX];

int inum1, inum2, inum3;

printf("Nhap lieu cho mang a: \n");

inum1 = max(ia, input(ia));

printf("Nhap lieu cho mang b: \n");

inum2 = max(ib, input(ib));

printf("Nhap lieu cho mang c: \n");

inum3 = max(ic, input(ic));

printf("So lon nhat cua mang a: %d, b: %d, c: %d.\n",

inum1, inum2, inum3);

getch();

}

Hàm input có kiểu trả về là int thông qua biến i (cho biết số lượng phần tử đã

nhập vào) và 1 tham số là mảng 1 chiều kiểu int. Dòng 41, 43, 45 lần lượt gọi hàm

input với các tham số là mảng a, b, c. Khi hàm input thực hiện việc nhập liệu thì các

phần tử trong mảng cũng được cập nhật theo.

f) Dùng mảng 2 chiều làm tham số cho hàm

Ví dụ 5.11: Nhập vào 2 ma trận vuông cấp n số thập phân. Cộng 2 ma trận này

lưu vào ma trận thứ 3 và tìm số lớn nhất trên ma trận thứ 3.

/* Cong ma tran */

#include <stdio.h>

#include <conio.h>

#define MAX 20

77

Page 78: Lt giao trinh nhap mon lap trinh c 2015_02_26

//Khai bao prototype

void input(float);

void output(float);

void add(float, float, float);

float max(float);

//Khai bao bien toan cuc

int in;

//Ham tim so lon nhat trong mang 2 chieu

float max(float fa[][MAX])

{

float fmax;

fmax = fa[0][0]; //cho phan tu dau tien la max

for (int i = 0; i < in; i++)

for (int j = 0; j< in; j++)

if (fmax < fa[i][j]) //neu so

dang xet > max

fmax = fa[i][j]; //gan so nay cho

max

return fmax; //tra ve ket qua

so lon nhat

}

//Ham nhap lieu mang 2 chieu

void input(float fa[][MAX])

{

float tg;

for (int i = 0; i < in; i++)

for (int j = 0; j< in; j++)

{

printf("Nhap vao ptu[%d][%d]: ", i, j);

scanf("%f", &fa[i,j]);

78

Page 79: Lt giao trinh nhap mon lap trinh c 2015_02_26

}

}

//Ham in mang 2 chieu ra man hinh

void output(float fa[][MAX])

{

for (int i = 0; i < in; i++)

{

for (int j = 0; j< in; j++)

printf("%5.2f", fa[i][j]);

printf("\n");

}

}

//Ham cong 2 mang 2 chieu

void add(float fa[][MAX], float fb[][MAX], float fc[]

[MAX])

{

for (int i = 0; i < in; i++)

for (int j = 0; j< in; j++)

fc[i][j] = fa[i][j] + fb[i][j];

}

int main()

{

float fa[MAX][MAX], fb[MAX][MAX], fc[MAX][MAX];

printf("Nhap vao cap ma tran: ");

scanf("%d", &in);

printf("Nhap lieu ma tran a: \n");

input(fa);

printf("Nhap lieu ma tran b: \n");

input(fb);

79

Page 80: Lt giao trinh nhap mon lap trinh c 2015_02_26

printf("Nhap lieu ma tran c: \n");

input(fc);

add(fa, fb, fc);

printf("Ma tran a: \n");

output(fa);

printf("Ma tran b: \n");

output(fb);

printf("Ma tran c: \n");

output(fc);

printf("So lon nhat cua ma tran c la: %5.2f.\n",

max(fc));

getch();

}

Trong chương trình khai báo biến in toàn cục do biến này sử dụng trong suốt quá

trình chạy chương trình. Tham số truyền vào hàm là mảng hai chiều dưới dạng a[]

[MAX] vì hàm không dành chỗ cho mảng, hàm chỉ cần biết số cột để tham khảo đến

các phần tử.

5.2. Chuỗi ký tự

5.2.1. Khái niệm

Chuỗi được xem như là một mảng 1 chiều gồm các phần tử có kiểu char như mẫu

tự, con số và bất cứ ký tự đặc biệt như +, -, *, /, $, #…

Theo quy ước, một chuỗi sẽ được kết thúc bởi ký tự null ('\0': kí tự rỗng).

Ví dụ: chuỗi "Infoworld" được lưu trữ như sau:

Cách khai báo chuỗi:

Ví dụ khai báo chuỗi có tên cname:

80

Page 81: Lt giao trinh nhap mon lap trinh c 2015_02_26

char cname[30];

Ý nghĩa: Khai báo chuỗi cname có chiều dài 30 kí tự. Do chuỗi kết thúc bằng kí

tự null, nên khi bạn khai báo chuỗi có chiều dài 30 kí tự chỉ có thể chứa 29 kí tự.

Ví dụ 5.12: Nhập vào in ra tên

/* Chuong trinh nhap va in ra ten*/

#include <stdio.h>

#include <conio.h>

int main()

{

char cname[30];

printf("Cho biet ten cua ban: ");

scanf("%s", cname);

printf("Chao ban %s\n", cname);

getch();

}

Lưu ý: Không cần sử dụng toán tử địa chỉ & trong cname trong lệnh scanf("%s",

cname), vì bản thân fname đã là địa chỉ.

Dùng hàm scanf để nhập chuỗi có hạn chế như sau: Khi bạn thử lại chương trình

trên với dữ liệu nhập vào là Mai Lan, nhưng khi in ra bạn chỉ nhận được Mai. Vì hàm

scanf nhận vào dữ liệu đến khi gặp khoảng trắng thì kết thúc.

5.2.2. Một số hàm thao tác trên chuỗi ký tự

Ví dụ 5.13: Sử dụng hàm gets, puts phải khai báo #include <stdio.h>

/* Chuong trinh nhap va in ra ten*/

#include <stdio.h>

int main()

{

char cname[30];

puts("Cho biet ten cua ban: ");

gets(cname);

81

Page 82: Lt giao trinh nhap mon lap trinh c 2015_02_26

puts("Chao ban ");

puts(cname);

}

Đối với hàm puts kí tự kết thúc chuỗi null (\0) được thay thế bằng kí tự newline

(\n). Hàm gets và puts chỉ có 1 đối số và không sử dụng dạng thức trong nhập liệu

cũng như xuất ra màn hình.

Khởi tạo chuỗi:

Ví dụ 5.14: Chương trình nhập và in ra tên

#include <stdio.h>

int main()

{

char cname[30];

char chao[] = "Chao ban";

printf("Cho biet ten cua ban: ");

gets(cname);

printf("%s %s.\n", chao, cname);

}

Chiều dài tối đa của chuỗi khởi tạo bằng số kí tự + 1 (kí tự null). Với chuỗi chao

có chiều dài là 9.

Mảng chuỗi:

Ví dụ 5.15: Chơng trình nhập tháng (số) và in tháng (chữ) tương ứng

#include <stdio.h>

int main()

{

char cthang[12][15] = {"January", "February",

"March", "April",

"May", "June", "July", "August",

"September",

"October", "November", "December"};

82

Page 83: Lt giao trinh nhap mon lap trinh c 2015_02_26

int ithang;

printf("Nhap vao thang (1-12): ");

scanf("%d", &ithang);

printf("%s.\n", cthang[ithang-1]);

}

5.2.3. Một số ví dụ minh họa

5.3. Dữ liệu structure

Đối với mảng, chỉ có thể lưu nhiều thông tin có cùng kiểu dữ liệu. Nhưng với

structure ta có thể lưu thông tin như một mảng có nhiều kiểu dữ liệu khác nhau.

5.3.1. Khái niệm

Ví dụ 5.16: khai báo một structure về thông tin nhân viên

Ví dụ trên định nghĩa kiểu dữ liệu mới có tên là struct nhanvien. Mỗi biến kiểu

này gồm 2 phần tử: biến nguyên có tên là manv và biến chuỗi có tên hoten.

5.3.2. Truy xuất đến các thành phần kiểu cấu trúc

5.3.3. Khai báo kiểu cấu trúc

5.3.4. Cách khai báo biến có kiểu structure

struct nhanvien nv; hoặc nhanvien nv;

Khai báo biến nv có kiểu struct nhanvien

Vừa tạo structure nhanvien vừa khai báo biến nv

struct nhanvien

{

83

Page 84: Lt giao trinh nhap mon lap trinh c 2015_02_26

int manv;

char hoten[30];

} nv;

Tham chiếu các phần tử trong structure:

Để tham chiếu đến manv trong nv ta viết như sau: nv.manv (là biến có kiểu int)

Đối với biến khai báo kiểu con trỏ nhanvien *nv thì tham chiếu đến phần tử manv: nv -> manv.

Ví dụ 5.17: Nhập và in danh sách nhân viên.

/* Danh sach nhan vien */

#include <stdio.h>

#include <stdlib.h>

#define MAX 50

int main()

{

struct nhanvien

{

int manv;

char hoten[30];

};

nhanvien snv[MAX];

char ctam[10];

int i, in;

printf("Nhap vao so nhan vien: ");

gets(ctam);

in = atoi(ctam);

84

Page 85: Lt giao trinh nhap mon lap trinh c 2015_02_26

//Nhap danh sach nhan vien

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

{

printf("Nhap vao ma nhan vien thu %d: ", i + 1);

gets(ctam);

snv[i].manv = atoi(ctam);

printf("Nhap vao ho ten: ");

gets(snv[i].hoten);

}

//in danh sach nhan vien

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

printf("%5d %s\n", snv[i].manv, snv[i].hoten);

}

g) Khởi tạo structure

Ví dụ 5.18: Nhập vào bảng số xe, cho biết xe đó đăng kí ở tỉnh nào

/* Xac dinh bien so xe */

#include <stdio.h>

#include <stdlib.h>

#define MAX 6

int main()

{

struct Tinh

{

int ma;

char *ten;

};

Tinh sds[MAX] = {{20, "Thai Nguyen"}, {29, "Ha Noi"},

{22, "Tuyen Quang"}};

char ctam[10];

int i, in;

85

Page 86: Lt giao trinh nhap mon lap trinh c 2015_02_26

printf("Nhap vao bien so xe: ");

gets(ctam);

in = atoi(ctam);

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

if (sds[i].ma == in)

printf("Xe dang ki o tinh %s.\n",

sds[i].ten);

}

h) Structure lồng nhau

Ví dụ 5.19: Danh sách nhân viên

#include <stdio.h>

#include <stdlib.h>

#define MAX 50

int main()

{

struct giacanh

{

char vo_chong[30];

char con;

};

struct nhanvien

{

int manv;

char hoten[30];

giacanh canhan;

};

nhanvien snv[MAX];

char ctam[10];

int i, in;

printf("Nhap vao so nhan vien: ");

86

Page 87: Lt giao trinh nhap mon lap trinh c 2015_02_26

gets(ctam);

in = atoi(ctam);

//Nhap danh sach nhan vien

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

{

printf("Nhap vao ma nhan vien thu %d: ", i + 1);

gets(ctam);

snv[i].manv = atoi(ctam);

printf("Nhap vao ho ten: ");

gets(snv[i].hoten);

printf("Cho biet ten vo (hoac chong): ");

gets(snv[i].canhan.vo_chong);

printf("So con: ");

gets(ctam);

}

//in danh sach nhan vien

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

{

printf("Ma so: %d\nHo ten: %s\n Ho ten vo (hoac

chong): %s\nSo con: %d", snv[i].manv, snv[i].hoten,

snv[i].canhan.vo_chong, snv[i].canhan.con);

}

87

Page 88: Lt giao trinh nhap mon lap trinh c 2015_02_26

CHƯƠNG 6. CHƯƠNG 6. TẬP TINTẬP TIN

6.1. Khái niệm về tệp tin

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 với nhau 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ên tiếng Anh của tệp là file, nó được dùng để chỉ ra một hộp đựng các phiếu

hay thẻ ghi của thư viện. Một hình ảnh rõ nét giúp ta hình dung ra tệp là tủ phiếu của

thư viện. Một hộp có nhiều phiếu giống nhau về hình thức và tổ chức, song lại khác

nhau về nội dung. ở đây, tủ phiếu là tệp, các lá phiếu là các thành phần của tệp. Trong

máy tính, một đĩa cứng hoặc một đĩa mềm đóng vai trò chiếc tủ (để chứa nhiều tệp).

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. Chính vì lý do

trên, chỉ những dữ liệu nào cần lưu trữ (như hồ sơ chẳng hạn) thì ta nên dùng đến tệp.

Tệp là một kiểu dữ liệu có cấu trúc. Định nghĩ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ùng kiểu, song mảng thường có số

phần tử cố định, số phần tử của tệp không được xác định trong định nghĩa.

Trong C, các thao tác tệp được thực hiện nhờ các hàm thư viện. Các hàm này

được chia làm hai nhóm: nhóm 1 và nhóm 2. Các hàm cấp 1 là các hàm nhập / xuất hệ

thống, chúng thực hiện việc đọc ghi như DOS. Các hàm cấp 2 làm việc với tệp thông

qua một biến con trỏ tệp.

Do các hàm cấp 2 có nhiều kiểu truy xuất và dễ dùng hơn so với các hàm cấp 1

nên trong các chương trình viết trong C, các hàm cấp 2 hay được sử dụng hơn.

Một tệp tin dù được xây dựng bằng cách nào đi nữa cũng chỉ đơn giản là một

dãy các byte ghi trên đĩa (có giá trị từ 0 đến 255). Số byte của dãy chính là độ dài của

tệp.

Có hai kiểu nhập xuất dữ liệu lên tệp: Nhập xuất nhị phân và nhập xuất văn bản.

88

Page 89: Lt giao trinh nhap mon lap trinh c 2015_02_26

Nhập xuất nhị phân:

- Dữ liệu ghi lên tệp theo các byte nhị phân như bộ nhớ, trong quá trình nhập

xuất, dữ liệu không bị biến đổi.

- Khi đọc tệp, nếu gặp cuối tệp thì ta nhận được mã kết thúc tệp EOF (được định

nghĩa trong stdio.h bằng -1) và hàm feof cho giá trị khác 0.

Nhập xuất văn bản:

- Kiểu nhập xuất văn bản chỉ khác kiểu nhị phân khi xử lý ký tự chuyển dòng

(mã 10) và ký tự mã 26. Đối với các ký tự khác, hai kiểu đều đọc ghi như nhau.

- Mã chuyển dòng:

Khi ghi, một ký tự LF (mã 10) được chuyển thành 2 ký tự CR (mã 13) và LF

Khi đọc, 2 ký tự liên tiếp CR và LF trên tệp chỉ cho ta một ký tự LF

Mã kết thúc tệp:

Trong khi đọc, nếu gặp ký tự có mã 26 hoặc cuối tệp thì ta nhận được mã kết

thúc tệp EOF (bằng -1) và hàm feof(fp) cho giá trị khác 0 (bằng 1).

6.2. Một số hàm thường dùng khi thao tác trên tệp

6.2.1. Khai báo sử dụng tệp

Để khai báo sử dụng tệp, ta dùng lệnh sau:

FILE biến_con_trỏ_tệp;

Trong đó biến_con_trỏ_tệp có thể là biến đơn hay một danh sách các biến phân

cách nhau bởi dấu phảy ( dấu , ).

Ví dụ 6.1:

FILE *vb, *np; /* Khai báo hai biến con trỏ tệp */

6.2.2. Mở tệp - hàm fopen

Cấu trúc ngữ pháp của hàm:

FILE *fopen(const char *tên_tệp, const char *kiểu);

Nguyên hàm trong: stdio.h

89

Page 90: Lt giao trinh nhap mon lap trinh c 2015_02_26

Trong đó:

Đối thứ nhất là tên tệp, đối thứ hai là kiểu truy nhập.

Công dụng:

Hàm dùng để mở tệp. Nếu thành công hàm cho con trỏ kiểu FILE ứng với tệp

vừa mở. Các hàm cấp hai sẽ làm việc với tệp thông qua con trỏ này. Nếu có lỗi hàm sẽ

trả về giá trị NULL.

Bảng sau chỉ ra các giá trị của kiểu:

Tên kiểu ý nghĩa

"r" "rt"Mở một tệp để đọc theo kiểu văn bản. Tệp cần đọc phải đã tồn

tại, nếu không sẽ có lỗ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ị xoá.

"a" "at"Mở một tệp để ghi bổ xung theo kiểu văn bản. Nếu tệp chưa

tồn tại thì tạo tệp mới.

"rb"Mở một tệp để đọc theo kiểu nhị phân. Tệp cần đọc phải đã tồn

tại, nếu không sẽ có lỗ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ị xoá.

"ab"Mở một tệp để ghi bổ xung theo kiểu nhị phân. Nếu tệp chưa

tồn tại thì tạo tệp mới.

"r+" "r+t"Mở một tệp để đọc/ghi theo kiểu văn bản. Tệp cần đọc phải đã

tồn tại, nếu không sẽ có lỗi

"w+" "w+t"Mở một tệp để đọc/ghi theo kiểu văn bản. Nếu tệp đã tồn tại thì

nó sẽ bị xoá.

"a+" "a+t" Mở một tệp để đọc/ghi bổ xung theo kiểu văn bản. Nếu tệp

90

Page 91: Lt giao trinh nhap mon lap trinh c 2015_02_26

chưa tồn tại thì tạo tệp mới.

"r+b"Mở một tệp để đọc/ghi theo kiểu nhị phân. Tệp cần đọc phải đã

tồn tại, nếu không sẽ có lỗi.

"w+b"Mở một tệp mới để đọc/ghi theo kiểu nhị phân. Nếu tệp đã tồn

tại thì nó sẽ bị xoá.

"a+b"Mở một tệp để đọc/ghi bổ xung theo kiểu nhị phân. Nếu tệp

chưa tồn tại thì tạo tệp mới.

Chú ý:Trong các kiểu đọc ghi, ta nên lầm sạch vùng đệm trước khi chuyển từ đọc

sang ghi hoặc ngược lại. Ta sẽ đề cập đến các hàm với tính năng xoá sau này.

Ví dụ 6.2:

f=fopen("TEPNP","wb");

6.2.3. Đóng tệp - hàm fclose

Cấu trúc ngữ pháp của hàm:

int fclose(FILE *fp);

Nguyên hàm trong: stdio.h

Trong đó:fp là con trỏ ứng với tệp cần đóng.

Công dụng:Hàm dùng để đóng tệp khi kết thúc các thao tác trên nó. Khi đóng

tệp, máy thực hiện các công việc sau:

Khi đang ghi dữ liệu thì máy sẽ đẩy dữ liệu còn trong vùng đệm lên đĩa

Khi đang đọc dữ liệu thì máy sẽ xoá vùng đệm

Giải phóng biến trỏ tệp.

Nếu lệnh thành công, hàm sẽ cho giá trị 0, trái lại nó cho hàm EOF.

Ví dụ 6.3:

fclose(f);

91

Page 92: Lt giao trinh nhap mon lap trinh c 2015_02_26

6.2.4. Đóng tất cả các tệp đang mở- hàm fcloseall:

Cấu trúc ngữ pháp của hàm:

int fcloseall(void);

Nguyên hàm trong: stdio.h

Công dụng:Hàm dùng để đóng tất cả các tệp đang mở . Nếu lệnh thành công,

hàm sẽ cho giá trị bằng số là số tệp được đóng, trái lại nó cho hàm EOF.

Ví dụ 6.4:

fcloseall();

6.2.5. Kiểmtra cuối tệp - hàm feof

Cấu trúc ngữ pháp của hàm:

int feof(FILE *fp);

Nguyên hàm trong: stdio.h

Trong đó fp là con trỏ tệp.

Công dụng:Hàm dùng để kiểm tra cuối tệp. Hàm cho giá trị khác 0 nếu gặp cuối

tệp khi đọc, trái lại hàm cho giá trị 0.

6.2.6. Truy nhập ngẫu nhiên - các hàm di chuyên con trỏ chỉ vị:

6.2.6.1. Chuyển con trỏ chỉ vị về đầu tệp - Hàm rewind:

Cấu trúc ngữ pháp:

void rewind(FILE *fp);

Nguyên hàm trong: stdio.h

Trong đó fp là con trỏ tệp.

Công dụng:Chuyển con trỏ chỉ vị của tệp fp về đầu tệp. Khi đó việc nhập xuất

trên tệp fp được thực hiện từ đầu.

Ví dụ 6.5:

rewind(f);

92

Page 93: Lt giao trinh nhap mon lap trinh c 2015_02_26

6.2.6.2. Chuyển con trỏ chỉ vị trí cần thiết - Hàm fseek

Cấu trúc ngữ pháp:

int fseek(FILE *fp, long sb, int xp);

Nguyên hàm trong: stdio.h

Trong đó

fp là con trỏ tệp.

sb là số byte cần di chuyển.

xp cho biết vị trí xuất phát mà việc dịch chuyển được bắt đầu từ đó.

xp có thể nhận các giá trị sau:

xp=SEEK_SET hay 0: Xuất phát từ đầu tệp.

xp=SEEK_CUR hay 1: Xuất phát từ vị trí hiện tại của con trỏ chỉ vị.

xp=SEEK_END hay 2: Xuất phát từ cuối tệp.

Công dụng:Chuyển con trỏ chỉ vị của tệp fp về vị trí xác định bởi xp qua một số

byte xác định bằng giá trị tuyệt đối của sb. Chiều di chuyển là về cuối tệp nếu sb

dương, trái lại nó sẽ di chuyển về đầu tệp. Khi thành công, hàm trả về giá trị 0. Khi có

lỗi hàm trả về giá trị khác không.

Chú ý:Không nên dùng fseek trên tệp tin văn bản, do sự chuyển đổi ký tự sẽ làm

cho việc định vị thiếu chính xác.

Ví dụ 6.6:

fseek(stream, SEEK_SET, 0);

6.2.6.3. Vị trí hiện tại của con trỏ chỉ vị - Hàm ftell:

Cấu trúc ngữ pháp:

int ftell(FILE *fp);

Nguyên hàm trong: stdio.h.

Trong đó fp là con trỏ tệp.

93

Page 94: Lt giao trinh nhap mon lap trinh c 2015_02_26

Công dụng:Hàm cho biết vị trí hiện tại của con trỏ chỉ vị (byte thứ mấy trên tệp

fp) khi thành công. Số thứ tự tính từ 0. Trái lại hàm cho giá trị -1L.

Ví dụ 6.7:

Sau lệnh fseek(fp,0,SEEK_END);

ftell(fp) cho giá trị 3.

Sau lệnh fseek(fp,-1,SEEK_END);

ftell(fp) cho giá trị 2.

6.2.7. Ghi các mẫu tin lên tệp - hàm fwrite

Cấu trúc ngữ pháp của hàm:

int fwrite(void *ptr, int size, int n, FILE *fp);

Nguyên hàm trong: stdio.h

Trong đó:

ptr là con trỏ trỏ tới vùng nhớ chứa dữ liệu cần ghi.

size là kích thước của mẫu tin theo byte

n là số mẫu tin cần ghi

fp là con trỏ tệp

Công dụng:Hàm ghi n mẫu tin kích thước size byte từ vùng nhớ ptr lên tệp

fp.Hàm sẽ trả về một giá trị bằng số mẫu tin thực sự ghi được.

Ví dụ 6.8:

#include <stdio.h>

struct mystruct

{

int i;

char ch;

};

int main()

94

Page 95: Lt giao trinh nhap mon lap trinh c 2015_02_26

{

FILE *stream;

struct mystruct s;

stream = fopen("TEST.TXT", "wb") /* Mở tệp TEST.TXT */

s.i = 0;

s.ch = 'A';

fwrite(&s, sizeof(s), 1, stream); /* Viết cấu trúc vào

tệp */

fclose(stream); /* Đóng tệp */

return 0;

}

6.2.8. Đọc các mẫu tin từ tệp - hàm fread

Cấu trúc ngữ pháp của hàm:

int fread(void *ptr, int size, int n, FILE *fp);

Nguyên hàm trong: stdio.h.

Trong đó:

ptr là con trỏ trỏ tới vùng nhớ chứa dữ liệu cần ghi.

size là kích thước của mẫu tin theo byte

n là số mẫu tin cần ghi

fp là con trỏ tệp

Công dụng:Hàm đọc n mẫu tin kích thước size byte từ tệp fp lên lên vùng nhớ

ptr.Hàm sẽ trả về một giá trị bằng số mẫu tin thực sự đọc được.

Ví dụ 6.9:

#include <string.h>

#include <stdio.h>

int main()

{

95

Page 96: Lt giao trinh nhap mon lap trinh c 2015_02_26

FILE *stream;

char msg[] = "Kiểm tra";

char buf[20];

stream = fopen("DUMMY.FIL", "w+");

/* Viết vài dữ liệu lên tệp */

fwrite(msg, strlen(msg)+1, 1, stream);

/* Tìm điểm đầu của file */

fseek(stream, SEEK_SET, 0);

/* Đọc số liệu và hiển thị */

fread(buf, strlen(msg)+1, 1, stream);

printf("%s\n", buf);

fclose(stream);

return 0;

}

6.2.9. Nhập xuất ký tự

6.2.9.1. Các hàm putc và fputc

Cấu trúc ngữ pháp:

int putc(int ch, FILE *fp);

int fputc(int ch, FILE *fp);

Nguyên hàm trong: stdio.h.

Trong đó:ch là một giá trị nguyên, fp là một con trỏ tệp.

Công dụng:Hàm ghi lên tệp fp một ký tự có mẫ bằng

m=ch % 256.

ch được xem là một giá trị nguyên không dấu. Nếu thành công hàm cho mã ký tự

được ghi, trái lại cho EOF

Ví dụ 6.10:

#include <stdio.h>

int main()

96

Page 97: Lt giao trinh nhap mon lap trinh c 2015_02_26

{

char msg[] = "Hello world\n";

int i = 0;

while (msg[i])

putc(msg[i++], stdout); /* stdout thiết bị ra chuẩn

- Màn hình*/

return 0;

}

6.2.9.2. Các hàm getc và fgettc

Cấu trúc ngữ pháp:

int gretc(FILE *fp);

int fputc(FILE *fp);

Nguyên hàm trong: stdio.h.

Trong đó:fp là một con trỏ tệp.

Công dụng:Hàm đọc một ký tự từ tệp fp. Nếu thành công hàm sẽ cho mã đọc

được ( có giá trị từ 0 đến 255). Nếu gặp cuối tệp hay có lỗi hàm sẽ trả về EOF.

Trong kiểu văn bản, hàm đọc một lượt cả hai mã 13, 10 và trả về giá trị 10. Khi

gặp mã 26 hàm sẽ trả về EOF.

Ví dụ 6.11:

#include <string.h>

#include <stdio.h>

#include <conio.h>

int main()

{

FILE *stream;

char string[] = "Kiem tra";

char ch;

/* Mở tệp để cập nhật*/

stream = fopen("DUMMY.FIL", "w+");

97

Page 98: Lt giao trinh nhap mon lap trinh c 2015_02_26

/*Viết một xâu ký tự vào tệp */

fwrite(string, strlen(string), 1, stream);

/* Tìm vị trí đầu của tệp */

fseek(stream, 0, SEEK_SET);

do

{

/* Đọc một ký tự từ tệp */

ch = fgetc(stream);

/* Hiển thị ký tự */

putch(ch);

} while (ch != EOF);

fclose(stream);

return 0;

}

6.2.10. Xoá tệp - hàm unlink:

Cấu trúc ngữ pháp:

int unlink(const char *tên_tệp)

Nguyên hàm trong: dos.h, io.h, stdio.h.

Trong đótên_tệp là tên của tệp cần xoá.

Công dụng:Dùng để xoá một tệp trên đĩa. Nếu thành công, hàm cho giá trị 0, trái

lại hàm cho giá trị EOF.

Ví dụ 6.12:

#include <stdio.h>

#include <io.h>

int main(void)

{

FILE *fp = fopen("junk.jnk","w");

int status;

fprintf(fp,"junk");

98

Page 99: Lt giao trinh nhap mon lap trinh c 2015_02_26

status = access("junk.jnk",0);

if (status == 0)

printf("Tệp tồn tại\n");

else

printf("Tệp không tồn tại\n");

fclose(fp);

unlink("junk.jnk");

status = access("junk.jnk",0);

if (status == 0)

printf("Tệp tồn tại\n");

else

printf("Tệp không tồn tại\n");

return 0;

}

6.3. Một số ví dụ

6.3.1. Ghi, đọc mảng

Ví dụ 6.13:Ghi n số nguyên vào file và độc ra từ file

#include <stdio.h>

#include <conio.h>

#include <stdlib.h>

#define MAX 5

int main()

{

FILE *f;

int i, ia[MAX], ib[MAX];

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

{

printf("Nhap vao mot so: ");

99

Page 100: Lt giao trinh nhap mon lap trinh c 2015_02_26

scanf("%d", &ia[i]);

}

if((f = fopen("array.dat", "wb")) == NULL)

{

printf("Khong the mo file!\n");

exit(0);

}

fwrite(ia, sizeof(ia), 1, f); //ghi mang vao

file

fclose(f);

f = fopen("array.dat", "rb");

fread(ib, sizeof(ib), 1, f); //doc mang tu

file

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

printf("%d ", ib[i]);

fclose(f);

getch();

}

6.3.2. Ghi, đọc structure

Ví dụ 6.14: Danh sách sinh viên

#include <stdio.h>

#include <conio.h>

#include <stdlib.h>

#define MAX 50

int main()

{

FILE *f;

struct nhanvien

100

Page 101: Lt giao trinh nhap mon lap trinh c 2015_02_26

{

int manv;

char hoten[30];

};

nhanvien snv[MAX], snv1[MAX];

char ctam[10];

int i, in;

printf("Nhap vao so nhan vien: ");

gets(ctam);

in = atoi(ctam);

//Nhap danh sach nhan vien va ghi vao file

if((f = fopen("struct.dat", "wb")) == NULL)

{

printf("Khong the mo file!\n");

exit(0);

}

fwrite(&in, sizeof(int), 1, f);

//ghi so nhan vien vao file

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

{

printf("Nhap vao ma nhan vien thu %d: ", i + 1);

gets(ctam);

snv[i].manv = atoi(ctam);

printf("Nhap vao ho ten: ");

gets(snv[i].hoten);

fwrite(&snv[i], sizeof(nhanvien), 1, f); //ghi

tung nhan vien vao file

}

fclose(f);

//doc danh sach nhan vien tu file va in ra

f = fopen("struct.dat", "rb");

101

Page 102: Lt giao trinh nhap mon lap trinh c 2015_02_26

fread(&in, sizeof(int), 1, f); //doc so

nhan vien

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

{

//doc tung nhan vien in ra man hinh

fread(&snv1[i], sizeof(nhanvien, 1, f);

printf("%5d %s\n", snv[i].manv, snv[i].hoten);

}

getch();

}

102

Page 103: Lt giao trinh nhap mon lap trinh c 2015_02_26

Tài liệu tham khảoTài liệu tham khảo

[1]. Lê Đăng Hưng, Trần Việt Linh, Lê Đức Trung, Nguyễn Thanh Thủy, Ngôn ngữ

lập trình C, NXB Giáo dục, 1996.

[2]. Phạm Văn Ất, Giáo trình kỹ thuật lập trình C - Căn bản và nâng cao, NXB Hồng

Đức, 2009.

[3]. Phạm Văn Ất, Giáo trình C++ và lập trình hướng đối, NXB Hồng Đức, 2009.

[4]. http://vi.wikipedia.org/wiki/C%2B%2B

[5]. https://developers.google.com/edu/c++

[6]. http://www.tutorialspoint.com/cplusplus/index.htm

[7]. http://www.tutorialspoint.com/cprogramming

[8]. http://www.cplusplus.com

[9]. http://www.cppreference.com

103