[c] giao trinh c dhbk - viet nhat

72
1 Ngôn nglp trình C Chương 1: Gii thiu chung Cao TunDũng 2007 Lp trình C - Vit Nht 2007 2 Tài liu tham kho The C Programming Language (2nd Edition) Kernighan & Ritchie Prentice Hall 1988. Ngôn NgLp Trình C. Quách Tun Ngc. Nhà XutBn Giáo Dc, 1998. Efficient C programming. Mark Allen Weiss. Prentice Hall, 1998. Kthutlp trình C, cơ svà nâng cao. PhmVăn t. Nhà Xut Bn Khoa Hc & KThut. Lp trình C - Vit Nht 2007 3 Mtskhái nim Computer program –chương trình máy tính là mttp các câu lnh (instruction) hướng dn máy tính làm mtsvic nht định. Programming language - Ngôn nglp trình là ngôn ngữ để viết chương trình. Có nhiu loi ngôn nglp trình. Compiler – trình biên dch, là phnmm chu trách nhimdch chương trình viếtbng mt ngôn nglp trình sang dng mã máy. Lp trình C - Vit Nht 2007 4 MACHINE CODE ASSEMBLER LANGUAGES HIGH-LEVEL LANGUAGES ForTran, COBOL, C, C++, LISP, Pascal, Java, ... 4GLs ORACLE, SEQUEL, INGRES, ... 5GLs artificial intelligence Các lp Ngôn nglp trình

Upload: hoang-nguyen

Post on 27-May-2015

235 views

Category:

Documents


8 download

TRANSCRIPT

Page 1: [C] giao trinh c   dhbk - viet nhat

1

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

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

Cao Tuấn Dũng2007

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

Tài liệu tham khảoThe C Programming Language (2nd Edition) Kernighan & Ritchie 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ấtBản Khoa Học & Kỹ Thuật.

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

Một số khái niệmComputer program –chương trình máy tính là một tập các câulệnh (instruction) hướng dẫn máy tính làm một số việc nhấtđịnh.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.Compiler – trình biên dịch, là phần mềm chịu trách nhiệm dịchchương trình viết bằng một ngôn ngữ lập trình sang dạng mãmáy.

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

MACHINE CODE

ASSEMBLER LANGUAGES

HIGH-LEVEL LANGUAGES

ForTran, COBOL, C, C++,LISP, Pascal, Java, ...

4GLs ORACLE, SEQUEL, INGRES, ...

5GLs artificial intelligence

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

Page 2: [C] giao trinh c   dhbk - viet nhat

2

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

Thuật toán - AlgorithmTập các lệnh được tổ chức có thứ tự nhằm giải quyết một bàitoán hoặc đạt đến một mục tiêu nào đó.Ví dụ:

hướng dẫn chế biến một món ăn,hướng dẫn sửa chữa xe máy,cách giải một bài toán.…

Algorithm –Thuật toán - Thuật giải

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

Thuật giải tốtMột thuật giải tốt là thuật giải:

chính xácrõ ràngđúnghiệu quảvà có thể bảo trì được.

Chúng ta có thể viết một thuật giải cho máy tính bằng ngônngữ 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 7

Tính điểm trung bình môn họcNhập: điểm thực hành Vật Lý, điểm bài tập, điểm bài kiểm tragiữa học kỳ, điểm bài kiểm tra cuối học kỳ.

Điểm hệ sốThực hành : 8 2bài tập: 9 2KT giữa kỳ: 8 4KT cuối kỳ: 8 6

Tổng cộng: TONG = 8*2 + 9*2 + 8*4 + 8*6Điểm trung bình: TB = TONG/(2+2+4+6)

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

Sơ đồ xử lýSử dụng sơ đồ xử lý để minh họa quá trình xử lý một chươngtrình.

start,stop

condition expression

process

data

flow

Bài tập: dùng sơ đồ để biểu diễn bài toán nhập và tính điểmtrung bình.

Page 3: [C] giao trinh c   dhbk - viet nhat

3

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

Ngôn ngữ C - Lịch sử phát triểnC được ra đời tại Bell Lab vào 1972, cha đẻ là Dennis Ritchie.

C và mối liên hệ với hệ điều hành Unix

Kernighan và Ritchie đưa ra phiên bản C chuẩn đầu tiên năm1978.

ANSI C - C được chuẩn hóa vào năm 1989 bởi American National Standards Institute.

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

Ngôn ngữ C – Đặc điểm chínhTí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.

Linh hoạt và mạnhBản thân ngôn ngữ không đặt ra giới hạn đối với người lập trìnhCá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ấpTính khả chuyển cao

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 11

Ngôn ngữ lập trình Ccó thể đọc và viết mã chương trình trên hầu hết các hệ thống.chuyển lên C++ và có thể viết các kịch bản CGI (CGI script) cho các Website.C là ngôn ngữ biên dịch (complied language).

Viết chương trình bằng ngôn ngữ C bằngcác chương trình soạn thảo (emacs, vi, các công cụ viết chương trình)

Không dùng các chương trình soạn thảovăn bản (vd:Word, WordPad)

Hello

C

Compiler

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

Cấu trúc một chương trình CKhai báo tệp tiêu đề

#include <stdio.h>#include <math.h>

Khai báo các cấu trúc, biến, hàm có sử dụng đến

Hàm chính main()- Điểm bắt đầu của chươngtrình- Chỉ có duy nhất- Từ hàm main thường gọiđến các chương trình con (hàm) khác.

1 /* Fig. 2.1: fig02_01.c2 A first program in C */3 #include <stdio.h>45 int main()6 {7 printf( "Welcome to C!\n" );89 return 0;10 }

- Các chú thích nằm trong /*….*/- Câu lệnh kết thúc bằng dấu ;- { } mở và đóng một khối lệnh

Page 4: [C] giao trinh c   dhbk - viet nhat

4

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

Giới thiệu chung về LinuxLinux là phiên bản phát triển có mã nguồn mở của hệ điềuhành Unix Linux ban đầu được tạo ra bởi Linus Toward, năm 1991Trên góc độ kỹ thuật, tên gọi Linux chỉ tương ứng với nhâncủa hệ điều hành (kernel), cung cấp các dịch vụ truy nhậpquản lý tài nguyên phần cứng cho người sử dụng và cácchương trình ứng dụngCác bản phân phối Linux: RedHat, SuSE, Debian, Mandrake.Linux kế thừa các ưu điểm của dòng hệ điều hành Unix: môitrường đa người dùng, đa nhiệm, chạy trên nhiều platform khác nhau.Linux có thể chạy tốt trên nhưng hệ thống cấu hình rất thấpnhư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 14

Hệ thống file trên LinuxTrong Linux, các tập tin được

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 phân biệt chữ hoa, chữthường đối với tên file

Mỗi người sử dụng khi đượctạo tài khoản sẽ có một thư mục, gọi là thư mục home. Ký hiệu ~. Thông thường người dùnguserid sẽ có thư mục home là/home/userid

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

Một số lệnh cần thiếtĐổi mật khẩu tài khoản: passwdHiện đường dẫn tới thư mục hiện hành: pwdLiệt kê danh sách các file trong thư mục: ls tên_thư_mục

ls –l examples xem nội dung thư mục con examples của thư mục hiệnhành theo từng trang.

Tạo thư mục : mkdir tên_thư_mục

Chuyển tới thư mục mới : cd đường_dẫn

Xem nội dung file: cat tên_fileXóa một thư mục hay file: rmSao chép file: cp nguồn đích

Xem hướng dẫn sử dụng một lệnh:man tên_lệnh. Ví dụ man mvlệnh --help

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 16

Trình soạn thảo emacsLinux tồn tại sẵn một số lệnh soạn thảo tập tin văn bản nhưlệnh vi. emacs (editor macros): trình soạn thảo văn bản đa chứcnăng. Hai phiên bản phổ biến: GNU emacs và xemacsDùng ngôn ngữ emacs lisp với khả năng mở rộng: soạn thảo, căn lề, nhận biết tag, gọi chương trình dịch, thậm chí duyệtWeb.emacs cho phép làm việc trên nhiều cửa sổ và bộ đệm. Nộidung soạn thảo không ghi trực tiếp vào file mà ghi lên bộđệm.emacs làm việc theo lệnh. Người sử dụng gõ lệnh trên cửa sổlệnh để tác động lên nội dung trong bộ đệm

Page 5: [C] giao trinh c   dhbk - viet nhat

5

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

Các lệnh cơ bản trong emacsQuy ước:

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

Trở về trạng thái chờ lệnh: C-gThao tác với file:

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.Lưu nội dung bộ đệm vào file: C-x C-s Lưu với tên khác: C-x C-w tên

Di chuyển con trỏSử dụng các phím mũi tênLên dòng trên C-p, xuống dòng dưới C-nPhía trước một ký tự C-b, sau một ký tự C-fVề đầu dòng C-a, về cuối dòng C-e

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

Các lệnh trong emacs (tiếp)Di chuyển con trỏ theo từ:

Về sau: M-f. Về trước M-bTheo câu: Chú ý emacs phân biệt câu với dòng.

Về đầu : M-a, về cuối câu: M-e. Theo bộ đệm: Về đầu: M-v. Về cuối: C-vThao tác soạn thảo, cắt dán

Xóa ký tự: Del hoặc C-dXóa từ con trỏ đến hết từ: M-d. Xóa từ con trỏ đến hết dòng: C-kXóa một dòng: C-a C-kChọn tất cả: C-x h. Undo : C-x uM-w: copy vùng được đánh dấu. 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 19

Các lệnh trong EmacsTìm kiếm trong văn bản:

Tìm xuôi chiều C-s từ_cần_tìmTìm ngược chiều C-r từ_cần_tìm

Soạn thảo trên nhiều cửa sổCho phép theo dõi nội dung ở những phần khác nhau của fileC-x-2 Chia hai cửa sổ theo chiều ngangC-x-3 Chia hai cửa sổ theo chiều dọcC-x-0 di chuyển giữa hai cửa sổC-x-1 Xóa tất cả các cửa sổ và về lại cửa sổ đầu tiên

Thoát khỏi EmacsC-x-c

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

Biên dịch chương trình C trên Linux

Hầu hết các bản phân phối của Linux đều tích hợp với trìnhbiên dịch ngôn ngữ C: gcc.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, sau đó liên kết mã đối tượng để tạo ra tập tin thực thiNếu không chỉ định tên tập tin thực thi, mặc định kết quả sẽ làa.outCác tham số biên dịch

-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-o: chỉ định tên file thực thi mong muốn-g: thêm thông tin gỡ rối (debug)-l: chỉ định thư viện liên kết.

gcc –Wall hello.c –o runhello./runhello

Page 6: [C] giao trinh c   dhbk - viet nhat

6

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

Biên dịch chương trình C trên Linux

Các tập tin makefile cho phép:Tạo các script biên dịch, tiết kiệm thời gian gõ lệnhTiết kiệm thời gian biên dịch vì chỉ dịch lại những tập tin có thayđổiRất phức tạp và dễ gây lỗi.

Có thể sử dụng lạiEXEC_NAME = helloWorldall: main.o

gcc –g –o $(EXEC_NAME) main.omain.o: main.c

gcc –g –c main.c –o main.oclean:

rm –rf main.o $(EXEC_NAME)

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

Một số lỗi thường gặp khi biên dịchSegfaults

Khi có lỗi truy nhập bộ nhớ. Ví dụ: cố gắng truy nhập thông tin từmột con trỏ NULL.

Linker errorsLỗi trong dòng lệnh gcc hay makefile

Multiple definitions of functionsĐịnh nghĩa sai trong cái chỉ thị tiền xử lý trong tập tin header như: #ifndef, #define

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

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

Cao Tuấn Dũng2007

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

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

1. #include <stdio.h>2.

