You are on page 1of 72

Tài liệu tham khảo

„ The C Programming Language (2nd Edition) Kernighan & Ritchie

Ngôn ngữ lập trình C „


Prentice Hall 1988.
Ngôn Ngữ Lập Trình C. Quách Tuấn Ngọc. Nhà Xuất Bản Giáo Dục,
1998.
„ Efficient C programming. Mark Allen Weiss. Prentice Hall, 1998.
„ Kỹ thuật lập trình C, cơ sở và nâng cao. Phạm Văn Ất. Nhà Xuất
Bản Khoa Học & Kỹ Thuật.

Chương 1: Giới thiệu chung

Cao Tuấn Dũng


2007

Lập trình C - Việt Nhật 2007 2

Một số khái niệm Các lớp Ngôn ngữ lập trình


„ Computer program –chương trình máy tính là một tập các câu
lệnh (instruction) hướng dẫn máy tính làm một số việc nhất 5GLs artificial intelligence
định.
4GLs ORACLE, SEQUEL, INGRES, ...
„ Programming language - Ngôn ngữ lập trình là ngôn ngữ để
viết chương trình. Có nhiều loại ngôn ngữ lập trình. HIGH-LEVEL ForTran, COBOL, C, C++,
„ Compiler – trình biên dịch, là phần mềm chịu trách nhiệm dịch LANGUAGES LISP, Pascal, Java, ...
chương trình viết bằng một ngôn ngữ lập trình sang dạng mã ASSEMBLER LANGUAGES
máy.
MACHINE CODE

Lập trình C - Việt Nhật 2007 3 Lập trình C - Việt Nhật 2007 4

1
Thuật toán - Algorithm Thuật giải tốt
„ Tập các lệnh được tổ chức có thứ tự nhằm giải quyết một bài „ Một thuật giải tốt là thuật giải:
toán hoặc đạt đến một mục tiêu nào đó. ‰ chính xác
„ Ví dụ: ‰ rõ ràng
‰ hướng dẫn chế biến một món ăn, ‰ đúng
‰ hướng dẫn sửa chữa xe máy, ‰ hiệu quả
‰ cách giải một bài toán. ‰ và có thể bảo trì được.
‰ …
„ Algorithm –Thuật toán - Thuật giải „ Chúng ta có thể viết một thuật giải cho máy tính bằng ngôn
ngữ bình thường nhưng có thể không rõ ràng. Thay vào đó,
chúng ta sẽ dùng ngôn ngữ lập trình (hoặc một ngôn ngữ giả
lập ngôn ngữ lập trình gọi là mã giả pseudocode)

Lập trình C - Việt Nhật 2007 5 Lập trình C - Việt Nhật 2007 6

Tính điểm trung bình môn học Sơ đồ xử lý


„ Nhập: điểm thực hành Vật Lý, điểm bài tập, điểm bài kiểm tra „ Sử dụng sơ đồ xử lý để minh họa quá trình xử lý một chương
giữa học kỳ, điểm bài kiểm tra cuối học kỳ. trình.
Điểm hệ số
Thực hành : 8 2 start,stop
bài tập: 9 2 condition expression data
KT giữa kỳ: 8 4
KT cuối kỳ: 8 6
flow
process
„ Tổng cộng: TONG = 8*2 + 9*2 + 8*4 + 8*6
„ Điểm trung bình: TB = TONG/(2+2+4+6)
Bài tập: dùng sơ đồ để biểu diễn bài toán nhập và tính điểm
trung bình.
Lập trình C - Việt Nhật 2007 7 Lập trình C - Việt Nhật 2007 8

2
Ngôn ngữ C - Lịch sử phát triển Ngôn ngữ C – Đặc điểm chính
„ C được ra đời tại Bell Lab vào 1972, cha đẻ là Dennis Ritchie. „ Tính hiệu quả cao, đặc biệt là trong lập trình hệ thống
‰ Cho phép truy nhập trực tiếp đến từng bit, byte, các cổng dữ liệu.
„ C và mối liên hệ với hệ điều hành Unix
„ Linh hoạt và mạnh
„ Kernighan và Ritchie đưa ra phiên bản C chuẩn đầu tiên năm ‰ Bản thân ngôn ngữ không đặt ra giới hạn đối với người lập trình
1978. ‰ Các ứng dụng phát triển từ C rất đa dạng.
„ Nằm giữa lớp ngôn ngữ lập trình bậc cao và bậc thấp
„ ANSI C - C được chuẩn hóa vào năm 1989 bởi American „ Tính khả chuyển cao
National Standards Institute. ‰ Một chương trình C viết trên một hệ thống máy tính này, có thể
dịch và chạy trên một hệ thống khác mà không hay ít phải sửa
đổi.

Lập trình C - Việt Nhật 2007 9 Lập trình C - Việt Nhật 2007 10

Ngôn ngữ lập trình C Cấu trúc một chương trình C


1 /* Fig. 2.1: fig02_01.c
„ có thể đọc và viết mã chương trình trên hầu hết các hệ thống. 2 A first program in C */ Khai báo tệp tiêu đề
„ chuyển lên C++ và có thể viết các kịch bản CGI (CGI script)
3 #include <stdio.h> #include <stdio.h>
4
cho các Website. 5 int main() #include <math.h>
6 {
„ C là ngôn ngữ biên dịch (complied language). 7 printf( "Welcome to C!\n" ); Khai báo các cấu trúc, biến,
8
9 return 0; hàm có sử dụng đến
10 }
Hàm chính main()
- Điểm bắt đầu của chương
C
- Các chú thích nằm trong /*….*/ trình
- Câu lệnh kết thúc bằng dấu ; - Chỉ có duy nhất
Compiler
- { } mở và đóng một khối lệnh - Từ hàm main thường gọi
Viết chương trình bằng ngôn ngữ C bằng đến các chương trình con
các chương trình soạn thảo (emacs, vi,
Hello (hàm) khác.
các công cụ viết chương trình)
Không dùng các chương trình soạn thảo
văn bản (vd:Word, WordPad)
Lập trình C - Việt Nhật 2007 11 Lập trình C - Việt Nhật 2007 12

3
Giới thiệu chung về Linux Hệ thống file trên Linux
„ Linux là phiên bản phát triển có mã nguồn mở của hệ điều ƒ Trong Linux, các tập tin được
hành Unix sắp xếp theo một dạng tương tự
cấu trúc cây. Thư mục gốc là /
„ Linux ban đầu được tạo ra bởi Linus Toward, năm 1991
„ Trên góc độ kỹ thuật, tên gọi Linux chỉ tương ứng với nhân ƒ Linux phân biệt chữ hoa, chữ
của hệ điều hành (kernel), cung cấp các dịch vụ truy nhập thường đối với tên file
quản lý tài nguyên phần cứng cho người sử dụng và các ƒ Mỗi người sử dụng khi được
chương trình ứng dụng tạo tài khoản sẽ có một thư mục,
„ Các bản phân phối Linux: RedHat, SuSE, Debian, Mandrake. gọi là thư mục home. Ký hiệu ~.
„ Linux kế thừa các ưu điểm của dòng hệ điều hành Unix: môi Thông thường người dùng
trường đa người dùng, đa nhiệm, chạy trên nhiều platform userid sẽ có thư mục home là
khác nhau. /home/userid
„ Linux có thể chạy tốt trên nhưng hệ thống cấu hình rất thấp
nhưng cũng chạy ổn định trên cả các máy chủ.

Lập trình C - Việt Nhật 2007 13 Lập trình C - Việt Nhật 2007 14

Một số lệnh cần thiết Trình soạn thảo emacs


„ Đổi mật khẩu tài khoản: passwd „ Linux tồn tại sẵn một số lệnh soạn thảo tập tin văn bản như
„ Hiện đường dẫn tới thư mục hiện hành: pwd lệnh vi.
„ Liệt kê danh sách các file trong thư mục: ls tên_thư_mục „ emacs (editor macros): trình soạn thảo văn bản đa chức
‰ ls –l examples xem nội dung thư mục con examples của thư mục hiện
hành theo từng trang. năng. Hai phiên bản phổ biến: GNU emacs và xemacs
„ Tạo thư mục : mkdir tên_thư_mục „ Dùng ngôn ngữ emacs lisp với khả năng mở rộng: soạn thảo,
„ Chuyển tới thư mục mới : cd đường_dẫn căn lề, nhận biết tag, gọi chương trình dịch, thậm chí duyệt
„ Xem nội dung file: cat tên_file Web.
„ Xóa một thư mục hay file: rm „ emacs cho phép làm việc trên nhiều cửa sổ và bộ đệm. Nội
„ Sao chép file: cp nguồn đích dung soạn thảo không ghi trực tiếp vào file mà ghi lên bộ
„ Xem hướng dẫn sử dụng một lệnh: đệm.
‰ man tên_lệnh. Ví dụ man mv
„ emacs làm việc theo lệnh. Người sử dụng gõ lệnh trên cửa sổ
‰ lệnh --help
lệnh để tác động lên nội dung trong bộ đệm
„ Tìm thư mục chứa lệnh: which tên_lệnh which gcc
„ Thoát khỏi hệ thống: logout

Lập trình C - Việt Nhật 2007 15 Lập trình C - Việt Nhật 2007 16

4
Các lệnh cơ bản trong emacs Các lệnh trong emacs (tiếp)
„ Quy ước: „ Di chuyển con trỏ theo từ:
‰ viết "C-x " là bấm nút Ctrl và phím "x", viết M-x có nghĩa là bấm phím ‰ Về sau: M-f. Về trước M-b
Meta(phím Alt hoặc Escape ) và phím "x"
‰ Viết C-x-h nghĩa là bấm Ctrl và x sau đó bấm h. „ Theo câu: Chú ý emacs phân biệt câu với dòng.
„ Trở về trạng thái chờ lệnh: C-g ‰ Về đầu : M-a, về cuối câu: M-e.
„ Thao tác với file: „ Theo bộ đệm: Về đầu: M-v. Về cuối: C-v
‰ Tìm và mở file: C-x C-f tên_file. Có thể sử dụng phím Tab để xem danh
sách tập tin. „ Thao tác soạn thảo, cắt dán
‰ Lưu nội dung bộ đệm vào file: C-x C-s ‰ Xóa ký tự: Del hoặc C-d
‰ Lưu với tên khác: C-x C-w tên ‰ Xóa từ con trỏ đến hết từ: M-d. Xóa từ con trỏ đến hết dòng: C-k
„ Di chuyển con trỏ ‰ Xóa một dòng: C-a C-k
‰ Sử dụng các phím mũi tên
‰ Chọn tất cả: C-x h. Undo : C-x u
‰ Lên dòng trên C-p, xuống dòng dưới C-n
‰ Phía trước một ký tự C-b, sau một ký tự C-f ‰ M-w: copy vùng được đánh dấu.
‰ Về đầu dòng C-a, về cuối dòng C-e ‰ C-w: cắt vùng đánh dấu. C-y dán nội dung.

Lập trình C - Việt Nhật 2007 17 Lập trình C - Việt Nhật 2007 18

Các lệnh trong Emacs Biên dịch chương trình C trên Linux
„ Tìm kiếm trong văn bản: „ Hầu hết các bản phân phối của Linux đều tích hợp với trình
‰ Tìm xuôi chiều C-s từ_cần_tìm biên dịch ngôn ngữ C: gcc.
‰ Tìm ngược chiều C-r từ_cần_tìm „ Sử dụng gcc
‰ gcc mặc định sẽ biên dịch tập tin mã nguồn thành mã đối tượng,
„ Soạn thảo trên nhiều cửa sổ sau đó liên kết mã đối tượng để tạo ra tập tin thực thi
‰ Cho phép theo dõi nội dung ở những phần khác nhau của file ‰ Nếu không chỉ định tên tập tin thực thi, mặc định kết quả sẽ là
‰ C-x-2 Chia hai cửa sổ theo chiều ngang a.out
‰ C-x-3 Chia hai cửa sổ theo chiều dọc ‰ Các tham số biên dịch
‰ C-x-0 di chuyển giữa hai cửa sổ „ -Wall : bật tất cả các cảnh báo
„ -c: chỉ biên dịch tạo tập tin mã đối tượng (object) a.o
‰ C-x-1 Xóa tất cả các cửa sổ và về lại cửa sổ đầu tiên
„ -o: chỉ định tên file thực thi mong muốn
„ Thoát khỏi Emacs „ -g: thêm thông tin gỡ rối (debug)
‰ C-x-c „ -l: chỉ định thư viện liên kết.
gcc –Wall hello.c –o runhello
./runhello

Lập trình C - Việt Nhật 2007 19 Lập trình C - Việt Nhật 2007 20

5
Biên dịch chương trình C trên Linux Một số lỗi thường gặp khi biên dịch
„ Các tập tin makefile cho phép: „ Segfaults
‰ Tạo các script biên dịch, tiết kiệm thời gian gõ lệnh ‰ Khi có lỗi truy nhập bộ nhớ. Ví dụ: cố gắng truy nhập thông tin từ
‰ Tiết kiệm thời gian biên dịch vì chỉ dịch lại những tập tin có thay một con trỏ NULL.
đổi „ Linker errors
‰ Rất phức tạp và dễ gây lỗi. ‰ Lỗi trong dòng lệnh gcc hay makefile
„ Có thể sử dụng lại „ Multiple definitions of functions
EXEC_NAME = helloWorld ‰ Định nghĩa sai trong cái chỉ thị tiền xử lý trong tập tin header như:
all: main.o #ifndef, #define
gcc –g –o $(EXEC_NAME) main.o
main.o: main.c
gcc –g –c main.c –o main.o
clean:
rm –rf main.o $(EXEC_NAME)

Lập trình C - Việt Nhật 2007 21 Lập trình C - Việt Nhật 2007 22

Chương trình C đầu tiên


1. #include <stdio.h>
Ngôn ngữ lập trình C 2.

