P. 1
Giao Trinh C_Uyên Trang

# Giao Trinh C_Uyên Trang

|Views: 161|Likes:

See more
See less

01/07/2013

pdf

text

original

## Sections

• CHƯƠNG 0
• GIỚI THIỆU
• 1.LỊCH SỬ NGÔN NGỮ LẬP TRÌNH C
• 2.ƯU, KHUYẾT ĐIỂM CỦA C
• 3.CÀI ĐẶT VÀ SỬ DỤNG TRÌNH SOẠN THẢO TURBO C
• 5. THỰC HIỆN CHẠY MỘT CHƯƠNG TRÌNH C
• CHƯƠNG 1
• CÁC THÀNH PHẦN CƠ BẢN - CHƯƠNG TRÌNH
• 1.TẬP KÝ TỰ CỦA C
• 2.TÊN
• 3.TỪ KHOÁ
• 4.CÁC KIỂU DỮ LIỆU CHUẨN
• 6.KHAI BÁO HẰNG
• 7.CÁC PHÉP TOÁN (TOÁN TỬ)
• 8CẤU TRÚC CƠ BẢN CỦA MỘT CHƯƠNG TRÌNH C
• 8.VÀO RA
• CHƯƠNG 2
• CÁC CÂU LỆNH ĐIỀU KHIỂN CHƯƠNG TRÌNH
• 1.CÂU LỆNH ĐƠN
• 2. CÂU LỆNH GHÉP
• 3. CÂU LỆNH if
• 4. CÂU LỆNH WHILE
• 5. CÂU LỆNH do…while
• 6. CÂU LỆNH FOR
• 7. CÂU LỆNH break VÀ continue
• 8. CÂU LỆNH switch
• CHƯƠNG 3
• MẢNG VÀ CON TRỎ
• 1. MẢNG
• 2. CON TRỎ
• 3. LIÊN HỆ GIỮA CON TRỎ VÀ MẢNG
• 4. CẤP PHÁT ĐỘNG
• 5. TÓM TẮT
• HÀM
• 1.GIỚI THIỆU
• 2. KHAI BÁO VÀ ĐỊNH NGHĨA HÀM
• 3. THAM SỐ TRONG LỜI GỌI HÀM
• 4.CẤP LƯU TRỮ VÀ PHẠM VI CỦA CÁC ĐỐI TƯỢNG
• 5. CON TRỎ HÀM
• 6. ĐỆ QUY
• CHƯƠNG 5
• CẤU TRÚC
• 1. CẤU TRÚC
• 2. CẤU TRÚC TỰ TRỎ
• 3. KIỂU HỢP (union)
• CHƯƠNG 6
• ĐỒ HOẠ
• 1.KHÁI NIỆM
• 2.KHỞI ĐỘNG ĐỒ HOẠ
• 3.CÁC LỖI THÔNG THƯỜNG TRONG ĐỒ HOẠ
• 4.CÁC MÀU VÀ MẪU
• 5.VẼ VÀ TÔ MÀU
• 6.KIỂU ĐƯỜNG
• 7.CỬA SỔ (viewport)
• 8.TÔ ĐIỂM, TÔ MIỀN
• 9.XỬ LÝ VĂN BẢN TRÊN MÀN HÌNH ĐỒ HOẠ
• BÀI TẬP
• CÁC THÀNH PHẦN CƠ BẢN CỦA C
• CÁC KIỂU DỮ LIỆU CƠ SỞ
• BIỂU THỨC, CÂU LỆNH VÀ CÁC PHÉP TOÁN
• CHƯƠNG 4
• CÁC CÂU LỆNH ĐIỀU KHIỂN
• THAM KHẢO
• CÁC CHỈ THỊ TIỀN XỬ LÝ
• 1.CHỈ THỊ #define ĐƠN GIẢN (MACRO)
• 2.CHỈ THỊ #define CÓ ĐỐI (MACRO)
• 3.CHỈ THỊ BAO HÀM TỆP #include
• 4.CÁC CHỈ THỊ BIÊN DỊCH CÓ ĐIỀU KIỆN #if
• 5.CÁC CHỈ THỊ BIÊN DỊCH CÓ ĐIỀU KIỆN #ifdef VÀ #ifndef
• 6.TỔ CHỨC CÁC TỆP THƯ VIỆN
• 7.CHỈ THỊ #error

# Giáo trình Ngôn ngữ lập trình C

Trần Uyên Trang

MỤC LỤC
CHƯƠNG 0.....................................................................................................................................................3 GIỚI THIỆU................................................................................................................................................3 1.LỊCH SỬ NGÔN NGỮ LẬP TRÌNH C ..............................................................................................3 2.ƯU, KHUYẾT ĐIỂM CỦA C..............................................................................................................3 3.CÀI ĐẶT VÀ SỬ DỤNG TRÌNH SOẠN THẢO TURBO C.................................................................4 5. THỰC HIỆN CHẠY MỘT CHƯƠNG TRÌNH C...............................................................................4 CHƯƠNG 1.....................................................................................................................................................5 CÁC THÀNH PHẦN CƠ BẢN - CHƯƠNG TRÌNH................................................................................5 1.TẬP KÝ TỰ CỦA C.............................................................................................................................5 2.TÊN.....................................................................................................................................................5 3.TỪ KHOÁ...........................................................................................................................................6 4.CÁC KIỂU DỮ LIỆU CHUẨN...........................................................................................................6 5. KHAI BÁO BIẾN................................................................................................................................7 6.KHAI BÁO HẰNG...............................................................................................................................8 7.CÁC PHÉP TOÁN (TOÁN TỬ)........................................................................................................10 8CẤU TRÚC CƠ BẢN CỦA MỘT CHƯƠNG TRÌNH C.....................................................................16 8.VÀO RA.............................................................................................................................................18 BÀI TẬP...............................................................................................................................................24 CHƯƠNG 2...................................................................................................................................................27 CÁC CÂU LỆNH ĐIỀU KHIỂN CHƯƠNG TRÌNH..............................................................................27 1.CÂU LỆNH ĐƠN..............................................................................................................................27 2. CÂU LỆNH GHÉP .........................................................................................................................27 3. CÂU LỆNH if...................................................................................................................................27 4. CÂU LỆNH WHILE.........................................................................................................................29 5. CÂU LỆNH do…while.....................................................................................................................30 6. CÂU LỆNH FOR..............................................................................................................................31 7. CÂU LỆNH break VÀ continue........................................................................................................34 8. CÂU LỆNH switch...........................................................................................................................36 BÀI TẬP...............................................................................................................................................38 CHƯƠNG 3...................................................................................................................................................41 MẢNG VÀ CON TRỎ .............................................................................................................................41 1. MẢNG..............................................................................................................................................41 2. CON TRỎ.........................................................................................................................................46 3. LIÊN HỆ GIỮA CON TRỎ VÀ MẢNG............................................................................................50 4. CẤP PHÁT ĐỘNG...........................................................................................................................54 5. TÓM TẮT.........................................................................................................................................57 CHƯƠNG 4...................................................................................................................................................59 HÀM..........................................................................................................................................................59 1.GIỚI THIỆU.....................................................................................................................................59 2. KHAI BÁO VÀ ĐỊNH NGHĨA HÀM................................................................................................61 3. THAM SỐ TRONG LỜI GỌI HÀM.................................................................................................66 4.CẤP LƯU TRỮ VÀ PHẠM VI CỦA CÁC ĐỐI TƯỢNG..................................................................70 5. CON TRỎ HÀM...............................................................................................................................75 6. ĐỆ QUY...........................................................................................................................................78 CHƯƠNG 5...................................................................................................................................................82 CẤU TRÚC...............................................................................................................................................82

Khoa Tin học

-1-

Giáo trình Ngôn ngữ lập trình C

Trần Uyên Trang

1. CẤU TRÚC......................................................................................................................................82 2. CẤU TRÚC TỰ TRỎ........................................................................................................................92 3. KIỂU HỢP (union)........................................................................................................................106 CHƯƠNG 6.................................................................................................................................................109 ĐỒ HOẠ .................................................................................................................................................109 1.KHÁI NIỆM....................................................................................................................................109 2.KHỞI ĐỘNG ĐỒ HOẠ..................................................................................................................110 3.CÁC LỖI THÔNG THƯỜNG TRONG ĐỒ HOẠ...........................................................................112 4.CÁC MÀU VÀ MẪU.......................................................................................................................113 5.VẼ VÀ TÔ MÀU..............................................................................................................................115 6.KIỂU ĐƯỜNG................................................................................................................................117 7.CỬA SỔ (viewport).........................................................................................................................120 VỚI VIEWPORTTYPE LÀ KIỂU CẤU TRÚC ĐƯỢC ĐỊNH NGHĨA NHƯ SAU:...................................................................120 ................................................................................................................................................................120 8.TÔ ĐIỂM, TÔ MIỀN.......................................................................................................................121 9.XỬ LÝ VĂN BẢN TRÊN MÀN HÌNH ĐỒ HOẠ..............................................................................123 10. CẮT, DÁN, VẼ HÌNH CHUYỂN ĐỘNG.....................................................................................124 BÀI TẬP..................................................................................................................................................128 CHƯƠNG 0.................................................................................................................................................128 GIỚI THIỆU............................................................................................................................................128 CHƯƠNG 1.................................................................................................................................................128 CÁC THÀNH PHẦN CƠ BẢN CỦA C.................................................................................................128 CHƯƠNG 2.................................................................................................................................................128 CÁC KIỂU DỮ LIỆU CƠ SỞ.................................................................................................................128 CHƯƠNG 3.................................................................................................................................................130 BIỂU THỨC, CÂU LỆNH VÀ CÁC PHÉP TOÁN...............................................................................130 CHƯƠNG 4.................................................................................................................................................132 CÁC CÂU LỆNH ĐIỀU KHIỂN............................................................................................................132 THAM KHẢO.............................................................................................................................................134 CÁC CHỈ THỊ TIỀN XỬ LÝ..................................................................................................................134 1.CHỈ THỊ #define ĐƠN GIẢN (MACRO)........................................................................................134 2.CHỈ THỊ #define CÓ ĐỐI (MACRO).............................................................................................135 3.CHỈ THỊ BAO HÀM TỆP #include.................................................................................................135 4.CÁC CHỈ THỊ BIÊN DỊCH CÓ ĐIỀU KIỆN #if............................................................................136 5.CÁC CHỈ THỊ BIÊN DỊCH CÓ ĐIỀU KIỆN #ifdef VÀ #ifndef.....................................................137 6.TỔ CHỨC CÁC TỆP THƯ VIỆN...................................................................................................138 7.CHỈ THỊ #error...............................................................................................................................138

Khoa Tin học

-2-

Giáo trình Ngôn ngữ lập trình C

Trần Uyên Trang

CHƯƠNG 0

GIỚI THIỆU
1. LỊCH SỬ NGÔN NGỮ LẬP TRÌNH C
Ngôn ngữ C do Brian W.Kernighan và Dennis M. Ritchie phát triển vào đầu những năm 70 tại phòng thí nghiệm BELL (Hoa Kỳ) với mục đích ban đầu là để phát triển hệ điều hành UNIX. Bối cảnh ra đời xuất phát từ nhu cầu cần phải có một ngôn ngữ lập trình hệ thống thay đổi cho hợp ngữ (Assembly) vốn nặng nề, độ tin cậy thấp và rất khó chuyển đổi giữa các hệ máy tính khác nhau. Phần lớn những ý tưởng quan trọng nhất của C xuất phát từ ngôn ngữ trước đó là ngôn ngữ BCPL, do Martin Richard viết. Ảnh hưởng của ngôn ngữ BCPL đối với C gián tiếp thông qua ngôn ngữ B, do Ken Thompson viết năm 1970 cho hệ điều hành UNIX, chạy trên họ máy tính PDP-7. Năm 1978, cuốn sách "The C programming languague" do chính hai tác giả Brian W.Kernighan và Dennis M. Ritchie biên soạn được xuất bản và phổ biến rộng rãi. Ngoài việc C được dùng để viết hệ điều hành UNIX, người ta nhanh chóng nhận ra sức mạnh của C trong việc xử lý các vấn đề thực tế như: xử lý số, văn bản, cơ sở dữ liệu, … Tuy vậy, khi độ phức tạp của các bài toán cần giải quyết trên thực tế ngày càng tăng thì các ngôn ngữ lập trình có cấu trúc đã bộc lộ những điểm yếu nhất định. Để khắc phục những hạn chế này, các nhà thiết kế phần mềm đã phát triển một ý tưởng mới, đó là lập trình hướng đối tượng. Đến năm 1983, Bjarne Stroustrup đã phát triển ngôn ngữ C thành ngôn ngữ C ++, (bổ sung mới các yếu tố hướng đối tượng (Oject). Đây là một trong những ngôn ngữ rất được ưu dùng. Vì vậy, hiện nay, ngoài Turbo C, Borland C, hầu hết các chương trình C đều được chạy trong môi trường C++.

2. ƯU, KHUYẾT ĐIỂM CỦA C 2.1 Ưu điểm
- C là một ngôn ngữ mạnh, mềm dẻo; được các nhà tin học chuyên nghiệp dùng phổ biến, nhất là để viết các phần mềm hệ thống (hệ điều hành, chương trình dịch, …) - Có thể dùng trên nhiều loại máy khác nhau cũng như nhiều hệ điều hành khác nhau. - Ít từ khoá Khoa Tin học -3-

PRJ. Nếu việc dịch chương trình nguồn không có lỗi.Cách 1: Nhấn tổ hợp Alt+x . nhấn EXIT đế quay lại màn hình soạn thảo Turbo C.Cách 2: Vào File. ta có thể soạn thảo và chạy chương trình trong môi trường C+ như trong môi trường Turbo C. BIN.Turbo C gồm các thư mục BGI. CÀI ĐẶT VÀ SỬ DỤNG TRÌNH SOẠN THẢO TURBO C . nhấn phím O hoặc chọn mục Dos Shell thì máy sẽ tạm thời thoát Turob C vào DOS. ví dụ: kí hiệu * có thể là toán tử nhân. + Như đã trình bày. INCLUDE. Để dịch và chạy chương trình. LIB. Ta có thể đặt thư mục TC ở một đĩa bất kì. Chú ý: Nếu Turbo C không được đặt trong C:\TC thì khi vào trình soạn thảo của C.Cú pháp lạ và khó học. Ở 2 trường hợp trên.exe trong thư mục TC\BIN. (hoặc nhấp kép vào Shortcut của nó). Trong trường hợp dùng môi trường soạn thảo của C (hoặc C ++). nhấn phím F2 để lưu chương trình. . NSD cần phải thiết lập lại môi trường: vào Option / Directories / Chỉ định lại đường dẫn đến các thành phần theo yêu cầu. Để vào màn hình soạn thảo Turbo C.… 3. chạy tệp tc. 5. Khoa Tin học -4- . * Để thoát khỏi TC: .2 Khuyết điểm . khai báo biến con trỏ. nhấn ^F9 (hoặc vào menu Run/Run). ta phải dịch chương trình nguồn để tạo ra tệp chương trình đích (có phần mở rộng là exe). THỰC HIỆN CHẠY MỘT CHƯƠNG TRÌNH C Sau khi soạn thảo chương trình nguồn trên một hệ soạn thảo nào đó và lưu lại trên đĩa.Giáo trình Ngôn ngữ lập trình C . Chú ý: Nếu đang ở menu File. Chọn mục Exit.Một số kí hiệu có nhiều nghĩa. EXAMPLE. thì ta có thể thực hiện chương trình đích từ dấu nhắc của hệ điều hành. sau khi soạn thảo chương trình nguồn. nếu chương trình nguồn chưa được lưu lần cuối thì Turbo C sẽ thông báo có lưu hay không.Có cấu trúc môđun Trần Uyên Trang 2.

.Tên bao gồm một dãy các kí tự: chữ. các từ lại được liên kết với nhau theo một quy tắc (đó là cú pháp của ngôn ngữ lập trình) nào đó để tạo thành các câu lệnh. Các kí tự được nhóm lại theo nhiều cách khác nhau để tạo nên các từ. kí tự gạch nối dưới. TẬP KÝ TỰ CỦA C Mọi ngôn ngữ lập trình đều được xây dựng trên bộ kí tự nào đó.CHƯƠNG TRÌNH 1.* / = < > − Các dấu ngăn cách: . dấu gạch nối '_' (underscore) và phải bắt đầu bằng một chữ hoặc dấu gạch nối '.Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang CHƯƠNG 1 CÁC THÀNH PHẦN CƠ BẢN . . TÊN .Tên hợp lệ là dãy kí tự liền nhau. số. . Ngôn ngữ lập trình C được xây dựng trên bộ kí tự sau: − 26 chữ cái in hoa: A B C … Y Z − 26 chữ cái in thường: a b c … y z − 10 chữ số: 0 1 2 …9 − Các kí hiệu toán học: + . . có thể gồm các chữ cái. Đến lượt mình.Tên hay định danh (identificator) là khái niệm để xác định các đại lượng khác nhau trong một chương trình. : space − Các dấu ngoặc: ( ) [ ] { } − Các kí hiệu đặc biệt: _ ? ~ ! # \$ % ^ & ' \ " v.'. các chữ số. Một chương trình bao gồm nhiều câu lệnh diễn đạt một thuật toán nào đó. Mọi tên được sử dụng trong chương trình đều phải được khai báo. Tên phải bắt đầu bằng chữ cái hoặc dấu gạch nối dưới. Ví dụ: Tên hợp lệ: LOPTT01 Loptt01 loptt01 a_1 _name Tên không hợp lệ: bai tap 1_baitap Khoa Tin học (vì có dấu space) (vì bắt đầu bằng số) -5- .v… 2.

hàm. cấu trúc. bảo trì chương trình. Việc đặt tên gợi nhớ rất có ích trong khi sửa chữa. mỗi từ có một ý nghĩa và tác dụng cụ thể. Khác với Pascal.2: TÊN Khoa Tin học Ý NGHĨA KÍCH PHẠM VI -6- . ngôn ngữ C phân biệt giữa chữ hoa và chữ thường. Abc. hay arraysize. TỪ KHOÁ Từ khoá là các từ dùng riêng của một ngôn ngữ lập trình. nhưng chúng ta có thể thay đổi lại bằng một giá trị từ 1 đến 32 trong chức năng Option/Compiler/Source/Identifier Length. CÁC KIỂU DỮ LIỆU CHUẨN Các kiểu dữ liệu chuẩn của C được mô tả ở bảng 1. aBC là khác nhau. AbC.Giáo trình Ngôn ngữ lập trình C name#3 (vì có dấu #) Trần Uyên Trang Độ dài cực đại của tên mặc định là 32. Bảng 1. còn chữ thường được dùng để đặt tên cho các biến. chỉ có 32 kí tự đầu tiên có ý nghĩa.1 Danh sách từ khoá thông dụng của C asm char double float int register static unsigned auto const else for interrupt return struct void break continue enum goto long short switch volatile case default extern huge near signed typedef while cdecl do far if pascal sizeof union 4. Từ khoá của C phải được dùng đúng cú pháp và không được định nghĩa lại. Các tên ABC. … Khi đặt tên phải luôn ghi nhớ nguyên tắc là tên ít nhiều phản ánh được bản chất của đối tượng được đặt tên. ABc. nhưng trong trường hợp đó. 3. Dĩ nhiên. ví dụ đặt tên cho biến chứa số phần tử của mảng là ArraySize sẽ dễ hiểu hơn là các tên as. Người ta thường dùng chữ hoa đặt tên cho các hằng. ta có thể đặt các tên có nhiều hơn 32 kí tự. abc.

4E-4932 ÷ ± 1. Các biến trong bộ nhớ ở các thời điểm khác nhau có thể cất giữ các giá trị khác nhau.4E-38 ÷ ± 3. Quy tắc khai báo như sau: <kiểu_dữ_liệu> <tên_biến>. và khi đó. 5.2 Các kiểu dữ liệu chuẩn của C Một số có kiểu float có độ chính xác là 6 chữ số sau dấu chấm thập phân.4E+38 float 4 byte ± 1.Giáo trình Ngôn ngữ lập trình C THƯỚC char unsigned char int unsigned int short int unsigned long int long int số thực dấu chấm động độ chính xác đơn double long double số thực dấu phẩy động độ chính xác kép 8 byte 10 byte số nguyên kí tự 1 byte 1 byte 2 byte 2 byte 2 byte 4 byte 4 byte -127 ÷ 128 0÷ 255 Trần Uyên Trang -32 768 ÷ 32 767 0 ÷ 65 535 -32768 ÷ 32 767 0 ÷ 4 294 967 295 -2 147 483 648 ÷ +2 147 483 647 ± 3. Ví dụ: Khoa Tin học -7- . Kiểu long int có thể viết gọn thành long. KHAI BÁO BIẾN Tất cả các biến phải được khai báo trước khi sử dụng và kiểu của chúng phải được mô tả ngay khi khai báo để chương trình dịch cấp phát bộ nhớ cho chúng.7E+308 ± 3.7E-308 ÷ ± 1. Một số kiểu double có độ chính xác tới 15 chữ số sau dấu chấm thập phân. các tên biến được phân cách nhau bởi dấu phẩy. kiểu unsigned int có thể viết thành unsigned. Có thể khai báo nhiều biến cùng kiểu trên một hàng.1E+4932 Bảng 1.

Giáo trình Ngôn ngữ lập trình C Khai báo các biến kiểu nguyên: int tuoiem, tuoianh; Khai báo biến kiểu thực: float hamf; Khai báo biến kiểu kí tự: char ma; 6. KHAI BÁO HẰNG

Trần Uyên Trang

6.1 Khai bao hằng
Hằng là đại lượng không đổi khi thực hiện chương trình. Khai báo (định nghĩa) một hằng về thực chất là gắn một tên (tên hằng) với một giá trị cụ thể nào đó. Về sau, khi gặp tên đó, chương trình dịch ngầm hiểu đó là giá trị tương ứng. Cú pháp khai báo như sau: #define <tên_hằng> <giá_trị> Chỉ thị này định nghĩa một hằng có tên là tên_hằng với giá trị là giá_trị. Khi biên dịch chương trình, chương trình dịch thay thế mọi xuất hiện của tên_hằng bằng giá_trị. Kiểu giá trị của hằng được xác định dựa theo nội dung của giá_trị. Ví dụ: #define MAXSIZE 100 #define DHSP "Truong Dai Hoc Su Pham" #define NEWLINE '\n' * Biến hằng: là các biến có giá trị không thay đổi, nghĩa là chương trình dịch sẽ cấp phát vùng nhớ tương ứng với kiểu của biến hằng và gán cho nó giá trị đã cho nhưng không thể thay đỗi giá trị của nó. Biến hằng được khai báo như sau: const <tên_kiểu> <tên_biến_hằng> =<giá_trị>; Ví dụ: const int MAXSIZE = 100; const char NEWLINE = '\n';

6.2 Cách biểu diễn hằng số
6.2.1 Hằng nguyên (int): * Miền giá trị: -32768 đến 32767 * Biểu diễn trong máy: ta có thể biểu diễn hằng nguyên dưới dạng thập phân, bát phân (cơ số 8) hay thập lục phân (cơ số 16). C quy định: - Hằng biểu diễn ở hệ bát phân: thêm số 0 ở đầu. - Hằng biểu diễn ở hệ thập lục phân: thêm 0x hặoc 0X ở đầu. Khoa Tin học -8-

Giáo trình Ngôn ngữ lập trình C Ví dụ: Giá trị thập phân 189

Trần Uyên Trang

biểu diễn ở hệ bát phân 0275

biểu diễn ở hệ thập lục phân 0xBD

6.2.1 Hằng nguyên dài (long int): được viết như hằng nguyên nhưng thêm chữ l hoặc L ở cuối giá trị. Ví dụ: 189l, 189L. Một hằng số nguyên vượt ra ngoài phạm vi giá trị cho phép của hằng nguyên cũng được hiểu là hằng long. Ví dụ: 1234567 được tự động hiểu là 1234567L. 6.2.1 Hằng dấu phẩy động: có hai cách viết giá trị của một hằng dấu phẩy động: ∗ Cách viết thông thường: Ví dụ: 123.456 ∗ Cách viết khoa học: hằng được viết gồm hai phần: phần định trị và phần mũ. Phần định trị: là số thực, có dạng mmmm.nnn, m và n là các số. Phần mũ: là số nguyên Ví dụ: 12.12E+3 có giá trị bằng 12.12*103, giá trị này có thể viết là 1.212E+4. Do đó, ta có thể tăng, giảm giá trị của phần mũ và dịch nguyển dấu chấm thập phân trong phần định trị nên số thục được viết dưới dạng này có tên gọi là số thực dấu phẩy động (hay số thực dấu chấm động), còn cách viết thông thường có tên gọi là số thực dấu phẩy tĩnh (hay số thực dấu chấm tĩnh). 6.2.1 Hằng kí tự: có thể biểu diễn: ∗ bằng kí hiệu trong bảng mã ASCII đặt giữa hai dấu nháy đơn. Ví dụ: 'A', '2', 'c', … ∗ bằng cặp bao gồm kí tự '\ ' và số thứ tự của kí tự trong bảng mã ASCII . Ví dụ: Biểu diễn theo cách thứ nhất Biểu diễn theo cách thứ hai 'A' '\65', hoặc '\0101', hoặc '\0x41' Có một số hằng ký tự đặc biệt có thể được viết theo quy ước: dùng cặp bao gồm kí tự '\ ' và kí tự trong bảng mã ASCII, cụ thể: Kí tự ' " \ \n \0 Khoa Tin học viết '\'' '\"' '\\' '\n' '\0' '\t' diễn giải dấu nháy đơn dấu ngáy kép dấu gạch chéo ngược kí tự xuống dòng kí tự NULL kí tự tab -9-

Giáo trình Ngôn ngữ lập trình C Bảng 1.3 Cách viết một số hằng kí tự đặc biệt 6.2.1 Hằng xâu kí tự: được đặt trong dấu nháy kép. Ví dụ: "Truong Dai Hoc Su Pham"

Trần Uyên Trang

7. CÁC PHÉP TOÁN (TOÁN TỬ) 7.1 Biểu thức trong C
Biểu thức là kết quả ghép nối các toán tử và các toán hạng để diễn đạt một công thức nào đó. Các toán hạng có thể là một đại lượng nào đó như: hằng, biến, lời gọi hàm…Số ngôi của một toán tử xác định số toán hạng kết hợp với toán tử đó. Thông thường ta có các toán tử hai ngôi và một ngôi. Các toán tử được trình bày ở các mục sau của phần 7 này. Mỗi biểu thức có một giá trị. Tuỳ theo giá trị của biểu thức mà ta có biểu thức nguyên hay biểu thức thực.

7.2 Các phép toán (toán tử) số học
Bảng 1.4 Các phép tính số học Toán tử Ý nghĩa VÍ DỤ đổi dấu một số thực hoặc nguyên -12, -a + cộng hai số thực hoặc nguyên 12+12.5, x + y trừ hai số thực hoặc nguyên 12-10, 12.5-3.4, x - y * nhân hai số thực hoặc nguyên 12*5, 12.3*2, x * y / chia hai số thực hoặc nguyên 23/3, 23.3/5, x / y % chia lấy phần dư của phép chia hai số nguyên 12%5, x % y Các phép toán + và - (hai ngôi) có cùng độ ưu tiên và thấp hơn độ ưu tiên của hai phép toán * và /. Bốn phép toán này lại có độ ưu tiên thấp hơn so với phép (một ngôi). Phép chia hai toán hạng nguyên cho kết quả là số nguyên (tương tự phép DIV trong Pascal). Ví dụ, 7/4 cho kết quả là 1, còn 7.0/4 hoặc 7/4.0 hoặc 7.0/4.0 cho kết quả là 1.75.

7.3 Các phép toán quan hệ
Toán tử > Khoa Tin học Ý nghĩa so sánh lớn hơn. Ví dụ 3>7 có giá trị 0 a>b - 10 -

Trần Uyên Trang 7>=7 có giá trị 1 a>=b so sánh nhỏ hơn. liên kết hai biểu thức lôgic.11 Ý nghĩa .6: Các phép toán lôgic Hai phép toán && và || có độ ưu tiên thấp hơn so với các phép toán quan hệ. !0 có giá trị 1 phép phủ định một ngôi !12 có giá trị 0 !a Bảng 1. nên biểu thức i<n+1 được hiểu là i<(n+1) . 7. Giá trị biểu thức 7<=3 || 8>=3 có giá trị 1 kết quả bằng 1 khi môt trong hai toán hạng n<=0 || n>=100 có giá trị 1. 7!=7 có giá trị 0 a!=b Bảng 1.Giáo trình Ngôn ngữ lập trình C >= < <= == != so sánh lớn hơn hoặc bằng. Tất cả các phép toán này lại có độ ưu tiên thấp hơn phép phủ định một ngôi.4 Các phép toán lôgic Toán tử && || ! Ý nghĩa Ví dụ liên kết hai biểu thức lôgic. Giá trị biểu 3<7 && 8>6 có giá trị 1 thức kết quả bằng 1 khi cả hai toán hạng có ch>='0' && ch<='9' giá trị 1.5 Các phép toán trên bít Phép toán & Khoa Tin học VÀ nhị phân .5 Các phép toán quan hệ Các phép toán trên áp dụng cho các toán hạng là số nguyên hay số thực Bốn phép toán đầu có cùng mực độ ưu tiên. a<=b 7= =7 có giá trị 1 so sánh bằng nhau. 7. hai phép toán sau có cùng độ ưu tiên nhưng thấp hơn bốn phép toán đầu. Các phép toán quan hệ có độ ưu tiên thấp hơn so với các phép toán số học. 7= = 6 có giá trị 0 a==b so sánh không bằng nhau. 6<7 có giá trị 1 10<=5 có giá trị 0 so sánh nhỏ hơn hoặc bằng.

!= với ~.12 - . khi viết: a = b = 5. Một số ví dụ: 1010 0001 1011 0110 & 1111 1111 = 1011 0110 0xa1b6 & 0xff = 0xb6 1010 0001 1011 0110 | 1111 1111 = 1010 0001 1111 1111 0xa1b6 | 0xff = 0xa1ff 0xa1b6 ^ 0xff = 0xffff = 0x5e49 0xa1b6 << 8 =0xb600 0xa1b6 >> 8 =0xa1 -256 << 2 = -1024 -256 >> 2 = -14 ~ 0xa1b6 = 0x5e49 Chú ý: rất dễ nhầm lẫn giữa các phép toán lôgic với phép toán trên bít: && với &. thì điều đó có nghĩa là gán giá trị của biểu thức b = 5 cho biến a. >> Dịch trái.Giáo trình Ngôn ngữ lập trình C | HOẶC nhị phân ^ HOẶC LOẠI TRỪ nhị phân <<. Biểu thức gán có thể được sử dụng trong các phép toán và các câu lệnh như các biểu thức thông thường.7 Các phép toán trên bít Ta nhắc lại rằng: 1&1 = 1 1&0 = 0 0&1 = 0 0&0 = 0 1|1 = 1 1|0 = 1 0|1 = 1 0|0 = 0 1^1 = 0 1^0 = 1 0^1 = 1 0^0 = 0 ~1 = 0 ~0 = 1 a<<n = a*2n a>>n = a/2n Trần Uyên Trang Các phép toán này không được dùng cho số kiểu float hay double. 7. dịch phải ~ BÙ 1 Bảng 1. || với |.' vào sau biểu thức gán thì sẽ thu được một câu lệnh gán. Nếu chúng ta thêm dấu '. Chẳng hạn.6 Biểu thức gán Biểu thức gán có dạng: <biến> = <biểu thức> Thực hiện một biểu thức gán thực chất là lấy giá trị của <biểu thức> gán cho <biến>. kết quả là b = 5 và a = 5. Khoa Tin học .

expr2. trái lại giá trị của biểu thức expr3 được dùng làm giá trị của biểu thức điều kiện.sẽ trừ toán hạng đi 1. chúng ta có thể viết: Toán tử Dạng tiền tố Dạng hậu tố ++ ++n n++ Khoa Tin học . expr1. sé gán 5 cho a. expr3 là các biểu thức nào đó.8 Phép toán tăng. giảm một đơn vị Giả định có câu lệnh: num = num +1. Toán hạng ở đây chỉ có thể là một biến (nguyên.có thể đứng trước (tiền tố) đứng sau (hậu tố) toán hạng. Các dấu phép toán ++ và -.Giáo trình Ngôn ngữ lập trình C Tương tự câu lệnh: Trần Uyên Trang x = (a = 5)*(b = 10). Trong C có hai phép toán một ngôi để tăng. Toán tử ++ có tác dụng tăng giá trị của biến num thêm 1. Nếu expr1 có giá trị khác 0 thì biểu thức điều kiện có giá trị cho bởi expr2. thực) mà khong thể là hằng hay một biểu thức. Ví dụ có thể dùng câu lệnh sau để xác định giá trị lớn nhất giữa hai số a và b: s = (a > b)? a : b. C cho phép sử dụng một số ký pháp đặc biệt của phép toán gán sau đây: Dạng viết thông thường Dạng viết rút gọn i = i + expr i += expr i = i – expr i -= expr i = i * expr i *= expr i = i / expr i /= expr i = i % expr i %= expr i = i & expr i &= expr i = i | expr i |= expr i = i ^ expr i ^= expr i = i >> expr i >>= expr i = i << expr i <<= expr 7. Kiểu của biểu thức điều kiện phụ thuộc vào kiểu của hai biểu thức expr2 và expr3 và là kiểu bao trùm nhất. như vậy.7 Biểu thức điều kiện Biểu thức điều kiện có dạng: expr1?expr2:expr3 trong đó.13 - . thì ta có thể viết gọn hơn là: num++. c: s = (a > b)?(a > c? a : c) : (b > c?b : c). giảm giá trị các biến. Còn câu lệnh sau đây xác định giá trị lớn nhất trong ba số a. Biểu thức điều kiện cũng được dùng như các biểu thức khác. 7. 10 cho b và sau đó gán tiếp 50 cho x. toán tử giảm -. Toán tử tăng ++ sẽ cộng thêm 1 vào toán hạng của nó. b.

Để xác định dịa chỉ của biến ngời ta sử dụng phép toán mộtngôi & đặt trước tên biến: &<tên_biến> Chẳng hạn.Giáo trình Ngôn ngữ lập trình C ---n n-- Trần Uyên Trang Sự khác nhau giữa dạng tiền tố và hậu tố này nảy sinh khi phép toán nằm trong một biểu thức. nếu ta khai báo: int i. Việc chuyển kiểu ở trên diễn ra do yêu cầu của người lập trình. i = 4 và j = 8 7.14 - . float. Khoa Tin học . 7. như là int. i = 4 và j = 9 j = i++ + 5. các toán hạng có kiểu thấp hơn (phạm vi biểu diến hẹp hơn) sẽ được chuyển đổi thành kiểu dữ liệu bao trùm hơn trước khi thực hiện phép toán và kết quả thu được sẽ có kiểu dữ liệu bao trùm nhất. giá trị cũ của biến được sử dụng để tính toán biểu thức bao.9 Phép toán lấy địa chỉ Bộ nhớ máy tính bao gồm nhiều byte được đánh số từ 0 đến giới hạn cuối cùng của bộ nhớ. Ta xét các ví dụ sau: Giả sử trước mỗi phép tính i = 3 và j = 15 Câu lệnh Kết quả i = ++j. còn với dạng hậu tố. Điểm khác nhau ở đây là cách sử dụng giá trị của biến toán hạng khi tính toán biểu thức bao. i=4 j = ++i + 5. C không sử dụng phép toán này cho các đối tượng khác như hằng.10 Phép toán chuyển đổi kiểu bắt buộc Ta có thể chuyển đổi một kiểu bất kì sang kiểu mong muốn bằng cách dùng toán tử chuyển kiểu bắt buộc theo quy tắc sau: (<kiểu>) <biểu_thức> Trong đó. Với dạng tiền tố. … Một số kiểu float nằm trong phạm vi số nguyên int khi chuyển sang kiểu int sẽ bị cắt bỏ phần thập phân. Trong khi thực hiên chương trình có thể có các chuyển đổi kiểu tự động trong trường hợp sau: Khi biểu thức gồm các toán hạng khác nhau về kiểu. ta thay đổi giá trị của biến trước khi sử dụng giá trị biến để tính toán các biểu thức bao quanh. Các số này được gọi là số thứ tự và cũng là địa chỉ của các byte bộ nhớ. rồi sau đó biến mới được thay đổi giá trị. i = 16 và j = 16 i = j++ i = 15 và j = 16 i++. Mỗi biến được khai báo sẽ chiếm giữ một vùng nào đó trong bộ nhớ và địa chỉ của nó là địa chỉ của byte đầu tiên trong vùng nhớ đó. <kiểu> có thể là tên của một kiểu dữ liệu nào đó. biểu thức. thì &i cho ta địa chỉ của vùng nhớ 2 byte có tên là i.

long int p. Trong bảng có một số phép toán sẽ được giớ thiệu ở các phần sau.8 liệt kê thứ tự ưu tiên và trật tự kết hợp của các phép toán.12 Thứ tự ưu tiên và trật tự kết hợp của các phép toán Thứ tự ưu tiên và trật tự kết hợp của các phép toán được sử dụng để xác định cách thức kết hợp các toán hạng với các toán tử khi tính toán biểu thức: Biểu thức con trong ngoặc được tính toán trước các phép toán khác. Ví dụ: a = 5. 6. máy phát hiện p kiểu cao hơn. Khi một toán hạng đứng cạnh hai toán tử. Mức 1 2 3 4 Khoa Tin học Bảng 1. khi các toán tử giống nhau hoặc có độ ưu tiên như nhau thì trạt tự kết hợp của các phép toán này sẽ xác định toán tử nào được kết hợp với phép toán. 7. − Trường hợp trái lại. --------> ! ~ ++ -. toán tử nào có độ ưu tiên cao hơn sẽ được kết hợp với toán hạng. float x. 7 a có giá trị 5 a = (5. − Kiểu kết quả này được chuyển sang kiểu của x là float.11 Toán tử danh sách (toán tử dấu phẩy) Khi có nhiều biểu thức được viết liên tiếp nhau và chúng được cách nhau bởi dấu phẩy thì máy sẽ thực hiện lần lượt các biểu thức theo thứ tự từ trái sang phải.15 - . ta phân biệt hai trường hợp: − Nếu hai toán tử có độ ưu tiên khác nhau. thì biểu thức x = n*p được tính như sau: − Để tính n*p. Kết qua n*p có kiểu long. Bảng 1.7) acó giá trị 7 7.6.8 Thứ tự ưu tiên của các phép toán Các toán tử Trật tự kết hợp ( ) [] -> .+ (type) * & sizeof <-------* (nhân) / % + --------> --------> ..Giáo trình Ngôn ngữ lập trình C char  int  long  float  double  long double chẳng hạn với khai báo: Trần Uyên Trang int n. nên n được chuyển sang kiểu long theo kiểu p. Các toán tử cùng độ ưu tiên sẽ tuân theo trình tự kết hợp hoặc từ trái sang phải hoặc từ phải sang trái. Phép toán một ngôi đứng bên trái toán hạng được kết hợp với toán hạng đi liền sau nó.

prinf(). main(). dòng 2. getch(). các hàm này sẽ xác định các thao tác tính toán thực tế cần phải thực hiện. Các hàm của C cũng tương tự như các hàm và thủ tục của ngôn ngữ Pascal.h> #include <conio.Giáo trình Ngôn ngữ lập trình C 5 6 7 8 9 10 11 12 13 14 << >> < <= > >= = = != & ^ | && || ?: = += -= *= /= %= <<= >>= &= |= ^= Trần Uyên Trang --------> --------> --------> --------> --------> --------> --------> --------> <-------<-------- 8 CẤU TRÚC CƠ BẢN CỦA MỘT CHƯƠNG TRÌNH C Hãy xem các thành phần cơ bản của chương trình hello. 8: dấu bắt đầu và kết thúc chương trình dòng 6. Khái niệm hàm Một chương trình C với bất kì kích thước nào cũng đều bao gồm một hay nhiều hàm. Trong chương trình ví dụ trên.1.16 - .h> void main() { printf("Hello"). } Giải thích: dòng 1: chú thích. 7: thân chương trình Cụ thể các thành phần chưa được trình bày sẽ được nêu rõ ở các mục sau: 8. scanf() là các hàm. Khoa Tin học . 3: khai báo tệp tiêu đề.c /*chương trình hiện lên dòng chữ Hello trên màn hình*/ #include <stdio. dòng 4: hàm chính dòng 5.c sau đây: Số thứ tự câu lệnh 1 2 3 4 5 6 7 8 Mã chương trình hello.

… Khoa Tin học . dòng đầu tiên: /*chương trình hiện lên dòng chữ Hello trên màn hình*/ là lời chú thích. số khác nằm trong các thư viện của các chuẩn . Các đối số được đặt trong dấu ngoặc đơn ( ) ngay sau tên hàm.3 Chú thích Trong ví dụ trên.h. chương trình C luôn bắt đầu bằng thực hiện tại điểm đầu của hàm này. Điều này có nghĩa là mọi chương trình C đều phải có một và chỉ một hàm main() ở đâu đó trong chương trình. một số hàm nằm trong chương trình. Ví dụ: printf("hello"). hàm này không có đối. Chẳng hạn. Hàm này có tác dụng nhận một kí tự từ bàn phím (console).17 - . hàm sẽ cho hiện lên màn hình dãy kí tự tạo nên đối. dễ kiểm tra. chúng ta có sử dụng hàm printf() là hàm chuẩn được khai báo trong tệp stdio.2 Khai báo tệp tiêu đề Khi sử dụng các hàm trong các thư viện chuẩn. Hàm trả về kí tự nhận được. bảo hành.h> #include <conio. Mục đích của việc sử dụng lời chú thích là để chương trình dễ hiểu. printf() là một hàm có trong thư viện chuẩn được sử dụng. Một phương pháp truyền dữ liệu cho các hàm là thông qua danh sách các đối số. chứa được tất cả các kí tự và có thể trải dài trên nhiều dòng khác nhau trong chương trình. theo sau là danh sách các đối số được đặt trong dấu ngoặc đơn ( ). không cho hiển thị lên màn hình. Trong trường hợp không có đối ta vẫn phải viết dấu ngoặc này. giải thích mục đích của chương trình. Do đó. sửa. Trong trường hợp này. Xét một ví dụ khác: getch( ).h> 8. Mọi kí tự nằm giữa /* và */ đều được chương trình dịch bỏ qua. chúng ta phải khai báo tệp tiêu đề (header file) chứa hàm nguyên mẫu tương ứng của hàm đó. không phải viết lại. chương trình có hai dòng: #include <stdio. 8. hàm main() ví dụ trên. Do đó. là một lời gọi hàm có tên getch( ). Hàm được gọi bởi tên của nó. Hàm main() này thường gọi tới các hàm khác để thựchiện công việc của nó. là một lời gọi hàm có tên printf với đối ở đây là xâu ký tự "hello".Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang Riêng hàm main() là một hàm đặc biệt. Trogn ví dụ trên. Lời chú thích có thể nằm bất kì ở đâu trong chương trình nguồn. hàm này sẽ dừng màn hình kết quả sau khi chạy chương trình nên cho phép ta xem kết quả của chương trình cho đến khi ta nhấn một phím bất kì. đối với chương trình trên.h và hàm getch() được khai báo trong conio. việc khai báo tệp tieu đề được bắt đầu bằng chỉ thị #include và theo sau là tên tệp tiêu đề. có chức năng đưa kết quả ra thiết bị đầu ra (thường là màn hình).

Việc sử dụng sai "định dạng" có thể đưa tới các kết quả bất thường. …]). khi đó chương trình dịch sẽ bỏ qua các kí tự sau dấu // cho đến hết dòng đó. ta có thể đặt lời chú thích sau dấu //. kí tự. Ở dạng đơn giản nhất. Chẳng hạn. 8. Các giá trị trong danh sách phân cách nhau bởi dấu phẩy.…) tương ứng với một số " định dạng nhất định. một số nguyên có thể hiển thị dưới dạng thập phân hay thập lục hay hệ bát phân nhưng không thể hiểu đó là địa chỉ của bộ nhớ . Bảng 1. mỗi "định dạng" trong xâu điều khiển <format> là một cặp kí hiệu "%" và một ký hiệu mô tả định dạng. xâu ký tự. thực.h khai báo các hàm vào ra chuẩn (standard input output) khôn gphụ htuộc vào thiết bị và conio. VÀO RA Các chương trnh dịch C cung cấp cho người lập trình hai thư viện các hàm vào ra.<argument>. Mỗi loại dữ liệu (nguyên. Điều này có nghĩa là tương ứng với một kiểu dữ liệu có thể có nhiều hình thức trình bày khác nhau. trong đó.<argument>.Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang Ngoài ra. Số lượng các giá trị trong [.h (console input output) khai báo các hàm vào ra sử dụng với các thiết bị vào ra xác định như là bàn phím. nhưng không thể hiển thị nó dưới dạng một xâu kí tự hay số thục. Danh sách [. trong đó stdio.8 Một số định dạng dùng cho hàm printf Định Áp dụng cho Ghi chú dạng kiểu dữ liệu %d int đối là một số nguyên %i int đối là một số nguyên hệ 10 có dấu %o int đối là một số nguyên hệ 8 không dấu %u int đối là một số nguyên không dấu %x int đối là một số nguyên hệ 16 không dấu (không có 0x đứng trước) Khoa Tin học . Danh sách các hàm này có thể tìm thấy trong hai tệp tiêu đề là stdio.<argument>.18 - .…] nếu có sẽ chứa các giá trị (hằng.h. Sau đây là các hàm vào ra hay được sử dụng: 9. một kí tự có thể hiển thị dưới dạng nguyên thuỷ của nó là một kí hiệu trong bảng mã ASCII hay là số thứ tự của nó trong bảng mã. biểu thức) được đưa ra. trong trình soạn thảo C++. <format> là xâu "điều khiển" xác định cách thức hiển thị dữ liệu trên thiết bị ra chuẩn (thường là màn hình).1 Hàm printf() Cú pháp của hàm printf() như sau: int printf(<format>[.…] bằng số "định dạng" có mặt trong xâu "điều khiển" <format>.h và conio. màn hình. biến.8 liệt kê một số định dạng tiêu biểu: Bảng 1. nhưng không thể áp dụng một cách "tuỳ ý" các định dạng cho các giá trị bất kì. Để thực hiện chức năng này trong xâu "điều khiển" có chứa các "định dạng".

