Bài
1: Những khái niệm cơ bản về ngôn ngữ C
Mục tiêu:
Kết thúc bài học này,
bạn có thể:
Ø Phân biệt sự khác nhau giữa Câu lệnh, Chương
trình và Phần mềm
Ø Biết được quá trình hình thành C
Ø Nên dùng C khi nào và tại sao
Ø Nắm được cấu trúc một chương trình C
Ø Hiểu rõ khái niệm giải thuật (algorithms)
Ø Vẽ lưu đồ (flowchart)
Ø Liệt kê các ký hiệu dùng trong lưu đồ
Giới thiệu
Ngày nay, khoa học máy
tính thâm nhập vào mọi lĩnh vực. Tự động hóa hiện đang là ngành chủ chốt điều
hướng sự phát triển thế giới. Bất cứ ngành nghề nào cũng cần phải hiểu biết ít
nhiều về Công nghệ Thông tin và lập trình nói chung. Cụ thể, C là một
ngôn ngữ lập trình cấp cao mà mọi lập trình viên cần phải biết. Vì thế, trong
giáo trình này, chúng ta sẽ nghiên cứu chi tiết cấu trúc ngôn ngữ C.
Ðầu tiên chúng ta tìm hiểu sự khác nhau của những khái niệm: Lệnh (Command),
Chương trình (Program) và Phần mềm (Software).
1.1 Ra lệnh cho máy tính làm việc
Khi một máy tính được
khởi động, nó sẽ tự động thực thi một số tiến trình và xuất kết quả ra màn
hình. Ðiều này diễn ra thế nào? Câu trả lời đơn giản là nhờ vào Hệ điều hành
cài đặt bên trong máy tính. Hệ điều hành (operating system) được xem như phần
mềm hệ thống. Phần mềm này khởi động máy tính và thiết lập các thông số
ban đầu trước khi trao quyền cho người dùng. Để làm được điều này, hệ điều hành
phải được cấu tạo từ một tập hợp các chương trình. Mọi chương trình đều cố gắng
đưa ra lời giải cho một hay nhiều bài toán nào đóMọi chương trình cố gắng đưa
ra giải pháp cho một hay nhiều vấn đề. Mỗi chương trình là tập hợp các câu lệnh
giải quyết một bài toán cụ thể. Một nhóm lệnh tạo thành một chương trình và một
nhóm các chương trình tạo thành một phần mềm.
Để rõ hơn, chúng ta hãy
xem xét một thí dụ : Một người bạn đến nhà chúng ta chơi và được mời món sữa
dâu. Anh ta thấy ngon miệng và muốn xin công thức làm. Chúng ta hướng dẫn cho
anh ta làm như sau :
1. Lấy một ít sữa.
2. Đổ nước ép dâu vào.
3. Trộn hỗn hợp này và làm lạnh.
Bây giờ nếu bạn của chúng ta theo những chỉ dẫn này, họ cũng có thể tạo ra món sữa dâu tuyệt vời.
Chúng ta hãy phân tích
chỉ thị (lệnh) ở trên:
Ø Lệnh đầu tiên : Lệnh này hoàn chỉnh chưa? Nó có
trả lời được câu hỏi lấy sữa ‘ở đâu’?.
Ø Lệnh thứ hai : Một lần nữa, lệnh này không nói
rõ nước ép dâu để ‘ở đâu’.
May mắn là bạn của chúng
ta đủ thông minh để hiểu được công thức pha chế nói trên, dù rằng còn nhiều
điểm chưa rõ ràng. Do vậy nếu chúng ta muốn phổ biến cách làm, chúng ta cần bổ
sung các bước như sau :
1. Rót một ly sữa vào máy trộn.
2. Đổ thêm vào một ít nước dâu ép.
3. Ðóng nắp máy trộn
4. Mở điện và bắt đầu trộn
5. Dừng máy trộn lại
6. Nếu đã trộn đều thì tắt máy, ngược lại thì trộn
tiếp.
7. Khi đã trộn xong, rót hỗn hợp vào tô và đặt vào
tủ lạnh.
8. Ðể lạnh một lúc rồi lấy ra dùng.
So sánh hai cách hướng
dẫn nêu trên, hướng dẫn thứ hai chắc chắn hoàn chỉnh, rõ ràng hơn, ai cũng có
thể đọc và hiểu được.
Tương tự, máy tính cũng
xử lý dữ liệu dựa vào tập lệnh mà nó nhận được. Ðương nhiên các chỉ thị đưa cho
máy vi tính cũng cần phải hoàn chỉnh và có ý nghĩa rõ ràng. Những chỉ thị này
cần phải tuân thủ các quy tắc:
1. Tuần
tự
2. Có
giới hạn
3. Chính
xác.
Mỗi chỉ thị trong tập
chỉ thị được gọi là “câu lệnh” và tập các câu lệnh được gọi là “chương trình”.
Chúng ta hãy xét trường
hợp chương trình hướng dẫn máy tính cộng hai số.
Các lệnh trong chương
trình có thể là :
1. Nhập số thứ nhất và nhớ nó.
2. Nhập số thứ hai và nhớ nó.
3. Thực hiện phép cộng giữa số thứ nhất và số thứ
hai, nhớ kết quả phép cộng.
4. Hiển thị kết quả.
5. Kết thúc.
Tập lệnh trên tuân thủ
tất cả các quy tắc đã đề cập. Vì vậy, tập lệnh này là một chương trình và nó sẽ
thực hiện thành công việc cộng hai số trên máy tính.
Ghi chú: Khả năng nhớ của
con người được biết đến như là trí nhớ, khả năng nhớ dữ liệu được đưa vào máy
tính được gọi là “bộ nhớ”. Máy tính nhận dữ liệu tại một thời điểm và làm việc
với dữ liệu đó vào thời điểm khác, nghĩa là máy tính ghi dữ liệu vào trong
bộ nhớ rồi sau đó đọc ra để truy xuất các giá trị dữ liệu và làm việc với chúng.
Khi khối lượng công việc
giao cho máy tính ngày càng nên nhiều và phức tạp thì tất cả các câu lệnh không
thể được đưa vào một chương trình, chúng cần được chia ra thành một số chương
trình nhỏ hơn. Tất cả các chương trình này cuối cùng được tích hợp lại để chúng
có thể làm việc với nhau. Một tập hợp các chương trình như thế được gọi là phần
mềm.
Mối quan hệ giữa ba khái
niệm câu lệnh, chương trình và phần mềm có thể được biểu diễn bằng sơ đồ trong
hình 1.1:
Hình 1.1: Phần mềm, chương trình và câu lệnh
1.2 Ngôn ngữ C
Vào đầu những năm 70 tại
phòng thí nghiệm Bell, Dennis Ritchie đã phát triển ngôn ngữ C. C được sử dụng
lần đầu trên một hệ thống cài đặt hệ điều hành UNIX. C có nguồn gốc từ ngôn ngữ
BCPL do Martin Richards phát triển. BCPL sau đó đã được Ken Thompson phát triển
thành ngôn ngữ B, đây là người khởi thủy ra C.
Trong khi BCPL và
B không hỗ trợ kiểu dữ liệu, thì C đã có nhiều kiểu dữ liệu khác nhau. Những
kiểu dữ liệu chính gồm : kiểu ký tự (character), kiểu số nguyên (interger) và
kiểu số thực (float).
C liên kết chặt chẽ với
hệ thống UNIX nhưng không bị trói buộc vào bất cứ một máy tính hay hệ điều hành
nào. C rất hiệu quả để viết các chương trình thuộc nhiều những lĩnh vực khác
nhau.
C cũng được dùng để lập
trình hệ thống. Một chương trình hệ thống có ý nghĩa liên quan đến hệ điều hành
của máy tính hay những tiện ích hỗ trợ nó. Hệ điều hành (OS), trình thông
dịch (Interpreters), trình soạn thảo (Editors), chương trình Hợp Ngữ (Assembly)
là các chương trình hệ thống. Hệ điều hành UNIX được phát triển dựa vào C. C
đang được sử dụng rộng rãi bởi vì tính hiệu quả và linh hoạt. Trình biên dịch
(compiler) C có sẵn cho hầu hết các máy tính. Mã lệnh viết bằng C trên máy này
có thể được biên dịch và chạy trên máy khác chỉ cần thay đổi rất ít hoặc không
thay đổi gì cả. Trình biên dịch C dịch nhanh và cho ra mã đối tượng không
lỗi.
C khi thực thi cũng rất
nhanh như hợp ngữ (Assembly). Lập trình viên có thể tạo ra và bảo trì thư viện
hàm mà chúng sẽ được tái sử dụng cho chương trình khác. Do đó, những dự án lớn
có thể được quản lý dễ dàng mà tốn rất ít công sức.
1.2.1 C – Ngôn ngữ bậc trung
C được hiểu là ngôn ngữ
bậc trung bởi vì nó kết hợp những yếu tố của những ngôn ngữ cấp cao và những
chức năng của hợp ngữ (ngôn ngữ cấp thấp). C cho phép thao tác trên những thành
phần cơ bản của máy tính như bits, bytes, địa chỉ…. Hơn nữa, mã C rất dễ di
chuyển nghĩa là phần mềm viết cho loại máy tính này có thể chạy trên một
loại máy tính khác. Mặc dù C có năm kiểu dữ liệu cơ bản, nhưng nó không được
xem ngang hàng với ngôn ngữ cao cấp về mặt kiểu dữ liệu. C cho phép chuyển kiểu
dữ liệu. Nó cho phép thao tác trực tiếp trên bits, bytes, word và con trỏ
(pointer). Vì vậy, nó được dùng cho lập trình mức hệ thống.
1.2.2 C - Ngôn ngữ cấu trúc
Thuật ngữ ngôn ngữ cấu
trúc khối (block-structured language) không áp dụng với C. Ngôn ngữ cấu trúc
khối cho phép thủ tục (procedures) hay hàm (functions) được khai báo bên trong
các thủ tục và hàm khác. C không cho phép việc tạo hàm trong hàm nên nó không
phải là ngôn ngữ cấu trúc khối. Tuy nhiên, nó được xem là ngôn ngữ cấu
trúc vì nó có nhiều điểm giống với ngôn ngữ cấu trúc ALGOL, Pascal và một
số ngôn ngữ tương tự khác.
C cho phép có sự tổng
hợp của mã lệnh và dữ liệu. Ðiều này là một đặc điểm riêng biệt của ngôn ngữ
cấu trúc. Nó liên quan đến khả năng tập hợp cũng như ẩn dấu tất cả thông tin và
các lệnh khỏi phần còn lại của chương trình để dùng cho những tác vụ riêng
biệt. Ðiều này có thể thực hiện qua việc dùng các hàm hay các khối mã lệnh
(Code Block). Các hàm được dùng để định nghĩa hay
tách rời những tác vụ được yêu cầu trong chương trình. Ðiều này cho phép những
chương trình hoạt động như trong một đơn vị thống nhất. Khối mã lệnh là
một nhóm các câu lệnh chương trình được nối kết với nhau theo một trật tự logic
nào đó và cũng được xem như một đơn vị thống nhất. Một khối mã lệnh được tạo
bởi một tập hợp nhiều câu lệnh tuần tự giữa dấu ngoặc mở và đóng xoắn như dưới
đây:
do
{
i = i + 1;
.
.
.
}
while (i < 40);
Ngôn ngữ cấu trúc hỗ trợ
nhiều cấu trúc dùng cho vòng lặp (loop) như là while, do-while, và for. Những
cấu trúc lặp này giúp lập trình viên điều khiển hướng thực thi trong chương
trình.
1.3 Cấu trúc chương trình C
C có một số từ khóa,
chính xác là 32. Những từ khóa này kết hợp với cú pháp của C hình thành ngôn
ngữ C. Nhưng nhiều trình biên dịch cho C đã thêm vào những từ khóa dùng
cho việc tổ chức bộ nhớ ở những giai đoạn tiền xử lý nhất định.
Vài quy tắc khi lập
trình C như sau :
-
Tất cả từ khóa là chữ thường (không in hoa)
-
Ðoạn mã trong chương trình C có phân biệt chữ thường và chữ hoa. Ví dụ : do
while thì khác với DO WHILE
-
Từ khóa không thể dùng cho các mục đích khác như đặt tên biến (variable name)
hoặc tên hàm (function name)
-
Hàm main() luôn là hàm đầu tiên được gọi đến khi một chương trình bắt đầu
chạy (chúng ta sẽ xem xét kỹ hơn ở phần sau)
Xem xét đoạn mã chương
trình:
main
()
{
/* This is a sample program */
int i = 0;
i = i + 1;
.
.
}
Ghi chú: Những khía cạnh
khác nhau của chương trình C được xem xét qua đoạn mã trên. Ðoạn mã này xem như
là đoạn mã mẫu, nó sẽ được dùng lại trong suốt phần còn lại của giáo trình này.
1.3.1 Ðịnh nghĩa Hàm
Chương trình C được chia
thành từng đơn vị gọi là hàm. Ðoạn mã mẫu chỉ có duy nhất một hàm main().
Hệ điều hành luôn trao quyền điều khiển cho hàm main() khi một chương trình C
được thực thi. Tên hàm luôn được theo sau là cặp dấu ngoặc đơn (). Trong dấu
ngoặc đơn có thể có hay không có những tham số (parameters).
1.3.2 Dấu phân cách (Delimiters)
Sau định nghĩa hàm sẽ là
dấu ngoặc xoắn mở {. Nó thông báo điểm bắt đầu của hàm. Tương tự,
dấu ngoặc xoắn đóng } sau câu lệnh cuối trong hàm chỉ ra điểm
kết thúc của hàm. Dấu ngoặc xoắn mở đánh dấu điểm bắt đầu của một khối mã lệnh,
dấu ngoặc xoắn đóng đánh dấu điểm kết thúc của khối mã lệnh đó. Trong đoạn mã
mẫu có 2 câu lệnh giữa 2 dấu ngoặc xoắn.
Hơn nữa, đối với hàm, dấu ngoặc xoắn cũng dùng để phân định những đoạn mã trong trường hợp dùng cho cấu trúc vòng lặp và lệnh điều kiện..
1.3.3 Dấu kết thúc câu lệnh (Terminator)
Dòng int i
= 0; trong đoạn mã mẫu là một câu lệnh (statement). Một câu lệnh trong
C thì được kết thúc bằng dấu chấm phẩy (;). C không hiểu việc xuống dòng
dùng phím Enter, khoảng trắng dùng phím spacebar hay một khoảng cách do dùng
phím tab. Có thể có nhiều hơn một câu lệnh trên cùng một hàng nhưng mỗi câu
lệnh phải được kết thúc bằng dấu chấm phẩy. Một câu lệnh không được kết thúc
bằng dấu chấm phẩy được xem như một câu lệnh sai.
1.3.4 Dòng chú thích (Comment)
Những chú thích thường
được viết để mô tả công việc của một lệnh đặc biệt, một hàm hay toàn bộ chương
trình. Trình biên dịch sẽ không dịch chúng. Trong C, chú thích bắt đầu bằng ký
hiệu /* và kết thúc bằng */. Trường hợp chú thích có nhiều dòng, ta phải chú ý
ký hiệu kết thúc (*/), nếu thiếu ký hiệu này, toàn bộ chương trình sẽ bị coi
như là một chú thích. Trong đoạn mã mẫu dòng chữ "This is a sample
program" là dòng chú thích. Trong trường hợp chú thích chỉ trên một dòng
ta có thể dùng //. Ví dụ:
int a = 0; // Biến ‘a’
đã được khai báo như là một kiểu số nguyên (interger)
1.3.5 Thư viện C (Library)
Tất cả trình biên dịch C
chứa một thư viện hàm chuẩn dùng cho những tác vụ chung. Một vài bộ cài đặt C
đặt thư viện trong một tập tin (file) lớn trong khi đa số còn lại chứa nó trong
nhiều tập tin nhỏ. Khi lập trình, những hàm được chứa trong thư viện có thể
được dùng cho nhiều loại tác vụ khác nhau. Một hàm (được viết bởi một lập
trình viên) có thể được đặt trong thư viện và được dùng bởi nhiều chương trình
khi được yêu cầu. Vài trình biên dịch cho phép hàm được thêm vào thư viện chuẩn
trong khi số khác lại yêu cầu tạo một thư viện riêng.
1.4 Biên dịch và thực thi một
chương trình (Compiling and Running)
Những bước khác nhau của việc dịch một chương trình C từ mã nguồn thành mã thực thi được thực hiện như sau :
Ø Soạn thảo/Xử lý từ
Ta dùng một trình xử lý
từ (word processor) hay trình soạn thảo (editor) để viết mã nguồn (source
code). C chỉ chấp nhận loại mã nguồn viết dưới dạng tập tin văn bản chuẩn. Vài
trình biên dịch (compiler) cung cấp môi trường lập trình (xem phụ lục) gồm trình
soạn thảo.
Ø Mã nguồn
Ðây là đoạn văn bản của
chương trình mà người dùng có thể đọc. Nó là đầu vào của trình biên dịch C.
Ø Bộ tiền xử lý C
Từ mã nguồn, bước đầu
tiên là chuyển nó qua bộ tiền xử lý của C. Bộ tiền xử lý này sẽ xem xét những
câu lệnh bắt đầu bằng dấu #. Những câu lệnh này gọi là các chỉ thị tiền biên
dịch (directives). Điều này sẽ được giải thích sau. Chỉ thị tiền biên dịch thường
được đặt nơi bắt đầu chương trình mặc dù nó có thể được đặt bất cứ nơi nào
khác. Chỉ thị tiền biên dịch là những tên ngắn gọn được gán cho một tập mã
lệnh.
Ø Mã nguồn mở rộng C
Bộ tiền xử lý của C khai
triển các chỉ thị tiền biên dịch và đưa ra kết quả. Ðây gọi là mã nguồn C mở
rộng, sau đó nó được chuyển cho trình biên dịch C.
Ø Trình biên dịch C (Compiler)
Trình biên dịch C dịch
mã nguồn mở rộng thành ngôn ngữ máy để máy tính hiểu được.
Nếu chương trình quá lớn
nó có thể được chia thành những tập tin riêng biệt và mỗi tập tin có thể được
biên dịch riêng rẽ. Ðiều này giúp ích khi mà một tập tin bị thay đổi, toàn
chương trình không phải biên dịch lại.
Ø Bộ liên kết (Linker)
Mã đối tượng cùng với
những thủ tục hỗ trợ trong thư viện chuẩn và những hàm được dịch riêng lẻ khác
kết nối lại bởi Bộ liên kết để cho ra mã có thể thực thi được.
Ø Bộ nạp (Loader)
Mã thực thi được thi
hành bởi bộ nạp của hệ thống.
Tiến trình trên được mô
tả qua lưu đồ 1.2 sau :
Hình 1.2: Biên dịch và
thực thi một chương trình
1.5
Các bước lập trình giải quyết vấn đề
Chúng ta thường gặp phải
những bài toán. Để giải quyết những bài toán đó, chúng ta cần hiểu chúng trước
rồi sau đó mới hoạch định các bước cần làm .
Giả sử chúng ta muốn đi
từ phòng học đến quán ăn tự phục vụ ở tầng hầm. Ðể thực hiện việc này chúng ta
cần hiểu nó rồi tìm ra các bước giải quyết trước
khi thực thi các bước đó:
BƯỚC 1 : Rời phòng
BƯỚC 2 : Ðến cầu thang
BƯỚC 3 : Xuống tầng hầm
BƯỚC 4 : Ði tiếp đến
quán ăn tự phục vụ
Thủ tục trên liệt kê tập
hợp các bước thực hiện được xác định rõ ràng cho việc giải quyết vấn đề. Một
tập hợp các bước như vậy gọi là giải thuật (Algorithm hay gọi vắn tắt là algo
).
Một giải thuật (còn gọi
là thuật toán) có thể được định nghĩa như là một thủ tục, công thức hay cách
giải quyết vấn đề. Nó gồm một tập hợp các bước giúp đạt được lời giải.
Qua phần trên, chúng ta
thấy rõ ràng để giải quyết được một bài toán, trước tiên ta phải hiểu bài toán
đó, kế đến chúng ta cần tập hợp tất cả những thông tin liên quan tới nó. Bước
kế sẽ là xử lý những mẩu thông tin đó. Cuối cùng, chúng ta cho ra lời giải của
bài toán đó.
Giải thuật chúng ta có
là một tập hợp các bước được liệt kê dưới dạng ngôn ngữ đơn giản. Rất có thể rằng
các bước trên do hai người khác nhau viết vẫn tương tự nhau nhưng ngôn ngữ dùng
diễn tả các bước có thể khác nhau. Do đó, cần thiết có những phương pháp chuẩn
mực cho việc viết giải thuật để mọi người dễ dàng hiểu nó. Chính vì vậy , giải
thuật được viết bằng cách dùng hai phương pháp chuẩn là mã giả (pseudo code) và
lưu đồ (flowchart).
Cả hai phương pháp này
đều dùng để xác định một tập hợp các bước cần được thi hành để có được lời
giải. Liên hệ tới vấn đề đi đến quán ăn tự phục vụ trên, chúng ta đã vạch ra
một kế hoạch (thuật toán) để đến đích. Tuy nhiên, để đến nơi, chúng ta phải cần
thi hành những bước này thật sự. Tương tự, mã giả và lưu đồ chỉ đưa ra những
bước cần làm. Lập trình viên phải viết mã cho việc thực thi những bước này qua
việc dùng một ngôn ngữ nào đó.
Chi tiết về về mã giả và
lưu đồ được trình bày dưới đây.
1.5.1
Mã giả (pseudo code)
Nhớ rằng mã giả không
phải là mã thật. Mã giả sử dụng một tập hợp những từ tương tự như mã thật nhưng
nó không thể được biên dịch và thực thi như mã thật.
Chúng ta hãy xem xét mã
giả qua ví dụ sau.Ví dụ này sẽ hiển thị câu 'Hello World!'.
Ví dụ 1:
BEGIN
DISPLAY 'Hello World!'
END
Qua ví dụ trên, mỗi đoạn
mã giả phải bắt đầu với từ BEGIN hoặc START, và kết thúc với từ END hay STOP.
Ðể hiển thị giá trị nào đó, từ DISPLAY hoặc WRITE được dùng. Khi giá trị được
hiển thị là một giá trị hằng (không đổi), trong trường hợp này là (Hello
World), nó được đặt bên trong dấu nháy. Tương tự, để nhận một giá trị của người
dùng, từ INPUT hay READ được dùng.
Ðể hiểu điều này rõ hơn,
chúng ta xem xét ví dụ 2, ở ví dụ này ta sẽ nhập hai số và máy sẽ hiển thị tổng
của hai số.
Ví dụ 2:
BEGIN
INPUT A, B
DISPLAY A + B
END
Trong đoạn mã giả này,
người dùng nhập vào hai giá trị, hai giá trị này được lưu trong bộ nhớ và có
thể được truy xuất như là A và B theo thứ tự. Những vị trí được đặt tên như vậy
trong bộ nhớ gọi là biến. Chi tiết về biến sẽ được giải thích trong phần sau
của chương này. Bước kế tiếp trong đoạn mã giả sẽ hiển thị tổng của hai giá trị
trong biến A và B.
Tuy nhiên, cũng đoạn mã
trên, ta có thể bổ sung để lưu tổng của hai biến trong một biến thứ ba rồi hiển
thị giá trị biến này như trong ví dụ 3 sau đây.
Ví dụ 3:
BEGIN
INPUT A, B
C = A + B
DISPLAY C
END
Một tập hợp những chỉ
thị hay các bước trong mã giả thì được gọi chung là một cấu trúc. Có ba loại
cấu trúc : tuần tự, chọn lựa và lặp lại. Trong đoạn mã giả ta viết ở trên,chúng
ta dùng cấu trúc tuần tự. Chúng được gọi như vậy vì những chỉ thị được thi hành
tuần tự, cái này sau cái khác và bắt đầu từ điểm đầu tiên. Hai loại cấu trúc
còn lại sẽ được đề cập trong những chương sau.
1.5.2
Lưu đồ (Flowcharts)
Một lưu đồ là một hình
ảnh minh hoạ cho giải thuật. Nó vẽ ra biểu đồ của luồng chỉ thị hay những hoạt
động trong một tiến trình. Mỗi hoạt động như vậy được biểu diễn qua những ký
hiệu.
Ðể hiểu điều này rõ hơn,
chúng ta xem lưu đồ trong hình 1.3 dùng hiển thị thông điệp truyền thống ‘Hello
World!’.
Hình 1.3: Lưu đồ
Lưu đồ giống với đoạn mã
giả là cùng bắt đầu với từ BEGIN hoặc START, và kết thúc với từ END hay STOP.
Tương tự, từ khóa DISPLAY được dùng để hiển thị giá trị nào đó đến người dùng.
Tuy nhiên, ở đây, mọi từ khóa thì nằm trong những ký hiệu. Những ký hiệu khác
nhau mang một ý nghĩa tương ứng được trình bày ở bảng trong Hình 1.4.
Hình 1.4: Ký hiệu trong
lưu đồ
Ta hãy xét lưu đồ cho ví
dụ 3 như ở Hình 1.5 dưới đây.
Hình 1.5: Lưu đồ cộng
hai số
Tại bước mà giá trị của
hai biến được cộng và gán cho biến thứ ba thì xem như là một xử lý và được
trình bày bằng một hình chữ nhật.
Lưu đồ mà chúng ta
xét ở đây là đơn giản.Thông thường, lưu đồ trải rộng trên nhiều trang giấy.
Trong trường hợp như thế, biểu tượng bộ nối được dùng để chỉ điểm nối của hai
phần trong một chương trình nằm ở hai trang kế tiếp nhau. Vòng tròn chỉ sự nối
kết và phải chứa ký tự hoặc số như ở hình 1.6. Như thế, chúng ta có thể tạo
liên kết giưa hai lưu đồ chưa hoàn chỉnh.
Hình 1.6: Bộ nối
Bởi vì lưu đồ được sử
dụng để viết chương trình, chúng cần được trình bày sao cho mọi lập trình
viên hiểu chúng dễ dàng. Nếu có ba lập trình viên dùng ba ngôn ngữ lập trình
khác nhau để viết mã, bài toán họ cần giải quyết phải như nhau. Trong trường
hợp này, mã giả đưa cho lập trình viên có thể giống nhau mặc dù ngôn ngữ lập
trình họ dùng và tất nhiên là cú pháp có thể khác nhau. Nhưng kết quả
cuối cùng là một. Do đó, cần thiết phải hiểu rõ bài toán và mã giả phải được
viết cẩn thận. Chúng ta cũng kết luận rằng mã giả độc lập với ngôn ngữ lập
trình.
Vài điểm cần thiết khác
phải chú ý khi vẽ một lưu đồ :
Ê Lúc đầu chỉ tập trung vào khía cạnh logic của
bài toán và vẽ các luồng xử lý chính của lưu đồ
Ê Một lưu đồ phải có duy nhất một điểm bắt đầu
(START) và một điểm kết thúc (STOP).
Ê Không cần thiết phải mô tả từng bước của chương
trình trong lưu đồ mà chỉ cần các bước chính và có ý nghĩa cần thiết.
Chúng ta tuân theo những
cấu trúc tuần tự, mà trong đó luồng thực thi chương trình đi qua tất cả các chỉ
thị bắt đầu từ chỉ thị đầu tiên. Chúng ta có thể bắt gặp các điều kiện trong
chương trình, dựa trên các điều kiện này hướng thực thi của chương trình có thể
rẽ nhánh. Những cấu trúc cho việc rẽ nhánh như là cấu trúc chọn lựa, cấu trúc điều
kiện hay rẽ nhánh. Những cấu trúc này được đề cập chi tiết sau đây:
Ø Cấu trúc IF (Nếu)
Cấu trúc chọn lựa cơ bản
là cấu trúc ‘IF’. Ðể hiểu cấu trúc này chúng ta hãy xem xét ví dụ trong đó
khách hàng được giảm giá nếu mua trên 100 đồng. Mỗi lần khách hàng trả tiền,
một đoạn mã chương trình sẽ kiểm tra xem lượng tiền trả có quá 100 đồng không?.
Nếu đúng thế thì sẽ giảm giá 10% của tổng số tiền trả, ngược lại thì không giảm
giá.
Ðiều này được minh họa
sơ lược qua mã giả như sau:
IF khách hàng mua trên 100 thì giảm giá 10%
Cấu trúc dùng ở đây là
câu lệnh IF.
Hình thức chung cho câu lệnh IF (cấu trúc IF) như sau:
IF Điều kiện
Các câu lệnh -> Phần thân của cấu trúc IF
END IF
Một cấu trúc ‘IF’ bắt
đầu là IF theo sau là điều kiện. Nếu điều kiện là đúng (thỏa điều kiện) thì
quyền điều khiển sẽ được chuyển đến các câu lệnh trong phần thân để thực thi.
Nếu điều kiện sai (không thỏa điều kiện), những câu lệnh ở phần thân không được
thực thi và chương trình nhảy đến câu lệnh sau END IF (chấm dứt cấu trúc IF).
Cấu trúc IF phải được kết thúc bằng END IF.
Chúng ta xem ví dụ 4 cho
cấu trúc IF.
Ví dụ 4:
Ví dụ 4:
Yêu cầu: Kiểm xem một số là chẵn hay không và hiển thị thông điệp
báo nếu đúng là số chẵn,
ta xử lý như sau :
BEGIN
INPUT num
r = num MOD 2
IF r=0
Display “Number is even”
END IF
END
Ðoạn mã trên nhập một số từ người dùng,
thực hiện toán tử MOD (lấy phần dư) và kiểm tra xem phần dư có bằng 0 hay
không. Nếu bằng 0 hiển thị thông điệp, ngược lại thoát ra.
Lưu đồ cho đoạn mã giả
trên thể hiện qua hình 1.7.
Hình 1.7 : Kiểm tra số chẵn
Cú pháp của lệnh IF trong C như sau:
if (Điều kiện)
{
Câu lệnh
}
Ø Cấu
trúc IF…ELSE
Trong ví dụ 4, sẽ hay hơn nếu ta cho ra thông điệp báo rằng số đó không là số chẵn tức là số lẻ thay vì chỉ thoát ra. Ðể làm điều này ta có thể thêm câu lệnh IF khác để kiểm tra xem trường hợp số đó không chia hết cho 2. Ta xem ví dụ 5.
Ví Dụ 5:
BEGIN
INPUT num
r = num MOD 2
IF r=0
DISPLAY “Even number”
END IF
IF r<>0
DISPLAY “Odd number”
END IF
END
Ngôn ngữ lập trình cung
cấp cho chúng ta cấu trúc IF…ELSE. Dùng cấu trúc này sẽ hiệu quả và
tốt hơn để giải quyết vấn đề. Cấu trúc IF …ELSE giúp lập trình
viên chỉ làm một phép so sánh và sau đó thực thi các bước tùy theo kết quả của
phép so sánh là True (đúng) hay False (sai).
Cấu trúc chung của câu lệnh IF…ELSE như sau:
IF Điều kiện
Câu
lệnh 1
ELSE
Câu
lệnh 2
END IF
Cú pháp của cấu trúc if…else trong C như
sau:
if(Điều kiện)
{
Câu lệnh 1
}
else
{
Câu
lệnh 2
}
Nếu điều kiện thỏa (True), câu lệnh 1 được thực thi. Ngược lại, câu lệnh 2 được thực thi. Không bao giờ cả hai được thực thi cùng lúc. Vì vậy, đoạn mã tối ưu hơn cho ví dụ tìm số chẵn được viết ra như ví dụ 6.
Ví dụ 6:
BEGIN
INPUT num
r = num MOD 2
IF r
= 0
DISPLAY “Even Number”
ELSE
DISPLAY “Odd Number”
END IF
END
Lưu đồ cho đoạn mã giả
trên thể hiện qua Hình 1.8.
Hình 1.8: Số chẵn hay số lẻ
Ø Ða
điều kiện sử dụng AND/OR
Cấu trúc IF…ELSE làm giảm độ phức tạp, gia
tăng tính hữu hiệu. Ở một mức độ nào đó, nó cũng nâng cao tính dễ đọc của mã.
Các thí dụ IF chúng ta đã đề cập đến thời điểm này thì khá đơn giản. Chúng chỉ
có một điều kiện trong IF để đánh giá. Thỉnh thoảng chúng ta phải kiểm tra cho
hơn một điều kiện, thí dụ: Ðể xem xét nhà cung cấp có đạt MVS (nhà cung cấp
quan trọng nhất) không?, một công ty sẽ kiểm tra xem nhà cung cấp đó đã có làm
việc với công ty ít nhất 10 năm không? và đã có tổng doanh thu ít nhất 5,000,000
không?. Hai điều kiện thỏa mãn thì nhà cung cấp được xem như là một MVS. Do đó
toán tử AND có thể được dùng trong câu lệnh ‘IF’ như trong ví dụ 7 sau:
Ví dụ 7:
BEGIN
INPUT yearsWithUs
INPUT bizDone
IF yearsWithUs >= 10 AND bizDone
>=5000000
DISPLAY
“Classified as an MVS”
ELSE
DISPLAY “A little
more effort required!”
END IF
END
Ví dụ 7 cũng khá đơn giản, vì nó chỉ có 2
điều kiện. Ở tình huống thực tế, chúng ta có thể có nhiều điều kiện cần được
kiểm tra. Nhưng chúng ta có thể dễ dàng dùng toán tử AND để nối những điều kiện
lại giống như ta đã làm ở trên.
Bây giờ, giả sử công ty trong ví dụ trên
đổi quy định, họ quyết định đưa ra điều kiện dễ dàng hơn. Như là : Hoặc làm
việc với công ty trên 10 năm hoặc có doanh số (giá trị thương mại,giao
dịch) từ 5,000,000 trở lên. Vì vâỵ, ta thay thế toán tử AND bằng toán tử OR.
Nhớ rằng toán tử OR cho ra giá trị True (đúng) nếu chỉ cần một điều kiện là
True.
Ø Cấu
trúc IF lồng nhau
Một cách khác để thực hiện ví dụ 7 là sử
dụng cấu trúc IF lồng nhau. Cấu trúc IF lồng nhau là câu lệnh IF này nằm trong
trong câu lệnh IF khác. Chúng ta viết lại ví dụ 7 sử dụng cấu trúc IF lồng nhau
ở ví dụ 8 như sau:
Ví dụ 8:
BEGIN
INPUT yearsWithUs
INPUT bizDone
IF yearsWithUs >= 10
IF bizDone >=5000000
DISPLAY “Classified as an MVS”
ELSE
DISPLAY “A little more
effort required!”
END IF
ELSE
DISPLAY “A little more effort
required!”
END IF
END
Ðoạn mã trên thực hiện cùng nhiệm vụ nhưng
không có ‘AND’. Tuy nhiên, chúng ta có một lệnh IF (kiểm tra xem bizDone
lớn hơn hoặc bằng 5,000,000 hay không?) bên trong lệnh IF khác (kiểm tra xem
yearsWithUs lớn hơn hoặc bằng 10 hay không?). Câu lệnh IF đầu tiên kiểm tra
điều kiện thời gian nhà cung cấp làm việc với công ty có lớn hơn 10 năm hay
không. Nếu dưới 10 năm (kết quả trả về là False), nó sẽ không công nhận nhà
cung cấp là một MVS; Nếu thỏa điều kiện nó xét câu lệnh IF thứ hai, nó sẽ kiểm
tra tới điều kiện bizDone lớn hơn hoặc bằng 5,000,000 hay không. Nếu thỏa điều
kiện (kết quả trả về là True) lúc đó nhà cung cấp được xem là một MVS, nếu
không thì một thông điệp báo rằng đó không là một MVS.
Lưu đồ cho mã giả của ví
dụ 8 được trình bày qua hình 1.9.
Hình 1.9: Câu lệnh IF
lồng nhau
Mã giả trong trường hợp này của cấu trúc
IF lồng nhau tại ví dụ 8 chưa hiệu quả. Câu lệnh thông báo không thỏa
điều kiện MVS phải viết hai lần. Hơn nữa lập trình viên phải viết thêm mã nên
trình biên dịch phải xét hai điều kiện của lệnh IF, do đó lãng phí thời gian.
Ngược lại, nếu dùng toán tử AND chỉ xét tới điều kiện của câu lệnh IF một lần.
Ðiều này không có nghĩa là cấu trúc IF lồng nhau nói chung là không hiệu quả.
Nó tùy theo tình huống cụ thể mà ta dùng nó. Có khi dùng toán tử AND hiệu quả
hơn, có khi dùng cấu trúc IF lồng nhau hiệu quả hơn. Chúng ta sẽ xét một ví dụ
mà dùng cấu trúc IF lồng nhau hiệu quả hơn dùng toán tử AND.
Một
công ty định phần lương cơ bản cho công nhân dựa trên tiêu chuẩn như trong bảng
1.1.
Grade
|
Experience
|
Salary
|
E
|
2
|
2000
|
E
|
3
|
3000
|
M
|
2
|
3000
|
M
|
3
|
4000
|
Bảng 1.1: Lương cơ bản
Vì vậy, nếu một công nhân được xếp loại là
E và có hai năm kinh nghiệm thì lương là 2000, nếu ba năm kinh nghiệm thì lương
là 3000.
Mã giả dùng toán tử AND cho vấn đề trên
như ví dụ 9:
Ví dụ 9:
BEGIN
INPUT grade
INPUT exp
IF grade =”E” AND exp =2
salary=2000
ELSE
IF grade = “E” AND exp=3
salary=3000
END IF
END IF
IF grade =”M” AND exp =2
salary=3000
ELSE
IF grade = “M” AND exp=3
salary=4000
END IF
END IF
END
Câu lệnh IF đầu tiên kiểm tra xếp loại và
kinh nghiệm của công nhân. Nếu xếp loại là E và kinh nghiệm là 2 năm thì lương
là 2000, ngoài ra nếu xếp loại E, nhưng có 3 năm kinh nghiệm thì lương là 3000.
Nếu cả 2 điều kiện không thỏa thì câu lệnh
IF thứ hai cũng tương tự sẽ kiểm điều kiện xếp loại và kinh nghiệm cho công
nhân để phân định lương.
Giả sử xếp loại của một công nhân là E và
có hai năm kinh nghiệm. Lương người đó sẽ được tính theo mệnh đề IF đầu tiên.
Phần còn lại của câu lệnh IF thứ nhất được bỏ qua. Tuy nhiên, điều kiện tại
mệnh đề IF thứ hai sẽ được xét và tất nhiên là không thỏa, do đó nó kiểm tra
mệnh đề ELSE của câu lệnh IF thứ 2 và kết quả cũng là False. Ðây quả là những
bước thừa mà chương trình đã xét qua. Trong ví dụ, ta chỉ có hai câu lệnh IF
bởi vì ta chỉ xét có hai loại là E và M. Nếu có khoảng 15 loại thì sẽ tốn thời
gian và tài nguyên máy tính cho việc tính toán thừa mặc dù lương đã xác định
tại câu lệnh IF đầu tiên. Ðây dứt khoát không phải là mã nguồn hiệu quả.
Bây giờ chúng ta xét mã
giả dùng cấu trúc IF lồng nhau đã được sửa đổi trong ví dụ 10.
Ví dụ 10:
BEGIN
INPUT grade
INPUT exp
IF grade=”E”
IF exp=2
salary = 2000
ELSE
IF exp=3
salary=3000
END IF
END IF
ELSE
IF grade=”M”
IF exp=2
Salary=3000
ELSE
IF exp=3
Salary=4000
END IF
END IF
END IF
END IF
END
Ðoạn mã trên nhìn khó đọc. Tuy nhiên, nó
đem lại hiệu suất cao hơn. Chúng ta xét cùng ví dụ như trên. Nếu công
nhân được xếp loại là E và kinh nghiệm là 2 năm thì lương được tính là 2000
ngay trong bước đầu của câu lệnh IF. Sau đó, chương trình sẽ thoát ra vì không
cần thực thi thêm bất cứ lệnh ELSE nào. Do đó, không có sự lãng phí và đoạn mã
này mang lại hiệu suất cho chương trình và chương trình chạy nhanh hơn.
Ø Vòng lặp
Một chương trình máy
tính là một tập các câu lệnh sẽ được thực hiện tuần tự. Nó có thể lặp lại một
số bước với số lần lặp xác định theo yêu cầu của bài toán hoặc đến khi một số
điều kiện nhất định được thỏa.
Chẳng hạn, ta muốn viết
chương trình hiển thị tên của ta 5 lần. Ta xét mã giả dưới đây.
Ví dụ 11:
BEGIN
DISPLAY “Scooby”
DISPLAY “Scooby”
DISPLAY “Scooby”
DISPLAY “Scooby”
DISPLAY “Scooby”
END
Nếu để hiển thị tên ta
1000 lần, nếu ta viết DISPLAY “Scooby” 1000 lần thì rất tốn công sức. Ta có thể
tinh giản vấn đề bằng cách viết câu lệnh DISPLAY chỉ một lần, sau đó đặt nó
trong cấu trúc vòng lặp, và chỉ thị máy tính thực hiện lặp 1000 lần cho câu
lệnh trên.
Ta xem mã giả của cấu
trúc vòng lặp trong ví dụ 12 như sau:
Ví dụ 12:
Do loop 1000 times
DISPLAY
“Scooby”
End loop
Những câu lệnh nằm giữa
Do loop và End loop (trong ví dụ trên là lệnh DISPLAY) được thực thi 1000 lần.
Những câu lệnh này cùng với các lệnh do loop và end
loop được gọi là cấu trúc vòng lặp. Cấu trúc vòng lặp giúp lập trình
viên phát triển thành những chương trình lớn trong đó có thể yêu cầu thực thi
hàng ngàn câu lệnh. Do loop…end loop là một dạng thức tổng
quát của vòng lặp.
Ví dụ sau là cách viết
khác nhưng cũng dùng cấu trúc vòng lặp.
Ví dụ 13:
BEGIN
cnt=0
WHILE (cnt < 1000)
DO
DISPLAY “Scooby”
cnt=cnt+1
END DO
END
Hình 1.10: Cấu trúc vòng
lặp
Chú ý rằng Hình 1.10
không có ký hiệu đặc biệt nào để biểu diễn cho vòng lặp. Chúng ta dùng ký hiệu
phân nhánh để kiểm tra điều kiện và quản lý hướng đi của của chương trình bằng
các dòng chảy (flow_lines).
Tóm tắt bài học
Ø Phần
mềm là một tập hợp các chương trình.
Ø Một
chương trình là một tập hợp các chỉ thị (lệnh).
Ø Những
đoạn mã lệnh là cơ sở cho bất kỳ một chương trình C nào.
Ø Ngôn
ngữ C có 32 từ khóa.
Ø Các
bước cần thiết để giải quyết một bài toán là nghiên cứu chi tiết bài toán đó,
thu thập thông tin thích hợp, xử lý thông tin và đi đến kết quả.
Ø Một
giải thuật là một danh sách rút gọn và logic các bước để giải quyết vấn đề.
Giải thuật được viết bằng mã giả hoặc lưu đồ.
Ø Mã
giả là sự trình bày của giải thuật trong ngôn ngữ tương tự như mã thật
Ø Một
lưu đồ là sự trình bày dưới dạng biểu đồ của một giải thuật.
Ø Lưu
đồ có thể chia nhỏ thành nhiều phần và đầu nối dùng cho việc nối chúng lại tại
nơi chúng bị chia cắt.
Ø Một chương trình có thể gặp một điều kiện dựa
theo đó việc thực thi có thể được phân theo các nhánh rẽ khác nhau. Cấu trúc
lệnh như vậy gọi là cấu trúc chọn lựa, điều kiện hay cấu trúc rẽ nhánh.
Ø Cấu
trúc chọn cơ bản là cấu trúc “IF”.
Ø Cấu trúc IF …ELSE giúp lập
trình viên chỉ làm so sánh đơn và sau đó thực thi các bước tùy theo kết quả của
phép so sánh là True (đúng) hay False (sai).
Ø Cấu
trúc IF lồng nhau là câu lệnh IF này nằm trong câu lệnh IF khác.
Ø Thông thường ta cần lặp lại một số bước với số
lần lặp xác định theo yêu cầu của bài toán hoặc đến khi một số điều kiện nhất
định được thỏa. Những cấu trúc giúp làm việc này gọi là cấu trúc vòng lặp.
Kiểm tra tiến độ học tập
1. C
cho phép ____________ của mã và dữ liệu.
2. Một là
một sự trình bày dạng biểu đồ minh họa tính tuần tự của những hoạt động được
thực thi nhằm đạt được một lời giải.
3. Lưu
đồ giúp chúng ta xem xét lại và gỡ rối chương trình một cách dễ
dàng.(True / False)
4. Một
lưu đồ có thể có tuỳ ý số điểm bắt đầu và số điểm kết thúc. (True / False)
5. Một
____ cơ bản là việc thực thi tuần tự những câu lệnh đến khi một điều kiện cụ
thể nào đó là đúng (True) hay sai (False).
Bài tập tự làm
1. Viết
một đoạn mã giả và vẽ một lưu đồ để nhập một giá trị là độ 0C
(Celsius) và chuyển nó sang độ 0F (Fahrenheit). [Hướng dẫn: C/5
= (F-32)/9]
2. Viết một đoạn mã giả và
vẽ một lưu đồ để nhập điểm của một sinh viên cho các môn : Vật lý, Hóa học, và
Sinh học. Sau đó hiển thị điểm trung bình và tổng của những điểm này.
Lưu đồ ở hình 1.10 sai thì phải? chỗ Yes phải là No, chỗ ghi No là Yes?
Trả lờiXóaadmin giải thích cho em với, em ko hiểu?
Cảm ơn bạn đã góp ý!
Trả lờiXóaMình đã sửa lại hình 1.10.
Thân!
Không có bài giải cho bài tập về nhà hả admin.
Trả lờiXóa:) chào bạn Ninh Nguyen.
Trả lờiXóaCảm ơn góp ý của bạn, mình sẽ cố gắng đưa thêm bài giải lên!
Bài đọc rất bổ ích, chân thành cảm ơn admin.
Trả lờiXóaRất bổ ích, cảm ơn anh.
Trả lờiXóaBây giờ em mới hiểu được câu nói " cách tốt nhất để bạn trả ơn người thầy của mình, là hãy truyền đạt bài học đó lại cho những khác "
Bai doc cua anh rat bo ich. hy vong anh viet them nhieu bai nua
Trả lờiXóaMình vừa bước vào học CNTT nên đọc không hiểu lắm :D
Trả lờiXóaAi Có Bải Giảng Hay Video Gì Thì Gởi Mình với Nha
Mail mình là veryfast_21122012@yahoo.com
tks nha ad
ad viết hay qé ^^
What's up to every , because I am actually keen of reading this weblog's post to be updated on a regular basis. It consists of nice data. google mail sign in
Trả lờiXóa