3. int main()4. {5. printf(“Hello\n");6. return 0;7. }

Page 7: [C] giao trinh c   dhbk - viet nhat

7

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

Chương trình C#include <stdio.h>

khai báo sử dụng thư viện xuất/nhập chuẩn (standard I/O library). Các thư viện khác: string, time, math…

int main()khai báo hàm main(). Chương trình C phải khai báo (duy nhất) 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().

{ … }mở và đóng một khối mã.

printfhàm printf() gửi kết xuất ra thiết bị xuất chuẩn (màn hình). Phầnnằm giữa “…“ gọi là chuỗi định dạng kết xuất (format string)

return 0;ngừng chương trình. Mã lỗi 0 (error code 0) – không có lỗi khichạy chương trình.

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

Mở rộng 11. #include <stdio.h>2.

3. int main()4. {5. int a, b, c;6. a = 5;7. b = 7;8. c = a + b;9. printf(“%d + %d = %d\n“, a, b, c);10. return 0;11. }

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

Tên (Định danh)Tên dùng để xác định các đối tượng khác nhau trong chươngtrìnhTên biến, tên hàm, tên hằng, tên nhãn.Quy tắc đặt tên:

Bao gồm các chữ cái, chữ số, dấu gạch dướiKhông được bắt đầu bằng chữ sốPhân biệt chữ hoa chữ thường.Không trùng với các từ khóa.

Tên đúng: sothu_3, tigiack

Tên sai:x^2, y-2, 23ant

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

Biến (variable)Biến tương ứng với một vùng trống nào đó trong bộ nhớ máy tínhdùng để giữ các giá trị. Là đại lượng mà giá trị của nó có thể thay đổi trongquá trình tính toá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ó

Khai báo: <type> <var-name>;

ví dụ:int b;float m_1, m_2;Gán giá trị vào biến: <var-name> = <value>;

vd: b = 5;

Sử dụng biến:

printf(“%d + %d = %d\n“, a, b, c);

Biếnnguyên 45

Page 8: [C] giao trinh c   dhbk - viet nhat

8

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

Mở rộng 21. #include <stdio.h>2.

3. int main()4. {5. int a, b, c;6. printf(“Nhap so thu nhat: “);7. scanf(“%d”, &a);8. printf(“Nhap so thu hai: “);9. scanf(“%d”, &b);10. c = a + b;11. printf(“%d + %d = %d\n“, a, b, c);12. return 0;13. }

Nhap so thu nhat:

Nhap so thu hai:

5 + 7 = 12

5

7

5712

abc

/ngonnguC/bin/tong

/ngonnguC/bin/

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

Chú ýC phân biệt chữ hoa/chữ thường do đó phải viết đúng tênlệnh.vd: printf chứ không phải là Printf, pRintf, PRINTF.

Trong câu lệnh scanf() để lấy giá trị vào biến, phải luôn dùngdấu & trước tên biến.

Khi gọi các hàm phải khai báo các tham số đúng vị trí và đầyđủ.

Phải khai báo biến trước khi sử dụng trong chương trình.

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

Các kiểu dữ liệu cơ bảnCharacter: char (ký tự 1-byte)Integer: int (các giá trị nguyên 2-byte)

-32768 đến 32767Số nguyên không dấu: unsigned int

0 đến 65535Số phẩy động độ chính xác đơn: float (các giá trị dấu chấmđộng 4-byte)

(+,-)3.4E-38 , (+,-)3.4E+38 Số phẩy động độ chính xác kép: double (dấu chấm động 8-byte)

(+,-)3.4E-308 , (+,-)3.4E+308

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

Biến và hằng sốBiến số (variable) được dùng để giữ các giá trị và có thể thayđổi các giá trị mà biến đang giữ

Khai báo: <typename> varname;Vd:

int i;float x, y, z;char c;

Gán giá trị cho biến: <varname> = <value>;vd:

i = 4;x = 5.4;y = z = 1.2;

Page 9: [C] giao trinh c   dhbk - viet nhat

9

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

Hằng sốHằng số (constant) giá trị không thay đổi trong quá trình sửdụng.Khai báo hằng:#define <constantname> <value>

vd:#define TRUE 1#define FALSE 0Giá trị hằng

Hằng nguyên: 3423, 0x48 = 4*16+8=72Hằng dấu phẩy động: -231.292, 123.456E-4Hằng ký tự: ‘a’, ‘b’‘9’ – ‘0’ = 57 – 48 = 9

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

Kiểu và chuyển kiểu (typecasting)C cho phép chuyển đổi kiểu dữ liệu cơ bản trong khi đangtính toán (chuyển kiểu tường minh).ví dụ:void main() {

float a;int b;b = 10/3;a = (float)10/3;printf(“a = %f \n b = %d\n”, a, b);

}

Chuyển kiểu tự động: khi biểu thức gồm hai toán hạng kháckiể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 35

Định nghĩa kiểu (typedef)Có thể định nghĩa các kiểu riêng bằng lệnh typedef.

vd:#define TRUE 1#define FALSE 0typedef int boolean;

void main() {boolean b;b = FALSE;/*...*/}

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

Các Toán tử

right to left= *= /= %= += -= &= |= ^= <<= >>=

Assignment14

13

12

11

10

9

8

7

6

5

4

3

2

2

1

0

Priority

Conditional operator

Logical OR

Logical AND

Boolean OR

Boolean XOR

Boolean AND

Equality

Relational

Shift

Additive

Multiplicative

Type cast

Prefix and unary

Postfix

Primary expression

Category

Right to left?

left to right||

left to right&&

left to right|

left to right^

left to right&

left to right== !=

left to right< <= > >=

left to right<< >>

left to right+ -

left to right* / %

right to left( typeName )

right to left! ~ + - ++ -- & sizeof

left to rightFunction() () [] ->

Noneidentifiers constants

AssociativityExample

Page 10: [C] giao trinh c   dhbk - viet nhat

10

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

Các toán tử so sánh và toán tử logic

15

7

5

7

0

X | Y

1

1

1

0

0

!Y

0

0

0

1

1

!X

1

1

1

1

0

X || Y

7

7

0

7

0

Y

0

0

0

X>>Y

32

48

24

X<<Y

0

0

1

X == Y

1

1

0

X != Y

1

0

1

X >= Y

1

0

0

X > Y

0

1

1

X <= Y

3

4

3

Y

018

515

005

000

000

X & YX && YX

Possible MistakesLogical Operators

304

413

303

X=YX < YX

Possible MistakesRelational and Quality Operators

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

Số nhị phânHệ đếm thập phân:

5426=5*103 + 4*102 + 2*101 + 6*100

254,68 = 2*102 + 5*101 + 4*100 + 6*10-1 + 8*10-2

Hệ đếm nhị phân (cơ số hai): Hệ chỉ có hai chữ số 0 và 1.1000 10112 = 1*27 + 0*26 + 0*25 + 0*24 + 1*23 + 0*22 + 1*21 + 1*20 = 27 + 23 + 21 + 20 = 1391011.012 = 1*23 + 0*22 + 1*21 + 1*20 + 0*2-1 + 1*2-2 = 11.25

Một chữ số nhị phân – BIT – là đơn vị lưu trữ thông tin nhỏ nhấtcủa máy tính.

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

Các phép toán số học+ - / * %: phép chia lấy phần dư trong số nguyên. (modulo).i = i + 1; i++; ++i;i = i – 1; i--; --i;i = i + 3; i += 3;i = i * j; i *= j;Phép chia kiểu nguyên: 7/5 cho kết quả 1.Phép lấy phần dư: 7 % 5 cho kết quả 2.Thứ tự ưu tiên:

Toán tử Tên gọi Thứ tự tính toán (precedence) () Ngoặc tròn Được ưu tiên nhất. Tính giá trị đầu tiên trong một biểu thức

*, /, or % Nhân, chia, lấy phần dư

Độ ưu tiên thứ hai, nếu cùng tồn tại thì được thực hiện từ trái qua phải

+ or - Cộng, trừ Độ ưu tiên thấp nhất

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

Toán tử tăng giảmCó thể viết i=i+1; (i=i-1;) dưới dạng

i++; ( i--; )hay ++i ( --i; )

Sự khác nhau giữa tiền tố và hậu tối++, giá trị của i tham gia vào việc lượng giá biểu thức chứa nótrước khi tăng.++I, giá trị của i tăng, sau đó giá trị mới có hiệu lực khi lượng giábiểu thức chứa nó.

Ví dụ: Với i= 4j = ++i +10; cho j bằng 15 và j= i++ +10; cho j=14.

int i= 6;printf ("%d\n",i++); /* Prints 6 sets i to 7 */int i= 6;printf ("%d\n",++i); /* prints 7 and sets i to 7 */

Page 11: [C] giao trinh c   dhbk - viet nhat

11

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

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ũng2007

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

Dòng vào, ra chuẩnViệc nhập dữ liệu được thực hiện thông qua dòng vào chuẩn stdin (bàn phím)

Khi có dữ liệu trên dòng vào chuẩn, các hàmnhận dữ liệu như scanf, getchar sẽ lấy phần dữliệu mà nó yêu cầuKhi dòng vào không đủ dữ liệu: máy chờ ngườidùng

Dòng ra chuẩn: màn hìnhCác hàm xuất dữ liệu

Printf, putcharThư viện vào ra chuẩn: stdio.h

a 12 1.4

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

Hàm printfint printf (char* địnhdạng, [danh sách đối,….]Vd: printf(“Gia tri ham tai toa do %d,%d la %f”, 2,3, 1.09);Dạng tổng quát của đặc tả chuyển dạng

%[-] [width][.prec] ký tự chuyển dạngwidth: dãy số nguyên xác định độ rộng tối thiểu của giá trị hiển thị.prec: dùng cho kiểu float, double

Đối số nguyên không dấuunsigned intu

Đối số là xâu ký tựchar *sĐối số là số dấu phẩy tĩnhfloat, doublefĐối số là số nguyên lớnlongldĐối số là số nguyên có dấuintdĐối số là một ký tựcharcÝ nghĩaKiểu giá trị của đối sốKý tự chuyển dạng

Page 12: [C] giao trinh c   dhbk - viet nhat

12

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

Hàm printfKhi không có mặt dấu trừ: kết quả dồn về bên phải. Ngược lại, kếtquả dồn về bên tráiKý tự chuyển dạng bắt đầu = 0, nếu độ dài của đối số nhỏ hơnwidth thì kết quả sẽ điền các ký tự 0 vào bên trái.Ví dụ: int i = -124;

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

"-0124"printf("%05d", i);

" -124"printf("%5d", i);"-124"printf("%-05d", i);

"-124 "Kết quả

printf("%-5d", i);Lệnh

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

Ký tự EscapeĐánh dấu các ký tự đặc biệt: \’, \”, \n, \t, \r, \\, \0Dùng trong hàm printf để định dạng dòng ra

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

Hàm scanfCó một số đặc điểm tương tự printf nhưng theo chiều ngược lại: đọc thông tin từ dòng vào.Cú pháp: int scanf(char *định_dạng, [danhsachdiachi]);

Trả về giá trị EOF nếu có lỗi.Xâu định dạng có cú pháp: %[*][width]kýtựchuyểndạng

int a;float x, y;char ch[6], ct[6];scanf("%f%5f%3d%3s%s", &x, &y,&a, ch, ct);

54.32e-1 25 12357287a

x = 5.432y=25.0a=123

ch="572"ct="87a

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

Một số hàm nhập xuất khácgetchar: Nhập một ký tự từ dòng vào:int getchar();

int c;c = getchar();

putcharputchar(int c);

fflush(stdin): Làm sạch dòng vào.

Nhập xuất xâu:char *gets(char *s) nhận dữ liệu cho đến khi gặp '\n'

char ten[30];int t;printf( "\nTuoi:");scanf("%d",&t);fflush(stdin); /* xoá mọi ký tự ở dòng vào */printf( "\nTen:");scanf("%s",ten);

Page 13: [C] giao trinh c   dhbk - viet nhat

13

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

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

Cao Tuấn Dũng2007

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

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

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

expression

statement(s)

Next statement

True False

Một quyết định có thểđược đưa ra dựa trên bấtcứ một biểu thức nào.

0 - false

khác 0 - true

Ví dụ:

3 - 4 - true

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

Ví dụ1. #include <stdio.h>

2. int main() { 3. int b;

4. printf("Enter a value:"); 5. scanf("%d", &b); 6. if (b < 0) 7. printf("The value \

is negative\n"); 8. return 0; 9. }

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

Ví dụ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 )

printf( "Vuot qua ky thi\n" );

true

false

diemthi >= 5 print “Qua”

Page 14: [C] giao trinh c   dhbk - viet nhat

14

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

if … else …if (<dieu kien>)

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

else{ /* cac lenh thuc hien neu dieu kien sai */ }

… expression

statement1

Next statement

True False

statement2

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

Ví dụ…printf(“1/X is: “);if(X)

printf(“ %f \n”, 1/X);else

printf(“ undefined \n”);…

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

Ví dụ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 nếu không thì sinh viên thi trượt.Mã chương trình C: if ( diemthi >= 5 )

printf( "Vuot qua ky thi\n" );else printf( "Truot\n" );

truefalse

print “Truot” print “Qua”

diemthi >= 5

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

Lỗi đơn giản nhưng dễ phạm1. #include <stdio.h>

2. int main() { 3. int b;

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

Page 15: [C] giao trinh c   dhbk - viet nhat

15

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

Lỗi đơn giản nhưng dễ phạm1. printf(“1/X is: “);2. if(X < 0) ;3. printf(“ X is negative \n”);4. …

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

Lệnh if else ifKhi muốn thực hiện 1 trong n quyết địnhif (biểu thức1)

lệnh 1;else if (biểu thức2)

lệnh 2;…

else if (biểu thức_n_1)lệnh n -1;else lệnh n;

Biểu thức 1

Biểu thức 2

Lệnh 1

Lệnh 1

+

+

-

-

Lệnh ứng với else cuối cùng

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

Lệnh if else ifLập chương trình nhập vào mã trình độ và đưa ra tên trình độ tươngứng

#include <stdio.h>int main(){

int ma;printf("\n Go vao ma trinh do:");scanf("%d", &ma);if (ma==1)

printf("\n Trinh do trung cap");else if (ma==2)

printf("\n Trinh do cao dang");else if (ma==3)

printf("\n Trinh do dai hoc");else

printf("\n Nhap sai ma");return 0;

}

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

Ví dụ: Kiểm tra nhiều điều kiện1. #include <stdio.h> 2. int main() {

int b;

3. printf("Enter a value:");4. scanf("%d", &b);5. if (b < 0)6. printf("The value is negative\n");7. else if (b == 0)8. printf("The value is zero\n");9. else10. printf("The value is positive\n");11. return 0; 12. }

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.

Page 16: [C] giao trinh c   dhbk - viet nhat

16

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

Điều kiện lồng nhauCâu lệnh if có thể được lồng vào nhau.1. if ( X >= 0 ) {2. if ( Y < 0 )3. Y = Y + sqrt(X);4. }5. else6. Y = Y + sqrt(-X);

Tuy nhiên, cần chú ý đến thứ tự các cặp lệnh if … else … khi lồngcác lệnh if. Nếu không sẽ phát sinh lỗi.1. if ( X >= 0 )2. if ( Y < 0 )3. Y = Y + sqrt(X);4. else5. Y = Y + sqrt(-X);

Bài tập: Viết chương trình giải phương trình bậc 2: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 62

Lặp - lệnh whilewhile (bieu thuc dieu kien)

{cac lenh}Khi biểu thức điều kiện (expression) còn khác 0 (TRUE), lệnh(statement) tiếp tục được thực hiện. Nếu expression bằng 0 (FALSE), lệnh while dừng và chương trình sẽ gọi lệnh kế tiếpsau while.Nếu lúc đầu expression bằng 0 thì (statement) trong while khôngbao giờ được gọi thực hiện.

expression

statement(s) Next statement

True

False

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

Ví dụIn bảng đổi nhiệt độ từ độ Fahrenheit (oF) sang độ Celcius(oC).

1. #include <stdio.h>

2. int main() {3. int a = 0;4. while (a <= 100) {5. printf("%4d degrees F = %4d degrees C\n",a, (a - 32)*5/9);6. a = a + 10;7. }8. return 0; 9. }

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

Ví dụ: Biến đếm điều khiểnBiến đếm điều khiển vòng lặp

Lặp cho đến khi bộ đếm đạt tới một giá trị nhất địnhVòng lặp xác định: số vòng lặp được biết trước.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 chocả lớp.Mã giả: Gán tong bang 0

Gán biến đếm sinh viên bằng 1While biến đếm nhỏ hơn hay bằng 120

Nhập điểm sốCộng điểm số vào tổngTăng 1 vào biến đếm

Điểm trung bình = tổng / 120Hiển thị ra màn hình

Page 17: [C] giao trinh c   dhbk - viet nhat

17

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

1. Khởi tạo biến

2. Thực hiện vònglặp

3. Xuất kết quả

1 /*

2 Tinh diem trung binh kiem tra

3 Dieu khien vong lap bang bien dem */

4 #include <stdio.h>

5

6 int main()

7 {

8 int counter, grade, total, average;

9

10 /* Khoi tao gia tri bien */

11 total = 0;

12 counter = 1;

13

14 /* Xu ly */

15 while ( counter <= 120 ) {

16 printf( "Nhap diem: " );

17 scanf( "%d", &grade );

18 total = total + grade;

19 counter = counter + 1;

20 }

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 66

Thiết kế giải thuật Top-downMở rộng bài toán:

Viết chương trình tính điểm trung bình mà số sinh viên khôngđược biết trước.Làm cách nào để kết thúc chương trình?

Sử dụng giá trị có vai trò "lính canh" Còn có tên gọi khác là cờChỉ ra dấu hiệu “kết thúc nhập dữ liệu.”Vòng lặp kết thúc khi người sử dụng nhập vào giá trị lính canh.Giá trị này được chọn sao cho không thể nhầm lẫn nó với các giátrị nhập vào thông thường khác.

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

Thiết kế giải thuật Top-downTiếp cận top-down, giải quyết từng bước vấn đề

Bắt đầu với vấn đề cần giải quyết từ đỉnh (top):Xác định điểm trung bình kiểm tra của cả lớp

Phân chia bài toán thành các công việc nhỏ hơn và liệt kê chúngtheo trình :

Khởi tạo biếnNhập dữ liệu, tính tổng và đếm số sinh viênTính điểm trung bình

Nhiều chương trình trải qua ba giai đoạn:Khởi tạo: khởi tạo giá trị các biếnXử lý: nhập giá trị dữ liệu và thao tác trên chúngKết thúc: Tính toán và hiển thị kết quả cuối cùng

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

1. Khởi tạo biến

2. Nhập liệu

2.1 Thi hành vònglặp

1 /*

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>

5

6 int main()

7 {

8 float average;

9 int counter, grade, total;

10

11 /* khởi tạo */

12 total = 0;

13 counter = 0;

14

15 /* xử lý */

16 printf( "Nhập điểm, -1 để thoát ra: " );

17 scanf( "%d", &grade );

18

19 while ( grade != -1 ) {

20 total = total + grade;

21 counter = counter + 1;

22 printf( "Enter grade, -1 to end: " );

23 scanf( "%d", &grade );

24 }

Page 18: [C] giao trinh c   dhbk - viet nhat

18

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

Các cấu trúc điều khiển lồng nhauBài toán

Một học viện có một danh sách kết quả kiểm tra của 120 sinhviên (1 = qua, 2 = trượt)Viết chương trình phân tích kết quả

Nếu có hơn 90 sinh viên thi đỗ, hiển thị "Chất lượng đạt"

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

Biến đếmđiều khiển vòng lặp có thể được sử dụngCó thể dùng hai biến đếm

Một cho số lượng thi đỗ, một cho số thi trượtKiểm tra kết quả thi—hoặc 1 hoặc 2

Nếu kết quả không phải là 1, coi như là 2

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

1 /* Fig. 3.10: fig03_10.c2 Phân tích kết quả thi */3 #include <stdio.h>45 int main()6 {7 /* Khai báo khởi tạo biến */8 int passes = 0, failures = 0, student = 1, result;910 /* Làm việc với 120 sinh viên; vòng lặp điều khiển bởi biến đếm */11 while ( student <= 120 ) {12 printf( "Enter result ( 1=pass,2=fail ): " );13 scanf( "%d", &result );1415 if ( result == 1 ) /* if/else lồng trong while */16 passes = passes + 1;17 else18 failures = failures + 1;1920 student = student + 1;21 }2223 printf( "Passed %d\n", passes );24 printf( "Failed %d\n", failures );2526 if ( passes > 90 )27 printf( "Chất lượng đạt\n" );2829 return 0; /* kết thúc thành công */30 }

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

Lặp - lệnh forfor (biểu thức khởi tạo; biểu thức kiểm tra; biểu thức tănggiảm){Các lệnh}

Khởi động. Sau đó, nếu điều kiện (test) khác 0: lệnh (statement) được thi hành, lệnh điều chỉnh lại “biến đếm” được gọi thi hành.

test

statement(s)

Next statement

True

False

adjustment

initialization

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

Ví dụIn ra các số từ 1 đến 10

Biểu thức khởi tạo được thực hiện một lần, còn các biểu thứccòn lại được tính nhiều lần. Vòng lặp for có thể lồng nhau nhiều lầnCâu lệnh break làm máy thoát khỏi vòng lặp for sâu nhấtchứa lệnh đó.In ra các chữ cái hoa

for (i = 1; i <= 10; i++)

printf("%d ", i);

char ch;

for (ch = 'A'; ch <= 'Z'; ch++)

printf("%c ", ch);

Page 19: [C] giao trinh c   dhbk - viet nhat

19

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

Lệnh for (tiếp theo)Giữa hai dấu ; có thể có nhiều hơn một biểu thức

Phân cách nhau bởi dấu phảy.Example:for (i = 0, j = 0; j + i <= 10; j++, i++)

printf( "%d\n", j + i );

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

Ví dụ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.

1. #include <stdio.h>

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 75

Ví dụ

Sum is 2550

1 /* Tính tổng các số chẵn2 từ 1 đến 100 */3 #include <stdio.h>45 int main()6 {7 int sum = 0, number;89 for ( number = 2; number <= 100; number += 2 )10 sum += number;1112 printf( "Sum is %d\n", sum );1314 return 0;15 }

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

Lặp - lệnh do whiledo

{statement(s)}while (expression) ;

Thực hiện lệnh (statement). Kiểm tra biểu thức điều kiện(expression). Nếu (expression) bằng 0, dừng. Nếu không, thựchiện (statement).Lệnh do while thực hiện (statement) ít nhất một lần.

expression

statement(s)

Next statementTrue

False

Page 20: [C] giao trinh c   dhbk - viet nhat

20

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

Ví dụ - giao diện chương trình1. #include <stdio.h>2. #define PTB1 13. #define PTB2 24. #define STOP 3

5. int main()6. {7. int i;8. do {9. printf(“ Chuong trinh giai phuong trinh bac thap \n”);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”);

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

14. printf(“ 3. Thoat chuong trinh \n\n”); 15. printf(“ Chon muc so (1/2/3) ? “);16. scanf(“%d”, &i);17. if(i == PTB1)18. printf(“Giai phuong trinh bac 1: hien chua co\n”);19. else if(i == PTB2)20. printf(“Giai phuong trinh bac 2: chua cai dat\n\n”);21. } while (i != STOP);

22. return 0;23. }

Bài tập: Ghép chương trình trên với hai chương trình trong bài tập1 và 2

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

breakdùng để thoát khỏi vòng lặp giữachừng.

cú pháp: break;

Thường sử dụng cùng với lệnh if đểkiểm tra điều kiện dừng trước khi dùnglệnh break.

Bài tập: Viết chương trình nhập vàomột số rồi tìm số nguyên tố đầu tiênlớn hơn số vừa nhập

for…{

for…{

for…{

….break;…

}…

}}

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

Tìm số nguyên tố lớnCho trước một số tự nhiên N, tìm số nguyên tố lớn hơn gầnnhất.Giải pháp:

Số nguyên tố là số nguyên tố không chia hết cho các số nhỏ hơncă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ẻ.

Thuật toán sơ khởi:Kiểm tra N và so sánh với 2, 3Nế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 2Thử thế nào?

Thử tất cả các số nhỏ hơn căn bậc hai của N, nếu N chia hết chomột số trong chúng thì N là hợp số.

Page 21: [C] giao trinh c   dhbk - viet nhat

21

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

Tìm số nguyên tố lớn1. #include <stdio.h>2. #define TRUE 13. main(void)4. {5. unsigned long int sochia, ucv_nguyento;6. int la_nguyento;

7. printf(“Nhap vao so khoi dau: “);8. scanf(“%lu”, & ucv_nguyento);9. if(ucv_nguyento <= 2)10. ucv_nguyento = 2;11. else if(ucv_nguyento !=3 )12. {13. if(ucv_nguyento %2 == 0)14. ucv_nguyento ++; /* Phai la so le */

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

16. for( ; ; ucv_nguyento += 2)17. {18. la_nguyento = !TRUE;19. for(sochia = 3; ucv_nguyento % sochia; sochia += 2)20. if(sochia * sochia > ucv_nguyento)21. { la_nguyento = TRUE;22. break;23. }24. if (la_nguyento)25. break;26. }27. }28. printf(“So nguyen to lon hon gan nhat la %lu\n”, ucv_nguyento);29. }

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

continuebỏ qua các lệnh kế tiếptrong một vòng lặp và bắtđầu vòng lặp tiếp theo.

cú pháp: continue;

chỉ áp dụng với lệnh lặp.

Bài tập: Viết chương trìnhnhập vào một số và tìm ratất cả các thừa số nguyêntố của số đó.

while(i<10){

scanf(“%d”, &grade);if ((grade<0) || (grade>100))

{printf(“Illegal grade – try again\n”);continue;

}…….}

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

Ví dụ minh họa: continue1 /* Ví dụ minh họa

2 Sử dụng continue trong vòng lặp for */

3 #include <stdio.h>4

5 int main()6 {7 int x;8

9 for ( x = 1; x <= 10; x++ ) {10

11 if ( x == 5 ) 12 continue; 1314

15 printf( "%d ", x ); 16 }17

18 printf( "\nDung lenh continue de bo qua gia tri 5\n" );19 return 0;20 }

1 2 3 4 6 7 8 9 10

Dung lenh continue de bo qua gia tri 5

Page 22: [C] giao trinh c   dhbk - viet nhat

22

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

Tìm thừa số nguyên tố1. #include <stdio.h>

2. main(void)3. {4. unsigned long N, thuasonguyento, phanconlai;

5. printf(“Nhap vao mot so tu nhien: “);6. scanf(“%lu”, &N);

7. thuasonguyento = 2;phanconlai = N;

8. while(thuasonguyento * thuasonguyento <= phanconlai)9. {10. if(phanconlai % thuasonguyento == 0)

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

12. { /* Tim ra mot thua so */13. printf(“%lu”, thuasonguyento);14. phanconlai /= thuasonguyento;15. continue;16. }17. /* Khong phai la thua so nguyen to */18. if(thuasonguyento == 2) thuasonguyento = 3;19. else20. thuasonguyento += 2;21. }22. /* thua so nguyen to cuoi cung */23. printf(“%lu\n”, phanconlai);24. }

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

Thực hành lệnh lặpViết chương trình giải các bài tập sau sử dụng lần lượt cáccấu trúc lặp: while, for, do whileNhập vào một số nguyên năm chữ số (giả sử người dùngtuân thủ nghiêm ngặt quy tắc nhập). In các chữ số này trênnăm hàng

Viết chương trình in ra giai thừa của số tự nhiên N.

Nhập mười số nguyên từ bàn phím và đưa ra số lớn nhất.

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

Lệnh switchBài tập:

Viết chương trình lấy ngẫu nhiên 1000 số nguyên và đếmsố lần xuất hiện ở hàng đơn vị các số chẵn (2, 4, 6, 8), số lẻ(1, 3, 5, 7, 9) và số 0.

Nếu chúng ta dùng cấu trúc lệnh if ... else ... if … thì phức tạpvà có thể đòi hỏi nhiều phép thử. Lý do: if ... else ... : rẽ nhánh hai chiều.

Thử cài đặt bài toán bằng if...else...

Page 23: [C] giao trinh c   dhbk - viet nhat

23

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

Lệnh switchDùng lệnh switch để cài đặt cơ chế rẽ nhánh nhiều chiều.cú pháp:switch(<expression>)

{case case1:case case2:

<statements>;break;

/* … */case casen:

<statements>;break;

default:<statements>;break;

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

Sơ đồ xử lý lệnh switch

true

false

.

.

.

case a case a action(s) break

case b case b action(s) break

false

false

case z case z action(s) break

true

true

default action(s)

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

Giải bài bằng switch1. #include <stdlib.h>2. #include <stdio.h>3. #include <time.h>

4. int main(void)5. { int n,i;6. int n_even = n_odd = n_zero = 0;

7. randomize();8. for(i=0; i<1000; i++)9. { n = random(1000);10. switch (n%10) {11. case 2:12. case 4:13. case 6:14. case 8:15. n_even++; 16. break;

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

17. case 1:18. case 3:19. case 5:20. case 7:

case 9:21. n_odd++; 22. break;23. case 0:24. n_zero++; 25. break;26. }27. }28. // print out the summary29. printf(“Number of even_eding number: %d\n”\

Number of odd_ending number: %d\n”\Number of zero_ending number: %d\n”,n_even, n_odd, n_zero);

30. return 0;31. }

Page 24: [C] giao trinh c   dhbk - viet nhat

24

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

Thống kê điểm số (American system)

Hệ thống điểm của học sinh, sinh viên Mỹ: A, B, C, D, E, FChương trình nhập điểm của sinh viên, kết thúc bằng EOFIn ra số lượng sinh viên đạt điểm số tương ứng

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

1. Khởi tạo cácbiến

2. Nhập liệu

2.1 Dùng switch để cập nhật cácbiến đếm

1 /*2 Thống kê điểm số */3 #include <stdio.h>45 int main()6 {7 int diem;8 int aCount = 0, bCount = 0, cCount = 0, 9 dCount = 0, fCount = 0;1011 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" );1314 while ( ( grade = getchar() ) != EOF ) {1516 switch ( grade ) { /* switch lồng trong while */1718 case 'A': /* điểm là hạng A */19 ++aCount; 20 break;2122 case 'B': /* điểm là hạng B */23 ++bCount; 24 break;2526 case 'C': /* điểm là hạng C */27 ++cCount; 28 break;2930 case 'D': /* điểm là hạng D */31 ++dCount; 32 break;

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

3. In kết quả

33

34 case 'F': /* điểm là hạng F */

35 ++fCount;

36 break;

37

38 case '\n': case' ': /* ignore these in input */

39 break;

40

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" ); 44 break;

45 }

46 }

