Bài giảng Kỹ thuật lập trình - Chương 3: Các kỹ thuật xây dựng chương trình phần mềm cung cấp cho người học các kiến thức: Mở đầu, làm việc với biến, viết mã chương trình hiệu quả. Mời các bạn cùng tham khảo nội dung chi tiết.
Trang 1
-_ Với mỗi bài toán, làm thể nào để:
~ Thiết kế giải thuật nhằm giải quyết bài toán đó
- Cài đặt giải thuật bằng một chương trình máy tỉnh
- Làm cho chương trình chạy
đúng trước khi tăng tính hiệu
quả của chương trình
- Tăng tính hiệu quả của
Trang 2II Làm việc với biến
[H Viết mã chương trình hiệu quả
IV Thiết kế chương trình
V Xay dung ham/thu tục
Trang 3
I MO ĐẦU
Trang 4
1 Mở dau - Compile / build (dịch):
°_ Source code (mã nguồn):
- _Executable program (chương trình thực
thi):
* Language (ng6n ngữ):
* Library (thu vién):
Trang 5
* Liệt kê và đo kích thước (2):
- Từ khóa cho khai báo biển (3):
Trang 6
C: Hello World
_ Lệnh tiền xử lý
_„Chú thích
/* My first C program which prints Hello World */
._—— mMain(): “start here”
int main (int argc, char *argv[])
#include <stdio.h> «~~
{
\ printf ("Hello World!\n")7; -~_
, return 07% —> Lệnh từ thư viện
Trang 7«+ Một số phần trong mã nguồn không ảnh hưởng đến nội dung câu lệnh
nhưng ảnh hưởng đến phong cách lập
trình -Ổ Các phần khác thường ảnh hưởng đến nội dung câu lệnh và phong cách lập trình
Trang 8
C: dịch từ mã nguôn sang mã máy
header ioc source compiler fics
Trang 9
C: dịch từ mã nguôn sang mã máy
° Một số compilers co vai trò rất lớn trong việc tối
ưu chương trình
— Chung phan tích sâu mã nguồn và làm mọi điều
"machinely“ có thể nhằm xác định nguồn gốc gây kém
hiệu quả trong mã nguồn (dư thừa tính toán, dư thừa dữ
liệu)
~ Ví dụ GNU g++ compiler trên Linux/Cygwin cho chương trình viết bằng C
* g++ -O5 -o myprog myprog.c
có thể cải thiện hiệu năng tử 10% dén 300%
Trang 10
- LTV có thể phải xem lại mã nguồn khi
thấy chương trình chạy chậm
-_ Vậy cần tập trung vào đâu để cải tiến
nhanh nhất, tốt nhất ?
Trang 12
Phong cách lập trình tốt
+ Phong cách lập trình (program style): cách trình bày một chương trình
+ VỊ sao program style lại quan trọng?
~ Lỗi thưởng xảy ra do sự nhầm lẫn cua LTV
- Biến này được dùng lam gi?
+ Hàm này được gọi như thế nào?
- Mã nguồn hiệu qua (good code)
«Ổ Đỗ đọc
-_ Dễ hiểu (dễ kiếm tra}
¢ Oé sits (dé bảo trì, cấp nhặt, trảnh lỗi)
+ Làm thế nào để mã nguồn trở nên dễ đọc, dễ hiếu, dễ sửa ?
Trang 13
Phong cách lập trình tốt
- _ Để máy tính làm tốt các công việc nặng nhọc của nó, hãy
~ Viết CT rõ ý, với cấu trúc rồ ràng
~ Viết lại mã nguồn thay vi cỗ gắng chủ giải hay chắp vả các đoạn
mã khó hiểu
Tránh dùng goto
- _ Để lập trình viên giảm bớt công việc không đảng cỏ, hãy
Viết chương trình với khuôn đạng rõ ràng
Chọn tên phủ hợp, gợi nhớ, không nhập nhằng
Cung cấp đầy đủ tài liệu liên quan đến các cấu trúc dữ liệu sử
dụng trong chương trình
Viết chú thích rõ rằng, cỏ ý nghĩa, sử dụng các thành ngữ phổ biến Dùng các thủ tục đệ quy cho những cấu trúc dữ liệu đệ quy ( list, cây phả hệ )
Trang 14
II CAC KY THUAT LAM
VIỆC VỚI BIẾN
1 Khai bao bien
Đặt tên biến
Sử dụng các kiểu dữ liệu hợp lý cho biến
4 Khởi tao biến
5 Sử dụng biến trung gian
6 Sư dụng biến tro
Trang 15
Biến (variable)
Ndi dung Dia chi
+ Luu tri’ di liéu cua chung trinh ‘
Trang 17
2 Đặt tên
Chương a)
Các kỹ thuế! + Tên:
T LHÌNH ~ Dùng bảng chữ của mỗi ngôn ngữ lập trình dé đặt tên
phần mềm ~ Tên bắt đầu bằng chữ cái, tiếp theo là chữ cái, chữ số,
I Mở đầu hoặc ký tự khác (_, $, tùy theo ngôn ngữ lập trình)
11 Các kỹ - Tên biến:
aera oie ~ Phải ngắn qọn và cỏ tính chất gơi nhớ hay miềễu tả
1 Khal bao — Bat dau bang chữ In thưởng
~ Nên là đanh tử hoặc cụm danh từ, nếu là cụm danh tử
thì có thế viết hoa chữ cải đầu của các danh tử tiếp
theo
* int myfirstNumber, mySecondNunber;
~- Chỉ đặt tên biễn hằng 1 chữ cải cho các biến trung gian hoặc biến đếm
¢ int 1 = @; (i,ÍJ,k, ,n)
* char c; (c,d, e)
Trang 18
Đặt tên biến trong C
°Ò Đặt đúng tên cho biến là điều quan trọng
-Ổ Nên có chú thích biến đó dùng làm gì trong
trường hợp tên không mang tính chất gợi nhớ
Trang 19
Đặt tên biến trong C
* Dung chi hoa, chữ thường nhất quán
Trang 20-_ Khi cần kết quả tính toán chính xác hơn nữa
- Khi tốc đồ tính toán là tiêu chí quan trong
~ int:
-Ổ Đánh chỉ số
-_ Mã hóa các trạng thải
* V.V
~ Tốc độ tính toán phụ thuộc vào phần cứng máy tính > chưa chắc
dùng kiểu int là nhanh nhất
Trang 21
printf(“ miles and yards ”, miles, yards);
printf (“equals kilometres.\n”, kilometres);
return EXIT_SUCCESS;
Trang 22
Hãy chọn các kiểu dữ liệu sao cho chương trình
trở nên đơn giản
short int small no;
unsigned char uchar;
long double precise_number;
short float not_so_precise;
onst short float pi = 3.14;
Trang 23
candy_per_person = total_candy / number_of_people;
* Tuy thudc vào chương trình dịch, đôi
Trang 24candy _per_person = total_candy / number_of_people;
-_ Ép kiểu là việc chuyển từ 1 giá trị kiểu này sang 1 giá
trị kiểu khác tương đương
- Ép kiểu là cách an toàn nhất để đảm bảo chương trình
Trang 25
Ví dụ về ép kiểu
#include <stdio.h>
#include <stdlib.h>
const float KILOMETRES PER_MILE = 1.609;
const float YARDS PER_MILE = 1760.8;
printf(“%d miles and %d yards ”, miles, yards);
printf(“equals %f kilometres.\n”, kilometres);
return EXIT_SUCCESS;
Trang 28
Khởi tạo 1 lần, dùng nhiều lần
Lưu ý: việc khai báo và khởi
tạo biến global cho phép
nhiều CTC trong chương trình
truy nhập và thay đổi giá trị
biến
Với các chương trình được
thiết kế theo modul, việc này
có thể làm cho
— cấu trúc chương trình bị phá vỡ
~ khó gỡ rỗi chương trinh
double defaultValue = sin(8.25);
float f() { ae value = defaultValue; — |
Trang 30
+ - Khởi tạo biến: lần đầu tiên gán giá trị cho một biến,
+ Giá trị của một biến chưa khởi tạo là không biết trước,
có thể là giá trị còn lưu lại từ lần chạy chương trình trước đó trong các ô nhớ tương ứng hoặc giá trị rỗng
* Nên qản giả trị khởi tạo cho biến ngay khi khai báo biến
Trang 31
Khai báo biến tính (Static Variables)
* Cac bién khai báo trong chương trình con (CTC) được cã
phát bộ nhớ khi CTC được gọi và sẽ bị loại bỏ khi kết thúc
CTC
- Khi gọi lại CTC, các biến cục bộ lại được cấp phát và khởi
tạo lại
* Nếu muốn 1 giá trị vẫn được lưu lại cho đến khi kết thúc
toàn chương trình, cần khai bao bién cục bộ của CTC đó là static và khởi tạo cho nó 1 giá tri
~ Việc khởi tạo sẽ chỉ thực hiện lân đầu tiên chương trình được gọi
và giá trị sau khi biến đối sẽ được lưu cho các lần gọi sau
~ Bằng cách nay 1 CTC có thế "nhớ” một vài thông tin sau mỗi lần
được gọi
* Dung bién static thay vi global :
- Khi khai báo 1 biến cục bộ của CTC là biến static, ta tránh được
việc bị các phần khác của CT chính làm thay đổi trạng thái CTC
Trang 32
void sumit() { static int sum = @;
printf(“Please enter 5 numbers to be summed\n”);
for (count = @; count < MAX; count++)
sumit();
return 9;
Trang 33
Stack, heap
* Khi thực hiện, vùng dữ liệu
(data segment) của 1 chương
trình được chia làm 3 phần :
— Static data: cac bién todn thé hay
bién tinh, vi dy array,
-_ Dữ liêu này sẽ còn cho đến
khi ta giải phóng hoặc khi kết thúc CT
Trang 34
Bài tập
/* File: xyz.c */
static int count;
static char name[8];
int main() {
/* program body */
return @;
* Phan ma nguén nao
cua chương trình được
truy nhập và thay đổi
giá trị của các biến
count, name ?
«Ò Giá trị khởi tạo ngầm
định của 2 biến này là
gì ?
Trang 35
aa - Str dung bién trung gian dé
SN - phan biệt các bước tính toán
1 Mé dau — dien dat r6 rang logic nghiệp vụ của chương
II Các kỹ trình
wecvớibiến | ° ƯU điểm:
` ae ~ Làm rõ cấu trúc chương trình
3 Sử dụng các — Rất hiệu quả khi xem lại mã nguồn
nh si” °ồ Không nên lạm dụng việc dùng mã
4 Khởi tạo trung gian, điêu này làm chương trình
Trang 36
Ví dụ: Thêm biến trung gian
const float YARDS _PER_MILE = 1760.0;
int main(void) f
int miles, yards;
float kilometres, yardsInMiles;
miles = 26; yards = 385;
yardsInMiles = (float)yards / YARDS _PER_MILE;
printf("%d yards = %f miles\n", yards, yardsInMiles);
kilometres = ((float)miles + yardsInMiles) *
KILOMETRES PER_MILE;
printf(“%d miles and %d yards ”, miles, yards);
phintf(“equals %f kilometres.\n”, kilometres);
return EXIT SUCCESS;
Trang 37
5, Thêm biến trung gian
* Chu y su’ dung dung tính chất của biến đã khai
const int FIVE = 5; const int FIVE = 5;
const double PI = 3.141593; const double PI = 3.141593;
Trang 38
5, Thêm biến trung gian
„ _ Chú ý sử dụng đúng tính chất của biến đã khai báo
~ volatile : giá trị của biến có thể được 1 tiến trình bên ngoài
chương trình thay đổi, thường sử dụng để trao đổi dữ liệu
với thiết bị ngoại vi
obuf(void) ¢
Nếu không khai báo iobuf là volatile, trình dịch bỏ qua không thực hiện vòng lặp
vi không có lệnh bên trong
Trang 39
- Sử dụng con trỏ cho phép ta truy nhập tới 1 đối
tượng gián tiếp qua địa chỉ của nó
-Ò Trong C/C++, con trỏ là một công cụ rất mạnh,
linh hoạt
Trang 40
a Khai báo và sử dụng con trỏ
* Khai bao con trỏ: Biến Địa chỉ Giá trị
kieuDL *<tenBienConTro>; a FFEC | 3
« Vi du:
int a = 3;
int *p; p = &a;
- Có nhiều kiểu biến với các kích thước khác
nhau, nên có nhiêu kiểu con trỏ
— Con trỏ int dé trỏ tới biến hay hàm kiểu int
~ Chỉ có thể trỏ tới một đối tượng cùng kiểu
- Sau khi khai báo, ta được con trỏ NULL, vì nó chưa trỏ tới 1 đối tượng nào
Pp N
Trang 41
a Khai báo và sử dụng con trỏ
°Ò Toán tử & va *
— Toán tử s: Trả về địa chỉ của biến
~ Toản từ *: Trả về giá trị chứa trong vùng nhớ được trỏ bởi biến
con trỏ
~- * và & có độ ưu tiên cao hơn tất cả các toán tử số học ngoại trừ
toán tử - (đảo dấu) và tăng giảm 1 đơn vị (++, )
Trang 42a Khai bao va su dụng con trỏ
- Một biến con trỏ có thể được gán bởi:
~ Địa chỉ của một biến khác;
Trang 43
Ví dụ 1
° Có thể viết *p 0 thể v cho mọi nơi có đối tượng mà
nó trỏ tới xuất hiện
Trang 45
Địa chỉ | Giá trị | Biến
Trang 46b Cac phép toan trén con tro
= C6 thé céng hoac trir bién con tro vdi 1 sé
nguyên n
- Kết quả là 1 con trỏ củng kiểu
— La dja chi mới trỏ tới 1 đối tượng khác nằm cách
đổi tượng đang bị trỏ n phần tử
* Phép trừ giữa 2 con trỏ cho ta khoảng cách (số
phần tử) giữa 2 con trỏ
° _ Không có phép cộng, nhân, chia, lấy số dư 2 con trỏ
°‹ Ví dụ:
~ char c, *pchar = &C;
— shorts, *pshort = &s;
~ long |, *plong = &l;
- pchar ++;
— pshort +4;
~ plong ;
Trang 47
b Các phép toán trên con trỏ
// pchar = 101; pshort = 103; plong = 99
Trang 48
b Các phép toán trên con trỏ
-Ò Có thể dùng các phép gán, so sánh các con trỏ,
nhưng cần chú ý đến sự tương thích về kiểu
-Ổ Cần ép kiểu nếu gán không đúng kiểu
double x = 1.5;
char *cPtr = &x; //Error: type mismatch
char *cPtr (char *)&x;
// OK: cPtr points to the first byte of x
Trang 49
c Con tro void
* Con tré dac biét, khéng dinh kiéu
* C6 thé nhan gia trị là địa chỉ của một biến thuộc bất kỳ kiểu dữ liệu nào
Trang 50
c Con trỏ void
* Thuc chat con tro void chỉ chứa một địa chỉ bộ nhớ mà
không biết tại địa chỉ đó có đối tượng kiêu dữ liệu gì
- _ Không thể truy cập nội dung của một đối tượng thông qua
con tro void
* Phai ép kiéu vé con tré cé dinh kiéu cua kiéu déi tung
float x; int y;
void *p; p = &x;
*b = 2.5; // báo lỗi vì p là con trỏ void
/* cần phải ép kiếu con trỏ void trước khi truy cập đối
tượng qua con trỏ */
*((float*)p) = 2.5; // x = 2.5
p = &y; // p chứa địa chỉ số nguyên y
*((int*)p) = 2; // y = 2
Trang 51
— ala mét dia chi
~ a có giá tri bang &a[@], ati = &a[ i]
~ Tuy nhiên, a là 1 hằng > Không thể dùng trong câu
lệnh gắn hay toán tử tăng, giảm như a++;
> C6 thé gán con trỏ p bang dia chi cia mang
> Có thể dùng con trỏ này để duyệt các phần tử
trong mang
* Vidu: int a[10], *p; p = a;
~ p+1 sẽ trỏ tới a[1], nghĩa là *(p+1) chính là a[1]
— p+2 sẽ trỏ tới a[2], *(p+2) là a[2]
~ p+i sẽ trỏ tới a[i], *(p+i) là afi]
a[0] la[ll a[2]
Trang 53
Ví dụ
-Ò _ Viết chương trình thực hiện các công việc sau,
mỗi công việc viết thành một hàm Cuối cùng,
viết hàm main để gọi các hàm đã viết
— Yêu cầu người dùng nhập vào n là số phần tử của mảng
nguyên (n<=1000)
- Nhập n phần tử cho mảng nguyên đó
— Sap xếp mảng nguyên theo thứ tự giảm dần
Trang 55
void nhap_mang(int *a, int n) {
Trang 56
void hien_thi_mang(int *a, int n) {
Trang 57
void sap xep mang(int *a, int n) {
Trang 58
printf( "Mang theo thu tu ban dau \n");
hien thi _mang(a, n);
Trang 59chương trình — char *tinhthanh; tinhthanh=“Da lat”;
we — char *tinhthanh =“Da lat”;
IL Các kỹ - -Ổ Ngoài ra các thao tac trên xâu cũng
thuật lâm việc ˆ >
với biển tương tự như trên màng
1 Khal báo — *(tinhthanh+4) = “a”;
Trang 60f Mang cac con tro
* Con tro cũng là một loại dữ liệu nên ta
có thể tạo một mảng các phần tử là
con trỏ
— kieuDuLieu *tenMangConTro[kichThuoc];
— Vidu: char *ds[10];
+ ds la 1 mang gdm 10 phan tu, mdi phan tu
là 1 con trỏ kiểu char, được dùng để lưu trữ
10 xâu ký tự nào đó
- Cũng có thể khởi tạo trực tiếp các giá
trị khi khai báo
- cha" *ma[10] = {“mot”,”hai”,”ba” };
Trang 61
Lưu ý
* Cần phân biệt mảng con trỏ và mảng nhiều
chiêu
- Mang nhiều chiều là mảng thực sự, được khai báo
và phải cấp phát đủ vùng nhớ dành săn cho các
phan tử
— Màng con trỏ chị dành không gian nhớ cho các biến
tro (chua dia chi) Khi khoi tao hay gan gia tri, can
them bo nho cho cac ptu sử dụng > Tốn nhiều hon
+ Uu diém cua mang tré
~ Có thê hoán chuyền các đối tượng (mảng con, cấu trúc ) được tro boi con tro nay bang cach hoàn
chuyền các con tro
— Truyền tham số trong hàm