Nếu fw bắt đầu bằng 0 thì khoảng trống còn thừa trước giá trị số được in ra sẽ bị lấp đầy bằng số 0. ta bổ sung thêm một số thuộc tính nữa trong các "định dạng" như là độ rộng (số kí tự) cần thiết để trình bày dữ liệu. double float. %G %c %s int float. F đối được chuyển sang dạng thập phân dấu chấm động đối được chuyển sang dạng thập phân dấu chấm tĩnh đối được chuyển sang dạng thập phân dấu chấm tĩnh hay động tuỳ thuộc vào loại nào ngắn hơn đối là một kí tự đối là một xâu kí tự. ngược lại. sẽ hiển thị ra màn hình là: Khoa Tin học Để trình bày dữ liệu đẹp hơn. double float. 10). Hàm trả về số kí tự được hiển thị. Ví dụ sau đây minh hoạ cách sử dụng một số "định dạng" đã được đề cập.Giáo trình Ngôn ngữ lập trình C %X %e. giá trị của đối sẽ được canh phải trong khoảng quy định sự xuất hiện của kết quả cần đưa ra nếu độ rộng của đối (trường ra) nhỏ hơn độ dài quy định fw. sẽ hiển thị ra màn hình là: -10 printf("%o".pp] trong đó. [.9 sẽ cung cấp một số thuộc tính định dạng thưòng sử dụng: Thuộc tính Sử dụng với Ví dụ minh hoạ Kết quả định dạng Độ rộng tối thiểu %d printf("%6d". double char char* Trần Uyên Trang đối là một số nguyên hệ 16 không dấu với các chữ số là A. "Khoa Tin học"). -10). Bảng 1. E. [[0]fw]: fw là số nguyên quy định độ rộng cho trường ra (khác độ dài thực tế của trường ra). %lf %g. C. 10). ^^^^10 Khoa Tin học . Nếu trường ra có kiểu xâu thì. printf("%d". nếu pp >= độ dài xâu thì cả xâu được hiển thị.… Những thuộc tính như vậy được đặt giữa dấu % và kí tự định dạng. %E %f. double. căn lề dữ liệu bên phải hay bên trái. còn nếu pp < độ dài xâu thì chỉ có pp kí tự đầu xâu được hiển thị. [-]: nếu có dấu này thì giá trị của đối được canh trái. sẽ hiển thị ra màn hình là: 12 printf("%s".pp]: hiển thị pp chữ số thập phân nếu trường ra có kiểu float. D. Phần thuộc tính này có dạng tổng quát như sau: [-] [[0]fw] [.19 - . B.

<argument>. danh sách các giá trị cần đưa ra [. Chương trình printf1.10: Bảng mã một số kí tự điều khiển thường dùng DÃY GIÁ TRỊ TRONG BẢNG MÃ ASCII KÍ TỰ MÃ HỆ 16 HỆ 10 Đổ chuông (BEL) \a 0x07 7 Xoá trái (backspace BS) \b 0x08 8 Nhảy cách ngang (HT) \t 0x09 9 Nhảy cách đứng (VT) Xuống dòng mới (LF) Xuống dưới (FF) Về đầu dòng (CR) Mã NULL \v \n \f \r \0 0x0B 0x0A 0x0C 0x0D 0x00 11 10 12 13 0 Tóm lại.…] có thể chứa các hằng. 3."CNTT-ĐHSP"). …Bảng 1. Khi một "định dạng" không tìm thấy đối tương tứng hoặc khi kiểu dữ liệu của giá trị đưa ra không tương thích với kí tự định dạng thì máy sẽ nhầm và có thể đưa ra kết quả không như mong muốn. Bảng 1. 123.10 trình bày một số kí tự thường dùng. trong xâu điều khiển có thể chứa: − Các kí tự được thông thường. Các kí tự này được sử dụng để gấy một số hiệu ứng đặc biệt như xuống dòng ('\n').…] − Các kí tự điều khiển (có mã ASCII nhở hơn 32). Trần Uyên Trang 3.Giáo trình Ngôn ngữ lập trình C %f %s … %f printf("%6f".c sau đây minh hoạ cách sử dụng các "định dạng" đã được đề cập: c Kết quả chương trình trên như sau: 10 10 Khoa Tin học .145). các kí tự này được hiển thị cùng với giá trị của các đối trong phần [.455). printf("%s". nhảy trang ('\f'). Giá trị của đối số sẽ được chuyển dạng và in ra theo các "định dạng" tương ứng.46 Độ rộng dành cho phần thập phân (Ghi chú: dấu ^ đại diện cho kí tự trống) Bên cạnh các "định dạng". Cần nhắc lại là mỗi "định dạng" cần có một đối tương ứng. Số giá trị đưa ra phải bằng số "định dạng".20 - . biến hoặc biểu thức. … printf("%6.<argument>.145000 CNTT-ĐHSP 123.2f".

Cần nói thêm là.123400 12. …}.21 - . đối tương ứng phải là địa chỉ của một biến nguyên %c nhập vào một kí tự. Quá trình thông dịch của hàm scanf( ) được thực hiện bằng cách đọc lần lượt các kí tự số có trong stdin cho đến khi gặp một kí tự khác số.11 Bảng các định dạng dùng trong hàm scanf( ) Định Ý nghĩa dạng %d nhập vào một số nguyên. …}. Hàm scanf( ) Bảng 1. &i). Hàm scanf( ) có nhiều chức năng chuyển dạng giốngnhư hàm printf( ). rồi lưu trữ kết quả trong các đối có địa chỉ được mô tả trong phần {<address>. %o nhập vào một số nguyên hệ 8. Máy sẽ nhập từ bàn phím một số kí tự nạp vào trong một vùng bộ nhớ trong (gọi là vùng nhớ đệm bàn phím (stdin)). đối tương ứng phải là một xâu kí tự %f nhập vào một số thực float.Giáo trình Ngôn ngữ lập trình C -10 65526 12 a A 65 12.2 Hàm scanf() Cú pháp của hàm scanf( ) như sau: int scanf(<format>. biến đổi chúng theo khuôn dạng được xác định bằng các "định dạng" trong xâu điều khiển <format>. scanf("%d". đối tương ứng phải là địa chỉ của một biến nguyên %x nhập vào một số nguyên hệ 16. khi thực hiện các lệnh: int n. các kí tự số vừa được duyệt sẽ được sử dụng để tạok giá trị của một số nguyên và số nguyên đó sẽ được đặt vào vùng nhớ xác định bởi địa chỉ của biến n.12 1.212340e+01 Xau ki tu Trần Uyên Trang 9. đối tương ứng phải là địa chỉ của một biến thực Khoa Tin học . đối tương ứng phải là địa chỉ của một biến nguyên.{<address>. giá trị của biến n sẽ không bị thay đổi. đối tương ứng phải là địa chỉ của một biến kiểu kí tự %s nhập vào một xâu kí tự. nếu không tìm thấy các kí tự số trong quá trình duyệt stdin. Hàm này đọc các kí tự từ thiết bị vào chuẩn (thông thuờng là bàn phím). …}). Số lượng "định dạng" trong <format> cũng phải bằng số phần tử trong {<address>. Ví dụ.

printf("Nhap gia tri cho bien double: "). printf("\nHien thi lai:\nSo int:%d\nSo long int:%ld\nSo float:%f\ \nSo double:%f\nKi tu:%c". long l.c). scanf("%d". scanf("%ld". char c. dùng \ */ getch().h> #include<conio. } Kết quả chương trình như sau: Nhap gia tri cho bien int: 123 Nhap gia tri cho bien long int: 123456 Nhap gia tri cho bien float: 123. &f). &c). float f.456 Nhap gia tri cho bien double: 123. &n). scanf("%f". double d. f.22 - .h> void main() { int n. /* Xoá màn hình */ printf("Nhap gia tri cho bien int: ").c sau đây mô tả cách sử dụng hàm scanf( ) để nhập giá trị cho các biến: #include<stdio. printf("Nhap gia tri cho bien float: "). printf("Nhap gia tri cho bien long int: "). /* dòng lệnh dài hơn một dòng.n.456001 So double:123. l. scanf("%lf". scanf("%c". &l). printf("Nhap gia tri cho bien char: ").456 Nhap gia tri cho bien char: Hien thi lai: So int:123 So long int:123456 So float:123.Giáo trình Ngôn ngữ lập trình C %ld %lf nhập vào một số nguyên long int nhập vào một số thực double Trần Uyên Trang Chương trình scanf1. &d). d. clrscr().456000 Ki tu: Khoa Tin học .

&n). Nhận xét thứ nhất thực ra không quan trọng lắm vì nó phụ thuộc vào cách biểu diễn số thực trong máy tính. char c. − trước lệnh scanf( ). long l. Theo kinh nghiệm. ta ấn phím enter nên vùng đệm stdin sẽ chỉ có kí tự xuống dòng. clrscr().h> #include<conio. Dựa vào quy tắc thứ hai ta có thể giải thích hai nhận xét liên quan đến kí tự c trong chương trình scanf11. double d. scanf("%ld". scanf("%d". Nhận xét thứ hai và ba gắn liền với cách thức đọc vùng đệm bàn phím stdin của hàm scanf( ). dấu chấm '.h> void main() { int n. float f. Thứ hai. Khoa Tin học . dấu tab. Quy tắc 2: Khi đọc kí tựu. hàm scanf( ) cho rằng mọ kí tự có trong stdin đều hợp lệ. hàm scanf( ) quan niệm rằng tất cả các kí tự số. printf("Nhap gia tri cho bien long int: ").' là kí tự hợp lệ còn các dấu phân cách các số là: dấu trắng (space). Sau khi kết thúc nhập giá trị cho biến d. dấu xuống dòng. Quy tắc 1: Khi đọc một số. giá trị của biến kí tự c không nhìn thấy được (nghĩa là có mã ASCII nhỏ hơn 32). Thứ nhất. đế xoá sạch stdin. Xét ví dụ sau: #include<stdio.23 - . hàm scanf( ) sử dụng dấu phân cách như trong đọc số. Quy tắc 3: Khi đọc xâu kí tự. chương trình không đợi chúng ta nhập vào kí tự tương tứng với c.c ở trên. để nhập được đúng giá trị cho biến kí tự thì: − phải sử dụng một lệnh scanf( ) riêng cho mỗi lần nhập kí tự.Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang Ta có ba nhận xét về kết quả thục hiện của chương trình trên. Thứ ba. printf("Nhap gia tri cho bien int: "). Kí tự này sẽ được gán cho biến c. thực hiện lệnh sau: fflush(stdin). giá trị của biến f được in ra khác tí chút so với giá trị đã nhập vào. &l).

d.Giáo trình Ngôn ngữ lập trình C printf("Nhap gia tri cho bien float: "). --.n.24 - Khoa Tin học . &f). chúng được sử dụng với các với các toán hạng nào? Các toán tử này thuộc kiểu biểu thức nào? .c). printf("Nhap gia tri cho bien char: ").456001 So double:12455. scanf("%c". scanf("%f". getch(). printf("Nhap gia tri cho bien double: ").456 Nhap gia tri cho bien double: 12455. l. f. } Kết quả của chương trình này: Nhap gia tri cho bien int: 123 Nhap gia tri cho bien long int: 123 Nhap gia tri cho bien float: 123. printf("\nHien thi lai:\nSo int:%d\nSo long int:%ld\n\ So float:%f\nSo double:%f\nKi tu:%c". &d). Các cách dùng khác nhau của chúng? Cho biết số byte được cấp phát cho mỗi kiểu dữ liệu trong C? Các toán tử lôgic trong C.356000 Ki tu:c Trần Uyên Trang BÀI TẬP 1 2 3 4 5 6 7 8 9 10 11 Biểu thức là gì? Các thành phần của một biểu thức? Toán tử là gì? Nêu các loại toán tử có trong C? Toán hạng là gì? Mối liên hệ giữa toán hạng và toán tử? Nêu các loại toán tử số học trong C? Tổng quát hoá luật kết hợp giữa các toán tử? Làm thế nào để chuyển một giá trị trả về bởi biểu thức sang một kiểu dữ liệu khác? Thứ tự của các toán tử có ý nghĩa như thế nào? Nêu các mối liên hệ về thứ tự của các toán tử? Khi nào thì nên sử dụng dấu ngoặc trong biểu thức? Các toán tử được thực hiện theo thứ tự như thế nào trong một biểu thức có chứa các dấu đóng mở ngoặc lồng nhau? Cho biết tác dụng của toán tử ++. &c). scanf("%lf".356 Nhap gia tri cho bien char: c Hien thi lai: So int:123 So long int:123 So float:123. fflush(stdin).

8 b) 6.2) && (n .0.10) g) n < p j) x*(q = = 2) h) n >= p k) x*(q = 5) i) n > q l) (float)n/p Cho biết giá trị của x nếu: int x = 5. a) 6. 18 19 20 Tìm giá trị của x: float z .25 - . float x = 1.Giáo trình Ngôn ngữ lập trình C 12 13 14 15 16 17 Trần Uyên Trang Toán tử trên bit? Công dụng của toán tử lôgic not ( ! )và toán tử not bit (~). Hãy cho biết kiểu và giá trị của các biếu trức sau: d) n + q g) q + 3*(n > p) e) n + x h) q&&n f) n%p + q i) (q . Khoa Tin học d)?= . float y = 9. a) 1 b) 1. Hai toán tử này có giống nhau không? Với hai toán hạng khác kiểu thì một biểu thức gán được xác định như thế nào? Nguyên nhân gây ra lỗi trong trường hợp này? Nêu các phép gán trong C? Trật tự thực hiện chúng như thế nào? Để sử dụng các hàm thư viện của C.0 c) 7. long q = 2. z = (int)3.0 d) Không phải các giá trị trên.8 .75. p = 4.8 c) 2 d) Không phải các giá trị trên. Viết chương trình tính x mũ y.0 + (int) 3. phải khai báo gì trong chương trình? Hãy viết mục đích của các biểu thức sau: a) a . z = y/z.z.b d) a != b b) a*(a+b) e) (a/b)%5 c) d = a*(a+b) f) –h Giả sử có khai báo sau: int n = 10. 21 Toán tử nào không phải là toán tử gán: a) = b) += c) != 26.

nhỏ nhất trong bốn số đó bằng sử dụng các biểu thức điều kiện Khoa Tin học . ta làm gì? 30.26 - . Tìm giá trị lớn nhất .Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang Biểu thức (100>79) && (‘A’< ‘B’) có tương đương với 100>79&&‘A’< ‘B’? 27. Muốn biết hình dáng kí tự có mã ASCII là 222. Nhập vào bốn số thực.

ở đâu có thể đặt một câu lệnh đơn thì ở đó cũng có thể đặt một câu lệnh ghép (khối lệnh). Các lệnh thành phần trong lệnh ghép sẽ được thực hiện một cách tuần tựu theo thứ tự xuất hiện. là một lệnh đơn. Trong trường hợp không có phần else thì máy sẽ bỏ qua <lệnh_2> và chuyển điều khiển sang câu lệnh ngay sau lệnh if. CÂU LỆNH if Câu lệnh if được dùng để lựa chọn quyết định.27 - . CÂU LỆNH GHÉP Câu lệnh ghép là tập hợp các câu lệnh được bao bởi dấu { và }. Một cách hình thức. là lệnh rỗng. Chẳng hạn. không thể khai báo một biến nguyên sau khi gọi hàm xoá màn hình clrscr(). tăng giảm giá trị) kết thúc bởi dấu . Một lời gọi hàm đi sau bằng dấu . [else <lệnh_2>. bao gồm ba câu lệnh hợp lệ. Phần thân của một hàm cũng là một câu lệnh ghép. Ví dụ: x = 0. Biểu thức expr luôn phải được đặt trong dấu ngoặc ( ). chỉ có <lệnh_2> sẽ được thực hiện. cú pháp của câu lệnh như sau: if (<expr>) <lệnh_1>. Do vậy cho phép các lệnh if có thể lồng nhau. sau một khối lệnh mặc dù điều đó là không sai. Dấu . printf("\n"). 3. Về cú pháp. 2. Bản thân dấu .] Trong đó. dùng để kết thúc một câu lệnh đơn. Đây chính là cấu trúc lệnh tuần tự của các ngôn ngữ lẩptình cấp cao. Biểu thức expr được tính. Phần sau if hay else có thể là một câu lẹnh đơn. Trong một khối lệnh có thể có các khai báo biến và hằng (khác với Pascal) nhưng phải đảm bảo rằng các khai báo phải được đặt trước tất các câu lệnh. Do phần else của lệnh if là tuỳ chọn nên có thể xảy ra nhập nhằng khi một else bị bỏ qua Khoa Tin học . Lưu ý rằng không cần đặt dấu . cũng là một câu lệnh đơn.Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang CHƯƠNG 2 CÁC CÂU LỆNH ĐIỀU KHIỂN CHƯƠNG TRÌNH 1. lệnh ghép hay một cấu trúc điều khiển chương trình khác. x++. else là phần không bắt buộc. CÂU LỆNH ĐƠN Một biểu thức lệnh (gán. nếu nó đúng (có giá trị khác 0) thì <lệnh_1> được thực hiện và bỏ qua <lệnh_2> Trái lại.

28 - . sau đó tính a/b. khong chia duoc"). Để không gây nhầm lẫn. void main(){ float a. else z = b. printf("Nhap a va b: "). hoặc if (n){ if (a > b) z = a. else z = b.&b). hoặc dùng dấu { } để gắn else với if tương ứng. else z = b. else printf("b = 0.Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang trong một dãy các câu lệnh if lồng nhau.a/b). trong câu lệnh sau: if (n) if (a > b) z = a.4f". getch(). if (b) printf("a/b = %10.} Chú ý: vì lệnh if chỉ kiểm tra giá trị của biểu thức nên có thể viết gọn hơn nữa theo cách: if (expr) thay cho if (expr!=0) Ví dụ: chương trình if1.c cho phép nhập 2 số thực a và b. scanf("%f%f". Vấn đề được giải quyết theo cách thông thuờng như sau: else được gắn với if không có else gần nhất trước đó. } Kết quả như sau: Trường hợp 1: Nhap a va b: 0 10 Khoa Tin học . chẳng hạn: if (n) if (a > b) z = a.&a. Chẳng hạn. thì else sẽ luôn kết hợp với if bên trong. ta canh thẳng hàng else với if tương ứng. b.

getch(). int total = 0. Chu trình này được tiếp tục cho đến khi biểu thức expr có giá trị 0. &a. #include <stdio. (Câu lệnh được while của C được thực hiện giống câu lệnh while …do của Pascal. Nếu giá trị của biểu thức này khác 0 thì <lệnh> (thường được gọi là thân vòng lặp while) sẽ được thực hiện và biểu thức expr sẽ được tính lại.h> main(){ float a. khong chia duoc Trần Uyên Trang 4.0000 Trường hợp 2: Nhap a va b: 10 0 b = 0. &c). scanf("%f%f%f". printf("Total: %d". while (count<=10) total+=count++.Giáo trình Ngôn ngữ lập trình C a/b = 0. hay để đễ nhớ.h> #include<conio. Cách thức thực hiện lệnh while như sau: Đầu tiên. total). c. biểu thức expr được tính. while (a+b<=c || b+c<=a || a+c<=b) Khoa Tin học .29 - . CÂU LỆNH WHILE Cú pháp câu lệnh while như sau: while (expr) <lệnh>. &b. ta có thể tạm dịch câu lệnh này là "chừng nào biểu thức còn khác 0 thì còn thực hiện thân lệnh") Ví dụ 1: dùng vòng lặp while để tính tổng của các số từ 1 đến 10. b.h> main(){ int count = 0. printf("Nhap vao do dai ba canh cua tam giac:"). #include <stdio. } Kết quả: Total: 55 Ví dụ 2: chương trình sau đây sử dụng vòng lặp while để nhập ba số thực dùng làm số đo ba cạnh của một tam giác.h> #include<conio. Khi biểu thức expr có giá trị 0 thì việc thực hiện chương trình chuyển sang câu lệnh sau thân while.