47

48 printf( "\Kết quả phân loại sinh viên:\n" );

49 printf( "A: %d\n", aCount );

50 printf( "B: %d\n", bCount );

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 96

Bài tập1) Viết chương trình tính giá trị biểu thức "a op b" như "2 + 3"a, b toán hạng – op : toán tử

2) Yêu cầu người sử dụng nhập vào một tháng. In ra số ngàytrong tháng đó.

Tháng có 31 ngày: 1, 3, 5, 7, 8, 10, 12 Tháng có 30 ngày: 4, 6, 9, 10 Tháng có 28 hoặc 29 ngày : 2

Page 25: [C] giao trinh c   dhbk - viet nhat

25

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

In số ngày trong một tháng#include <stdio.h> int main () {

int thang; printf("\n Nhap vao thangs trong

nam "); scanf("%d",&thang); switch(thang) {

case 1: case 3: case 5: case 7: case 8: case 10: case 12: printf("\n Thang %d co 31

ngay ",thang); break;

case 4: case 6: case 9: case 11: printf("\n Thang %d co 30

ngay ",thang); break; case 2: printf ("\ Thang 2 co 28 hoac

29 ngay"); break; default : printf("\n Khong co thang

%d", thang); break;

} return 0;

}

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

Tính ex với độ chính xác 10-5

ex = 1+x/1!+x2/2!+……………..+ xn/n!#include <stdio.h>void main() {

float epsilon = 0.00001;float x,add;int i=1;float result = 0.0; add = 1;printf("Chương trình tính giá trị e mũ x. \n");printf("x="); scanf("%f", &x);while (add > epsilon) {

result = result + add;add = add*x/i;i = i+1;

}printf ("Ket qua la:%f", result);

}

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

Một số toán tử và lệnh khácToán tử ‘,’ được dùng để khởi động nhiều biến trong vònglặp.Ví dụ:

for(i = 0, j = 0; i < 5; i++, j += i++)printf(“i = %d, j = %d, i+j = %d\n”, i, j, i+j);

Kết quả là: ????

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 100

Một số toán tử và lệnh khácLệnh goto cho phép nhảy không điều kiện đến bất kỳ nơi nàotrong chương trình.Cú pháp:

goto <label>

Ví dụ: xem chương trình ví dụ.

