ảnh hưởng của BCPL gián tiếp thông qua ngôn ngữ B do Ken Thompson viết vào năm 1970 cho hệ điều hành UNIX chạy trên họ máy tính PDP- 7 Từ khi ra đời ngôn ngữ lập trình C có nhiều loại ch
Trang 1CH ƯƠ NG 1 NH NG KHÁI NI M C B N V NGÔN NG C Ữ Ệ Ơ Ả Ề Ữ 3
1.1 L ch s hình th nh v phát tri n ị ử à à ể 3
1.2 Các tính ch t ấ đặ c tr ng ư 3
1.3 C u trúc c b n c a m t ch ấ ơ ả ủ ộ ươ ng trình C 3
#include <stdio.h> 5
1.4 B ch vi t, t khoá, tên ộ ữ ế ừ 5
1.4.1 B ch vi t ộ ữ ế 5
1.4.2 Tên 6
1.4.3 T khoá ừ 6
1.5 M t s ki u d li u c b n ộ ố ể ữ ệ ơ ả 6
1.6 Bi n ế 7
1.7 H ng s ằ ố 7
1.8 Bi u th c ể ứ 9
1.9 Các phép toán 9
1.9.1 Các phép toán s h c: ố ọ 9
1.9.2 Các phép toán quan h : ệ 10
1.9.3 Các phép toán logic 10
1.9.4 Các phép toán t ng, gi m ă ả 12
1.9.5 Phép toán l y a ch bi n (&) ấ đị ỉ ế 12
1.9.6 Phép toán chuy n ể đổ i ki u giá tr : ể ị 12
- Khi toán h ng trong m t phép toán có ki u khác nhau thì ki u th p h n ạ ộ ể ể ấ ơ c chuy n th nh ki u cao h n: int->long->float->double đượ ể à ể ơ 12
1.9.7 Bi u th c gán ể ứ 13
1.9.8 Bi u th c i u ki n ể ứ đ ề ệ 13
CH ƯƠ NG 2 CÁC CÂU L NH I U KHI N CH Ệ Đ Ề Ể ƯƠ NG TRÌNH 14
2.1 Câu l nh ệ đơ 14 n 2.2 Câu l nh ghép ệ 14
2.3 V o/ra à 14
2.3.1 H m printf à 14
2.3.2 H m scanf à 15
2.3.3.Ví d minh ho : ụ ạ 16
2.4 Các câu l nh i u khi n ch ệ đ ề ể ươ ng trình 16
2.4 1 Câu l nh if – else ệ 16
thay cho 16
2.4.2 C u trúc i u khi n switch ấ đ ề ể 17
a./ Cú pháp câu l nh ệ 17
2.4.3 C u trúc l p while ấ ặ 18
{ int dau,i,n; 20
2.4.4 C u trúc l p do while ấ ặ 20
2.4.5 C u trúc l p for ấ ặ 22
2.4.6 Toán t break v continue ử à 24
CH ƯƠ NG 3 CON TR VÀ M NG Ỏ Ả 26
3.1 M ng ả 26
3.1.1 Khái ni m v nh ngh a ệ à đị ĩ 26
3.1.2 Khai báo m ng ả 26
3.1.3 Truy nh p v o các ph n t c a m ng ậ à ầ ử ủ ả 26
3.1.4 Xâu kí tự 28
Trang 23.2 Con trỏ 30
3.2.1 Khái ni m v cách khai báo con tr ệ à ỏ 30
3.2.2 Con tr v a ch bi n ỏ à đị ỉ ế 30
3.2.3 S d ng các con tr ử ụ ỏ 30
3.2.4 Các phép toán trên con trỏ 31
3.2.5 Con tr ki u void ỏ ể 32
3.3 Liên h gi a con tr v m ng ệ ữ ỏ à ả 32
3.3.1 Con tr v m ng m t chi u ỏ à ả ộ ề 32
3.3.2 Con tr v xâu kí t ỏ à ự 33
3.3.3 Con tr v m ng nhi u chi u ỏ à ả ề ề 33
CH ƯƠ NG 4 C U TRÚC Ấ 34
4.1 C u trúc ấ 34
4.1.1 nh ngh a c u trúc Đị ĩ ấ 34
4.1.2 Khai báo c u trúc ấ 34
4.1.3 nh ngh a ki u b ng typedef Đị ĩ ể ằ 35
4.1.4 Truy nh p ậ đế n các th nh ph n c a c u trúc à ầ ủ ấ 36
4.1.5 Th nh ph n ki u FIELD (nhóm bit) à ầ ể 37
4.2 Ki u h p (union) ể ợ 38
CH ƯƠ NG 5 HÀM VÀ C U TRÚC CH Ấ ƯƠ NG TRÌNH 39
5.1 M ở đầ 39 u: 5 2 Ví d ụ đơ n gi n v ch ả ề ươ ng trình có h m: à 39
5 3 Quy t c xây d ng m t h m ắ ự ộ à 40
5 4 Quy t c ho t ắ ạ độ ng c a h m: ủ à 40
5 5 C u trúc t ng quát c a ch ấ ổ ủ ươ ng trình có h m: à 41
5.6 Xây d ng v s d ng h m ự à ử ụ à 41
5.6.1 Các khái ni m liên quan ệ đế n h m: à 41
5.6.2 Xây d ng h m: ự à 41
5.6.3 S d ng h m ử ụ à 42
5.6.4 Nguyên t c ho t ắ ạ độ ng c a h m ủ à 42
5.7 Các t p header ệ 43
5.8 C p l u tr v ph m vi c a các ấ ư ữ à ạ ủ đố ượ 44 i t ng 5.9 Đệ qui 47
CH ƯƠ NG 6 ĐỒ HO Ạ 48
6.1 Các ch ế độ đồ ho , h to ạ ệ ạ độ 48
2.6 nh ngh a ch ng h m Đị ĩ ồ à 62
2.7 Tham s ng m nh trong l i g i h m ố ầ đị ờ ọ à 62
2.8 B sung thêm các toán t qu n lý b nh ổ ử ả ộ ớ độ ng: new v delete à 63
CH ƯƠ NG 3 ĐỐ ƯỢ I T NG VÀ L P Ớ 63
3.1 Đố ượ 63 i t ng 3.2 L p ớ 64
3.2.1 Khai báo l p ớ 64
3.2.2 T o ạ đố ượ 65 i t ng 3.2.3 Các th nh ph n d li u: à ầ ữ ệ 66
3.2.4 H m th nh ph n (ph à à ầ ươ ng th c) ứ 66
3.2.5 T khoá private v public ừ à 66
3.3.H m thi t l p(constructor) à ế ậ 67
3.4 H m hu b (desreuctor) à ỷ ỏ 69
Trang 33.5 H m thi t l p sao chép(copy constructor) à ế ậ 70 3.6 H m b n, l p b n à ạ ớ ạ 73
CHƯƠNG 1 NHỮNG KHÁI NIỆM CƠ BẢN VỀ NGÔN NGỮ C1.1 Lịch sử hình thành và phát triển
Ngôn ngữ C do Brian W.Kerningham và Dennis M.Ritchice phát triển vào năm
1970 tại phòng thí nghiệm BELL (Hoa kỳ) với mục đích ban đầu để phát triển hệ điều hành UNIX
Phần lớn các ý tưởng quan trọng nhất của C xuất phát từ ngôn ngữ có tên BCPL
do Martin Richards nghiên cứu ảnh hưởng của BCPL gián tiếp thông qua ngôn ngữ B
do Ken Thompson viết vào năm 1970 cho hệ điều hành UNIX chạy trên họ máy tính PDP- 7
Từ khi ra đời ngôn ngữ lập trình C có nhiều loại chương trình dịch C khác nhau như: Turbo C của hãng Borland Inc, Quick C, Microsoft C, VC của hãng Microsoft Corp, Lattice C của Lattice
Sự phát triển của ngôn ngữ lập trình trong những năm 1980 đã đưa đến phong cách lập trình hướng đối tượng (OOP – Object Oriented Programing) mà một trong những ngôn ngữ rất được ưa dùng là C++ một bổ sung mới các yếu tố hướng đối tượng
ra mã máy; tiếp cận trực tiếp với các thiết bị phần cứng
Ngôn ngữ C thực hiện các cơ chế như các phép toán xử lý trực tiếp các đối tượng hợp thành, các cơ chế vào ra, phương pháp truy nhập tệp bằng những lời gọi hàm trong thư viện
C đưa ra các kết cấu điều khiển cơ bản cho các chương trình có cấu trúc; cung cấp con trỏ và khả năng định địa chỉ số học Các định nghĩa hàm không được lồng nhau1.3 Cấu trúc cơ bản của một chương trình C
Trước tiên ta xét ví du: Viết chương trình C hiện dòng thông báo “ Turbo C” ra màn hình
/* Chương trình hiện lên dòng thông báo trên màn hình*/
Trang 4}
Thực hiện chương trình:
Các bước để thực hiện chương trình này như sau:
- Tạo ra chương trình nguồn có tên VIDU.C bằng hệ soạn thảo của Turbo C hoặc trên một hệ soạn thảo nào đó
- Dịch và chương trình bằng CTRL + F9 để tạo ra một tệp chương trình nếu không có lỗi
Giải thích chương trình
Một chương trình C với bất kỳ kích thước nào đều bao gồm một số hàm, các hàm này sẽ xác định các thao tác tính toán thực tế cần phải thực hiện Các hàm của C cũng tương tự như các hàm và thủ tục của chương trình viết bằng Pascal Trong chương
trình ví dụ trên main() là một hàm như vậy Thông thường chúng ta có thể lấy bất kỳ
tên nào để đặt cho tên hàm, nhưng hàm main() là một hàm đặc biệt Chương trình C luôn bắt đầu thực hiện tại điểm đầu của hàm này và kết thúc khi hàm này kết thúc Điều này có nghĩa mọi chương trình viết bằng ngôn ngữ lập trình C đều có một và chỉ một hàm main() đặt ở đâu đó trong chương trình Hàm main() này thường gọi các hàm khác
để thực hiện công việc của chương trình, một số hàm nằm trong chương trình, số khác nằm trong các thư viện chuẩn
Hàm printf () có trong thư viện chuẩn được sử dụng mà không phải viết lại, có chức năng đưa kết quả ra thiết bị đầu ra Câu lệnh printf (“ Turbo C”); sẽ đưa ra màn hình dòng chữ nằm trong các dấu nháy kép Có thể dùng hàm printf để trình bày các đối tượng dữ liệu khác nhau
Khai báo tệp tiêu đề
Trong ngôn ngữ lập trình Pascal chặng hạn khi ta muốn sử dụng lệnh xoá màn hình “ Clrscr;” hay lệnh di chuyển con trỏ màn hình “Gotoxy(x,y)” v.v Ta thấy các hàm và thủ tục này nằm trong thư viên chuẩn CRT do đó muốn chương trình sử dụng được các hàm và thủ tục đó thì tại đầu chương trình ta phải khai báo : USES CRT;
Tương tự như vậy trong ngôn ngữ lập trình C khi sử dụng các hàm chuẩn trong các thư viện chuẩn chúng ta phải khai báo tệp tiêu đề (header file) chứa các hàm nguyên mẫu tương ứng các hàm đó, các lệnh được bắt đầu bằng #include theo sau là tệp tiêu đề
Có hai cách viết như sau:
Cách 1: #include <[đường dẫn\] tentep>
Ví dụ: #include <a:\Baitap\Bai1.C>
#include <stdio.h>
Cách 2: #include “[đường dẫn\]tentep”
Ví dụ: #include “a:\Baitap\Bai2.C”
Trang 5#include “conio.h”
Tác dụng: Trước khi dịch, chương trình dịch sẽ tìm tệp theo tentep và đường
dẫn đã chỉ ra trong #include Nếu tìm thấy thì nội dung của tệp này được gọi ra và chèn vào tệp nguồn đang xét đúng vị trí của #include Nếu không tìm thấy thì thông báo lỗi
Hai cách khai báo trên khác nhau ở chỗ Nếu tentep được chỉ ra trong khai báo
#include không có đường dẫn thì
Cách 1: tự động tìm tentep trong thư mục INCLUDE
Cách 2: tự động tìm tentep trong thư mục hiện thời nếu không có thì tìm trong
kỳ đâu trong chương trình và có thể trải trên nhiều dòng khác nhau trong chương trình
Trong chương trình viết bằng ngôn ngữ C mỗi câu lệnh có thể viết trên một hay nhiều dòng và phải kết thúc bằng dấu chấm phẩy
1.4 Bộ chữ viết, từ khoá, tên
1.4.1 Bộ chữ viết
Mỗi ngôn ngữ lập trình đều được xây dựng từ một bộ ký tự nào đó Các ký tự được nhóm lại theo nhiều cách khác nhau để lập lên các từ Đến lượt mình các từ được liên kết theo một quy tắc nào đó để tạo thành các câu lệnh Một chương trình bao gồm nhiều câu lệnh và diễn đạt một thuật toán để giải một bài toán nào đó
Ngôn ngữ C được xây dựng trên bộ ký tự sau:
Các chữ cái hoa: A B C ZCác chữ cái thường: a b c zCác chữ số: 0 1 2 9
Các kí hiệu toán học: + - * / = < >
Các dấu ngoặc: [ ] { } ( ) Các ký hiệu đặc biệt khác: , ; : / ? @ # $ % ^ & ‘ “
Các dấu ngăn cách không nhìn thấy như dấu cách, dấu nhảy cách tab, dấu xuống dòng
Dấu gạch nối dưới: _
Trang 61.4.2 Tên
Tên là một dãy ký tự : chữ, số và dấu gạch nối được dùng để chỉ tên hằng, tên biến, tên mảng, tên hàm Tên phải bắt đầu bằng một chữ hoặc dấu gạch nối Tên không được đặt trùng với từ hoá
Ví dụ các tên viết hợp lệ: Giai_Phuong_Trinh_Bac2
abc123
Ví dụ các tên viết không hợp lệ: Baitap 1
Chú ý:
-Trong ngôn ngữ lập trình C tên được phân biệt chữ hoa và chữ thường
-Thông thường chữ hoa thường được dùng để đặt tên cho các hằng, còn các đại lượng khác thì dùng chữ thường
1.4.3 Từ khoá
- Là những từ có một ý nghĩa hoàn toàn xác định trong chương trình:
- Không được dùng từ khoá để đặt tên cho các hằng, biến, mảng, hàm
- Từ khoá phải viết bằng chữ thường
Ví dụ từ khoá viết đùng: struct
Ví dụ từ khoá viết sai: Struct
1.5 Một số kiểu dữ liệu cơ bản
Tất cả các biến phải được khai báo trước và kiểu của chúng phải được mô tả ngay khi khai báo Có bốn kiểu dữ liệu cơ bản trong C là: char, int, float và double
đơn
±3.4E-38 -> ±3.4E+38 4 byte
double Số thực dấu phẩy động độ chính xác
kép
±1.7E-308 -> ±1.7E+308 8 byte
Một số float có độ chính xác là 6 chữ số sau dấu chấm thập phân Còn số double được biểu diễn với độ chính xác tới 15 chữ số sau dấu chấm thập phân
Bên cạnh đó chúng ta có thể áp dụng một số các “tiền tố” đi kèm các kiểu dữ liệu cơ bản với mục đích thay đổi phạm vi biểu diễn của biến được khai báo Có các tiền tố như là: short, long, signed (ngầm định đối với char, int), unsigned
Trang 7Dữ liệu chứa trong máy tính có thể là biến hoặc hằng
biến là đại lượng có thể thay đổi được trong quá trình tính toán
hằng là đại lượng có giá trị không thay đổi
Trang 8Được viết theo hai cách sau:
- Dạng thập phân gồm:Phần nguyên, dấu chấm thập phân, phần thập phân
Chú ý: Hằng ký tự biểu thị mã của ký tự đó trong bảng mã ASCII Do vậy một hằng ký
tự cũng có thể tham gia vào các phép toán
Ví dụ:
‘A’+10 có giá trị (65+10=75)Hằng ký tự còn có thể được viết theo cách: ‘\c1c2c3’
trong đó c1c2c3 là một số hệ 8 mà giá trị của nố chính là mã ASCII của ký tự cần biểu diễn
Ví dụ: ‘a’ hay ‘\141’
Một số ký tự đặc biệt:
Trang 9\b Xoá trái
1.7.4 Hằng xâu ký tự
- Là một dãy các ký tự đặt trong hay dấu nháy “ ”
- Xâu ký được lưu trữ trong một mảng ô nhớ liền nhau song còn thêm ô nhớ cuối cùng chứa mã là 0(ký hiệu là ‘\0’ )
Ví dụ: “Nguyen Van Anh”
Đươc tổ chức trong bộ nhớ như sau:
Chú ý: Chúng ta cần phân biệt “A” và ‘A’ Trong đó “A” được chứa trong 2 byte, còn ‘A’ chỉ mất 1 byte và nó có thể tham gia tính toán trong các biểu thức
* Hằng có thể định nghĩa bằng hai cách:
Cách 1: Dùng toán tử #define nhằm định nghĩa một hằng ký hiệu
#define <Tenhang> <Xaukytu>
Cấu trúc này định nghĩa một hằng ký hiệu có tên <Tenhang> bằng xâu kí tự Khi biên dịch chương trình, chương trình dịch thay thế các lần xuất hiện của <Tenhang> bằng xâu ký tự tương ứng
mà có các biểu thức nguyên hay biểu thức thực Các mệnh đề logic có giá trị nguyên trong đó giá trị khác 0 tương ứng mệnh đề đúng, còn giá trị 0 tương ứng mệnh đề sai Biểu thức được sử dụng trong: Vế phải của lệnh gán; làm tham số thực của các hàm; làm chỉ số; các câu lệnh if, for, while, do while; các biểu thức lớn hơn
Trang 10* Phép nhân 4*2=8
Chú ý: Nếu phép chia hai toán hạng đều nguyên thì phép chia cho kết quả là phần
nguyên của thương hai toán hạng đó
- Nếu một trong hai toán hạng là kiểu thực thì lúc này kết quả của phép chia cho
Các phép toán logic được thể hiện dưới bảng sau:
và (and) Giá trị bằng 1 khi cả 2 toán hạng có giá trị 1
(2>1)&&(5=2) 0
Phép hoặc (or) Giá trị biểu thức bằng 1 khi một trong hai toán hạng bằng 1
Hai phép toán && và || có số ưu tiên thấp hơn so với các phép toán quan hệ Tất
cả các phép toán này lại có số ưu tiên thấp hơn phép phủ định một ngôi
Các phép toán quan hệ và logic được sử dụng để thiết lập điều kiện rẽ nhánh trong lệnh if và điều khiển kết thúc chu trình trong các câu lệnh for while do while Giá
Trang 11trị của toán hạng khác 0 sẽ được coi là TRUE và ngược lại giá trị bằng 0 sẽ được coi là FALSE
Trang 121.9.4 Các phép toán tăng, giảm
Trong ngôn ngữ lập trình C đưa ra hai phép toán một ngôi để tăng và giảm các biến (nguyên và thực hoặc biến con trỏ) Toán tử tăng ++ sẽ thêm 1 vào toán hạng của
nó, toán tử giảm – sẽ trừ đi 1
Dấu phép toán ++ và có thể đứng trước hoặc đứng sau toán hạng Như vậy ta
có thể viết: ++n, n++, n,
n Sự khác nhau của ++n và n++ ở chỗ: Trong phép toán n++ thì n tăng sau khi giá trị của nó được sử dụng, còn trong ++n thì giá trị của n tăng trước khi giá trị của nó được sử dụng Tương tự đối với –n và n
Ví dụ: giả sử trước mỗi phép tính int i=3, j=15;
1.9.5 Phép toán lấy địa chỉ biến (&)
- Để lấy địa chỉ của một biến ta dùng toán tử & cụ thể như sau:
& tên_biến
Ví dụ: &x lấy địa chỉ của biến a
&n lấy địa chỉ của biến n
1.9.6 Phép toán chuyển đổi kiểu giá trị:
Việc chuyển đổi kiểu dữ liểu trong C thường diễn ra tự động trong các trường hợp sau:
- Khi toán hạng trong một phép toán có kiểu khác nhau thì kiểu thấp hơn được chuyển thành kiểu cao hơn: int->long->float->double
- Khi gán một giá trị kiểu này cho một biến (hoặc phần tử mảng) kiểu kia
Ví dụ: int c;
c=2.45;/* c sẽ nhận giá trị là 2*/
- Khi truyền giá trị cho các đối số của hàm, trong câu lệnh return của hàm
Ngoài ra ta có thể chuyển từ một kiểu giá trị này sang một kiểu giá trị khác bất
kỳ ta muốn bằng cách ép kiểu theo mẫu sau:
(Kiểu_dữ_liệu) biểu_thức
Ví dụ:
float c=7.4;
Trang 13Cách viết dưới tương đương Biến = (biến) op (Biểu_thức) trong đó op là một toán tử nào đó Giá trị của Biểu_thức sẽ được gán cho biến sau câu lệnh này
Nếu ta thêm dấu ; vào sau biểu thức gán sẽ thu được một câu lệnh gán
Biểu thức gán có thể được sử dụng trong các phép toán và các câu lệnh như các biểu thức thông thường Chẳng hạn khi viết: a=b=5; thì điều đó có nghĩa rằng gán giá trị của biểu thức b=5 cho biến a Kết quả là b=5 và a=5 Tương tự sau câu lệnh: x = (a=5) * (b=10); sẽ gán 5 cho a, 10 cho b và sau đó gán tiếp 50 cho x
1.9.8 Biểu thức điều kiện
Biểu thức điều kiện có dạng:
Biểu_thức1 ? Biểu_thức2 : Biểu_thức3
Nếu Biểu_thức1 !=0 thì giá trị của biểu thức điều kiện sẽ là biểu_thức_2, trái lại
là giá trị của biểu_thức3 Kiểu của biểu thức điều kiện là kiểu cao nhất trong các kiểu của Biểu_thức2 và biểu_thức3
Biểu thức điều kiện cũng được dùng như các biểu thức khác Ví dụ dùng câu lệnh sau để xác định giá trị lớn nhất giữa 2 số a và b:
s = (a>b) ? a: b;
Trang 14CHƯƠNG 2 CÁC CÂU LỆNH ĐIỀU KHIỂN CHƯƠNG TRÌNH2.1 Câu lệnh đơn
Một biểu thức theo sau bằng một dấu ; trở thành một câu lệnh đơn Ví dụ:
2.2 Câu lệnh ghép
Là tập hợp các câu lệnh được bao bởi hai dấu { và } Về cú pháp, bất cứ ở đâu có thể đặt được câu lệnh đơn đều có thể đặt khối lệnh ở đó Không đặt dấu ; sau một khối lệnh
fw là một số nguyên xác định độ rộng tối thiểu dành cho trường ra
Trang 15op là một số nguyên xác định số chữ số thập phân(đối với float, double)
hoặc độ dài của xâu ký tụ
:ab:
- Các ký tự chuyển dạng
char, unsigned short
cho kiểu float, double
- Danh sách các đối: Mỗi đối là một biến, biểu thức, phần tử mảng, lời gọi
hàm Giữa các đối cách nhau bởi dấu phẩy
Chú ý: Tương ứng với mỗi đối phải có một đặc tả tương ứng
2.3.2 Hàm scanf
Hàm scanf dùng để nhập dữ liệu từ bàn phím và lưu vào bộ nhớ theo địa chỉ xác
định
Dạng tổng quát của hàm:
int scanf(dong_dieu_khien, danh_sach_cac_doi);
- Dòng điều khiển: Là một xâu ký tự đặt trong dấu “ ” chỉ bao gồm các đặc tả có
dạng sau:
Trang 16%ky_tu_chuyen_dangNếu trong hàm scanf dong_dieu_khien có nhiều đặc tả thì các đặc tả viết liền vào nhau không có dấu phẩy ngăn cách giữa các đặc tả.
- Danh sách các đối: Là địa chỉ của các biến hay địa chỉ của các phần tử của mảng Nếu danh sách đối có nhiều hơn một thì giữa các đối đặt cách nhau một dấu phẩy
Tương ứng với đặc tả nào thì đối đó và mỗi đối thì phải có một đặc tả tương ứng
printf(“Ban hay nhap vao ba so a,b,c=”);
scanf(“%d%d%d”,&a,&b,&c);
printf(“Tong cua ba so la =%d”,a+b+c);
Trang 17else
{ delta=b*b-4*a*c;
if (delta<0) printf(“ Phuong trinh vo nghiem trong truong so thuc”);
else
if (delta=0) printf(“Phuong trinh co nghiem kep x1=x2=%8.2f”,-b/(2*a));else
{ printf(“Phuong trinh co hai nghiem phan biet\n”);
printf(“x1=%8.2f \n x2=%8.2f”,sqrt(delta))/(2*a), sqrt(delta))/(2*a));
} }
Trang 18Trong đó: *switch, case, default là các từ khoá
* bieu_thuc: là một biểu thúc nguyên bất kỳ
* ei:là giá trị nguyên mà biểu thức có thể nhận được Có thể là kiểu char vì
nó có thể được chuyển đổi thành kiểu int
* Những phần đặt trong hai dấu [ và ] có thể có hoặc không
b./ Sự hoạt động của cấu trúc điều khiển switch phụ thuộc vào giá trị của bieu_thuc
* Khi giá trị này bằng ei máy sẽ nhảy tới khối lệnh có nhãn case ei và thực hiện
từ Khối_lệnh_i trở đi cho tới khi gặp câu lệnh break hoặc câu lệnh goto, return hay dấu } kết thúc switch Khi đó máy sẽ thoát ra khỏi cấu trúc lệnh và thực hiện các câu lệnh tiếp theo sau cấu trúc lệnh
* Khi giá trị của bieu_thuc khác tất cả các giá trị ei thì cách làm việc của máy lại phụ thuộc vào sự có mặt hay không có mặt của default Khi có default máy nhảy tới câu lệnh có nhãn default Khi không có default máy tiến hành thực hiện các câu lệnh sau cấu trúc này
}
2.4.3 Cấu trúc lặp while
a./ Cú pháp câu lệnh
Trang 19- Công_việc có thể là một lệnh đơn hay một khối lệnh
c./ Sự hoạt động của câu lệnh while được tiến hành lần lượt được tiến hành theo các bước sau:
Bước 1: Tiến hành tính toán giá trị của bt
Bước 2: Nếu biểu thức có giá trị bằng không máy thoát khỏi chu trình và tiến hành thực hiện các câu lệnh sau câu lệnh while Nếu biểu thức có giá trị khác không máy tiến hành thực hiện Công_việc và quay về bước 1
printf(“Ban hay cho gia tri n=”);scanf(“%d”,&n);
printf(“Ban hay cho gia tri cua a=”);scantf(“%f”,&a);
while (i++<=n) { dau=dau*(-1);
tg=tg*a;
s=s+dau*tg;
} printf(“Gia tri cua tong la=%8.2f”,s);
getch();
}
Trang 20Chú ý: bt có thể là một dãy các biểu thức đặt cách nhau bởi dấu phẩy Tính đúng sai của
bt được hiểu là tính đúng sai của biểu thức cuối cùng trong dãy
printf(“Ban hay cho gia tri n=”);scanf(“%d”,&n);
printf(“Ban hay cho gia tri cua a=”);scantf(“%f”,&a);
while (tg*=a,dau*=-1,++i<n) s+=dau*tg;
printf(“Gia tri cua tong la=%8.2f”,s);
Bước 1: Thực hiện Công_việc
Bước 2: Sau khi thực hiện xong Công_việc máy tiến hành tính toán giá trị của bt.Nếu bt có giá trị khác không máy sẽ trở lại bước 1 để tiếp tục thực hiện vòng lặp mới của chu trình Nếu bt có giá trị bằng không máy sẽ ra khỏi chu trình và chuyển tới câu lệnh đứng sau cấu trúc do while
c./ Ví dụ áp dụng
Trang 21Ví dụ1:
Nhập một số giá trị từ bàn phím và đếm xem ta nhập được bao phần tử có giá trị dương Khi ta không muốn nhập thì nhập giá trị 0
Trang 22printf(“So thu: %d”,++i);scanf(“%d”,&n);
Chú ý: bt có thể là một dãy các biểu thức đặt cách nhau bởi dấu phẩy Tính đúng sai của
bt được hiểu là tính đúng sai của biểu thức cuối cùng trong dãy
printf(“So thu: %d”,i);scanf(“%d”,&n);
Trang 23a./ Cú pháp câu lệnh
for(bt1; bt2; bt3) Công_việc;
Trong đó:
- for là từ khoá
- bt1,bt2,bt3 là các biểu thức
- Công_việc có thể là một lệnh đơn hay một khối lệnh
b./ Sự hoạt động của câu lệnh for được tiến hành theo các bước sau:
Bước 1: Xác định giá trị của bt1
Bước 2: Xác định giá trị của bt2
Bước 3: Tuỳ thuộc vào tính đúng, sai của biểu thúc bt2 máy sẽ tiến hành lựa chọn một trong hai nhánh sau:
Nếu bt2 có giá trị bằng không, máy sẽ ra khỏi vòng lặp for và chuyển tới câu lệnh sau cấu trúc for
Nếu bt2 có giá trị khác không, máy sẽ tiến hành thực hiện các câu lệnh trong thân for Khi thực hiện xong Công_việc hay gặp câu lệnh continue trong thân for máy
sẽ chuyển sang buớc 4 (khởi đầu lại)
Bước 4: Tính bt3 sau đó quay lại bước 2 để bắt đầu lại vòng lặp mới của chu trình
Chú ý: Các bt1,bt2,bt3 có thể vắng mặt nhưng phải để lại dấu chấm phẩy
Nếu bt2 vắng mặt thì máy coi luôn đúng Khi đó muốn thoát khỏi vòng lặp thì phải dùng câu lệnh return, break hay goto
Các bt1,bt2,bt3 có thể gồm nhiều biểu thức cách nhau bởi dấu phẩy Nếu bt2 gồm nhiều biểu thức thì tính đúng, sai của bt2 căn cứ vào tính đúng sai của biểu thức cuối cùng
Trang 242.4.6 Toán tử break và continue
2.4.6.1 Câu lênh break
Cho phép ra khỏi for, while, do while và switch Nếu có nhiều vòng lặp lồng nhau, câu lệnh break sẽ ra khỏi chu trình(hoặc switch bên trong nhất chứa nó)
Ví dụ: Nhập vào một dãy số từ bàn phím, tìm phần tử dương đầu tiên xuất hiện trong dãy
if(a[i]>0) break;
if(i<n) printf(“\n Phan tu duong dau tien la a[%d]=%d”,i,a[i]);
else printf(“\n Tat ca dem am”);
getch();
}
2.4.6.2 Câu lệnh continue
Dùng để quay về đầu vòng lặp mới của chu trình bên trong nhất chứa nó
Ví dụ: Tìm số phần tử dương, tổng các phần tử dương và phần tử dương lớn nhất của mảng hai chiều a gồm m(m<=10) hàng, n(n<=10) cột với các phần tử là các số nguyên
Trang 25{ printf(“a[%d][%d]=”),i,j);
scanf(“%d”,&a[i][j]);
}max=a[0][0];
for(i=0;i<m;++i) for(j=0;j<n;++j) { if (a[i][j]<=0) continue;
Trang 26CHƯƠNG 3 CON TRỎ VÀ MẢNG3.1 Mảng
3.1.1 Khái niệm và định nghĩa
- Mảng(array) là dãy liên tiếp các phần tử, mỗi phần tử chứa (hay có thể chứa) một dữ liệu có cùng một kiểu và có chung một tên Có bao nhiêu kiểu biến thì cũng có bấy nhiêu kiểu mảng
- Mảng có thể có một hay nhiều chiều Chúng ta có thể khai báo mảng với số chiều là một, hai hay tuỳ ý Ngôn ngữ C không giới hạn số chiều của mảng (nếu như khả năng của máy cho phép)
3200 bytes; mảng ch bao gồm 20 kí tự chiếm 20 bytes
b) Định nghĩa kiểu bằng typedef.
- Cách viết:
Ví dụ: Định nghĩa mảng:
typedef float mang1c[20]
sau đó, ta khai báo
3.1.3 Truy nhập vào các phần tử của mảng
Trang 27Mỗi phần tử được truy nhập thông qua tên và chỉ số tương ứng, phần tử đầu tiên
có chỉ số là 0 Ví dụ: với khai báo mảng ti ở trên, ta có:
ti[0] là phần tử đầu tiên
số chiều của mảng
- Biểu thức dùng làm chỉ số có thể là thực Khi đó phần nguyên của biểu thức thự sẽ là chỉ số mảng, ví dụ:
- Khi chỉ số vượt ra ngoài kích thước mảng, máy vẫn không báo lỗi, nhưng sẽ truy nhập đến một vùng nhớ bên ngoài mảng và có thể làm rối loạn chương trình Vì vậy để đảm bảo chương trình chạy đúng, người lập trình phải tự động làm công tác kiểm tra miền của các chỉ số
Bài tập mẫu:
Lập chương trình thực hiện các thao tác sau:
- Nhập vào một dãy số nguyên
Trang 28Khi gặp một xâu kí tự, máy sẽ cấp phát một khoảng nhớ cho một mảng kiểu char
đủ lớn để chứa các kí tự của xâu và chứa thêm kí tự ‘/0’ là kí tự kết thúc xâu Mỗi kí tự của xâu được chứa trong một phần tử của mảng Như vậy xâu kí tự là một trường hợp riêng của mảng một chiều khi mỗi thành phần của mảng là một kí tự Xâu kí tự được kết thúc bằng một kí kiều đặc biệt NUL có mã ASCII bằng 0 (kí hiệu ‘\0’
Trong C không tồn tại phép toán so sánh, gán nội dung của xâu này cho xâu khác Để thực hiện công việc này C cung cấp cho người lập trình một thư viện các hàm
chuẩn, được khai báo trong tệp tiêu đề có tên là string.h Để sử dụng các hàm thao tác trên xâu, ở đầu chương trình cần phải có dòng khai báo #include <string.h>.
Một số hàm thông dụng
kí tự NUL trong xâu s
strncpy(char dest[], char source[], int n) Tương tự như strcpy, nhưng ngừng sao
chép sau n kí tự trong trường hợp không có
đủ số kí tự trong source thì hàm sẽ điền thêm các kí tự trắng vào xâu dest
hàm này độ dài xâu ch1 bằng tổng độ dài của cả hai xâu ch1 và ch2 trước lời gọi hàm
n kí tự đầu tiên của ch2
sánh theo kiểu từ điển Giá trị trả về:
0 nếu xâu ch1 bằng xâu ch2
>0 nếu xâu ch1 lớn hơn xâu ch2
<0 nếu xâu ch1 nhỏ hơn xâu ch2int strncmp(char ch[1], char ch2[], int n) Tương tự như hàm strcmp(), nhưng chỉ giới
hạn việc so sánh với n kí tự đầu tiên của hai xâu
Trang 29int stricmp(char ch[1], char ch2[]) Tương tự như hàm strcmp(), nhưng không
phân biệt chữ hoa và chữ thườngint strincmp(char ch[1], char ch2[], int n) Tương tự như hàm stricmp(), nhưng chỉ
giới hạn việc so sánh với n kí tự đầu tiên của hai xâu
xâu s, trả về địa chỉ của kí tự này
kiếm bắt đầu từ cuối xâu
tự thường
bằng kí tự c
chỉ của lần xuất hiện đầu tiên của s2 trong s1 hoặc NUL khi không tìm thấy
Ngoài ra còn có hai hàm vào ra dùng riêng cho các xâu kí tự
Trang 303.2.1 Khái niệm và cách khai báo con trỏ
Một con trỏ (pointer) là một biến mà nội dung của nó là địa chỉ của một đối tượng khác Đối tượng ở đây có thể là một biến hoặc một hàm và không phải là một hằng Việc sử dụng các biến con trỏ sẽ giúp chúng ta khai thác đến một biến thông qua địa chỉ của nó Khả năng đó cộng với khả năng tính toán linh hoạt trên các con trỏ của
C đã khiến con trỏ trở thành một công cụ mạnh để thực hiện nhiều thao tác mà thiếu nó thì không thể làm đợc hoặc rất khó khăn Các con trỏ và mảng có mối liên quan mật thiết
Khai báo một biến con trỏ theo mẫu
Kiểu_dữ_liệu*tên_con_trỏ;
với câu lệnh khai báo trên, con trỏ chưa trỏ đến địa chỉ nào cả, và nó có giá trị bằng NULL NULL là một hằng số biểu thị giá trị của con trỏ khi chưa được gán địa chỉ nào
Ví dụ: int *pn; /* Khai báo con trỏ pn chứa địa chỉ của biến nguyên*/
3.2.2 Con trỏ và địa chỉ biến
Bộ nhớ máy tính bao gồm một bảng các ô nhớ liên tiếp có thể đánh địa chỉ được Chúng ta có thể thao tác trên từng ô nhớ riêng rẽ hoặc trên một nhóm các ô nhớ liên tiếp 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 byte, một biến thực được cấp phát bốn byte Địa chỉ của biến được tính là số thứ ttự của byte đầu tiên trong dãy các bytes được cấp cho biến Vì vậy người ta phân biệt các con trỏ theo kiểu địa chỉ chứa trong các con trỏ
3.2.3 Sử dụng các con trỏ
- Toán tử một ngôi & cho ta địa chỉ của một đối tượng, như vậy câu lệnh:
p= &c;
gán địa chỉ của biến kí tự c cho con trỏ p, và ta nói rằng p “trỏ đến” c
- Toán tử một ngôi * cho ta nội dung của một đối tượng con trỏ Toán tử này cho phép truy nhập đến các đội tượng được trỏ bởi các con trỏ Giả sử rằng x,y là hai biến
số nguyên và pi là biến con trỏ int Dãy các câu lệnh sau minh hoạ cách khai báo con trỏ và sử dụng các toán tử & và *:
int x=1, y=2, z[10];
Trang 31int *pi; /* pi là một biến con trỏ kiểu nguyên */
pi = &x; /* địa chỉ của x được gán cho pi, và pi trỏ tới biến x */
*pi = 0; /* từ bây giờ x có giá trị bằng 0*/
pi = &z[0]; /* từ đây pi chứa địa chỉ của z[0], tức là địa chỉ của mảng z*/
- Nếu pi trỏ tới biến số nguyên, chúng ta có thể viết *pi thay cho x ở tất cả mọi nơi có x xuất hiện; vì vậy:
*pi = *pi +10;
thêm 10 vào *pi (nghĩa là x)
- Các toán tử một ngôi * và & có độ ưu tiên cao hơn các toán tử số học, vì vậy
- Vì con trỏ cũng là một biến, do đó chúng ta co sthể sử dụng bản thân tên các biến con trỏ trong câu lệnh Xét ví dụ sau:
int x=1, *pi, *qi;
pi = &x;
qi = pi;
câu lệnh thứ ba sao chép nội dung của pi vào trong qi, nhờ vậy mà pi và qi trỏ đến cùng một đối tượng (biến x)
3.2.4 Các phép toán trên con trỏ
- Khă năng thực hiện tính 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:
Ví dụ:
px= &x;
py = px +1; /* py trỏ đến số nguyên nằm sau x trong bộ nhớ */
Việc cộng trừ một con trỏ với một số nguyên có một ý tưởng rõ rệt nếu ta so sánh con trỏ với địa chỉ các ngội nhà là một biến có địa chỉ náo đó, các địa chỉ này được đánh số tăng dần theo một chiều nhất định Biết địa chỉ nhà này, ta có thể tính địa chỉ của nhà bên cạnh bằng cách cộng thêm 1 hoặc trừ đi 1 vào địa chỉ của căn nhà đã biết,
và cứ thế tiếp tục Điều đó có nghĩa khi cộng hoặc trừ con trỏ với một số nguyrn n,, ta
Trang 32sẽ được một địa chỉ mới chỉ đến một biến khắc nằm cách biến trước (hoặc sau) đó n vị trí
- Do phép cộng một con trỏ với một số nguyên cho ta một con trỏ, nên phép trừ hai con trỏ được coi là hợp lệ và cho kết quả 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ỏ
- Phép cộng, nhân, chia hai con trỏ là không hợp lệ (không có ý nghĩa về mặt logic)
- Có thể áp dụng các phép so sánh, phép gán cho các con trỏ với đòi hỏi các toán hạng con trỏ phải có cùng kiểu Mọi sự chuyển đổi kiểu tự động từ các kiểu khác thành các kiểu con trỏ phải được cân nhắc
- Có thể áp dụng phép toán chuyển đổi kiểu bắt buộc để chuyển đổi kiểu của một con trỏ Ví dụ: int *addr1; char *addr2; addr1 = (int *) addr2;
3.2.5 Con trỏ kiểu void
Con trỏ kiểu void được khai báo như sau:
- Các phép toán số học, so sánh không dùng được trên con trỏ void
- Con trỏ void được dùng làm đối để nhận bất kỳ kiểu địa chỉ nào từ tham số thực sự trong các lời gọi hàm Một hàm được khai báo kiểu void không quan tâm đến giá trị trả về
3.3 Liên hệ giữa con trỏ và mảng
Trong C, khái niệm con trỏ và mảng liên quan mật thiết với nhau Tất cả các thao tác mà chúng ta thực hiện chỉ thông qua chỉ số trên mảng có thể thực hiện nhờ công cụ con trỏ Tuy nhiên cùng một ý tưởng thuật toán, chươmg trình sử dụng các con trỏ nói chung nhanh hơn nhưng đồng thời khó hiểu hơn so với chương trình sử dụng các mảng
Trang 33kí pháp a[i] biểu thị thành phần thứ i+1 của mảng a Nếu pa là một con trỏ kiểu nguyên
int *pa;
khi đó phép gán: pa = &a[0] (tương đương pa = a)
đ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ỉ a[0]
sao chép nội dungcủa a[0] vào biến nguyên x
là một con trỏ kiểu char thì phép gán:
pc = “Dai hoc sư pham KT hung Yen”
là hợp lệ Khi đó câu lệnh: puts(pc) sẽ in ra màn hình dòng chữ:
Dai hoc sư pham KT hung Yen
Giữa con trỏ kiểu char và mảng kiểu char có sự khác biệt
Xét ví dụ sau:
char ch[20];
char *pc;
pc = “Dai hoc sư pham KT hung Yen” /* hợp lệ*/
ch = “Dai hoc sư pham KT hung Yen” /* không hợp lệ vì mảng kí tự là một hằng*/
3.3.3 Con trỏ và mảng nhiều chiều
Việc xử lý mảng nhiều chiều phức tạp hơn so với mảng một chiều Không phải mọi qui tắc đúng với mảng một chiều đều có thể đem ra áp dụng đối với mảng nhiều chiều
Phép toán lấy địa chỉ nói chung không dùng được đối với các thành phần của mảng nhiều chiều (trừ trường hợp mảng hai chiều số nguyên)
Trang 34để tính toán được địa chỉ của phần tử ở dòng i cột j, chúng ta dù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 nên thành ohần a[i][j] sẽ có địa chỉ là (float *)a + i*n +j
Tổng quát, nếu mảng có kiểu type và có kích thước các chiều tương ứng là n1, n2, , nk Địa chỉ thành phần a[0] [0] là (type*)a và địa chỉ của a[i1][i2] [ik] được tính:
i n
k j
k
a type +∑ ∏ +
*)
(
Để vào số liệu cho mảng nhiều chiều có thể dùng biến trung gian: đọc một giá trị
và chứa tạm vào biến trung gian, sau đó ta gán biến này cho phần tử mảng
CHƯƠNG 4 CẤU TRÚC4.1 Cấu trúc
4.1.1 Định nghĩa cấu trúc
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 được truy nhập thông qua tên Khái niệm cấu trúc trong C có nhiều nét tương tự như khái niệm về bản ghi (record) trong Pascal hay Foxpro
4.1.2 Khai báo cấu trúc
- Cú pháp:
struct [ten_cau_truc]
{ Khao báo các thành phần;
- trong đó:
struct là từ khoá đứng trước khai báo cấu trúc; tên_cấu_trúc là một tên hợp lệ
được dùng làm tên cấu trúc, tên này có thể có hoặc không; danh sách các biến cấu trúc:
liệt kê các biến có kiểu cấu trúc vừa khai báo, các biến này sẽ sử dụng trong chương trình, danh sách này có thể có hoặc không, nhưng ít nhất một trong hai hoặc là
tên_cấu_trúc hoặc danh sách các biến cấu trúc phải có mặt trong khai báo
Ví dụ:
struct hoc_sinh
{ char ho_ten[30];
float diem;
Trang 35} hs, dshs[100];
Câu lệnh này có thể tác thành hai câu lệnh như sau:
struct học_sinh
{ char ho_ten[30];
struct
{ char ho_ten[30];
float diem;
}hs, dshs[100];
4.1.3 Định nghĩa kiểu bằng typedef
Ngôn ngữ C cho phép ta đặt lại tên kiểu cho riêng mình bằng câu lệnh như sau:
typedef kiểu_đã_có tên_kiểu_mới;
tên_kiểu_mới là tên mới mà ta muốn đặt
Xét câu lệnh sau:
sau câu lệnh này, byte được xem là kiểu dữ liệu tương đương với unsigned char và có thể sử dụng trong khai báo các biến khác
typedef thường được sử dụng để định nghĩa các kiểu dữ liệu phức hợp thành một tên duy nhất để dễ dàng hơn khi viết
Trang 36t-hoc_sinh hs,dshs[100];
Để khai báo một biến con trỏ cấu trúc ta có thể sử dụng câu lệnh sau:
ptr_hoc_sinh ptrhs;
4.1.4 Truy nhập đến các thành phần của cấu trúc
Các thành phần của cấu trúc được truy nhập thông qua tên biến cấu trúc và tên thành phần Nguyên tắc chung như sau:
tên_biến_cấu trúc tên_thành_phần
chẳng hạn để truy nhập đến các thành phần của biến hs chúng ta viết như sau:
hs.ho_ten
hs.diem
Ví dụ: viết chương trình nhập vào họ tên và điểm thi của các học sinh của một lớp và
in ra danh sách các học sinh phải thi lại
Trang 37}
} while (strcmp(hoten,"")!=0);
k=0;
printf("Danh sach sinh vien thi lai la: \n");
for (i=0; i<n; i++)
- đối với các biến cấu trúc đơn ví dụ hs có thể sử dụng #define để rút gọn
“đường truy nhập” đến các cấu trúc, ví dụ:
4.1.5 Thành phần kiểu FIELD (nhóm bit)
Ngôn ngữ C cho phép chúng ta khai thác từng bit như một thành phần riêng biệt của cấu trúc Một thành phần như vậy được gọi là một field (tạm dịch là một vùng) Khai báo cho một cấu trúc có các thành phần là các field được thực hiện như một cấu trúc bình thường:
Số bit không vượt quá 15, hay độ dài tính theo bit của field không được vượt quá
16 bít Turbo C sẽ cấp phát cho flags n từ (16 bits) bằng tổng các with chi cho 16, nếu