điều kiện kết thúc trong vòng lặp repeat. Trái lại. Đối với repeat…until. … repeat write('n='). getch().until và do…while là ngược nhau. câu lệnh do…while kiểm tra tra điều kiện ở cuối chu trình. Hãy so sánh đoạn chương trình nhập vào một số nguyên dương bằng C và Pascal: int n. Khoa Tin học .30 - . Câu lệnh while kiểm tra điều kiện kết thúc vòng lặp ngay khi bắt đầu vòng lặp. &b. Do đó. Nói cách khác. có thể phần thân lệnh while không được thực hiện lần nào. &a. } printf("Duoc roi!"). ngược lại. sau mỗi lần đi qua thân chu trình. } Chương trình cho kết quả như sau: Nhap vao do dai ba canh cua tam giac:1 2 3 Chua duoc! Nhap lai:3 4 1 Chua duoc! Nhap lai:3 4 5 Duoc roi! Trần Uyên Trang 5. Câu lệnh do…while của C so với câu lệnh repeat…until của Pascal có một vài điểm khác biệt. CÂU LỆNH do…while Cú pháp câu lệnh do…while như sau: do { <lệnh> } while (expr). đối với do…while của C. ta lặp lại công việc khi biểu thức điều kiện sau từ khoá while có giá trị khác 0 (vẫn còn đúng). } while (n<=0). Do vậy. scanf("%d". vòng lặp còn được thực hiện chứng nào biểu thức điều kiện đi sau từ khoá until còn chưa đúng (nghĩa là sai). … do{ printf("n=")..Giáo trình Ngôn ngữ lập trình C { printf("Chua duoc!\nNhap lai:"). &c). readln(n). scanf("%f%f%f". n:integer. until (n>0). chu trình bao giờ cũng được thực hiện ít nhất một lần. &n).

chương trình sau đây vẫn "chạy" tốt: main() { int i=10. printf("Duoc roi!"). [expr2]. printf("Nhap vao do dai ba canh cua tam giac:").h> main(){ float a. getch(). &b. } Kết quả chương trình: Nhap vao do dai ba canh cua tam giac:1 2 3 Chua duoc! Nhap lai:1 2 4 Chua duoc! Nhap lai:3 4 5 Duoc roi! 6. c. b. do { scanf("%f%f%f". do{} while (i--). if (a+b<=c || b+c<=a || a+c<=b) printf("Chua duoc!\nNhap lai:"). &c). [expr3]) <lệnh> Khoa Tin học . } while (a+b<=c || b+c<=a || a+c<=b).Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang Phần thân câu lệnh repeat…until có thể là một dãy các lệnh tuy nhiên không cần sử dụng hai từ khoá xác định khối. } Chương trình sau đây sử dụng vòng lặp do…while để nhập ba số nguyên dùng làm độ dài ba cạnh của một tam giác.h> #include<conio.31 - . CÂU LỆNH FOR Cú pháp: for ( [expr1]. clrscr(). trái lại với do…while điều này lại bắt buộc ngay cả khi bên trong do…while không thực hiện bất cứ một lệnh nào. &a. #include <stdio.Chẳng hạn.

Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang Có thể diễn đạt cú pháp này bằng vòng lặp while như sau: expr1. biểu thức điều kiện expr2 được tính lại để kiểm tra sẽ thực hiện một vòng lặp nữa hay vòng for kết thúc. nhóm lệnh trong thân for được thực hiện. } Kết quả chương trình như sau: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 Có thể thấy rằng chương trình này được chuyển đổi từ chương trình Pascal sau: program for1. var i: interger. end. nếu cho giá trị khác 0. ta thấy rằng biểu thức expr1 được thực hiện đầu tiên và duy nhất một lần. expr1 và expr3 là các phép gán hoặc lời gọi hàm.i<=100. o expr3: thay đổi giá trị các biến điều khiển. Sau đó. vòng lặp for tính giá trị biểu thức quan hệ expr2. tiếp đến là thực hiện biểu thức expr3. expr3 là các biểu thức. còn expr2 là biểu thức quan hệ hoặc lôgic.i++) printf("%4d". expr2. Theo cách biểu diễn tương đương bằng vòng lặp while. expr1. trong đó: o expr1: khởi tạo giá trị ban đầu cho các biến điều khiển. while (expr2) { <lệnh> expr3. i). begin for i:=1 to 100 do write(i:4). o expr2: điều kiện để tiếp tục vòng lặp. sau đó. for (i=1. Thông thường. Một cách đơn giản. Khoa Tin học .32 - . có thể hiểu ý nghĩa của vòng for như như một vòng lặp với số bước xác định. #include<stdio. } Trong đó.h> main() { int i.

i*j). vòng for trong ngôn ngữ C có thể có nhiều biến điều khiển.65)(37.61)(41.56)(46.77) (25. } getch().71)(31. for (i=1. Cuối cùng.51) Về mặt cú pháp.j.70)(32. có tổng bằng 101.33 - .91)(11. for (i=1.i++.62)(40. printf("\n").52)(50.Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang Tuy nhiên.66)(36 .i<j.57)(45.j--) printf("(%d.98)(4.96)(6.85)(17. 88)(14.92)(10. một trong ba biểu thức thành phần của vòng for đều có thể vắng mặt.89)(13. Khi biểu thức expr2 không có mặt. clrscr().75)(27. Chương trình sau đây sử dụng vòng for với hai biến điều khiển để in ra từng cặp hai số trong phạm vi 100.58)(44.64)(38.i++) { for (j=1.67)(35.59)(43.j=100.87)(15.83)(19. getch().73)(29.99)(3. } Khoa Tin học .95)(7.82)(20. Có thể thoát khỏi vòng lặp vô hạn nhờ các câu lệnh ngắt như break hoặc return được đề cập ở các phần tiếp theo.i<=10.j.79)(23. nhưng phải có dấu .74)(28. cũng giống như các câu lệnh có cấu trúc khác.%d)".80)(22.76)(26.j).j++) printf("%5d".i.j<=10.h> main() { int i.90)(12.69)(33.93)(9.84)(18.h> #include<conio.100)(2.h> main() { int i.97)(5.72)(30. Trong nhiều trưòng hợp điều này còn làm cho chương trình dễ đọc hơn. thân của vòng for có thể chứa vòng for khác tạo thành các vòng for lồng nhau. } Kết quả chương trình như sau: (1. clrscr(). Điều đó làm mất đi tính chất "có số vòng lặp xác định nhưng lại tăng thêm tính mềm dẻo cho vòng for.94)(8.68)(34.63)(39.86)(16.78)(24.55)(47.54 )(48. thì ta coi biểu thức điều kiện luôn luôn đúng.81)(21.53)(49. #include<stdio. Xét ví dụ sau: /* In ra bảng cửu chương*/ #include<stdio.60)(42.h> #include<conio.

Sau đây là ví dụ dùng lệnh break để thoát ra khỏi vòng lặp do…while vô hạn: #include<stdio. }while (1). if (n>0) break.1 Lệnh break Trong một số trường hợp ta cần phải thoát khỏi một chu trình mà không cần thực hiện kiểm tra điều kiện lặp. &n).h> #include<conio. scanf("%d". CÂU LỆNH break VÀ continue 7. Câu lệnh break cho phép thoát ra khỏi các vòng lặp for. clrscr().Giáo trình Ngôn ngữ lập trình C Kết quả như sau: 1 2 3 4 5 6 7 8 9 10 2 4 6 8 10 12 14 16 18 20 3 6 9 12 15 18 21 24 27 30 4 8 12 16 20 24 28 32 36 40 5 10 15 20 25 30 35 40 45 50 6 12 18 24 30 36 42 48 54 60 7 14 21 28 35 42 49 56 63 70 8 16 24 32 40 48 56 64 72 80 9 10 18 20 27 30 36 40 45 50 54 60 63 70 72 80 81 90 90 100 Trần Uyên Trang 7. } Kết quả như sau: n= -12 Not OK! n= 0 Khoa Tin học .Câu lệnh break cho phép chương trình thoát ngay lập tức ra khỏi vòng lặp trong vùng chứa nó. printf("So duong!").h> main() { int n. getch(). do…while.34 - . do { printf("\nn= "). while. else printf("Not OK!").

n. n= 0 Lan nhap thu: 4.s=0. n= -10 Lan nhap thu: 2. s+=n. } Kết quả chương trình như sau: Lan nhap thu: 1. n= -10 Lan nhap thu: 3.h> #include<conio.35 - . &n). i++) { printf("\nLan nhap thu: %d. s). clrscr().Giáo trình Ngôn ngữ lập trình C Not OK! n= 5 So duong! Trần Uyên Trang 7. n= ". getch().h> main() { int i. printf("Da nhap mot so duong %d\n". i<=10. scanf("%d". n= 3 Da nhap mot so duong 3 Khoa Tin học . n). } printf("\nTong cac so duong: %d". Chương trình ví dụ sau minh hoạ cách sử dụng lệnh continue để in ra các số dương trong số 10 lần nhập. n= 0 Lan nhap thu: 7. for (i=1. if (n<=0) continue. n= 0 Lan nhap thu: 5. #include<stdio.i). n= 0 Lan nhap thu: 6.2 Lệnh continue Khi gặp câu lệnh continue chương trình không kết thúc nốt vòng lặp chứa nó mà bỏ qua các lệnh còn lại trong thân vòng lặp để bắt đầu một lần lặp mới.

số 50 và số 100 trong sô 10 lần nhập số nguyên.h> #include<conio. Câu lệnh switch tính giá trị của biểu thức số expr trong ngoặc và so sánh giá trị này với các giá trị đứng sau case. i++) { Khoa Tin học . c50=0.c100=0. #include<stdio. câu lệnh tương ứng với nhãn này được thực hiện nếu không có trường hợp nào thoả mãn. Nó kiểm trả xem một biểu thức expr có giá trị ứn với một trong số các giá trị hằng hay không và nhảy đến câu lệnh tương ứng khi so trúng. for (i=1. Nếu so trúng thì sẽ thực hiện nhóm lệnh tương ứng với trường hợp đó.h> main() { int i. clrscr(). chương trình sau đây đếm số lượng sô 1.c1=0. [break.]] } Câu lệnh switch cho phép ra quyết định nhiều nhánh hoàn toàn giống như câu lệnh case of của Pascal.n. case tương ứng với các trường hợp khác nhau. n= 0 Lan nhap thu: 9. Mỗi trường hợp đều được đánh nhãn bởi case. nếu không có sẽ không thực hiện gì cả.36 - . Chú ý rằng default là phần tuỳ chọn. [break. i<=10.] case <value3>: <lệnh3>. [break. n= 10 Da nhap mot so duong 10 Lan nhap thu: 10.Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang Lan nhap thu: 8.] [default : <lệnh> [break.] … case <valuen>: <lệnhn>. CÂU LỆNH switch Cú phápcủa câu lệnh switch như sau: switch (expr) { case <value1>: <lệnh1>. kí tự hoặc biểu thức hằng). [break. tiếp theo là một giá trị (nguyên. case và default có thể xuất hiện theo bất kì trật tự nào. n= 10 Da nhap mot so duong 10 Tong cac so duong: 23 8. Nếu có nhãn default.] case <value2>: <lệnh2>.

h> #include<conio. câu lệnh break tạo ra sự phân cách giữa các nhóm lệnh tương ứng với với các trường hợp khác nhau. n= 100 Lan nhap thu: 9.c1).c100). khi đo nhóm lệnh của các nhãn case đi trước sẽ bao gồm cả các lệnh của nhóm case đứng sau.break.c50). case 100: c100++. n= -10 Lan nhap thu: 6.i). Vd: Xét chương trình xác định số ngày trong một tháng dựa vào số hiệu chỉ tháng. switch (n) { case 1: c1++. scanf("%d". printf("\nSo lan nhap so 50: %d". break. case 50: c50++.37 - . Nếu muốn có nhiều nhãn case sử dụng chung một nhóm lệnh nào đó thì ta nên đặt chúng cạnh nhau. n= -12 Lan nhap thu: 5. n= 10 Lan nhap thu: 2.Giáo trình Ngôn ngữ lập trình C printf("Lan nhap thu: %d. #include<stdio. n= 100 So lan nhap so 1: 2 So lan nhap so 50: 1 So lan nhap so 100 Trần Uyên Trang Trong thân switch. printf("\nSo lan nhap so 100: %d". giữa các nhãn case này sẽ không đặt lệnh break. n= ".h> main() { int thang. n= 10 Lan nhap thu: 3. } Kết quả chương trình như sau: Lan nhap thu: 1. getch(). } } printf("\nSo lan nhap so 1: %d". songay. n= 1 Lan nhap thu: 7. break. Điều đó cho phé thoát ngay khỏi switch một khi các công việc tương ứng với một trường hợp đã thực hiện xong. n= 10 Lan nhap thu: 4. n= 1 Lan nhap thu: 10. &n). n= 50 Lan nhap thu: 8. Khoa Tin học .

break. In ra màn hình các dấu * theo các hình dạng sau: a) * ** *** **** ***** b) * ** *** **** ***** Khoa Tin học .break. &thang).Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang clrscr(). printf("Nhap vao so chi thang: ").38 - . BÀI TẬP 1. scanf("%d". switch (thang) { case 1: case 3: case 5: case 7: case 8: case 10: case 12:printf("Thang nay co 31 ngay"). case 2: printf("Thang nay co 28 hoac 29 ngay"). trường hợp cuối cùng sử dụng default. } Kết quả khi "chạy" chương trình như sau: Nhap vao so chi thang: 10 Thang nay co 31 ngay Vd: Với ví dụ trên kiểm tra số ngày trong tháng với trường hợp có năm nhuần và không có năm nhuần. case 4: case 6: case 9: case 11:printf("Thang nay co 30 ngay").break. } getch().

kiểm tra xem nó có phải số nguyên tố hay không. vuông hay thường. vuông cân. 2. sau đó xác định xem tam giác tương ứng có tính chất gì: đều. Nhập vào ba số thực dùng làm số đo ba cạnh một tam giác. In ra bảng mã ASCII.39 - . 4.Giáo trình Ngôn ngữ lập trình C c) * * * * * Trần Uyên Trang d) * * * * * e) * * * * * * * * * * * * f) * * * * * * * * * * * * 1. liệt kê tất các số nguyên tố nhỏ hơn n . Nhập vào một sồ nguyên dương n. Khoa Tin học . trong đó mỗi cột bao gồm kí tự và mã của kí tự đó dưới dạng thập phân / thập lục phân / bát phân . 3. Nhập vào một số nguyên dương. cân.

Nhập vào các số nguyên cho đến khi gặp 0. 9. kiểm tra xem số đó có phải số hoàn thiện hay không! (Số hoàn thiện là số có giá trị bằng tổng tất cả các ước số của nó không tính bản thân nó ) . đưa ra giá trị lớn nhất trong số các số chia hết cho 5 vừa nhập được . Nhập vào một nguyên dương.40 - . Nhập vào mốt số nguyên dương. Nhập vào một số nguyên dương n. Khoa Tin học . số lần nhập vào số 30. Đưa ra tổng các chữ số của số đó. Nhập vào một số nguyên dương. Cho biết số đó có bao nhiêu chữ số . Tính số lần nhập vào số 1. Nhập liên tiếp không quá n số tự nhiên. Nhập vào một số nguyên dương n. in ra số theo thự tự ngươc lại . 10. 8. số lần nhập vào số 50. 6. liệt kê các số hoàn thiện nhỏ hơn n . 11. 7.Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang 5. Nhập vào một số nguyên dương.

type là kiểu của các thành phần mảng. mảng mi sẽ được cấp phát 7*2 = 14 byte trong bộ nhớ. Ngôn ngữ C không giới hạn số chiều của mảng. 1.41 - .2. Nói cách khác.2 Truy nhập vào các phần tử của mảng Mỗi phần tử của mảng được truy nhập thông qua tên biến mảng và chỉ số tương ứng. array_name là tên mảng. Địa chỉ của vùng nhớ cấp phát cho biến mảng được xác định bởi tên của biến mảng. chiếm 32*1 = 32 byte. với khai báo mảng mi như trên. các phần tử này chứa dữ liệu thuộc cùng một kiểu. Trong khi đó mảng ten gồm 32 kí tự.2 Khai báo mảng 1. /* mảng số nguyên 7 phần tử*/ char ten[32]. Ta gọi những mảng được tạo ra bằng cách khai báo là mảng tĩnh để phân biệt với mảng được tự động tạo ra và xoá đi nhờ các công cụ cấp phát động. phần tử đầu tiên có chỉ số là 0.1 Mảng một chiều Nguyên tắc chung để khai báo một biến mảng như sau: <type> <array_name>[sizze]. trong đó.Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang CHƯƠNG 3 MẢNG VÀ CON TRỎ 1. Một mảng số nguyên gồm các phần tử là các biến số nguyên. MẢNG 1. ta có: mi[0] là phần tử đầu tiên mi[1] là phần tử thứ hai mi[2] là phần tử thứ ba … Khoa Tin học . size là số phần tử trong mảng. Chừng nào còn tồn tại thì tên mảng còn xác định và vùng nhớ dành cho mảng cũng cố định. /* mảng kí tự 32 phần tử*/ Kích thước của biến mảng được xác định dựa vào kiểu thành phần và số phần tử trong mảng. 1. Ví dụ: int mi[7]. tên biến mảng cho một giá trị mô tả địa chỉ đầu của mảng. Kích thước này phải được khai báo tường minh trong phần khai báo mảng vì nó xác định vị trí và kích thước của vùng nhớ trong bộ nhớ được cấp phát cho mảng. Kích thước của mảng chính là số các phần tử trong mảng. Mảng có thể có một hay nhiều chiều. Một mảng số thực bao gồm các phần tử là các biến thực. Chẳng hạn.1 Khái niệm và định nghĩa Mảng (array) là một dãy liên tiếp các phần tử trong bộ nhớ. Ví dụ.2.