Lệnh goto làm mất cấu trúc chương trình.

Page 26: [C] giao trinh c   dhbk - viet nhat

26

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

Từ khóa của Cauto break case charconst continue default dodouble else enum externfloat for goto ifint long register returnshort signed sizeof staticstruct switch typedef unionunsigned void volatile while

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

Từ khóa của C#define để khai báo hằng số và …typedef để khai báo kiểu dữ liệu riêng

Toán tử sizeof xác định số byte được dùng để chứa một đốitượng

ví dụ: typedef unsigned long int Int32;/* ... */int x;x = sizeof(Int32); // x = 4

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

Chương 4: Mảng

Cao Tuấn Dũng2007

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

MảngMảng là tập hợp các giá trị cùng kiểu.Dãy liên tục các ô nhớ lưu các phần tử có liên quan đến nhauKhai báo:typename arrayname[array_size];

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

int a[array_size];n = array_size;

Truy cập phần tử mảng qua chỉ số của phần tử: iarray[i]; // 0 <= i <= array_size-1, i ∈N0

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

Page 27: [C] giao trinh c   dhbk - viet nhat

27

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

MảngCác phần tử mảng hoạt động như cácbiến thông thường

c[ 0 ] = 3;printf( "%d", c[ 0 ] );

Các thao tác toán học trên chỉ số mảngIf x bằng 3

c[ 5 - 2 ] == c[ 3 ] == c[ x ]

Ví dụ khai báo mảng:int c[ 10 ]; float myArray[ 3284 ];

Khai báo nhiều mảng cùng kiểuTương tự khi khai báo nhiều biến cùngkiểuint b[ 100 ], x[ 27 ];

Tên mảng(Các phần tử mảngcó cùng chung mộttên, c)

Vị trí của mộtphần tử trong mảngc

c[6]

-45

6

0

72

1543

-89

0

62

-3

1

6453

78

c[0]

c[1]

c[2]

c[3]

c[11]

c[10]

c[9]

c[8]

c[7]

c[5]

c[4]

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

Chú ý C không kiểm tra giới hạn của chỉ số truy cập phần tử mảng. Truy cập đến phần tử i>=array_size không có cảnh báo, nhưng giá trị không kiểm soát được.

Kích thước mảng phải là một hằng số.

Kích thước mảng có thể được khai báo tường minh hoặcthông qua một giá trị định nghĩa trước (#define)

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

Ví dụ thực tếBài toán: Sử dụng bảng số liệuvề lượng mưa hàng thángtrong năm.Input: thángOutput: Lượng mưa trung bìnhcho tháng đó

tháng lượng mưa TB (in mm) 0 30 1 40 2 45 3 95 4 130 5 220 6 210 7 185 8 135 9 80 10 40 11 45

Bảng lượng mưa

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

Khởi tạo mảngMảng có thể được khởi tạo bởi một dãy cácgiá trị thích hợp.

int n[ 5 ] = { 1, 2, 3, 4, 5 }; Nếu không đủ các giá trị khởi tạo cho tất cả, các phầntử bên phải sẽ có giá trị 0int n[ 5 ] = { 0 } => Tất cả phần tử = 0.

Nếu kích thước mảng bị bỏ qua, chươngtrình dịch tự phát hiện kích thước cầnthiết.

int n[ ] = { 1, 2, 3, 4, 5 };

Các khai báo sau đây là hợp lệint Squares[5] = {0,1,4,9,16};int Squares[5] = {0,1,4};int Squares[] = {0,1,4,9,16};int Squares[];

Page 28: [C] giao trinh c   dhbk - viet nhat

28

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

Chú ýKhông thể thực hiện các thao tác chép nội dung một mảngsang mảng khác.Chép từng phần tử mảng

char A[3]={‘a’,’b’,’c’};char B[3];B = A; // ???for(int i=0; i<3; i++)

B[i] = A[i];hoặc chép khối bộ nhớ (sẽ được đề cập sau)Không dùng phép so sánh trực tiếp (==) nội dung trong haimảng.Phép so sánh (A==B) so sánh địa chỉ hai vùng nhớ mà A và B chỉ đến.

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

Bảng lượng mưa (tiếp)#include <stdio.h>

int main(){int thang;int bangmua[12] = { 30, 40, 45, 95, 130, 220,

210, 185, 135, 80, 40, 45 };

printf("Nhap thang: ");scanf("%d", &thang);

printf("Luong mua trung binh cua thang: %d mm.\n", bangmua[thang-1]);

return 0;}

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

Bảng lượng mưa (tiếp)#include <stdio.h>

int main(){int thang;int bangmua[12] = { 30, 40, 45, 95, 130, 220,

210, 185, 135, 80, 40, 45 };

printf("Nhap thang: ");scanf("%d", &thang);

printf("Luong mua trung binh cua thang: %d mm.\n", bangmua[thang-1]);

return 0;}

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

Chú ýCác phần tử trong mảng được dùng như các biến đơn thôngthường.

Các hàm printf, scanf không làm việc với kiểu mảng, do đó việcnhậ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ửmảng.

1. // nhap gia tri cho cac phan tu mang2. float a[4];3. for(int i=0; i<4; i++)4. {5. printf(“a[%d]=“,i);6. scanf(“%f”, &a[i]);7. }

Chỉ số của phần tử mảng phải thuộc kiểu nguyên (int, short int, long int, char)

Page 29: [C] giao trinh c   dhbk - viet nhat

29

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

Khởi tạo mảng gồm các số chẵn từ 2 đến20

#include <stdio.h>

#define arraySize 10

int main(){

int s[ arraySize ]; // mảng S có 10 phần tửint i;

for ( i = 0; i < arraySize; i++ ) // khởi tạo giá trịs[ i ] = 2 + 2 * i;

printf("Phan tu \t Gia tri\n");for ( i = 0; i < arraySize; i++ )

printf("%d\t%d\n", i, s[i]);return 0;

}

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

Nhập xuất dữ liệu cho mảng#include <stdio.h>#define SOTHANG 12

/* Lưu và hiển thị lượng mưa */

int main(){int solieu[SOTHANG];int thang;

for ( thang=0; thang < SOTHANG; thang++ ){

scanf("%d", &solieu[thang] );}

...

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

Nhập xuất dữ liệu cho mảng#include <stdio.h>#define SOTHANG 12...

/* Print from January to December */for ( thang=0; thang< SOTHANG; thang++ ){

printf( "%5d ” , solieu[thang] );}printf("\n");

/* Print from December to January */for ( thang = SOTHANG - 1; thang >= 0; thang-- ){

printf( "%5d ” , solieu[month] );}printf("\n");

return 0;}

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

1 /*2 Histogram printing program */3 #include <stdio.h>4 #define SIZE 1056 int main()7 {8 int n[ SIZE ] = { 19, 3, 15, 7, 11, 9, 13, 5, 17, 1 };9 int i, j;1011 printf( "%s%13s%17s\n", "Element", "Value", "Histogram" );1213 for ( i = 0; i <= SIZE - 1; i++ ) {14 printf( "%7d%13d ", i, n[ i ]) ;1516 for ( j = 1; j <= n[ i ]; j++ )17 printf( "%c", '*' );1819 printf( "\n" );20 }2122 return 0;23 }

Element Value Histogram0 19 *******************1 3 ***2 15 ***************3 7 *******4 11 ***********5 9 *********6 13 *************7 5 *****8 17 *****************9 1 *

Page 30: [C] giao trinh c   dhbk - viet nhat

30

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

Đổ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à 0Lấy các số dư theo chiều ngược lại

23 2

111 2

51 2

21 2

10 2

0110111

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

Đổi số nguyên dương sang nhị phân

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

Khởi tạo ngẫu nhiênTạo dãy số nguyên dương 500 số. Mỗi số có giá trị trongkhoả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ị trungbình.

Tạo số ngẫu nhiên#include <stdlib.h>#include <time.h>srand(time(NULL)); /* Khởi tạo bộ sinh số ngẫu nhiên, gọi một lần

duy nhất */rand() ; sinh số nguyên ngẫu nhiên1+ rand() % N

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

Sắp xếp mảng

Sắp xếp dữ liệuLà một ứng dụng quan trọngHầu hết mọi cơ quan tổ chức cần sắp xếp dữ liệu

Sắp xếp nổi bọtDuyệt mảng vài lầnSo sánh các cặp phần tử liên tiếp

Nếu thứ tự tăng (hay bằng nhau) không thay đổi gì.Nếu thứ tự giảm: tráo đổi hai phần tử.

Lặp lại bước trên cho mọi phần tử

Page 31: [C] giao trinh c   dhbk - viet nhat

31

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

Sắp xếp mảng

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

Sắp xếp mảng

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

Sắp xếp mảngfor (pass = 0; pass < arraySize - 1; pass++ )

for (j = 0; j < arraySize - 1; j++ )

// So sánh hai phần tử kề nhau và đổi chỗ chúng khi// phần từ trước lớn hơn phần tử sauif ( a[ j ] > a[ j + 1 ] ) { hold = a[ j ]; a[ j ] = a[ j + 1 ]; a[ j + 1 ] = hold;

}

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

Mảng hai chiều

Một phần tử mảng có thể là một mảngkhácMảng của các mảng được gọi là mảngnhiều chiều

Hàng 0

Hàng 1

Hàng 2

Cột 0 Cột 1 Cột 2 Cột 3

a[ 0 ][ 0 ]

a[ 1 ][ 0 ]

a[ 2 ][ 0 ]

a[ 0 ][ 1 ]

a[ 1 ][ 1 ]

a[ 2 ][ 1 ]

a[ 0 ][ 2 ]

a[ 1 ][ 2 ]

a[ 2 ][ 2 ]

a[ 0 ][ 3 ]

a[ 1 ][ 3 ]

a[ 2 ][ 3 ]

Chỉ số hàngTên mảng

Chỉ số cột

Page 32: [C] giao trinh c   dhbk - viet nhat

32

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

Mảng nhiều chiềuKhai báo mảng 2 chiều:

type name[row_size][column_size];

Khởi tạoint SumSquares[2][3] = { {0,1,4}, {1,2,5} };int SumSquares[2][3] = { {0,1,4} };int SumSquares[ ][3] = { {0,1,4}, {1,2,5} };int SumSquares[ ][3] = { {0,1, }, {1} };int SumSquares[ ][3];

0 1 41 2 5

SumSquares

0 1 4 1 2 5

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

Ví dụ: Lượng mưa hàng năm

Bài toán: thao tác trên bảng vũ biểu• input: tháng và năm• output: lượng mưa trung bình vào năm, tháng đó

0 1 2 3 4 5 6 7 8 9 10 110 30 40 75 95 130 220 210 185 135 80 40 451 25 25 80 75 115 270 200 165 85 5 10 02 35 45 90 80 100 205 135 140 170 75 60 953 30 40 70 70 90 180 180 210 145 35 85 804 30 35 30 90 150 230 305 295 60 95 80 30

nam

thang

Lượng mưa trung bình năm (mm)

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

#define NYEARS 5#define NMONTHS 12

int main(){

int table[NYEARS][NMONTHS] ={

{30,40,75,95,130,220,210,185,135,80,40,45},{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}

};int year, month;printf("Enter year and month: "); scanf("%d %d", &year, &month);

if ((0 <= year) && (year < NYEARS) &&(0 <= month) && (month < NMONTHS))printf("Rainfall for year %d month %d is %d", year, month,

table[year-1][month-1]);else{

printf("Data non available");}return 0;

}

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

Nhập Mảng 2 chiều1. #define MAX_STUDENT 52. #define MAX_SUBJECT 6

3. int StudentScore[MAX_STUDENT][MAX_SUBJECT];

4. void read_Score(int Score[MAX_STUDENT][MAX_SUBJECT],int nStudents, int nSubjects)

5. {6. int i,j;7. for(i=0; i<nStudents; i++)8. for(j=0; j<nSubjects; j++)9. scanf(“%d”, &Score[i][j]);10. }

Page 33: [C] giao trinh c   dhbk - viet nhat

33

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

Biểu diễn mảng 2 chiều

0 1 4

1 2 5

StudentScores

0 1 4 1 2 5

? ? ?

? ? ?

? ? ? ? ? ?

? ? ? ? ? ?

? ? ? ? ? ?

? ? ? ? ? ?

Student1 Student2

Student1

Student2

Student3

Student4

Student5

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

Bài tậpViết chương trình nhập vào một dãy số theo thứ tự tăng, nếunhập sai quy cách thì yêu cầu nhập lại. In dãy số sau khinhập xong. Nhập thêm một số và chèn số đó vào dãy số saocho không thay đổi tính chất của dãy. In lại dãy mới để kiểmtra.Viết chương trình nhập vào một ma trận nguyên m hàng n cột. In ma trận ra màn hình. Nhập vào một số nguyên và kiểmtra 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

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

Hàm (function)

Cao Tuấn Dũng2007

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

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

Với chương trình máy tínhVới chương trình đơn giản, tấtcả các xử lý nên được đặttrong hàm main.

Chia để trị: Phân chia chươngtrình thành các phần nhỏ - cácchương trình con (routine) hay còn gọi là các hàm (function)

Chương trình con ACác biếnCâu lệnh

Kết thúc chương trình con A

Chương trình con BCác biếnCâu lệnh

Kết thúc chương trình con B

Chương trình

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

Page 34: [C] giao trinh c   dhbk - viet nhat

34

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

Hàm – Mô đun hóa chương trìnhTrong C mọi chương trình con là hàm, không có sự phân biệt giữahàm và thủ tục.Cách tiếp cận phân tích bài toán theo hướng top-down: xác địnhchức năng của các hàm.

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áchgọi lẫn nhau và truyền các thông tin qua lại giữa các hàm.Các hàm có thể được dùng lại nhiều lần thành lập các thư việnhà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ánhọ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 134

HàmLà một đoạn mã lệnh độc lập, được đặt tên, thực hiện mộtnhiệm vụ cụ thể và có thể trả về một giá trị cho chương trìnhgọi hàmSử 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ýThống nhất các đoạn mã tương tự nhau, sử dụng nhiều lần trongmột chương trìnhTái sử dụng mã lệnh trong nhiều hơn một chương trình

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

Các hàm toán học

ceil(9.2) bằng 10.0ceil(-9.8) bằng -9.0

làm tròn sốnguyênnhỏ nhấtkhông lớnhơn x

ceil(x)

nếu x≥0 thì fabs(x) bằng xnếu x<0 thì fabs(x) bằng -x

giá trị tuyệtđối của x

fabs(x)

log10(1.0) bằng 0.0log10(10.0) bằng 1.0

logarithm thập phân(cơ số 10) của x

log10(x)

log(2.718282) bằng1.0

logarithm tự nhiên(cơ số e) của x

log(x)

exp(1.0) bằng2.718282

hàm mũ exexp(x)

sqrt(9.00) bằng 3.0Căn bậc 2 của x

sqrt(x)

Ví dụMô tảHàm

tan(0.0) bằng 0.0tan của x (x theoradian)

tan(x)

cos(0.0) bằng 1.0cos của x (x theoradian)

cos(x)

sin(0.0) bằng 0.0sin của x (x theoradian)

sin(x)

fmod(13.657,2.333) bằng1.992

phần dư của phépchia x cho y

fmod(x,y)

pow(2,7) bằng 128x mũ y (xy)pow(x,y)

floor(9.2) bằng 9.0floor(-9.8) bằng -10.0

làm tròn số nguyênlớn nhất không nhỏhơn x

floor(x)

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

Ví dụ đầu tiên: Hàm lập phương

Cho vao mot so nguyen: 6Gia tri lap phuong cua 6 la 216

#include <stdio.h>

/* nguyen mau ham*/

int cube(int x);

void main() {

int a, kq;

printf("Cho mot so nguyen:"); scanf("%d", &a);

kq=cube(a);

printf("\n Gia tri lap phuong cua %d la %d", a, kq);

}

/* Ham tinh lap phuong */

int cube(int x) {

int x3;

x3 = x*x*x;

return x3;

}

Page 35: [C] giao trinh c   dhbk - viet nhat

35

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

Hoạt động của hàmCác lệnh trong hàm chưa đượcthực hiện cho tới khi hàm đượcgọi. Khi hàm được gọi điềukhiển thực hiện các lệnh đượcchuyển cho hàm.Chương trình gửi thông tin đếnhàm: các đối sốHàm gửi lại thông tin: giá trị trảvềBốn bước cơ bản khi gọi hàm:

Chương trìnhKhai báo Biến; Lệnh;….Lời gọi hàmLệnh…….Kết thúc

Hàm

danh sách đối số

Giá trị trả về

Cấp phát bộ nhớ cho các đối số và biến cục bộGán giá trị của các tham số thực cho đối số tương ứngThi hành lệnhGặ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 138

Khai báo hàmNguyên mẫu hàm (prototype): nguyên mẫu hàm cho chươngtrình dịch biết sự tồn tại của một hàm với tên, danh sách đốisố, kiểu giá trị trả về cụ thểCú pháp:

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);int Min(int x, int y);

Nguyên mẫu hàm chỉ cần thiết khi phần định nghĩa hàm nằmphía sau lời gọi hàm trong chương trình.Nguyên mẫu hàm được chương trình dịch sử dụng để kiểmtra tính hợp lệ của hàm

Nguyên mẫu hàm phải khớp với định nghĩa hàm

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

Tệp tiêu đềChứa các nguyên mẫu hàm của các hàm trong thư viện

stdio.h, stdlib.h, math.h, time.hChứa nguyên mẫu các hàm do người dùng định nghĩaSử dụng tệp tiêu đề do người dùng định nghĩa

Khai báo các hàm vào lưu trong file riêngĐặt tên filename.hKhai 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 140

Định nghĩa hàmNơi cài đặt thực sự mã cho một hàmDòng đầu tiên tương tự như nguyên mẫu hàm, tuy nhiên

chỉ định rõ danh sách đối sốkhông kết thúc bằng dấu ;

Phần tiếp theo là thân hàm

Page 36: [C] giao trinh c   dhbk - viet nhat

36

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

Các thành phần của hàmTên hàm (name)danh sách tham số (list of parameters)kiểu trả về (return type)thân hàm (function body)lệnh trả về (return)

<return_type> function_name (<list_of_parameters>)

Các hàm phải được khai báo trước khi được gọi thi hành.

giao diện(interface) của hàm

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

Hàm radianHàm chuyển đổi số đo góc từ độ sang radian

#include <stdio.h>#include <math.h>#define PI 3.14159

/* nguyen mau ham*/float Radian(float x);void main() {

float ang, adj, opp;printf("Nhap gia tri cua goc (theo do:"); scanf("%f", &ang);printf("Nhap canh ke:"); scanf("%f", &adj);opp= adj*tan(Radian(ang));printf("Canh doi la: %f\n", opp);

}/* 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 143

Thành phần của hàm – Tên hàmTên hàm là một định danh (identifier), do đó nó tuân theo cácquy định của ngôn ngữ C cho định danh. (xem bảng các toántử)

Nên đặt tên có ý nghĩa.

Không đặt tên trùng với tên các hàm hệ thống trong C hoặccác từ khóa của C.

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

Danh sách tham sốDanh sách tham số xác định các đối số được đưa vào hàm.

Các đối số được khai báo trong phần mô tả cài đặt của hàmthì được gọi là các tham số hình thức (formal parameters).

Mỗi tham số hình thức là một cặp: <type> <identifier>. Từkhoá void có thể được dùng nếu không có tham số hình thứcnà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à đúngkiểu như đã khai báo.

Page 37: [C] giao trinh c   dhbk - viet nhat

37

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

Ví dụ/* ... */

1. float max(float x, float y)2. {3. return (x > y ? x : y);4. }

/*…*/

6. int main()7. {8. float z = 4.7;9. float x = max(4.5, z);10. }

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

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ộtgiá trị: giá trị trả về.

Chương trình gọi hàm có thể sử dụng giá trị trả về.

Một số hàm không cần trả về các giá trị. Từ khóa void đượcdùng trong khai báo giá trị trả về của các hàm này.

Kiểu int sẽ là kiểu của trị trả về nếu không chỉ rõ kiểu giá trịtrả về trong khai báo hàm.

ví dụ: afunction() { /*…*/ }

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

Thân hàm (function body){ /* các đoạn mã trong thân hàm */ }

Các biến có thể được khai báo bên trong hàm biến cục bộ(local variable)

Biến cục bộ không được trùng tên với tham số hình thứctrong khai báo hàm.

Các biến cục bộ chỉ có giá trị trong phạm vi của hàm.

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

Hàm tìm USCLN giữa hai sốint USCLN(int a, int b) {

a=abs(a); b=abs(b); while(a!=b) {

if(a>b) a=a-b;

else b=b-a;

} return a;

}

Page 38: [C] giao trinh c   dhbk - viet nhat

38

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

Phạm vi truy cập của biếnPhạm vi truy cập (scope) của biến xác định vùng chươngtrình có thể truy cập đến biến.

Biến được khai báo trong khối lệnh (nằm giữa { }) có thểđược truy cập bởi các lệnh nằm trong cùng khối và các lệnhthuộc các khối con.

Biến được khai báo “ngoài cùng” có phạm vi truy cập trongtoàn chương trình biến toàn cục (global variables).

Biến cục bộ (local variable) được khai báo và sử dụng trongphạm vi một khối lệnh và các khối lệnh con.

Biến thuộc phạm vi trong cùng được tham chiếu đến đầu tiên.Lập trình C - Việt Nhật 2007 150

Ví dụ1. int i=1; /* i là biến toàn cục vì nằm ở ngoài các khối lệnh */

2. { /* block A */3. int i=2;4. printf (“%d\n”, i); /* outputs 2 */ }5. { /* Block B */6. int i=3;7. printf (“%d\n”, i); /* outputs 3 */

8. { /* Block C */9. int i=4;10. printf (“%d\n”, i); /* outputs 4 */ }11. { /* Block D */12. printf (“%d\n”, i); /* outputs 3 */ }13. }14. { /* Block E */15. printf (“%d\n”, i); /* outputs 1 */ }

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

Phạm vi của biến

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

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ínhlà 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ụcbộ. Tuy nhiên rất ít khi người ta sử dụng nó vì cácbiế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ếnautomatic.

Page 39: [C] giao trinh c   dhbk - viet nhat

39

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

Cấp lưu trữ và phạm vi các đối tượng

Cấp lưu trữ ( storage class): thời gian sống + phạm viCó tất cả bốn cấp lưu trữ trong C: tự động, toàn cục (ngoài), tĩnh và register được khai bao thông qua các từ khóa auto, extern, static và register. Mặt khác cũng lưu ý rằng cấp lưu trữ của một biến đôi khiđược xác định bởi chính vị trí khai báo của biến đó trongchương trình. Trong các trường hợp khác người ta dùngbốn từ khóa nói trên trong khai báoVí dụ:auto int a,b,c;extern float r1,r2;static int count = 0;extern char star;

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

Biến tự động/* Hoán vị giá trị hai số nguyên */#include <stdio.h>void swap(auto int* , auto int* ); /* Hàm nguyên mẫu */main(){

auto int x, y;x = 10; y = 20;printf("Ban đầu x = %d, y = %d", x, y);swap( &x, &y);printf("Sau đó x = %d, y = %d", x, y);

}/* Định nghĩa hàm swap */void swap( auto int* a, auto int* b) {

auto int temp;temp = *a;*a = *b;*b = temp;

}

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

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

Phạm vi (scope) của biến toàn cục là toàn bộ chươngtrình

Các biến toàn cục được định nghĩa bên ngoài mọi hàmdo vậy chúng có tiềm năng sử dụng cho nhiều hàm.

Biến toàn cục còn đóng một vai trò quan trọng khi pháttriển các ứng dụng lớn, vì khi đó hiển nhiên là cácchương trình nguồn để trên nhiều tệp khác nhau.

Từ khoá extern thông báo với trình biên dịch rằng tênvà 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 156

Biến toàn cục#include <stdio.h>long fibo(int count);long f1=1,f2=1;/* khai báo biến toàn cục */main(){int count,n;printf("\nn =");scanf("%d",&n);for(count=1;count<=n; ++count)printf("\ni=%2d F=%ld", count,fibo(count));

}

long int fibo(int count){

long int f;f=(count<3) ? 1: f1+f2;f2=f1; f1=f;return f;

}

Page 40: [C] giao trinh c   dhbk - viet nhat

40

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

Biến tĩnh (static)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ươngtrình. Cấp phát bộ nhớ một lần và tồn tại cho đến khi kết thúcstatic tênkiểu tênbiến = giatri;

#include <stdio.h>int inc(){

static int n=0;n++;return n;

}void main(){

printf("\n Ket qua inc lan 1: %d", inc());printf("\n Ket qua inc lan 2: %d", inc());

}

