Lập trình C - Cấu trúc dữ Liệu giải thuật Sử dụng một biểu thức mà trong đó chứa nhiều loại dữ liệu nhưng lại không biết chắc chắn kiểu dữ liệu của kết quả.. Lập trình C - Cấu trúc dữ Li
Trang 1TỔNG QUAN 1
1 MỞ ĐẦU:
1.1 Lập trình: (Programming) là một quá trình viết chương trình bằng một ngôn ngữ
nào đó mà máy tính có thể thực hiện và những người lập trình khác có thể hiểu
1.2 Các bước trong giai đoạn lập trình:
Bước 1 : GIẢI THUẬT
(i) Nghĩ ra cách giải ( giải thuật)
(ii) Làm rõ ràng giải thuật : bằng cách phân đoạn giải thuật thông qua các hình vẽ, sơ đồ Thông thường, người ta dùng lưu đồ (Flow Chart) để trình bày giải thuật
Bước 2 : VIẾT CHƯƠNG TRÌNH
(i) Viết phần lõi của thân chương trình
(ii) Thêm các phần nhập và xuất
(iii) Thêm các phần khai báo
Bước 3 : CHẠY THỬ, SỬA CHỮA
(i) Chạy thử chương trình trình nhiều lần, sửa chữa những lỗi nhỏ
(ii) Sửa chữa, cải tiến chương trình
Bước 4 : TỔNG KẾT
(i) Thêm những ghi chú cho chương trình như :
Mục đích của cả chương trình
Mục đích của 1 đoạn chương trình hay 1 phát biểu
1.3 Thuật toán (Algorithm):
1.3.1 Thuật toán: là một dãy các bước chặt chẽ và rõ ràng, xác định một trình tự
các thao tác trên một số đối tượng nào đó sao cho một số hữu hạn lần thực hiện ta thu được kết quả như mong đợi
1.3.2 Các đặc trưng của thuật toán :
Tính dừng (tính kết thúc): Một thuật toán bao giờ cũng phải dừng sau một số hữu hạn các bước thực hiện
• Phân biệt được giữa giải thuật, thuật toán, lưu đồ, mã giả và chương trình
• Từ cùng 1 chương trình, học sinh có thể lần lượt lập giải thuật, thuật toán, lưu đồ, mã giả và viết chương trình
• Làm quan với các khái niệm về biến, hằng số, kiểu dữ liệu, toán tử, lệnh gán, các đối tượng nhập xuất trong C
MỤC TIÊU
Trang 2Lập trình C - Cấu trúc dữ Liệu giải thuật Tính phổ dụng (tính chính xác): thuật toán có thể giải bất kỳ bài toán nào trong một lớp các bài toán Cụ thể là thuật toán có thể làm việc với các dữ liệu khác nhau và luôn dẫn đến một kết quả mong muốn
Ví dụ : chương trình Giải phương trình bậc hai phải cho kết quả luôn đúng với các dữ liệu số nhập vào cho a,b,c là bất kỳ (số nguyên, số thực, số dương, số âm .)
Tính duy nhất : nghĩa là với nhiều lần chạy chương trình trên cùng moat tập dữ liệu đàu vào phải cho ra cùng một kết quả
Tính rõ ràng: giải thuật phải được thể hiện bằng các câu lệnh minh bạch; các câu lệnh được sắp xếp theo thứ tự nhất định
Tính khách quan: Một giải thuật dù được viết bởi nhiều người trên nhiều máy tính vẫn phải cho kết quả như nhau
1.3.3 Một thuật toán không phải là một chương trình, thuật toán có thể được mô
tả bởi một trong ba cách:
Mã tự nhiên
Mã giả (pseudocode)
Dùng các biểu tượng được quy định để biểu diễn giải thuật (flowchart)
Thời gian để giải bài toán theo thuật toán đó quá lớn
Các điều kiện kỹ thuật cho thuật toán khó đáp ứng
(iii) Có những bài toán có thể giải được một cách hữu hiệu bằng một lời giải nào đó, nhưng lời giải này lại vi phạm một số tính chất của thuật toán Trong thực tiễn, có rất nhiều trường hợp người ta chấp nhận các cách giải thường cho kết quả tốt (tất nhiên không phải lúc nào cũng tốt) nhưng ít phức tạp, hiệu quả và khả thi
Do đó, người ta mở rộng khái niệm thuật toán (giúp cho thuật toán bớt
“cứng nhắc”) bằng một khái niệm mới là giải thuật Giải thuật là những cách giải không hoàn toàn đáp ứng đầy đủ các tính chất của một thuật toán nhưng vẫn cho kết quả gần đúng Hiện nay đã có những giải thuật đệ quy, giải thuật ngẫu nhiên, giải thuật Heuristic,
Để thuận tiện, trong tài liệu này sẽ sử dụng khái niệm giải thuật để chỉ chung cho thuật toán và giải thuật
Tóm lại, Giải thuật là một tập hợp hữu hạn của các chỉ thị hay phương cách được định nghĩa rõ ràng cho việc hoàn tất một số sự việc từ một trạng thái ban đầu cho trước; khi các chỉ thị này được áp dụng triệt để thì sẽ dẫn đến kết quả sau cùng như đã dự đoán
Trang 31.4.1 Mã tự nhiên:
1.4.1.1 Khái niệm:
Là viết nội dung chương trình bằng ngôn ngữ tự nhiên giản lược
1.4.1.2 Quy ước :
Phải dễ hiểu, dễ nhớ, nhất quán và không có sự hiểu lầm
1.4.1.3 Ví dụ : viết chương trình cho người dùng nhập 1 số nguyên dương
(n) Tính tổng các số từ 1 đến n
B1: Nhập số n B2: Tổng=0 B3: Số đang xét=1 B4: Thực hiện khi Số đang xét <=n
Cộng dồn Số đang xét vào biến Tổng Tăng số đang xét lên 1 đơn vị
Quay lại B4 B5: Xuất giá trị của Tổng
1.4.2 Mã giả ( pseudocode ):
IF <Điều kiện> THEN …ENDIF
IF < Điều kiện > THEN ELSE ENDIF WHILE < Điều kiện > DO … ENDWHILE
DO … UNTIL < Điều kiện >
WRITE … RETURN …
1.4.2.3 Ví dụ : viết chương trình cho người dùng nhập 1 số nguyên dương
(n) Tính tổng các số từ 1 đến n
Input: n Process:
Tong=0 SoDangXet=1 WHILE (SoDangXet <=n) DO Tong = Tong + SoDangXet SoDangXet = SoDangXet +1
ENDWHILE Output: Tong
Trang 4Lập trình C - Cấu trúc dữ Liệu giải thuật
1.4.3 Lưu đồ chương trình:
1.4.3.1 Khái niệm : Còn được gọi là sơ đồ khối Là sơ đồ thể hiện các bước
của giải thuật liên quan đến một vấn đề nào đó được đưa vào giải quyết bằng máy tính
1.4.3.2 Các ký hiệu dùng trong lưu đồ:
nhập xuất
Chức năng của công việc vào ra dữ liệu
xử lý Nhóm lệnh để thự hiện một chức năng nào đó của
chương trình chương
trình con
chương trình con đã định nghĩa
quyết định
Quyết định rẽ nhánh nào căn cứ vào điều kiện chỉ định được ghi trong khối Trong một số trường hợp, hình thoi được mở rộng thành 1 hình đa giác có nhiều đường ra, ứng với các giá trị của biểu thức bên trong
Hướng xử lý của lưu đồ
nối trang Điểm vào hay điểm ra của từng trang trong lưu đồ
chương trình
điểm cuối
Điểm đầu hay điểm cuối của lưu đồ
Nối Điểm vào hay điểm ra của từng phần trong lưu đồ
chương trình
1.4.3.3 Một số ví dụ biểu diễn thuật toán bằng lưu đồ:
1.4.3.3.1 Thuật toán không phân nhánh:
Ví dụ: Tính a=b2+c2 Với b và c được nhập vào
từ bàn phím (hình 1)
Begin
b, c A=b 2 +c 2
A End
(Hình 1)
Trang 51.4.3.3.2 Thuật toán có phân nhánh:
Ví dụ 1: Cho nhập 3 số, in ra giá trị lớn nhất trong 3 số
Có thể thực hiện bằng nhiều cách, trong phần này nêu lên 2 trong các cách:
Cách 1: hình 2 (dùng biến trung gian) Cách 2: hình 3 (dùng phép AND/OR/NOT trong điều kiện
Ví dụ 2: Giải phương trình bậc 1 ax+b=0 Với a,b được nhập vào(hình 4)
Ví dụ 3: Giải phương trình bậc 2 ax2 + bx + c =0 Với a, b, c được nhập vào (hình 5)
Max < c Max = c
Đ
(Hình 3)
Số lớn nhất là a
b>=a AND b>=c Số lớn nhất là bS
Đ
Trang 6Lập trình C - Cấu trúc dữ Liệu giải thuật
1.4.3.3.3 Thuật toán lặp có chu trình:
Ví dụ 4: Nhập n Tính tổng các số từ 1 đến n Minh họa sau nêu lên 2 cách
Cách 1: xét điều kiện (i<=n) trước khi tính tổng S
Cách 2: tính tổng S trước, xét đìều kiện (i<n) sau
S
Đ
(Hình 5)
Giải PTB1(b,c)
“PTVN”
delta=b*b -4ac
delta = 0 S
–b/2a
Đ Đ
Begin
n i=1; S=0
End
S Đ
(Hình 6)
S
i <=n
S = S+i
Trang 72 NGÔN NGỮ LẬP TRÌNH C:
2.1 Ngôn ngữ lập trình:
Là tập hợp các chỉ thị, dữ liệu và các nguyên tắc dùng để xây dựng một chương trình
Ngôn ngữ lập trình có thể phân loại theo hai cách:
(i) Ngôn ngữ bậc cao, ngôn ngữ bậc trung, ngôn ngữ bậc thấp
(ii) Ngôn ngữ hướng thủ tục – ngôn ngữ hướng đối tượng
C là một ngôn ngữ bậc trung có chứa các đặc trưng của cả hai loại ngôn ngữ hướng thủ tục – ngôn ngữ hướng đối tượng
2.2 Cấu trúc đơn giản của chương trình C:
// Các chỉ thị tiền xử lý
#include <tên tập tin h>
#define // Hàm chính của chương trình void main()
{ }
2.2.1 Các chỉ thị tiền xử lý:
#include <tên tập tin h>: dùng để chèn nội dung của một file khác vào
chương trình nguồn tại đúng vị trí mà chỉ thị include xuất hiện Khi lập trình
trên môi trường NET, một số tập tin loại này đã được đưa vào thư viện của
.NET nên không có phần h đi sau, VD: include <iostream>
#define: dùng để định nghĩa các tên hằng số (constant) và các macro có
phạm vi sử dụng trong toàn chương trình hoặc cho đến khi được định nghĩa
lại sau chỉ thị #undef
2.2.2 Hàm main():
Các dạng của hàm main:
Kiểu_trả_về main(int i, char *str[])
{ /* Các khai báo*/
Trang 8Lập trình C - Cấu trúc dữ Liệu giải thuật
2.3 Viết chương trình với C:
Mỗi chương trình trong C phải có một và duy nhất một hàm main Hàm này
được xem như hàm điều khiển, bởi vì nó điểu khiển (gọi thực hiện) các module khác
Các lệnh của một hàm phải đặt giữa cặp dấu {}
Cuối mỗi lệnh trong hàm phải có dấu chấm phẩy (;)
Trong ngôn ngữ C, có phân biệt ký tự hoa/thường đối với các hằng chuỗi, danh định, và từ khóa
Trên một dòng có thể chứa nhiều lệnh
Một lệnh có thể viết trên nhiều dòng, ngoại trừ các hằng chuỗi, danh định, và từ khóa
Tuy nhiên ta nên trình bày chương trình một cách rõ ràng để dễ đọc và sửa chữa, ví dụ sau đây cũng là một chương trình có thể thực hiện được nhưng nó là điển hình cho một cách trình bày chương trình vô cùng kém:
VD: Thay vì Nên sửa lại là
#include <stdlib.h>
int main() {printf(
“Hello” );
printf(“World”);return 0;}
#include <stdlib.h>
int main() { printf(“Hello” );
printf(“World”);
return 0;
}
3 BIẾN VÀ KHAI BÁO BIẾN:
3.1 Khái niệm về biến:
Biến là tên do người lập trình đặt ra dùng để tham khảo tới một vùng nhớ trong máy tính
Một biến có thể chứa một giá trị phù hợp với kiểu dữ liệu mà ta đã khai báo cho nó
Giá trị trong biến có thể thay đổi được trong chương trình
Tên biến gồm chữ cái, ký số, dấu nối (_) và không được bắt đầu bằng ký số Biến khai báo trong một khối được gọi là biến cục bộ, biến không thuộc khối nào gọi là biến toàn cục
Biến có tác dụng trong toàn khối kể từ lúc được khai báo
3.2 Cú pháp:
<data type> variable_name1, variable_name2;
Ví dụ: int sum;
long int datenum;
foat a,b,c;
Ta cũng có thể gán giá trị cho biến ngay tại thời điểm khai báo (phép gán ký hiệu bởi dấu bằng =)
int a=3,b=5;
Trang 9Vị trí khai báo biến trong chương trình:
#include <stdio.h>
void main() { //Các khai báo biến // Các phát biểu (lệnh) của chương trình
3.3 Các lỗi thường gặp khi viết chương trình:
3.3.1 Lỗi về cú pháp:
Bỏ sót cặp ngoặc đơn -( )- sau từ khóa main
Bỏ sót hoặc đánh không chính xác dấu { ở tại vị trí bắt đầu thân của một hàm
Bỏ sót hoặc đánh không chính xác dấu } ở tại vị trí kết thúc của một hàm Không đặt hằng chuỗi vào cặp dấu nháy kép “”
Thiếu dấu chấm phẩy (;) sau mỗi câu lệnh
Dư dấu chấm phẩy (;) sau từ khóa main “main();”
3.3.2 Lỗi khác:
Quên khai báo biến sử dụng trong chương trình
VD: int a=5;
a = a + b; // chưa khai báo biến b
Lưu một giá trị vào một biến nhưng không cùng kiểu dữ liệu với biến
VD: int a;
a = 1.257; //gán số thực vào biến nguyên
Sử dụng biến trong một biểu thức khi biến chưa được gán giá trị Lỗi này không được phát hiện bởi trình biên dịch) Khi đó kết quả của biểu thức có thể là một giá trị bất kỳ do đó kết quả của biểu thức là vô nghĩa
VD: int a=5, b;
a = a + b; // biến b chưa được gán giá trị
Sử dụng giá trị của phép chia không chính xác Lỗi này thường xuất hiện trong các biểu thức có nhiều toán hạng và lỗi này rất khó phát hiện
VD: cần tính biểu thức 3.2 + 2/3 + 1.5 cho kết quả sẽ bằng 4.7 (=3.2 + 0 +1.5) thay vì kết quả đúng phải bằng 5.36666666666667
(=3.2+0.6666666666667+1.5)
Trang 10Lập trình C - Cấu trúc dữ Liệu giải thuật Sử dụng một biểu thức mà trong đó chứa nhiều loại dữ liệu nhưng lại không biết chắc chắn kiểu dữ liệu của kết quả
Khi sử dụng hàm phải khai báo tiền xử lý #include <stdio.h>
printf: tên hàm, phải viết bằng chữ thường
đối mục 1,…: là các mục dữ kiện cần in ra màn hình Các đối mục này có
thể là biến, hằng hoặc biểu thức phải được định trị trước khi in ra
chuỗi định dạng: được đặt trong cặp nháy kép (" "), gồm 3 loại:
(i) Đối với chuỗi ký tự ghi như thế nào in ra giống như vậy
(ii) Đối với những ký tự chuyển đổi dạng thức cho phép kết xuất giá trị của các đối mục ra màn hình tạm gọi là mã định dạng Sau đây là các dấu mô tả định dạng:
%d Số nguyên thập phân có dấu %u Số nguyên hex không dấu
%f Số chấm động (ký hiệu thập phân) %o Số nguyên bát phân không dấu
%e Số chấm động (ký hiệu có số mũ)
(iii) Các ký tự điều khiển và ký tự đặc biệt
\a Alert (bell) Tiếng kêu bip
\b Backspace Tương tự như phím Backspace
\n Newline Xuống dòng và chuyển con nháy về đầu dòng
\r Carriage return Nhảy về đầu dòng (không xuống dòng)
\t Horizontal tab Canh cột tab ngang
\' Single quotation mark In ra dấu '
\" Double quotation mark In ra dấu "
\\ Backslash In ra dấu \
\0 Null character
Trang 114.1.4 Ví dụ:
Quy ước sử dụng trong các ví dụ:
\n Gạch dưới nét đơn Ký tự điều khiển
%d hay %5d Đậm, nghiêng ký tự chuyển đổi dạng thức
\“ Gạch dưới nét đôi Ký tự đặc biệt
_ Ký tự gạch dưới Cursor sau khi xuống dòng bằng \n
VD Lệnh sử dụng trong chương trình Kết quả in ra màn hình
_
3 printf(“TP \n\“ Ho Chi Minh \””); TP
“ Ho Chi Minh ”
4 int x=5;
printf("Gia tri cua bien x la: %d \n", x);
Gia tri cua bien x la: 5
11 int a=13, b=5;
printf("Tong cua %02d va %02d la %04d", a, b, a+b); Tong cua 13 va 05 la 0018 (v)
Giải thích
(i): %5d: in giá trị của a trong độ rộng 5 ký tự và canh phải
%1d: khi độ rộng định dạng nhỏ (ít) hơn giá trị thực sự của biến (độ rộng của 18 là 2 lớn
hơn 1), giá trị của biến vẫn được đảm bảo in đầy đủ
(ii): định số lượng số lẻ cho biến kiểu số thực
(iii): định dạng số lượng số lẻ khơng cĩ tác dụng đối với số nguyên
(iv): %-5d: tương tự như %5d nhưng canh trái giá trị của biến
(v): %04d: số 4 đi trước ký tự d là độ rộng cần biểu diễn, số 0 cho biết các khoảng trống sẽ được
thay thế bằng số 0 Lưu ý: khơng thể thay thế số 0 bằng ký tự khác, vì kết quả sẽ khơng đúng
Trang 12Lập trình C - Cấu trúc dữ Liệu giải thuật
Khi sử dụng hàm phải khai báo tiền xử lý #include <stdio.h>
scanf: tên hàm, phải viết bằng chữ thường
khung định dạng: được đặt trong cặp nháy_Bép (" ") là hình ảnh dạng dữ liệu nhập vào
đối mục 1,…: là danh sách các đối mục cách nhau bởi dấu phẩy, mỗi đối mục sẽ tiếp nhận giá trị nhập vào
4.2.4 Ví dụ:
VD Lệnh sử dụng Giải thích
1 scanf("%d", &i); %d là mã định dạng, &i là đối mục
Nếu nhập vào 12abc, biến i chỉ nhận giá trị 12 Nhập 3.4 chỉ nhận giá trị 3
2 scanf("%d%d", &a, &b); Nhập vào 2 số nguyên a, b phải cách nhau bằng khoảng
trắng (space bar) hoặc enter
5 CÁC KIỂU DỮ LIỆU:
Có ba loại dữ liệu cơ bản được dùng trong C: số nguyên (integer), số thực (floating point numbers) và ký tự (character)
long 4 –2,147,483,648 đến 2,147,483,647 LONG_MIN LONG_MAX
Trang 13Tên kiểu thước Kích Miền giá trị Nhỏ nhất Lớn nhất
float 4 3.4E +/- 38 (7 digits) FLT_MIN FLT_MAX
double 8 1.7E +/- 308 (15 digits) DBL_MIN DBL_MAX
long double 10 1.2E +/- 4932 (19 digits) LDBL_MIN LDBL_MAX
Khi ghi một số thực trong chương trình ta có sự phân biệt như sau:
(i) Có ký hiệu f phía sau là giá trị thuộc kiểu float
(ii) Có ký hiệu l phía sau là giá trị thuộc kiểu long double
(iii) Ví dụ: 9.234 thuộc kiểu double
9.234f thuộc kiểu float 9.234l thuộc kiểu long double
Các cách trình bày số thực:
Dạng thập phân chuẩn Dạng số mũ Dạng khoa học
1652
63421
.00731 000625
1.625e36.3421e47.31e-3 6.25e-4
1.625x103 6.3421x104 7.31x10-36.25x10-4
5.3 Ký tự:
Kiểu ký tự bao gồm 256 ký tự trong đó bao gồm các chữ cái (chữ thường và chữ hoa), chữ số, các dấu, một số các ký hiệu
Phân loại kiểu dữ liệu ký tự trong C:
unsigned char 1 Không có 0 to 255 Trong chương trình, để trình bày một hằng ký tự ta đặt vào dấu nháy đơn: ‘a’ ,
‘D’ , …
6 TOÁN TỬ TRONG C:
6.1 Toán tử số học:
Mỗi phép toán số học sẽ kết hợp 2 toán hạng
Phép nhân
/ Phép chia Tùy thuộc vào kiểu dữ liệu
% Phép chia lấy phần dư Chỉ áp dụng cho hai số nguyên
- Phép trừ
6.1.1 Xác định kiểu dữ liệu của kết quả trong phép toán số học:
Nếu cả hai toán hạng là số nguyên thì kết quả thuộc kiểu nguyên
Nếu có một toán hạng nào là kiểu số thực thì kết quả thuộc kiểu thực
Trang 14Lập trình C - Cấu trúc dữ Liệu giải thuật
6.1.2 Sự kết hợp và độ ưu tiên của các toán tử:
Hai phép toán 2 ngôi không bao giờ đứng cạnh nhau
Phần biểu thức được đặt trong ngoặc sẽ được ưu tiên tính toán trước
Có thể có nhiều cặp dấu ngoặc được sử dụng lồng vào nhau, khi đó biểu thức đặt ở ngoặc trong cùng có ưu tiên cao nhất
Độ ưu tiên của các phép toán theo thứ tự liệt kê ở bảng trên Nếu có 2 phép toán giống nhau trong cùng biểu thức thì thứ tự xét độ ưu tiên là từ trái sang phải
Dấu ngoặc không thể thay thế cho ký hiệu trong phép nhân
Ví du:ï không thể viết (3+4)(5+1) mà phải viết (3+4)*(5+1)
6.2 Các toán tử quan hệ ( relational operators ):
Công dụng: tạo ra các điều kiện mà dựa vào đó một chương trình có thể giải quyết vấn đề mềm dẻo, linh hoạt
Các biểu thức sử dụng toán tử quan hệ gọi là biểu thức quan hệ (relation expression)
Một biểu thức quan hệ đơn giản gồm một toán tử quan hệ kết hợp với hai biến hoặc hai giá trị hằng Các toán tử này có thể áp dụng trên các kiểu dữ liệu: số nguyên, số thực, ký tự
Các toán tử quan hệ trong C sau:
< So sánh nhỏ hơn tuoi<30
> So sánh lớn hơn chieucao >1.7
<= So sánh nhò hơn hoặc bằng trongluong<=80
>= So sánh nhò hơn hoặc bằng soluong>=100
Một biểu thức quan hệ (điều kiện) sẽ có một trong hai kết quả đúng hoặc sai Nếu đúng thì biểu thức có giá trị 1, ngược lại có giá trị 0
Một biểu thức quan hệ chỉ dùng 1 phép toán quan hệ gọi là biểu thức quan hệ đơn giản
Ví dụ: #include <stdio.h>
void main(void) { char ch1,ch2;
ch1='a';
ch2='b';
printf(“%d”,(ch1>ch2) ; // sẽ xuất ra màn hình số 0 (≈ false)
}
Trang 156.3 Toán tử logic:
Các toán tử logic: ° AND (&&)
° OR (||)
° NOT (!) Khi cần tạo ra các điều kiện phức hợp chúng ta sẽ sử dụng kết hợp giữa các toán tử quan hệ và các toán tử logic Khi đó các biểu thức quan hệ đơn giản (như +, - , , /, ) nên đặt trong cặp dấu ngoặc đơn ( )
Giá trị của biểu thức ghép được cho trong bảng sau Trong đó true =1 và false
=0:
A B A && B A || B ! A
False False False False True
False True False True True
True True True True False
Ví dụ: Ta có biểu thức sau:
• (tuoi<=30) && (cao>1.50) // biểu thức trên có giá trị bằng 1 khi
// giá trị của biến tuoi >30 và giá trị của biến cao phải >1.5
6.4 Toán tử một ngôi:
Trong chương trình chúng ta cũng thường sử dụng các lệnh tăng hoặc giảm giá trị của biến đếm đi 1
ví dụ như:
Thay vì viết như trên ta có thể viết:
Các phép toán ++, như trên gọi phép toán một ngôi
Việc đặt phép toán một ngôi trước hoặc sau tên biến có sự khác nhau khi sử dụng phép toán này chung với các phép toán khác:
(i) Nếu phép toán một ngôi đặt trước tên biến thì giá trị của biến sẽ tăng/giảm
1 trước khi thục hiện những phép toán khác
(ii) Nếu phép toán một ngôi đặt sau tên biến thì giá trị những phép toán khác sẽ được thực hiện trước sau đó mới tăng/giảm giá trị biến đi 1
Trang 16Lập trình C - Cấu trúc dữ Liệu giải thuật
6.6 Toán tử trên bit:
Toán tử trên bit chỉ có tác dụng trên các kiểu số nguyên
& And 1 & 1 = 1 1 & 0 = 0 0 & 1 = 0 0 & 0 = 0
| Or 1 | 1 =1 1 | 0 = 1 0 | 1 =1 0 | 0 = 0
1 ^ 0 = 1 0 ^ 0 = 0
>> Shift phải A >> n = A/(2n)
<< Shift trái A << n = A*(2n)
6.7 Độ ưu tiên của các phép toán:
Toán tử Độ ưu tiên Trình tự kết hợp
! ~ ++ - + * & sizeof 2 Từ phải qua trái
<< >> 5 Từ trái qua phải
< <= >= > 6 Từ trái qua phải
= += -= *= /= %= … 14 Từ phải qua trái
6.8 Các lỗi thường gặp:
Quên khai báo các biến sử dụng trong chương trình
Lưu một giá trị vào một biến nhưng không cùng kiểu dữ liệu với biến
Sử dụng biến trong một biểu thức khi nó chưa có giá trị Lỗi này thí không được phát hiện bởi rình biên dịch, khi đó giá trị của biến là một giá trị bất kỳ và kết quả của biểu thức là vô nghĩa
Sử dụng giá trị của phép chia không chính xác Lỗi này thường xuất hiện trong các biểu thức có nhiều toán hạng và lỗi này rất khó phát hiện
Ví dụ: 3.2+ 2/3+ 1.5 thì kết quả sẽ bằng 4.7 thay vì phải bằng 5.3
Sử dụng một biểu thức mà trong đó chứa nhiều loại dữ liệu nhưng lại không biết chắc chắn kiểu dữ liệu của kết quả
Trang 177 LỆNH GÁN – HẰNG:
(i) Khi dùng biến trong biểu thức bên phải dấu =
Biến này trước đó phải được gán các giá trị hợp lệ
Ví dụ:
#include <stdio.h>
void main()
{ float fdai, frong, fdientich;
fdientich =fdai * frong; // fdai và frong chưa được gán giá trị fdai=27.2;
frong=13.6;
printf( “Dien tich hinh chu nhat la: %f, fdientich”;
}
Chương trình trên sẽ cho kết quả không chính xác vì biến fdai và frong
chưa có giá trị khi dùng trong biểu thức gán
(ii) Lệnh sau là không hợp lệ: amount + 128 = 1000 + 10 + 5;
(iii) Giá trị của biểu thức gán: chính là giá trị gán cho biến
Ví dụ: nếu ta có biểu thức gán: a=5; thì bản thân biểu thức (a=5) có giá trị là 5
Vì vậy câu lệnh sau sẽ in lên màn hình số 5:
(vi) Khi kết quả của biểu thức bên phải vượt quá phạm vi của biến bên trái thì
giá trị gán vào biến sẽ không chính xác
7.1.4 Các dạng biến đổi của lệnh gán:
Khi viết chương trình chúng ta thường sử dụng các lệnh gán có dạng như sau:
Trang 18Lập trình C - Cấu trúc dữ Liệu giải thuật
Trong các trường hợp trên ta có thể sử dụng các toán tử gán +=; -=; *=;
/=; %= được cung cấp bởi C (gọi là shortcut assignment operators)
Về ý nghĩa thì các lệnh gán trong hai trường hợp trên có cùng mục đích
nhưng cách dùng shortcut assignment operators sẽ giúp chương trình chạy
nhanh hơn
7.2 Các phép biến đổi kiểu (cast):
Có hai trường hợp chuyển đổi kiểu dữ liệu:
• Trong một biểu thức chứa nhiều loại dữ liệu
• Chuyển đổi dữ liệu trong biểu thức gán
Hai trường hợp chuyển đổi trên tự động diễn ra một cách ngấm ngầm bên trong
Ngoài ra C cũng cung cấp cho người lập trình các toán tử biến đổi kiểu trực
tiếp gọi là cast operator Đây là những toán tử một ngôi
Cú pháp: datatype(expression)
datatype là kiểu dữ liệu mà ta muốn áp đặt cho cho biểu thức
Ví dụ:
#include <stdio.h>
void main(void)
{ float a=3.5f, b=3.0f;
printf(“%f,int(a*b); // a*b=10.5, nhưng kết quả chỉ in ra 10
//do giá trị đã được đổi kiểu
{ float fchuvi, fbankinh;
printf( “Nhap ban kinh hinh tron:” ;
Trang 19Nếu một literal data được sử dụng nhiều nơi trong một chương trình, thì có
khả năng chứa các lỗi tiềm ẩn, ví dụ giá trị của một literal data ghi không
thống nhất tại các vị trí trong chương trình, hoặc khi cần thay đổi giá trị của
một literal data nào đó người lập trình phải sửa ở nhiều vị trí trong chương
trình Vì vậy vừa làm mất thời gian vừa dễ sai sót Để tránh tình trạng này C
cung cấp cơ chế đặt tên cho một literal data thông qua từ khóa const gọi là khai báo hằng
7.3.2 Hằng:
Chứa dữ liệu, dữ liệu này không thể thay đổi được trong chương trình
Muốn sử dụng phải khai báo
Phải có kiểu (tương tự như biến)
Khai báo hằng có kiểu long int thì phải thêm vào cuối “L” (450000L)
Cú pháp: const <data type> <name_const> = <value>;
Ví dụ: const float PI=3.1416;
Vị trí khai báo hằng trong chương trình:
void main() { //các khai báo hằng;
//các khai báo biến;
//các lệnh khác;
}
8 CÁC HÀM TOÁN HỌC TRONG C:
Mặc dù có cung cấp các toán tử số học như + - * / nhưng vẫn không đủ để dùng; ví dụ như không có toán tử để tính lũy thừa hay căn của một số Thay vào đó C cung cấp một số hàm toán học để có thể sử dụng trong chương trình
Trước khi dùng một hàm ta cần phải biết:
• Tên của hàm muốn sử dụng
• Công dụng của hàm
• Loại dữ liệu sẽ cung cấp cho hàm
• Kiểu dữ liệu của kết quả trả về bởi hàm
Cú pháp chung của một hàm là:
Function_name (danh sách các đối số)
Khi sử dụng hàm toán học cần khai báo prototype:
# include <math.h>
Trang 20Lập trình C - Cấu trúc dữ Liệu giải thuật Một số hàm thường dùng:
Tên Hàm Công Dụng Kiểu dữ liệu của kết quả
abs(x) Tính trị tuyệt đối của số x (x có kiểu là int) int
fabs(x) Tính trị tuyệt đối của số x (x có kiểu là double) double
labs(x) Tính trị tuyệt đối của số x (x có kiểu là long int) long int
• Đối số của những hàm trên có thể là:
Số nguyên hoặc số thực
Nó có thể là hằng, biến hoặc một biểu thức
Ví dụ: #include <stdio.h>
Trang 21CÁC CẤU TRÚC ĐIỀU KHIỂN 2
1 CẤU TRÚC if – else:
1.1 Công dụng: Cấu trúc if – else chỉ cho máy tính chọn thực hiện một trong hai
dãy lệnh dựa vào kết quả của một điều kiện (biểu thức quan hệ hay biểu thức
so sánh)
1.2 Cú pháp:
if (biểu thức điều kiện) {Nhóm Lệnh 1; } else
{Nhóm Lệnh 2;}
Giải thích:
• Nếu điều kiện có kết quả <>0 thì thực hiện NhómLệnh 1,ngược lại thực hiện NhómLệnh 2
• Khi NhómLệnh1, NhómLệnh2 nhiều hơn 1 lệnh (lệnh ghép -compound
statements), thì cả nhóm lệnh phải được đặt trong cặp ngoặc nhọn ({})
Ví dụ: Viết chương trình cho người dùng nhập 1 số In ra kết quả cho biết số vừa nhập là số âm hay số dương (>=0)
else printf(“ So %f la so am”, num);
}
• Hiểu và vận dụng được các cấu trúc điều khiển để giải quyết các yêu cầu của chương trình cần thực hiện
• Từ cùng 1 chương trình cần dùng các lệnh lặp, học sinh có thể
chương trình trong đó lần lượt dùng các lệnh while, for, do
• Phân biệt được sự khác nhau giữa các lệnh lặp while, for, do Hiểu và vận dụng được khi nào nên dùng lệnh lặp while, khi nào nên dùng for và khi nào nên dùng lệnh lặp do
MỤC TIÊU
Trang 22Lập trình C - Cấu trúc dữ Liệu giải thuật
1.3 Cấu trúc if không else:
Đây là dạng biến đổi của cấu trúc trên, ở dạng này không có phần else
Cú pháp: if (biểu thức điều kiện)
Lệnh;
Giải thích: khi điều kiện có giá trị khác 0 thì lệnh sẽ được thực hiện Ngược lại sẽ không làm gì và thực hiện các lệnh sau đó (nếu có) Cũng như trên, lệnh cũng có thể là một lệnh ghép
Ví du1: Chương trình sau cho phép nhập 3 số nguyên, sau đó cho biết số lớn nhất trong
3 số vừa nhập
#include <stdio.h>
void main()
{ int num1, num2, num3, max;
printf(“Nhap so thu nhat:”);
if (max<num3) max=num3;
printf(“so lon nhat trong so vua nhap la: %d,max”;
}
1.4 Cấu trúc if lồng nhau:
Cho phép trong mỗi phần của if hoặc else có thể chứa một cấu trúc if – else khác Toàn bộ một cấu trúc if – else được xem như một câu lệnh đơn
Ví dụ:
Chương trình sau đây cho nhập điểm,
in ra xếp loại Biết cáchxếp loại dựa
trên bảng sau:
else
if (diem <=7)
Trang 23printf(“Trung binh”);
else
if (diem <=9) printf(“Kha”);
else
printf(“Gioi”);
}
2 CẤU TRÚC switch:
2.1 Công dụng: Với các bài toán phải chọn một trong nhiều trường hợp nếu viết
theo cấu trúc if – else ta nhận thấy khó khăn khi đọc và theo dõi mạch chương
trình, trong trường hợp này ta nên sử dụng cấu trúc switch
• Biểu thức: có thể là biến hoặc biểu thức
• case: Nếu kết quả của biểu thức sau switch bằng với giá trị đi sau case nào thì thực hiện các lệnh thuộc về case đó (bắt đầu từ dòng lệnh ngay dưới case cho đến khi gặp lệnh break)
• Default: Nếu như giá trị của biểu thức không bằng một giá trị nào trong các giá trị có trong cấu trúc switch thì các lệnh thuộc default sẽ được thực hiện :
• Lệnh break: có công dụng thoát khỏi một cấu trúc tại thời điểm nó được gọi Trong trường hợp này nó được dùng để thoát khỏi switch sau khi đã thực
hiện một nhóm lệnh thuộc về một nhãn nào đó Nếu không có lệnh này thì
Trang 24Lập trình C - Cấu trúc dữ Liệu giải thuật sau khi thực hiện xong các lệnh cần thiết nó sẽ thực hiện tiếp các lệnh của các trường hợp bên dưới
{ unsigned short int so;
printf(“Nhap mot so nguyen : ");
} Chương trìnhï sau cho phép nhập một ký tự, sau đó cho biết ký tự vừa nhập có phải là một nguyên âm hay không
} }
Trang 252.5 Các lỗi thường gặp:
Dùng toán tử gán trong biểu thức quan hệ
Khi có nhiều lệnh thuộc về if hoặc else không đặt giữa cặp ngoặc { }
Trong cấu trúc switch thiếu break ở những vị trí cần thiết
3 CÁC CẤU TRÚC LẶP
3.1 Cấu trúc while:
Biểu thức ĐiềuKiện phải được đặt trong cặp ngoặc đơn
NhómLệnh bên dưới biểu thức ĐiềuKiện sẽ được thực hiện lặp đi lặp lại khi mà biểu thức ĐiềuKiện vẫn có giá trị khác không Như vậy tất nhiên ở đâu đó trong đoạn lệnh của while phải có một lệnh làm thay đổi giá trị của biểu thức ĐiềuKiện
Câu lệnh bên dưới ĐiềuKiện phải là một lệnh duy nhất hoặc là một lệnh
ghép (nhiều lệnh đặt vào trong {})
3.1.3 Hoạt động của while như sau:
Kiểm tra giá trị của biểu thức ĐiềuKiện
Nếu biểu thức ĐiềuKiện có giá trị khác không
• Thực hiện lệnh bên dưới
• Quay lại kiểm tra biểu thức ĐiềuKiện
Ngược lại: kết thúc cấu trúc while
Hình minh họa tiến trình hoạt động của while
Điểm vào vòng lặp while
Kiểm Tra giá trị của BTDK
Giá trị của BTĐK bằng 0 (sai) Kết thúc
vòng lặphil
Giá trị của BTĐK khác 0 (đúng)
Thực hiện NhómLệnh
của while
Quay lại kiểm tra BTĐK
Trang 26Lập trình C - Cấu trúc dữ Liệu giải thuật
3.1.4 Cấu trúc while thường được dùng khi:
Cần thực hiện nhiều lần (lặp đị, lặp lại) một nhóm lệnh
Trước khi cho nhóm lệnh thực hiện, cần kiểm tra một số điều kiện
3.2 Cấu trúc for :
3.2.3 Hoạt động của for:
3.2.4 Cấu trúc for thường được dùng khi:
Cần thực hiện nhiều lần (lặp đị, lặp lại) một nhóm lệnh
Số lần lặp đã được xác định trước
Thực hiện các lệnh khởi tạo
Kiểm Tra giá trị của BTDK
Giá trị của BTĐK bằng 0 (sai)
Kết thúc vòng lặp for
Giá trị của BTĐK khác 0 (đúng)
Thực hiện NhómLệnh
của for
Quay lại kiểm tra BTĐK
Điểm vào vòng lặp for
Thực hiện các lệnh tác
động đến BTĐK
Trang 273.3 Cấu trúc do-while:
3.3.1 Công dụng:
Cả hai vòng lặp while và for điều kiểm tra BTĐK trước khi bắt đầu thực hiện
lệnh của vòng lặp Vì vậy, có khả năng lệnh của vòng lặp không được thực hiện lần nào vì ngay lần kiểm tra đầu tiên kết quả của BTĐK đã bằng 0 Trong một vài trường hợp khi sử dụng vòng lặp ta cần nó thực hiện ít nhất là một lần, ví dụ như ta muốn một chương trình có thể thực hiện nhiều lần theo ý muốn của người sử dụng
Ví dụ: #include <stdio.h>
if (so%2==0) printf(“ \nso vua nhap la so chan”);
else printf(“ \nso vua nhap la so le”);
printf(“ \nco nhap so khac hay khong (c/k): “);
scanf(“%c”, &tiep);
} }
Chương trình trên do dùng vòng lặp while ta phải có lệnh tiep=’c’ trước
vòng lặp để bảo đảm vòng lặp sẽ thực hiền được một lần Muốn bỏ lệnh này thì việc kiểm tra BTĐK phải được thực hiện ở cuối vòng lặp và vòng lặp
do – while là vòng lặp có đặc tính trên
3.3.2 Cú pháp:
do { NhómLệnh;
}while (biểu thức điều kiện);
3.3.3 Hoạt động của do – while:
Điểm vào vòng lặp do - while
Kiểm Tra giá trị của BTDK
Giá trị của BTĐK sai (=0) Kết thúc
vòng lặp
do-while
Giá trị của BTĐK đúng (≠0)
Thực hiện lệnh của do-while
Trang 28Lập trình C - Cấu trúc dữ Liệu giải thuật
3.3.4 Cấu trúc do-while thường được dùng khi:
Cần thực hiện nhiều lần (lặp đị, lặp lại) một nhóm lệnh
Việc kiềm tra điều kiện chỉ thực hiện sau khi người dùng cung cấp một số thông tin nhất định (có trong điều kiện kiểm tra)
3.4 Các cấu trúc lồng nhau:
Toàn bộ một cấu trúc while, for, do-while được xen như một câu lệnh vì vậy ta
có thể lồng ghép các cấu trúc này vào nhau
Ví dụ: in các bảng cửu chương 2,3,4 lên màn hình
• Cách 1:
void main()
{ int i, bcc;
for (i=1;i<=9;i++) { for (bcc =2; bcc <=4; bcc ++) printf(“%3d * %2d = %3d”, bcc, i, i*bcc);
printf(“\n”);
} }
Cú pháp : break;
Ví dụ: Viết chương trình tính tổng các số nguyên được nhập từ bàn phím chương trình kết thúc khi có một số âm được nhập
Trang 29while (1) { printf(“Nhap mot so nguyen: ");
so=0;
while (so>=0) { printf(“Nhap mot so nguyen: ");
đầu lần lặp mới Nếu có các lệnh còn lại (cùng trong vòng lặp) đặt sau
continue sẽ không được thực hiện
Ví dụ: Viết chương trình tính tổng các số nguyên dương được nhập từ bàn phím chương trình kết thúc khi có một số =0 được nhập
scanf(“%d”, &so);
if (so=0) break;
if (so<0) { printf(“Du lieu khong hop le”);
Trang 30Lập trình C - Cấu trúc dữ Liệu giải thuật
3.6 Các lỗi thường gặp:
Lưu ý đến phần khởi tạo giá trị và phần biểu thức điều kiện tránh tình trạng vòng lặp có thể thực hiện thiếu hoặc dư một lần
Ví dụ: for (i=1; i<11 ; i++) // sẽ thực hiện 10 lần
for (i=1; i<=10 ; i++) // cũng thực hiện 10 lần for (i=0; i<11 ; i++) // thực hiện 11 lần
Sử dụng toán tử gán (=) thay vì toán tử quan hệ bằng (==) trong các biểu thức điều kiện, hay ngược lại với biểu thức khởi tạo trong for
Sử dụng dấu phẩy (,) ngăn cách giữa 3 nhóm lệnh trong ngoặc của for thay vì
chấm phẩy (;)
Quên dấu chấm phẩy sau while (BTĐK) của do - while
Trang 311.2 Khái niệm
Hàm là một đoạn chương trình độc lập thực hiện trọn vẹn một công việc nhất định sau khi thực hiện xong, hàm có thể sẽ trả về giá trị cho chương trình gọi nó
1.3 Mục đích khi sử dụng các hàm con
Một chương trình thông thường sẽ có nhiều chức năng ta nên thiết kế mỗi chức năng như vậy là một hàm Trong mỗi hàm này có thể sẽ được chia nhỏ thành nhiều hàm nữa Khi các hàm chức năng đã được xây dựng hoàn chỉnh tất cả những hàm này sẽ được kết nối bởi hàm main, tại thời điểm này chúng ta sẽ không quan tâm đến chi tiết của các hàm chức năng nữa mà chỉ cần biết đầu ra (kết quả thực hiện) của những hàm này
Tóm lại:
• Khi có một công việc giống nhau cần thực hiện ở nhiều vị trí
• Khi cần chia một chương trình lớn phức tạp thành các đơn thể nhỏ (hàm con) để chương trình được trong sáng, dễ hiểu trong việc xử lý, quản lý việc tính toán và giải quyết vấn đề
Lưu ý: khi tạo một hàm trong C chúng ta phải quan tâm hai điều:
• Nội dung của hàm
• Sự tương tác của nó với những hàm khác, bao gồm việc truyền dữ liệu chính xác vào trong hàm khi gọi hàm thực hiện và giá trị mà hàm sẽ trả về khi thực hiện xong
• Hiểu và tổ chức được chương trình thành các hàm chức năng
• Phân biệt được các loại tham số: tham số hình thức trị và tham số hình thức biến
• Hiểu và xây dựng được các hàm có kiểu trả về của hàm do người lập trình quyết định
MỤC TIÊU
Trang 32Lập trình C - Cấu trúc dữ Liệu giải thuật
1.4 Cấu trúc một chương trình C
1.4.1 Khối khai báo: Bao gồm các khai báo về:
• Sử dụng thư viện
• Hằng số sẽ sử dụng trong chương trình
• Hàm con (các nguyên mẫu hàm - prototype)
• Các biến toàn cục
• Các kiểu dữ liệu tự định nghĩa
1.4.2 Hàm chính (main())
Chứa các biến, các lệnh và các lời gọi hàm cần thiết trong chương trình
1.4.3 Các hàm con:
• Được sắp xếp riêng rẽ, mỗi hàm nằm trên 1 đoạn riêng
• Các hàm nằm rời nhau Không đặt nội dung của hàm này chứa trong hàm khác, hoặc nội dung của 2 hàm có phần giao nhau
• Không cần quan tâm thứ tự sắp xếp trước/sau của các hàm
//Khai báo biến toàn cục và nguyên mẫu hàm
void ThayThe(char * S, char *St );
Trang 33//Cài đặt các hàm con Thường được tổ chức thành file riêng (ví dụ: HamPhu.cpp)
void ThayThe(char * S, char *St )
void Ghi1Sector(int vt, char buf[512])
void TimVaThayThe(char * S, char *St, unsigned char buf[])
{ for(int i=33;i<=500;i++)
{ Doc1Sector(i, buf);
char * p=strstr(buf, S);
if(p) { ThayThe(p, St);
Ghi1Sector(i, buf);
} }
}
2.1 Đặt tên cho hàm:
Mỗi hàm có một tên để phân biệt, tên hàm trong C được đặt theo quy tắc sau:(cũng là quy tắc đặt tên cho các danh định sau này)
Chỉ được dùng chữ cái, chữ số hoặc dấu _ để đặt tên hàm
Ký tự đầu tiên phải là một chữ cái hoặc dấu _
Tên hàm không được trùng tên với từ khóa
Trang 34Lập trình C - Cấu trúc dữ Liệu giải thuật Có phân biệt chữ hoa, chữ thường Thông thường ta dùng chữ thường để đặt tên cho hàm, biến và chữ hoa đặt tên cho hằng
Số ký tự tối đa là 31
2.2 Khai báo nguyên mẫu hàm (prototypes):
2.2.1 Công dụng:
Nguyên mẫu của hàm dùng để mô tả :
• Kiểu dữ liệu trả về của hàm
• Tên hàm
• Số lượng tham số
• Trật tự của các tham số
• Kiểu dữ liệu của những tham số mà nó sẽ nhận khi được gọi thực hiện Ngoại trừ hàm main tất cả các hàm khác (không phải hàm có sẵn của C) có trong chương trình đều phải khai báo nguyên mẫu Điều này giúp cho trình biên dịch phát hiện ra các lỗi sai sót về kiểu dữ liệu trả về của hàm cũng như số giá trị và kiểu dữ liệu của các giá trị truyền cho hàm khi nó được gọi thực hiện
2.2.2 Cú pháp khai báo một nguyên mẫu:
<Kiểu dữ liệu của hàm> Tên hàm ([ danh sách các tham số]);
2.2.3 Lưu ý:
Nguyên mẫu hàm thực chất là dòng đầu của hàm thêm dấu chấm phẩy (;)
vào cuối, tuy nhiên tham số trong nguyên mẫu hàm có thể bỏ phần tên Khi một hàm có nhiều tham số thì danh sách kiểu dữ liệu các tham số phải có dấu phẩy giữa hai kiểu
Các prototype thường được khai báo ở đầu chương trình sau các dòng
#include
2.2.4 Ví dụ:
int fmax(int, int); // phải có dấu chấm phẩy cuối khai
float swap(int, char, char, double); // báo của mỗi hàm
void display(double, double);
2.3 Cách xây dựng một hàm con
2.3.1 Kiểu dữ liệu của hàm
Xác định dựa vào kết quả của bài toán (Output) Gồm 2 loại :
• void: Hàm không trả về giá trị Những hàm loại này thường rơi vào những
nhóm chức năng: Nhập / xuất dữ liệu , thống kê, sắp xếp, liệt kê
void Tên_hàm (danh sách các tham số) { Khai báo các biến cục bộ
Các câu lệnh / khối lệnh hay lời gọi đến hàm khác
}
Trang 35• Kiểu dữ liệu cơ bản (rời rạc/ liên tục) hay kiểu dữ liệu có cấu trúc: Kiểu
dữ liệu tùy theo mục đích của hàm cần trả về giá trị gì thông qua việc phân tích bài toán Những hàm loại này thường được sử dụng trong các trường
hợp: Đếm, kiểm tra, tìm kiếm, tính trung bình, tổng, tích,
<Kiểu dữ liệu> Tên_hàm ([danh sách các tham số]) { <Kiểu dữ liệu> kq;
Khai báo các biến cục bộ Các câu lệnh / khối lệnh hay lời gọi đến hàm khác
2.4 Định nghĩa hàm:
Định nghĩa hàm là viết nội dung của hàm đó Mỗi hàm sẽ được định nghĩa một lần trong chương trình và có thể được gọi thực hiện bởi một hàm khác có trong chương trình
Giống như hàm main mỗi hàm trong C gồm hai phần: phần tiêu đề của hàm (Function Header) và phần thân hàm (Function Body)
Nên đặt tên hàm theo quy ước đặt tên trong C sao cho tên gọi đúng với chức năng hay mục đích thực hiện của hàm và gợi nhớ
(không có dấu ; ở cuối)
{
}
Ví dụ: Các khai báo nguyên mẫu hàm và tiêu đề hàm tương ứng;
• int fmax(int , int);
int fmax(int x, int y)
• void display(double , char );
void display(double m, char s)
tên tham số hình thức
tên tham số hình thức
Trang 36Lập trình C - Cấu trúc dữ Liệu giải thuật
• void mess(void); hoặc void mess();
void mess(void)
Nhận xét:
• Tiêu đề của một hàm thì gần tương tự như nguyên mẫu chỉ khác là ở cuối dòng không có dấu ; và danh sách các tham số trong tiêu đề phải có tên tham số
• Tên các tham số hình thức do người lập trình đặt, và nó dùng để nhận các giá trị truyền từ bên ngoài vào khi hàm thực hiện
Thân hàm: Bao gồm các lệnh các phép toán sẽ tác động lên các giá trị được truyên cho hàm thông qua các tham số hình thức, để tạo ra kết quả
Ví dụ: Xem xét chương trình sau, chương trình in lên màn hình giá trị lớn nhất của hai số nguyên được nhập từ bàn phím, trong chương trình có một hàm findmax dùng để tìm giá trị lớn nhất trong hai số:
#include <stdio.h>
int TimMax(int, int); //prototype declare
void main()
{
int so1, so2;
printf(“ Nhập số thứ nhất:”);
if (x>=y) return x; // Function body
else return y; // Function body
}
2.5 Lời gọi hàm:
Lời gọi hàm giống như một lệnh, nó xuất hiện trong chương trình khi có yêu cầu gọi thực hiện một hàm nào đó thực hiện Lời gọi hàm bao gồm tên hàm các dữ liệu truyền cho hàm được gọi Nếu nguyên mẫu của hàm có tham số thì khi gọi hàm phải truyền giá trị
Trong ví dụ trên dòng lệnh findmax(num1,num2) trong hàm main là một lời gọi
hàm Trong đó:
• findmax : Tên hàm được gọi
• num1,num2 : Dữ liệu truyền cho hàm
Số lượng dữ liệu truyền cho hàm phải bằng số lượng tham số khi khai báo nguyên mẫu và đúng thứ tự đã khai báo (cùng kiểu dữ liệu của tham số)
Trang 373 PHÂN LOẠI THAM SỐ TRUYỀN CHO HÀM:
3.1 Sử dụng tham số của hàm là tham trị
Tham số dạng này chỉ mang ý nghĩa là dữ liệu đầu vào
Đặc điểm của cách dùng tham số này là: Khi hàm gọi truyền giá trị cho các tham số của hàm được gọi (trực tiếp bằng hằng hoặc thông qua các biến), thì những tham số này sẽ nhận giá trị được truyền cho nó và lưu ở một vị trí khác trong bộ nhớ Do đó việc tác động lên các tham số của hàm được gọi tuyệt đối không làm ảnh hưởng đến giá trị của các đối tượng mà hàm gọi đã dùng để truyền cho nó
Cơ chế truyền và xử lý dữ liệu diễn ra như sau:
• Hàm gọi (chẳng hạnï như hàm main trong ví dụ trên) có thể dùng hằng hoặc biến để truyền giá trị cho tham số của chương trình được gọi, ví
dụ như ta có thể gọi hàm findmax như sau: findmax(10,5) (giá trị truyền
cho tham số x,y là hằng)
• Hàm được gọi (chẳng hạn như hàm findmax trong ví dụ trên) sẽ nhận
giá trị truyền cho nó và lưu những giá trị này vào một vùng nhớ gọi là vùng nhớ tạm Khi đó mọi lệnh tác động lên tham số trong chương trình con này sẽ tác động lện vùng nhớ tạm Vùng nhớ tạm sẽ bị xóa
ngay sau khi hàm được gọi (findmax) kết thúc
3.2 Sử dụng tham số của hàm là tham chiếu:
Có sự thay đổi giá trị của tham số trong quá trình thực hiện và cần lấy lại
giá trị đó sau khi ra khỏi hàm Ứng dụng của tham số loại này có thể là dữ liệu đầu ra (kết quả) hoặc cũng có thể vừa là dữ liệu đầu vào vừa là dữ liệu đầu ra.
Theo cách này thì khi gọi thực hiện một hàm có tham số thì hàm gọi phải dùng biến để truyền dữ liệu cho các tham số của hàm được gọi Lúc này tham số sẽ nhận địa chỉ trong bộ nhớ RAM của biến đã truyền cho nó, và mọi tác động lên tham số của hàm được gọi sẽ tác động trực tiếp lên biến tương ứng của chương trình gọi
Cú pháp để khai báo một tham số dạng tham chiếu trong dòng prototype và dòng function header của hàm như sau:
data_type& //khai báo trên dòng prototype
data_type& reference_name //Khai báo trên function header
Ví dụ: chương trình sau sử dụng hàm swap có công dụng nhận giá trị của hai biến và đổi giá trị của hai biến cho nhau:
#include <stdio.h>
#include <conio.h>
void swap(int&, int&);
void main()
Trang 38Lập trình C - Cấu trúc dữ Liệu giải thuật
#include <stdio.h>
#include <conio.h>
void TinhToan(float, float, float ,float&, float&);
void main()
{ float n1,n2,n3, Tong, Tich;
printf(“\n Nhap vao ba so muon tinh tong, tich ");
scanf (“%d%d%d”,&n1,&n2, &n3);
calc(n1,n2,n3,sum,product);
printf(“\nTong ba so la:%d \n ", Tong);
printf(“\nTich ba so la: %d \n", Tich);
3.3 Ví dụ về trình tự khi xây dựng hàm:
Ví dụ 1: Viết CT nhập số nguyên dương n và in ra màn hình các ước số của n
Phân tích bài toán:
• Input: n (Để xác định tham số)
- Kiểu dữ liệu: số nguyên dương (unsigned int)
- Giá trị n không bị thay đổi trong quá trình tìm ước số Tham số của
hàm không là con trỏ
Trang 39• Output: In ra các ước số của n (Để xác định kiểu dữ liệu hàm)
- Không trả về giá trị
- Kiểu dữ liệu của hàm là void
• Xác định tên hàm: Hàm này dùng in ra các ước số của n nên có thể
đặt là LietKeUocSo
Ta có nguyên mẫu hàm:
void LietKeUocSo ( unsigned int n );
void LietKeUocSo (unsigned int n)
{ for(int i=1; i<=n; i++)
if (n%i==0) printf(“%d \t”,i);
}
Lưu ý cách gọi hàm: Đối với hàm có kiểu dữ liệu hàm là void thì khi gọi không cần phải gán giá trị vào biến, ngược lại phải gọi như trong Ví dụ 2 (Phải khai báo tương ứng kiểu với kiểu dữ liệu hàm sẽ gọi và gán giá trị trả
về vào biến đó)
Ví dụ 2: Viết chương trình nhập số nguyên dương n và tính tổng
n
S = 1 + 2 + 3 +L+ , với n>0 Phân tích bài toán:
• Input: n (Để xác định tham số)
- Kiểu dữ liệu: số nguyên dương (unsigned int)
- Giá trị n không bị thay đổi trong quá trình tính tổng Tham số của
hàm không là con trỏ
• Output: Tổng S (Để xác định kiểu dữ liệu hàm)
- Trả về giá trị của S
Trang 40Lập trình C - Cấu trúc dữ Liệu giải thuật
- S là tổng các số nguyên dương nên S cũng là số nguyên dương
Kiểu trả về của hàm là unsigned int (hoặc unsigned long cho trường
hợp giá trị của tổng lớn hơn 2 bytes)
• Xác định tên hàm: Hàm này dùng tính tổng S nên có thể đặt là TongS
Ta có nguyên mẫu hàm:
unsigned long TongS ( unsigned int n );
i++;
}
return S;
}
4 PHẠM VI CỦA BIẾN:
4.1 Biến cục bộ: Là các biến được khai báo trong thân của một hàm nào đó Các
biến này chỉ có giá trị trong phạm vị hàm khai báo nó
4.2 Biến toàn cục: Là các biến được khai báo bên ngoài các hàm Những biến
này có giá trị với tất cả các hàm được khai báo sau nó