Một điểm khác biệt giữa C là Pascal là ngôn ngữ C không đưa ra các kiểm tra về sự giới hạn chỉ số các phần tử của mảng. &temp1). Ta gọi đây là cách nhập trực tiếp (ii) Sử dụng một biến trung gian có cùng kiểu với các phần tử của mảng. có hai cách để thực hiện: (i) Sử dụng các hàm nhập (scanf( )) để nhập giá trị cho phần tử cần nhập. %mi[6]). mảng hai chiều các số nguyên thực chất là mảng một chiều có kiểu thành phần là mảng một chiều các số nguyên. ta có thể viết: tb[i] để chỉ một mảng 20 số thực nào đó trong tb còn tb[i][j] để xác định một số thực nào đó trong tb.Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang Để làm chỉ số cho mảng. mỗi phần tử của biến mảng ten được xem là một biến kí tự. Chẳng hạn. Ví dụ: int temp1. Chẳng hạn. 1. … scanf("%d". Tuy nhiên chương trình dịch C cũng không đưa ra bất kì cảnh báo nào nếu chúng ta viết mi[10] trong một biểu thức nào đó trong chương trình. Trước tiên ta nhập giá trị cho biến trung gian. m[6] là hợp lệ.3 Nhập dữ liệu cho biến mảng Về nguyên tắc. với mảng mi ở trên. Ví dụ: scanf("%d". biến. trong khai báo sau đây: float tb[10][20].42 - . 1. scanf("%f". &tb[2][1]). …. Chẳng hạn. sau đó gán giá trị của biến trung gian này cho phần tử cần nhập giá trị.2. về nguyên tắc chỉ có các phần tử mi[0]. ten[10] = 'Y'. float temp2. mi[1]. Trong khai báo mảng nhiều chiều ta phải mô tả kích thước của tất cả các chiều. biểu thức. Mỗi phần tử của biến mảng mi được xem như là một biến nguyên.1 Mảng nhiều chiều Ngôn ngữ C coi rằng một mảng nhiều chiều là một mảng một chiều trong đó mỗi phần tử là một mảng với số chiều không ít hơn một. mỗi kích thước như thế được đặt trong dấu ngoặc vuông [ ]. Ví dụ: ai[1] = 5. ta có thể xem tb như là một mảng một chiều có 10 thành phần và mỗi thành phần là một mảng chứa 20 số thực. Khoa Tin học . Như vậy. ta có thể dùng các đại lượng với giá trị là số: hằng.

i). trong khi đó vì áp dụng phép toán địa chỉ lên các phần tử của mảng nên một số trường hợp khi kiểu thành phần không phải là kiểu nguyên. /* nhập giá trị cho từng phần tử*/ for (i=0. i++){ printf("dayso[%d]=". scanf("%d". &dayso[i]). dayso[i]). i<n. /*ấn phím bất kì để kết thúc*/ getch(). i++) printf("%5d". tb[3][4] = temp2. cách thứ hai thường ổn định hơn.Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang mi[6] = temp1. không làm treo máy. scanf("%f". &temp2). /* dãy số có tối đa 100 phần tử*/ clrscr(). Ở đây ta có thể sử dụng một trong các vòng lặp của C để thực hiện công việc.i. Chương trình array. /*n là số phần tử của dãy số */ int dayso[100]. #include<stdio.h> void main(){ int n.h> #include<conio. } /*Hiển thị dãy*/ for (i=0. } Kết quả chương trình như sau: Nhap vao so phan tu: 102 Nhap vao so phan tu: -12 Nhap vao so phan tu: 5 Khoa Tin học . Theo kinh nhgiệm. } while (n<=0||n>=100). scanf("%d". i<n. Trong chương trình này ta sử dụng vòng lặp for. cách nhập trực tiếp có thể làm treo máy.c sau đây minh họa cách sử dụng mảng số nguyên để thực hiện: nhập và in ra một dãy số nguyên. &n).43 - . /*nhập số phần tử của dãy số */ do { printf("\nNhap vao so phan tu: ").

44 - .2 Vào ra với xâu kí tự ∗ Sử dụng printf( ) và scanf() Để nhập xuất xâu ký tự với scanf( ) printf( ) ta sử dụng định dạng ''%s'' trong xâu điều khiển. để bảo đảm việc nhập đúng nên sử dụng lệnh scanf(… ) riêng cho mỗi phần nhập xâu và trước mỗi lệnh đó nên sử dụng lệnh sau: Khoa Tin học .4 Xâu kí tự 1. một biến xâu kí tự muốn có chiều dài 9 phải được khai báo như một mảng kí tự có 10 phần tử. cộng xâu. nên được mã hoá bằng 2 byte.4. còn trong phần tham số đi sau ta sử dụng tên của biến xâu. Sự khác nhau giữa mảng kí tự và xâu kí tự là trong xâu kí tự có có kí tự kết thúc xâu là kí tự NULL hay '\0'.h. Để thực hiện việc này C cung cấp cho người lập trình một thư viện các hàm chuẩn là string.Giáo trình Ngôn ngữ lập trình C dayso[0]=12 dayso[1]=-102 dayso[2]=0 dayso[3]=2 dayso[4]=4 12 -102 0 2 Trần Uyên Trang 4 1. Trong C không tồn tại các phép toán so sánh. Ví dụ 'A' là kí tự A được mã hoá bằng 1 byte. Đây là căn cứ của các thao tác trên xâu như: tính chiều dài của xâu. Hình sau đưa ra một hình ảnh về nội dung xâu kí tự str: str[0] 'A' str[1] 'n' str[2] 'h' str[3] 'E' str[4] 'm' str[5] 'B' str[6] 'a' str[7] 'n' str[8] '\0' str[9] Hình 3. trong khi "A" là một xâu kí tự chứa kí tự 'A' và '\0'.1 Khai báo xâu kí tự Một biến xâu kí tự được khai báo tương tự như một mảng một chiều chứa các kí tự.1 Nội dung một xâu kí tự Cần phân biệt giữa kí tự và xâu kí tự một kí tự. 1. Chẳng hạn: char str[10].4.… Do đó. gán nội dung của xâu này cho xâu khác. Khi nhập xâu kí tự.

{0. -120}}. puts(str).2 Mảng nhiều chiều int a2i[3][4] = {{1. Khoa Tin học . Hàm gets( ) đọc từ bàn phím tất cả các kí tự và điền vào xâu str. getch(). 3.0. Khi lệnh gets( ) đi sau các lệnh nhập khác nên sử dụng thêm ffllush(stdin). 0. clrscr(). 2. } Kết quả chương trình như sau: Nhap vao mot dong: Dai hoc Da Nang Ban da nhap vao xau: Dai hoc Da Nang 1. -90.5. gets(str). 2. Khác với scanf( ) hàm gets( ) cho phép nhập cả các kí tự trắng trong nội dung của xâu. 0}. #include<stdio.5. Cú pháp sử dụng như sau: gets(str). Kết thúc việc đọc kí tự.Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang fflush(stdin). 4. 10. Hàm puts( ) in nội dung xâu kí tự str ra màn hình va thay thế kí hiệu '\0 ' kết thúc xâu bằng kí hiệu xuống dòng '\n'.1 Mảng một chiều int ai[7] = {1. -12.h> #include<conio. Chương trình sau đây minh hoạ cách sử dụng gets( ) và puts( ) để nhập và in xâu kí tự. printf("\nNhap vao mot dong: "). 1}. 1. phía trước để đảm bảo viêc nhập không bị sai . Việc đọc kết thúc khi máy gặp kí tự xuống dòng '\n' (sinh ra khi ta ấn phíp ENTER ).5 Khai báo và khởi đầu giá trị cho mảng 1. ∗ Sử dụng puts( ) và gets( ) Hai hàm này được khai báo trong tệp tiêu đề stdio. 9} {0. một kí tự '\0' được gắn thêm vào cuối xâu. puts(str).45 - . Chú ý rằng nếu ta nhập vào một xâu có kích thước lớn hơn hoặc bằng với kích thước mảng khai báo để chứa xâu thì máy sẽ bị lỗi. 12. printf("\nBan da nhap vao xau: ").h> void main(){ char str[81]. 3.h.

CON TRỎ 2. Chẳng hạn: int t[] = {1. chỉ những phần tử đầu tiên được gán giá trị.5. Kích thước của biến con trỏ phụ thuộc vào cách biểu diễn địa chỉ bộ nhớ trong máy tính. char *pc. Nói cách khác type* chính là một kiểu dữ liệu con trỏ. có thể khai báo nhiều biến trỏ liên tiếp nhau: int *pi.Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang 1. do đó. Ta có thể không cần mô tả đủ số lượng các giá trị trong danh sách. *qc. Khai báo một biến con trỏ theo mẫu sau : <type> *<ptr_name>. *qi. biến trỏ chưa chỉ đến địa chỉ nào cả và nó có giá trị bằng NULL. float *pf. kích thước biến con trỏ là 2 byte. Cũng có thể không cần mô tả số phần tử của biến mảng. tương ứng khai báo một mảng có số phần tử là 3. 10. Khả năng đó cộng với khả năng tính toán linh hoạt trên các con trỏ của C khiến con trỏ trở thành một công cụ rất mạnh để thực hiện nhiều thao tác mà thiếu nó thì không thể làm được hoặc làm rất khó khăn . 'b'. Thường thì người ta sử dụng hai thanh ghi 16 bit để biểu thị địa chỉ bộ nhớ. * Cách 2: char str[6] = "abc". *qf. Với câu lệnh khai báo trên. Việc sử dụng các biến con trỏ sẽ cho phép ta tham chiến đến một biến thông qua địa chỉ của nó. Khi đó chương trình dịch tự động xác định dựa vào danh sách giá trị mô tả kèm theo. ptr_name là tên của biến trỏ.46 - . Giống như khai báo biến. 20}. 2. NULL là một hằng số biểu thị giá trị của con trỏ khi chưa được gán địa chỉ nào. Khi đó. trong đó : type là kiểu dữ liệu của biến mà con trỏ chứa địa chỉ . đối tượng ở đây có thể là một biến hoặc một hàm mà khômg thể là một hằng. Khoa Tin học .2 Xâu kí tự * Cách 1: char str[6] = {'a'. 'c'}. các phần tử còn lại sẽ lấy giá trị ngẫu nhiên.1 Khái niệm và khai báo con trỏ Một con trỏ là môt biến/hằng có giá trị là địa chỉ của một đối tượng khác.

lấy giá trị của biến nguyên n được trỏ bởi pi. nếu không có. *pi. còn biến con trỏ có giá trị là địa chỉ của một biến. Như vậy lệnh: pi = &n. không thể gán giá trị của một con trỏ nguyên cho một con trỏ thực.p. chẳng hạn. Các lệnh sau đây là không hợp lệ: Khoa Tin học . Chú ý: Dấu ngoặc ( ) cần phải có trong ví dụ cuối cùng. ta sẽ có hai sách để mô tả giá trị của n. Nói cách khác: *pi tương đương với n. Phép toán này hoàn toàn tương đương với: ++*pi.y. không thể gán giá trị một con trỏ nguyên cho con trỏ thực mà không thực hiện phép chuyển kiểu.Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang Ngôn ngữ C quy định tương ứng với mỗi kiểu dữ liệu sẽ có một kiểu biến con trỏ riêng biệt. có tác dụng gán giá trị 3 cho biến n. *qi. 2. Như vậy.3 Các phép toán trên con trỏ 2. Còn *pi = *pi + 10.1 và 2. sẽ cho phép cả pi và qi xác định cùng một biến (biến n). tăng giá trị của đối tượng được trỏ bởi pi thêm 1. qi = pi.1 Phép gán trên hai con trỏ cùng kiểu Chỉ có thể gán địa chỉ một biến nguyên cho một biến trỏ nguyên. ch2. giữa các biến con trỏ khác kiểu nhau cũng có một số điểm khác biệt.… Giống như biến nguyên và biến thực.n. Khi đó ta nói rằng pi “chỉ đến” hoặc “trỏ đến” n.z. Cũng vậy. Toán tử một ngôi & cho ta địa chỉ của một biến. cộng thêm 10 và ghi kết quả trong m. Như vậy. là hợp lệ vì nó gán địa chỉ của biến nguyên n cho con trỏ nguyên pi. Như vậy chúng ta sẽ có con trỏ kiểu nguyên int* để chứa địa chỉ của biến nguyên. Điều này là do các toán tử * và ++ có cùng mức ưu tiên và được thực hiện từ phải sang trái. phép gán: m = *pi +10.47 - . Theo khai báo ở phần 2. và n là một. *pi=3.2 thì các lệnh sau: pi = &n. Vì vậy. thì thêm 10 vào n. char ch1. con trỏ kí tự char*. Khi pi trỏ đến n. còn: *pi+=1. hoặc trực tiếp bằng tên của biến hoặc bằng cách áp dụng toán tử một ngôi * lên biến con trỏ.3. chúng ta tăng giá trị của pi chứ không phải giá trị của đối tượng mà pi trỏ tới.2 Toán tử & và * Xét các khai báo biến sau: int m. con trỏ thực float* hay double* chứa địa chỉ của các biến thực. float x. Các toán tử một ngôi * và & có độ ưu tiên cao hơn các toán tử số học. (*pi)++. 2.

48 - . #include<stdio. /*vì pf là biến trỏ thực còn m có kiểu nguyên.n=100. &m.Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang pf = &m. m.n.*pc++). n.h> #include<conio. /*vì hai biến trỏ pf và pi không cùng kiểu. p=200. clrscr().h> void main(){ int n. &n. Khoa Tin học . getch(). scanf("%d".*/ pf = pi. Phép cộng con trỏ pi+1 sẽ cho ta địa chỉ của số nguyên m đi ngay trước n. byte thap 10 2. pf = (float*)&pi. Chúng ta cũng biết rằng pi chỉ đến n.h> #include<conio.p sẽ tương ứng với ba vùng nhớ 2 byte liên tiếp nhau. Tuy nhiên các lệnh sau thì hợp lệ nhờ phép chuyển đổi kiểu được thực hiện trước lệnh gán: pf = (float*)&m. *pc. pc = (char*)&n. printf("\nNhap vao mot so nguyen: "). pc+1 trỏ đến byte thấp */ printf("Byte cao %x. p là ba biến nguyên khai báo liên tiếp nhau. /* pc trỏ đến byte cao của n.3. } Kết quả sau khi "chạy" chương trình như sau: Nhap vao mot so nguyen: 16 Byte cao 0. clrscr(). &p). char *pc.2 chúng ta biết rằng m. int *pi= &n.&n). còn pi+(-1) sẽ cho ta địa chỉ của số nguyên đi liền sau n. printf("\nm=%d n=%d p=%d". Khi đó. Điều này được minh hoạ trong chương trình contro1. printf("\n&n=%p &m=%p &p=%p". m. Chương trình sau đây minh hoạ cách dùng toán tử chuyển kiểu bắt buộc để tính byte cao và thấp của một số nguyên.2 Phép cộng con trỏ với số nguyên Trong phần 2. n.c sau đây: #include<stdio. p).h> void main(){ int m=2. byte thap %x".

*pi).*(pi-1)). printf("\n*(pi+1)= %d". Thì hiệu: qi – pi có giá trị bằng 1.Biết địa chỉ của nhà này. printf("\n*(pi-1)= %d".3. printf("\n*pi = %d". 2. Điều đó có nghĩa là khi cộng hoặc trừ con trỏ với một số nguyên n. qi = &m.1 Con trỏ kiểu void Khoa Tin học . getch(). Chẳng hạn. Hằng con trỏ NULL luôn khác với mọi địa chỉ bộ nhớ và có thể đem so sánh với mọi biến con trỏ khác kiểu nhau. chia hai con trỏ. tiêu chuẩn so sánh dựa trên vị trí ô nhớ tương ứng với hai con trỏ. pi.4 Các phép toán quan hệ trên các con trỏ cùng kiểu Có thể so sánh các con trỏ cùng kiểu. 2. ta có thể tính địa chỉ của nhà bên cạnh bằng cách cộng thêm 1 hay trừ đi 1 vào địa chỉ của căn nhà đã biết và cứ thế tiếp tục.3 Phép trừ hai con trỏ cùng kiểu Do phép cộng một con trỏ với một số nguyên cho ta một con trỏ cùng kiểu. ta sẽ được một địa chỉ mới chỉ đến một biến khác nằm cách biến trước đó n vị trí. nhân. pi-1). Với hai con trỏ khác kiểu nhau. nếu muốn so sánh với nhau phải thực hiện phép chuyển đổi kiểu. không có phép cộng. Tuy vậy.Giáo trình Ngôn ngữ lập trình C printf("\npi =%p pi+1=%p pi-1=%p".4.*(pi+1)). nếu: pi = &n.4 Con trỏ void* 2. nên phép trừ hai con trỏ cùng kiểu được coi là hợp lệ và cho kết quả là một số nguyên biểu thị “khoảng cách” giữa các biến con trỏ.49 - . mỗi ngôi nhà là một biến có địa chỉ nào đó thì các địa chỉ này được đánh số tăng dần theo một chiều nhất định. pi+1.3. } Kết quả sau "chạy" chương trình như sau: m=2 n=100 p=200 &n=FFF2 &m=FFF4 &p=FFF0 pi =FFF2 pi+1=FFF4 pi-1=FFF0 *pi = 100 *(pi+1)= 2 *(pi-1)= 200 Trần Uyên Trang Việc cộng trừ một con trỏ với một số nguyên có ý nghĩa trực quan như sau: nếu ta so sánh con trỏ với địa chỉ các ngôi nhà trên một con đường. 2.

1 Con trỏ và mảng một chiều Xét lệnh: int a[10]. Trong khai báo biến trỏ đa cấp. …. a[9]. px = &x. 2. py = &y. do vậy nếu pi là một con trỏ nguyên thì phép gán sau đây là hợp lệ: pi = a. Khai báo này sẽ xin cấp phát một vùng nhớ cho 10 số nguyên a[0]. ….4. Ví dụ: int *pi. biến thực… Các lệnh sau đây là hợp lệ: void * px. Quả thực: pi[0]. vẫn có một số điểm khác nhau giữa tên mảng và biến trỏ cùng kiểu. int **ppi = &pi. 2. …. float y = 0. Số lượng dấu * xác định cấp của con trỏ. Người ta gọi những đối tượng có giá trị là địa chỉ của một biến con trỏ là con trỏ đa cấp. a[9] có địa chỉ xác định bởi a. …. a+9 tương ứng là địa chỉ của a[0]. a[1].1. Nói cách khác. a[9] còn .Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang Trong ngôn ngữ C. Một biến kiểu void không tương ứng với bất kì vùng nhớ nào. Vậy chính a là địa chỉ của biến nguyên a[0]. a[1].5 Con trỏ đa cấp Bản thân biến con trỏ cũng có địa chỉ. a[1]. do đó có thể chứa địa chỉ của nó trong một đối tượng khác. pi[9] tương ứng với a[0]. Không thể thực hiện các phép tính số học trên con trỏ kiểu void*. có một liên hệ mật thiết giữa việc đánh chỉ số trên mảng với tính toán trên con trỏ. Tên mảng là hằng địa chỉ còn biến con trỏ là biến. *py. …. int x = 1.50 - . dĩ nhiên ta có thể thực hiện các phép toán số học trên con trỏ pi. kiểu dữ liệu void là kiểu dữ liệu rỗng (empty type).2 Con trỏ kiểu void* Con trỏ kiểu void* có thể nhận địa chỉ của bất kì vùng nhớ nào dù đó là vùng nhớ tương ứng với biến nguyên. Không thể thực hiện các phép toán Khoa Tin học . Tuy vậy. 3. pi[1]. Điều này có thể giải thích được nhờ bản chất của các phép toán. a+2. a+1. người ta sử dụng một số dấu * trước tên biến trỏ. Sau phép gán này chúng ta có thể sử dụng pi như một tên mảng. LIÊN HỆ GIỮA CON TRỎ VÀ MẢNG 3.

e = 0.1 Con trỏ đa cấp và mảng nhiều chiều Con trỏ một cấp và mảng một chiều có nhiều điểm tương đồng. và cũng có thể sử dụng ppi như tên một biến mảng. 3. ta có thể thực hiện phép gán: ppi = a2.1 Mảng các con trỏ Khi kiểu phần tử của một biến mảng là kiểu con trỏ thì ta sẽ có một mảng các con trỏ. clrscr().h> void main(){ int i. int *ptr_array[6]. Con trỏ hai cấp là con trỏ chỉ đến con trỏ một cấp. d = 10. 3.j. Điều đó khiến cho chúng ta dường như đã có được một mảng đặc biệt gồm các biến mà vị trí thực sự của chúng trong bộ nhớ là bất kì. ptr_array[2] = &c. Chương trình array2. int a = 12. ptr_array[1] = &b. thì b = a.51 - . Mảng hai chiều là mảng một chiều của các mảng một chiều.h> #include<conio. Khoa Tin học . Cũng không thể thực hiện được phép gán trong đó tên biến mảng đứng một mình bên trái toán tử gán.*x. ptr_array[4] = &e. thì như vậy. Vì vậy có thể suy ra rằng giữa con trỏ hai chiều và mảng hai chiều cũng có nhiều điểm tương đồng. /* a là tên mảng khai báo ở phần trên*/ là sai vì không thể gán giá trị cho một hằng. Chẳng hạn với các khai báo: int **ppi. #include<stdio.f = 8. ptr_array[3] = &d. /*Gán các thành phần cho mảng */ ptr_array[0] = &a. chẳng hạn: int b[10]. b = 2.Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang tự tăng giá trị lên tên biến mảng. Suy luận này cũng có thể mở rộng cho các mảng và con trỏ nhiều mức hơn. Và bằng việc đổi chỗ các con trỏ thành phần này chúng ta có thể đổi thứ tự sắp xếp của các biến trong mảng này mà không cần thay đổi thực sự vị trí của chúng. chúng ta có thể truy xuất được các biến này thông qua một mảng mà không cần đến vị trí thực sự của các biến đó có liên tiếp hay không.c sau đây đưa ra một cách sắp xếp các số mà không tác động lên bản thân các phần tử được sắp xếp. c = 6. int a2[10][10]. Nếu các con trỏ thành phần trong mảng chỉ đến các biến nào đó.

getch(). Vì ta chỉ lưu địa chỉ của chúng nên việc sắp xếp lại thứ tự của các mảng này so với nhau thực chất chỉ là việc sắp xếp lại các địa chỉ của chúng trong mảng các con trỏ của chúng ta mà thôi. i<5. #include<stdio. int s[10]. n. ptr_array[i] = ptr_array[j]. Khoa Tin học . int i. int *pa[10]. i++) { pa[i] = a[i]. } Sau khi thực hiện.Giáo trình Ngôn ngữ lập trình C ptr_array[5] = &f. scanf("%d%d". chương trình cho kết quả: 0 2 6 8 10 12 Trần Uyên Trang Nếu các phần tử thành phần của mảng con trỏ lại được gán địa chỉ của các mảng khác thì ta sẽ được một mảng của các mảng. Không giống như các mảng hai chiều. int *ps[10]. printf("Nhap hai kich thuoc mang: ").h> #include<conio. i<6. j++) { if(*ptr_array[i]>*ptr_array[j]) { x = ptr_array[i]. for (i=0. clrscr(). ptr_array[j] = x. &n). i++) printf("%3d". j. Chương trình array3. i<m. i++) for (j=i+1.c sau đây in ra các hàng của ma trận theo thứ tự tăng dần của tổng giá trị trên từng hàng. j<6.52 - . /* Sắp xếp lại dãy số theo thứ tự tăng dần*/ for (i=0. m. các mảng con của chúng ta có thể nằm ở vị trí bất kì. &m. temp. } } /* In ra kết quả*/ for (i=0.h> void main(){ int a[10][10].*ptr_array[i]).

} for (i=0. printf("\n").a[i][j] = temp. j++) printf("%4d". &temp). j++) s[i]+=a[i][j].53 - . i++) { for (j=0. j<n. pa[i] = pa[j]. ps[i] = ps[j]. } for (i=0. for (j=0. for (i=0. j<n. pa[i][j]). } printf("\nMang a:\n"). i++) { s[i] = 0. i<m. } for (i=0. j++) printf("%4d". i. j++) if (*ps[i]>*ps[j]) { int *t. j<n. } printf("\nCac dong theo thu tu tang tong hang (pa): \n"). printf("\n"). i++) { for (j=0. t = ps[i]. pa[j] = t. i<m. for (i=0. } Khoa Tin học Trần Uyên Trang .Giáo trình Ngôn ngữ lập trình C ps[i]=s+i. i<m-1. scanf("%d". t = pa[i]. i<m. i<m. a[i][j]). j<m.j). ps[j] = t. i++) for (j=0. j++) { printf("a[%d][%d] = ". i++) for (j=i+1. } getch(). j<n.

các loại danh sách liên kết (DSLK). Khoa Tin học .h Cú pháp: malloc(size). Có nhiều cấu trúc dữ liệu sử dụng cách cấp phát động. stdlib. ta có thể liệt kê một vài loại như: cây. Giá trị trả về: Trong trường hợp cấp phát thành công. Hàm malloc( ) dùng để xin cấp một vùng bộ nhớ có kích thước size byte từ vùng nhớ heap. Vùng nhớ heap được sử dụng cho mục đích cấp phát động các khối nhớ có kích thước thay đối.h. hàm malloc( ) trả về trị NULL.1 Hàm malloc( ) Các tệp tiêu đề liên quan: alloc. vì khi không cần dùng tới nữa thì có thể giải phóng để cho các công việc tiếp theo có thể sử dụng được.Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang Kết quả sau khi thực hiện chương trình: Nhap hai kich thuoc mang: 3 2 a[0][0] = 70 a[0][1] = 90 a[1][0] = 100 a[1][1] = 0 a[2][0] = 10 a[2][1] = 40 Mang a: 70 90 100 0 10 40 Cac dong theo thu tu tang tong hang (pa): 10 40 100 0 70 90 4. cùng một vùng bộ nhớ có thể được sử dụng cho các mục đích khác nhau trong thời gian thực hiện của chương trình. Hàm này cho phép chương trình xin cấp phát vùng bộ nhớ đúng với kích thước mà chương trình cần. hàm malloc( ) trả về một con trỏ trỏ tới khối nhớ mới được cung cấp. Như vậy.54 - . 4. CẤP PHÁT ĐỘNG Ý nghĩa của việc cấp phát bộ nhớ động là cho phép chương trình sử dụng vừa đúng số lượng bộ nhớ mà chương trình cần. Trong trường hợp có lỗi (không đủ bộ nhớ để cấp phát).

/* cấp phát vùng nhớ cho ma trận*/ ppd = (double**) malloc(10*sizeof(double*)). phải sử dụng hàm farcalloc( ) (cấp phát xa). Hàm calloc( ) xin cấp một vùng bộ nhớ kích thước (nitems*size) byte và xoá trắng vùng nhớ này.size). hàm này trả về trị NULL. *qi.2. hàm malloc( ) trả về NULL. i++) ppd[i] = (double*)malloc(10*sizeof(double)). hàm calloc( ) trả về một con trỏ trỏ tới khối nhớ mới được cấp phát. Ví dụ: int *pi.h Cú pháp calloc(nitems. Ví dụ: int *pi. /* cấp phát vùng nhớ cho một mảng 12 số nguyên .h. double *pd. /* cấp phát vùng nhớ cho một mảng 12 số nguyên . Hàm calloc( ) Các tệp tin tiêu đề liên quan: alloc. Trong trường hợp có lỗi (không đủ bộ nhớ để cấp phát hoặc một trong hai tham số bằng 0). double *pd. /* cấp phát vùng nhớ cho xâu kí tự*/ pc = (char*)malloc(20). pd = (double*)malloc(10*sizeof(double)). i<0. Muốn xin cấp phát vùng nhớ có kích thước lớn hơn 64Kb. Trần Uyên Trang Chúng ta phải sử dụng phép chuyển kiểu đối với giá trị trả về của malloc( ) để đảm bảo các yêu cầu của phép gán. Giá trị trả về: Trong trường hợp cấp phát thành công. char *pc. Khoa Tin học . /* cấp phát vùng nhớ cho một số nguyên*/ qi = (int*)malloc(sizeof(int)). int i.55 - . double **ppd.mảng động*/ pi = (int*)calloc(12. int i.sizeof(int)). double **ppd.mảng động*/ pi = (int*)malloc(12*sizeof(int)). 4.Giáo trình Ngôn ngữ lập trình C Nếu tham số size bằng 0. for (i = 0. stdlib.

i<10. free(ppd). Ví dụ Chương trình free1. 4.h. calloc( ) hoặc realloc( ). scanf("%d%d". Trần Uyên Trang 4. for(i=1. i++) Khoa Tin học .sizeof(double)). printf("Kich thuoc ma tran: ").3. stdlib. &m.c sau minh hoạ cách sử dụng các hàm cấp phát động để tạo mảng động. double temp. Bạn đọc có thể xem thêm các chương trình trong phần trợ giúp của các chương trình dịch C. i++) free(ppd[i]).j. for (i=0. free(pi).n. clrscr().sizeof(double*)). /* cấp phát vùng nhớ cho ma trận*/ ppd = (double**)calloc(10.h Cú pháp free(address). ppd = (double**)calloc(m.Giáo trình Ngôn ngữ lập trình C /* cấp phát vùng nhớ cho một mảng 12 số thực. &n). Hàm free( ) giải phóng một khối nhớ đã được cấp phát trước đó bằng hàm malloc( ). free(pc).sizeof(double)). i<0. Hàm free() Các tệp tin tiêu đề liên quan: alloc.h> #include<stdlib.h> #include<alloc. Ví dụ: free(qi).h> #include<conio. free(pd). #include<stdio. for (i = 0.mảng động*/ pd = (double*)calloc(12. int m.56 - . i<m. Địa chỉ vùng nhớ được giải phóng được truyền làm tham số của hàm free( ). int i.sizeof(double*)).4. i++) ppd[i] = (double*)calloc(10.h> void main() { double **ppd.

i<m. scanf("%lf". Một mảng là một nhóm các phần tử có cùng kiểu giá trị được lưu trữ kế tiếp nhau trong bộ nhớ. i++) for (j=0. bằng các câu lệnh nhập dữ liệu. j<n. Xâu kí tự là một mảng đặc biệt chứa các kí tự '\0' ở cuối xâu.Giáo trình Ngôn ngữ lập trình C ppd[i] = (double*)calloc(n. Chỉ số các phần tử tính từ 0. j). Ngôn ngữ C không tự động kiểm tra sự quá giới hạn kích thước của mảng. một hằng nguyên hay một biểu thức có giá trị nguyên. i<m.ppd[i][j] = temp. j++) { printf("ppd[%d][%d] = ".00 20. Khoa Tin học . i<m. i++) { for (j=0. i++) free(ppd[i]).57 - . } for (i=0.2f". } for (i=0. Các thành phần mảng có thể được khởi tạo theo ba cách: trong khi khai báo.00 Trần Uyên Trang 5. getch(). Chỉ số của phần tử mảng có thể là giá trị của một biến nguyên. sizeof(double)).ppd[i][j]). for (i=0. i. Một mảng kí tự có thể sử dụng để lưu trữ xâu kí tự. Truy nhập đến các thành phần mảng bằng tên biến mảng và chỉ số. j++) printf("%6. free(ppd).00 1.00 30.00 0. &temp). j<n. bằng các câu lệnh gán. printf("\n"). } Kết quả sau khi thực hiện chương trình: Kich thuoc ma tran: 3 2 ppd[0][0] = 10 ppd[0][1] = 20 ppd[1][0] = 30 ppd[1][1] = 40 ppd[2][0] = 0 ppd[2][1] = 1 10.00 40. TÓM TẮT Có thể lưu một danh sách các giá trị trong mảng.

Độ lệch giữa hai con trỏ cũng giống như khái niệm chỉ số đối với mảng. +=. Khi thực hiện các thao tác số học đối với con trỏ trên mảng kí tự. -. có các loại biến con trỏ khác nhau.(trên các con trỏ). Tên mảng là một hằng con trỏ chỉ đến phần tử đầu tiên trong mảng (phần tử thứ tự 0). Các con trỏ có thể được so sánh với nhau theo các toán tử so sánh. -. Toán hạng ở đây là một biến nào đó và không phải là biến kiểu thanh ghi (register). Một con trỏ có thể được đánh chỉ số như mảng. Có ba giá trị có thể sử dụng để khởi tạo cho một biến coc trỏ: 0. +. Các thao tác số học có thể thực hiện trên con trỏ là ++. (i) không sử dụng mảng con trỏ (ii) có sử dụng mảng các con trỏ. Chỉ có một số nguyên có thể gán được cho con trỏ đó là 0. Tương ứng với các kiểu dữ liệu khác nhau. -=(giữa con trỏ và một số nguyên) Các thao tác số học trên con trỏ chỉ được thực hiện trên một phần bộ nhớ liên tục chẳng hạn như một mảng. -=. Toán tử * tham chiếu nội dung của một của đối tượng mà toán hạng của * trỏ tới trong bộ nhớ. Một con trỏ void không áp dụng được phép toán *. Ý nghĩa của các phép so sánh giống như các phép so sáng thông thường. Có thể gán giá trị của một con trỏ cho một con trỏ khác cùng kiểu. Có thể khai báo một mảng các con trỏ. Toán tử & trả về địa chỉ của toán hạng của nó. Khoa Tin học . Các con trỏ cần phải được khai báo trước khi sử dụng. Khởi tạo một con trỏ bằng 0 đồng nghĩa với khởi tạo NULL cho con trỏ.58 - .Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang Một xâu có thể được nhập bằng scanf( ) với mô tả %s hoặc bằng hàm gets( ) và có thể được hiển thị bởi hàm printf( ) với định dạng %s hoặc puts( ). NULL hoặc một địa chỉ. Con trỏ là biến chứa địa chỉ của các biến khác. kết quả thu được giống như đối với các thao tác số học thông thường bởi vì mỗi kí tự được lưu trữ một byte trong bộ nhớ.

Chúng ta sẽ bàn đến cả hai loại trên trong chương này. Kinh nghiệm cho thấy rằng cách tốt nhất để phát triển và bảo trì các chương trình lớn là xây dựng chúng từ những mảnh nhỏ hơn hay các mô đun.59 - . các biến định nghĩa trong chương trình con là các biến cục bộ. Các hàm chuẩn trong thư viện của C cung cấp rất nhiều các thao tác tính toán. vào/ra và nhiều thao tác thông dụng khác. Các tham số của chương trình con nói chung cũng được xem như các biến cục bộ. cài đặt.GIỚI THIỆU 1.''chia để trị'' giúp cho việc phát triển các ứng dụng dễ dàng hơn. Mô đun hoá chương trình có nhiều ưu điểm. Ưu điểm thứ ba là tránh việc lặp đi lặp lại các đoạn mã trong chương trình. Nói chung.2 Các mô đun chương trình trong C Các mô đun trong C được gọi là hàm. nhưng các hàm này không thay đổi trong các chương dịch C khác nhau. thao tác trên xâu kí tự. Chương này mô tả các đặc tính của ngôn ngữ lập trình C trong quá trình thiết kế. Các tham số cung cấp thông tin truyền giữa các chương trình con. Các chương trình C nói chung được viết bằng cách kết hợp các hàm mà lập trình viên tự viết với các hàm chuẩn trong thư viện của C. Hầu hết các chương trình con đều có các tham số. Việc gói các đoạn mã vào trong chương trình cho phép cả đoạn mã đó thực hiện ở nhiều nơi trong chương trình chỉ với một lời gọi hàm đơn giản. chúng chỉ được biết trong bản thân chương trình con tại đó chúng được định nghĩa. 1. Mặc dù các hàm trong thư viện chuẩn không là một phần trong ngôn ngữ lập trình C theo chuẩn ANSI C. Một ưu điểm nữa là tính sử dụng lại. Khoa Tin học . nghĩa là khả năng dùng các chương trình con có sẵn như các khối cơ bản để xây dựng lên các chương trình mới. Chúng làm cho công việc của các lập trình viên dễ dàng hơn vì các hàm này đưa ra rất nhiều khả năng cho các lập trình viên. Các hàm printf ( ) hay scanf( ) … mà chúng ta dùng trong các chương trình trước đây chính là các hàm thư viện chuẩn. hoạt động và bảo trì các chương trình lớn.Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang CHƯƠNG 4 HÀM 1. Các chương trình con cho phép lập trình viên mô đun hoá chương trình. Trước tiên. Khi đó việc quản lí sẽ dễ hơn đối với chương trình ban đầu. thao tác trên kí tự.1 Tổng quát về chương trình con Hầu hết chương trình máy tính giải quyết các vấn đề trong thực tế đều lớn hơn rất nhiều so với các ví dụ được giới thiệu trong cuốn sách này.

Bình thường các hàm được gọi trong chương trình bằng cách viết tên hàm. 1. Hàm sqrt( ) nhận các tham số kiểu double và trả lại giá trị là số kiểu double.0 pow(2. 2.y) fmod(x. các lời gọi hàm xác định tên của hàm và cung cấp các thông tin (hay còn gọi là các tham số) theo đúng trình tự khi khai báo hàm đó.718282 log(2. Các hàm được gọi thực hiện bằng các lời gọi hàm. Một vài hàm trong thư viện các hàm toán học của C được tổng kết trong bảng 4.0 log10(1. Tiếp sau câu lệnh sẽ in ra 30. Ví dụ để tính và in ra căn bậc hai của 900. có tham số hoặc danh sách tham số cách nhau bởi dấu phẩy được đặt trong cặp dấu ngoặc đơn.2f".718282) bằng 1. Chúng ta sẽ sử dụng thư viện các hàm toán học ở đây để giới thiệu các khái niệm về hàm. Các hàm loại này đôi khi còn được gọi là hàm người dùng định nghĩa.0 = 25.00.992 sin(0. d = 3.2f". Trong các phần sau.0) bằng 0.0)).Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang Lập trình viên có thể viết các hàm thao tác các công việc xác định dùng tại nhiều nơi trong chương trình.8) bằng -9 floor(-9.0 nếu x ≥ 0 thì fabs(x) bằng x nếu x ≤ 0 thì fabs(x) bằng -x ceil(9.0)).3 Giới thiệu thư viện các hàm toán học Thư viện các hàm toán học (khai báo trong tệp tiêu đề math.0 trong dấu ngoặc. Số 900.0 floor(9.00 Hàm sqrt(x) exp(x) log(x) log10(x) fabs(x) ceil(x) floor(x) Ý nghĩa căn bậc hai của x hàm ex logarith tự nhiên (cơ số e) của x logarith thập phân (cơ số 10) của x giá trị tuyệt đối của x làm tròn thành số nguyên nhỏ nhất lớn hơn x làm tròn thành số nguyên lớn nhất nhỏ hơn x x mũ y (xy) Ví dụ sqrt(9. ví dụ nếu cl = 13. các hàm khác sẽ được đề cập tới.h) cho phép lập trình viên thực hiện các thao tác toán học cơ bản.333) bằng 1.8) bằng 9.0) bằng 2.0 là 5.0 ceil(-9.0 log10(10.0 thì câu lệnh: printf("%. hàm căn bậc hai sqrt( ) được gọi để tính căn bậc hai của số 900.1.0) bằng 0.0 + 3.00) bằng 3 exp(1. sqrt(900. Các tham số của hàm có thể là các hằng.8) bằng -10. sqrt(c1+d*4.0.0 * 4.5) bằng 32 fmod(13.0 là tham số của hàm sqrt( ). biến hay các biểu thức.657.60 - pow(x. sẽ tính và in ra căn bậc hai của 13.0 ta viết: printf("%.0 . Khi câu lệnh trên được thực hiện.0) bằng 1.y phần dư của phép chia x cho y ) sin(x) sin của x (x tính theo radian) Khoa Tin học .2) bằng 10.

0) bằng 1.0) bằng 0.61 - . Hàm này gọi các hàm khác để thực hiện công việc của chương trình. #include<stdio.0 Bảng 4.1 Một ví dụ Mỗi chương trình đều có một hàm chính main (). return y.1 Các hàm thường dùng trong thư viện chuẩn các hàm toán học 2. y = x*x.0 tan(x) tan của x (x tính theo radian) tan(0. KHAI BÁO VÀ ĐỊNH NGHĨA HÀM 2./* khai báo hàm nguyên mẫu */ main() { int i.square(i)). i++) printf("%d ". sau đó nó tính x*x rồi kết quả được trả lại cho hàm printf() trong hàm main(). Khoa Tin học . Chương trình ví dụ funcl. } /* định nghĩa hàm */ int square(int x) { int y.i<=10. getch().h> #include<conio.square(i)). sau cùng printf( ) hiển thị kết quả ra màn hình. Nó nhận một bản sao giá trị của i trong tham số hình thức x. for(i=1.c dùng hàm square() để tính bình phương các số nguyên từ 1 đến 10. Quá trình này lặp đi lặp lại 10 lần trong vòng lặp for.h> int square(int). clrscr(). Ta sẽ xem xét cách viết một hàm.Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang cos(x) cos của x (x tính theo radian) cos(0. } Kết quả khi thực hiện chương trình: 1 4 9 16 25 36 49 64 81 100 Hàm square( ) được gọi thực hiện trong hàm main() trong câu lệnh: printf("%d ". nơi mà hàm square() được gọi.

Khi tham số truyền cho hàm khác kiểu nguyên hoặc không tự động chuyển sang kiểu nguyên thì chương trình dịch sẽ đưa ra thông báo lỗi. Hãy xem một số thí dụ định nghĩa hàm trong bảng 4. C chỉ không cho phép hàm trả về giá trị là một biến mảng. các câu lệnh } Trong đó. <tên-hàm> là bất kỳ tên (identifier) hợp lệ nào. Nếu không xác định <kiểu-giá-trị-trảvề> thì trình biên dịnh sẽ ngầm định coi đó là int. Từ khoá int đặt trước tên hàm cho thấy hàm square( ) trả lại kết quả là hàm số nguyên. Khai báo hàm sẽ nêu chi tiết hơn trong phần 2. Chương trình biên dich sẽ tham khảo dòng khai báo hàm để kiểm tra xem các tham số trong các lần gọi hàm square( ) có đúng như mô tả không. Câu lệnh return trong hàm square( ) trả kết quả tính toán được lại cho hàm gọi nó. Từ khoá int trong ngoặc thông báo cho trình biên dịch biết hàm square( ) nhận một tham số là số nguyên do hàm gọi nó truyền cho.2.2 Tổng quát về định nghĩa hàm Khuôn dạng của phần cài đặt hàm có dạng: [<kiểu_giá_trị_trả_về>] <tên_hàm>([<danh_sách_tham_số>]) { các khai báo …. Dòng int square (int). Khác với Pascal. Nếu <kiểu-giá-trị-trả-về> là void thì hàm không trả lại giá trị nào cả. Từ khoá int bên trái tên hàm thông báo cho trình biên dịch biết hàm square( ) trả lại kết quả là một số nguyên do chương trình gọi nó. chính là dòng khai báo hàm (function prototype . 2.3.Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang Định nghĩa hàm square( ) cho thấy hàm này nhận một tham số nguyên x. Khoa Tin học . còn mọi kiểu dữ liệu hợp lệ khác đều có thể sử dụng để mô tả kiểu giá trị trả về cho hàm.62 - . <kiểu-giá-trị-trả-về> là kiểu dữ liệu của kết quả trả lại cho hàm gọi nó.hay còn gọi là nguyên mẫu của hàm).

khai báo và cài đặt một hàm lại không được nằm trong một hàm khác. Có một số cách để trả lại quyền điều khiển tại điểm mà hàm đó được gọi. Ba số nguyên ban đầu được nhập vào từ bàn phím bằng hàm scanf( ).c sau đây sử dụng hàm max( ) do người sử dụng định nghĩa để trả lại số nguyên lớn nhất trong ba số nguyên.63 - . Tham số truyền cho hàm là một mảng 20 phần tử kiểu thực. Bảng 4. hàm trả về giá trị là một kí tự.Giáo trình Ngôn ngữ lập trình C float fct1(float t[20]) { … } float ftc2(float *t) { … } char ftc3(int a. hàm trả về giá trị là một số thực. int b) { … } Trần Uyên Trang hàm trả về giá trị là một số thực.2 Một số ví dụ định nghĩa hàm Các khai báo và các câu lệnh trong cặp dấu { } tạo thành phần thân của hàm. Nếu hàm không trả lại giá trị thì quyền điều khiển được trả lại khi gặp dấu đóng ngoặc } cuối cùng của hàm hoặc khi thực hiện câu lệnh: return. Tham số truyền cho hàm là một biến mảng thực hoặc một con trỏ thực. Tuy nhiên. Một khối đơn giản là một câu lệnh ghép có cả phần khai báo trong đó. sẽ trả lại trị tính được của biểu thức cho hàm gọi nó. Phần thân của hàm còn gọi là khối. Sau đó chúng được truyền cho hàm Khoa Tin học . Tham số truyền cho hàm là hai số nguyên. Chương trình func2. Nếu hàm trả lại kết quả thì câu lệnh return biểu_thức. Các biến có thể khai báo trong bất kì khối nào và các khối có thể lồng nhau.

} /* định nghĩa hàm max*/ int max(int x. printf("Nhap ba so nguyen: ").64 - . số lượng và kiểu và thứ tự các tham số được truyền cho hàm. int.&a. Hàm nguyên mẫu của hàm max( ) trong chương trình func2. int z) { int max=x. int. largest = max(a. if (z>max) max = z. Chương trình biên dịch dùng hàm nguyên mẫu để kiểm tra các lời gọi hàm.Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang max( ) để xác định số lớn nhất. &c). #include<stdio. scanf("%d%d%d".largest. return max.h> #include<conio.largest). Hàm nguyên mẫu thông báo cho chương trình biên dịch biết kiểu dữ liệu hàm trả lại. Giá trị này được trả lại vào biến largest trong hàm main( ) bằng lệnh return trong hàm max( ). int). Các phiên bản C trước đây không thực hiện quá trình kiểm tra này nên có thể xảy ra nhiều lỗi.3 Hàm nguyên mẫu Mộ trong những đặc trưng quan trọng của ANSI C là hàm nguyên mẫu (dạng hàm)./* hàm nguyên mẫu */ void main() /* hàm main*/ { int a. printf("So lon nhat la: %d". &b. int).b.h> int max(int. Giá trị trong biến largest này sau đó được in ra trong câu lệnh printf. khi thực hiện ứng dụng rất khó phát hiện. getch(). } Kết quả khi thực hiện chương trình: Nhap ba so nguyen: -12 90 0 So lon nhat la: 90 2.c là: int max(int. if (y>max) max = y.b. Khoa Tin học .c). Chú ý rằng hàm nguyên mẫu giống dòng đầu tiên trong phần định nghĩa hàm nhưng có thể không cần tên các tham số hình thức. Hàm nguyên mẫu trên thông báo rằng max( ) nhận ba tham số kiểu int và trả lại kết quả kiểu int. chẳng hạn do truyền sai thứ tự các tham số. int y.c. clrscr().

h có thể đưa vào trong chương trình của ta bằng chỉ thị #include<square. nghĩa là chuyển các tham số truyền vào theo các kiểu thích ứng.h ctype. Các tệp tiêu đề này cũng thường có phần mở rộng là .h các giới hạn của hệ thống locale. Ví dụ tệp tiêu đề square. khi đó trình biên dịch sẽ không phát hiện được các lỗi về truyền sai tham số và sai kiểu trả về của hàm. limits.h các hàm và các thông tin liên quan đến việc thay đối ngôn ngữ và mã nước của chương trình đang chạy math. Khi gặp lời gọi hàm trước tiên.000. Vấn đề này được nêu rõ ở chương "bộ tiền xử lí".h các hàm nguyên mẫu của các hàm thư viện toán học setjmp.h các macro hiển thị các thông tin về lỗi float. Lập trình viên có thể tạo các tệp tiêu đề riêng của mình.h định nghĩa các macro làm việc với danh sách các tham số đối với Khoa Tin học .3 liệt kê một số tệp tiêu đề có thể dùng trong chương trình.3f". hay chuyển kí tự giữa chữ hoa và chữ thường.3 sẽ được mô tả chi tiết trong phần " bộ tiền xử lí".h các giới hạn của số dấu phẩy động của hệ thống. Hàm nguyên mẫu sẽ yêu cầu trình biên dịch chuyển số nguyên 4 thành số double 4.4 Các tệp tiêu đề (header file) Mỗi thư viện chuẩn tương ứng có một tệp tiêu đề chứa các khai báo của các hàm trong thư viện này cùng với các định nghĩa các kiểu dữ liệu khác nhau.Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang Khi gặp một lời gọi hàm không đúng theo hàm nguyên mẫu. Tệp *. Khái niệm macro dùng trong bảng 4.h các hàm nguyên mẫu và các macro điều khiển các điều kiện khác nhau có thể xuất hiện trong quá trình thực hiện chương trình. sẽ in ra giá trị 2. sqrt(4)). Nếu không có hàm nguyên mẫu. stdarg. các hằng dùng trong các hàm đó.h các hàm nguyên mẫu của các hàm cho phép bỏ qua lời gọi hàm thông thường và trả quyền điều khiển lại một vị trí khác signal. Một đặc tính quan trọng của hàm nguyên mẫu là khả năng ép kiểu các tham số. 2. trình biên dịch sẽ tự tạo ra hàm nguyên mẫu của hàm khi gặp hàm lần đầu tiên thông qua định nghĩa hàm hoặc lời gọi hàm.h và có thể sử dụng chỉ thị #include để thêm vào chương trình.h Nội dung các macro và thông tin trợ giúp lập trình debug các hàm nguyên mẫu của các hàm kiểm tra một số thuộc tính của các kí tự. Lỗi cú pháp cũng xuất hiện khi hàm nguyên mẫu và định nghĩa hàm khác nhau.65 - .h asset. trình biên dịch sẽ thông báo lỗi cú pháp. ví dụ câu lệnh: printf("%. hàm nguyên mẫu tương ứng sẽ có giá trị trả về kiểu nguyên int và không có một ràng buộc gì về danh sách các tham số.h> ở đầu chương trình.0 trước khi truyền cho hàm sqrt( ). errno. Bảng 4.

2 Truyền tham số trong C Trong C. các hàm nguyên mẫu và kiểu dữ liệu cho thao tác thời gian.h time. Mỗi tham số hình thức sẽ tương ứng đại diện cho một hàm số thực. Ta gọi đây là tham số hình thức vì thực tế chúng chỉ đóng vai trò ''người đại diện'' cho các tham số thực trong các lời gọi hàm. Chẳng hạn. lỗi mà các chương trình con thay đổi các biến toàn cục của chương trình gọi nó.c sau đây là một minh chứng cho nhận xét này. THAM SỐ TRONG LỜI GỌI HÀM 3.66 - . Vì vậy mọi sự thay đổi trong hàm trên bản sao sẽ không ảnh đến giá trị ban đầu của biến (nếu có) nằm trong hàm gọi.1 Một số khái niệm Tham số hình thức: khái niệm này chỉ đến các tham số được khai báo trong phần danh sách tham số trong định nghĩa hàm. nếu bên trong hàm được gọi có thay đổi đến tham số hình thức thì những thay đổi đó cũng tác dụng trên các than số thực tương ứng.Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang stddef. tất cả các tham số được truyền theo trị. Mỗi tham số thực tương ứng với một tham số hình thức. định nghĩa các kiểu chung dùng để thực hiện tính toán các hàm nguyên mẫu và các thông tin liên quan của các hàm thư viện vào/ra chuẩn các hàm nguyên mẫu và các thông tin liên quan của các hàm chuyển kiểu. Tham số thực (sự) : khái niệm này chỉ đến các thông tin được truyền cho hàm trong các lời gọi hàm. Trong trường hợp này tham số hình thức và tham số thực là một. nếu tham số hình thức được khai báo như là con trỏ thì tham số thực tương ứng phải là địa chỉ của một biến hoặc là tên của biến mảng. cung cấp bộ nhớ.h string.h stdio. … Bảng 4.h stdlib.3 Một số tệp tiêu đề của các thư viện chuẩn 3.h … những hàm mà số lượng và kiểu của các tham số là không biết. Chương trình swap1. một bản sao giá trị của tham số thực (có thể là giá trị của biến. hàm gọi sẽ truyền trực tiếp tham số đó (bắt buộc phải là biến) cho hàm được gọi. Kiểu dữ liệu của tham số hình thức sẽ quyết định kiểu giá trị cho tham số thực tương ứng. 3. Truyền theo tham biến chỉ nên dùng khi hàm bị gọi thật sự cần thiết thay đổi giá trị của biến truyền vào cho nó. Các lỗi này rất khó phát hiện. Điều này đôi khi dẫn đến hiệu ứng phụ. Khi tham số được truyền theo trị. hằng hay của một biểu thức) được tạo ra và gán cho các tham số hình thức của hàm. Khoa Tin học . tạo số ngẫu nhiên. ta phân biệt: truyền theo trị và truyền theo tham biến. Liên quan đến việc truyền thông tin cho hàm. Khi một tham số được truyền theo tham biến. Như vậy. Truyền theo trị được dùng bất cứ khi nào hàm bị gọi không cần thiết thay đổi giá trị biến mà hàm gọi truyền vào tham số cho nó.… các hàm nguyên mẫu của các hàm xử lí xâu. Điều này giúp tránh được hiệu ứng phụ.

y). có thể là địa chỉ của một biến hoặc tên của một biến mảng.h> void swap(int a.c trong đó các tham số hình thức trong hàm swap( ) là con trỏ.67 - . swap(x. int *b). y). int b).Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang #include<stdio. Còn khi truyền tên của mảng thì sẽ có hai cái lợi so với việc khai báo tham số hình thức như một mảng: thứ nhất tiết kiệm được thời gian sao chép dữ liệu. void main() { int x = 10.h> #include<conio. a = b. x. void main() { int x = 10. Khoa Tin học . } void swap(int a.3 Tham số hình thức của hàm là con trỏ Khi tham số hình thức của hàm là con trỏ thì tham số thực tương ứng phải là một địa chỉ. int b) { int temp. printf("Truoc khi goi swap: x = %d y= %d". thứ hai có thể thay đổi giá trị của các phần tử trong biến mảng được truyền vào. #include<stdio. Khi truyền địa chỉ của biến cho hàm người ta có thể tuỳ thích thay đổi giá trị của biến với địa chỉ được truyền. y = 20. b = temp. y). Sau đây giới thiệu một số chương trình minh hoạ. x. printf("\nSau khi goi swap: x = %d y= %d". } Kết quả thực hiện chương trình: Truoc khi goi swap: x = 10 y= 20 Sau khi goi swap: x = 10 y= 20 3.c sau đây là một phiên bản sửa đổi từ swap1.h> void swap(int *a.h> #include<conio. getch(). y = 20. clrscr(). Chương trình swap2. temp = a.