Ket qua inc lan 1: 1Ket qua inc lan 2: 2

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

Biến tĩnh#include<stdio.h>long fibo(int count);main(){int count,n;printf("\nn =");scanf("%d",&n);for(count=1;count<=n; ++count)printf("\ni=%2d F=%ld", count,fibo(count));

}long int fibo(int count){

static long int f1=1,f2=1;long int f;f=(count<3) ? 1: f1+f2;f2=f1; f1=f;return f;

}Nếu bỏ từ khóa static ở trong thân hàm main ????

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

Biến registerTừ khoá register được đặt trước khai báo của các biếntự động để đề nghị trình biên dịch duy trì giá trị biến đótrong thanh ghi của máy tính, giúp nâng cao tốc độ thựchiện.

Trình biên dịch có thể bỏ qua từ khoá register khi khôngcòn đủ thanh ghi nữa và nói chung chúng chỉ áp dụngcho các biến kiểu int và char.

Ví dụ sau đề nghị trình biên dịch đặt biến counter vàomộ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 160

Lệnh returnkết thúc hàm và trả quyền điều khiển về cho phần chươngtrình có lời gọi hàm.

cú pháp:return Expr;

hoặcreturn;

hàm tự kết thúc khi thực hiện hết lệnh cuối cùng.

Page 41: [C] giao trinh c   dhbk - viet nhat

41

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

Một số ví dụTính tổng các số nguyên tố nhỏ hơn n

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

Một số ví dụ minh họaChương trình tính tổng các số nguyên tố

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

Một số bài tậpViết chương trình tính tiền thuê máy dịch vụ Internet vàin ra màn hình kết quả. Dữ liệu nhập vào là giờ bắt đầuthuê (GBD), giờ kết thúc thuê (GKT) và số máy thuê

Đ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

Nhập vào ba số thực a, b, c kiểm tra xem chúng có phảilà ba cạnh một tam giác không. Nếu có tính diện tích, độdài 3 đường cao.

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

Truyền tham số khi gọi hàmTruyền tham chiếu (call by reference): các tham chiếu đếncác tham số hình thức là tham chiếu đến các đối số. Giá trịcủa các đối số có thể được thay đổi từ xử lý bên trong hàm.

Truyền giá trị (call by value): các đối số đưa vào hàm đượcchép vào các tham số hình thức. Các giá trị của các đối sốđượ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ốtruyền vào.

Page 42: [C] giao trinh c   dhbk - viet nhat

42

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

Truyền giá trị1. /* Swapping routine that doesn’t work */2. #include <stdio.h>

3. void Swap(int x, int y){ int Temp;

4. Temp = x;5. x = y;6. y = Temp;7. }

8. main(void)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 166

Tại sao truyền giá trị không làmthay đổi giá trị đối số

main#1::Left = 5

main#1::Right = 7

Swap#1::Temp = ?

Swap#1::x = 5

Swap#1::y = 7

M1M2

M3M4M5

main#1::Left = 5

main#1::Right = 7

Swap#1::Temp = 5

Swap#1::x = 7

Swap#1::y = 5

M1M2

M3M4M5

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

Truyền bằng tham chiếu/* Swapping routine that does work */#include <stdio.h>void Swap(int &x, int &y){

int Temp;

Temp = x;x = y;y = Temp;

}

main(void) {

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 168

Tại sao truyền bằng tham chiếu làmthay đổi giá trị đối số

main#1::Left = 5

main#1::Right = 7

Swap#1::Temp = ?

Swap#1::x

Swap#1::y

M1M2

M3M4M5

main#1::Left = 7

main#1::Right = 5

Swap#1::Temp = 5

Swap#1::x

Swap#1::y

M1M2

M3M4M5

Page 43: [C] giao trinh c   dhbk - viet nhat

43

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

Dừng chương trình và mã lỗiThô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ươngtrì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ắtlỗi trong quá trình chạy.

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

Truyền mảng cho hàm

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

Truyền mảng cho hàm

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

1 /* Fig. 6.13: fig06_13.c2 Passing arrays and individual array elements to functions */3 #include <stdio.h>4 #define SIZE 556 void modifyArray( int [], int ); /* appears strange */7 void modifyElement( int );89 int main()10 {11 int a[ SIZE ] = { 0, 1, 2, 3, 4 }, i; 1213 printf( "Effects of passing entire array call "14 "by reference:\n\nThe values of the "15 "original array are:\n" );1617 for ( i = 0; i <= SIZE - 1; i++ ) 18 printf( "%3d", a[ i ] );1920 printf( "\n" );21 modifyArray( a, SIZE ); /* passed call by reference */22 printf( "The values of the modified array are:\n" );2324 for ( i = 0; i <= SIZE - 1; i++ )25 printf( "%3d", a[ i ] );2627 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 ] );31 return 0;32 }

Page 44: [C] giao trinh c   dhbk - viet nhat

44

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

Hàm truy cập, in Mảng 2 chiều1. void print_Score(int Score[MAX_STUDENT][MAX_SUBJECT],

int nStudents, int nSubjects)2. {3. int i,j;

4. for(i=0; i<nStudents; i++)5. {6. for(j=0; j<nSubjects; j++)7. printf(“%2d\t”, &Score[i][j]);8. printf(“\n”);9. }10. }

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

Chương trình1. main(void)2. {3. int nStudents, nScores;

4. scanf(“%d %d”, &nStudents, &nScores);5. if(nStudents <= MAX_STUDENT &&

nScores <= MAX_SCORES)6. read_Score(StudentScore, nStudents, nScores);

7. print_Score (StudentScore, nStudents, nScores);

8. return 0;9. }

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

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

Ví dụ: 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);…

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