3. int main()
4. {
5. printf(“Hello\n");
6. return 0;
Chương 2: Khái niệm cơ sở
Biến, Hằng, Toán tử, Kiểu dữ liệu cơ sở, Các phép toán và Các từ
khóa
7. }

Cao Tuấn Dũng


2007

Lập trình C - Việt Nhật 2007 24

6
Chương trình C Mở rộng 1
„ #include <stdio.h> 1. #include <stdio.h>
‰ khai báo sử dụng thư viện xuất/nhập chuẩn (standard I/O library).
2.
Các thư viện khác: string, time, math…
„ int main() 3. int main()
‰ khai báo hàm main(). Chương trình C phải khai báo (duy nhất) 4. {
một hàm main(). Khi chạy, chương trình sẽ bắt đầu thực thi ở
câu lệnh đầu tiên trong hàm main(). 5. int a, b, c;
„ {…} 6. a = 5;
‰ mở và đóng một khối mã. 7. b = 7;
„ printf
8. c = a + b;
‰ hàm printf() gửi kết xuất ra thiết bị xuất chuẩn (màn hình). Phần
nằm giữa “…“ gọi là chuỗi định dạng kết xuất (format string) 9. printf(“%d + %d = %d\n“, a, b, c);
„ return 0; 10. return 0;
ngừng chương trình. Mã lỗi 0 (error code 0) – không có lỗi khi
‰
chạy chương trình. 11. }
Lập trình C - Việt Nhật 2007 25 Lập trình C - Việt Nhật 2007 26

Tên (Định danh) Biến (variable)


„ Tên dùng để xác định các đối tượng khác nhau trong chương „ Biến tương ứng với một vùng trống nào đó trong bộ nhớ máy tính
dùng để giữ các giá trị. Là đại lượng mà giá trị của nó có thể thay đổi trong
trình quá trình tính toán.
„ Tên biến, tên hàm, tên hằng, tên nhãn. „ Một biến luôn có: tên, kiểu, kích thước, giá trị.
„ Việc đọc giá trị một biến không làm thay đổi giá trị của nó
„ Quy tắc đặt tên:
‰ Bao gồm các chữ cái, chữ số, dấu gạch dưới „ Khai báo: <type> <var-name>;
‰ Không được bắt đầu bằng chữ số ví dụ:
‰ Phân biệt chữ hoa chữ thường. int b;
float m_1, m_2; Biến
‰ Không trùng với các từ khóa. Gán giá trị vào biến: 45
„ nguyên
<var-name> = <value>;
„ Tên đúng: sothu_3, tigiack vd: b = 5;

„ Sử dụng biến:
„ Tên sai:x^2, y-2, 23ant printf(“%d + %d = %d\n“, a, b, c);

Lập trình C - Việt Nhật 2007 27 Lập trình C - Việt Nhật 2007 28

7
Mở rộng 2 Chú ý
1. #include <stdio.h> 12 c „ C phân biệt chữ hoa/chữ thường do đó phải viết đúng tên
2. 7 b lệnh.
3. int main() 5 a vd: printf chứ không phải là Printf, pRintf, PRINTF.
4. {
5. int a, b, c; „ Trong câu lệnh scanf() để lấy giá trị vào biến, phải luôn dùng
6. printf(“Nhap so thu nhat: “); dấu & trước tên biến.
7. scanf(“%d”, &a); /ngonnguC/bin/tong
8. printf(“Nhap so thu hai: “); „ Khi gọi các hàm phải khai báo các tham số đúng vị trí và đầy
Nhap so thu nhat: 5 đủ.
9. scanf(“%d”, &b);
Nhap so thu hai: 7
10. c = a + b;
11. printf(“%d + %d = %d\n“, a, b, c); „ Phải khai báo biến trước khi sử dụng trong chương trình.
5 + 7 = 12
12. return 0;
/ngonnguC/bin/
13. }

Lập trình C - Việt Nhật 2007 29 Lập trình C - Việt Nhật 2007 30

Các kiểu dữ liệu cơ bản Biến và hằng số


„ Character: char (ký tự 1-byte) „ Biến số (variable) được dùng để giữ các giá trị và có thể thay
„ Integer: int (các giá trị nguyên 2-byte) đổi các giá trị mà biến đang giữ
‰ -32768 đến 32767
„ Số nguyên không dấu: unsigned int „ Khai báo: <typename> varname;
‰ 0 đến 65535
Vd:
int i;
„ Số phẩy động độ chính xác đơn: float (các giá trị dấu chấm
float x, y, z;
động 4-byte)
char c;
‰ (+,-)3.4E-38 , (+,-)3.4E+38
„ Số phẩy động độ chính xác kép: double (dấu chấm động 8- „ Gán giá trị cho biến: <varname> = <value>;
byte) vd:
‰ (+,-)3.4E-308 , (+,-)3.4E+308 i = 4;
x = 5.4;
y = z = 1.2;
Lập trình C - Việt Nhật 2007 31 Lập trình C - Việt Nhật 2007 32

8
Hằng số Kiểu và chuyển kiểu (typecasting)
„ Hằng số (constant) giá trị không thay đổi trong quá trình sử „ C cho phép chuyển đổi kiểu dữ liệu cơ bản trong khi đang
dụng. tính toán (chuyển kiểu tường minh).
Khai báo hằng: „ ví dụ:
#define <constantname> <value> void main()
{
vd: float a;
#define TRUE 1 int b;
#define FALSE 0 b = 10/3;
a = (float)10/3;
„ Giá trị hằng printf(“a = %f \n b = %d\n”, a, b);
‰ Hằng nguyên: 3423, 0x48 = 4*16+8=72 }
‰ Hằng dấu phẩy động: -231.292, 123.456E-4
‰ Hằng ký tự: ‘a’, ‘b’ „ Chuyển kiểu tự động: khi biểu thức gồm hai toán hạng khác
‰ ‘9’ – ‘0’ = 57 – 48 = 9 kiểu thì kiểu thấp hơn sẽ được nâng thành kiểu cao hơn
‰ 1.5*(11/3)=4.5
Lập trình C - Việt Nhật 2007 33 Lập trình C - Việt Nhật 2007 34

Định nghĩa kiểu (typedef) Các Toán tử


Priority Category Example Associativity
„ Có thể định nghĩa các kiểu riêng bằng lệnh typedef.
0 Primary expression identifiers constants None
1 Postfix Function() () [] -> left to right
vd: 2 Prefix and unary ! ~ + - ++ -- & sizeof right to left
#define TRUE 1 2 Type cast ( typeName ) right to left

#define FALSE 0 3 Multiplicative * / % left to right

typedef int boolean; 4 Additive + - left to right


5 Shift << >> left to right
6 Relational < <= > >= left to right
void main() { 7 Equality == != left to right
boolean b; 8 Boolean AND & left to right

b = FALSE; 9 Boolean XOR ^ left to right

/*...*/ 10 Boolean OR | left to right


11 Logical AND && left to right
}
12 Logical OR || left to right
13 Conditional operator ? Right to left

14 Assignment = *= /= %= += -= right to left


&= |= ^= <<= >>=

Lập trình C - Việt Nhật 2007 35 Lập trình C - Việt Nhật 2007 36

9
Các toán tử so sánh và toán tử logic Số nhị phân
Relational and Quality Operators Possible Mistakes „ Hệ đếm thập phân:
X Y X<Y X <= Y X>Y X >= Y X != Y X == Y X=Y X<<Y X>>Y ‰ 5426=5*103 + 4*102 + 2*101 + 6*100
3 3 0 1 0 1 0 1 3 24 0 ‰ 254,68 = 2*102 + 5*101 + 4*100 + 6*10-1 + 8*10-2
3 4 1 1 0 0 1 0 4 48 0
„ Hệ đếm nhị phân (cơ số hai): Hệ chỉ có hai chữ số 0 và 1.
4 3 0 0 1 1 1 0 3 32 0
‰ 1000 10112 = 1*27 + 0*26 + 0*25 + 0*24 + 1*23 + 0*22 + 1*21 + 1*20 =
27 + 23 + 21 + 20 = 139
‰ 1011.012 = 1*23 + 0*22 + 1*21 + 1*20 + 0*2-1 + 1*2-2 = 11.25
Logical Operators Possible Mistakes „ Một chữ số nhị phân – BIT – là đơn vị lưu trữ thông tin nhỏ nhất
X Y X && Y X || Y !X !Y X&Y X|Y của máy tính.
0 0 0 0 1 0 0 0
„
0 7 0 1 1 0 0 7
5 0 0 1 0 1 0 5
5 7 1 1 0 1 5 7
8 7 1 1 0 1 0 15

Lập trình C - Việt Nhật 2007 37 Lập trình C - Việt Nhật 2007 38

Các phép toán số học Toán tử tăng giảm


„ + - / * „ Có thể viết i=i+1; (i=i-1;) dưới dạng
„ %: phép chia lấy phần dư trong số nguyên. (modulo). ‰ i++; ( i--; )
„ i = i + 1; i++; ++i; ‰ hay ++i ( --i; )
„ i = i – 1; i--; --i; „ Sự khác nhau giữa tiền tố và hậu tố
„ i = i + 3; i += 3; ‰ i++, giá trị của i tham gia vào việc lượng giá biểu thức chứa nó
„ i = i * j; i *= j; trước khi tăng.
„ Phép chia kiểu nguyên: 7/5 cho kết quả 1. ‰ ++I, giá trị của i tăng, sau đó giá trị mới có hiệu lực khi lượng giá
„ Phép lấy phần dư: 7 % 5 cho kết quả 2. biểu thức chứa nó.
„ Thứ tự ưu tiên: „ Ví dụ: Với i= 4
Toán tử Tên gọi Thứ tự tính toán (precedence) ‰ j = ++i +10; cho j bằng 15 và j= i++ +10; cho j=14.
() Ngoặc tròn Được ưu tiên nhất. Tính giá trị đầu tiên trong một biểu thức int i= 6;
printf ("%d\n",i++); /* Prints 6 sets i to 7 */
*, /, or % Nhân, chia, lấy Độ ưu tiên thứ hai, nếu cùng tồn tại thì được thực hiện từ
phần dư trái qua phải int i= 6;
+ or - Cộng, trừ Độ ưu tiên thấp nhất printf ("%d\n",++i); /* prints 7 and sets i to 7 */
Lập trình C - Việt Nhật 2007 39 Lập trình C - Việt Nhật 2007 40

10
Các phép gán tắt

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

Chương 3: Cách thức vào ra

Cao Tuấn Dũng


2007

Lập trình C - Việt Nhật 2007 41

Dòng vào, ra chuẩn Hàm printf


„ Việc nhập dữ liệu được thực hiện thông qua „ int printf (char* địnhdạng, [danh sách đối,….]
dòng vào chuẩn stdin (bàn phím) „ Vd: printf(“Gia tri ham tai toa do %d,%d la %f”, 2,3, 1.09);
‰ Khi có dữ liệu trên dòng vào chuẩn, các hàm „ Dạng tổng quát của đặc tả chuyển dạng
nhận dữ liệu như scanf, getchar sẽ lấy phần dữ a 12 1.4 ‰ %[-] [width][.prec] ký tự chuyển dạng
liệu mà nó yêu cầu
‰ width: dãy số nguyên xác định độ rộng tối thiểu của giá trị hiển thị
‰ Khi dòng vào không đủ dữ liệu: máy chờ người
‰ .prec: dùng cho kiểu float, double
dùng
Ký tự chuyển dạng Kiểu giá trị của đối số Ý nghĩa
„ Dòng ra chuẩn: màn hình c char Đối số là một ký tự
„ Các hàm xuất dữ liệu d int Đối số là số nguyên có dấu
‰ Printf, putchar ld long Đối số là số nguyên lớn
„ Thư viện vào ra chuẩn: stdio.h f float, double Đối số là số dấu phẩy tĩnh
s char * Đối số là xâu ký tự
u unsigned int Đối số nguyên không dấu

Lập trình C - Việt Nhật 2007 43 Lập trình C - Việt Nhật 2007 44

11
Hàm printf Ký tự Escape
„ Khi không có mặt dấu trừ: kết quả dồn về bên phải. Ngược lại, kết „ Đánh dấu các ký tự đặc biệt: \’, \”, \n, \t, \r, \\, \0
quả dồn về bên trái „ Dùng trong hàm printf để định dạng dòng ra
„ Ký tự chuyển dạng bắt đầu = 0, nếu độ dài của đối số nhỏ hơn
width thì kết quả sẽ điền các ký tự 0 vào bên trái.
„ Ví dụ: int i = -124;
Lệnh Kết quả
printf("%-5d", i); "-124 "
printf("%5d", i); " -124"
printf("%-05d", i); "-124"
printf("%05d", i); "-0124"
char c='j'; float x=28.932, y= 4.061;
printf("%c nam o toa do %2.3f %f", c, x, y);
Sẽ hiển thị: j nam o toa do 28.932 4.061000
Lập trình C - Việt Nhật 2007 45 Lập trình C - Việt Nhật 2007 46

Hàm scanf Một số hàm nhập xuất khác


„ Có một số đặc điểm tương tự printf nhưng theo chiều ngược lại: „ getchar: Nhập một ký tự từ dòng vào:
đọc thông tin từ dòng vào. „ int getchar();
„ Cú pháp: int scanf(char *định_dạng, [danhsachdiachi]); ‰ int c;
„ Trả về giá trị EOF nếu có lỗi. ‰ c = getchar();
„ Xâu định dạng có cú pháp: %[*][width]kýtựchuyểndạng „ putchar
‰ putchar(int c);
„ fflush(stdin): Làm sạch dòng vào.
int a; char ten[30];
int t;
float x, y; x = 5.432 printf( "\nTuoi:");
char ch[6], ct[6]; y=25.0 scanf("%d",&t);
fflush(stdin); /* xoá mọi ký tự ở dòng vào */
scanf("%f%5f%3d%3s%s", &x, &y,&a, ch, ct); a=123 printf( "\nTen:");
scanf("%s",ten);
ch="572"
54.32e-1 25 12357287a ct="87a „ Nhập xuất xâu:
‰ char *gets(char *s) nhận dữ liệu cho đến khi gặp '\n'

Lập trình C - Việt Nhật 2007 47 Lập trình C - Việt Nhật 2007 48

12
Câu lệnh điều kiện if
if (<dieu kien>)

Ngôn ngữ lập trình C {


/* cac lenh thuc hien neu dieu kien dung */
}

True False
expression
Một quyết định có thể
được đưa ra dựa trên bất
Các cấu trúc điều khiển cứ một biểu thức nào. statement(s)
0 - false
Cao Tuấn Dũng khác 0 - true
2007 Ví dụ:
Next statement
3 - 4 - true

Lập trình C - Việt Nhật 2007 50

Ví dụ Ví dụ
1. #include <stdio.h> „ Mã giả (pseudo code): Nếu điểm thi lớn hơn hay bằng 5 thì sinh viên
đã vượt qua kỳ thi.
„ Mã chương trình C: if ( diemthi >= 5 )
2. int main() { printf( "Vuot qua ky thi\n" );
3. int b;

4. printf("Enter a value:");
5. scanf("%d", &b); true
diemthi >= 5 print “Qua”
6. if (b < 0)
7. printf("The value \
false
is negative\n");
8. return 0;
9. }
Lập trình C - Việt Nhật 2007 51 Lập trình C - Việt Nhật 2007 52

13
if … else … Ví dụ
if (<dieu kien>) …
{ printf(“1/X is: “);
/* cac lenh thuc hien neu dieu kien dung */
if(X)
}
printf(“ %f \n”, 1/X);
else
{ else
/* cac lenh thuc hien neu dieu kien sai */ printf(“ undefined \n”);
} True False …
… expression

statement1 statement2

Next statement
Lập trình C - Việt Nhật 2007 53 Lập trình C - Việt Nhật 2007 54

Ví dụ Lỗi đơn giản nhưng dễ phạm


„ Mã giả (pseudo code): Nếu điểm thi lớn hơn hay bằng 5 thì sinh viên 1. #include <stdio.h>
đã vượt qua kỳ thi nếu không thì sinh viên thi trượt.
„ Mã chương trình C: if ( diemthi >= 5 ) 2. int main() {
printf( "Vuot qua ky thi\n" );
else printf( "Truot\n" ); 3. int b;
„

4. printf("Enter a value:");
5. scanf("%d", &b);
false true
diemthi >= 5 6. if (b == 5)
print “Truot” print “Qua” 7. printf(“b is "); printf( “5 \n”);
8. return 0;
9. }

Lập trình C - Việt Nhật 2007 55 Lập trình C - Việt Nhật 2007 56

14
Lỗi đơn giản nhưng dễ phạm Lệnh if else if
1. printf(“1/X is: “); Khi muốn thực hiện 1 trong n quyết định
2. if(X < 0) ; if (biểu thức1)
3. printf(“ X is negative \n”); lệnh 1;
+
4. … else if (biểu thức2)
Biểu thức 1 Lệnh 1
lệnh 2;
-

+
else if (biểu thức_n_1) Lệnh 1
Biểu thức 2
lệnh n -1;
-
else lệnh n;
Lệnh ứng với else cuối cùng

Lập trình C - Việt Nhật 2007 57 Lập trình C - Việt Nhật 2007 58

Lệnh if else if Ví dụ: Kiểm tra nhiều điều kiện


„ Lập chương trình nhập vào mã trình độ và đưa ra tên trình độ tương 1. #include <stdio.h>
ứng 2. int main() {
int b;
#include <stdio.h>
int main() 3. printf("Enter a value:");
{
4. scanf("%d", &b);
int ma;
printf("\n Go vao ma trinh do:"); 5. if (b < 0)
scanf("%d", &ma); 6. printf("The value is negative\n");
if (ma==1) 7. else if (b == 0)
printf("\n Trinh do trung cap");
8. printf("The value is zero\n");
else if (ma==2)
printf("\n Trinh do cao dang"); 9. else
else if (ma==3) 10. printf("The value is positive\n");
printf("\n Trinh do dai hoc"); 11. return 0;
else
12. }
printf("\n Nhap sai ma");
return 0;
} ‰ Bài tập: Viết chương trình giải phương trình bậc nhất:
ax + b = 0. Biện luận các điều kiện có nghiệm của phương trình.
Lập trình C - Việt Nhật 2007 59 Lập trình C - Việt Nhật 2007 60

15
Điều kiện lồng nhau Lặp - lệnh while
„ Câu lệnh if có thể được lồng vào nhau. „ while (bieu thuc dieu kien)
1. if ( X >= 0 ) {
{cac lenh}
2. if ( Y < 0 )
3. Y = Y + sqrt(X); ‰ Khi biểu thức điều kiện (expression) còn khác 0 (TRUE), lệnh
4. } (statement) tiếp tục được thực hiện. Nếu expression bằng 0
5. else (FALSE), lệnh while dừng và chương trình sẽ gọi lệnh kế tiếp
6. Y = Y + sqrt(-X); sau while.
‰ Nếu lúc đầu expression bằng 0 thì (statement) trong while không
„ Tuy nhiên, cần chú ý đến thứ tự các cặp lệnh if … else … khi lồng
các lệnh if. Nếu không sẽ phát sinh lỗi. bao giờ được gọi thực hiện.
1. if ( X >= 0 )
2. if ( Y < 0 )
False
3. Y = Y + sqrt(X); expression
4. else
5. Y = Y + sqrt(-X); True

Bài tập: Viết chương trình giải phương trình bậc 2: statement(s)
„ Next statement
ax^2 + bx +c = 0. Chú ý các điều kiện có nghiệm.
Lập trình C - Việt Nhật 2007 61 Lập trình C - Việt Nhật 2007 62

Ví dụ Ví dụ: Biến đếm điều khiển


„ In bảng đổi nhiệt độ từ độ Fahrenheit (oF) sang độ Celcius „ Biến đếm điều khiển vòng lặp
(oC). ‰ Lặp cho đến khi bộ đếm đạt tới một giá trị nhất định
‰ Vòng lặp xác định: số vòng lặp được biết trước.
1. #include <stdio.h> ‰ Ví dụ: Một lớp học 120 sinh viên phải làm bài tập. Điểm số (số
nguyên trong khoảng 0 đến 10). Tính điểm bài tập trung bình cho
cả lớp.
2. int main() {
‰ Mã giả:
3. int a = 0; Gán tong bang 0
4. while (a <= 100) { Gán biến đếm sinh viên bằng 1
5. printf("%4d degrees F = %4d degrees C\n",a, (a - 32)*5/9); While biến đếm nhỏ hơn hay bằng 120
Nhập điểm số
6. a = a + 10; Cộng điểm số vào tổng
7. } Tăng 1 vào biến đếm
Điểm trung bình = tổng / 120
8. return 0;
Hiển thị ra màn hình
9. }
Lập trình C - Việt Nhật 2007 63 Lập trình C - Việt Nhật 2007 64

16
1 /*
2 Tinh diem trung binh kiem tra
3
4
Dieu khien vong lap bang bien dem */
#include <stdio.h>
Thiết kế giải thuật Top-down
5
1. Khởi tạo biến
6 int main()
„ Mở rộng bài toán:
7 {
2. Thực hiện vòng
8 int counter, grade, total, average;
lặp Viết chương trình tính điểm trung bình mà số sinh viên không
9
10 /* Khoi tao gia tri bien */
được biết trước.
11 total = 0; ‰ Làm cách nào để kết thúc chương trình?
12 counter = 1;
3. Xuất kết quả
13
„ Sử dụng giá trị có vai trò "lính canh"
14 /* Xu ly */ ‰ Còn có tên gọi khác là cờ
15 while ( counter <= 120 ) {
16 printf( "Nhap diem: " );
‰ Chỉ ra dấu hiệu “kết thúc nhập dữ liệu.”
17 scanf( "%d", &grade ); ‰ Vòng lặp kết thúc khi người sử dụng nhập vào giá trị lính canh.
18 total = total + grade;
19 counter = counter + 1;
‰ Giá trị này được chọn sao cho không thể nhầm lẫn nó với các giá
20 } trị nhập vào thông thường khác.
21
22 /* Kêt thuc */
23 average = total / 120;
24 printf( "Diem trung binh cua ca lop la %d\n", average );
25
26 return 0; /* Chuong trinh ket thuc thanh cong */
27 } Lập trình C - Việt Nhật 2007 65 Lập trình C - Việt Nhật 2007 66

1 /*

Thiết kế giải thuật Top-down


2 Chương trình tính điểm trung bình
3 sự dụng biến canh để điều khiển vòng lặp */
4 #include <stdio.h> 1. Khởi tạo biến
5

„ Tiếp cận top-down, giải quyết từng bước vấn đề 6 int main()
7 { 2. Nhập liệu
‰ Bắt đầu với vấn đề cần giải quyết từ đỉnh (top): 8 float average;
Xác định điểm trung bình kiểm tra của cả lớp 9 int counter, grade, total;
2.1 Thi hành vòng
‰ Phân chia bài toán thành các công việc nhỏ hơn và liệt kê chúng 10
lặp
theo trình : 11 /* khởi tạo */
12 total = 0;
Khởi tạo biến
13 counter = 0;
Nhập dữ liệu, tính tổng và đếm số sinh viên
14
Tính điểm trung bình
15 /* xử lý */
„ Nhiều chương trình trải qua ba giai đoạn: 16 printf( "Nhập điểm, -1 để thoát ra: " );

‰ Khởi tạo: khởi tạo giá trị các biến 17 scanf( "%d", &grade );
18
‰ Xử lý: nhập giá trị dữ liệu và thao tác trên chúng 19 while ( grade != -1 ) {
‰ Kết thúc: Tính toán và hiển thị kết quả cuối cùng 20 total = total + grade;
21 counter = counter + 1;
22 printf( "Enter grade, -1 to end: " );
23 scanf( "%d", &grade );
24 }
Lập trình C - Việt Nhật 2007 67 Lập trình C - Việt Nhật 2007 68

17
1 /* Fig. 3.10: fig03_10.c
2 Phân tích kết quả thi */

Các cấu trúc điều khiển lồng nhau 3


4
#include <stdio.h>

5 int main()
6 {

„ Bài toán 7
8
/* Khai báo khởi tạo biến */
int passes = 0, failures = 0, student = 1, result;
‰ Một học viện có một danh sách kết quả kiểm tra của 120 sinh 9

viên (1 = qua, 2 = trượt) 10


11
/* Làm việc với 120 sinh viên; vòng lặp điều khiển bởi biến đếm */
while ( student <= 120 ) {
‰ Viết chương trình phân tích kết quả 12 printf( "Enter result ( 1=pass,2=fail ): " );
13 scanf( "%d", &result );
„ Nếu có hơn 90 sinh viên thi đỗ, hiển thị "Chất lượng đạt" 14

„ Chú ý 15
16
if ( result == 1 )
passes = passes + 1;
/* if/else lồng trong while */

‰ Chương trình phải xử lý 120 kết quả 17 else


18 failures = failures + 1;
„ Biến đếmđiều khiển vòng lặp có thể được sử dụng 19
‰ Có thể dùng hai biến đếm 20 student = student + 1;
21 }
„ Một cho số lượng thi đỗ, một cho số thi trượt 22
‰ Kiểm tra kết quả thi—hoặc 1 hoặc 2 23 printf( "Passed %d\n", passes );
24 printf( "Failed %d\n", failures );
„ Nếu kết quả không phải là 1, coi như là 2 25
26 if ( passes > 90 )
27 printf( "Chất lượng đạt\n" );
28
29 return 0; /* kết thúc thành công */
Lập trình C - Việt Nhật 2007 69 30 } Lập trình C - Việt Nhật 2007 70

Lặp - lệnh for Ví dụ


„ for (biểu thức khởi tạo; biểu thức kiểm tra; biểu thức tăng „ In ra các số từ 1 đến 10
giảm) for (i = 1; i <= 10; i++)
{Các lệnh}
printf("%d ", i);
‰ Khởi động. Sau đó, nếu điều kiện (test) khác 0: lệnh (statement)
„ Biểu thức khởi tạo được thực hiện một lần, còn các biểu thức
được thi hành, lệnh điều chỉnh lại “biến đếm” được gọi thi hành.
còn lại được tính nhiều lần.
initialization „ Vòng lặp for có thể lồng nhau nhiều lần
False „ Câu lệnh break làm máy thoát khỏi vòng lặp for sâu nhất
test
chứa lệnh đó.
True „ In ra các chữ cái hoa
statement(s) char ch;
for (ch = 'A'; ch <= 'Z'; ch++)
adjustment Next statement printf("%c ", ch);

Lập trình C - Việt Nhật 2007 71 Lập trình C - Việt Nhật 2007 72

18
Lệnh for (tiếp theo) Ví dụ
„ Giữa hai dấu ; có thể có nhiều hơn một biểu thức „ Bài toán đổi nhiệt độ. Yêu cầu: hiển thị nhiệt độ chính xác đến con
số thập phân sau dấu phẩy.
‰ Phân cách nhau bởi dấu phảy.
‰ Example: 1. #include <stdio.h>
for (i = 0, j = 0; j + i <= 10; j++, i++)
printf( "%d\n", j + i );
2. int main() {
3. float a = 0;
4. int i;
5. for(i=0; i<=100; i+=10) {
6. printf("%6.2f degrees F = %6.2f degrees C\n",
a, (a - 32.0) * 5.0 / 9.0);
7. a = a + 10;
8. }
9. return 0;
10. }

Lập trình C - Việt Nhật 2007 73 Lập trình C - Việt Nhật 2007 74

Ví dụ Lặp - lệnh do while


1 /* Tính tổng các số chẵn „ do
2 từ 1 đến 100 */
3 #include <stdio.h>
{statement(s)}
4 while (expression) ;
5 int main() ‰ Thực hiện lệnh (statement). Kiểm tra biểu thức điều kiện
6 { (expression). Nếu (expression) bằng 0, dừng. Nếu không, thực
7 int sum = 0, number;
hiện (statement).
8
9 for ( number = 2; number <= 100; number += 2 ) ‰ Lệnh do while thực hiện (statement) ít nhất một lần.
10 sum += number;
11
12 printf( "Sum is %d\n", sum ); statement(s)
13
14 return 0;
15 } False
expression
Sum is 2550
True Next statement

Lập trình C - Việt Nhật 2007 75 Lập trình C - Việt Nhật 2007 76

19
Ví dụ - giao diện chương trình
1. #include <stdio.h> 14. printf(“ 3. Thoat chuong trinh \n\n”);
2. #define PTB1 1 15. printf(“ Chon muc so (1/2/3) ? “);
3. #define PTB2 2 16. scanf(“%d”, &i);
4. #define STOP 3 17. if(i == PTB1)
18. printf(“Giai phuong trinh bac 1: hien chua co\n”);
19. else if(i == PTB2)
5. int main()
20. printf(“Giai phuong trinh bac 2: chua cai dat\n\n”);
6. {
21. } while (i != STOP);
7. int i;
8. do { 22. return 0;
9. printf(“ Chuong trinh giai phuong trinh bac thap \n”); 23. }
10. printf(“ 1. Giai phuong trinh bac 1: ax + b = 0 \n”);
11. printf(“ 2. Giai phuong trinh bac 2 : ax^2 + bx + c = 0 \n”); „ Bài tập: Ghép chương trình trên với hai chương trình trong bài tập
1 và 2

Lập trình C - Việt Nhật 2007 77 Lập trình C - Việt Nhật 2007 78

break Tìm số nguyên tố lớn


„ dùng để thoát khỏi vòng lặp giữa for… „ Cho trước một số tự nhiên N, tìm số nguyên tố lớn hơn gần
chừng. { nhất.
for… „ Giải pháp:
cú pháp: { ‰ Số nguyên tố là số nguyên tố không chia hết cho các số nhỏ hơn
break; for… căn bậc hai của nó.
{ ‰ Không tính trường hợp 2, 3 thì số nguyên tố phải lẻ.
„ Thường sử dụng cùng với lệnh if để …. „ Thuật toán sơ khởi:
kiểm tra điều kiện dừng trước khi dùng break; ‰ Kiểm tra N và so sánh với 2, 3
lệnh break. … ‰ Nếu N chẵn thì tăng lên 1. Bắt đầu thử với một số lẻ.
}
‰ Nếu N là hợp số thì tăng N lên 2
„ Bài tập: Viết chương trình nhập vào …
‰ Thử thế nào?
một số rồi tìm số nguyên tố đầu tiên }
„ Thử tất cả các số nhỏ hơn căn bậc hai của N, nếu N chia hết cho
lớn hơn số vừa nhập } một số trong chúng thì N là hợp số.

Lập trình C - Việt Nhật 2007 79 Lập trình C - Việt Nhật 2007 80

20
Tìm số nguyên tố lớn
1. #include <stdio.h> 16. for( ; ; ucv_nguyento += 2)
2. #define TRUE 1 17. {
3. main(void) 18. la_nguyento = !TRUE;
4. { 19. for(sochia = 3; ucv_nguyento % sochia; sochia += 2)
5. unsigned long int sochia, ucv_nguyento;
20. if(sochia * sochia > ucv_nguyento)
6. int la_nguyento;
21. { la_nguyento = TRUE;
7. printf(“Nhap vao so khoi dau: “); 22. break;
8. scanf(“%lu”, & ucv_nguyento); 23. }
9. if(ucv_nguyento <= 2) 24. if (la_nguyento)
10. ucv_nguyento = 2; 25. break;
11. else if(ucv_nguyento !=3 ) 26. }
12. { 27. }
13. if(ucv_nguyento %2 == 0) 28. printf(“So nguyen to lon hon gan nhat la %lu\n”, ucv_nguyento);
14. ucv_nguyento ++; /* Phai la so le */ 29. }

Lập trình C - Việt Nhật 2007 81 Lập trình C - Việt Nhật 2007 82

continue Ví dụ minh họa: continue


1 /* Ví dụ minh họa
2 Sử dụng continue trong vòng lặp for */
„ bỏ qua các lệnh kế tiếp while(i<10) 3 #include <stdio.h>
trong một vòng lặp và bắt { 4

đầu vòng lặp tiếp theo. scanf(“%d”, &grade); 5 int main()

if ((grade<0) || (grade>100)) 6 {
7 int x;
cú pháp: { 8
continue; printf(“Illegal grade – try again\n”); 9 for ( x = 1; x <= 10; x++ ) {
continue; 10

} 11 if ( x == 5 )
„ chỉ áp dụng với lệnh lặp. ……. 12 continue;
} 13
14
„ Bài tập: Viết chương trình 15 printf( "%d ", x );
nhập vào một số và tìm ra 16 }
tất cả các thừa số nguyên 17
18 printf( "\nDung lenh continue de bo qua gia tri
tố của số đó. 5\n" );
19 return 0;
20 }
1 2 3 4 6 7 8 9 10
Lập trình C - Việt Nhật 2007 83 Lập trình C - Việt Nhật 2007 84
Dung lenh continue de bo qua gia tri 5

21
Tìm thừa số nguyên tố
1. #include <stdio.h> 12. { /* Tim ra mot thua so */
13. printf(“%lu”, thuasonguyento);
2. main(void) 14. phanconlai /= thuasonguyento;
3. { 15. continue;
4. unsigned long N, thuasonguyento, phanconlai; 16. }
17. /* Khong phai la thua so nguyen to */
5. printf(“Nhap vao mot so tu nhien: “); 18. if(thuasonguyento == 2) thuasonguyento = 3;
6. scanf(“%lu”, &N); 19. else
20. thuasonguyento += 2;
7. thuasonguyento = 2; 21. }
phanconlai = N; 22. /* thua so nguyen to cuoi cung */
23. printf(“%lu\n”, phanconlai);
8. while(thuasonguyento * thuasonguyento <= phanconlai) 24. }
9. {
10. if(phanconlai % thuasonguyento == 0)

Lập trình C - Việt Nhật 2007 85 Lập trình C - Việt Nhật 2007 86

Thực hành lệnh lặp Lệnh switch


„ Viết chương trình giải các bài tập sau sử dụng lần lượt các „ Bài tập:
cấu trúc lặp: while, for, do while Viết chương trình lấy ngẫu nhiên 1000 số nguyên và đếm
„ Nhập vào một số nguyên năm chữ số (giả sử người dùng số lần xuất hiện ở hàng đơn vị các số chẵn (2, 4, 6, 8), số lẻ
tuân thủ nghiêm ngặt quy tắc nhập). In các chữ số này trên (1, 3, 5, 7, 9) và số 0.
năm hàng
„ Nếu chúng ta dùng cấu trúc lệnh if ... else ... if … thì phức tạp
„ Viết chương trình in ra giai thừa của số tự nhiên N. và có thể đòi hỏi nhiều phép thử.
Lý do: if ... else ... : rẽ nhánh hai chiều.
„ Nhập mười số nguyên từ bàn phím và đưa ra số lớn nhất.
„ Thử cài đặt bài toán bằng if...else...

Lập trình C - Việt Nhật 2007 87 Lập trình C - Việt Nhật 2007 88

22
Lệnh switch Sơ đồ xử lý lệnh switch
„ Dùng lệnh switch để cài đặt cơ chế rẽ nhánh nhiều chiều.
cú pháp:
switch(<expression>) case a
true
case a action(s) break
{ false
case case1:
case case2: case b
true
case b action(s) break
<statements>; false
break;
/* … */ .
.
case casen: .

<statements>;
break; true
case z case z action(s) break
default:
false
<statements>;
break; default action(s)
}
Lập trình C - Việt Nhật 2007 89 Lập trình C - Việt Nhật 2007 90

Giải bài bằng switch


1. #include <stdlib.h> 17. case 1:
2. #include <stdio.h> 18. case 3:
3. #include <time.h> 19. case 5:
20. case 7:
4. int main(void) case 9:
21. n_odd++;
5. { int n,i;
22. break;
6. int n_even = n_odd = n_zero = 0; 23. case 0:
24. n_zero++;
7. randomize(); 25. break;
8. for(i=0; i<1000; i++) 26. }
9. { n = random(1000); 27. }
10. switch (n%10) { 28. // print out the summary
11. case 2: 29. printf(“Number of even_eding number: %d\n”\
Number of odd_ending number: %d\n”\
12. case 4: Number of zero_ending number: %d\n”,
13. case 6: n_even, n_odd, n_zero);
14. case 8: 30. return 0;
31. }
15. n_even++;
16. break;

Lập trình C - Việt Nhật 2007 91 Lập trình C - Việt Nhật 2007 92

23
1 /*
2 Thống kê điểm số */
Thống kê điểm số (American system) 3
4
#include <stdio.h>

5 int main() 1. Khởi tạo các


6 {
7 int diem;
biến
„ Hệ thống điểm của học sinh, sinh viên Mỹ: A, B, C, D, E, F 8 int aCount = 0, bCount = 0, cCount = 0,
„ Chương trình nhập điểm của sinh viên, kết thúc bằng EOF 9
10
dCount = 0, fCount = 0;
2. Nhập liệu
„ In ra số lượng sinh viên đạt điểm số tương ứng 11 printf( "Nhập phân loại học tập theo chữ hoa.\n" );
12 printf( "Nhấn ký tự EOF để kết thúc nhập liệu.\n" );
13
14 while ( ( grade = getchar() ) != EOF ) {
2.1 Dùng switch
15 để cập nhật các
16
17
switch ( grade ) { /* switch lồng trong while */ biến đếm
18 case 'A': /* điểm là hạng A */
19 ++aCount;
20 break;
21
22 case 'B': /* điểm là hạng B */
23 ++bCount;
24 break;
25
26 case 'C': /* điểm là hạng C */
27 ++cCount;
28 break;
29
30 case 'D': /* điểm là hạng D */
Lập trình C - Việt Nhật 2007 93 31 ++dCount; Lập trình C - Việt Nhật 2007 94
32 break;

33

Bài tập
34 case 'F': /* điểm là hạng F */
35 ++fCount;
36 break;
37
3. In kết quả
38 case '\n': case' ': /* ignore these in input */ 1) Viết chương trình tính giá trị biểu thức "a op b" như "2 + 3"
39 break;
40
a, b toán hạng – op : toán tử
41 default: /* catch all other characters */
42 printf( "Nhập sai ký tự phân hạng kết quả." );
43 printf( " Làm ơn nhập lại.\n" );
2) Yêu cầu người sử dụng nhập vào một tháng. In ra số ngày
44 break; trong tháng đó.
45 }
46 }
47 „ Tháng có 31 ngày: 1, 3, 5, 7, 8, 10, 12
48 printf( "\Kết quả phân loại sinh viên:\n" ); „ Tháng có 30 ngày: 4, 6, 9, 10
49 printf( "A: %d\n", aCount );
50 printf( "B: %d\n", bCount ); „ Tháng có 28 hoặc 29 ngày : 2
51 printf( "C: %d\n", cCount );
52 printf( "D: %d\n", dCount );
53 printf( "F: %d\n", fCount );
54
55 return 0;
56 }
Lập trình C - Việt Nhật 2007 95 Lập trình C - Việt Nhật 2007 96

24
In số ngày trong một tháng Tính ex với độ chính xác 10-5
#include <stdio.h> case 4: „ ex = 1+x/1!+x2/2!+……………..+ xn/n!
int main () case 6: #include <stdio.h>
{ case 9: void main() {
int thang; case 11: float epsilon = 0.00001;
printf("\n Nhap vao thangs trong printf("\n Thang %d co 30 float x,add;
nam "); ngay ",thang); int i=1;
scanf("%d",&thang); break; float result = 0.0;
switch(thang) { case 2: add = 1;
case 1: printf ("\ Thang 2 co 28 hoac printf("Chương trình tính giá trị e mũ x. \n");
case 3: 29 ngay");
printf("x="); scanf("%f", &x);
case 5: break;
while (add > epsilon) {
case 7: default :
result = result + add;
case 8: printf("\n Khong co thang
%d", thang); add = add*x/i;
case 10:
break; i = i+1;
case 12:
} }
printf("\n Thang %d co 31
ngay ",thang); return 0; printf ("Ket qua la:%f", result);
break; } }

Lập trình C - Việt Nhật 2007 97 Lập trình C - Việt Nhật 2007 98

Một số toán tử và lệnh khác Một số toán tử và lệnh khác


„ Toán tử ‘,’ được dùng để khởi động nhiều biến trong vòng „ Lệnh goto cho phép nhảy không điều kiện đến bất kỳ nơi nào
lặp. trong chương trình.
Ví dụ: Cú pháp:
for(i = 0, j = 0; i < 5; i++, j += i++) goto <label>
printf(“i = %d, j = %d, i+j = %d\n”, i, j, i+j);
Ví dụ: xem chương trình ví dụ.
„ Kết quả là: ????
„ Lệnh goto làm mất cấu trúc chương trình.
„ Toán tử ba ngôi
<TestExpr> ? <YesExpr> : <NoExpr>

Ví dụ:
Max = (Y > Z) ? Y : Z;

Lập trình C - Việt Nhật 2007 99 Lập trình C - Việt Nhật 2007 100

25
Từ khóa của C Từ khóa của C
„ auto break case char „ #define để khai báo hằng số và …
„ const continue default do „ typedef để khai báo kiểu dữ liệu riêng
„ double else enum extern
„ float for goto if „ Toán tử sizeof xác định số byte được dùng để chứa một đối
„ int long register return tượng
„ short signed sizeof static
ví dụ:
„ struct switch typedef union typedef unsigned long int Int32;
„ unsigned void volatile while /* ... */
int x;
x = sizeof(Int32); // x = 4

Lập trình C - Việt Nhật 2007 101 Lập trình C - Việt Nhật 2007 102

Mảng
„ Mảng là tập hợp các giá trị cùng kiểu.
Ngôn ngữ lập trình C „

„
Dãy liên tục các ô nhớ lưu các phần tử có liên quan đến nhau
Khai báo:
typename arrayname[array_size];

„ số phần tử trong mảng: array_size;

int a[array_size];
Chương 4: Mảng n = array_size;

a[0] a[1] a[2] … a[n-1] a[n-1]


Cao Tuấn Dũng a
2007
„ Truy cập phần tử mảng qua chỉ số của phần tử: i
array[i]; // 0 <= i <= array_size-1, i ∈N0
Lập trình C - Việt Nhật 2007 104

26
Mảng Tên mảng
(Các phần tử mảng Chú ý
có cùng chung một
tên, c)
„ Các phần tử mảng hoạt động như các „ C không kiểm tra giới hạn của chỉ số truy cập phần tử mảng.
biến thông thường Truy cập đến phần tử i>=array_size không có cảnh báo,
c[ 0 ] = 3; c[0] -45
nhưng giá trị không kiểm soát được.
printf( "%d", c[ 0 ] ); c[1] 6

„ Các thao tác toán học trên chỉ số mảng c[2] 0


c[3] 72 „ Kích thước mảng phải là một hằng số.
‰ If x bằng 3 c[4] 1543
c[ 5 - 2 ] == c[ 3 ] == c[ x ] c[5] -89
„ Ví dụ khai báo mảng: c[6] 0
„ Kích thước mảng có thể được khai báo tường minh hoặc
int c[ 10 ]; c[7] 62 thông qua một giá trị định nghĩa trước (#define)
float myArray[ 3284 ]; c[8] -3
c[9] 1
„ Khai báo nhiều mảng cùng kiểu c[10] 6453
‰ Tương tự khi khai báo nhiều biến cùng c[11] 78
kiểu
int b[ 100 ], x[ 27 ];
Vị trí của một
phần tử trong mảng
Lập trình C - Việt Nhật 2007 c 105 Lập trình C - Việt Nhật 2007 106

Ví dụ thực tế Khởi tạo mảng


„ Bài toán: Sử dụng bảng số liệu „ Mảng có thể được khởi tạo bởi một dãy các
về lượng mưa hàng tháng tháng lượng mưa TB (in mm) giá trị thích hợp.
trong năm. 0 30 ‰ int n[ 5 ] = { 1, 2, 3, 4, 5 };
1 40 ‰ Nếu không đủ các giá trị khởi tạo cho tất cả, các phần
„ Input: tháng tử bên phải sẽ có giá trị 0
„ Output: Lượng mưa trung bình 2 45 ‰ int n[ 5 ] = { 0 } => Tất cả phần tử = 0.
3 95
cho tháng đó
4 130
„ Nếu kích thước mảng bị bỏ qua, chương
5 220
trình dịch tự phát hiện kích thước cần
6 210
7 185
thiết.
‰ int n[ ] = { 1, 2, 3, 4, 5 };
8 135
9 80
10 40 „ Các khai báo sau đây là hợp lệ
int Squares[5] = {0,1,4,9,16};
11 45 int Squares[5] = {0,1,4};
Bảng lượng mưa int Squares[] = {0,1,4,9,16};
int Squares[];

Lập trình C - Việt Nhật 2007 107 Lập trình C - Việt Nhật 2007 108

27
Chú ý Bảng lượng mưa (tiếp)
„ Không thể thực hiện các thao tác chép nội dung một mảng #include <stdio.h>
sang mảng khác.
int main()
Chép từng phần tử mảng
{
char A[3]={‘a’,’b’,’c’};
int thang;
char B[3]; int bangmua[12] = { 30, 40, 45, 95, 130, 220,
B = A; // ??? 210, 185, 135, 80, 40, 45 };
for(int i=0; i<3; i++)
B[i] = A[i]; printf("Nhap thang: ");
hoặc chép khối bộ nhớ (sẽ được đề cập sau) scanf("%d", &thang);
„ Không dùng phép so sánh trực tiếp (==) nội dung trong hai
printf("Luong mua trung binh cua thang: %d mm.\n",
mảng. bangmua[thang-1]);
Phép so sánh (A==B) so sánh địa chỉ hai vùng nhớ mà A và B
chỉ đến. return 0;
}

Lập trình C - Việt Nhật 2007 109 Lập trình C - Việt Nhật 2007 110

Bảng lượng mưa (tiếp) Chú ý


#include <stdio.h> „ Các phần tử trong mảng được dùng như các biến đơn thông
thường.
int main()
{ „ Các hàm printf, scanf không làm việc với kiểu mảng, do đó việc
nhập xuất giá trị là do người lập trình tự tiến hành với từng phần tử
int thang; mảng.
int bangmua[12] = { 30, 40, 45, 95, 130, 220,
210, 185, 135, 80, 40, 45 }; 1. // nhap gia tri cho cac phan tu mang
2. float a[4];
printf("Nhap thang: "); 3. for(int i=0; i<4; i++)
scanf("%d", &thang); 4. {
5. printf(“a[%d]=“,i);
printf("Luong mua trung binh cua thang: %d mm.\n", 6. scanf(“%f”, &a[i]);
bangmua[thang-1]); 7. }
return 0; „ Chỉ số của phần tử mảng phải thuộc kiểu nguyên (int, short int, long
} int, char)

Lập trình C - Việt Nhật 2007 111 Lập trình C - Việt Nhật 2007 112

28
Khởi tạo mảng gồm các số chẵn từ 2 đến Nhập xuất dữ liệu cho mảng
20
#include <stdio.h>
#include <stdio.h> #define SOTHANG 12
#define arraySize 10
/* Lưu và hiển thị lượng mưa */

int main()
int main()
{
{
int s[ arraySize ]; // mảng S có 10 phần tử
int solieu[SOTHANG];
int i;
int thang;
for ( i = 0; i < arraySize; i++ ) // khởi tạo giá trị
s[ i ] = 2 + 2 * i; for ( thang=0; thang < SOTHANG; thang++ )
printf("Phan tu \t Gia tri\n"); {
for ( i = 0; i < arraySize; i++ ) scanf("%d", &solieu[thang] );
printf("%d\t%d\n", i, s[i]); }
return 0;
} ...

Lập trình C - Việt Nhật 2007 113 Lập trình C - Việt Nhật 2007 114

1 /*
2 Histogram printing program */

Nhập xuất dữ liệu cho mảng 3


4
#include <stdio.h>
#define SIZE 10
5
6 int main()
#include <stdio.h> 7 {
#define SOTHANG 12 8 int n[ SIZE ] = { 19, 3, 15, 7, 11, 9, 13, 5, 17, 1 };
... 9 int i, j;
/* Print from January to December */ 10
for ( thang=0; thang< SOTHANG; thang++ ) 11 printf( "%s%13s%17s\n", "Element", "Value", "Histogram"
);
12
{
13 for ( i = 0; i <= SIZE - 1; i++ ) {
printf( "%5d ” , solieu[thang] );
14 printf( "%7d%13d ", i, n[ i ]) ;
} 15
printf("\n"); 16 for ( j = 1; j <= n[ i ]; j++ )
17 printf( "%c", '*' );
/* Print from December to January */ 18
for ( thang = SOTHANG - 1; thang >= 0; thang-- ) 19 printf( "\n" );
{ 20 }
21
printf( "%5d ” , solieu[month] ); Element Value Histogram
22 return 0;
} 23 }
0 19 *******************
1 3 ***
printf("\n"); 2 15 ***************
3 7 *******
return 0; 4 11 ***********
5 9 *********
} 6 13 *************
7 5 *****
Lập trình C - Việt Nhật 2007 115 8 17 C - Việt Nhật
Lập trình *****************
2007 116
9 1 *

29
Đổi số nguyên dương sang nhị phân Đổi số nguyên dương sang nhị phân
„ Nguyên lý:
‰ Chia liên tiếp số cần chuyển đổi cho 2 cho đến khi thương số là 0
‰ Lấy các số dư theo chiều ngược lại

23 2
1 11 2

1 5 2
1 2 2
0 1 2
10111 1 0

Lập trình C - Việt Nhật 2007 117 Lập trình C - Việt Nhật 2007 118

Khởi tạo ngẫu nhiên Sắp xếp mảng


„ Tạo dãy số nguyên dương 500 số. Mỗi số có giá trị trong „ Sắp xếp dữ liệu
khoảng 1 đến 1000. In ra màn hình giá trị trung bình của dãy,
số phần tử trong dãy bằng, nhỏ hơn, lớn hơn giá trị trung
‰ Là một ứng dụng quan trọng
bình. ‰ Hầu hết mọi cơ quan tổ chức cần sắp xếp dữ liệu

„ Tạo số ngẫu nhiên „ Sắp xếp nổi bọt


#include <stdlib.h>
‰ Duyệt mảng vài lần
#include <time.h>
‰ So sánh các cặp phần tử liên tiếp
srand(time(NULL)); /* Khởi tạo bộ sinh số ngẫu nhiên, gọi một lần
duy nhất */ „ Nếu thứ tự tăng (hay bằng nhau) không thay đổi gì.
rand() ; sinh số nguyên ngẫu nhiên „ Nếu thứ tự giảm: tráo đổi hai phần tử.
1+ rand() % N ‰ Lặp lại bước trên cho mọi phần tử

Lập trình C - Việt Nhật 2007 119 Lập trình C - Việt Nhật 2007 120

30
Sắp xếp mảng Sắp xếp mảng

Lập trình C - Việt Nhật 2007 121 Lập trình C - Việt Nhật 2007 122

Sắp xếp mảng Mảng hai chiều


for (pass = 0; pass < arraySize - 1; pass++ ) „ Một phần tử mảng có thể là một mảng
for (j = 0; j < arraySize - 1; j++ )
khác
„ Mảng của các mảng được gọi là mảng
// So sánh hai phần tử kề nhau và đổi chỗ chúng khi nhiều chiều
// phần từ trước lớn hơn phần tử sau
if ( a[ j ] > a[ j + 1 ] ) { Cột 0 Cột 1 Cột 2 Cột 3
hold = a[ j ]; Hàng 0 a[ 0 ][ 0 ] a[ 0 ][ 1 ] a[ 0 ][ 2 ] a[ 0 ][ 3 ]
Hàng 1 a[ 1 ][ 0 ] a[ 1 ][ 1 ] a[ 1 ][ 2 ] a[ 1 ][ 3 ]
a[ j ] = a[ j + 1 ]; Hàng 2
a[ 2 ][ 0 ] a[ 2 ][ 1 ] a[ 2 ][ 2 ] a[ 2 ][ 3 ]
a[ j + 1 ] = hold;
Chỉ số cột
Tên mảng
}
Chỉ số hàng
Lập trình C - Việt Nhật 2007 123 Lập trình C - Việt Nhật 2007 124

31
Mảng nhiều chiều Ví dụ: Lượng mưa hàng năm
thang
„ Khai báo mảng 2 chiều:
0 1 2 3 4 5 6 7 8 9 10 11
type name[row_size][column_size]; 0 30 40 75 95 130 220 210 185 135 80 40 45
SumSquares
1 25 25 80 75 115 270 200 165 85 5 10 0

nam
0 1 4 2 35 45 90 80 100 205 135 140 170 75 60 95
1 2 5
3 30 40 70 70 90 180 180 210 145 35 85 80
4 30 35 30 90 150 230 305 295 60 95 80 30
0 1 4 1 2 5
Lượng mưa trung bình năm (mm)
„ Khởi tạo
„ int SumSquares[2][3] = { {0,1,4}, {1,2,5} };
„ int SumSquares[2][3] = { {0,1,4} }; Bài toán: thao tác trên bảng vũ biểu
„ int SumSquares[ ][3] = { {0,1,4}, {1,2,5} }; • input: tháng và năm
„ int SumSquares[ ][3] = { {0,1, }, {1} };
„ int SumSquares[ ][3]; • output: lượng mưa trung bình vào năm, tháng đó
Lập trình C - Việt Nhật 2007 125 Lập trình C - Việt Nhật 2007 126

#define NYEARS 5
#define

int main()
NMONTHS 12
Nhập Mảng 2 chiều
{
int table[NYEARS][NMONTHS] =
{ 1. #define MAX_STUDENT 5
{30,40,75,95,130,220,210,185,135,80,40,45}, 2. #define MAX_SUBJECT 6
{25,25,80,75,115,270,200,165, 85, 5,10, 0},
{35,45,90,80,100,205,135,140,170,75,60,95},
{30,40,70,70, 90,180,180,210,145,35,85,80},
{30,35,30,90,150,230,305,295, 60,95,80,30}
3. int StudentScore[MAX_STUDENT][MAX_SUBJECT];
};
int year, month;
printf("Enter year and month: "); scanf("%d %d", &year, &month); 4. void read_Score(int Score[MAX_STUDENT][MAX_SUBJECT],
int nStudents, int nSubjects)
if ((0 <= year) && (year < NYEARS) && 5. {
(0 <= month) && (month < NMONTHS))
printf("Rainfall for year %d month %d is %d", year, month, 6. int i,j;
table[year-1][month-1]);
else 7. for(i=0; i<nStudents; i++)
{
printf("Data non available");
8. for(j=0; j<nSubjects; j++)
} 9. scanf(“%d”, &Score[i][j]);
return 0;
} 10. }

Lập trình C - Việt Nhật 2007 127 Lập trình C - Việt Nhật 2007 128

32
Biểu diễn mảng 2 chiều Bài tập
StudentScores
„ Viết chương trình nhập vào một dãy số theo thứ tự tăng, nếu
Student1 0 1 4 ? ? ? nhập sai quy cách thì yêu cầu nhập lại. In dãy số sau khi
nhập xong. Nhập thêm một số và chèn số đó vào dãy số sao
Student2 1 2 5 ? ? ?
cho không thay đổi tính chất của dãy. In lại dãy mới để kiểm
Student3 ? ? ? ? ? ? tra.
Student4 ? ? ? ? ? ? „ Viết chương trình nhập vào một ma trận nguyên m hàng n
Student5 ? ? ? ? ? ?
cột. In ma trận ra màn hình. Nhập vào một số nguyên và kiểm
tra xem có phần tử nào trong ma trận có cùng giá trị hay
không. Ở vị trí nào và có bao nhiêu phần tử.
„ Viết chương trình đảo một mảng một chiều. Ví dụ:
‰ 1, 3, 5, 8, 7, 9, 6 thành 6, 9, 7, 8, 5, 3, 1

0 1 4 ? ? ? 1 2 5 ? ? ?

Student1 Student2
Lập trình C - Việt Nhật 2007 129 Lập trình C - Việt Nhật 2007 130

Lập trình cấu trúc


„ Trong thực tế: Sản xuất bằng cách lắp ghép các module: các
module được lắp ghép lại thành sản phẩm, các module có thể được
Ngôn ngữ lập trình C cải tiến nhưng không ảnh hưởng đến các module khác trong sản
phẩm.

Chương trình
Chương trình con A
Với chương trình máy tính Các biến
„ Với chương trình đơn giản, tất Câu lệnh
Hàm (function) cả các xử lý nên được đặt
Kết thúc chương trình con A
trong hàm main.
Chương trình con B
Cao Tuấn Dũng „ Chia để trị: Phân chia chương Các biến
2007 trình thành các phần nhỏ - các Câu lệnh
chương trình con (routine) hay
Kết thúc chương trình con B
còn gọi là các hàm (function)

Lập trình C - Việt Nhật 2007 132

33
Hàm – Mô đun hóa chương trình Hàm
„ Trong C mọi chương trình con là hàm, không có sự phân biệt giữa „ Là một đoạn mã lệnh độc lập, được đặt tên, thực hiện một
hàm và thủ tục. nhiệm vụ cụ thể và có thể trả về một giá trị cho chương trình
„ Cách tiếp cận phân tích bài toán theo hướng top-down: xác định gọi hàm
chức năng của các hàm. „ Sử dụng hàm trong chương trình giúp:
‰ Chia nhỏ chương trình thành những mô đun nhỏ dễ quản lý
„ Một chương trình C là một tập hợp các hàm tương tác bằng cách
‰ Thống nhất các đoạn mã tương tự nhau, sử dụng nhiều lần trong
gọi lẫn nhau và truyền các thông tin qua lại giữa các hàm.
một chương trình
„ Các hàm có thể được dùng lại nhiều lần Æ thành lập các thư viện
‰ Tái sử dụng mã lệnh trong nhiều hơn một chương trình
hàm. (vd: stdio, stdlib, conio, math, string,…)
„ Hai loại hàm trong C:
‰ Hàm chuẩn trong các thư viện C: printf, scanf, các hàm tính toán toán
học, xử lý xâu ký tự, …
‰ Hàm do người dùng định nghĩa.

Lập trình C - Việt Nhật 2007 133 Lập trình C - Việt Nhật 2007 134

Các hàm toán học Ví dụ đầu tiên: Hàm lập phương


Hàm Mô tả Ví dụ floor(x) làm tròn số nguyên floor(9.2) bằng 9.0 #include <stdio.h>
sqrt(x) Căn bậc 2 sqrt(9.00) bằng 3.0 lớn nhất không nhỏ floor(-9.8) bằng -10.0 /* nguyen mau ham*/
của x hơn x
int cube(int x);
exp(x) hàm mũ ex exp(1.0) bằng
2.718282 void main() {
pow(x,y) x mũ y (xy) pow(2,7) bằng 128 int a, kq;
log(x) logarithm log(2.718282) bằng
tự nhiên 1.0 printf("Cho mot so nguyen:"); scanf("%d", &a);
(cơ số e)
của x kq=cube(a);
fmod(x,y phần dư của phép fmod(13.657,2.333) bằng
log10(x) logarithm log10(1.0) bằng 0.0 ) chia x cho y 1.992 printf("\n Gia tri lap phuong cua %d la %d", a, kq);
thập phân log10(10.0) bằng 1.0 }
(cơ số 10)
của x sin(x) sin của x (x theo sin(0.0) bằng 0.0 /* Ham tinh lap phuong */
fabs(x) giá trị tuyệt nếu x≥0 thì fabs(x) radian) int cube(int x) {
đối của x bằng x int x3;
nếu x<0 thì fabs(x)
bằng -x cos(x) cos của x (x theo cos(0.0) bằng 1.0 x3 = x*x*x;
radian)
ceil(x) làm tròn số ceil(9.2) bằng 10.0 return x3;
nguyên ceil(-9.8) bằng -9.0 }
nhỏ nhất tan(x) tan của x (x theo tan(0.0) bằng 0.0
không lớn Cho vao mot so nguyen: 6
radian)
hơn x Gia tri lap phuong cua 6 la 216
Lập trình C - Việt Nhật 2007 135 Lập trình C - Việt Nhật 2007 136

34
Hoạt động của hàm Khai báo hàm
„ Các lệnh trong hàm chưa được „ Nguyên mẫu hàm (prototype): nguyên mẫu hàm cho chương
thực hiện cho tới khi hàm được danh sách đối số trình dịch biết sự tồn tại của một hàm với tên, danh sách đối
gọi. Khi hàm được gọi điều số, kiểu giá trị trả về cụ thể
khiển thực hiện các lệnh được Chương trình
chuyển cho hàm. Khai báo Biến; „ Cú pháp:
„ Chương trình gửi thông tin đến Lệnh; ‰ Kiểu giá trị trả về Tênhàm(kiểu đối số 1, kiểu đối số 2,…);
…. int Max(int x, int y);
hàm: các đối số Hàm „
Lời gọi hàm
„ Hàm gửi lại thông tin: giá trị trả Lệnh int Min(int x, int y);
về ……. „ Nguyên mẫu hàm chỉ cần thiết khi phần định nghĩa hàm nằm
„ Bốn bước cơ bản khi gọi hàm: Kết thúc phía sau lời gọi hàm trong chương trình.
Giá trị trả về „ Nguyên mẫu hàm được chương trình dịch sử dụng để kiểm
‰Cấp phát bộ nhớ cho các đối số và biến cục bộ tra tính hợp lệ của hàm
‰Gán giá trị của các tham số thực cho đối số tương ứng ‰ Nguyên mẫu hàm phải khớp với định nghĩa hàm
‰Thi hành lệnh

‰Gặp câu lệnh return: Xóa các đối số, biến cục bộ, thoát khỏi hàm

Lập trình C - Việt Nhật 2007 137 Lập trình C - Việt Nhật 2007 138

Tệp tiêu đề Định nghĩa hàm


„ Chứa các nguyên mẫu hàm của các hàm trong thư viện „ Nơi cài đặt thực sự mã cho một hàm
‰ stdio.h, stdlib.h, math.h, time.h „ Dòng đầu tiên tương tự như nguyên mẫu hàm, tuy nhiên
„ Chứa nguyên mẫu các hàm do người dùng định nghĩa ‰ chỉ định rõ danh sách đối số
„ Sử dụng tệp tiêu đề do người dùng định nghĩa ‰ không kết thúc bằng dấu ;
‰ Khai báo các hàm vào lưu trong file riêng „ Phần tiếp theo là thân hàm
‰ Đặt tên filename.h
‰ Khai báo sử dụng các hàm này ở chương trình khác
„ #include "filename.h"

‰ Sử dụng lại các hàm đã khai báo

Lập trình C - Việt Nhật 2007 139 Lập trình C - Việt Nhật 2007 140

35
Các thành phần của hàm Hàm radian
„ Hàm chuyển đổi số đo góc từ độ sang radian
„ Tên hàm (name) #include <stdio.h>
„ danh sách tham số (list of parameters) giao diện #include <math.h>
#define PI 3.14159
„ kiểu trả về (return type) (interface) của hàm
„ thân hàm (function body) /* nguyen mau ham*/
float Radian(float x);
„ lệnh trả về (return) void main() {
float ang, adj, opp;
printf("Nhap gia tri cua goc (theo do:"); scanf("%f", &ang);
‰ <return_type> function_name (<list_of_parameters>) printf("Nhap canh ke:"); scanf("%f", &adj);
opp= adj*tan(Radian(ang));
printf("Canh doi la: %f\n", opp);

„ Các hàm phải được khai báo trước khi được gọi thi hành. }
/* Ham tinh Radian */
float Radian(float deg) {
float result;
result = PI * deg/180.0;
return result;
}

Lập trình C - Việt Nhật 2007 141 Lập trình C - Việt Nhật 2007 142

Thành phần của hàm – Tên hàm Danh sách tham số


„ Tên hàm là một định danh (identifier), do đó nó tuân theo các „ Danh sách tham số xác định các đối số được đưa vào hàm.
quy định của ngôn ngữ C cho định danh. (xem bảng các toán
tử) „ Các đối số được khai báo trong phần mô tả cài đặt của hàm
thì được gọi là các tham số hình thức (formal parameters).
„ Nên đặt tên có ý nghĩa.
„ Mỗi tham số hình thức là một cặp: <type> <identifier>. Từ
„ Không đặt tên trùng với tên các hàm hệ thống trong C hoặc khoá void có thể được dùng nếu không có tham số hình thức
các từ khóa của C. nào cần khai báo. Các tham số trong các hàm khác nhau có
thể trùng tên.

„ Khi gọi hàm, các đối số đưa vào hàm phải đầy đủ và đúng
kiểu như đã khai báo.

Lập trình C - Việt Nhật 2007 143 Lập trình C - Việt Nhật 2007 144

36
Ví dụ Giá trị trả về (return value)
„ /* ... */ „ Một hàm được phép trả về cho phần chương trình gọi nó một
1. float max(float x, float y) giá trị: giá trị trả về.
2. {
3. return (x > y ? x : y); „ Chương trình gọi hàm có thể sử dụng giá trị trả về.
4. }
„ Một số hàm không cần trả về các giá trị. Từ khóa void được
„ /*…*/ dùng trong khai báo giá trị trả về của các hàm này.

6. int main() „ Kiểu int sẽ là kiểu của trị trả về nếu không chỉ rõ kiểu giá trị
7. { trả về trong khai báo hàm.
8. float z = 4.7;
9. float x = max(4.5, z); ví dụ:
afunction() { /*…*/ }
10. }

Lập trình C - Việt Nhật 2007 145 Lập trình C - Việt Nhật 2007 146

Thân hàm (function body) Hàm tìm USCLN giữa hai số


„ { /* các đoạn mã trong thân hàm */ } int USCLN(int a, int b)
{
a=abs(a);
„ Các biến có thể được khai báo bên trong hàm Æ biến cục bộ
b=abs(b);
(local variable)
while(a!=b)
{
„ Biến cục bộ không được trùng tên với tham số hình thức if(a>b)
trong khai báo hàm. a=a-b;
else
„ Các biến cục bộ chỉ có giá trị trong phạm vi của hàm. b=b-a;
}
return a;
}

Lập trình C - Việt Nhật 2007 147 Lập trình C - Việt Nhật 2007 148

37
Phạm vi truy cập của biến Ví dụ
„ Phạm vi truy cập (scope) của biến xác định vùng chương 1. int i=1; /* i là biến toàn cục vì nằm ở ngoài các khối lệnh */
trình có thể truy cập đến biến.
2. { /* block A */
3. int i=2;
„ Biến được khai báo trong khối lệnh (nằm giữa { }) có thể 4. printf (“%d\n”, i); /* outputs 2 */ }
được truy cập bởi các lệnh nằm trong cùng khối và các lệnh 5. { /* Block B */
thuộc các khối con. 6. int i=3;
7. printf (“%d\n”, i); /* outputs 3 */
„ Biến được khai báo “ngoài cùng” có phạm vi truy cập trong 8. { /* Block C */
toàn chương trình Æ biến toàn cục (global variables). 9. int i=4;
10. printf (“%d\n”, i); /* outputs 4 */ }
„ Biến cục bộ (local variable) được khai báo và sử dụng trong 11. { /* Block D */
phạm vi một khối lệnh và các khối lệnh con. 12. printf (“%d\n”, i); /* outputs 3 */ }
13. }
14. { /* Block E */
„ Biến thuộc phạm vi trong cùng được tham chiếu đến đầu tiên. 15. printf (“%d\n”, i); /* outputs 1 */ }
Lập trình C - Việt Nhật 2007 149 Lập trình C - Việt Nhật 2007 150

Phạm vi của biến Biến tự động ( automatic)


¾ Biến automatic được khai báo trong một hàm và nó là
biến cục bộ trong hàm này, tức là phạm vi của nó chính
là hàm mà trong đó biến này được khai báo.

„ Chú ý:
‰ Từ khoá auto được dùng để khai báo các biến cục
bộ. 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à automatic.
‰ Tham số hình thức trong một hàm cũng là biến

automatic.

Lập trình C - Việt Nhật 2007 151 Lập trình C - Việt Nhật 2007 152

38
Cấp lưu trữ và phạm vi các đối tượng Biến tự động
/* Hoán vị giá trị hai số nguyên */
Cấp lưu trữ ( storage class): thời gian sống + phạm vi #include <stdio.h>
„ Có tất cả bốn cấp lưu trữ trong C: tự động, toàn cục (ngoài), void swap(auto int* , auto int* ); /* Hàm nguyên mẫu */
tĩnh và register được khai bao thông qua các từ khóa auto, main()
{
extern, static và register.
auto int x, y;
„ Mặt khác cũng lưu ý rằng cấp lưu trữ của một biến đôi khi x = 10; y = 20;
được xác định bởi chính vị trí khai báo của biến đó trong printf("Ban đầu x = %d, y = %d", x, y);
swap( &x, &y);
chương trình. Trong các trường hợp khác người ta dùng
printf("Sau đó x = %d, y = %d", x, y);
bốn từ khóa nói trên trong khai báo }
„ Ví dụ: /* Định nghĩa hàm swap */
auto int a,b,c; void swap( auto int* a, auto int* b)
{
extern float r1,r2; auto int temp;
static int count = 0; temp = *a;
extern char star; *a = *b;
*b = temp;
}
Lập trình C - Việt Nhật 2007 153 Lập trình C - Việt Nhật 2007 154

Biến toàn cục (global, external). Biến toàn cục


#include <stdio.h>
long fibo(int count);
„ Phạm vi (scope) của biến toàn cục là toàn bộ chương long f1=1,f2=1;/* khai báo biến toàn cục */
trình main()
{
int count,n;
„ Các biến toàn cục được định nghĩa bên ngoài mọi hàm printf("\nn =");scanf("%d",&n);
do vậy chúng có tiềm năng sử dụng cho nhiều hàm. for(count=1;count<=n; ++count)
printf("\ni=%2d F=%ld", count,fibo(count));
}
„ Biến toàn cục còn đóng một vai trò quan trọng khi phát
triển các ứng dụng lớn, vì khi đó hiển nhiên là các long int fibo(int count)
{
chương trình nguồn để trên nhiều tệp khác nhau. long int f;
f=(count<3) ? 1: f1+f2;
f2=f1; f1=f;
„ Từ khoá extern thông báo với trình biên dịch rằng tên return f;
và kiểu của biến đặt sau đã được khai báo ở đâu đó rồi. }

Lập trình C - Việt Nhật 2007 155 Lập trình C - Việt Nhật 2007 156

39
Biến tĩnh (static) Biến tĩnh
„ Biến tồn tại liên tục từ lúc bắt đầu cho tới lúc kết thúc chương #include<stdio.h>
long fibo(int count);
trình.
main()
„ Cấp phát bộ nhớ một lần và tồn tại cho đến khi kết thúc {
„ static tênkiểu tênbiến = giatri; int count,n;
printf("\nn =");scanf("%d",&n);
for(count=1;count<=n; ++count)
#include <stdio.h> printf("\ni=%2d F=%ld", count,fibo(count));
int inc(){ }
Ket qua inc lan 1: 1
static int n=0; long int fibo(int count)
Ket qua inc lan 2: 2
n++; {
return n; static long int f1=1,f2=1;
} long int f;
void main(){ f=(count<3) ? 1: f1+f2;
f2=f1; f1=f;
printf("\n Ket qua inc lan 1: %d", inc());
return f;
printf("\n Ket qua inc lan 2: %d", inc()); }
} „ Nếu bỏ từ khóa static ở trong thân hàm main ????

Lập trình C - Việt Nhật 2007 157 Lập trình C - Việt Nhật 2007 158

Biến register Lệnh return


„ Từ khoá register được đặt trước khai báo của các biến „ kết thúc hàm và trả quyền điều khiển về cho phần chương
tự động để đề nghị trình biên dịch duy trì giá trị biến đó trình có lời gọi hàm.
trong thanh ghi của máy tính, giúp nâng cao tốc độ thực
hiện. „ cú pháp:
return Expr;
„ 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úng chỉ áp dụng hoặc
cho các biến kiểu int và char. return;

„ Ví dụ sau đề nghị trình biên dịch đặt biến counter vào „ hàm tự kết thúc khi thực hiện hết lệnh cuối cùng.
một trong các thanh ghi của máy và khởi tạo nó giá trị
ban đầu bằng 1:
register int counter = 1;

Lập trình C - Việt Nhật 2007 159 Lập trình C - Việt Nhật 2007 160

40
Một số ví dụ Một số ví dụ minh họa
„ Tính tổng các số nguyên tố nhỏ hơn n „ Chương trình tính tổng các số nguyên tố

Lập trình C - Việt Nhật 2007 161 Lập trình C - Việt Nhật 2007 162

Một số bài tập Truyền tham số khi gọi hàm


„ Viết chương trình tính tiền thuê máy dịch vụ Internet và „ Truyền tham chiếu (call by reference): các tham chiếu đến
in ra màn hình kết quả. Dữ liệu nhập vào là giờ bắt đầu các tham số hình thức là tham chiếu đến các đối số. Giá trị
thuê (GBD), giờ kết thúc thuê (GKT) và số máy thuê của các đối số có thể được thay đổi từ xử lý bên trong hàm.
‰ Điều kiện dữ liệu: 6 <=GBD < GKT <= 21, Giờ nguyên.
‰ Đơn giá 2500 đ cho mỗi giờ trước 5h30 và 3500 cho mỗi giờ sau 5h30 „ Truyền giá trị (call by value): các đối số đưa vào hàm được
chép vào các tham số hình thức. Các giá trị của các đối số
„ Nhập vào ba số thực a, b, c kiểm tra xem chúng có phải được sử dụng trong hàm nhưng những thay đổi của tham số
hình thức trong hàm không làm thay đổi giá trị của các đối số
là ba cạnh một tam giác không. Nếu có tính diện tích, độ
truyền vào.
dài 3 đường cao.

Lập trình C - Việt Nhật 2007 163 Lập trình C - Việt Nhật 2007 164

41
Truyền giá trị Tại sao truyền giá trị không làm
1. /* Swapping routine that doesn’t work */
thay đổi giá trị đối số
2. #include <stdio.h>

3. void Swap(int x, int y)


{ int Temp; M1 main#1::Left = 5 M1 main#1::Left = 5
M2 main#1::Right = 7 M2 main#1::Right = 7
4. Temp = x;
5. x = y;
6. y = Temp;
7. } M3 Swap#1::Temp = ? M3 Swap#1::Temp = 5
M4 Swap#1::x = 5 M4 Swap#1::x = 7
8. main(void) M5 Swap#1::y = 7 M5 Swap#1::y = 5
9. { int Left, Right;

10. Left = 5; Right = 7;


11. Swap(Left, Right);
12. printf(“Left = %d, Right = %d\n”, Left, Right);
13. }

Lập trình C - Việt Nhật 2007 165 Lập trình C - Việt Nhật 2007 166

Truyền bằng tham chiếu Tại sao truyền bằng tham chiếu làm
„ /* Swapping routine that does work */
thay đổi giá trị đối số
„ #include <stdio.h>
„ void Swap(int &x, int &y)
{
M1 main#1::Left = 5 M1 main#1::Left = 7
int Temp;
M2 main#1::Right = 7 M2 main#1::Right = 5
Temp = x;
x = y;
y = Temp;
} M3 Swap#1::Temp = ? M3 Swap#1::Temp = 5
M4 Swap#1::x M4 Swap#1::x
main(void)
M5 Swap#1::y M5 Swap#1::y
{
int Left, Right;

Left = 5; Right = 7;
Swap(Left, Right);
printf(“Left = %d, Right = %d\n”, Left, Right);
}

Lập trình C - Việt Nhật 2007 167 Lập trình C - Việt Nhật 2007 168

42
Dừng chương trình và mã lỗi Truyền mảng cho hàm
„ Thông thường main trả về giá trị kiểu int

„ có thể sử dụng khai báo: void main()

„ Nên sử dụng giá trị trả về để kiểm soát xử lý của chương


trình.

„ Sử dụng hàm exit(<exitcode>); để dừng chương trình và trả


về mã lỗi.

„ Nên xây dựng một đoạn chương trình con làm nhiệm vụ bắt
lỗi trong quá trình chạy.

Lập trình C - Việt Nhật 2007 169 Lập trình C - Việt Nhật 2007 170

1 /* Fig. 6.13: fig06_13.c


2 Passing arrays and individual array elements to functions */

Truyền mảng cho hàm 3


4
5
#include <stdio.h>
#define SIZE 5

6 void modifyArray( int [], int ); /* appears strange */


7 void modifyElement( int );
8
9 int main()
10 {
11 int a[ SIZE ] = { 0, 1, 2, 3, 4 }, i;
12
13 printf( "Effects of passing entire array call "
14 "by reference:\n\nThe values of the "
15 "original array are:\n" );
16
17 for ( i = 0; i <= SIZE - 1; i++ )
18 printf( "%3d", a[ i ] );
19
20 printf( "\n" );
21 modifyArray( a, SIZE ); /* passed call by reference */
22 printf( "The values of the modified array are:\n" );
23
24 for ( i = 0; i <= SIZE - 1; i++ )
25 printf( "%3d", a[ i ] );
26
27 printf( "\n\n\nEffects of passing array element call "
28 "by value:\n\nThe value of a[3] is %d\n", a[ 3 ] );
29 modifyElement( a[ 3 ] );
30 printf( "The value of a[ 3 ] is %d\n", a[ 3 ] );
Lập trình C - Việt Nhật 2007 171 31 return 0; Lập trình C - Việt Nhật 2007 172
32 }

43
Hàm truy cập, in Mảng 2 chiều Chương trình
1. void print_Score(int Score[MAX_STUDENT][MAX_SUBJECT], 1. main(void)
int nStudents, int nSubjects) 2. {
2. {
3. int nStudents, nScores;
3. int i,j;

4. for(i=0; i<nStudents; i++)


4. scanf(“%d %d”, &nStudents, &nScores);
5. { 5. if(nStudents <= MAX_STUDENT &&
6. for(j=0; j<nSubjects; j++)
nScores <= MAX_SCORES)
7. printf(“%2d\t”, &Score[i][j]); 6. read_Score(StudentScore, nStudents, nScores);
8. printf(“\n”);
9. } 7. print_Score (StudentScore, nStudents, nScores);
10. }
8. return 0;
9. }
Lập trình C - Việt Nhật 2007 173 Lập trình C - Việt Nhật 2007 174

„ Sử dụng hàm như tham số.

„ Ví dụ:
Ngôn ngữ lập trình C
bài tập viết chương trình giải phương trình bậc hai.


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

Đệ Quy

Cao Tuấn Dũng


2007

Lập trình C - Việt Nhật 2007 175

44
Nguyên lý Tính giai thừa
„ Trong C cho phép trong thân một hàm có thể gọi ngay „ Ví dụ: Viết chương trình nhập số tự nhiên n và tính giai thừa : n!.
đến chính nó, cơ chế này gọi là đệ qui. „ Giải quyết bài toán bằng vòng lặp
„ Có thể định nghĩa hàm đệ qui là hàm sẽ gọi đến chính 1. #include <stdio.h>
nó trực tiếp hay gián tiếp thông qua các hàm khác.
„ Cách tiến hành giải một bài toán đệ qui nhìn chung có 2. unsigned long int factorial(int n)
những điểm chung sau. 3. { unsigned long f = 1;
‰ Hàm đệ qui thực ra chỉ biết cách giải bài toán trong trường hợp đơn giản 4. for (int i = 1; i<=n; i++)
nhất (hay còn gọi là trường hợp cơ sở). 5. f *= i;
‰ Nếu hàm được gọi trong các trường hợp phức tạp hơn, hàm đệ qui sẽ 6. return f;
chia công việc cần giải quyết thành hai phần. Một phần hàm biết cách 7. }
giải quyết như thế nào, 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 đệ qui, phần sau phải
giống với bài toán ban đầu nhưng đơn giản hơn hay nhỏ hơn bài toán 8. int main(void)
ban đầu. 9. { int n;
‰ Để đảm bảo việc đệ qui có kết thúc, mỗi một lần gọi đệ qui thì bài toán
phải đảm bảo đơn giản hơn và các bước đệ qui này còn thực hiên tiếp 10. printf(“Nhap n:”); scanf(“%d”, &n);
cho dến khi nào bài toán đơn giản dần, đơn giản tới mức trở thành printf(“n! = %d! = %l\n”, n, factorial(n));
trường hợp cơ sở. 11. return 0;
12. }
Lập trình C - Việt Nhật 2007 177 Lập trình C - Việt Nhật 2007 178

Tính giai thừa Dãy Fibonaci


Tuy nhiên cũng có thể định nghĩa đệ qui hàm giai thừa như sau :
„
nếu n>0 n! = n * (n-1)!
„ Một ví dụ thứ hai dùng đệ qui là tính dẫy số
nếu n=0 n! = 0! = 1 Fibonaci
‰ Dãy số Fibonaci gồm những số
1. #include <stdio.h>
0, 1, 1, 2, 3, 5, 8, 13, 21 ...
2. unsigned long int factorial(int n)
3. { if(n==0) ‰ Bắt đầu từ hai số 0 và 1, tiếp sau đó các số Fibonaci
4. return 1;
5.
6. }
return (n* factorial(n-1)); sau bằng tổng của 2 số Fibonaci trước nó.
‰ Dẫy Fibonaci có thể định nghĩa đệ qui như sau:
7. int main(void)
{ int n;
8.
fibonaci(0) = 0; fibonaci(1) = 1;
printf(“Nhap n:”); scanf(“%d”, &n);
fibonaci(n) = fibonaci(n-1) + fibonaci(n-2) ∀n>1
9.
10. printf(“n! = %d! = %l\n”, n, factorial(n));
11. return 0;
12. }

Lập trình C - Việt Nhật 2007 179 Lập trình C - Việt Nhật 2007 180

45
Dãy Fibonaci (tiếp) Lời gọi hàm đệ quy và Điều kiện
/* Tính dẫy số Fibonaci phương pháp đệ qui */ dừng của thuật giải đệ quy
#include <stdio.h>
long fibo( long ); /* Hàm nguyên mẫu */ „ Bài toán giải bằng thuật giải đệ quy phải có điều kiện dừng.
main()
{
long result, n;
printf("Hãy nhập vào một số nguyên : "); „ Thuật toán đệ quy trên máy tính có thể bị giới hạn bởi dung
scanf("%ld", &n); lượng bộ nhớ do lời gọi hàm liên tiếp.
result = fibo(n);
printf("Fibonaci thứ %ld là : %ld\n", number, result);
return 0;
}
/* Định nghĩa đệ qui hàm fibonaci */
long fibo( long n)
{ main
if ( n = 0 || n = 1 )
return n;
else factorial (4) factorial (3) factorial (2) factorial (1)
return fibo(n-1) + fibo(n-2);
}
Hãy vẽ sơ đồ tiến trình gọi hàm khi thực hiện tính dãy fibonacci bằng
đệ quy.
Lập trình C - Việt Nhật 2007 181 Lập trình C - Việt Nhật 2007 182

Bài toán Tháp Hà Nội Thuật giải


„ Có 3 cái cột và một chồng đĩa ở cột thứ nhất. Hãy chuyển „ Chuyển (n-1) đĩa sang cột trung gian.
chồng đĩa sang cột thứ ba với điều kiện mỗi lần di chuyển chỉ „ Chuyển đĩa lớn nhất sang cột đích.
một đĩa và các đĩa bé luôn nằm trên đĩa lớn. „ Chuyển (n-1) đĩa từ cột trung gian sang cột đích.

„ Truyền thuyết: lúc thế giới hình thành, trong ngôi đền thờ
Brahma có một chồng 64 cái đĩa. Mỗi ngày, có một thầy tu di
chuyển một đĩa. Đến khi hết đĩa thì đó là ngày tận thế.

Lập trình C - Việt Nhật 2007 183 Lập trình C - Việt Nhật 2007 184

46
Cài đặt bằng đệ quy
1. MoveDisk(disk_number, starting_post, target_post,
intermediate_post)
2.
3.
{
if(disk)number > 1)
Ngôn ngữ lập trình C
4. {
5. MoveDisk(disk_number-1, starting_post,
intermediate_post, target_post);
6. printf(“Move disk number %d, from post %d to post %d.\n”,
disk_number, starting_post, target_post);
7. MoveDisk(disk_number-1,intermediate_post,
target_post, starting_post); CON TRỎ
8. }
9. else
10. printf(“Move disk number 1 from post %d to post %d.\n”, Cao Tuấn Dũng
starting_post, target_post); 2007
11. }

Lập trình C - Việt Nhật 2007 185

Con trỏ Truyền tham số qua trị


„ Biến con trỏ 1. #include <stdio.h>

2. void move_one(int x, int y)


„ Khai báo biến con trỏ
3. {
4. x = x-1;
„ Địa chỉ và giá trị 5. y = y+1;
6. }
„ Truyền tham chiếu trong lời gọi hàm
7. int main(void)
8. {
9. int a = 4, b = 7;
10. move_one(a, b);
11. print(“%d, %d\n”, a, b);
12. return 0;
13. }
Lập trình C - Việt Nhật 2007 187 Lập trình C - Việt Nhật 2007 188

47
Bộ nhớ Giá trị biến và địa chỉ trong bộ nhớ
„ Biến là tên các vùng nhớ được dùng để giữ các giá trị.
M1 main#1::a „ Khi chúng ta khai báo một biến, máy sẽ cấp phát cho biến đó
M2 main#1::b một số ô nhớ liên tiếp đủ để chứa nội dung của biến, ví dụ
một biến ký tự được cấp phát một byte, một biến nguyên
được cấp phát hai bytes, một biến thực được cấp phát bốn
M3 move_one#1::x bytes .v.v
M4 move_one#1::y „ Hàm move_one(a, b) cần truy cập vào các vị trí nhớ của a và
b cũng như các giá trị của a và b.

„ Bằng cách nào?


x 1024: 4 giá trị

tên biến địa chỉ

Lập trình C - Việt Nhật 2007 189 Lập trình C - Việt Nhật 2007 190

Kiểu dữ liệu Con trỏ Khai báo, toán tử và sử dụng trong


„ Địa chỉ của biến được tính là số thứ tự của byte đầu tiên trong
hàm
dãy các bytes được cấp cho biến. Tuỳ theo kích thước bộ „ Khai báo kiểu dữ liệu con trỏ:
nhớ người ta biểu diễn địa chỉ bằng hai hoặc bốn bytes.
int * “con trỏ đến kiểu int”
float * “con trỏ đến kiểu float”
„ Một biến kiểu con trỏ (pointer) chứa một tham chiếu char * “con trỏ đến kiểu character”
(reference) đến một biến loại khác. Nói khác đi, biến con trỏ
chứa địa chỉ ô nhớ của một biến.
„ Toán tử
int x; 1024: 4 & địa chỉ của một đối tượng
int* xp; * giá trị của vùng nhớ biến con trỏ chỉ đến
x
/* con tro tro toi mot so nguyen */
1024: „ Con trỏ được dùng như tham số hình thức trong khai báo
x = 4;
hàm để truyền và lấy các đối số có giá trị thay đổi.
xp = &x; xp

Lập trình C - Việt Nhật 2007 191 Lập trình C - Việt Nhật 2007 192

48
Con trỏ và địa chỉ biến Sử dụng Con trỏ
„ Địa chỉ của hai biến ký tự liên tiếp sẽ cách nhau một byte „ Truy cập vùng nhớ được chỉ bởi một con trỏ
trong khi địa chỉ của hai biến nguyên liên tiếp cách nhau hai int x=1,y=2,z[10];
int *pi; /*pi là một biến con trỏ có kiểu nguyên*/
byte còn địa chỉ của hai biến thực liên tiếp cách nhau tới bốn
pi = &x; /*Địa chỉ của x được gán cho pi, và pi trỏ tới biến x*/
bytes. y=*pi; /*y có giá trị bằng 1*/
„ Người ta phân biệt các con trỏ theo các kiểu địa chỉ chứa *pi=15; /*Từ bây giờ x có giá trị bằng 15*/
trong các con trỏ: con trỏ kiểu nguyên dùng để chứa địa chỉ pi=&z[0]; /*Từ đây pi chứa địa chỉ của z[0], tức là địa chỉ của mảng z*/
các biến nguyên, con trỏ ký tự chứa địa chỉ các biến ký tự,
con trỏ thực chứa địa chỉ các biến thực.
1024: 15
x

1024:
... p a
pi

Lập trình C - Việt Nhật 2007 193 Lập trình C - Việt Nhật 2007 194

Các phép toán trên con trỏ Các phép toán trên con trỏ
„ Một biến con trỏ có thể được cộng, trừ với một số nguyên (int „ Có thể áp dụng các phép so sánh, phép gán cho các con trỏ.
,long) để cho kết quả là một con trỏ cùng kiểu. Xét ví dụ sau: Trong các phép toán này đòi hỏi các toán hạng con trỏ phải
int *x=2,*px,*py; có cùng kiểu. Mọi sự chuyển đổi kiểu tự động từ các kiểu
px = &x; khác thành các kiểu con trỏ phải luôn luôn được cân nhắc và
py = px+1; /*py trỏ đến số nguyên nằm sau x hỏi ý kiến bởi chương trình biên dịch.
trong bộ nhớ*/ int *addr1;
„ Phép trừ hai con trỏ cùng kiểu được coi là hợp lệ và cho kết char *addr2;
quả là một số nguyên biểu thị "khoảng cách" (ở đây bằng số addr1=0; /*Chương trình dịch sẽ đưa ra
phần tử ) giữa hai biến con trỏ. một warning */
Ví dụ 3.?. Quay về ví dụ trên, câu lệnh addr2 = (char *)0; /*Phép gán này hợp lệ*/
x=py-px; if(addr1==addr2) /*Gây ra một warning*/
gán 1 cho x.
{
„ Phép cộng hai con trỏ không hợp lệ. Cũng vậy đối với các addr1 = (int *)addr2; /*Hợp lệ*/
phép nhân, chia hai con trỏ.
}

Lập trình C - Việt Nhật 2007 195 Lập trình C - Việt Nhật 2007 196

49
Sử dụng con trỏ như tham số Bộ nhớ
„ #include <stdio.h>
„ void move_one(int* xPtr, int* yPtr) M1 main#1::a
{ M2 main#1::b
*xPtr = *xPtr-1;
*yPtr = *yPtr+1;
} M3 move_one#1::xPtr
„ int main(void) M4 move_one#1::yPtr
{
int a, b;
a=4; b=7;
move_one(&a, &b);
print(“%d, %d\n”, a, b);
return 0;
}
Lập trình C - Việt Nhật 2007 197 Lập trình C - Việt Nhật 2007 198

Hàm swap Bài tập


„ void swap(int *px, int *py) Lập chương trình:
{ - Nhập từ bàn phím một số nguyên.
int temp; - Đưa ra màn hình dưới dạng hexadecimal nội dung byte cao và
temp = *px; byte thấp của số nguyên.
*px = *py;
#include <stdio.h>
*py = temp;
main() {
}
int n;
char *pc;
„ main(void) printf("Nhap vao so nguyen : ");
{ scanf("%d",&n);
int a, b; pc=(char *)&n; /*pc trỏ đến byte cao cua n, pc+1
a=2; b=9; trỏ đến byte thấp*/
swap(&a, &b); printf("Byte cao %x ,byte thap %x",*pc ,*pc++);
} }
Lập trình C - Việt Nhật 2007 199 Lập trình C - Việt Nhật 2007 200

50
Con trỏ void Con trỏ và mảng một chiều
„ Kiểu dữ liệu void „ Xét câu lệnh: int a[10];
Giá trị trả về của hàm: không cần giá trị trả về a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8] a[9]
Tham số trong hàm: không có tham số
„ Con trỏ kiểu void được khai báo như sau: „ Tên mảng là một hằng địa chỉ, nó chính là địa chỉ của phần
tử đầu tiên của mảng; điều này có nghĩa là:
void *tên_con_trỏ;
a tương đương với &a[0]
„ Đây là con trỏ đặc biệt, con trỏ không kiểu, nó có thể nhận
bất kỳ địa chỉ kiểu nào. Chẳng hạn các câu lệnh sau là hợp „ Nếu pa là một con trỏ kiểu nguyên,
lệ: int *pa;
void *px,*py; „ Khi đó phép gán pa
int x=1; pa = &a[0];
float y=0.1; „ Đem pa trỏ đến phần tử a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8] a[9]

px=&x; thứ nhất (có chỉ số là 0) của a;


py=&y; nghĩa là pa chứa địa chỉ của a[0].

Lập trình C - Việt Nhật 2007 201 Lập trình C - Việt Nhật 2007 202

Con trỏ và mảng một chiều Con trỏ và mảng một chiều
„ pa +i là địa chỉ của a[i] và *(pa+i) là nội dung của a[i] „ Có sự khác nhau giữa tên của mảng và con trỏ. Một con trỏ là
một biến và vì thế, các câu lệnh pa=a và pa++ là hợp lệ.
pa+9 a[9] Nhưng một tên mảng không phải là một con trỏ, do đó các
câu lệnh kiểu như a=pa;a++ là không hợp lệ. (Về thực chất,
... ...
tên mảng là một hằng con trỏ do đó chúng ta không thể thay
đổi giá trị của nó được).

pa+1 a[1]
„ Ví dụ : viết chương trình thực hiện các công việc sau:
‰ Đọc từ bàn phím các phần tử của một mảng.
pa a[0] ‰ Tính tổng của chúng

„ Một biểu thức chứa một mảng và một chỉ số tương đương với
một cách viết khác sử dụng một con trỏ cùng một độ lệch.

Lập trình C - Việt Nhật 2007 203 Lập trình C - Việt Nhật 2007 204

51
#include <stdio.h> #include <stdio.h>
#include <stdio.h> #include <stdio.h> main() main()
main() main() { {
{ { float a{5],s, *p;
float a{5],s,*p;
int i; p=a;
float a{5],s; float a{5],s; for(i=0;i<5;i++) int i; p=a;
int i int i [ for(i=0;i<5;i++)
for(i=0;i<5;i++) for(i=0;i<5;i++) printf("\na[%d] = [
[ [ ",i) ;
printf("\na[%d] =
scanf("%f",&p[i]);
printf("\na[%d] = printf("\na[%d] = ",i) ;
}
",i) ; ",i) ; s=0; scanf("%f",p+i);
scanf("%f",&a[i]); scanf("%f",a+i); for(i=0;i<5;i++) }
} } s+=p[i]; s=0;
s=0; s=0; printf("\n tong la: for(i=0;i<5;i++)
%10.2f",s);
for(i=0;i<5;i++) for(i=0;i<5;i++) } s+=*(p+i);
s+=a[i]; s+=a[i]; printf("\n tong la:
printf("\n tong la: printf("\n tong la: %10.2f",s);
%10.2f",s); %10.2f",s); }
} }
Lập trình C - Việt Nhật 2007 205 Lập trình C - Việt Nhật 2007 206

Truyền mảng qua con trỏ Con trỏ và mảng nhiều chiều
1. #include <stdio.h> „ Phép toán lấy địa chỉ nói chung không dùng được đối với các thành
2. #define SIZE 5 phần của mảng nhiều chiều (trừ trường hợp mảng hai chiều các số
nguyên).
3. void getArray(int *a, int size);
„ Phép cộng địa chỉ trong mảng hai chiều
4. main() „ Xét khai báo
5. {int an_array[SIZE]; float a[2][3];
6. getArray(an_array, SIZE); „ Với khai báo này hệ thống cấp sáu phần tử liên tiếp trong bộ nhớ theo
7. return 0; thứ tự sau:
8. }
a[0][0] a[0][1] a[0][2] a[1][0] a[1][1] a[1][2]
„ tên của mảng hai chiều được hiểu như địa chỉ của phần tử đầu tiên của
9. void getArray(int *a, int size)
nó; phép cộng địa chỉ phải hiểu như sau: C cho rằng mảng hai chiều là
10. {for(int i=0; i<size; i++) {
mảng của mảng; như vậy với khai báo trên thi a là mảng mà mỗi phần tử
11. printf(“a[%d]=“); của nó là một dãy gồm 3 số thực. Vì vậy
12. scanf(“%d”, &a[i]);
‰ a trỏ tới đầu hàng thứ nhất (phần tử a[0][0]
13. }
‰ a+1 trỏ tới đầu hàng thứ hai (phần tử a[1][0]
14. }

Lập trình C - Việt Nhật 2007 207 Lập trình C - Việt Nhật 2007 208

52
Con trỏ và mảng hai chiều Tính địa chỉ từng phần tử
„ Để truy xuất vào các phần tử của mảng hai chiều ta ‰ Để ý rằng, a là một hằng con trỏ trỏ đến các dòng của một ma trân
hai chiều, vì vậy
vẫn có thể dùng con trỏ theo cách sau:
a trỏ đến dòng thứ nhất
float *p, a[2][3]; a+1 trỏ đến dòng thứ hai
p=(float*)a;
‰ Để tính toán được địa chỉ của phần tử ở dòng i cột j chúng ta phải
„ Khi đó dùng phép chuyển đổi kiểu bắt buộc đối với a: (float * )a, đây là
p trỏ tới a[0][0] con trỏ trỏ đến thành phần a[0][0] của ma trận. Và vì vậy thành
phần a[i][j] sẽ có địa chỉ là (float *a) +i*n+j (n là số cột).
p+1 trỏ tới a[0][1]
p +2 trỏ tới a[0][2] ‰ Một cách tổng quát, nếu mảng có kiểu type và có kích thước các
chiều tương ứng là n1,n2,..,nk (Giả sử mảng a có k chiều). Địa chỉ
p +3 trỏ tới a[1][0] cuả thành phần a[0]..[0] (k chỉ số 0) là (type *)a, và địa chỉ của
p +4 trỏ tới a[1][1] a[i1][i2]...[ik] được tính như sau
k −1 k
p +5 trỏ tới a[1][2] (type*)a + ∑ ij ∏ nl + ik
j =1 l = j +1

Lập trình C - Việt Nhật 2007 209 Lập trình C - Việt Nhật 2007 210

Ví dụ: Đọc dữ liệu cho mảng hai chiều Mảng các con trỏ
#include <stdio.h> „ Chúng ta có thể khai báo một mảng các con trỏ bằng câu
main()
{ lệnh sau:
float a[2][3],*p; type *pointer_array[size];
int i,m,n;
p=(float*)a;
„ ví dụ câu lệnh,
for(i=0;i<2;i++) char *ma[10];
for(j=0;j<3;j++)
Sẽ khai báo một mảng 10 con trỏ char có thể được dùng để
{
printf("a[%d][%d] = ",i,j); khai báo một mảng để lưu trữ địa chỉ của mười chuỗi ký tự
scanf("%f",p+i*3+j); nào đó.
} „ Nếu các con trỏ được chuẩn bị để chỉ đến một biến nào đó đã
for(i=0;i<2;i++)
for(j=0;j<3;j++) có, thì như vậy, 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
printf("%6.2f",a[i][j]); biến đó có liên tiếp hay không.
if(j==2) printf("\n");
}
}
Lập trình C - Việt Nhật 2007 211 Lập trình C - Việt Nhật 2007 212

53
Ví dụ: sắp xếp thông qua con trỏ
‰ Xem xét một mảng các con trỏ ptr_array được gán các địa chỉ /*Gán các thành phần của mảng*/
ptr_array[0]=&a;
của các biến int có giá trị và vị trí bất kỳ. Chúng ta sẽ dùng một
ptr_array[1]=&b;
hàm để sắp xếp lại các địa chỉ này trong mảng để sao cho các ptr_array[2]=&c;
địa chỉ của các số bé được xếp trước địa chỉ của các số lớn hơn. ptr_array[3]=&d;
‰ Không làm thay đổi vị trí hoặc thay đổi các giá trị của các biến ptr_array[4]=&e;
nhưng mảng vẫn có vẻ như là một mảng chỉ đến các giá trị đã ptr_array[5]=&f;
sắp xếp có thứ tự. /*Sắp xếp lại dãy số*/
for(i=0;i<5;i++)
for(j=i+1;j<6;j++)
#include <stdio.h> if(*ptr_array[i]>*ptr_array[j])
main() { {
x=ptr_array[i];
int i,j,*x; ptr_array[i]=ptr_array[j];
int d=10,e=3,f=7; ptr_array[j]=x;
}
int a=12,b=2,c=6;
/*In kết quả sau khi sắp xếp*/
int *ptr_array[6]; for(i=0;i<6;i++)
printf(" %d \n",*ptr_array[i]);
}

Lập trình C - Việt Nhật 2007 213 Lập trình C - Việt Nhật 2007 214

Mảng nhiều chiều và mảng con trỏ Cấp phát động


„ Giữa mảng nhiều chiều và mảng các con trỏ tồn tại nhiều „ Ý nghĩa của việc cấp phát bộ nhớ động là cho phép
điểm khác nhau: chương trình sử dụng vừa đúng khối lượng bộ nhớ mà
‰ Mảng nhiều chiều thực sự là mảng có khai báo, do đó có chỗ đầy đủ cho
tất cả các phần tử của nó. Còn mảng các con trỏ chỉ mới có chỗ cho các
chương trình cần, và khi không cần dùng tới nữa thì có
biến con trỏ mà thôi. thể giải phóng để cho các công việc tiếp theo có thể sử
„ Việc sử dụng mảng các con trỏ có hai ưu điểm: dụng được. Như vậy, cùng một vùng bộ nhớ có thể
‰ Việc truy xuất đến các phần tử là truy xuất gián tiếp thông qua các con được sử dụng cho các mục đích khác nhau trong thời
trỏ và như vậy, vị trí của các mảng con này có thể là bất kỳ, và chúng có gian thực hiện của chương trình.
thể là những mảng đã có bằng cách xin cấp phát chỗ động hay bằng
khai báo biến mảng bình thường, tùy ý. „ Vùng nhớ heap được sử dụng cho mục đích cấp phát
‰ Các mảng con của nó được chỉ đến bởi các con trỏ, có thể có độ dài tùy động các khối nhớ có kích thước thay đổi. Có nhiều cấu
ý, hoặc có thể không có (nếu con trỏ đó không được chuẩn bị, hoặc trúc dữ liệu sử dụng cách cấp phát động, ta có thể liệt kê
được gán bằng NULL).
một vài loại như: cây (tree), các loại danh sách liên kết.

Lập trình C - Việt Nhật 2007 215 Lập trình C - Việt Nhật 2007 216

54
Cấp phát động Ví dụ
#include <stdio.h>
„ Hàm malloc trong thư viện < stdlib.h>, <alloc.h> #include <string.h>
Cú pháp khai báo #include <alloc.h>
#include <process.h>
(type*)malloc (số ô nhớ cần cấp phát);
main()
‰ Hàm malloc dùng để xin cấp phát một vùng bộ nhớ (với kích {
thước được xác định khi gọi hàm) từ vùng nhớ heap. Hàm này char *str;
/* cấp phat bộ nhớ cho string */
cho phép một chương trình xin cấp phát một vùng bộ nhớ đúng if ((str = (char *) malloc(10)) == NULL)
với kích thước mà chương trình cần. {
‰ Giá trị trả về: printf("Not enough memory to allocate buffer\n");
exit(1); /* Kết thúc chương trình trong trường hợp tràn
„ Trong trường hợp cấp phát thành công, hàm malloc trả về một con bộ nhớ*/
trỏ tới khối nhớ mới được cung cấp. }
„ Trong trường hợp có lỗi (không đủ bộ nhớ để cấp phát, malloc trả về /* copy "Hello" into string */
strcpy(str, "Hello");
giá trị NULL.
/* display string */
„ Nếu tham số size==0, malloc trả về con trỏ NULL printf("String is %s\n", str);
/* free memory */
free(str);
}
Lập trình C - Việt Nhật 2007 217 Lập trình C - Việt Nhật 2007 218

Cấp phát động Ví dụ


„ Hàm calloc (trong thư viện <stdlib.h>, <alloc.h) #include <stdio.h>
#include <alloc.h>
‰ Cú pháp khai báo
#include <string.h>
(datatype*)calloc(n, sizeof(object)); int main(void)
‰ Hàm calloc xin cấp phát một vùng nhớ kích thước {
n*sizeof(object) bytes và xóa trắng vùng nhớ này. Muốn xin char *str = NULL;
cấp phát vùng nhớ có kích thước lớn hơn 64K, phải sử dụng /* allocate memory for string */
hàm farcalloc() (Cấp phát xa) str = (char *) calloc(10, sizeof(char));
‰ Giá trị trả về: /* copy "Hello" into string */
„ Trong trường hợp thành công, calloc trả về con trỏ tới vùng nhớ mới strcpy(str, "Hello");
được cấp phát. /* display string */
„ Khi có lỗi cấp phát (không đủ bộ nhớ hoặc một trong hai tham số printf("String is %s\n", str);
nitems hoặc size bằng 0) thì hàm trả về NULL. /* free memory */
free(str);
return 0;
}

Lập trình C - Việt Nhật 2007 219 Lập trình C - Việt Nhật 2007 220

55
Cấp phát động
„ Hàm farrealloc, realloc (thư viện <alloc.h>, <stdlib.h>) #include <stdio.h>
‰ Cú pháp khai báo #include <alloc.h>
(datatype*)realloc(buf_ptr,newsize ); #include <string.h>
int main(void)
void far *farrealloc(void far *oldblock, unsigned long
nbytes); {
char *str;
‰ Trong đó buf_ptr là con trỏ đang chỉ tới vùng ô nhớ được cấp phát từ
/* allocate memory for string */
trước, còn newsize là kích thước mới càn cấp phát; như vậy hàm này
điều chỉnh lại kích thước của khối nhớ block thành size, sao chép nội str = (char *) malloc(10);
dung vùng nhớ cũ vào vùng mới nếu thấy cần thiết /* copy "Hello" into string */
‰ Hàm farrealloc chỉnh lại kích thước của khối nhớ block thành nbytes, strcpy(str, "Hello");
sao chép nội dung của vùng nhớ cũ vào vùng nhớ mới nếu vùng nhớ printf("String is %s\n Address is %p\n", str, str);
mới được cấp phát lại không cùng địa chỉ với vùng trước cấp phát. str = (char *) realloc(str, 20);
‰ Giá trị trả về: printf("String is %s\n New address is %p\n", str,
str);
„ Trong trương hợp thành công, cả hai hàm trả về địa chỉ của khối mới /* free memory */
được cấp phát lại, địa chỉ mới có thể khác so với địa chỉ của khối ban free(str);
đầu.
return 0;
„ Trong trường hợp thất bại, cả hai hàm trả về NULL. }

Lập trình C - Việt Nhật 2007 221 Lập trình C - Việt Nhật 2007 222

Giải phóng vùng nhớ đã cấp phát


„ Hàm farfree, free (Thư Viện: <alloc.h>)
‰ Cú pháp khai báo:
„ void farfree(void far *block);
Ngôn ngữ lập trình C
„ void free(void *block);
‰ Hàm farfree giải phóng một khối bộ nhớ đã được cấp phát trước
đấy bởi hàm farcalloc, farmalloc hoặc farrealloc.
‰ Hàm free giải phóng một khối nhớ đã được cấp phát trước đó
bằng hàm calloc, malloc, hoặc realloc.
KÝ TỰ VÀ XÂU (CHUỖI) KÝ TỰ

Cao Tuấn Dũng


2007

Lập trình C - Việt Nhật 2007 223

56
Ký tự (character) Nhập xuất Ký tự
„ Kiểu char: „ scanf
‰ ký tự “in được” gồm: 26 chữ thường (a..z), 26 chữ hoa (A..Z), 10 char ch;
chữ số (0..9), khoảng trắng, các ký tự: scanf(“%c”, &ch);
!“#$%&‘()*+,-./:;<=>?@[\]^_{|}~
‰ Các ký tự “không in được”: tab, lert (bell), newline, formfeed,... „ sử dụng các đoạn macro có trong thư viện <stdio.h>
putchar: đưa ký tự ra thiết bị xuất chuẩn (stdout)
„ các ký tự “in được” đặc biệt: ‘\\’, ‘\’’, ‘\”’ putchar(‘\n’);
getchar: lấy ký tự từ thiết bị nhập chuẩn (stdin)
„ các ký tự “không in được” đặc biệt: ch = getchar();
\n new line
\a bell „ getch: lấy trực tiếp ký tự từ bàn phím không hiển thị ra màn hình
\0 null character ch = getch();
\b backspace getche(): lấy trực tiếp ký tự từ bàn phím và hiển thị ký tự ra màn
\t horizontal tab hình.
... ch = getche();

Lập trình C - Việt Nhật 2007 225 Lập trình C - Việt Nhật 2007 226

getchar putchar
1. #include <stdio.h> 1. /* putchar example */
2. #include <stdio.h>

2. int main(void) 3. /* define some box-drawing characters */


3. { 4. #define LEFT_TOP 0xDA
4. int c; 5. #define RIGHT_TOP 0xBF
6. #define HORIZ 0xC4
7. #define VERT 0xB3
5. /* Note that getchar reads from stdin and is line buffered; this 8. #define LEFT_BOT 0xC0
means it will not return until you press ENTER. */ 9. #define RIGHT_BOT 0xD9

6. while ((c = getchar()) != '\n') 10. int main(void)


11. {
7. printf("%c", c);
12. char i, j;
13. /* draw the top of the box */
8. return 0; 14. putchar(LEFT_TOP);
9. } 15. for (i=0; i<10; i++)
Lập trình C - Việt Nhật 2007 227
16. putchar(HORIZ); Lập trình C - Việt Nhật 2007 228

57
Một số hàm khác
putchar(RIGHT_TOP);
17.
18. putchar('\n');
„ kbhit: kiểm tra có phím bấm

/* draw the middle */


19.
20. for (i=0; i<4; i++)
1. /* khbit example */
21. { 2. #include <conio.h>
22. putchar(VERT);
23. for (j=0; j<10; j++)
24. putchar(' '); 3. int main(void)
25. putchar(VERT);
4. {
26. putchar('\n');
27. } 5. cprintf("Press any key to continue:");
28. /* draw the bottom */ 6. while (!kbhit()) /* do nothing */ ;
29. putchar(LEFT_BOT);
30. for (i=0; i<10; i++) 7. cprintf("\r\nA key was pressed...\r\n");
31. putchar(HORIZ);
32. putchar(RIGHT_BOT); 8. return 0;
33. putchar('\n'); 9. }
34. return 0;
35. } Lập trình C - Việt Nhật 2007 229 Lập trình C - Việt Nhật 2007 230

Chuỗi ký tự (string) Ký tự và Chuỗi


„ ChuỗI ký tự „ Các hằng ký tự
‘s’, ‘N’, ‘9’, ‘%’, ‘\n’, ‘ ‘, ‘\0’, …
„ Khai báo biến kiểu chuỗI ký tự.
‘\0’: ký tự null
„ Các hằng chuỗi ký tự:
„ Làm việc vớI các biến kiểu chuỗi ký tự. “So %d khong la so nguyen to.\n”

„ Các biến kiểu ký tự:

char ch1=‘c’, ch2=‘n’, ch3=‘t’;


printf(“Khoa %c%c%c%c\n”, ch1, ch2, ch3, ch3);

Lập trình C - Việt Nhật 2007 231 Lập trình C - Việt Nhật 2007 232

58
Xâu ký tự Khai báo và khởi tạo một xâu
„ Một xâu là một mảng một chiều các ký tự „ Dưới dạng một mảng các ký tự:
char cay[6]={‘m’,’i’,’t’,’\0’}; char ten[10]={‘h’,’o’,’a’,’h’,’o’,’n’,’g’,’\0’};
printf(“Trong vuon co cay %s\n”, cay);
„ Một xâu cũng chứa một con trỏ trỏ tới ký tự đầu tiên char ten[10];
ten[0]=‘h’; ten[1]=‘o’; ten[2]=‘a’;
ten[3]=‘h’; ten[4]=‘o’; ten[5]=‘n’; ten[6]=‘g’;
„ chính xác hơn xâu là mảng một chiều các ký tự kết thúc bằng ten[7]=\0’;
ký tự null (null-terminated array of char)
char ten[10]=“hoahong”;
cay
‘m’ ‘i’ ‘t’ ‘\0’ char ten[]=“hoahong”; // Tạo mảng 8 phần tử. Ký tự cuối cùng là ‘\0’
„ Dưới dạng con trỏ
‰ char *colorptr = “blue”; // Tạo con trỏ colorptr trỏ đến xâu “blue”
cay[0] cay[4] nằm đâu đó trong bộ nhớ

Lập trình C - Việt Nhật 2007 233 Lập trình C - Việt Nhật 2007 234

Khai báo dưới dạng mảng ký tự Lỗi khi tạo một chuỗi
Ký tự Chỉ có thể chứa
kết thúc:
tối
• Đánh dấu đakết
4 ký tự,xâu
thúc „ Chú ý: không có phép gán trong kiểu dữ liệu chuỗi
Khai báo 1: do `\0’
• ký tự đặc biệt: ’\0’ „ như thế này là sai
char name[5] = “Ann”;
• aka NUL (single L) char ten[10];
ten = “hoahong”;

name A n n \0
is 0x2000

0x2000 0x2004

Lập trình C - Việt Nhật 2007 235 Lập trình C - Việt Nhật 2007 236

59
Chú ý Ký tự trong xâu
0x3995 0x399C
„ Không :
sử dụng toán tử gán = để chép nội dung của một chuỗi sang
chuỗi khác. name J o h n \0
char a[4]=“hi”; is 0x3995
char b[4];
b = a; //???
index 0 index 4
„ Không:
dùng toán tử == để so sánh nội dung hai chuỗi char name[8] = “John”;
char a[] = “hi”; int i = 2;
char b[] = “there”;
printf(“Ky tu tai chi so %d la %c.\n”, i, name[i]);
if(a==b) //???
{}
Ket qua: Ky tu tai chi so 2 la h.

Lập trình C - Việt Nhật 2007 237 Lập trình C - Việt Nhật 2007 238

Ký tự trong xâu Thư viện hàm thao tác với ký tự


0x3995 0x399C
„ Chứa các hàm hữu ích cho việc kiểm tra và biến đổi ký tự
„ Mỗi hàm nhận 1 ký tự hoặc EOF làm đối số
name J o X n \0 „ Nằm trong ctype.h
is 0x3995

index 2

char name[8] = “John”;

name[2] = ‘X’;
printf(“Ten: %s\n”, name);

Ket qua: Ten: JoXn

Lập trình C - Việt Nhật 2007 239 Lập trình C - Việt Nhật 2007 240

60
Danh sách các hàm Làm việc với chuỗi
Prototype Description

int isdigit( int c ) Trả về true nếu c là một chữ số và false nếu không phải „ #include <string.h>
int isalpha( int c ) Trả về true nếu c là một chữ cái và false nếu không phải
int isalnum( int c ) Trả về true nếu c là một chữ số hay chữ cái và false nếu không
int isxdigit( int c ) Trả về true nếu c là một chữ số hệ 16 và false nếu không „ Với hàm scanf và printf
int islower( int c ) Trả về true nếu c là một chữ thường và false nếu không phải
int isupper( int c ) Trả về true nếu c là một chữ hoa và false nếu không phải
int tolower( int c ) Trả về chữ thường nếu c là một chữ hoa và không thay đổi 1. #include <stdio.h>
trong trường hợp ngược lại
int toupper( int c ) Trả về chữ hoa nếu c là một chữ thường và không thay đổi
2. void main (void)
trong trường hợp ngược lại
3. {
int isspace( int c ) Trả về true nếu c là các ký tự trắng, xuống dòng ‘\n’, ‘\t’,
‘\r’ ‘\v’ 4. char name[20];
int iscntrl( int c ) Trả về true nếu c là một ký tự điều khiển false nếu không phải 5. printf (“Enter a name: “);
int ispunct( int c ) Trả về true nếu c là một ký tự in trừ chữ số, chữ cái và ký tự
trắng và false nếu không phải
6. scanf (“%s”, name); // there is no & before name
int isprint( int c ) Trả về true nếu c là một ký tự in tính cả ký tự trắng và false 7. printf (“Hello %s\n”, name);
nếu không phải
int isgraph( int c ) Trả về true nếu c là một ký tự in không tính ký tự trắng và 8. }
false nếu không phải

Lập trình C - Việt Nhật 2007 241 Lập trình C - Việt Nhật 2007 242

strlen() Gán một chuỗi vào chuỗi khác


„ Độ dài chuỗi: Số ký tự trong chuỗi không kể null. „ gán từng ký tự trong chuỗi.
size_t strlen(const char *s); 1. char str[] = “qua mang cut”;
2. char newstr[30];
1. #include <stdio.h> 3. for(int i = 0; i<strlen(str); i++)
2. #include <string.h> 4. newstr[i] = str[i];
5. newstr[i] = ‘\0’;
3. int main(void)
4. { „ dùng hàm strcpy trong <string.h>
5. char *string = "Borland International"; char *strcpy(char *dest, const char *src);
6. printf("%d\n", strlen(string)); // 21
7. return 0; chép chuỗi src sang chuỗi dest cho đến khi gặp null
8. } character
strcpy(newstr, str);
Lập trình C - Việt Nhật 2007 243 Lập trình C - Việt Nhật 2007 244

61
Ví dụ Lỗi thường gặp 1
#include <stdio.h>
#include <string.h>

#define MAXLENGTH 100


Không tương thích kiểu
int main()
{
char string1[MAXLENGTH]; Example:
char string2[MAXLENGTH]; char name1[5] = “Ann”;
strcpy(string1, “Hello World!”); char name2[5] = “Dave”;
strcpy(string2, string1);
name2 = name1;
return 0;
}
Error: “LValue required ...”
string1: “Hello World!”
string2: “Hello World!”
Lập trình C - Việt Nhật 2007 245 Lập trình C - Việt Nhật 2007 246

Lỗi thường gặp 2 Ghép chuỗi bằng strcat()


char *strcat(char *dest, const char *src);
Thiếu bộ nhớ „

„ Ghép chuỗi src vào cuối chuỗi dest. Chiều dài chuỗi kết quả là
char name[] = “Ann”; strlen(dest) + strlen(src)

strcpy(name, “David”);
1. char destination[25];
2. char *blank = " ", *c = “C++“;
3. char *turbo = "Turbo";

name 4. strcpy(destination, turbo);


A n n \0
is 0x2000 5. strcat(destination, blank);
6. strcat(destination, c);
0x2000 0x2003 7. printf("%s\n", destination);
8. ...
Lập trình C - Việt Nhật 2007 247 Lập trình C - Việt Nhật 2007 248

62
So sánh chuỗi: strcmp()
Không đủ không
„ int strcmp(const char *s1, const char*s2);
gian lưu trữ ký tự
char name[5]; „ kết quả: số âm nếu s1 < s2
0 nếu s1 == s2
strcpy(name, “Ann”); số dương nếu s1 > s2
strcat(name, “ Smith”);
„ Hàm strncmp()

int strncmp(const char *s1, const char *s2, size_t maxlen);


name A n n S m i t h \0
so sánh hai chuỗi với chiều dài cần so sánh là maxlen
is 0x2000

0x2000 0x2004

Lập trình C - Việt Nhật 2007 249 Lập trình C - Việt Nhật 2007 250

strncat() và strncpy() Biến đổi chuỗi sang số


„ strncpy „ Sử dụng stdlib.h
char *strncpy(char *dest, const char *src, size_t maxlen); „ atoi(), atof(), atol():
đổi chuỗi ký tự sang số.
chép tối đa maxlen ký tự từ chuỗi src sang chuỗi dest
int atoi(const char *s);
double atof(const char *s);
„ strncat long atol(const char *s);
char *strncat(char *dest, const char *src, size_t maxlen);
„ ...
ghép tối đa maxlen ký tự trong chuỗi src vào cuối chuỗi dest float f;
char *str = "12345.67";

f = atof(str);
printf("string = %s float = %f\n", str, f);
...

Lập trình C - Việt Nhật 2007 251 Lập trình C - Việt Nhật 2007 252

63
Nhập/xuất chuỗi Chuỗi ký tự với tư cách tham số hàm
„ gets: lấy chuỗi ký tự từ thiết bị nhập chuẩn stdin „ Khi làm tham số hình thức, xâu được khai báo
puts: đưa chuỗi ký tự ra thiết bị xuất chuẩn stdout
dưới dạng
char *gets(char *s); char* hoặc char[]
int puts(const char *s); ‰ Ví dụ:
void Greet ( char* name )
void Greet ( char name[] )
„ vd:
1. char string[80];
„ Những thay đổi xâu trong hàm sẽ có tác động
2. printf("Input a string:"); toàn cục.
3. gets(string);
4. printf("The string input was: %s\n", string);
5. puts(string);
Lập trình C - Việt Nhật 2007 253 Lập trình C - Việt Nhật 2007 254

Ví dụ
#include <stdio.h>
#include <stdio.h>
#include <string.h> int main()
#include <string.h> int main()
#define NAMELEN 50 {
#define NAMELEN 50 {
char user[NAMELEN];
char user[NAMELEN];
/* Hien thi loi chao don gian */
/* Hien thi loi chao den nguoi dung */
printf("Who are you? ");
printf("Who are you? ");
void Greet ( char * name ) scanf("%s", user);
void Greet ( char * name ) scanf("%s", user);
{ Greet(user);
{ Greet(user);
strcat(name, "! How are ya?"); printf("%s\n", user);
strcat(name, "! How are ya?"); printf("%s\n", user);
}
}
return 0;
return 0;
}
}

name user
user

Jake\0 Jake\0
Lập trình C - Việt Nhật 2007 255 Lập trình C - Việt Nhật 2007 256

64
#include <stdio.h> #include <stdio.h>
#include <string.h> int main() #include <string.h> int main()
#define NAMELEN 50 { #define NAMELEN 50 {
char user[NAMELEN]; char user[NAMELEN];
/* Print a simple greeting to /* Print a simple greeting to
the user */ printf("Who are you? "); the user */ printf("Who are you? ");
scanf("%s", user); scanf("%s", user);
void Greet ( char * name ) Greet(user); void Greet ( char * name ) Greet(user);
{ printf("%s\n", user); { printf("%s\n", user);
strcat(name, "! How are ya?"); strcat(name, "! How are ya?");
} return 0; } return 0;
} }

name user user

Jake! How are ya?\0 Jake! How are ya?\0


Lập trình C - Việt Nhật 2007 257 Lập trình C - Việt Nhật 2007 258

Mảng các chuỗi: char * [ ] Kiểu liệt kê (enumerated type)


„ char *Words[ ] = {“hong”, “cuc”, “lan”, “nhai”,”mo”}; „ Kiểu liệt kê khai báo một tập các hằng số theo thứ tự.
„
Words
Words[0] Words[1] Words[2] Words[3] Words[4]
„ Nếu không có khai báo rõ ràng, các hằng bắt đầu từ giá trị 0.

enum NgayTrongTuan {Hai, Ba, Tu, Nam, Sau, Bay, CN};

enum NgayTrongTuan ngay;


ngay = Hai; // 0

h o n g \0 c u c \0 l a n \0 n h a i \0 m o \0 „ Khai báo giá trị khác cho các hằng.

enum Month {Jan = 1, Feb = 2, Mar, Apr, Jun, July};

Lập trình C - Việt Nhật 2007 259 Lập trình C - Việt Nhật 2007 260

65
Khái niệm và định nghĩa
¾ Trong thực tế lập trình, chúng ta có thể sẽ cần đến những
Ngôn ngữ lập trình C kiểu dữ liệu phức tạp hơn được tạo thành từ những kiểu dữ
liệu đơn giản mà chúng ta đã biết.
¾ Mảng lưu giữ các phần tử cùng kiểu
¾ Có những lúc ta muốn lưu giữ đồng thời các dữ liệu khác
kiểu.
¾ Ví dụ:
KIỂU CẤU TRÚC (STRUCTURE) ¾ Tiêu đề, tên nghệ sỹ, giá bán của các CD trong cửa hàng
¾ Tên người và số điện thoại
¾ Tên học sinh, ID, và điểm số….
Cao Tuấn Dũng
¾ Cấu trúc là một kiểu dữ liệu bao gồm nhiều thành phần có thể
2007
thuộc nhiều kiểu dữ liệu khác nhau. Các thành phần được
truy nhập thông qua tên.

Lập trình C - Việt Nhật 2007 262

Cấu trúc (structure) Khai báo kiểu cấu trúc


„ Trong C, một cấu trúc được biết đến với từ khóa struct
„ Cấu trúc chứa một số các thành phần (trường) xác định, có thể có struct Ban Mọi cấu trúc
kiểu khác nhau. { phải có tên
char ten[DODAI];
long dienthoai;
„ Khai báo: char diachi[KICHTHUOC]; Các thành phần
}; của cấu trúc là
struct Tên cấu trúc
{ các thành viên
tên kiểu tên trường_1 ;
tên kiểu tên trường_2 ;
tên kiểu tên trường_3 ; Đây mới chỉ định
<< ... >> nghĩa kiểu cấu trúc,
}; chưa khai báo biến

Lập trình C - Việt Nhật 2007 263 Lập trình C - Việt Nhật 2007 264

66
Định nghĩa kiểu bằng typedef Định nghĩa cấu trúc bằng typedef
typedef kiểu_đã_có tên_kiểu_mới; typedef struct
{
„ trong đó : tên kiểu tên trường_1 ;
tên kiểu tên trường_2 ;
‰ kiểu_đã_có là kiểu dữ liệu mà ta muốn đổi tên. tên kiểu tên trường_3 ;
‰ tên_kiểu_mới là tên mới mà ta muốn đặt. << ... >>
} tên kiểu cấu trúc ;
„ Xét câu lệnh sau
typedef unsigned char byte; typedef struct {
char ho_ten[20];
„ sau câu lệnh này, byte được xem như là kiểu dữ liệu float diem;
tương đương với unsigned char và có thể được sử dụng } hoc_sinh;
trong các khai báo biến như các kiểu dữ liệu khác.
typedef struct
{
char ten[DODAI];
long dienthoai;
char diachi[KICHTHUOC];
} Ban;

Lập trình C - Việt Nhật 2007 265 Lập trình C - Việt Nhật 2007 266

Định nghĩa Cấu trúc Kích thước của một cấu trúc
1. struct SinhVien „ Kích thước kiểu dữ liệu cấu trúc:
2. {
3. char *hoten;// toi da 30 ky tu sizeof(<<typename>>)
4. int namsinh; // >= 1960
„ vd:
5. char *noisinh; // 3 chu cai viet tat cua noi sinh
6. char *maso; // maso dai toi da 10 ky tu SinhVien_t_size = sizeof(SinhVien); // 48
7. };

8. // khai bao kieu SinhVien


9. typedef struct SinhVien SinhVien;

Lập trình C - Việt Nhật 2007 267 Lập trình C - Việt Nhật 2007 268

67
Khai báo biến cấu trúc Khai báo biến cấu trúc (tt)
Khai báo biến cùng định nghĩa cấu trúc 1. struct SinhVien
struct hoc_sinh { 2. {
char ho_ten[20]; 3. char hoten[31]; // toi da 30 ky tu
float diem;
4. int namsinh; // >= 1960
} hs,dshs[100];
5. char noisinh[4];// 3 chu cai viet tat cua noi sinh
Khai báo sau khi định nghĩa kiểu bằng từ khóa struct
struct hoc_sinh VietNhat101, dssv[50]; 6. char maso[11]; // maso dai toi da 10 ky tu
7. } X, Y, Z;
Khai báo biến cùng định nghĩa typedef
typedef struct { 8. Khởi tạo
char ho_ten[20]; 9. struct SinhVien NguyenLe = (“Nguyen Le”, 1983, “HU”,
float diem; “301160123”);
} hoc_sinh;
Khai báo biến sau định nghĩa kiểu bằng từ khóa typedef 10. Z = NguyenLe;
hoc_sinh hs,*ptr_hocsinh;

Lập trình C - Việt Nhật 2007 269 Lập trình C - Việt Nhật 2007 270

Chú ý Truy cập thành phần trong Cấu trúc

„ Khi khai báo biến cấu trúc, nếu „ Toán tử thành viên: .
X.hoten // “Nguyen Van X”
X.namsinh // 1983
‰ khai báo nhiều giá trị khởi tạo hơn số trường của kiểu
dữ liệu Æ sai. gets(X.hoten);
scanf(“%d %s %s”, &X.namsinh, X.noisinh,
X.maso);
‰ khai báo giá trị khởi tạo cho một số trường trong cấu „ Có thể thực hiện phép gán biến cấu trúc này sang biến cấu
trúc, các trường còn lại sẽ tự động được gán giá trị 0. trúc khác.
X = NguyenLe;
Thực chất đây là phép gán từng bit.

„ Tuy nhiên với các cấu trúc có mảng ở trong, nên dùng cách
chép từng thành phần.

Lập trình C - Việt Nhật 2007 271 Lập trình C - Việt Nhật 2007 272

68
Truy cập qua con trỏ Truy cập thành phần cấu trúc
„ Khai báo con trỏ đến cấu trúc tương tự như các kiểu dữ liệu struct friendStr
khác. {
char name[MAXNAME];
long int phoneNumber;
SinhVien *SV_ptr;
char street[MAXSTREET];
};
„ Với một con trỏ, các thành phần của cấu trúc có thể được struct friendStr sarah;
truy nhập thông qua toán tử -> Hoặc
„ SV_ptr->namsinh = 1988; sarah.phoneNumber = 55559999;
strcpy(sarah.name,"Sarah Finch");
„ strcpy(SV_ptr->noisinh, "Ha noi");
strcpy(sarah.street,"Firthsmith St");
Hoặc
scanf("%s",sarah.name);
scanf("%ld",&sarah.phoneNumber);
scanf("%s",sarah.street);

Lập trình C - Việt Nhật 2007 273 Lập trình C - Việt Nhật 2007 274

Ví dụ
#include <stdio.h>
Chú ý
#define MAXLEN 50
struct Sinhvien
{ „ Không dùng phép so sánh == với hai cấu trúc
char ten[MAXLEN];
float diem; „ Chúng ta chỉ có thể so sánh các thành phần của cấu trúc
};

int main() if (svA == svB)


{
struct Sinhvien svA;
{
struct Sinhvien svB; printf(“Trung lap du lieu.\n”);
printf("Nhap ten va diem cho sinh vien A: "); }
scanf("%s %f", svA.ten, &(svA.diem));
printf("Nhap ten va diem cho sinh vien B: ");
scanf("%s %f", svB.ten, &(svB.diem)); if (strcmp(svA.ten, svB.ten) == 0
printf("Sinh vien A: %s\t%f\n", svA.ten, svA.diem);
&& (svA.diem == svB.diem) )
printf("Sinh vien B: %s\t%f\n", svB.ten, svB.diem); {
return 0; printf(“Trung lap du lieu.\n”);
} }
Lập trình C - Việt Nhật 2007 275 Lập trình C - Việt Nhật 2007 276

69
Truyền cấu trúc như là tham số Truyền bằng tham trị
„ Như một biến bình thường biến cấu trúc có thể
được truyền bằng:
void hienthiCautruc ( Sinhvien sv )
‰ - tham trị: Không làm thay đổi cấu trúc {
printf("Ten\t: %s\n", sv.ten);
printf("Diem\t: %.1f\n\n", sv.diem);
}
‰ - tham biến thông qua con trỏ: thay đổi nội
dung cấu trúc main()
{
Sinhvien svA = {“Dao Xuan Vu”, 9.0};
„ Truy nhập nội dung: (*sptr).item
hienthiCautruc(svA);
„ Đọc qua địa chỉ: &((*sptr).item)
}
Lập trình C - Việt Nhật 2007 277 Lập trình C - Việt Nhật 2007 278

Truyền bằng tham chiếu Mảng các Cấu trúc


„ Khai bao biến mảng các Cấu trúc cũng giống như khai báo biến
void nhapThongtin ( Sinhvien* sptr ) mảng trên các kiểu dữ liệu cơ bản khác.
{
printf(“Nhap ten va ID:\n”); „ Dùng tên mảng khi truy cập từng phần tử trong mảng các cấu trúc
và toán tử thành viên để truy cập các trường dữ liệu của từng thành
scanf(“%s”, (*sptr).ten ); /*chu y ngoac*/ phần cấu trúc.
scanf(“%ld”, &((*sptr).id) );
} struct Sinhvien {
char ten[20];
char ID[5];
int main() float diem;
{ } dssv[100];
Sinhvien svA;
nhapThongtin(&svA); dssv[0].ten
} dssv[i].id

Lập trình C - Việt Nhật 2007 279 Lập trình C - Việt Nhật 2007 280

70
Mảng cấu trúc
#include <stdio.h>
#include <stdlib.h>

#define MAXLEN 50
dssv #define MAXN 20
id:VN006 dssv[0]chỉ đến typedef struct {
0 char ten[MAXLEN];
toàn thể struct float diem;
name: "Mai"
} Sinhvien;

id:VN101 Sinhvien readRecord ( void )


1 {
name: "Thuy" Sinhvien svmoi;
printf("Nhap ten va diem: ");
scanf("%s %f", sv.ten, &(sv.diem));
id: VN033 return svmoi;
2 }
name: "Phong" void printRecord ( Sinhvien sv )
{
dssv[3].name cho ta printf(" Ten: %s\n", sv.ten);
id: VN087
3 thành phần của struct printf("Diem: %.1f\n\n", sv.diem);
return;
name: "Linh" }
Lập trình C - Việt Nhật 2007 281 Lập trình C - Việt Nhật 2007 282

Union
int main()
{
int count = 0;
Sinhvien dssv[MAXN];
int i; „ Khai báo union được dùng để khai báo các biến dùng chung
printf("Co bao nhieu sinh vien? ");
scanf("%d", &count); bộ nhớ.
if (count > MAXN)
{ union int_or_long {
printf("Khong du bo nho luu tru.\n");
exit(1); int i;
} long l;
for (i=0; i < count; i++)
} a_number;
{
dssv[i] = readRecord(); „ Các thành phần của union có thể không có kích thước bằng
}
printf("\nDanh sach lop:\n\n"); nhau.
for (i=0; i < count; i++)
{
printRecord(dssv[i]); „ Kích thước bộ nhớ trong khai báo union là kích thước của
} kiểu dữ liệu lớn nhất có trong khai báo union.
return 0;
}
Lập trình C - Việt Nhật 2007 283 Lập trình C - Việt Nhật 2007 284

71
Ví dụ
1. union int_or_long {
2.

3.
int
long
i;
l; Ngôn ngữ lập trình C
4. } a_number;
5. a_number.i = 5;
6. a_number.l = 100L;

7. // anonymous union
8. union { TẬP TIN (FILE)
9. int i;
10. float f;
11. }; Cao Tuấn Dũng
12. i = 10; 2007
13. f = 2.2;

Lập trình C - Việt Nhật 2007 285

72

You might also like