68 - . printf("An phim bat ki de ket thuc. } Kết quả thực hiện chương trình: Truoc khi goi swap: x = 10 y= 20 Sau khi goi swap: x = 20 y= 10 Trần Uyên Trang Chương trình func3. sapxepds(a). printf("\nIn day so: "). x.. #include<stdio.h> void nhapds(int *d). getch(). printf("Truoc khi goi swap: x = %d y= %d". clrscr(). } void swap(int *a.c sau đây thực hiện các thao tác nhập và in và sắp xếp một dãy số trong đó tên mảng được truyền như một tham số cho hàm. swap(&x. *a = *b."). printf("\nSau khi goi swap: x = %d y= %d". y).Giáo trình Ngôn ngữ lập trình C clrscr(). nhapds(a). x. void sapxepds(int *d). printf("\nNhap day so:\n"). int *b) { int *temp. *temp = *a.&y). void inds(int *d). inds(a). } void nhapds(int *d) { Khoa Tin học . inds(a). *b = *temp.. y).h> #include<conio. void main() { int a[5]. getch(). printf("\nDay so sau khi sap xep:\n").

d[i]).Giáo trình Ngôn ngữ lập trình C int i. i<5. j.. i++) printf("%4d". i<5.. i++) for (j=i+1.69 - . d[i] = d[j]. i<4. printf("\n"). i). int temp. for (i=0. } void sapxepds(int *d) { int i. for (i=0. Trần Uyên Trang Khoa Tin học .d[i] = temp. j++) if(d[i]>d[j]) { int temp = d[i]. i++) { printf("d[%d] = ". d[j] = temp. scanf("%d". for (i=0. } } void inds(int *d) { int i. j<5.&temp). } } Kết quả thực hiện chương trình: Nhap day so: d[0] = 10 d[1] = -90 d[2] = 2 d[3] = 7 d[4] = 100 In day so: 10 -90 2 7 100 Day so sau khi sap xep: -90 2 7 10 100 An phim bat ki de ket thuc.

clrscr().CẤP LƯU TRỮ VÀ PHẠM VI CỦA CÁC ĐỐI TƯỢNG 4.4 Tham số của hàm main( ) Chúng ta đề cập đến tham số của hàm main( ) khi viết chương trình có tham số dòng lệnh. argv[i]). for (i=0.i++) printf("Tham so thu %d la: %s". i<argc. Chương trình sau đây minh hoạ cách viết chương trình sử dụng tham số dòng lệnh. char *argv[]) { int i. i+1.Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang 3.70 - . Giá trị của agrc và nội dung của agrv được tự động xác định khi thực hiện chương trình. #include<stdio.exe I love you↵ thì chương trình được thực hiện và cho kết quả: Tham so thu 1 la: D:\TC\MAIN.exe. } Sau khi dịch và tạo ra file d:\tc\main. Các khai báo (và định nghĩa) này có thể được đặt ở ngoài tất cả các hàm hoặc ở bên trong một hàm nào đó (điều này chỉ đúng đối với các biến). Các khai báo đặt ở các vị trí khác nhau làm cho đối tượng được Khoa Tin học .EXE Tham so thu 2 la: I Tham so thu 3 la: love Tham so thu 4 la: you (↵ là kí hiệu của việc gõ phím enter) Chú ý: Trong môi trường soan thảo của Borland C hoặc Turbo C ta có thể đưa vào các tham số dòng lệnh cho chương trình nhờ lệnh Run / Arguments… 4. getch(). Tham số agrv là một mảng các xâu kí tự tương ứng với các tham số dòng lệnh.h> #include<conio.h> void main(int argc. char *argv[]) Tham số argc mô tả số lượng các tham số dòng lệnh bao gồm cả tên chương trình.1 Khái niệm Ta biết rằng mỗi đối tượng (biến hoặc hàm) sử dụng trong một chương trình cần phải có các khai báo (và định nghĩa). Tại cửa sổ lệnh nếu ta gõ: d:\tc\main. Trong trường hợp này hàm main( ) sẽ được khai báo với hai tham số hình thức: void main( int argc.

Từ khoá auto Từ khoá auto được dùng để khai báo các biến cục bộ. Một số đối tượng có thời gian tồn tại rất ngắn.71 - . static và register để chỉ định phạm vi và thời gian tồn tại của các biến. một hàm hoặc một tệp nguồn hoặc toàn thể chương trình. Thuộc loại này bao gồm các hàm và các biến khai báo bên ngoài các hàm. Tuy nhiên mặc dù biến và tên hàm tồn tại ngay khi bắt đầu chương trình nhưng không có nghĩa là đối tượng này có thể dùng bất cứ đâu trong chương trình. một số thì liên tục được tạo ra và xoá đi. Cấp lưu trữ của đối tượng được xác định dựa theo vùng bộ nhớ được cấp phát. sau đề nghị trình biên dịch đặt biến counter vào một trong các thanh ghi của máy và khởi tạo nó giá trị ban đầu bằng 1: Khoa Tin học . extern. Ví dụ. Ngôn ngữ C cung cấp 4 từ khoá sau: auto. thời gian tồn tại (lifetime) và cấp lưu trữ (storage class). do đó nâng cao tốc độ thực hiện (vì truy nhập. Các từ khoá extern và statis dùng để khai báo các đối tượng (biến hoặc hàm) có thời gian lưu trữ tĩnh và phạm vi toàn cục. Phạm vi có thể là trong một khối lệnh. các đối tượng được cấp phát bộ nhớ thường trực thì có cấp lưu trữ cố định (static). Sau khi một số đối tượng đã được khai báo (và định nghĩa) máy tính sẽ cung cấp cho biến hay hàm vùng nhớ thường trực hay động trong thời gian thực hiện chương trình. Phạm vi và thời gian tồn tại và cấp lưu trữ của một đối tượng được xác định bằng cách tổ hợp các từ khoá chỉ định cấp lưu trữ với các khai báo cùng vị trí đặt bên trong hay bên ngoài một hàm hay một khối lênh. Đối với hàm. Tuy nhiên rất ít khi người ta sử dụng nó vì các biến cục bộ đã mặc nhiên được xem là auto. tên của hàm cũng tồn tại ngay khi chương trình bắt đầu thược hiện.Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang khai báo có các tính chất khác nhau. Từ khoá register: Từ khoá register được đặt trước khi khai báo của các biến tự động nhằm yêu cầu chương trình biên dịnh duy trì giá trị biến đó trong thanh ghi của máy tính. chúng ta sẽ xem xét vấn đề này sau. một số khác tồn tại trong suốt thời gian thực hiện chương trình. Sự khác nhau đó thể hiện ở phạm vi sử dụng (scope). Đối với biến. vùng nhớ được cung cấp và được khởi tạo ngay khi bắt đầu chương trình. Các biến có cấp lưu trữ động được tạo ra khi vào khối mà chúng ta được khai báo. Bên cạnh đó cũng có một số biến cục bộ có thuộc tính này. thao tác dữ liệu trực tiếp trên thanh ghi máy tính là nhanh nhất). Các đối tượng (biến hoặc hàm) có cấp lưu trữ cố định tồn tại ngay khi chương trình bắt đầu thực hiện. chúng tồn tại khi điều khiển còn đang trong khối đó và chúng ta sẽ bị xoá khi quyền điều khiển thoát ra khỏi khối. Như vậy. Phạm vi của một đối tượng là phần chương trình mà đối tượng còn được nhìn thấy và có thể sử dụng bởi phần chương trình đó. Các từ khoá auto và register dùng để khai báo các đối tượng có cấp lưu trữ động và phạm vi cục bộ. một đối tượng có thể có thời gian tồn tại lâu dài hay tạm thời (so với thời gian thực hiện của chương trình). Chúng có thể chia thành hai nhóm theo thời gian tồn tại hay phạm vi.

Khoa Tin học . có thể khai báo khai báo các biến cục bộ tĩnh bằng cách đặt từ khoá static trước khai báo biến. Chỉ khi nào chương trình kết thúc các biến tĩnh mới được giải phóng khỏi bộ nhớ.h> #include<conio. Các biến loại này có ứng dụng trong việc viết những hàm cần phải bảo toàn một số giá trị giữa những lần gọi. Ví dụ: { ……. clrscr(). Từ khoá static Biến tĩnh là biến có thời gian tồn tại cùng với chương trình. void main() { int i. các biến tĩnh cục bộ không được nhận biết ở bên ngoài hàm khai báo chúng nhưng chúng vẫn duy truỳ được giá trị của chúng giữa mỗi lần gọi hàm. for (i=1. Theo định nghĩa. Chương trình biên dịch có thể bỏ qua từ khoá register khi không còn đủ thanh ghi nữa và nói chung chỉ áp dụng cho các biến kiểu int và char. i<10. Bên cạnh các biến ngoài. Cú pháp như sau: static <khai báo biến>. /* x là biến cục bộ tĩnh*/ … } Từ khoá static đi với biến cục bộ thông báo cho trình biên dịch biết cần cung cấp một vùng lưu trữ thường xuyên cho biến cục bộ này.Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang register int counter = 1.h> void fct(). các biến khai báo bên ngoài các hàm sẽ là biến tĩnh vì tồn tại độc lập với các hàm. static int x. Khác với biến toàn cục. có thể sử dụng trong mọi hàm miễn là hàm đó không khai báo các biến cục bộ cùng tên. các khai báo register thường cũng rất ít được dùng vì bộ tối ưu của trình biên dịch thường có khả năng nhận biết được các biến thường xuyên được sử dụng và đặt chúng vào các thanh ghi nếu thấy cần thiết mà không cần thiết có các từ khoá register trong chương trình nguồn.c sau đây minh hoạ cách sử dụng biến cục bộ static: #include<stdio. Ngày nay. Biến tĩnh được tạo ra khi chương trình khởi động khởi động chương trình. đây là điểm khác với biến cục bộ thông thường. Chương trình func4.i++) fct().72 - .

Bởi vì chương trình có thể do nhiều người cùng lập. ngầm định đều được khởi tạo giá trị bằng 0 (con trỏ thì khởi tạo giá trị NULL) Trong chương trình func4. } void fct() { static int count = 1.c. hiển nhiên là các chương trình nguồn phải được lưu trữ trên nhiều tệp khác nhau. y. char ch.count++). Nguyên tắc như sau: Chẳng hạn tệp A có chứa khai báo các biến toàn cục sau: int x. Từ khoá extern Các biến ngoài chỉ có thể sử dụng được trong các hàm định nghĩa trong tệp nguồn khai báo chúng. y. Khoa Tin học . Chú ý rằng tất cả các hàm đều là đối tượng ngoài vì ngôn ngữ C không cho phép một hàm được định nghĩa bên trong một hàm khác. Khi phát triển các ứng dụng lớn. printf("\nLan goi ham thu %d". nếu ta khai báo một biến toàn cục để lưu giá trị của count thì bất kì chương trình nào muốn sử dụng hàm fct( ) cũng phải xem xét việc khai báo biến đó. extern char ch. phải đảm bảo không có sự nhầm lẫn nào với các biến khác được khai báo và rất khó có thể đưa hàm này vào thư viện.Giáo trình Ngôn ngữ lập trình C getch(). Vậy làm cách nào các hàm ở một tệp này có thể truy nhập tới các biến được khai báo hoặc gọi tới các hàm được định nghĩa ở một tệp khác? Từ khoá extern cho phép sử dụng các biến hàm trên phạm vi nhiều tệp. đồng thời việc phân nhỏ chương trình nguồn còn làm tăng tốc độ biên dịch. } Kết quả thực hiện chương trình: Lan goi ham thu 1 Lan goi ham thu 2 Lan goi ham thu 3 Lan goi ham thu 4 Lan goi ham thu 5 Lan goi ham thu 6 Lan goi ham thu 7 Lan goi ham thu 8 Lan goi ham thu 9 Trần Uyên Trang Tất cả các biến có thời gian lưu trữ tĩnh. Tệp B muốn sử dụng các biến toàn cục ở trên tệp A thì cần khai báo: extern int x.73 - .

Khi các khối lồng nhau. Phạm vi của khối kết thúc khi gặp kí tự đóng ngoặc kết thúc khối }của khối đó. tuy nhiên có thể sử dụng các tệp đối tượng (*.3 Tệp project Khi viết các chương trình lớn người ta thường để các hàm trên nhiều tệp nguồn khác nhau. nó chỉ có thể được tham chiếu trong khối đó hoặc các khối lồng trong khối đó thôi.Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang Từ khoá extern thông báo với trình biên dịch rừng tên và kiểu của các biến đặt sau đã được khai báo ở đâu đó rồi. Các danh biểu khai báo trong khối có phạm vi trong khối đó. Ví dụ khi ta khai báo một biến cục bộ trong một khối. Khi liên kết. phạm vi trong khối và trong hàm nguyên mẫu.C hoặc các tệp viết trên ngôn ngữ Assembly. Nói cách khác.2 Bốn kiểu phạm vi trong chương trình C Phạm vi của một đối tượng (biến hay hàm) là phần của chương trình mà đối tượng đó có thể được tham chiếu tới. trình biên dịch sẽ bỏ qua. nếu có tên tham số. các danh biểu dùng trong hàm nguyên mẫu có thể dùng lại ở những nơi khác. Các biến cục bộ được khai báo đầu hàm có phạm vi khối như các tham số của hàm đó. phạm vi trong têp. trình liên kết sẽ tự giải quyết vấn đề tham khảo tới biến công cộng được phân phối ở ngoài tệp B. Các nhãn được dùng trong lệnh switch có thể được dùng bất cứ ở đâu trong thân hàm nhưng không thể bị tham chiếu bởi câu lệnh ở ngoài thâm hàm đó. cac sbiến ở trong một khối chỉ có phạm vi là khối đó càc tất cả các khối lồng trong nó. 4. Bất cứ một khối nào cũng có thể kha báo các biến trong đó. Như vậy có thể hiểu rằng nội dung của một tệp project là danh sách tên các tệp dùng để tạo nên một chương trình ứng dụng. 4. các danh biểu dùng trong danh sách các tham số của hàm nguyên mẫu chỉ có phạm vi trong hàm nguyên mẫu. Cuối cùng. Thông thường các tệp này là chương trình nguồn. Có bốn loại phạm vi khác nhau: phạm vi trong hàm.OBJ) sinh ra do việc biên dịch các chương trình nguồn *. định nghãi hàm và cá hàm nguyên mẫu được đặt ở ngoài tất cả các hàm đều có phạm vi tệp. Các biến tĩnh cục bộ cũng có phạm vi khối. Một đối tượng khai báo ở ngoài các hàm thì có phạm vi trong tệp đó. các tệp thành phần khác chứa các hàm thư viện tự định nghĩa để sử dụng trong chương Khoa Tin học .74 - . Có thể nói thuộc tính thời gian tồn tại độc lập với thuộc tính phạm vi. Mặc dù vậy vẫn chỉ có duy nhất một tệp nguồn chứa hàm main( ). Các nhãn của chương trình (danh biểu theo sau là dấu hai chấm chư start:) chỉ có phạm vi trong hàm. mặc dù chúng tồn tại từ khi chương trình bứt đầu thực hiện. Các hàm nguyên mẫu không yêu cầu tên trong danh sách các tham số mà chỉ yêu cầu kiểu. Tệp project là hình thức để liên kết các tệp nguồn đó vói nhau trước khi biên dịch. Vì vậy. extern thông báo với trình biên dịch không cần cấp phát thêm vùng nhớ cho các biến đó một lần nữa. Các biến toàn cục.

CON TRỎ HÀM 5. trình biên dịch chuyển chương trình nguồn sang dạng mã máy và thiết lập môt điểm xâm nhập vào hàm (chính là vị trí của chỉ thị mã máy đầu tiên của hàm). Ta gọi đây là con trỏ hàm. sau đó thực hiện lệnh Project/Add item… hay nhấn phím INS (Insert) và thực hiện các chỉ dẫn trên màn hình. Để hiểu được các con trỏ hàm làm việc như thế nào. Sau đây chúng ta nói về các thao tác trên một tệp project. máy tính sẽ thực hiện một chỉ thị call chuyển điều khiển đến điểm xâm nhập này.Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang trình. chọn cửa sổ project. Khi biên dịch hàm. Trong cửa sổ này hiện lên các tệp thành phần. trên màn hình xuất hiện thêm một cửa sổ tệp project. Biên dịch và thực hiện tệp project: Khi một tệp project được mở thì mọi thao tác biên dịch (F9. Để loại bỏ một tệp thành phần khỏi tệp project. Vì vậy nếu muốn biên dịch và thực hiện một chương trình nguồn đơn lẻ khác thì phải đóng tệp project đang mở. Thứ tự các tệp thành phần trong tệp project không quan trọng. ta cần hiểu một chút về cách biên dịch và gọi một hàm.prj. cuối cùng thực hiện lệnh Project/Delete item hoặc nhấn phím Del (Delete). Để mở một tệp project. Trong trường hợp gọi hàm bằng tên hàm thì điểm xâm nhập này là trị tức thời (gần như Khoa Tin học . thực hiện lệnh Project/Open project…sau đó lựa chọn một tệp project đã có hoặc đăng kí tên cho một tệp project mới. Bỏ một tệp khỏi tệp project. Cửa sổ project: Một khi đã đăng kí tên tệp project mới hay mở một tệp project đã có. Mở một tệp project: Tệp project thường có phần mở rộng là . 5. Tại mỗi thời điểm chỉ có thể mở không quá một tệp project. sau đó lựa chọn tên tệp cần xoá.1 Khái niệm Mặc dù một hàm không phải là một biến nhưng nó vẫn chiếm vị trí trong bộ nhớ và ta có thể gán vị trí của nó cho một loại biến con trỏ. Con trỏ hàm có thể sử dụng thay cho tên hàm và việc sử dụng con trỏ cho phép các hàm cũng được truyền như là tham số cho các hàm khác. Mọi tệp chương trình khác đều không được xem xét. Thêm một tệp vào tệp project: Để thêm một tệp thành phần. Như vậy nếu đang làm việc với một tệp project việc mở project khác sẽ đóng tệp project trước đó. Alt+F9) và thực hiện (Ctrl+F9) chỉ liên quan đến các tệp thành phần trong tệp project. Khi có lời gọi thực hiện hàm.75 - . Đóng tệp project đang mở: Thực hiện lênh: Project/Close project. trước hết chọn cửa sổ project. Con trỏ này trỏ đến điểm xâm nhập vào hàm.

c sau đây thực hiện việc sắp xếp dãy số theo nhiều tiêu chuẩn khác nhau: (i) sắp xếp tăng dần theo giá trị. Chương trình func5.3 Tham số hình thức của hàm là con trỏ hàm Như đã đề cập ở phần 2. trong khi con trỏ hàm: void fptr2(int. (ii) sắp xếp tăng dần theo trị tuyệt đối mà chỉ dùng một hàm sắp xếp. Cách gọi hàm thông qua biến trỏ hàm gọi là cách gọi hàm gián tiếp. int)). Vì vậy. khi gọi hàm gián tiếp thông qua một biến trỏ thì biến trỏ đó phải trỏ tới chỉ thị mã máy đầu tiên của hàm đó. void inds(int *). 5. Khi đó trong lời gọi hàm chúng ta có thể sử dụng tên một hàm khác làm tham số thực. int tangtd(int. #include<stdio. 5.h> #include<conio. int).h> #include<math.float). Trái lại. void sapxep(int *. Khoa Tin học . chỉ có thể lấy giá trị của các hàm một tham số kiểu int và có giá trị trả về cũng là kiểu nguyên int. int). trong đó tham số thứ nhất có kiểu int và tham số thứ hai có kiểu float.2 Khai báo con trỏ hàm Cú pháp khai báo: [<kiểu_giá_trị>](*tên_biến_con_trỏ_hàm>)([<danh_sách_tham_sô>]). cách gọi hàm này là cách gọi hàm trực tiếp. Một con trỏ hàm chỉ có thể nhậm giá trị là tên của các hàm có cùng kiểu giá trị trả về kiểu giá trị của các tham số.h> void nhapds(int *d).Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang là một hằng và không chứa trong biến nào cả). có thể kha báo tham số hình thức của hàm là một con trỏ hàm. int tanggt(int. Ý nghĩa của các thành phần trong khai báo con trỏ hàm giống như đối với con trỏ hàm.76 - . Chẳng hạn con trỏ hàm: int fptr1(int). int (*cmp)(int. C không hạn chế về kiểu giá trị của tham số hình thức. void main() { int a[5]. thì có thể nhận giá trị là tên các hàm có kiểu giá trị trả về là void và có hai tham số.2.

i<5. i++) { printf("d[%d] = ". for (i=0. i++) for (j=i+1.int)) { int i. } } int tanggt(int a. } } void inds(int *d) { int i. scanf("%d".&temp).tanggt). for (i=0. } void sapxep(int *d. d[i] = d[j]. i<4. printf("\nDay so sau khi sap xep tang theo gia tri tuyet doi:\n").tangtd). printf("\nDay so vua nhap: "). i++) printf("%4d". i<5. for (i=0. printf("\nDay so sau khi sap xep tang:"). sapxep(a. inds(a).77 - . nhapds(a). int b) Khoa Tin học Trần Uyên Trang . } void nhapds(int *d) { int i.d[j])) { int temp = d[i]. d[j] = temp. j. int temp. printf("\n"). int (*cmp)(int. j++) if(cmp(d[i]. j<5.Giáo trình Ngôn ngữ lập trình C clrscr(). inds(a). i). sapxep(a. getch().d[i] = temp. d[i]). inds(a). printf("\nNhap vao day so nguyen:\n").

hàm chỉ cần trả lại kết quả. Khi hàm đệ quy được gọi trong các trường hợp cơ sở. việc dùng hàm gọi ngay chính nó rất hữu dụng.Giáo trình Ngôn ngữ lập trình C { return a>b?1:0. Cách tiến hành giải một bài toán đệ quy nhìn chung có những điểm chung sau đây: Hàm đệ quy thực ra chỉ giải bài toán trong trường hợp đơn giản nhất hay còn gọi là trường hợp cơ sở. Vấn đề đệ quy là một vấn đề phức tạp. } int tangtd(int a. (ii) Khi gọi một hàm bằng con trỏ hàm f cần phải có dấu ngoặc. Một phần hàm biết Khoa Tin học . vì vậy trong phần này chỉ giới thiệu một số khía cạnh cùng với những ví dụ đơn giản nhất của vấn đề đệ quy. Trước tiên ta xem xét khái niệm đệ quy. int b) { return abs(a)>abs(b)?1:0. ĐỆ QUY Các chương trình đã xét đều có chung cấu trúc phân cấp giữa hàm gọi và hàm bị gọi. Tuy nhiên trong một số bài toán.78 - . (iii) Không có sự khác biệt nào giữa việc gọi bằng tên của hàm và gọi bằng con trỏ hàm. hàm đệ quy sẽ chia công việc cần giải quyết thành hai phần. Nếu hàm được gọi trong các trường hợp phức tạp hơn. } Kết quả thực hiện chương trình: Nhap vao day so nguyen: d[0] = -12 d[1] = 100 d[2] = -70 d[3] = 0 d[4] = 56 Day so vua nhap: -12 100 -70 0 56 Day so sau khi sap xep tang: -70 -12 0 56 100 Day so sau khi sap xep tang theo gia tri tuyet doi: 0 -12 56 -70 100 Trần Uyên Trang Chú ý: (i) Các hàm có thể trỏ thành đối tượng được gọi trong hàm khác nên được khai báo trước. Có thể định nghĩa hàm đệ quy là hàm sẽ gọi đến chính nó trực tiếp hay gián tiếp thông qua các hàm khác. 6. sau đó kiểm tra trên một vài chương trình có chứa các hàm đệ quy. hàm được gọi theo kiểu f(danh sách các tham số nếu có).

i=i+3) printf("%d! = %ld\n".h> #include<conio. 0! được định nghĩa bằng 1. for (i=n. for(i=0. i<10. phần sau phải giống với bài toán ban đầu nhung đơn giản hơn hay nhỏ hơn bài toán ban đầu. ta xem xét ví dụ tính n giai thừa (n!) sau đây: Theo định nghĩa n! bằng tất cả các số tự nhiên từ 1 đến n: n! = n * (n-1) … 2 * 1 Ví dụ 5! = 5 * 4 * 3 * 2 * 1 = 120. sau đó lấy kết quả tính 1!. getch(). lại lấy kết quả để tính 2! và cuối cùng mới tính được 3! : 3! = 3*(2!) = 3*(2*(1!) = 3*(2*(1*(0!))) 3! = 3*(2*(1*1))) = 3*(2*1)= 3*2 =6 Sau đây là chương trình tính n giai thừa sử dụng hàm đệ quy: #include<stdio.i. Ta nhận thấy hàm đệ quy xử lí trường hợp cơ sở để trả lại kết quả tính được cho các hàm phức tạp hơn nữa…cứ như vậy cho đến lời gọi hàm ban đầu.h> long gt(long). Bởi vì bài toán mới giống với bài toán ban đầu nên hàm sẽ thực hiện gọi chính nó để giải quyết công việc đơn giản hơn này .Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang cách giải quyết như thế nào.đây chính là lời gọi đệ quy hay còn gọi là một bước đệ quy. đơn giản tới mức trở trành trường hợp cơ sở. } long gt(long num) { if (num == 0) Khoa Tin học . Để đảm bảo việc đệ quy có kết thúc. i>=1. clrscr(). void main() { int i.79 - . Tuy nhiên cũng có thể đinh nghĩa đệ quy hàm giai thừa như sau: nếu n>0 n! = n * (n-1)! nếu n=0 n! = 0! = 1 Khi đó để tính 3! quá trình tính phải lần ngược trở về tính 0!. i--) kq*= i. mỗi một lần gọi đệ quy thì bài toán phải đảm bảo bảo đơn giản hơn và các bước đệ quy này còn thực hiện liên tiếp cho đến khi nào bài toán đơn giản dần. Trước khi đưa ra các nhận xét tiếp. Để tính n! có thể dùng vòng lặp như sau: kq = 1. còn phần kia vẫn không biết cách giải quyết như thế nào tuy nhiên để được gọi là có khả năng đệ quy. gt(i)).

1. 2 . Tỉ số giữa hai số Fibonaci liên tiếp khoảng 1. printf("\n Hay nap vao mot so nguyen: "). result = fibo(number). Các kiến trúc sư thường thiết kế kích thước cửa sổ.h> long fibo(long). nhà ở có tỉ lệ chiều dài và chiều rộng bằng tỉ số vàng. tiếp sau đó các số Fibonaci sau bằng tổng của hai số Fibonaci đứng trước nó. Dãy Fibonaci gặp rất nhiều trong thực tế. number. 13.… bắt dầu từ hai số 0 và 1.618…Số này gặp rất nhiều trong thực tế và được gọi là tỉ số vàng.Giáo trình Ngôn ngữ lập trình C return 1. } Kết quả thực hiện chương trình: 0! = 1 3! = 6 6! = 720 9! = 362880 Trần Uyên Trang Ví dụ thứ hai dùng hệ qui là tính dãy số Fibonaci. fibonaci(1) = 1. 21. void main() { long result. Các bưu thiếp cũng thường có tỉ lệ giữa chiều dài và chiều rộng bằng tỉ số vàng. result). 8. else return (num*gt(num-1)). #include<stdio.80 - . 3 . printf("Fibonaci thu %ld la: %ld \n". Chú ý rằng dãy số Fibonaci tăng rất nhanh. fibonaci(n) = fibonaci(n-1) + fibonaci(n-2) ∀n>1 Chương trình trong bài tập mẫu sau đây tính đệ quy số Fibonaci thứ i bằng cách dùng hàm fibonaci( ). clrscr(). getch(). Dẫy Fibonaci có thể định nghĩa đệ quy như sau: fibonaci(0) = 0. Dãy số Fibonaci gồm những số: 0 . scanf("%ld". number. 5 . phòng. 1. &number). } long fibo(long n) { if (n == 0||n == 1) Khoa Tin học . đặc biệt khi mô tả các mô hình xoắn ốc.h> #include<conio. vì vậy chúng ta chọn kiểu long cho tham số và giá trị trả về của hàm fibonaci( ).

nếu không. có thể tính theo phương pháp lặp (phi đệ qui) hoặc phương pháp đệ qui. So sánh đệ quy và lặp Ta đã xét cách tính giai thừa của một số.…).81 - . Tuy nhiên trong nhiều trường hợp người ta vẫn dùng phương pháp đệ quy vì nó cho phép diễn đạt được tương đối trực quan và dễ hiểu quá trình giải quyết bài toán. } Kết quả thực hiện chương trình: Hay nap vao mot so nguyen: 8 Fibonaci thu 8 la: 21 Trần Uyên Trang Mỗi lần hàm fibo( ) được gọi. Khoa Tin học . Mỗi lần gọi hàm. còn phương pháp đệ quy còn được quá trình lặp bằng cách sử dụng liên tục các lời gọi hàm. quá trình lặp sẽ không thoát ra được khi điều kiện lặp không bao giờ sai. địa chỉ trở về của hàm. Lập trình đệ quy sử dụng cấu trúc lựa chọn. nó kiểm tra ngay lập tức liệu đây có phải là trường hợp cơ sở. Cả hai phương pháp đều liên quan đến quá trình lặp. còn lời gọi đệ qui không thoát ra được khi các bước đệ qui không làm cho bài toán đơn giản hơn để cuối cùng đạt tới trường hợp cơ sở. n bằng 0 hay 1 hay không. Tuy nhiên phương pháp đệ quy không hiệu quả do nó liên tự thực hiện các lời gọi hàm. còn lặp sử dụng cấu trúc lặp. Vì vậy phương pháp lặp có lẽ được ưu chuộng hơn do khả năng tiết kiệm. Tuy nhiên. còn lời gọi đệ qui làm cho các lời gọi hàm đơn giản dần cho đến khi đạt tới trường hợp cơ sở. Nếu đúng thì n được trả lại. tốn thêm bộ nhớ (lưu các biến của hàm. lại cần thêm một bản sao của hàm. còn lời gọi đệ quy kết thúc khi gặp trường hợp cơ sở. Cả hai phương đều phải kiểm tra khi nào kết thúc. else return (fibo(n-1)+fibo(n-2)). Phương pháp lặp kết thúc khi điều kiện để tiếp tục vòng lặp sai. nó sẽ tạo ra hai lời gọi đệ qui đơn giản hơn lời gọi đến hàm fibo ban đầu. tức là khi n>1.Giáo trình Ngôn ngữ lập trình C return n. nên tốn thời gian xử lý và không gian nhớ. Trong phần này ta sẽ so sánh hai phương pháp này và tìm hiểu tại sao trong thực tế thường chọn phương pháp lặp hơn. Cả hai phương pháp này đều có thể dẫn đến trường hợp vô hạn không dừng. Quá trình lặp thực hiện các tác động lên điều kiện lặp nhờ các lệnh trong thân câu lệnh lặp cho đến điều kiện lặp sai. phương pháp lặp sử dụng vòng lặp tường minh.

<tên_cấu_trúc> là tên hợp lệ được dùng làm tên cấu trúc. bao gồm kiểu dữ liệu và một danh sách cá khai báo tên của các thành phần tạo nên cấu trúc này.82 - . được tạo thành từ những kiểu dữ liệu đơn giản mà đã biết.v…để có thể xử lý biến này như một phần tử thống nhất. trong đó struct là từ khoá đứng trước một khai báo cấu trúc. ta có thể cần đến một biến nào đó có khả năng lưu trữ được cả tên. chúng ta có thể sẽ cần đến những kiểu dữ liệu phức tạp hơn. Chúng ta gọi những kiểu dữ liệu như vậy là cấu trúc. Chúng ta xét các ví dụ sau: struct hocsinh { char hoten[20]. Khái niệm cấu trúc trong C có nhiều nét tương tự như khái niệm về bản ghi (record) trong PASCAL hay trong FOXPRO 1.y.2 Khai báo cấu trúc 1. Các thành phần được truy nhập thông tin qua tên.1 Khái niệm và định nghĩa cấu trúc Trong thực tế lập trình. mức lương. <khai_báo_các_thành_phần> tựa như khai báo biến. để lưu trữ những thông tin liên quan đến một đối tượng nhân viên. ngày sinh lẫn mã số sinh viên. } Khoa Tin học . địa chỉ. }.1 Khai báo kiểu dữ liệu cấu trúc Cú pháp: struct <tên_cấu_trúc> { <khai_báo_các_thành_phần> }. CẤU TRÚC 1. Thông thường người ta sử dụng thuật ngữ trường để chỉ các thành phần của cấu trúc. float diemthi. Những kiểu dữ liệu này cho ta một khả năng kết hợp một nhóm các biến để thể hiện một đối tượng chung. Cấu trúc là một kiểu dữ liệu bao gồm nhiều thành phần có thể thuộc nhiều kiểu dữ liệu khác nhau. thể hiện thông tin của một nhân viên cụ thể. Chẳng hạn.Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang CHƯƠNG 5 CẤU TRÚC 1. Ngôn ngữ C cho phép chúng ta tự xây dựng những kiểu dữ liệu phức hợp như vậy và sử dụng những kiểu dữ liệu này để khai báo cho các biến sử dụng sau đó. struct diem{ float x. v.2.

1. dsiem[100]. Trong cú pháp trên ta thấy rằng phần <tên_cấu_trúc> là tuỳ chọn. ta có thể viết lại khai báo cấu trúc dagiac như sau: struct dagiac{ itn n. 1. Chẳng hạn: ptr_p = &p. ngôn ngữ C cho phép khai báo trực tiếp kiểu của các thành phần là biến cấu trúc bên trong một cấu trúc lớn hơn.2 Khai báo kiểu dữ liệu cấu trúc Cú pháp: struct <tên_cấu_trúc> <tên_biến_cấu_trúc>.3 Khai báo con trỏ cấu trúc Cú pháp: struct <tên_cấu_trúc> *<tên_biến_cấu_trúc>. Ví dụ: struct hocsinh hs. Khai báo thứ hai mô tả các toạ độ của một điểm trên mặt phẳng toạ độ thực. Tuy vậy. nếu không có <tên_cấu_trúc> thì cấu trúc khai báo tương ứng không thể sử dụng về sau.q.4 Khai báo đồng thời cấu trúc và biến cấu trúc Cú pháp: struct [<tên_cấu_trúc>] { <khai_báo_các_thành_phần> }<danh_sách_biến_cấu_trúc >. 1. sau khi khai báo con trỏ cấu trúc ptr_p có giá trị NULL. Ví dụ: struct diem *ptr_p. gồm hai thành phần là x (hoành độ) và y (tung độ).Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang Khai báo thứ nhất xác định một kiểu cấu trúc có tên là hocsinh gồm hai thành phần: hoten (họ tên) và diemthi (điểm thi). Giống như Pascal.83 - . struct diem p. Con trỏ này có thể nhận giá trị là địa chỉ của các biến cấu trúc kiểm diem. Ví dụ: struct dagiac { int n.2. dshs[100]. Khoa Tin học . struct diem dsdinh[20]. Dù rằng hai thành phần của cấu trúc giống hệt nhau và có thể sử dụng mảng để thay thế nhưng vệc sử dụng cấu trúc trong trường hợp này làm cho thông tin được mô tả tường minh hơn. Giống như mọi con trỏ khác. Chẳng hạn nếu không định nghĩa riêng cấu trúc diem.2. dg2.2. } dg1.

Giáo trình Ngôn ngữ lập trình C struct { float x,y; }dsdinh[10]; }dg1, dg2;

Trần Uyên Trang

1.3 Đặt tên kiểu dữ liệu bằng typedef
1.3.1 Từ khoá typedef Ngôn ngữ C cho phép thêm tên mới cho một kiểu dữ liệu bằng câu lệnh như sau: typedef <tên_kiểu_đã_có> <tên_mới>; trong đó <tên_kiểu_đã_có> là kiểu dữ liệu mà ta muốn thêm tên mới, <tên_mới> là tên mới mà ta muốn đặt. Xét câu lệnh sau: typedef unsigned char byte; Sau câu lệnh này byte được xem như là kiểu dữ liệu tương đương với unsigned char và có thể được sử dụng trong các khai báo biến như các kiểu dữ liệu khác. Xét chương trình struct1.c sau: #include<stdio.h> #include<conio.h> typedef unsigned char byte; void main() { byte ch =15, ch1; int i; clrscr(); ch1 = ch; for(i=0; i<5; i++) ch>>=1; printf("\nByte %X Sau khi dich phai 5 lan la : %X", ch1, ch); getch(); } Kết quả thực hiện chương trình: Byte F Sau khi dich phai 5 lan la : 0 typedef thường được sử dụng để định nghĩa lại các kiểu dữ liệu phức hợp thành một tên duy nhất để dễ dàng viết hơn trong khi viết. Ví dụ: typedef int * ptrint Khoa Tin học - 84 -

Giáo trình Ngôn ngữ lập trình C

Trần Uyên Trang

định nghĩa một kiểu dữ liệu con trỏ nguyên. Sau câu lệnh này để khai báo một biến con trỏ nguyên ptr_int chúng ta chỉ cần viết: ptrint ptr_int; 1.3.2 Sử dụng typedef với cấu trúc Đặc biệt đối với các kiểu dữ liệu cấu trúc, typedef cho phép đơn giản hoá cách viết khi khai báo. Xét ví dụ sau: struct hocsinh { char hoten[20]; float diemthi; } typedef struct hocsinh t_hocsinh; typedef struct hocsinh *ptr_hocsinh; Với các câu lệnh này, tên mới của cấu trúc strcut hocsinh sẽ là t_hocsinh, đồng thời còn định nghĩa một kiểu con trỏ cấu trúc có tên là ptr_hocsinh. Khi đó câu lệnh khai báo biến cấu trúc viết gọn lại như sau: t_hocsinh hs, dshs[100]; Để khai báo biến con trỏ cấu trúc, ta có thể sử dụng câu lệnh sau: ptr_hocsinh ptrhs; Câu lệnh này rõ ràng ngắn gọn hơn câu lệnh struct hocsinh *ptrhs; Có thể sử dụng typedef ngay trong khi khai báo cấu trúc như ví dụ sau: typedef struct { char hoten[20]; float diemthi; }t_hocsinh; Trong khai báo này cần chú ý hai điểm: thứ nhất, tên cấu trúc bây giờ có thể không cần; thứ hai các tên đi sau dấu } không phải là tên biến mà là tên của kiểu dữ liệu đang định nghĩa.