Đệ Quy

Cao Tuấn Dũng2007

Page 45: [C] giao trinh c   dhbk - viet nhat

45

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

Nguyên lýTrong C cho phép trong thân một hàm có thể gọi ngayđến chính nó, cơ chế này gọi là đệ qui.Có thể định nghĩa hàm đệ qui là hàm sẽ gọi đến chínhnó 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ónhững điểm chung sau.

Hàm đệ qui thực ra chỉ biết cách giải bài toán trong trường hợp đơn giảnnhất (hay còn gọi là trường hợp cơ sở). Nếu hàm được gọi trong các trường hợp phức tạp hơn, hàm đệ qui sẽ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áchgiả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ảigiống với bài toán ban đầu nhưng đơn giản hơn hay nhỏ hơn bài toánban đầu. Để đảm bảo việc đệ qui có kết thúc, mỗi một lần gọi đệ qui thì bài toánphải đảm bảo đơn giản hơn và các bước đệ qui này còn thực hiên tiếpcho dến khi nào bài toán đơn giản dần, đơn giản tới mức trở thànhtrường hợp cơ sở.

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

Tính giai thừaVí dụ: Viết chương trình nhập số tự nhiên n và tính giai thừa : n!.Giải quyết bài toán bằng vòng lặp

1. #include <stdio.h>

2. unsigned long int factorial(int n)3. { unsigned long f = 1;4. for (int i = 1; i<=n; i++)5. f *= i;6. return f;7. }

8. int main(void)9. { int n;

10. printf(“Nhap n:”); scanf(“%d”, &n);printf(“n! = %d! = %l\n”, n, factorial(n));

11. return 0;12. }

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

Tính giai thừaTuy 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)!nếu n=0 n! = 0! = 1

1. #include <stdio.h>

2. unsigned long int factorial(int n)3. { if(n==0)4. return 1;5. return (n* factorial(n-1));6. }

7. int main(void)8. { int n;

9. printf(“Nhap n:”); scanf(“%d”, &n);10. printf(“n! = %d! = %l\n”, n, factorial(n));11. return 0;12. }

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

Dãy Fibonaci

Một ví dụ thứ hai dùng đệ qui là tính dẫy sốFibonaci

Dãy số Fibonaci gồm những số0, 1, 1, 2, 3, 5, 8, 13, 21 ...

Bắt đầu từ hai số 0 và 1, tiếp sau đó các số Fibonacisau bằng tổng của 2 số Fibonaci trước nó.Dẫy Fibonaci có thể định nghĩa đệ qui như sau:

fibonaci(0) = 0; fibonaci(1) = 1;fibonaci(n) = fibonaci(n-1) + fibonaci(n-2) ∀n>1

Page 46: [C] giao trinh c   dhbk - viet nhat

46

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

Dãy Fibonaci (tiếp)/* Tính dẫy số Fibonaci phương pháp đệ qui */#include <stdio.h>long fibo( long ); /* Hàm nguyên mẫu */main(){long result, n;printf("Hãy nhập vào một số nguyên : ");scanf("%ld", &n);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){if ( n = 0 || n = 1 )return n;elsereturn fibo(n-1) + fibo(n-2);}

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

Lời gọi hàm đệ quy và Điều kiệndừng của thuật giải đệ quy

Bài toán giải bằng thuật giải đệ quy phải có điều kiện dừng.

Thuật toán đệ quy trên máy tính có thể bị giới hạn bởi dung lượng bộ nhớ do lời gọi hàm liên tiếp.

factorial (4) factorial (3) factorial (2) factorial (1)

main

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 183

Bài toán Tháp Hà NộiCó 3 cái cột và một chồng đĩa ở cột thứ nhất. Hãy chuyểnchồng đĩa sang cột thứ ba với điều kiện mỗi lần di chuyển chỉmột đĩa và các đĩa bé luôn nằm trên đĩa lớn.

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 dichuyể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 184

Thuật giảiChuyển (n-1) đĩa sang cột trung gian.Chuyển đĩa lớn nhất sang cột đích.Chuyển (n-1) đĩa từ cột trung gian sang cột đích.

Page 47: [C] giao trinh c   dhbk - viet nhat

47

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

Cài đặt bằng đệ quy1. MoveDisk(disk_number, starting_post, target_post,

intermediate_post)2. {3. if(disk)number > 1) 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);8. }9. else10. printf(“Move disk number 1 from post %d to post %d.\n”,

starting_post, target_post);11. }

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

CON TRỎ

Cao Tuấn Dũng2007

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

Con trỏBiến con trỏ

Khai báo biến con trỏ

Địa chỉ và giá trị

Truyền tham chiếu trong lời gọi hàm

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

Truyền tham số qua trị1. #include <stdio.h>

2. void move_one(int x, int y)3. {4. x = x-1;5. y = y+1;6. }

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

Page 48: [C] giao trinh c   dhbk - viet nhat

48

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

Bộ nhớ

main#1::a

main#1::b

move_one#1::x

move_one#1::y

M1M2

M3M4

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

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ị.Khi chúng ta khai báo một biến, máy sẽ cấp phát cho biến đó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ốnbytes .v.vHà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

địa chỉtên biến

giá trị41024:

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

Kiểu dữ liệu Con trỏĐịa chỉ của biến được tính là số thứ tự của byte đầu tiên trongdãy các bytes được cấp cho biến. Tuỳ theo kích thước bộnhớ người ta biểu diễn địa chỉ bằng hai hoặc bốn bytes.

Một biến kiểu con trỏ (pointer) chứa một tham chiếu(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.

int x;int* xp;

/* con tro tro toi mot so nguyen */

x = 4;xp = &x;

41024:x

1024:

xp

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

Khai báo, toán tử và sử dụng tronghàm

Khai báo kiểu dữ liệu con trỏ:int * “con trỏ đến kiểu int”float * “con trỏ đến kiểu float”char * “con trỏ đến kiểu character”

Toán tử& địa chỉ của một đối tượng* giá trị của vùng nhớ biến con trỏ chỉ đến

Con trỏ được dùng như tham số hình thức trong khai báohàm để truyền và lấy các đối số có giá trị thay đổi.

Page 49: [C] giao trinh c   dhbk - viet nhat

49

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

Con trỏ và địa chỉ biếnĐịa chỉ của hai biến ký tự liên tiếp sẽ cách nhau một byte trong khi địa chỉ của hai biến nguyên liên tiếp cách nhau haibyte còn địa chỉ của hai biến thực liên tiếp cách nhau tới bốnbytes.Người ta phân biệt các con trỏ theo các kiểu địa chỉ chứatrong các con trỏ: con trỏ kiểu nguyên dùng để chứa địa chỉ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.

... p a

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

Sử dụng Con trỏTruy cập vùng nhớ được chỉ bởi một con trỏint x=1,y=2,z[10];int *pi; /*pi là một biến con trỏ có kiểu nguyên*/pi = &x; /*Địa chỉ của x được gán cho pi, và pi trỏ tới biến x*/y=*pi; /*y có giá trị bằng 1*/*pi=15; /*Từ bây giờ x có giá trị bằng 15*/pi=&z[0]; /*Từ đây pi chứa địa chỉ của z[0], tức là địa chỉ của mảng z*/

151024:x

1024:

pi

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

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,long) để cho kết quả là một con trỏ cùng kiểu. Xét ví dụ sau:

int *x=2,*px,*py;px = &x;py = px+1; /*py trỏ đến số nguyên nằm sau x trong bộ nhớ*/

Phép trừ hai con trỏ cùng kiểu được coi là hợp lệ và cho kếtquả là một số nguyên biểu thị "khoảng cách" (ở đây bằng sốphần tử ) giữa hai biến con trỏ.Ví dụ 3.?. Quay về ví dụ trên, câu lệnhx=py-px;

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ácphép nhân, chia hai con trỏ.

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

Các phép toán trên con trỏCó thể áp dụng các phép so sánh, phép gán cho các con trỏ. Trong các phép toán này đòi hỏi các toán hạng con trỏ phảicó cùng kiểu. Mọi sự chuyển đổi kiểu tự động từ các kiểukhác thành các kiểu con trỏ phải luôn luôn được cân nhắc vàhỏi ý kiến bởi chương trình biên dịch.int *addr1;char *addr2;addr1=0; /*Chương trình dịch sẽ đưa ramột warning */addr2 = (char *)0; /*Phép gán này hợp lệ*/if(addr1==addr2) /*Gây ra một warning*/

{addr1 = (int *)addr2; /*Hợp lệ*/}

Page 50: [C] giao trinh c   dhbk - viet nhat

50

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

Sử dụng con trỏ như tham số#include <stdio.h>void move_one(int* xPtr, int* yPtr){*xPtr = *xPtr-1;*yPtr = *yPtr+1;}int main(void){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 198

Bộ nhớ

main#1::a

main#1::b

move_one#1::xPtr

move_one#1::yPtr

M1M2

M3M4

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

Hàm swapvoid swap(int *px, int *py){int temp;temp = *px;*px = *py;*py = temp;}

main(void){int a, b;a=2; b=9;swap(&a, &b);}

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

Bài tậpLập chương trình:- Nhập từ bàn phím một số nguyên.- Đưa ra màn hình dưới dạng hexadecimal nội dung byte cao và

byte thấp của số nguyên.

#include <stdio.h>main() {

int n;char *pc;printf("Nhap vao so nguyen : ");scanf("%d",&n);pc=(char *)&n; /*pc trỏ đến byte cao cua n, pc+1 trỏ đến byte thấp*/printf("Byte cao %x ,byte thap %x",*pc ,*pc++);

}

Page 51: [C] giao trinh c   dhbk - viet nhat

51

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

Con trỏ voidKiểu dữ liệu voidGiá trị trả về của hàm: không cần giá trị trả vềTham số trong hàm: không có tham số

Con trỏ kiểu void được khai báo như sau: void *tên_con_trỏ;Đây là con trỏ đặc biệt, con trỏ không kiểu, nó có thể nhậnbất kỳ địa chỉ kiểu nào. Chẳng hạn các câu lệnh sau là hợplệ:void *px,*py;int x=1;float y=0.1;px=&x;py=&y;

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

Con trỏ và mảng một chiềuXét câu lệnh: int a[10];

Tên mảng là một hằng địa chỉ, nó chính là địa chỉ của phầntử đầu tiên của mảng; điều này có nghĩa là:a tương đương với &a[0]Nếu pa là một con trỏ kiểu nguyên,int *pa;Khi đó phép gánpa = &a[0];Đem pa trỏ đến phần tửthứ nhất (có chỉ số là 0) của a; nghĩa là pa chứa địa chỉ của a[0].

a[9]a[8]a[7]a[6]a[5]a[4]a[3]a[2]a[1]a[0]

a[0] a[1] a[2] a[3] a[4] a[5] a[6] a[7] a[8] a[9]

pa

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

Con trỏ và mảng một chiềupa +i là địa chỉ của a[i] và *(pa+i) là nội dung của a[i]

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

... ...

a[9]pa+9

pa+1 a[1]

a[0]pa

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

Con trỏ và mảng một chiềuCó 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ệ. Nhưng một tên mảng không phải là một con trỏ, do đó cáccâ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).

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.Tính tổng của chúng

Page 52: [C] giao trinh c   dhbk - viet nhat

52

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

#include <stdio.h>main(){float a{5],s;int ifor(i=0;i<5;i++)

[printf("\na[%d] =

",i) ; scanf("%f",a+i);

}s=0;

for(i=0;i<5;i++)s+=a[i];

printf("\n tong la: %10.2f",s);}

#include <stdio.h>main(){float a{5],s;int ifor(i=0;i<5;i++)[

printf("\na[%d] = ",i) ;

scanf("%f",&a[i]);}s=0;for(i=0;i<5;i++)s+=a[i];printf("\n tong la: %10.2f",s);

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

#include <stdio.h>main(){float a{5],s,*p;int i; p=a;for(i=0;i<5;i++)

[printf("\na[%d] =

",i) ; scanf("%f",p+i);

}s=0;

for(i=0;i<5;i++)s+=*(p+i);

printf("\n tong la: %10.2f",s);}

#include <stdio.h>main(){float a{5],s, *p;int i; p=a;for(i=0;i<5;i++)[

printf("\na[%d] = ",i) ;

scanf("%f",&p[i]);}s=0;for(i=0;i<5;i++)s+=p[i];printf("\n tong la: %10.2f",s);

}

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

Truyền mảng qua con trỏ1. #include <stdio.h>2. #define SIZE 5

3. void getArray(int *a, int size);

4. main()5. {int an_array[SIZE];6. getArray(an_array, SIZE);7. return 0;8. }

9. void getArray(int *a, int size)10. {for(int i=0; i<size; i++) {11. printf(“a[%d]=“);12. scanf(“%d”, &a[i]);13. }14. }

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

Con trỏ và mảng nhiều chiềuPhép toán lấy địa chỉ nói chung không dùng được đối với các thànhphần của mảng nhiều chiều (trừ trường hợp mảng hai chiều các sốnguyên).Phép cộng địa chỉ trong mảng hai chiều

Xét khai báofloat a[2][3];Với khai báo này hệ thống cấp sáu phần tử liên tiếp trong bộ nhớ theothứ tự sau: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ủanó; phép cộng địa chỉ phải hiểu như sau: C cho rằng mảng hai chiều là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ửcủa nó là một dãy gồm 3 số thực. Vì vậy

a trỏ tới đầu hàng thứ nhất (phần tử a[0][0]a+1 trỏ tới đầu hàng thứ hai (phần tử a[1][0]

Page 53: [C] giao trinh c   dhbk - viet nhat

53

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

Con trỏ và mảng hai chiều

Để truy xuất vào các phần tử của mảng hai chiều tavẫn có thể dùng con trỏ theo cách sau:float *p, a[2][3];p=(float*)a;Khi đóp trỏ tới a[0][0]p+1 trỏ tới a[0][1]p +2 trỏ tới a[0][2]p +3 trỏ tới a[1][0]p +4 trỏ tới a[1][1]p +5 trỏ tới a[1][2]

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

Tính địa chỉ từng phần tửĐể ý rằng, a là một hằng con trỏ trỏ đến các dòng của một ma trânhai chiều, vì vậya trỏ đến dòng thứ nhấta+1 trỏ đến dòng thứ hai

Để tính toán được địa chỉ của phần tử ở dòng i cột j chúng ta phảidùng phép chuyển đổi kiểu bắt buộc đối với a: (float * )a, đây làcon trỏ trỏ đến thành phần a[0][0] của ma trận. Và vì vậy thànhphần a[i][j] sẽ có địa chỉ là (float *a) +i*n+j (n là số cột).

Một cách tổng quát, nếu mảng có kiểu type và có kích thước cácchiều tương ứng là n1,n2,..,nk (Giả sử mảng a có k chiều). Địa chỉcuả thành phần a[0]..[0] (k chỉ số 0) là (type *)a, và địa chỉ củaa[i1][i2]...[ik] được tính như sau

( *)type a i n ij l k

j

k

l j

k

+ +=

= +∑ ∏

1

1

1

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

Ví dụ: Đọc dữ liệu cho mảng hai chiều#include <stdio.h>main()

{float a[2][3],*p;int i,m,n;p=(float*)a;for(i=0;i<2;i++)

for(j=0;j<3;j++){printf("a[%d][%d] = ",i,j);scanf("%f",p+i*3+j);}

for(i=0;i<2;i++)for(j=0;j<3;j++)

{printf("%6.2f",a[i][j]);

if(j==2) printf("\n");}

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

Mảng các con trỏChúng ta có thể khai báo một mảng các con trỏ bằng câulệnh sau:type *pointer_array[size];

ví dụ câu lệnh,char *ma[10];

Sẽ khai báo một mảng 10 con trỏ char có thể được dùng đểkhai báo một mảng để lưu trữ địa chỉ của mười chuỗi ký tựnào đó.Nếu các con trỏ được chuẩn bị để chỉ đến một biến nào đó đãcó, thì như vậy, chúng ta có thể truy xuất được các biến nàythông qua một mảng mà không cần đến vị trí thực sự của cácbiến đó có liên tiếp hay không.

Page 54: [C] giao trinh c   dhbk - viet nhat

54

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

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ỉcủa các biến int có giá trị và vị trí bất kỳ. Chúng ta sẽ dùng mộthàm để sắp xếp lại các địa chỉ này trong mảng để sao cho cá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.Không làm thay đổi vị trí hoặc thay đổi các giá trị của các biếnnhưng mảng vẫn có vẻ như là một mảng chỉ đến các giá trị đãsắp xếp có thứ tự.

#include <stdio.h>main() {

int i,j,*x;int d=10,e=3,f=7;int a=12,b=2,c=6;int *ptr_array[6];

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

/*Gán các thành phần của mảng*/ptr_array[0]=&a;ptr_array[1]=&b;ptr_array[2]=&c;ptr_array[3]=&d;ptr_array[4]=&e;ptr_array[5]=&f;

/*Sắp xếp lại dãy số*/for(i=0;i<5;i++)

for(j=i+1;j<6;j++)if(*ptr_array[i]>*ptr_array[j])

{x=ptr_array[i];ptr_array[i]=ptr_array[j];ptr_array[j]=x;}

/*In kết quả sau khi sắp xếp*/for(i=0;i<6;i++)

printf(" %d \n",*ptr_array[i]);}

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

Mảng nhiều chiều và mảng con trỏGiữa mảng nhiều chiều và mảng các con trỏ tồn tại nhiềuđiểm khác nhau:

Mảng nhiều chiều thực sự là mảng có khai báo, do đó có chỗ đầy đủ chotấ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ácbiến con trỏ mà thôi.

Việc sử dụng mảng các con trỏ có hai ưu điểm: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 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óthể là những mảng đã có bằng cách xin cấp phát chỗ động hay bằngkhai báo biến mảng bình thường, tùy ý.Các mảng con của nó được chỉ đến bởi các con trỏ, có thể có độ dài tùyý, hoặc có thể không có (nếu con trỏ đó không được chuẩn bị, hoặcđược gán bằng NULL).

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

Cấp phát động

Ý nghĩa của việc cấp phát bộ nhớ động là cho phépchương trình sử dụng vừa đúng khối lượng bộ nhớ màchương trình cần, và khi không cần dùng tới nữa thì cóthể giải phóng để cho các công việc tiếp theo có thể sửdụng được. Như vậy, cùng một vùng bộ nhớ có thểđược sử dụng cho các mục đích khác nhau trong thờigian thực hiện của chương trình. Vùng nhớ heap được sử dụng cho mục đích cấp phátđộng các khối nhớ có kích thước thay đổi. Có nhiều cấutrúc dữ liệu sử dụng cách cấp phát động, ta có thể liệt kêmột vài loại như: cây (tree), các loại danh sách liên kết.

Page 55: [C] giao trinh c   dhbk - viet nhat

55

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

Cấp phát độngHàm malloc trong thư viện < stdlib.h>, <alloc.h>

Cú pháp khai báo(type*)malloc (số ô nhớ cần cấp phát);

Hàm malloc dùng để xin cấp phát một vùng bộ nhớ (với kíchthước được xác định khi gọi hàm) từ vùng nhớ heap. Hàm nàycho phép một chương trình xin cấp phát một vùng bộ nhớ đúngvới kích thước mà chương trình cần.Giá trị trả về:

Trong trường hợp cấp phát thành công, hàm malloc trả về một con 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ềgiá trị NULL.Nếu tham số size==0, malloc trả về con trỏ NULL

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

Ví dụ#include <stdio.h>#include <string.h>#include <alloc.h>#include <process.h>main(){

char *str;/* cấp phat bộ nhớ cho string */if ((str = (char *) malloc(10)) == NULL){

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

bộ nhớ*/}

/* copy "Hello" into string */strcpy(str, "Hello");/* display string */printf("String is %s\n", str);/* free memory */free(str);

}

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

Cấp phát độngHàm calloc (trong thư viện <stdlib.h>, <alloc.h)

Cú pháp khai báo(datatype*)calloc(n, sizeof(object));

Hàm calloc xin cấp phát một vùng nhớ kích thướcn*sizeof(object) bytes và xóa trắng vùng nhớ này. Muốn xincấp phát vùng nhớ có kích thước lớn hơn 64K, phải sử dụnghàm farcalloc() (Cấp phát xa)Giá trị trả về:

Trong trường hợp thành công, calloc trả về con trỏ tới vùng nhớ mớiđược cấp phát.Khi có lỗi cấp phát (không đủ bộ nhớ hoặc một trong hai tham sốnitems hoặc size bằng 0) thì hàm trả về NULL.

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

Ví dụ#include <stdio.h>#include <alloc.h>#include <string.h>int main(void){

char *str = NULL;/* allocate memory for string */str = (char *) calloc(10, sizeof(char));/* copy "Hello" into string */strcpy(str, "Hello");/* display string */printf("String is %s\n", str);/* free memory */free(str);return 0;

}

Page 56: [C] giao trinh c   dhbk - viet nhat

56

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

Cấp phát độngHàm farrealloc, realloc (thư viện <alloc.h>, <stdlib.h>)

Cú pháp khai báo(datatype*)realloc(buf_ptr,newsize );void far *farrealloc(void far *oldblock, unsigned long nbytes);Trong đó buf_ptr là con trỏ đang chỉ tới vùng ô nhớ được cấp phát từ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ộidung vùng nhớ cũ vào vùng mới nếu thấy cần thiếtHàm farrealloc chỉnh lại kích thước của khối nhớ block thành nbytes, sao chép nội dung của vùng nhớ cũ vào vùng nhớ mới nếu vùng nhớ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.Giá trị trả về:

Trong trương hợp thành công, cả hai hàm trả về địa chỉ của khối mớiđượ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 đầu.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 222

#include <stdio.h>#include <alloc.h>#include <string.h>int main(void){

char *str;/* allocate memory for string */str = (char *) malloc(10);/* copy "Hello" into string */strcpy(str, "Hello");printf("String is %s\n Address is %p\n", str, str);str = (char *) realloc(str, 20);printf("String is %s\n New address is %p\n", str, str);/* free memory */free(str);return 0;

}

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

Giải phóng vùng nhớ đã cấp phátHàm farfree, free (Thư Viện: <alloc.h>)

Cú pháp khai báo:void farfree(void far *block);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.

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

KÝ TỰ VÀ XÂU (CHUỖI) KÝ TỰ

Cao Tuấn Dũng2007

Page 57: [C] giao trinh c   dhbk - viet nhat

57

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

Ký tự (character)Kiểu char:

ký tự “in được” gồm: 26 chữ thường (a..z), 26 chữ hoa (A..Z), 10 chữ số (0..9), khoảng trắng, các ký tự:! “ # $ % & ‘ ( ) * + , - . / : ; < = > ? @ [ \ ] ^ _ { | } ~Các ký tự “không in được”: tab, lert (bell), newline, formfeed,...

các ký tự “in được” đặc biệt: ‘\\’, ‘\’’, ‘\”’

các ký tự “không in được” đặc biệt: \n new line\a bell\0 null character\b backspace\t horizontal tab...

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

Nhập xuất Ký tựscanf

char ch;scanf(“%c”, &ch);

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)

putchar(‘\n’);getchar: lấy ký tự từ thiết bị nhập chuẩn (stdin)

ch = getchar();

getch: lấy trực tiếp ký tự từ bàn phím không hiển thị ra màn hìnhch = getch();

getche(): lấy trực tiếp ký tự từ bàn phím và hiển thị ký tự ra mànhình.

ch = getche();

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

getchar1. #include <stdio.h>

2. int main(void)3. {4. int c;

5. /* Note that getchar reads from stdin and is line buffered; this means it will not return until you press ENTER. */

6. while ((c = getchar()) != '\n')7. printf("%c", c);

8. return 0;9. }

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

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

3. /* define some box-drawing characters */4. #define LEFT_TOP 0xDA5. #define RIGHT_TOP 0xBF6. #define HORIZ 0xC47. #define VERT 0xB38. #define LEFT_BOT 0xC09. #define RIGHT_BOT 0xD9

10. int main(void)11. {12. char i, j;13. /* draw the top of the box */14. putchar(LEFT_TOP);15. for (i=0; i<10; i++)16. putchar(HORIZ);

Page 58: [C] giao trinh c   dhbk - viet nhat

58

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

17. putchar(RIGHT_TOP);18. putchar('\n');

19. /* draw the middle */20. for (i=0; i<4; i++)21. {22. putchar(VERT);23. for (j=0; j<10; j++)24. putchar(' ');25. putchar(VERT);

26. putchar('\n');27. }28. /* draw the bottom */29. putchar(LEFT_BOT);30. for (i=0; i<10; i++)31. putchar(HORIZ);32. putchar(RIGHT_BOT);33. putchar('\n');

34. return 0;35. } Lập trình C - Việt Nhật 2007 230

Một số hàm kháckbhit: kiểm tra có phím bấm

1. /* khbit example */2. #include <conio.h>

3. int main(void)4. {5. cprintf("Press any key to continue:");6. while (!kbhit()) /* do nothing */ ;7. cprintf("\r\nA key was pressed...\r\n");8. return 0;9. }

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

Chuỗi ký tự (string)ChuỗI ký tự

Khai báo biến kiểu chuỗI ký tự.

Làm việc vớI các biến kiểu chuỗi ký tự.

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

Ký tự và ChuỗiCác hằng ký tự‘s’, ‘N’, ‘9’, ‘%’, ‘\n’, ‘ ‘, ‘\0’, …

‘\0’: ký tự nullCác hằng 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);

Page 59: [C] giao trinh c   dhbk - viet nhat

59

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

Xâu ký tựMột xâu là một mảng một chiều các ký tự