1.4 Thao tác trên biến cấu trúc
1.4.1 Truy nhập đến thành phần trong cấu trúc Mỗi biến cấu trúc là một thể hiện của cấu trúc, nghĩa là nó mô tả cụ thể giá trị của các thành phần được khai báo bên trong cấu trúc. Chẳng hạn, biến cấu trúc p và q sẽ có các thành phần x và y khác nhau trong cấu trúc diem. Và dĩ nhiên có thể gán cho hai thành phần x và y của cấu trúc p các giá trị khác nhau. Như vây, để xác định một thành phần bên trong biến cấu trúc người ta cần đến cả tên biến và tên thành phần. Nguyên tắc chung như sau: <tên_biến_cấu_trúc>.<tên_thành_phần> Khoa Tin học - 85 -

Giáo trình Ngôn ngữ lập trình C

Trần Uyên Trang

Dấu chấm ở đây được gọi là toán tử truy nhập thành phần cấu trúc. Nếu bản thân thành phần của biến cấu trúc là một biến cấu trúc thì vẫn áp dụng được toán tử này để xác định các thành phần "sâu hơn" trong cấu trúc thành phần. Ví dụ: p.x = 5; p.y = 10; dg1.n = 10; dg1.dsdinh[2].x = 100; dg1.dsdinh[2].y = 100; ... 1.4.2 Truy nhập đến thành phần trong cấu trúc từ con trỏ cấu trúc Giả sử có con trỏ ptr_p chỉ đến p, khi đó có hai cách để xác định p: * Cách thứ nhất: áp dụng toán tử * lên con trỏ ptr_p, nghĩa là *ptr_p: (*ptr_p).x * Cách thứ hai: sử dụng toán tử mũi tên -> (dấu trừ kết hợp với dấu lớn hơn) như sau: ptr_p->x 1.4.3 Nhập dữ liệu cho biến cấu trúc Ngôn gnữ C không đưa ra các phương tiện để nhập dữ liệu cho biến cấu trúc. Như vậy, người lập trình phải tự mình thực hiện các thao tác nhập dữ liệu cho các thành phần trong cấu trúc. Theo kinh nghiệm, nếu áp dụng trực tiếp hàm scanf( ) lên các thành phàn cấu trúc thì nhiều trường hợp sẽ xảy ra hiện tượng treo máy. Biện pháp được đề nghị là sử dụng biến trung gian: trước hết chúng ta nhập các số liệu cho biến trung gian rồi sau đó mới đem gán các giá trị nhập được cho các thành phần cần nhập. Điều này tương tự như việc nhập dữ liệu cho các phần tử của mảng. Đoạn chương trình sau trình bày cách nhập dữ liệu cho biến cấu trúc p: … float temp; printf("Toa do x: "); scanf("%f", &temp); p.x = temp; printf("Toa do y: "); scanf("%f", &temp); p.y = temp; … Trong chương trình struct2.c sau đây có khai báo một mảng các cấu trúc hocsinh và thực hiện một số thao tác quen thuộc trên danh sách sinh viên: (i) vào số liệu (ii) in ra danh sách sinh viên phải thi lại #include<stdio.h> Khoa Tin học - 86 -

Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang #include<conio. do { fflush(stdin).2f\n".scanf("%f". ++k.diem). gets(name). i++) if (dshs[i]. if (strcmp(name. n+1). dshs[i]. clrscr()."")!=0) { strcpy(dshs[n]. float diem./* số lượng học sinh của lớp đã được nhập*/ int k. for(i=0. dshs[n++]. printf("Nhap vao hoc sinh thu: %d\n". return."")!=0).hoten. printf("Danh sach hoc sinh thi lai:\n").h> #include<string.name). %s %6. }hocsinh.hoten./* số lượng học sinh thi lại */ int i.87 - . } }while (strcmp(name. dshs[i]. float d. } else { k = 0. &d). hocsinh dshs[100]. } Khoa Tin học . printf("Diem: ").diem < 5) printf("%d.h> typedef struct { char hoten[20]. char name[20]. printf("Ho ten:"). void main() { int n = 0. i<n. if(!n) { printf("Chua nhap hoc sinh nao!\n").diem = d. if (!k) printf("Khong co hoc sinh thi lai!").

4 Nhap vao hoc sinh thu: 4 Ho ten:M Diem: 3. Khoa Tin học .6 Nhap vao hoc sinh thu: 2 Ho ten:T Diem: 8.h> #include<conio. Câu lệnh gán cấu trúc thực hiện gán giá trị các trường của cấu trúc bên vế phải cho các trường tương ứng trong biến cấu trúc bên vế trái.h> void main() { struct { char ht[20].4. Chương trình struct3.9 Nhap vao hoc sinh thu: 3 Ho ten:F Diem: 3.c sau đây cụ thể hoá lời giải thích này: #include<stdio.1 Nhap vao hoc sinh thu: 6 Ho ten: Danh sach hoc sinh thi lai: 1. } Kết quả thực hiện chương trình: Nhap vao hoc sinh thu: 1 Ho ten:A Diem: 5.h> #include<stdlib. F 3.Giáo trình Ngôn ngữ lập trình C getch().40 2. M 3. ta có thể thực hiện lệnh gán sau đây: q = p.90 Trần Uyên Trang 1. Chẳng hạn nếu p và q có cùng kiểu diem.9 Nhap vao hoc sinh thu: 5 Ho ten:M Diem: 5.4 Phép gán giữa các biến cấu trúc Có thể thực hiện phép gán nội dung một biến cấu trúc cho một biến cấu trúc khác cùng kiểu.88 - .h> #include<string.