char cay[6]={‘m’,’i’,’t’,’\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

chính xác hơn xâu là mảng một chiều các ký tự kết thúc bằngký tự null (null-terminated array of char)

cay‘\0’‘t’‘i’‘m’

cay[4]cay[0]

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

Khai báo và khởi tạo một xâuDưới dạng một mảng các ký tự:char ten[10]={‘h’,’o’,’a’,’h’,’o’,’n’,’g’,’\0’};

char ten[10];ten[0]=‘h’; ten[1]=‘o’; ten[2]=‘a’; ten[3]=‘h’; ten[4]=‘o’; ten[5]=‘n’; ten[6]=‘g’;ten[7]=\0’;

char ten[10]=“hoahong”;

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” nằm đâu đó trong bộ nhớ

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

Khai báo dưới dạng mảng ký tự

Khai báo 1:

char name[5] = “Ann”;

A n n \0

Ký tự kết thúc:• Đánh dấu kết thúc xâu• ký tự đặc biệt: ’\0’• aka NUL (single L)

0x2000 0x2004

name

is 0x2000

Chỉ có thể chứatối đa 4 ký tự,

do `\0’

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

Lỗi khi tạo một chuỗi

Chú ý: không có phép gán trong kiểu dữ liệu chuỗinhư thế này là sai

char ten[10];ten = “hoahong”;

Page 60: [C] giao trinh c   dhbk - viet nhat

60

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

Chú ý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.

char a[4]=“hi”;char b[4];b = a; //???

Không:dùng toán tử == để so sánh nội dung hai chuỗi

char a[] = “hi”;char b[] = “there”;if(a==b) //???

{ }

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

Ký tự trong xâu

char name[8] = “John”;int i = 2;

printf(“Ky tu tai chi so %d la %c.\n”, i, name[i]);

Ket qua: Ky tu tai chi so 2 la h.

index 0 index 4

J o h n \0

0x3995 0x399C

name

is 0x3995

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

Ký tự trong xâu

J o X n \0

0x3995 0x399C

name

is 0x3995

Ket qua: Ten: JoXn

index 2

char name[8] = “John”;

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

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

Thư viện hàm thao tác với ký tự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ốNằm trong ctype.h

Page 61: [C] giao trinh c   dhbk - viet nhat

61

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

Danh sách các hàmPrototype Description

int isdigit( int c ) Trả về true nếu c là một chữ số và false nếu không phải

int isalpha( int c )

int isalnum( int c )

int isxdigit( int c )

int islower( int c )

int isupper( int c )

int tolower( int c )

int toupper( int c )

int isspace( int c )

int iscntrl( int c )

int ispunct( int c )

int isprint( int c )

int isgraph( int c )

Trả về true nếu c là một chữ cái và false nếu không phải

Trả về true nếu c là một chữ số hay chữ cái và false nếu khôngTrả về true nếu c là một chữ số hệ 16 và false nếu không

Trả về true nếu c là một chữ thường và false nếu không phải Trả về true nếu c là một chữ hoa và false nếu không phải

Trả về chữ thường nếu c là một chữ hoa và không thay đổi trong trường hợp ngược lạiTrả về chữ hoa nếu c là một chữ thường và không thay đổi trong trường hợp ngược lại

Trả về true nếu c là các ký tự trắng, xuống dòng ‘\n’, ‘\t’, ‘\r’ ‘\v’

Trả về true nếu c là một ký tự điều khiển false nếu không phải 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

Trả về true nếu c là một ký tự in tính cả ký tự trắng và false nếu không phải Trả về true nếu c là một ký tự in không tính ký tự trắng vàfalse nếu không phải

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

Làm việc với chuỗi#include <string.h>

Với hàm scanf và printf

1. #include <stdio.h>2. void main (void)3. {4. char name[20];5. printf (“Enter a name: “);6. scanf (“%s”, name); // there is no & before name7. printf (“Hello %s\n”, name);8. }

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

strlen()Độ dài chuỗi: Số ký tự trong chuỗi không kể null.

size_t strlen(const char *s);

1. #include <stdio.h>2. #include <string.h>

3. int main(void)4. {5. char *string = "Borland International";6. printf("%d\n", strlen(string)); // 217. return 0;8. }

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

Gán một chuỗi vào chuỗi khácgán từng ký tự trong chuỗi.

1. char str[] = “qua mang cut”;2. char newstr[30];3. for(int i = 0; i<strlen(str); i++)4. newstr[i] = str[i];5. newstr[i] = ‘\0’;

dùng hàm strcpy trong <string.h>char *strcpy(char *dest, const char *src);

chép chuỗi src sang chuỗi dest cho đến khi gặp null character

strcpy(newstr, str);

Page 62: [C] giao trinh c   dhbk - viet nhat

62

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

Ví dụ#include <stdio.h>#include <string.h>

#define MAXLENGTH 100

int main(){

char string1[MAXLENGTH];char string2[MAXLENGTH];

strcpy(string1, “Hello World!”);strcpy(string2, string1);

return 0;}

string1: “Hello World!”string2: “Hello World!”

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

Lỗi thường gặp 1

char name1[5] = “Ann”;char name2[5] = “Dave”;

name2 = name1;

Không tương thích kiểu

Example:

Error: “LValue required ...”

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

Lỗi thường gặp 2

Thiếu bộ nhớ

A n n \0

0x2000 0x2003

char name[] = “Ann”;

strcpy(name, “David”);

name

is 0x2000

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

Ghép chuỗi bằng strcat()char *strcat(char *dest, const char *src);

Ghép chuỗi src vào cuối chuỗi dest. Chiều dài chuỗi kết quả làstrlen(dest) + strlen(src)

1. char destination[25];2. char *blank = " ", *c = “C++“;3. char *turbo = "Turbo";

4. strcpy(destination, turbo);5. strcat(destination, blank);6. strcat(destination, c);7. printf("%s\n", destination);8. ...

Page 63: [C] giao trinh c   dhbk - viet nhat

63

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

char name[5];

strcpy(name, “Ann”);strcat(name, “ Smith”);

Không đủ khônggian lưu trữ ký tự

A n n S m i t

0x2000 0x2004

h \0name

is 0x2000

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

So sánh chuỗi: strcmp()

int strcmp(const char *s1, const char*s2);

kết quả: số âm nếu s1 < s20 nếu s1 == s2số dương nếu s1 > s2

Hàm strncmp()

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

so sánh hai chuỗi với chiều dài cần so sánh là maxlen

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

strncat() và strncpy()strncpychar *strncpy(char *dest, const char *src, size_t maxlen);

chép tối đa maxlen ký tự từ chuỗi src sang chuỗi dest

strncatchar *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

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

Biến đổi chuỗi sang sốSử dụng stdlib.hatoi(), atof(), atol():đổi chuỗi ký tự sang số.

int atoi(const char *s); double atof(const char *s); long atol(const char *s);

...float f;char *str = "12345.67";

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

...

Page 64: [C] giao trinh c   dhbk - viet nhat

64

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

Nhập/xuất chuỗigets: lấy chuỗi ký tự từ thiết bị nhập chuẩn stdinputs: đưa chuỗi ký tự ra thiết bị xuất chuẩn stdout

char *gets(char *s); int puts(const char *s);

vd:1. char string[80];

2. printf("Input a string:");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 254

Chuỗi ký tự với tư cách tham số hàm

Khi làm tham số hình thức, xâu được khai báo dưới dạngchar* hoặc char[]

Ví dụ:void Greet ( char* name )void Greet ( char name[] )

Những thay đổi xâu trong hàm sẽ có tác động toàn cục.

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

Ví dụ#include <stdio.h>#include <string.h>#define NAMELEN 50

/* Hien thi loi chao den nguoi dung */

void Greet ( char * name ){strcat(name, "! How are ya?");

}

int main(){char user[NAMELEN];

printf("Who are you? ");scanf("%s", user);Greet(user);printf("%s\n", user);

return 0;}

user

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

int main(){char user[NAMELEN];

printf("Who are you? ");scanf("%s", user);Greet(user);printf("%s\n", user);

return 0;}

#include <stdio.h>#include <string.h>#define NAMELEN 50

/* Hien thi loi chao don gian */

void Greet ( char * name ){strcat(name, "! How are ya?");

}

name user

Jake\0

Page 65: [C] giao trinh c   dhbk - viet nhat

65

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

int main(){char user[NAMELEN];

printf("Who are you? ");scanf("%s", user);Greet(user);printf("%s\n", user);

return 0;}

#include <stdio.h>#include <string.h>#define NAMELEN 50

/* Print a simple greeting to the user */

void Greet ( char * name ){strcat(name, "! How are ya?");

}

user

Jake! How are ya?\0

name

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

int main(){char user[NAMELEN];

printf("Who are you? ");scanf("%s", user);Greet(user);printf("%s\n", user);

return 0;}

#include <stdio.h>#include <string.h>#define NAMELEN 50

/* Print a simple greeting to the user */

void Greet ( char * name ){strcat(name, "! How are ya?");

}

user

Jake! How are ya?\0

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

Mảng các chuỗi: char * [ ]char *Words[ ] = {“hong”, “cuc”, “lan”, “nhai”,”mo”};

WordsWords[0] Words[1] Words[2] Words[3] Words[4]

h o n g \0 c u c \0 l a n \0 n h a i \0 m o \0

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

Kiểu liệt kê (enumerated type)Kiểu liệt kê khai báo một tập các hằng số theo thứ tự.

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

Khai báo giá trị khác cho các hằng.

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

Page 66: [C] giao trinh c   dhbk - viet nhat

66

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

KIỂU CẤU TRÚC (STRUCTURE)

Cao Tuấn Dũng2007

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

Khái niệm và định nghĩaTrong thực tế lập trình, chúng ta có thể sẽ cần đến nhữngkiể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ểuCó những lúc ta muốn lưu giữ đồng thời các dữ liệu kháckiểu.Ví dụ:

Tiêu đề, tên nghệ sỹ, giá bán của các CD trong cửa hàngTên người và số điện thoạiTên học sinh, ID, và điểm số….

Cấu trúc là một kiểu dữ liệu bao gồm nhiều thành phần có thểthuộc nhiều kiểu dữ liệu khác nhau. Các thành phần đượctruy nhập thông qua tên.

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

Cấu trúc (structure)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ókiểu khác nhau.

Khai báo:

struct Tên cấu trúc{

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

};

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

Khai báo kiểu cấu trúc

struct Ban{

char ten[DODAI];long dienthoai;char diachi[KICHTHUOC];

};

Mọi cấu trúcphải có tên

Các thành phầncủa cấu trúc làcác thành viên

Đây mới chỉ địnhnghĩa kiểu cấu trúc, chưa khai báo biến

Page 67: [C] giao trinh c   dhbk - viet nhat

67

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

Định nghĩa kiểu bằng typedeftypedef kiểu_đã_có tên_kiểu_mới;

trong đó : kiểu_đã_có là kiểu dữ liệu mà ta muốn đổi tên.tên_kiểu_mới là tên mới mà ta muốn đặt.

Xét câu lệnh sautypedef unsigned char byte;

sau câu lệnh này, byte được xem như là kiểu dữ liệutương đương với unsigned char và có thể được sử dụngtrong các khai báo biến như các kiểu dữ liệu khác.

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

Định nghĩa cấu trúc bằng typedeftypedef struct

{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 ;<< ... >>

} tên kiểu cấu trúc ;

typedef struct {char ho_ten[20];float diem;} hoc_sinh;

typedef struct{

char ten[DODAI];long dienthoai;char diachi[KICHTHUOC];

} Ban;

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

Định nghĩa Cấu trúc1. struct SinhVien2. {3. char *hoten;// toi da 30 ky tu4. int namsinh; // >= 19605. char *noisinh; // 3 chu cai viet tat cua noi sinh6. char *maso; // maso dai toi da 10 ky tu7. };

8. // khai bao kieu SinhVien9. typedef struct SinhVien SinhVien;

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

Kích thước của một cấu trúcKích thước kiểu dữ liệu cấu trúc:

sizeof(<<typename>>)

vd:

SinhVien_t_size = sizeof(SinhVien); // 48

Page 68: [C] giao trinh c   dhbk - viet nhat

68

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

Khai báo biến cấu trúcKhai báo biến cùng định nghĩa cấu trúcstruct hoc_sinh {

char ho_ten[20];float diem;} hs,dshs[100];

Khai báo sau khi định nghĩa kiểu bằng từ khóa structstruct hoc_sinh VietNhat101, dssv[50];

Khai báo biến cùng định nghĩa typedeftypedef struct {

char ho_ten[20];float diem;} hoc_sinh;

Khai báo biến sau định nghĩa kiểu bằng từ khóa typedefhoc_sinh hs,*ptr_hocsinh;

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

Khai báo biến cấu trúc (tt)1. struct SinhVien2. {3. char hoten[31]; // toi da 30 ky tu4. int namsinh; // >= 19605. char noisinh[4];// 3 chu cai viet tat cua noi sinh6. char maso[11]; // maso dai toi da 10 ky tu7. } X, Y, Z;

8. Khởi tạo9. struct SinhVien NguyenLe = (“Nguyen Le”, 1983, “HU”,

“301160123”);

10. Z = NguyenLe;

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

Chú ý

Khi khai báo biến cấu trúc, nếu

khai báo nhiều giá trị khởi tạo hơn số trường của kiểudữ liệu sai.

khai báo giá trị khởi tạo cho một số trường trong cấutrúc, các trường còn lại sẽ tự động được gán giá trị 0.

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

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

Toán tử thành viên: .X.hoten // “Nguyen Van X”X.namsinh // 1983

gets(X.hoten);scanf(“%d %s %s”, &X.namsinh, X.noisinh,

X.maso);Có thể thực hiện phép gán biến cấu trúc này sang biến cấutrú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áchchép từng thành phần.

Page 69: [C] giao trinh c   dhbk - viet nhat

69

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

Truy cập qua con trỏKhai báo con trỏ đến cấu trúc tương tự như các kiểu dữ liệukhác.

SinhVien *SV_ptr;

Với một con trỏ, các thành phần của cấu trúc có thể được truy nhập thông qua toán tử ->SV_ptr->namsinh = 1988;strcpy(SV_ptr->noisinh, "Ha noi");

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

Truy cập thành phần cấu trúcstruct friendStr

{char name[MAXNAME];long int phoneNumber;char street[MAXSTREET];

};struct friendStr sarah;Hoặcsarah.phoneNumber = 55559999;strcpy(sarah.name,"Sarah Finch");strcpy(sarah.street,"Firthsmith St");Hoặcscanf("%s",sarah.name);scanf("%ld",&sarah.phoneNumber);scanf("%s",sarah.street);

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

Ví dụ

#include <stdio.h>#define MAXLEN 50struct Sinhvien{

char ten[MAXLEN];float diem;

};

int main(){

struct Sinhvien svA;struct Sinhvien svB;

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));

printf("Sinh vien A: %s\t%f\n", svA.ten, svA.diem);printf("Sinh vien B: %s\t%f\n", svB.ten, svB.diem);

return 0;}

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

Chú ýKhông dùng phép so sánh == với hai cấu trúcChúng ta chỉ có thể so sánh các thành phần của cấu trúc

if (svA == svB){printf(“Trung lap du lieu.\n”);

}

if (strcmp(svA.ten, svB.ten) == 0&& (svA.diem == svB.diem) )

{printf(“Trung lap du lieu.\n”);

}

Page 70: [C] giao trinh c   dhbk - viet nhat

70

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

Truyền cấu trúc như là tham số

Như một biến bình thường biến cấu trúc có thể được truyền bằng:

- tham trị: Không làm thay đổi cấu trúc

- tham biến thông qua con trỏ: thay đổi nội dung cấu trúc

Truy nhập nội dung: (*sptr).itemĐọc qua địa chỉ: &((*sptr).item)

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

Truyền bằng tham trị

void hienthiCautruc ( Sinhvien sv ){printf("Ten\t: %s\n", sv.ten);printf("Diem\t: %.1f\n\n", sv.diem);

}

main(){Sinhvien svA = {“Dao Xuan Vu”, 9.0};hienthiCautruc(svA);

}

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

Truyền bằng tham chiếu

void nhapThongtin ( Sinhvien* sptr ){printf(“Nhap ten va ID:\n”);scanf(“%s”, (*sptr).ten ); /*chu y ngoac*/scanf(“%ld”, &((*sptr).id) );

}

int main(){Sinhvien svA;nhapThongtin(&svA);

}

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

Mảng các Cấu trúcKhai bao biến mảng các Cấu trúc cũng giống như khai báo biếnmảng trên các kiểu dữ liệu cơ bản khác.

Dùng tên mảng khi truy cập từng phần tử trong mảng các cấu trúcvà toán tử thành viên để truy cập các trường dữ liệu của từng thànhphần cấu trúc.

struct Sinhvien {char ten[20];char ID[5];float diem;} dssv[100];

dssv[0].tendssv[i].id

Page 71: [C] giao trinh c   dhbk - viet nhat

71

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

Mảng cấu trúcdssv dssv[0]chỉ đến

toàn thể structid:VN006

name: "Mai"

id:VN101

name: "Thuy"

id: VN033

name: "Phong"

id: VN087

name: "Linh"

0

1

2

3dssv[3].name cho tathành phần của struct

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

#include <stdio.h>#include <stdlib.h>

#define MAXLEN 50#define MAXN 20typedef struct {char ten[MAXLEN];float diem;

} Sinhvien;

Sinhvien readRecord ( void ){Sinhvien svmoi; printf("Nhap ten va diem: ");scanf("%s %f", sv.ten, &(sv.diem)); return svmoi;

}

void printRecord ( Sinhvien sv ){printf(" Ten: %s\n", sv.ten);printf("Diem: %.1f\n\n", sv.diem);return;

}

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

int main(){int count = 0;Sinhvien dssv[MAXN];int i; printf("Co bao nhieu sinh vien? ");scanf("%d", &count); if (count > MAXN){printf("Khong du bo nho luu tru.\n");exit(1);

}

for (i=0; i < count; i++){dssv[i] = readRecord();

} printf("\nDanh sach lop:\n\n");for (i=0; i < count; i++){

printRecord(dssv[i]);} return 0;

}

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

UnionKhai báo union được dùng để khai báo các biến dùng chungbộ nhớ.

union int_or_long {int i;long l;

} a_number;

Các thành phần của union có thể không có kích thước bằngnhau.

Kích thước bộ nhớ trong khai báo union là kích thước củakiểu dữ liệu lớn nhất có trong khai báo union.

Page 72: [C] giao trinh c   dhbk - viet nhat

72

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

Ví dụ1. union int_or_long {2. int i;3. long l;4. } a_number;5. a_number.i = 5;6. a_number.l = 100L;

7. // anonymous union8. union {9. int i;10. float f;11. };12. i = 10;13. f = 2.2;

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

TẬP TIN (FILE)

Cao Tuấn Dũng2007