2 Truyền biến cấu trúc bằng tham biến Việc truyền địa chỉ biến cấu trúc cho hàm có hai lợi ích. b. Chương trình struct4.h> typedef struct { float x.ht. cấu trúc sẽ chậm đi do phải tốn nhiều thời gian cho việc sao chép dữ liệu trong mỗi lời gọi hàm liên quan đến cấu trúc. dù kích thước biến nhường nào thì địa chỉ của biến vẫn chỉ là 2 bytes.h> #include<conio.ht. thay vì truyền nội dung cấu trúc người ta chỉ truyền cho hàm địa chỉ của cấu trúc. b.x. Lý do là vì trong trường hợp này nội dung của biến cấu trúc dùng làm tham số thực sẽ được sao chép sang vùng nhớ dành cho tham số hình thức. } Kết quả thực hiện chương trình: a: {Nguyen van A 10 10} b: {Nguyen van A 10 10} Trần Uyên Trang 1. Vì vậy.y = 10. Và hơn nữa nội dung của biến cấu trúc dùng làm tham số thực lại không thể thay đổi được. } a. b. a.y.x. ta có thể sử dụng toán tử '-> 'để thực hiện các truy xuất dữ liệu lên biến cấu cấu trúc liên quan. thứ hai. a. a."Nguyen van A").y. Nhằm mục đích nâng cao tốc độ thực hiện cấu trúc và đôi khi cần thực hiện các thay đổi dữ liệu trên các cấu trúc thao tác. #include<stdio. clrscr().h> #include<math.5. b = a.5. b.y). thứ nhất. printf("a: {%s %d %d}\n".x = 10. typedef struct Khoa Tin học .1 Truyền biến cấu trúc bằng tham trị Việc khai báo tham số hình thức của hàm là một biến cấu trúc ảnh hưởng ít nhiều đến tốc độ thực hiện chương trình.89 - . a.c sau đây khai báo cấu trúc mô tả một tam giác dựa trên toạ độ ba đỉnh và thực hiện một số tính toán trên tam giác. Chúng ta biết rằng kích thước của các biến cấu trúc thường rất lớn.Giáo trình Ngôn ngữ lập trình C int x. strcpy(a. }diem. a. printf("b: {%s %d %d}\n". 1.ht.y). getch().5 Truyền biến cấu trúc cho hàm 1.

tg. printf("Dinh B\n"). printf("x = ").t->A.t->B.B. C. tg. printf("Dinh C\n"). }tamgiac. &temp).y = temp. } printf("Dien tich: %f\n". printf("Canh BC: %f\n". printf("Nhap toa do cac dinh cuar tam giac:\n"). float dientich(tamgiac). switch (loaitamgiac(tg)) { case 1: printf("Tam giac deu\n"). float canh(diem. diem).scanf("%f". Khoa Tin học Trần Uyên Trang . tg. nhaptoado(&tg). dientich(tg)). break.x = temp. &temp). case 3: printf("Tam giac can\n").Giáo trình Ngôn ngữ lập trình C { diem A. break. printf("x = "). } /* */ void nhaptoado(tamgiac *t) { float temp.t->B.scanf("%f".y = temp. getch(). case 4: printf("Tam giac vuong\n").scanf("%f".scanf("%f". &temp). printf("y = "). break. printf("y = "). canh(tg.scanf("%f".C.B)). printf("Canh CA: %f\n". &temp).A.t->C.x = temp. B. /* */ void nhaptoado(tamgiac*).A)). break. break. diem). printf("Dinh A\n").y = temp. &temp). &temp). case 5: printf("Tam giac thuong\n"). printf("y = "). printf("x = "). canh(tg. printf("Canh AB: %f\n". clrscr(). float canhbp(diem. void main() { tamgiac tg.t->C. canh(tg.C)).90 - . int loaitamgiac(tamgiac).t->A.x = temp. case 2: printf("Tam giac vuong can\n").scanf("%f".

p.A). b.x. p = (a+b+c)/2. else if(a2==b2+c2||b2==a2+c2||c2==a2+b2) return 4.x. b2.B).B. else return 3.A). } float dientich(tamgiac t) { float a. c2 = canhbp(t. return(sqrt(p*(p-a)*(p-b)*(p-c))). if(a2==b2||b2==c2||c2==a2) if(a2==b2&&b2==c2) return 1. c = canh(t. c2.91 - .2.C).2. t. c.x-q.2.B. b = canh(t.C).x-q. t.0))). a2 = canhbp(t. b2 = canhbp(t.B).0)).y-q.A. t.2.C.Giáo trình Ngôn ngữ lập trình C } /* */ float canh(diem p. } /* */ float canhbp(diem p. diem q) { return(pow(p.0)+pow(p.C. t. else if (a2==b2+c2||b2==a2+c2||c2==a2+b2) return 2. } Kết quả thực hiện chương trình: Nhap toa do cac dinh cuar tam giac: Dinh A x=0 y=0 Dinh B Khoa Tin học Trần Uyên Trang . t. } int loaitamgiac(tamgiac t) { float a2.A.y-q. a = canh(t.y. diem q) { return(sqrt(pow(p. t.0)+pow(p. else return 5.y.

Khi số mối nối tăng lên. Việc sử dụng cấu trúc tự trỏ để quản lý danh sách tỏ ra linh hoạt hơn so với cách quản lý danh sách bằng mảng tĩnh. Với cấu trúc tự trỏ. Sau đây là một ví dụ về cấu trúc tự trỏ để tạo các danh sách liên kết hai chiều hoặc cây nhị phân: struct hocsinh{ char hoten[20]. struct hocsinh *psau. chúng ta có thể kéo dài danh sách ra vô hạn miễn là bộ nhớ máy tính có thể cấp phát được. float diem. nhờ hai thành phần con trỏ trước và sau tương ứng chỉ đến địa chỉ của cấu trúc chứa thông tin về các học sinh đứng liền trước và Khoa Tin học . việc duyệt danh sách sẽ linh hoạt hơn nhưng phải trả giá cho việc cập nhật danh sách cũng như chi phí bộ nhớ để duy trì các kiên kết. *psau.000000 Trần Uyên Trang 2. khi đó ta chỉ có thể duyệt danh sách theo môt chiều nhất định. Hạn chế của cách quản lý này là việc quản lý danh sách trở nên phức tạp hơn so với mảng. việc duyệt danh sách phải tuân theo một số kiểu nhất định. float diem. Tất cả điều này có được là nhờ các phương tiện cấp phát bộ nhớ. }. Dưới đây là một số ví dụ về cấu trúc tự trỏ: struct hocsinh{ char hoten[20].000000 Tam giac vuong Dien tich: 6.1 Nhắc lại khái niệm Cấu trúc có ít nhất một thành phần là con trỏ chỉ đến bản thân cấu trúc được gọi là cấu trúc tự trỏ. nếu mỗi phần tử chỉ có một mối nối.000000 Canh CA: 3. phụ thuộc vào các con trỏ liên kết trong mỗi thành phần. CẤU TRÚC TỰ TRỎ 2. struct hocsinh *ptruoc. } Trong câu lệnh khai báo này. Khai báo này định nghĩa một cấu trúc tự trỏ có thể dùng để quản lý danh sách các học sinh. Chẳng hạn.000000 Canh AB: 4. đồng thời sẽ rất tiết kiệm bộ nhớ khi có một số lượng hạn chế đối tượng cần quản lý.92 - .Giáo trình Ngôn ngữ lập trình C x=0 y=4 Dinh C x=3 y=0 Canh BC: 5.

Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang liền sau trong danh sách. giá trị trả về của push( ) sẽ là địa chỉ của cấu trúc mới được thêm vào với nội dung là tham số thứ hai của push(). trong đó thành phần d chứa chữ số nhị phân. Ban đầu head có giá trị NULL. cây nhị phân sẽ được trình bày ở các phần tiếp theo. Định nghĩa của cấu trúc như sau: typedef struct stack_binary { unsigned char d. Việc vài đặt các thao tác trên danh sách móc nối quen thuộc như: ngăn xếp. }binary. hàng đợi. thay đổi nội dung các phần tử) được thực hiện ở một đầu của danh sách. danh sách head sẽ được kéo dài thêm nhờ hàm: binary push(binary*. prev xác định địa chỉ của biến cấu trúc chứa chỉ số nhị phân hàng thấp hơn. Việc giải phóng bộ nhớ được thực hiện bởi hàm: binary pop(binary*). Khoa Tin học . đồng thời giải phóng vùng nhớ động cấp phát cho chúng. sau đó cùng với quá trình lặp của thuật toán Euclit. Ngăn xếp được quản lý thông qua một biến trỏ xác định địa chỉ của phần tử cuối cùng đưa vào danh sách. Cú pháp khai báo như sau: typedef struct stack { < khai báo phần dữ liệu chứa trong mỗi phần tử> struct strck *prev. Cấu trúc tự trỏ trong trường hợp này được sử dụng để mô tả danh sách các chữ số nhị phân của số. Để làm ví dụ minh hoạ xét chương trình xác định dạng biểu diễn nhị phân của một số nguyên dương. trong đó tham số thứ nhất là giá trị của head hiện tại. Các chữ số nhị phân của số được chứa trong một danh sách xác định bởi con trỏ head: binary *head. 2. Cấu trúc tự trỏ quản lý ngăn xếp chỉ có một thành phần tự trỏ (thành phần con trỏ chỉ đến bản thân cấu trúc). Sau mỗi thao tác lấy ra một phần tử (POP) hay đưa thêm một phần tử (PUSH) ta cần phải cập nhật lại con trỏ đầu. chúng ta có thể dễ dàng duyệt danh sách theo cả hai chiều "tiến" hoặc "lui".2 Ngăn xếp (stack) Ngăn xếp là kiểu danh sách đặc biệt với các thao tác (chèn. struct stack_binary *prev. unsined). xoá. Để in ra số nhị phân tương ứng chúng ta cần lần lượt lấy các phần tử trong danh sách cấu trúc xác định bởi head.93 - . }t_stack.

(unsigned char)(n%2)). }while (head!=NULL). scanf("%d". void main() { unsigned int n. unsigned char).h> typedef struct stack_binary { unsigned char d. unsigned char c) { binary *p. } while(n!=0). binary *pop(binary *).h> #include<alloc. binary *head = NULL. do { printf("%1d". if (n==0) break. giải phóng vùng nhớ cấp phát cho head và trả về địa chỉ của phần tử vừa mới trở thành đỉnh mới của ngăn xếp. &n). do { printf("\nNhap vao mot so nguyen khac 0:"). } binary *push(binary *head . binary *push(binary *. head = pop(head).Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang Hàm pop ( ) nhận một tham số là giá trị của head hiện tại. clrscr(). Chương trình được viết như sau: #include<stdio. head->d).94 - . Khoa Tin học . struct stack_binary *prev.h> #include<stdlib. p = (binary*)malloc(sizeof(binary)).h> #include<conio. }binary. }while(1). printf("Dang bieu dien nhi phan:\n"). n/=2. do { head = push(head.

return p. p->prev = head. Sự khác nhau giữa ngăn xếp và hàng đợi được thể hiện khi cài đặt cụ thể của các thao tác thêm. } Nhap vao mot so nguyen khac 0:255 Dang bieu dien nhi phan: 11111111 Nhap vao mot so nguyen khac 0:1 Dang bieu dien nhi phan: 1 Nhap vao mot so nguyen khac 0:6 Dang bieu dien nhi phan: 110 Nhap vao mot so nguyen khac 0:8 Dang bieu dien nhi phan: 1000 Nhap vao mot so nguyen khac 0:2 Dang bieu dien nhi phan: 10 Nhap vao mot so nguyen khac 0: Trần Uyên Trang 2. free(head). Khoa Tin học . sửa. Vì vậy. phần tử được lấy ra nếu có thời gian tồn tại trong danh sách lâu nhất so với các phần tử khác.3 Hàng đợi (queue) Hàng đợi là một kiểu danh sách trong đó việc thêm các phần tử mới diễn ra ở cuối của danh sách còn việc xoá các phần tử diễn ra ở đầu của danh sách. struct queue{ <phần thông tin cần quản lý> <phần liên kết> }t_queue. Cấu trúc tự trỏ mô tả hàng đợi có thể khai báo giống như cấu trúc dùng cho ngăn xếp.95 - . cấu trúc này có tên là FIFO (Fist In First Out-Vào trước ra trước). xoá. Với cách tổ chức như vậy. return p. } binary * pop(binary * head) { binary *p = head->prev.Giáo trình Ngôn ngữ lập trình C p->d = c.

Các công việc tương ứng sẽ được cài đặt trong hàm: t_khachhang *muave(t_khachhang*). char hoten[20]. long.c sau đây mô tả cách sử dụng cấu trúc tự trỏ để mô phỏng việc xếp hàng mua vé tàu tại ga Hà Nội. }t_khachhang. Thao tác này sẽ cập nhật lại cuoicung. ví dụ.h> #include<stdlib. Công việc này đồng nghĩa với việc loại khách hàng đầu tiên trong danh sách. Một ví dụ khác rất quen thuộc với người sử dụng máy nhắn tin để ghi lại các thông báo gửi cho mình: thông báo đến trước sẽ được hiện lên đầu tiên v. Yêu cầu là khách hàng nào xếp trước được ưu tiên giải quyết trước.h> typedef struct queue_khachhang { Khoa Tin học .h> #include<string.v… Chương trình queue. Việc xếp hàng được thực hiện theo nguyên tắc ai đến trước sẽ được mua vé trước. Ta có cấu trúc thông tin như sau: typedef struct khachhang{ long cmt. char*). Như vậy nó sẽ tác động đến dautien. Hàm them( ) thực chất bổ sung thêm một cấu trúc tiếp theo sau cấu trúc xác định bởi cuoicung đồng thời cập nhật lại giá trị của cuoicung. struct khachhang *truoc. Việc quản lý danh sách các khách hàng đang mua vé được thực hiện thông qua hai biến trỏ dautien và cuoicung. Hàm này sẽ xoá khỏi danh sách cấu trúc đang được trỏ bởi dautien và cho biến trỏ này chỉ đến phần tử tiếp theo. Công việc tương ứng được thực hiện trong hàm: t_khachhang *them(t_khachhang*.h> #include<conio. chỉ đến hai biến cấu trúc mô tả người đầu tiên và người cuối cùng tương ứng: Có hai tác động lên danh sách khách hàng: (i) Thêm một khách hàng vào danh sách. Chương trình minh hoạ: #include<stdio. Thông tin về khách hàng là số chứng minh thư và họ tên.Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang Cấu trúc hàng đợi thường được dùng làm bộ đệm lưu trữ các công việc cần giải quyết theo trình tự.96 - . giải quyết danh sách xếp hàng của khách hàng.h> #include<alloc. (ii) Gọi một khách hàng vào mua vé.

++n). do { printf("\nNhap them mot khach hang:\n"). p = (t_khachhang*)malloc(sizeof(t_khachhang)). temp_cmt. long temp_cmt. dautien->hoten). t_khachhang *muave(t_khachhang*). char ht[20]. else cuoicung = them(cuoicung. gets(ht). t_khachhang *dautien = NULL. printf("So chung minh thu:"). long c. }while (1). n=0.dautien->cmt. struct queue_khachhang *next. p->cmt = c. strcpy(p->hoten. char t[20]) { t_khachhang *p.if(temp_cmt==0) break. } t_khachhang *them(t_khachhang *cuoi. dautien=muave(dautien). fflush(stdin).long. *cuoicung = NULL. clrscr(). scanf("%ld". printf("%8ld %20s\n". t_khachhang *them(t_khachhang* . /* Gọi khách hàng mua ve vao*/ printf("Danh sach khach hang mua ve:\n"). char str[20]).t). printf("Ten khach hang:"). n = 0. char hoten[20].temp_cmt.ht). }while(dautien!=NULL). if(dautien==NULL) dautien = cuoicung = them(cuoicung. } t_khachhang. void main() { unsigned int n. getch(). &temp_cmt). ht).Giáo trình Ngôn ngữ lập trình C long cmt. Khoa Tin học Trần Uyên Trang .97 - . do { printf("%2d".

return p. } Kết quả thực hiện chương trình: Nhap them mot khach hang: So chung minh thu:20057458 Ten khach hang:Phuong Nhap them mot khach hang: So chung minh thu:20057459 Ten khach hang:Toan Nhap them mot khach hang: So chung minh thu:200574510 Ten khach hang:Thang Nhap them mot khach hang: So chung minh thu:200579100 Ten khach hang:Phap Nhap them mot khach hang: So chung minh thu:0 Danh sach khach hang mua ve: 120057458 Phuong 220057459 Toan 3200574510 Thang 4200579100 Phap Trần Uyên Trang 2. } t_khachhang *muave(t_khachhang *dautien) { t_khachhang *d = dautien->next. (ii. Mỗi nút trong cây tương ứng với một đối tượng được quản lý bao gồm. cuoi->next = p.1) Thông tin về bản thân đối tượng. return d.4 Cây nhị phân (Binary tree) * Một cách phi hình thức. (ii) Hoặc cây được tạo thành bằng một gốc và hai cây con tương ứng là cây con trái là cây con phải.98 - . cây nhị phân được định nghĩa như sau: (i) Hoặc cây rỗng không chứa thành phần nào.Giáo trình Ngôn ngữ lập trình C p->next=NULL. Khoa Tin học .

99 - . nút gốc được duyệt cuối cùng. mỗi nút có một trường dữ liệu đặc biệt được gọi là khoá đặc trưng của nút. Các thao tác trên cây nhị phân tìm kiếm bao gồm: (i) Thêm một nút mới vào cây nhị phân. cây con phải được duyệt cuối cùng. rồi sau đó tuỳ theo đặc điểm của nút đó để thực hiện thao tác tiếp theo. Trong cây nhị phân tìm kiếm. Giá trị của khoá phải có kiểu dữ liệu sao cho có định nghĩa một quan hệ thứ tự giữa các giá trị.1) Nếu nút cần xoá là nút lá. việc xoá cũng dễ dàng. Trong cây nhị phân tìm kiếm thông thường ta quy định khoá của nút gốc bé hơn khoá của nút con phải và lớn hơn khoá của nút con trái. }t_banary_tree. kiểu dữ liệu có thể định nghĩa một quan hệ thứ tự là tập hợp các số nguyên với quan hệ lớn hơn ">" hoặc tập các xâu kí tự cũng với quan hệ ">". * Có ba giải thuật duyệt cây nhị phân là: (i) Duyệt theo thứ tự trước: duyệt gốc trước.3) Vấn đề chỉ thực sự phức tạp khi ta phải xoá một nút có đầy đủ con trái và con phải. (ii.2) Trong trường hợp nút xoá chỉ có một nút con. Ta xem xét cách cài đặt các thao tác này trên một lớp đặt biệt các cây nhị phân tìm kiếm. Như vậy để quản lý cây nhị phân ta sử dụng cấu trúc tự trỏ có hai thành phần liên kết: typedef struct binary_tree { <phần mô tả thông tin về đối tượng> struct binary_tree *left. cây con phải được duyệt tiếp sau. cuối cùng duyệt cây con phải. (ii. rồi duyệt cây con trái. (ii) Loại bỏ nút trong cây. Thí dụ. Thông thường các thông tin này là địa chỉ của các đối tượng. (iii) Duyệt theo thứ tự sau: đầu tiên duyệt cây con trái. Cả ba giải thuật trên là đệ qui vì rằng các cây con trái. Việc thêm nút đồng nghĩa với việc xác định vị trí trong cây của nút mới. Ta phân biệt ba trường hợp: (ii. Thao tác này bắt đầu bao gồm xác định nút cần xoá. trong trường hợp này vai trò của nút cần được chuyển sang cho nút con trái có khoá lớn nhất.2) Thông tin xác định các nút bên trái và bên phải nếu có của nút đang xem xét. cây con phải là một cây với kích thước nhỏ hơn.c sau đây cài đặt các thao tác trên cây tìm kiếm nhị phân có khoá là các số nguyên dương. sau đó duyệt gốc. Chương trình tree. mọi chuyện dễ dàng. (ii) Duyệt theo thứ tự giữa: duyệt cây con trái trước. *right. Khoa Tin học . Nút mới này phải có khoá khác với tất cả các nút đã có trong cây.Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang (ii.

unsigned int). struct tree *left. clrscr().Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang Cấu trúc của cây nhị phân tìm kiếm như sau: typedef struct tree{ unsigned int value.h> /*Cấu trúc mô tả cây nhị phân tìm kiếm*/ typedef struct tree { unsigned int n. t_tree *root = NULL. /*Xac dinh nut con lon nhat trong nhanh ben trai*/ t_tree *contrailonnhat(t_tree*).h> #include<conio. /*Tim nut voi khhoa nao do*/ t_tree *nut(t_tree*. /*Duyet cay theo thu tu giua*/ void infix(t_tree *). } t_tree. } t_tree. #include<stdio. /*Ham chinh*/ void main() { unsigned int n. *right. unsigned int). Khoa Tin học . struct tree *left. *right.100 - . Để quản lý cây nhị phân ta cần đến một biến con trỏ xác định địa chỉ của nút gốc trong cây: t_tree root.h> #include<stdlib. unsigned int). unsigned int. /* Giai phong cac vung nho cap phat cho cay*/ t_tree *xoacay(t_tree *). int *). /*Ham tao nut goc */ t_tree *taocay(unsigned int). /*Loai khoi cay mot nut*/ t_tree *xoanut(t_tree*.h> #include<alloc. /*Xac dinh nut cha hoac nut co kha nang lam nut cha cua mot nut co khoa la mot gia tri nao do*/ t_tree *nutcha(t_tree *. /*Them nut moi vao cay */ void themnut(t_tree *.

Khoa Tin học . infix(root). printf("Day so vua nhap duoc sap xep tang dan:\n"). }while(1). root = xoanut(root. /* Trai lai ta them mot nut moi vao cay*/ else themnut(root. } t_tree *taocay(unsigned int n) { t_tree *p. return p. scanf("%d".101 - . q = (t_tree*)malloc(sizeof(t_tree)). do { printf("\nNhap vao mot so nguyen can loai bo:"). p = (t_tree*)malloc(sizeof(t_tree)). getch(). q->right = NULL. root = xoacay(root). infix(root). } Trần Uyên Trang void themnut(t_tree *r. p->left = NULL. *q. q->left = NULL. } while(1). p->n = n.scanf("%d". n). p->right = NULL. int k. &n). if (n ==0) break. /*Neu la nut dau tien trong cay nhi phan thi phai tao no */ if (root == NULL) root = taocay(n). n). &n).Giáo trình Ngôn ngữ lập trình C /*tao cay*/ do { printf("Nhap vao mot so nguyen:"). printf("Day so sau khi xoa:\n"). if (n==0) break. unsigned int n) /*Viec them nut chi dien ra khi nut co khoa tuong ung chua co trong cay */ { t_tree *p.

case 2: if (p->right!=NULL) printf("Nut da co trong cay\n"). return NULL. *q.102 - . else p->left = q.Giáo trình Ngôn ngữ lập trình C q->n = n. if (p!=NULL) /*Neu nut can xoa la nut la. break.&k). p = nutcha(r.n).n. } q = nutcha(r. chi viec xoa nut do va cap nhat cac lien ket trong nut cha cua no */ { if (p->left ==NULL && p->right ==NULL) { if (p==r) { free(p). else p->right = q. int k. ta phai kiem tra ba truong hop */ { t_tree *p.n. } /*Neu nut chi co mot nut con. switch(k) { case 1: if (p->left!=NULL) printf("Nut da co trong cay\n"). Khoa Tin học Trần Uyên Trang . p =nut(r. break.&k).free(p). } return r. break. unsigned int n) /*De xoa mot nut. switch(k) { case 1: q->left = NULL. *t. } } t_tree *xoanut(t_tree *r . case 2: q->right = NULL. free(p). break. *s.

103 - .break.&k). } /*Truong hop kho nhat.free(p).free(p). } return r. return q.Giáo trình Ngôn ngữ lập trình C ta thay the no boi con cua no trong cay */ if (p->left ==NULL) { if (p==r) { q = p->right. break. nut can xoa co ca hai nut con Chung ta phai tim cho duoc nut con trong nhanh con ben trai */ s= contrailonnhat(p). free(p). t = nutcha(p.&k). free(p).n. } return r.n. return q. break. case 2: q->right = p->left. break. switch(k) { case 1: q->left = p->left. case 2: q->right = p->right. } q = nutcha(r. } q = nutcha(r.s->n. /* Cap nhat lai cac lien ket cua bo*/ if(t!=p) { Khoa Tin học Trần Uyên Trang . switch(k) { case 1: q->left = p->right.&k).free(p). free(p). } if (p->right ==NULL) { if (p ==r) { q = p->left.

} else { free(p). return s. } } if (p ==r) { free(p). unsigned int n. int *k) Khoa Tin học Trần Uyên Trang .&k)!=NULL)) { switch(k) { case 1: q->left = s. infix(r->right). return r. } } void infix(t_tree* r) { if(r==NULL) return. break.104 - . s->left = p->left. case 2: q->right = s. r->n). s->right = p->right. printf("%4u". } t_tree *nutcha(t_tree *r. return r. infix(r->left).Giáo trình Ngôn ngữ lập trình C t->right = s->left. } else s->right= p->right.n. break. /* s bay gio dong vai tro cua p*/ if ((q=nutcha(r. } } else { printf("Khong tim thay nut tuong ung\n").

else if (r->right->n ==n||r->right ==NULL) { *k = 2. if (r->n >n) return nut(r->left. } else return nutcha(r->left. free(r). unsigned int n) { if (r==NULL) return NULL. p = r->left. if (r->n>n) if (r->left->n==n||r->left==NULL) { *k = 1. if (r->right!=NULL) xoacay(r->right). n. else return (r->right. Khoa Tin học Trần Uyên Trang . } t_tree *nut(t_tree *r. n.n). while (p->right !=NULL) p = p->right. } else return nutcha(r->right. k). return r. return r. k).105 - .n). if (r->n ==n) return r. } t_tree *contrailonnhat(t_tree *r ) { t_tree *p.Giáo trình Ngôn ngữ lập trình C { if (r->n ==n) return NULL. return p. } t_tree *xoacay(t_tree *r) { if (r->left!=NULL) xoacay(r->left).

Như vậy union cho phép ta sử dụng một vùng nhớ cho nhiều biến khác nhau. nhưng khác biến cấu trúc ở chỗ: các trường trong biến cấu trúc được cấp phát các vùng nhớ khác nhau. KIỂU HỢP (union) 3. con trỏ union cũng tương tự như đối với các cấu trúc. 3. Một cấu trúc có thể có thành phần union và ngược lại các thành phần của union lại có thể là cấu trúc.106 - . còn các trường của biến union được cấp phát chung một vùng nhớ. Ta xét ví dụ khai báo sau: typedef union { Khoa Tin học .2 Khai báo kiểu dữ liệu union Khai báo một union tương tự như khai báo một biến cấu trúc. thay cho từ kháo struct ta dùng từ khoá union.1 Đặt vấn đề Một biến kiểu union cũng bao gồm nhiều thành phần giống như một biến cấu trúc.Giáo trình Ngôn ngữ lập trình C return NULL. mảng các union. Việc định nghĩa một biến kiểu union. } Kết quả thực hiện chương trình: Nhap vao mot so nguyen:10 Nhap vao mot so nguyen:4 Nhap vao mot so nguyen:16 Nhap vao mot so nguyen:1 Nhap vao mot so nguyen:8 Nhap vao mot so nguyen:3 Nhap vao mot so nguyen:2 Nhap vao mot so nguyen:5 Nhap vao mot so nguyen:9 Nhap vao mot so nguyen:12 Nhap vao mot so nguyen:19 Nhap vao mot so nguyen:14 Nhap vao mot so nguyen:17 Nhap vao mot so nguyen:0 Day so vua nhap duoc sap xep tang dan: 1 2 3 4 5 8 9 10 12 14 16 17 19 Nhap vao mot so nguyen can loai bo:1 Day so sau khi xoa: 2 3 4 5 8 9 10 12 14 16 17 19 Nhap vao mot so nguyen can loai bo:19 Day so sau khi xoa: 2 3 4 5 8 9 10 12 14 16 17 19 Nhap vao mot so nguyen can loai bo:0 Trần Uyên Trang 3.

void main() { u a.ch[1]). Hãy xem chương trình ví dụ sau: #include<stdio.n = 0x1b1a.n = 0x1b1a. unsigned char ch[2].Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang unsigned int n.ch[1] = 0x1b như vậy ta đã dùng khai báo union để tách ra byte cao và byte thấp của một số nguyên. val a.ch[0] = 1a a. Phép gán: a. a.ch[0] = %x\n". }val. } u. Kich thuoc cua union 2 a. char ch[2].ch[0] = 0x1a và a. printf("a. a.n = 0x1b1a. sizeof(a)).\n"). printf("Kich thuoc cua union %d\n".n = 0x1b1a. x[10]. sẽ gán một số trong hệ 16 là 0x1b1a cho thành phần n của a. printf("a. b và mảng union. printf("a.h> #include<conio. Câu lệnh trong ví dụ trên định nghĩa kiểu union val gồm hai thành phần là n và mảng kí tự ch.ch[1] = 1b Khoa Tin học . } Kết quả thực hiện chương trình: a. clrscr().ch[1] = %x\n".h> typedef union { unsigned int n. a.ch[0]). Do n chiếm hai byte của union nên sau câu lệnh trên ta có: a. Độ dài của val bằng độ dài của trường n và bằng 2.107 - . getch(). Tiếp đó khai báo các biến union a. b.

108 - .Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang Khoa Tin học .

Ví dụ: Màn hình VGA 640 x 480 0. chúng ta chủ yếu làm việc với kiểu màn hình văn bản. MCGA và các máy tính tương thích CGA. các các kí tự. màu tô. 0 479. 479 Mỗi loại màn hình có cách xử lí đồ hoạ riêng.màn hình). thường là *. 0 639. VGA và các máy tính tương thích EGAVGA.Vẽ.Xác định màu nền (màu . hình vẽ. tô màu các hình mà ta mong muốn . Độ phân giải của một màn hình là số điểm có thể có của màn hình đó. Ở màn hình đồ hoạ.Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang CHƯƠNG 6 ĐỒ HOẠ 1.109 - .BGI IBM 8514 các máy tính tương thích Khoa Tin học IBM8514. kiểu tô.BGI Hercules monochorome và các máy tính tương thích HERC. nên Turbo C cung cấp một tệp tin điều khiển đồ hoạ cho từng loại màn hình.BGI . màu đường vẽ.BGI IBM CGA.Các thao tác đồ hoạ khác như hiện dòng chữ.1: Các kiểu màn hình đồ hoạ và tệp điều khiển chúng KIỂU MÀN HÌNH TÊN TỆP TIN ATT & T6300 (400 dòng) ATT. … được thể hiện và xử lí đến từng điểm nhỏ (pixel). Độ phần giải càng cao thì số điểm ảnh trên màn hình càng lớn và chất lượng đồ hoạ càng cao. và kí tự hiển thị trên màn hình (kiểu và kích thước) cũng không thay đổi được. .Khởi động đồ hoạ .Đóng hệ thống đồ hoạ để trở về mode văn bản. 0 639. KHÁI NIỆM Từ trước đến nay.BGI IBM EGA.BGI. Nghĩa là màn hình với 25 dòng và 80 cột. Các phần cơ bản của một chương trình đồ hoạ: . Bảng 13.… . Các điểm được bố trí theo chiều thẳng đứng từ trên xuống và ngang từ trái qua phải.

thì ta nên dùng hằng DETECT (0) cho graphdriver. + Mode đồ hoạ ở độ phân giải cao nhất ứng với màn hình đang sử dụng cũng được phát hiện và trị số của nó được gán cho biến graphmode. .h" void main() Khoa Tin học . Như vậy.BGI 2. Khi đó.Giáo trình Ngôn ngữ lập trình C IBM 3270 PC Trần Uyên Trang PC3270. char *driverpath). KHỞI ĐỘNG ĐỒ HOẠ . mode = EGALO.Mục đích của việc khởi động hệ thống đồ hoạ là xác định thiết bị đồ hoạ (màn hình) và mốt (mode) đồ hoạ sẽ sử dụng trong chương trình. &mode. initgraph(&mh. việc dùng hằng DETECT không những khởi động được hệ thống đồ hoạ với mode cao nhất mà còn cho ta biết kiểu màn hình đang sử dụng.h” main() { int mh = EGA. } * Chú ý: . giá trị số của nó được gán cho biến graphdriver.Nếu không biết chính xác màn hình đang dùng là gì.Khi lập trình. ta dùng hàm sau: void initgraph(int *graphdriver. graphdriver: loại màn hình graphmode: mode đồ họa Ví dụ: #include “graphics. int *graphmode. #include "graphics. kết quả của hàm initgraph sẽ là: + Kiểu màn hình đang sử dụng dược phát hiện.Để khởi động đồ hoạ. ta có thể dùng tên hằng hoặc giá trị hằng tương ứng trong bảng 13. “D:\\TC\\BGI”): … closegraph(). .Độ phân giải phụ thuộc vào cả màn hình và mode đồ hoạ.110 - . driverpath là đường dẫn đến thư mục chứa các tệp diều khiển đồ hoạ. Ví dụ 1: Xác định kiểu màn hình và mode đang sử dụng bằng DETECT.2 .h" #include "stdio.

Giáo trình Ngôn ngữ lập trình C { Trần Uyên Trang int mh = 0. closegraph(). &mode.2: Bảng giá trị của graphdriver. mode = 0. } Bảng 13. graphmode GRAPHDRIVER GRAPHMODE ĐỘ PHÂN HẰNG GIÁ TRỊ HẰNG GIÁ TRỊ GIẢI DETECT CGA 0 1 CGAC0 CGAC1 CGAC2 CGAC3 CGAHi MCGA0 MCGA1 MCGA2 MCGA3 MCGAMed MCGAHi EGALO EGAHi EGA64LO EGA64Hi EGAMONOHi VGALO VGAMED VGAHI MCGA 2 EGA EGA64 EGAMONO VGA 3 4 5 9 0 1 2 3 4 0 1 2 3 4 5 0 1 0 1 0 0 1 2 320 x 200 320 x 200 320 x 200 320 x 200 640 x 200 320 x 200 320 x 200 320 x 200 320 x 200 640 x 200 640 x 480 640 x 200 640 x 350 640 x 200 640 x 350 640 x 350 640 x 200 640 x 350 640 x 480 HERCMONO ATT400 Khoa Tin học 7 8 HERCMONOHI ATT400C0 ATT400C1 0 1 720 x 348 320 x 200 320 x 200 . initgraph(&mh.""). mh).111 - . getch(). mode). printf("\nGia tri mode cua man hinh la: %d". printf("\nGia tri so cua man hinh la: %d".

Lỗi đồ hoạ còn phát sinh khi dùng các hàm đồ hoạ. Trong mọi trường hợp.112 - . Bảng 13. nếu máy không tìm thấy các chương trình điều khiển đồ hoạ thì sẽ phát sinh lỗi và việc khởi động coi như không thành công. CÁC LỖI THÔNG THƯỜNG TRONG ĐỒ HOẠ Khi khởi động hệ thống đồ hoạ. ta có thể dùng hàm grapherrormsg() với mã lỗi do hàm graphresult()trả về để biết được đó là lỗi gì.3 Các mã lỗi của graphresult() HẰNG TRỊ LỖI PHÁT HIỆN grOk 0 Không có lỗi grNoInitGraph -1 Chưa khởi động hệ đồ hoạ grNotDetected -2 Không có phần cứng đồ hoạ grFileNotFound -3 Không tìm thấy trình điều khiển đồ hoạ grInvalidDriver -4 Trình điều khiển không hợp lệ grNoLoadMem -5 Không đủ RAM cho đồ hoạ grNoScanMem -6 Vượt vùng RAM trong scan fill grNoFloodMem -7 Vượt vùng RAM trong flood fill grFontNoFound -8 Không tìm thấy tệp Font grNoFontMem -9 Không đủ RAM để nạp Font grInvalidMode -10 Kiểu đồ hoạ không hợp lệ cho trình điều khiển grError -11 Lỗi đồ hoạ tổng quát grIOerror -12 Lỗi đồ hoạ vào ra grInvalidFont -13 Tệp Font không hợp lệ grInvalidFontNum -14 Số hiệu Font không hợp lệ Ví dụ: Đoạn mã sau cho biết nội dung lỗi: Khoa Tin học .Giáo trình Ngôn ngữ lập trình C ATT400C2 ATT400C3 ATT400CMED ATT400CHI PC3270HI IBM8514LO IBM8514HI 2 3 4 5 0 0 1 Trần Uyên Trang 320 x 200 320 x 200 640 x 400 640 x 400 720 x 350 640 x 480 256 màu 1204 x 768 256 màu PC3270 IBM8514 10 6 3. Bảng 13. hàm graphresult() cho biết có lỗi hay không và lỗi đó là lỗi gì.3 cho biết các mã lỗi mà hàm này phát hiện được.

grapherror(maloi)). ta dùng hàm: void setpalette(int colornum. pattern xác định kiểu tô.Giáo trình Ngôn ngữ lập trình C int maloi.Thay đổi giải màu: Để thay đổi giải màu đã định nghĩa trong bảng 13. Trần Uyên Trang 4.Chọn màu đường vẽ: void setcolor(int color).4 Bảng giá trị mặc định của color TÊN HẰNG GIÁ TRỊ SỐ MÀU HIỂN THỊ BLACK 0 đen BLUE 1 xanh da trời GREEN 2 xanh lá cây CYAN RED MAGENTA BROWN LIGHTGRAY DARKGRAY LIGHTBLUE LIGHTGREEN LIGHTCYAN LIGHTRED LIGHTMAGENTA YELLOW WHITE 3 4 5 6 7 8 9 10 11 12 13 14 15 xanh lơ đỏ tím nâu xám nhạt xám sẫm xanh da trời nhạt xanh lá cây nhạt xanh lơ nhạt đỏ nhạt tím nhạt vàng Trắng .113 - . Trong cả 3 trường hợp trên.Chọn màu nền: void setbkcolor(int color). printf(“Loi do hoa la: ”. Bảng 13. . int color). int color). CÁC MÀU VÀ MẪU . maloi = grapresult(). color xác định mã màu.4. Khoa Tin học . .Chọn kiểu tô (pattern) và màu tô: void setfillstyle(int pattern.

palettetype là kiểu đã được Turbo C định nghĩa như sau: # define MAXCOLORS 15 struct palettetype { unsigned char size. Khoa Tin học . }.Nhận giải màu: void getpalette(struct palettetype *palette). unsigned char colors[MAXCOLORS +1]. . LIGHTCYAN). Các màu khác không bị ảnh hưởng. Hàm getbkcolor() trả về màu nền đã xác định trước đó.Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang Ví dụ: setpalette(0. size: số lượng màu trong palette colors: mảng chứa màu với chỉ số mảng từ 0 đến size-1 Bảng 13. Hàm getmaxcolor() trả về số lượng màu cực đại thuộc giải màu hiện đang có hiệu lực.5 Bảng giá trị mặc định của pattern TÊN HẰNG GIÁ TRỊ SỐ MÀU HIỂN THỊ EMPTY_FILL 0 tô bằng màu nền SOLID_FILL 1 tô bằng đường nét liền LINE_FILL 2 tô bằng --LTSLASH_FILL SLASH_FILL BKSLASH_FILL LTBKSLASK_FILL HATCH_FILL XHATCH_FILL INTERLEAVE_FILL WIDE_DOT_FILL CLOSE_DOT_FILL 3 4 5 6 7 8 9 10 11 tô bằng /// tô bằng /// in đậm tô bằng \\\ in đậm tô bằng \\\ tô bằng đường gạnh bóng nhạt tô bằng đường gạnh bóng chữ thập tô bằng đường đứt quảng tô bằng dấu chấm thưa tô bằng dấu chấm dày Hàm getcolor() trả về màu đã xác định trước đó.114 - . Ở đây. sẽ biến màu đầu tiên trong bảng thành LIGHTCYAN.

&mode.Vẽ cung tròn. . mode = 0. int y. r : bán kính . int y.h" #include "stdio.Vẽ đường tròn void circle(int x. VẼ VÀ TÔ MÀU Ta tìm hiểu các hàm vẽ và tô màu qua bốn nhóm chính sau: a. (x. #include "graphics. void arc(int x. setbkcolor(1).y) : toạ độ của tâm ellipse gd : góc đầu gc : góc cuối xr. int y.h"s void main() { int mh = 0. int gd. int gc. (x."d:\\tc\\bgi").y) : toạ độ của tâm cung tròn.360]. initgraph(&mh. int r). (x.115 - . int r). int gd.y) : toạ độ của tâm cung tròn.Vẽ cung ellipse void ellipse(int x. } 5. gc : góc cuối r : bán kính Chú ý: Góc trong tất cả các hàm ở phần này được tính bằng đơn vị độ và nằm trong [0. int xr. int yr). (x. gd : góc đầu. yr : bán kính trục ngang là trục đứng . closegraph().y) : toạ độ của tâm hình quạt gd : góc đầu gc : góc cuối r : bán kính b.Hình quạt void pieslice(int x. outtext("CONG NGHE THONG TIN").Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang Ví dụ 2: Hiển thị chữ “CONG NGHE THONG TIN” màu đỏ trên nền xanh da trời. setcolor(4). Đường tròn và hình tròn . int r). int gc. int gc. int y. Đường gấp khúc và hình đa giác Khoa Tin học . getch(). int gd.

mode = 0.y2). a). y1) thì ta có đường gấp khúc khép kín. int y2).yn) trùng với (x1.a).20. int y). int dy). ta phải đưa n điểm vào một mảng a kiểu int một chiều: a[0]=x1.Vẽ và tô màu hình đa giác fillpoly(n.5."d:\\tc\\bgi"). poly2).30.Vẽ đường thẳng nối 2 điểm void line(int x1. &mode. poly1).100}. a[1]=y1. setfillstyle(2. int x2. a[2]=x2. n : số đỉnh a : mảng một chiều chứa giá trị vị trí của đỉnh Khi điểm cuối (xn.… . n : số đỉnh a : mảng một chiều chứa giá trị vị trí của đỉnh Ví dụ 3: Vẽ đường gấp khúc và hình tam giác. y) . getch(). Sau khi vẽ.5.116 - .Vẽ đường thẳng từ điểm hiện tại đến điểm có toạ độ hơn kém một lượng (dx.yn). con trỏ chuyển đến điểm (x.100.5.100.h" void main() { int mh = 0. (x1.h" #include "stdio.30. #include "graphics. Khoa Tin học . a[3]=y2.300. drawpoly(4. . (x.Vẽ đường thẳng từ điểm hiện tại đến điểm có toạ độ được chỉ định void lineto(int x. setbkcolor(1).Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang Để vẽ hình gấp khúc đi qua n điểm (x1. YELLOW).y1).dy) void linerel(int dx.40.…(xn. y1): toạ độ điểm thứ nhất (x1. // Xay dung cac toa do dinh int poly1[]={5. y1): toạ độ điểm thứ hai Chú ý: Vị trí con trỏ không thay đổi sau khi vẽ. int poly2[]={100. int y1. initgraph(&mh. y) : toạ độ điểm.100. closegraph(). (x2. } c.50}.Vẽ đường gấp khúc khép kín: drawpoly(n. Đường thẳng . fillpoly(4. . thì trước hết.390.

int thickness). Tác động đến nét vẽ của các thủ tục line. int y1. int dy). int depth. int x2. (x1. int y2).Di chuyển con trỏ đến vị trí chỉ định void moveto(int dx.Vẽ HCN có các cạnh song song với các cạnh màn hình void rectangle(int x1. int x2. d. int x2. int y2.… Hàm này cho phép ta ấn dịnh 3 yếu tố của đường thẳng là dạng. lineto.Vẽ và tô màu HCN void bar(int x1. rectangle. cirrcle. int y1. y2): toạ độ đỉnh bên trên trái và bên dưới phải của HCN. KIỂU ĐƯỜNG . y) đến điểm (x + dx.Hàm void setlinestyle(int linestyle. y1). y2): toạ độ đỉnh bên trên trái và bên dưới phải của HCN. + Dạng: do tham số linestyle quy định. int y1. Hình chữ nhật (HCN) . int top). Sau đây là một số dạng mặc định.Vẽ khối hộp CN void bar3d(int x1.117 - . . y1). Tham số top có thể nhận trị 0 (không hiển thị mặt trên của khối CN). (x2. . y1). (x1. tham số depth xác định số điểm ảnh trên bề sâu của khối 3 chiều. bề dày. drawpoly. hay 1 (có mặt trên). . DẠNG SOLID_LINE Khoa Tin học GIÁ TRỊ Ý NGHĨA 0 nét liền .Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang Đường thẳng được vẽ từ vị trí hiện tại (x. (x2. HCN này được tô màu. (x2. TopON TopOFF 6. int pattern. y2): toạ độ đỉnh bên trên trái và bên dưới phải của HCN. y + dy). int y2) (x1. Con trỏ di chuyển đến vị trí mới. kiểu.

0. . line(0. 100. //Luu lai kieu cu getlinesettings(&kieucu).Giáo trình Ngôn ngữ lập trình C DOTTED_LINE CENTER_LINE DASHED_LINE USERBIT_LINE 4 1 2 3 nét chấm nét chấm gạch nét gạch mẫu tự tạo Trần Uyên Trang + Bề dày: do tham số thickness quy định. 0. int thickness.h" #include "conio. Sau đây là một số dạng mặc định: NORM_WIDTH = 1 bề dày bình thường THICK_WIDTH = 3 bề dày gấp 3 + Kiểu: nếu tham số là USERBIT_LINE thì ta có thể tạo ra mẫu đường thẳng bằng tham số pattern. #include "graphics."d:\\tc\\bgi").setcolor(RED). pattern. 100). Cho phép nhận các giá trị của 3 yếu tố ở mục 1. setbkcolor(WHITE). unsigned int upattern.getch(). initgraph(&mh.0. THICK_WIDTH). &mode.118 - .Hàm void getlinesettings(struct linesettingstype *lineinfo). Ví dụ: int pettern = 0x1010. 100). setlinestyle(USERBIT_LINE. NORM_WIDTH). 100). 100.h" void main() { int mh= 0. //Thiet lap kieu moi setlinestyle(DOTTED_LINE. với linesettingstype được định nghĩa như sau: struct linesettingstype { int linestyle. 150. line(0.getch(). } Ví dụ 4: Minh hoạ hàm setlinestyle và getlinesettings. line(50. //Phuc hoi kieu cu Khoa Tin học . struct linesettingstype kieucu. mode=0.0.

goto tt. y2). x2=getmaxx(). kieucu. Kiểu thể hiện do tham số writemode xác dịnh. Ứng dụng: Khi thiết lập kiểu writemode bằng XOR_PUT rồi vẽ lại đường thẳng cùng màu thì sẽ xoá đường thẳng cũ và trả về màn hình nguyên thuỷ.BLUE).upattern. x2. Khi thực hiện."d:\\tc\\bgi"). lineto. x2. rectangle. drwpoly.Hàm void setwritemode(int writemode). y1. tt: rectangle(x1.h" #include "stdio.delay(200). mode = 0. x1=0. &mode. + Nếu writemode = XOR_PUT (= 1): màu của đường thẳng sẽ kết hợp với màu của từng chấm điểm của đường hiện hành trên màn hình theo phép XOR để tạo nên một đường thẳng mới. if( (x1+1)<(x2-1)&&(y1+1)<(y2-1)) { rectangle(x1.x2. } setwritemode(COPY_PUT).Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang setlinestyle(kieucu. setwritemode(XOR_PUT). 100.y2=getmaxy().y2--. int x1. } .//Xoa HCN x1++. line(50. Thiết lập kiểu thể hiện đường thẳng cho các hàm line.thickness).y1=0. y2.//tro ve overrite mode getch(). y1. kieucu. setbkcolor(CYAN).y1++ . setfillstyle(CLOSE_DOT_FILL.h" void main() { int mh = 0. setcolor(YELLOW). ta sẽ thấy hình chữ nhật thu nhỏ dần vào tâm màn hình. y2).x2--. closegraph().linestyle. Khoa Tin học .150.200). initgraph(&mh. #include "graphics.h" #include "dos. getch(). + Nếu writemode = COPY_PUT (= 0): đường thẳng được vẽ đè lên dòng hiện hành.119 - . linerel. y1. closegraph(). Ví dụ 5: minh hoạ cách dùng hàm setwritemode.

Giáo trình Ngôn ngữ lập trình C }

Trần Uyên Trang

7. CỬA SỔ (viewport)
a. Viewport: là một vùng chữ nhật trên màn hình đồ hoạ tựa như window trong textmode. - Để thiết lập viewport ta dùng hàm sau: void setviewport(int x1, int y1, int x2, int y2, int clip); (x1, y1), (x2, y2): toạ độ đỉnh bên trên trái và dưới phải của cửa sổ. clip: cho phép vẽ ra ngoài cửa sổ mới hay không, tuỳ thuộc vào giá trị sau: Nếu clip=1: không cho phép Nếu clip=0: cho phép Ví dụ: setviewport(100, 100, 200, 200, 1); sẽ thiết lập một cửa sổ mà góc phải của nó có toạ độ là (0,0) và không cho phép vẽ ra cửa sổ mới này. - Nhận viewport hiện hành, ta dùng hàm sau: void getviewsettings(struct viewporttype *vp); với viewporttype là kiểu cấu trúc được định nghĩa như sau:

struct viewporttype {
int left, top, right, bottom; int clip; } - Xoá viewport hiện hành, ta dùng hàm sau: void clearviewport(void); - Xoá mọi thứ trên màn hình và đưa con trỏ về toạ độ (0, 0) của màn hình, ta dùng hàm sau: void cleardevice(void); b. Toạ độ âm dương: Nhờ sử dụng viewport ta có thể viết các chương trình theo tọa độ âm dương. Muốn vậy, ta thiết lập viewport sao cho tâm tuyệt đối của màn hình là góc trái trên của viewport, và tham số clip = 0 để có thể vẽ ra ngoài viewport. Ví dụ: Đoạn mã thực hiện việc này int xmid, ymid; xmid=getmaxx()/2;ymid=getmaxy()/2; setviewport(xmid, ymid, getmaxx(), getmaxy(), 0); Như thế, màn hình sẽ được chia thàmh 4 phần với toạ độ âm dương như sau: x âm y âm x dương y âm

Khoa Tin học

- 120 -

x âm x dương y dương y dương

Giáo trình Ngôn ngữ lập trình C

Trần Uyên Trang

Ví dụ 6: Vẽ đồ thị hàm sin trong hệ trục toạ độ âm dương. #include "graphics.h" #include "stdio.h" #include "math.h" void main() { double scaleX=20; double scaleY=50 ; int mh = 0, mode = 0; int xmid,ymid, x, y, i; initgraph(&mh, &mode,"d:\\tc\\bgi"); xmid=getmaxx()/2;ymid=getmaxy()/2; setviewport(xmid,ymid,getmaxx(),getmaxy(),0); //Ke he truc toa toa do setcolor(BLUE); line(0, -ymid, 0, ymid); line(-xmid, 0, xmid, 0); settextjustify(1,1); setcolor(RED); outtext("(0,0)"); for(i= -400;i <= 400; i++) { x = floor(2*M_PI*i*scaleX/200); y = floor(sin(2*M_PI*i/200)*scaleY); putpixel(x, y, YELLOW); } getch(); closegraph(); }

8. TÔ ĐIỂM, TÔ MIỀN
- Tô điểm (x, y) theo màu xác định: void putpixel( int x, int y); - Lấy số hiệu màu ở điểm ảnh (x, y) unsigned getpixel(int x, int y); Khoa Tin học - 121 -

Giáo trình Ngôn ngữ lập trình C

Trần Uyên Trang

Nếu điểm này chưa được tô màu bởi các hàm vẽ hoặc putpixel, mà chỉ mới thiết lập setbkcolor thôi thì hàm trả về giá trị 0. Vì vậy, có thể xác định các nét vẽ trên màn hình đồ hoạ và vẽ ra giấy bằng đoạn sau: if (getpixel(x, y)!=0) { // điểm (x, y) được vẽ; } - Tô miền void floodfill(int x, int y, int border); (x, y) toạ độ của một điểm trong miền cần tô (điểm gieo) border: chứa mã của một màu Sự hoạt động của hàm này phục thuộc vào giá trị x, y, border và trạng thái màn hình. Cụ thể: - Khi trên màn hình có đường (cong, gấp khúc) khép kín mà mã màu của nó (màu viền) bằng giá trị border (màu tô) thì: + Miền giới hạn bởi đường kín sẽ được tô màu nếu diểm gieo nằm trong miền. + Trong trường hợp trái lại, phần ngoài hình bao bởi đường sẽ được tô. - Khi trên màn hình không có một đường cong như vậy, thì cả màn hình được tô màu. Ví dụ 7: Vẽ một dường tròn đỏ trên nền xanh. Toạ độ điểm gieo (x,y) được nhập từ bàn phím. Tuỳ thuộc vào (x,y) mà chương trình sẽ cho các kết quả khác nhau. #include "graphics.h" #include "conio.h" void main() { int mh= 0, mode=0; int x, y; initgraph(&mh, &mode,"d:\\tc\\bgi"); setbkcolor(CYAN);setcolor(RED); setfillstyle(11,BLUE); circle(320,100,50); moveto(1,150); outtext("Toa do diem gieo: "); scanf("%d%d", &x, &y); floodfill(x, y, RED); getch(); closegraph(); } Khoa Tin học - 122 -

XỬ LÝ VĂN BẢN TRÊN MÀN HÌNH ĐỒ HOẠ a. . c.CHR tồn tại trên đĩa) Trong đó: . 100. sẽ hiển thị trên màn hình đồ hoạ bằng outtext hoặc outtextxy. outtext( “Cong Nghe Thong Tin”).Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang 9. int vert). scanf(). … Nếu chasize =10: font được thể hiện trong hình chữ nhật 80*80 pixel.Hàm void outtext(char *str). Font: Các tệp tin font chữ có phần mở rộng là . các hàm getch(). Các font này cho các kích thước và kiểu chữ khác nhau.chasize: là hệ số phóng to kí tự và có giá trị trong (1. Để chọn và nạp font. int chasize). (Hàm này chỉ có tác dụng khi tệp .font: xác định kiểu chữ và nhận một trong các hằng sau: DEFAULT_FONT=0 TRILEX_FONT=1 SMALL_FONT=2 SANS_SERIF_FONT=3 GOTHIC_FONT=4 . y) Ví dụ:2 đoạn mã sau đây tương đương về tác dụng: outtextxy(100. và moveto(100.123 - . Chú ý: Trong màn hình đồ hoạ. b. Trong đó: Khoa Tin học . .direction: là một trong 2 hằng số: HORIZ_DIR = 0: văn bản sẽ hiển thị theo hướng nằm ngang VERT_DIR = 1: văn bản sẽ hiển thị theo hướng đứng từ dưới lên. 100). ta dùng hàm sau: void settextstyle(int font. char *str). Chú ý: các giá trị do settextstyle thiết lập sẽ giữ nguyên cho đến khi gọi một settextstyle mới. Nếu chasize =2: font được thể hiện trong hình chữ nhật 16*16 pixel.Hàm void outtextxy(int x. 10) Nếu chasize =1: font được thể hiện trong hình chữ nhật 8*8 pixel. Xử lí văn bản trên màn hình đồ hoạ . hiển thị chuỗi str tại vị trí (x. int direction. int y. hiển thị chuỗi str tại vị trí hiện hành của con trỏ. Vị trí hiển thị void settextjustify(int horiz. kbhit() vẫn tác dụng như màn hình text. “Cong Nghe Thong Tin”).CHR trên đĩa.

size.1) outtextxy(100. size <= 5. mode=0.Hàm void textheight(char *str). Ví dụ:Với 8*8 bitmap font và hệ số khuếch đại là 1 thì textheight(“H”)=8.h" #include "conio. &mode.Hàm void textwidth(char *str). d.0). y. Bề rộng và bề cao của văn bản . trả lại chiều cao của chuỗi mà str trỏ tới. "TIN HOC").size). kích thước font. initgraph(&mh.h" void main() { int mh= 0. CẮT."d:\\tc\\bgi"). outtextxy(0.horiz là một trong các hằng sau: LEFT-TEXT=0: văn bản xuất hiện bên phải con trỏ CENTER_TEXT=1: con trỏ ở tâm văn bản RIGHT_TEXT=2: văn bản xuất hiện bên trái con trỏ BOTTOM_TEXT=0: văn bản xuất hiện phía trên con trỏ CENTER_TEXT=1:con trỏ ở tâm văn bản TOP_TEXT=2: văn bản xuất hiện phía dưới con trỏ Ví dụ: settextjustify(1. settextjustify(0. closegraph(). DÁN. VẼ HÌNH CHUYỂN ĐỘNG Khoa Tin học . y. y+= textheight("TIN HOC")+10. } . hệ số khuếch đại. size++) { settextstyle(0. } getch().Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang . “PHNG”). for (size = 1. trả lại bề rộng của chuỗi do str trỏ tới dựa vào chiều dài chuỗi. Ví dụ 8: Cho hiện 5 dòng chữ với định dạng khác nhau #include "graphics. 100. y =10.0.124 - . 10.

30. 20. Chép điểm ảnh void getimage(int x1. cao của nó vào vùng nhớ do bitmap trỏ tới. int x2. Khoa Tin học . initgraph(&mh. b. y1. Vùng nhớ và biến bitmap cho bởi hàm malloc. putimage.125 - . Độ lớn của vùng nhớ được xác định bằng hàm imagesize."d:\\tc\\bgi").h" void main() { int mh= 0. &mode. #include "graphics. int y1. y2) và các thông tin về bề rộng. 40). p). d. void *bitmap. 20. Sao lưu ảnh void putimage(int x. int y2. p = (char*)malloc(size). char *p. AND_PUT =3: các điểm ảnh trong bitmap kết hợp với các điểm ảnh trên màn hình theo phép AND. sau đó lặp lại đúng câu lệnh đó thì hình sẽ bị xoá và màn hình trỏ lại như cũ. Tham số copymode xác định kiểu sao chép ảnh: COPY_PUT=0: sao chép nguyên xi XOR_PUT=1:các điểm ảnh trong bitmap kết hợp với các điểm ảnh trên màn hình theo phép XOR. getimage(10. unsigned size. c. size = imagesize(10. Kỹ thuật này được dùng để tạo các hình ảnh chuyển động. int copymode). n: số byte của vùng nhớ. getimage.h" #include "alloc. Chép các điểm ảnh của HCN (x1. Sao lưu ảnh trong vùng nhớ bitmap ra màn hình tại vị trí (x. Lấy số byte cần thiết để lưu ảnh trong phạm vi HCN: unsigned imagesize(int x1.Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang a. 40. getmaxy()/2). int x2. x2. int y2). Ví dụ 9: Ví dụ minh hoạ cách dùng imagesize. malloc. int y. Tạo con trỏ trỏ tới một vùng nhớ mới được cấp phát #include “alloc.0. y). getmaxx()/2.h” void *malloc(unsigned n). void *bitmap). mode=0. 30. OR_PUT=2: các điểm ảnh trong bitmap kết hợp với các điểm ảnh trên màn hình theo phép OR. NOT_PUT =4: ảnh xuất hiện trên màn hình theo dạng đảo ngược ( phép NOT) với ảnh trong bitmap. bar(0. int y1. Chú ý: Nếu dùng XOR_PUT đẽ chép hình.

i. p. 100. char *p[101]. //Luu hien trng 100 hinh chu nhat tren man hinh de khoi phuc Khoa Tin học .126 - . setcolor(RED). putimage(100.Cách 2: Lưu ảnh vào vùng nhớ rồi đưa ảnh ra màn hình ở các vị trí khác nhau. } e. ++i) putpixel(random(getmaxx()). Ví dụ 10: Bắn pháo hoa trên bầu trời đầy sao. initgraph(&mh.h" #include "alloc.Cách 1: Dùng hàm cleardevice . COPY_PUT). n.Giáo trình Ngôn ngữ lập trình C getch(). Đưa trạng thái cũ màn hình ra xếp đè lên ảnh vừa vẽ. random(getmaxy()). i <= 100. Vẽ một hình ảnh.Cách 3: Lưu trạng thái màn hình vào một chỗ nào đó.Cách 1: vẽ lại một ảnh nhưng ở các vị trí khác nhau . int x[101]. 3/ Xoá hình . mode=0. #include "graphics. . getch().h" void main() { int mh= 0. Tạo ảnh di động Nguyên tắc tạo ảnh di động là: 1/ Vẽ một hình (trong chuỗi hình di động) 2/ Delay 3/ Xoá hình đó 4/ Vẽ hình kế tiếp 5/ Delay … Trần Uyên Trang 1/ Vẽ một hình (trong chuỗi hình di động) . &mode.h" #include"stdlib. y[101]. closegraph()."d:\\tc\\bgi"). cleardevice(). //Ve bau troi day sao for(i = 1. random(getmaxcolor())).Cách 2: Dùng hàm putimage (mode XOR_PUT) để xếp chồng lên ảnh cần xoá.

p[i]). getimage(x[i]. y[i]+10). y[i]. delay(500). closegraph(). 5). getch(). x[i]+10. y[i]+10. if (x[i] < 0) x[i] = 0. 360. } delay(500). } //Chu trinh ban phao hoa do { //Dua 100 qua phao len man hinh tai cac vi tri quy dinh for (i = 1. i <= 100. y[i]. 0. p[i] = (char*)malloc(n).Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang for (i = 1.p[i]. getch(). ++i) { setfillstyle(SOLID_FILL. } while(!kbhit()). y[i]+5. COPY_PUT). pieslice(x[i]+5. i--) putimage(x[i]. i<= 100. //Xoa chum phao vua ban bawng cach khoi phuc man hinh for (i = 100. y[i] = random(getmaxy()) -10. ++i) { x[i] = random(getmaxx()) -10. x[i]+10.i%15+1). i >= 1. y[i]. n = imagesize(x[i].127 - . } Khoa Tin học . if (y[i] < 0) y[i] = 0.

tính phân phối và tính tổng quát. Có nên dùng tiếng Việt trong chương trình C? CHƯƠNG 2 CÁC KIỂU DỮ LIỆU CƠ SỞ 2. là gì? 3.128 - . Chương trình nguồn là gì? Chương trình đích là gì? 8. tính trong sáng. Thuận lợi khi sử dụng ngôn ngữ bậc cao? 6. tính hiệu quả. Vì sao phải biết các từ khóa của C? 4. Cho biết tên của một số thiết bị nhớ phụ điển hình. Hãy nêu các thành phần chính của một chương trình C. CHƯƠNG 1 CÁC THÀNH PHẦN CƠ BẢN CỦA C 1. Hãy kể ra các kí tự trong C. Ý nghĩa và tầm quan trọng của từ “main”. 6. Tại sao các đặc tính này lại quan trọng? 8. Byte. Thế nào là lời chú giải trong C? Các chú thích thường được đặt ở đâu? Đặt như thế nào? 3. Ngôn ngữ máy là gì? Sự khác nhau giữ ngôn ngữ mày và ngôn ngữ bậc cao? 5.Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang BÀI TẬP CHƯƠNG 0 GIỚI THIỆU 1. Ý nghĩa của quá trình biên dịch? Ý nghĩa của quá trình thông dịch? Hai quá trình này khác nhau như thế nào? 7. Tại sao khi viết mã nguồn. Tên là gì? Dùng để làm gì? 5. Hãy tổng quát hoá ý nghĩa của các đặc tính sau: tính toàn vẹn. tính đơn giản. Có phải các chương trình C phải được viết bằng chữ thường không? Các kí tự viết hoa có được sử dụng trong chương trình C không? Giải thích. nodle. word. Máy tính cá nhân là gì? 2. Cho biết một số ngôn ngữ bậc cao thông dụng. bit. Hãy nêu nguồn gốc phát triển và tác giả của ngôn ngữ C. ta thường phải thụt vào? 7. 2. Khoa Tin học . Các loại bộ nhớ này khác bộ nhớ chính ở chỗ nào? 4.

5 b) 12. Thế nào là một biến? Nêu các đặc điểm của biến? 15. white. void. Mục đích của khai báo kiểu dữ liệu? Nêu cú pháp của một khai báo? 16. Tính điểm trung bình và hiển thị theo dạng sau: Ho ten: Nguyen Van A Điem toan: 8. name_address. Khi viết số nguyên. có phải các biến phải được khai báo trước khi được sử dụng? 17. Bảng mã ASCII là gì? Cụ thể về các nhóm kí tự được mã hoá trong bảng mã? 13. Hãy cho biết tên và diễn giải bốn kiểu dữ liệu cơ bản trong C. Mục đích của số mũ trong hằng dấu chấm động là gì? 11. Hãy tổng quát hoá các luật xác định cách đặt tên trong C? Các kí tự viết thường có tương đương với viết hoa khống? Một tên được định nghĩa có thể bao gồm các số không? Có thể bao gồm cả kí tự đặc biệt không? 4. Xác định các hằng chuỗi kí tự trong số các hằng sau: a) ‘abn’ d) “11:12:97” b) “Red. 5. Hằng số nguyên không dấu (unsigned integer) là gì? Thế nào là một hằng số nguyên dài? Làm thế nào để phân biệt các hằng số nguyên này? 9. Mỗi hừng kí tự đại diện cho một giá trị số phải không? 12. Xác định các trị số đúng của các hằng sau: a) 0.129 - . file_3.00 Diem hoa: 8. Thông thường thì miền giá trị lớn nhất của hằng nguyên là bao nhiêu? Hãy viết các giá trị đó trong các hệ trên. Trong C. Xác định các hằng kí tự trong số các hằng sau: a) ‘a’ b) ‘\\’ c) ‘\0’ d) ‘xy’ e) ‘\032’ f) ‘&’ g) ‘\n’ h) ‘\a’ k) ‘T’ l) ‘\0xef’ 21.50 Diem tb: 8. Hằng chuỗi kí tự là gì? Có khác với hằng kí tự không? 14. diểm toán. Hằng kí tự là gì? Nêu sự khác nhau giữa hằng kí tự với các hằng số. nam address. \$tax. Hãy mô tả 2 cách viết khác nhau của hằng dấu chấm đọng? Các quy luật nào được áp dụng cho mỗi trường hợp? 10. Hãy nêu các từ khoá trong C. return. Cho biết cách gán giá trị cho biến khi khai báo? 18. Viết chương trình nhập vào: tên học sinh.12 c) 9e12 d) 1e-12 f) 29374 g) 0. 123_ten. điểm lý.Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang 3.3E12 h) 0x8273ef k)01234 l) 01122 m)0xefef 20. làm thế nào để phân biệt là trong hệ 10. 8. blue” e) “Please contact me …” c) “Ten: f) “Chuong 3” 22. điểm hoá. Xác định các tên đúng: record. 19. 6. hệ 8 hay hệ 16? 7. name.00 Diem ly: 9.50 Khoa Tin học .

--. Tính diện tích của nó. CÂU LỆNH VÀ CÁC PHÉP TOÁN Biểu thức là gì? Các thành phần của một biểu thức? Toán tử là gì? Nêu các loại toán tử có trong C? Toán hạng là gì? Mối liên hệ giữa toán hạng và toán tử? Nêu 5 loại toán tử số học trong C? Tổng quát hoá luật kết hợp giữa các toán tử? 26 Làm thế nào để chuyển một giá trị trả về bởi biểu thức sang một kiểu dữ liệu khác? Gọi quá trình chuyển đổi này là gì? 27 Thứ tự của các toán tử có ý nghĩa như thế nào? Nêu các mối liên hệ về thứ tự của các toán tử? 28 Khi nào thì nên sử dụng dấu ngoặc trong biểu thức? Khi nào nên tránh sử dụng chúng? 29 Các toán tử được thực hiện theo thứ tự như thế nào trong một biểu thức có chứa các dấu đóng mở ngoặc lồng nhau? 30 Cho biết tác dụng của toán tử ++. Các cách dùng khác nhau của chúng? 31 Cho biết số byte được cấp phát cho mỗi kiểu dữ liệu trong C? 32 Các toán tử lôgic trong C. Viết chương trình nhập vào hai đáy và chiều cao hình thang. #define? 41 Hãy viết mục đích của các biểu thức sau: a) a . Viết chương trình hiển thị một mẫu đơn giản tự chọn.Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang 23.b d) a != b b) a*(a+b) e) (a/b)%5 c) d = a*(a+b) f) –h Khoa Tin học . phải khai báo gì trong chương trình? 40 Cách sử dụng của phát biểu #include. CHƯƠNG 3 BIỂU THỨC. chúng được sử dụng với các với các toán hạnh nào? Các toán tử này thuộc kiểu biểu thức nào? 33 Toán tử trên bit? 34 Công dụng của toán tử lôgic not ( ! )và toán tử not bit (~). 24. Hai toán tử này có giống nhau không? 35 Với hai toán hạn khác kiểu thì một biểu thức gán được xác định như thế nào? Nguyên nhân gây ra lỗi trong trường hợp này? 36 Nêu các phép gán trong C? Trật tự thực hiện chúng như thế nào? 37 Có phải các hàm thư viện của C cũng là một phần của ngôn ngữ C? Giải thích? 38 Đối số là gì? Cách viết đối số? Cách gọi một hàm thư viện trong C? Cách gọi hàm không có đối? 39 Để sử dụng các hàm thư viện của C.130 22 23 24 25 .

75.8 g) 2 h) Không phải các giá trị trên.0 + (int) 3. mục đích của chúng: a) abs(i-2*j) l) sqrt(x*x+y*y) 2 44 Khoa Tin học . p = 4.0 d) Không phải các giá trị trên. b) Chỉ dẫn #define có thể được sử dụng đề cho chương trình dễ đọc. z = (int)3. 45 Tìm câu sai: a) Sử dụng chỉ dẫn #define nói chung làm giảm kích thước chương trình. Viết chương trình tính x mũ y. e) 1 f) 1. 46 Toán tử nào không phải là toán tử gán: a) = b) += c) != d)?= 26.8 b) 6.2) && (n . float y = 9.131 - . z = y/z. long q = 2. kết thúc. float x = 1.8 .Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang 42 Giả sử có khai báo sau: int n = 10. Hãy cho biết ý nghĩa. a) 6.10) g) n < p j) x*(q = = 2) h) n >= p k) x*(q = 5) i) n > q l) (float)n/p Cho biết giá trị của x nếu: int x = 5. c) Chỉ dẫn #define không có dấu . dễ hiểu. 43 Tìm giá trị của x: float z . Viết chương trình tính z = e a +sin ( x ) −x Các biểu thức sau có sử dụng các hàm thư viện. Biểu thức (100>79) && (‘A’< ‘B’) có tương đương với 100>79&&‘A’< ‘B’? 27.0. Hãy cho biết kiểu và giá trị của các biếu thức sau: d) n + q g) q + 3*(n > p) e) n + x h) q&&n f) n%p + q i) (q .z.0 c) 7.

5.y) g) floor(x+y) r) tolower(80) h) islower(c) s) pow(x. So sánh toán tử điều kiện?: với lệnh if…else. ‘r’) . ta làm gì? 30.Giáo trình Ngôn ngữ lập trình C b) fabs(x+y) c) isprint(c) d) isdigit(c) e) toupper(d) f) ceil(x) g) floor(x+y) h) islower(c) i) issupper(j) j) exp(x) k) log(g) m) isalnum(10*i) n) isascii(20*i) o) isalpha(10*i) p) toascii(10*i) q) fmod(x. Ý nghĩa của cấu trúc lựa chọn? 3.y) i) issupper(j) t) sin(x+y) j) exp(x) u) srlen(‘‘the word’’) k) log(g) v) strpos(‘‘the word’’. Hãy xác định giá trị trả về của các biểu thức sau theo khai báo: int i = 8. double x = 0.005. j = 10. Mục đích sử dụng toán tử if… else. Các toán tử if else lồng nhau đợc dịch như thế nào? Hãy cho biết cách dịch phát biểu sau: if e1 if e1 S1 else S2 7. CHƯƠNG 4 CÁC CÂU LỆNH ĐIỀU KHIỂN 1. d = 'd' . Muốn biết hình dáng kí tự có mã ASCII là 222. y = -0. Trần Uyên Trang 28. ‘r’) . 6.y) t) sin(x+y) u) srlen(‘‘the word’’) v) strpos(‘‘the word’’. Ý nghĩa của cấu trúc rẽ nhánh? 2.132 - .01 . 29. Lập chương trình: a) Đầu tiên in ra dòng chữ: Ngon ngu lap trinh Khoa Tin học . Hằng kiểu kí tự và biến kiểu kí tự được dịch như thế nào khi chúng được sử dụng như là các toán hạng trong biểu thức quan hệ? 4. a) abs(i-2*j) l) sqrt(x*x+y*y) b) fabs(x+y) m) isalnum(10*i) c) isprint(c) n) isascii(20*i) d) isdigit(c) o) isalpha(10*i) e) toupper(d) p) toascii(10*i) f) ceil(x) q) fmod(x. char c = ’c’ .y) r)tolower(80) s) pow(x. Lập chương trình hiển thị một chữ cái ngẫu nhiên.

c) Nếu bấm phím C thì máy hiện ra: Turbo C d) Nếu bấm P thi hiện ra: Pascal 8. Lập chương trình giải phương trình bậc nhất một ẩn.Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang b) Nếu không bấm phím hoặc bấm một phím khác C và P thì dòng chữ tiếp tục hiện ra. bặc hai một ẩn.133 - . hệ phương trình bậc một hai ẩn. Khoa Tin học .

M). nếu Delta là một tên đã định nghĩa. ta nên viết là: #define length (3+5) Khoa Tin học .… .Phép thế không thực hiện cho các hằng chuỗi kí tự (được đặt trong dấu “ ”). trước khi định nghĩa lại. cho tới cuối tệp gốc.” . M). máy sẽ thay thế tên bằng dãy_kí_tự.Cuối dòng #define không có dấu “.Phạm vi của tên được định nghĩa là từ lúc nó được định nghĩa.134 - . #define M 300 in("\nN=%d M=%d". Điều này có tác dụng tránh sự lặp lại những câu lệnh. ta nên giải phóng nó bằng chỉ thị: #undef tên (Nếu không giải phóng. máy sẽ cảnh báo khi chạy chương trình) Ví dụ 1: Cho biết kết quả chương trình sau: #include "stdlib. (=3+5) nhưng doublesize = 2*length sẽ là 2*3+5 Do đó. #undef M #define M (N+400) in("\nN=%d M=%d". thì sẽ không có việc thay thế nào trong câu lệnh sau: printf(“\nDelta”).Trong chương trình. CHỈ THỊ #define ĐƠN GIẢN (MACRO) a. Cách viết: #define tên dãy_kí_tự .Khi định nghĩa một biểu thức. M). } b. ta nên đặt nó trong các dấu ngoặc đơn. . N. khi máy gặp tên. Chẳng hạn. in("\nN=%d M=%d". Tuy nhiên. getch(). và từ thời điểm này trở đi nó có ý nghĩa mới.Có thể định nghĩa lại tên (đã định nghĩa).Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang THAM KHẢO CÁC CHỈ THỊ TIỀN XỬ LÝ 1. biểu thức. Một số chú ý . Ví dụ:#define length 3+5 thì size = length. N. N.h" #define in printf #define N 100 void main() { int M=200. .

CHỈ THỊ #define CÓ ĐỐI (MACRO) a. Ví dụ:#define cube(y) (y*y*y) thì khi viết : cube(a + b) sẽ nhận được kết quả là: cube(a+b*a+b*a+b) chứ không phải là cube(a+b)*(a+b)*(a+b) 3. r + s). b. B) (A)>(B)?(A):(B) là sai. nghĩa là chương trình sẽ kết thúc với mọi giá trị của x! . CHỈ THỊ BAO HÀM TỆP #include a.Một số định nghĩa thông dụng: #define PI 3. lệnh x = max(p + q. . Ví dụ:#define max(A. exit(1). sẽ được thay bằng: x = (p + q) > ( r + s)?(p + q):(r + s).Khi viết biểu thức thay thế.} nhưng nếu ta không dùng cặp {} ở định nghĩa thì (1) sẽ tương đương với: if (x > max) printf(“\nKet thuc”). B) ở trên có thể dùng cho kiểu nguyên hay thực … đều được. Khi đó văn bản thay thế sẽ phụ thuộc vào cách gọi tới macro. Đối của macro không có kiểu nhất định. ta nên đặt nó trong cặp dấu {} Ví dụ: #define Ketthuc {printf(“\nKet thuc”). .Khi định nghĩa một đoạn chương trình gồm nhiều lệnh.Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang . Một số chú ý . Cho nên. exit(1). exit(1). B) (A)>(B)?(A):(B) Khi đó.14159 #define begin { #define end } #define TRUE 1 #define FALSE 0 #define ESC 0x1b 2.Như vậy.} thì nếu trong chương trình ta sử dụng lệnh: f (x > max) Ketthuc //(1) sẽ tương đương với: if (x > max) {printf(“\nKet thuc”). Ví dụ:Khai báo: #define max (A. macro max(A. các đối hình thức cần được bao quanh bởi các dấu ngoặc đơn “(…)”. Chỉ thị #include chỉ đường cho bộ tiền xử lí nhận nội dung của tệp khác và đặt chèn vào tệp chương trình nguồn đang xét. ta có thể xây dựng được các hàm đơn giản để sử dụng trong chương trình.135 - . b. Có thể dùng #define để định nghĩa các macro có đối tương tự như hàm. Các cách viết Khoa Tin học . nhờ các macro có đối.Giữa tên macro và dấu mở ngoặc “(” không có dấu cách.

c có chứa chỉ thị #include “tệp1”. … Nếu trong một chương trình nào đó ta cần đến các hàm trong các tệp trên. Ví dụ:#include <e:\thuvien\ matran. Công dụng của #include . #include sẽ tìm tệp trong thư mục INCLUDE của Turbo C. Mỗi hàm do một nhóm người xây dựng.c” #include <hamtoan. tệp gốc main.c” #include “hamtoan.c. Nếu không tìm thấy thì chương trình sẽ báo lỗi. Khoa Tin học . tìm trong thư mục hiện hành. Cách thức làm việc của 2 dạng #include trên chỉ khác nhau khi không có thông tin đường dẫn. các hàm xử lí ma trận được lưu ở tệp matran. Để tránh lỗi này khi dịch. Chương trình này được dịch và thực hiện theo các quy tắc như đối với một chương trình viết trên một tệp. Ví dụ: #include <d:\TurboC\hamtoan. chương trình sẽ tìm tệp theo tên và đường dẫn ghi trong chỉ thị. .c. Còn #include ở cách 2 thì trước tiên. Chẳng hạn. nên các hàm thường được chứa trên các tệp khác nhau.136 - . Chỉ thị #include cho phép ghép các hàm trên các tệp khác nhau vào tệp gốc để tạo thành một chương trình hoàn chỉnh.Cách 1: #include <[dường dẫn]tên_tệp> . Nếu tìm thấy thì nội dung của tệp này được chèn vào tệp nguồn đang xét tại đúng vị trí của #include.c d.Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang . vì có những đối tượng được khai báo lại.Sử dụng được các tệp có sẵn của TC. cả hai tệp tệp1 và tệp2 đều được ghép vào tệp main. thì trước khi dịch tệp main. CÁC CHỈ THỊ BIÊN DỊCH CÓ ĐIỀU KIỆN #if Giả sử chương trình của ta cần đến các tệp module_a và module_b: #include “module_a “ #include “module_b” Và trong cả 2 tệp này đều có chứa chỉ thị #include “tệp x” thì có thể gây ra lỗi khi dịch.c> 4.Tổ chức thư viện: trong quá trình làm việc ta thường xây dựng được các hàm hữu ích.Tổ chức chương trình trên nhiều tệp: một chương trình lớn thường gồm nhiều hàm. ta dùng các chỉ thị #if.c. thì ta chỉ cần đưa các tệp trên vào chương trình bằng chỉ thị #include. ở cách 1.c> #include “d:\TurboC\hamtoan. Chẳng hạn. Như vậy . Trong tệp1 lại có chứa chỉ thị #include “tệp1”. trên thực tế thì chương trình chứa trên nhiều tệp nhưng nhờ #include ta vẫn có thể xem như một tệp. Khi đó. nếu không thấy thì tiếp tục tìm trong thư mục INCLUDE.c> c. Các #include lồng nhau: C cho phép các #include lồng nhau. .Cách 2: #include “[dường dẫn]tên_tệp” * Tác dụng: Trước khi dịch. các hàm đồ hoạ được lưu ở dohoa.

ngược lại sẽ biên dịch đoạn chương trình 2.Dạng 3: #ifndef tên_macro đoạn chương trình #endif Ý nghĩa: nếu tên_macro chưa được định nghĩa (bởi #define) thì trình biên dịch Turbo C sẽ dịch đoạn chương trình nằm giữa #ifndef và #endif. Các chỉ thị này có thể dùng theo các dạng sau: . đoạn này sẽ bị bỏ qua.Dạng 1: #ifdef tên_macro đoạn chương trình #endif Ý nghĩa: nếu tên_macro đã định nghĩa (bởi #define) thì trình biên dịch Turbo C sẽ dịch đoạn chương trình nằm giữa #ifdef và #endif. Khoa Tin học . Các tên đã được định nghĩa bằng #define cũng được xem là các hằng. Trái lại. Trái lại. . trái lại dịnh đoạn chương trình 2. Trái lại. . 5. biểu_thức_hằng là biểu thức là các toán hạng của nó đều là các hàng. CÁC CHỈ THỊ BIÊN DỊCH CÓ ĐIỀU KIỆN #ifdef VÀ #ifndef Một phương pháp biên dịch có điều kiên khác là dùng chỉ thị #ifdef và #ifndef. đoạn này bị bỏ qua. đoạn này bị bỏ qua. .Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang Các dạng chỉ thị #if .Dạng 1: #if biểu_thức_hằng đoạn chương trình #endif Tác dụng: Nếu biểu_thức_hằng là đứng thì TC sẽ biên dịch đoạn chương trình giữa #if và #endif. chúng có nghĩa là: “nếu đã định nghĩa” và “nếu chưa định nghĩa”.Dạng 2: #ifdef tên_macro đoạn chương trình 1 #else đoạn chương trình 2 #endif Ý nghĩa: nếu tên_macro đã định nghĩa (bởi #define) thì trình biên dịch Turbo C sẽ dịch đoạn chương trình 1.Dạng 2: #if biểu_thức_hằng đoạn chương trình 1 #else đoạn chương trình 2 #endif Tác dụng: nếu biểu_thức_hằng là đúng thì Turbo C sẽ biên dịch đoạn chương trình 1.137 - .

138 - .Dạng 4: #ifndef tên_macro đoạn chương trình 1 #else đoạn chương trình 2 #endif Trần Uyên Trang Ý nghĩa: nếu tên_macro chưa được định nghĩa (bởi #define) thì trình biên dịch Turbo C sẽ dịch đoạn chương trình 1. mặc dù tệp beta. #else printf("no max"). Các phiên bản sau của beta. Chú ý: Các đoạn chương trình trong #ifdef và #ifndef có thể chứa các chỉ thị tiền xử lí. khi lập trình ta nên tổ chức chúng như sau (giống như cách tổ chức các tệp tiêu đề của C): Ví dụ tệp beta . Ví dụ: #if(soluong>soluongmax)||(chiso>soluongmax) Khoa Tin học .Giáo trình Ngôn ngữ lập trình C .h đều bị bỏ qua vì _BETA_H_ đã được định nghĩa trong lần đầu gặp tệp beta.h) 7.h được chèn vào tệp nguồn tại nhiều chỗ. TỔ CHỨC CÁC TỆP THƯ VIỆN Để các tệp tiêu đề (tệp thư viện) có thể được kết nối nhiều lần vào một chương trình nguồn mà không gây lỗi. #endif } 6. sẽ dịch đoạn chương trình 2. #endif #ifndef min printf("min").h #endif Như vậy. Ví dụ 4: Cho biết kết quả chạy chương trình sau: #define ted 10. nhưng nó chỉ được biên dịch lần đầu (lúc đó _BETA_H_ còn chưa xác định). Trái lại. CHỈ THỊ #error Chỉ thị #error sẽ dừng biên dịch chương trình và in ra một thông báo lỗi.h: #ifndef _BETA_H_ #define_BETA_H_ //Nội dung thực sự của tệp beta . Chỉ thị này có thể sử dụng để kiểm tra tính nhất quán của các hằng. main() { #ifdef max printf("\nmax"). Nên chúng ta có thể sử dụng các phương án lồng nhau dối với #ifdef và #ifndef như thể đã làm với #if.

139 - . can so luong lon hon!!! #endif Khoa Tin học .Giáo trình Ngôn ngữ lập trình C Trần Uyên Trang #error Soluongmax qua nho.

scribd
/*********** DO NOT ALTER ANYTHING BELOW THIS LINE ! ************/ var s_code=s.t();if(s_code)document.write(s_code)//-->