Professional Documents
Culture Documents
ÔN TẬP CUỐI KỲ MÔN KỸ THUẬT LẬP TRÌNH
ÔN TẬP CUỐI KỲ MÔN KỸ THUẬT LẬP TRÌNH
Mục lục
Bài 1: Tổng quan về ngôn ngữ lập trình.........................................................................................................2
1. Có 3 thành phần căn bản của bất cứ 1 NNLT nào:..................................................................................2
2. Phân biệt giữa Compiler (biên dịch) và Interpreter (thông dịch).............................................................2
3. Các mô thức lập trình...............................................................................................................................2
4. C và C++..................................................................................................................................................3
Bài 2: Quản lý bộ nhớ.......................................................................................................................................3
1. Con trỏ (pointer).......................................................................................................................................3
2. Cấp phát bộ nhớ động...............................................................................................................................4
Bài 3: Hàm (Function)......................................................................................................................................6
1. Hàm và truyền tham số.............................................................................................................................6
2. Đa năng hóa hàm (Overloading)..............................................................................................................7
3. Đa năng hóa toán tử..................................................................................................................................7
4. Con trỏ hàm..............................................................................................................................................8
5. Khái quát hóa hàm (Function templates).................................................................................................9
6. Hàm nặc danh – cú pháp lambda..............................................................................................................9
Bài 4 + 5: Kỹ thuật viết mã nguồn hiệu quả và Phong cách lập trình........................................................11
1. Các kỹ thuật viết mã nguồn hiệu quả.....................................................................................................11
2. Static, Stack, Heap..................................................................................................................................12
3. Tính Sigmoid..........................................................................................................................................12
4. Một số quy tắc cơ bản trong lập trình.....................................................................................................13
Bài 6: Đệ quy và khử đệ quy..........................................................................................................................14
1. Phân loại đệ quy.....................................................................................................................................14
2. Đệ quy có nhớ và đệ quy quay lui..........................................................................................................15
3. Khử đệ quy.............................................................................................................................................16
Bài 7: Các cấu trúc dữ liệu.............................................................................................................................18
Bài 8: Bẫy lỗi và lập trình phòng ngừa..........................................................................................................19
1. Assertion.................................................................................................................................................19
2. Xử lý ngoại lệ.........................................................................................................................................20
Bài 9: Gỡ lỗi, kiểm thử và tinh chỉnh mã nguồn..........................................................................................21
1. Gỡ lỗi......................................................................................................................................................21
2. Kiểm thử.................................................................................................................................................21
3. Tinh chỉnh mã nguồn..............................................................................................................................22
Bài 1: Tổng quan về ngôn ngữ lập trình
1. Có 3 thành phần căn bản của bất cứ 1 NNLT nào:
Mô thức lập trình là những nguyên tắc chung cơ bản, dùng bởi LTV để xây
dựng chương trình.
Cú pháp của ngôn ngữ là cách để xác định cái gì là hợp lệ trong cấu trúc các
câu của ngôn ngữ (cách viết một chương trình hợp lệ)
Ngữ nghĩa là xác định ý nghĩa thao tác cần phải thực hiên, ứng với tổ hợp kí tự
dựa vào ngữ cảnh của nó.
Lỗi cú pháp được chương trình dịch phát hiện và thông báo cho người lập chương trình biết ,
chỉ có các chương trình không còn lỗi cú pháp mới có thể được dịch sang ngôn ngữ máy.
Lỗi ngữ nghĩa chỉ được phát hiện khi thực hiện chương trình trên dữ liệu cụ thể .
2. Phân biệt giữa Compiler (biên dịch) và Interpreter (thông dịch)
Compiler
Quá trình biên dịch bao gồm việc dịch toàn bộ mã nguồn của chương trình thành
mã máy tương ứng. Kết quả là một file thực thi độc lập, có thể chạy trên hệ điều
hành mà không cần có compiler.
Mã nguồn được biên dịch chỉ cần thực hiện một lần và có thể được chia sẻ và thực
thi trên nhiều hệ thống khác nhau mà không cần biên dịch lại.
Ví dụ về chương trình được biên dịch là ngôn ngữ C/C++, Fortran, Pascal.
Interpreter
Interpreter đọc và thực thi mã nguồn lúc chương trình chạy, dịch từng câu lệnh
thành mã máy và thực thi ngay lập tức
Mã nguồn được thông dịch mỗi lần chạy, không tạo ra file thực thi độc lập
Ví dụ về chương trình được thông dịch là Python, Ruby.
Tuy nhiên, đôi khi các ngôn ngữ lập trình kết hợp cả compiler và interpreter. Ví dụ, ngôn ngữ
Java được biên dịch thành bytecode bởi compiler và sau đó được thực thi thông qua một
interpreter gọi là Java Virtual Machine (JVM). Tương tự đối với C#
3. Các mô thức lập trình
Hướng mệnh lệnh (Imperative paradigm). Ví dụ: C
Thành phần: các lệnh khai báo, lệnh gán, lệnh điều khiển chương trình, chia
chương trình thành các chương trình con (function)
Hướng mệnh lệnh tập trung vào việc thay đổi trạng thái của các biến thông qua các
câu lệnh. Các câu lệnh được sắp xếp tuần tự và thực hiện theo từng bước.
Hướng chức năng (Functional paradigm) Ví dụ: Racket, Haskell
Thành phần: các CTDL và các hàm liên quan, các hàm cơ sở, các toán tử
Đặc trưng cơ bản: modul hóa chương trình
Hướng chức năng tập trung vào việc xác định các hàm và biểu thức toán học. Các
hàm không thay đổi trạng thái và sử dụng giá trị đầu vào để tính toán kết quả.
Hướng logic (Logic paradigm) Ví dụ: Prolog
Dựa trên các tiên đề, các quy luật suy diễn và các truy vấn. Ctr thực hiện từ việc
t.kiếm có hệ thống trong 1 tập các sự kiện, sử dụng 1 tập các luật để đưa ra kết luận
Hướng đối tượng (Object-oriented programming) Ví dụ: Java, C++
Tập trung vào đối tượng, gồm các thuộc tính (properties) và phương thức
(methods), để mô phỏng thế giới thực.
Đối tượng được xem như một thực thể độc lập có khả năng tự thực hiện các hành
động và tương tác với nhau
4. C và C++
Ngôn ngữ C
Ra đời: 1970, gắn liền với sự phát triển của HĐH Unix. TG: Dennis Ritchie
Mục tiêu: Đề cao tính hiệu quả, Có khả năng truy xuất phần cứng ở cấp thấp, Ngôn
ngữ có cấu trúc (thay cho lập trình bằng hợp ngữ)
Ngôn ngữ C++
Ra đời năm 1979 bằng việc mở rộng ngôn ngữ C. Tác giả: Bjarne Stroustrup
Mục tiêu: Thêm các tính năng mới, Khắc phục một số nhược điểm của C
Bổ sung những tính năng mới so với C:
Lập trình hướng đối tượng (OOP)
Lập trình tổng quát (template)
Nhiều tính năng nhỏ giúp lập trình linh hoạt hơn nữa (thêm kiểu bool,
định nghĩa chồng hàm, namespace, xử lý ngoại lệ,...)
Truyền tham số bằng địa chỉ (thực hiện được cả trong C và C++) : Khi truyền tham số
bằng địa chỉ, địa chỉ của biến gốc được truyền vào hàm. Thay đổi được thực hiện trực tiếp
trên địa chỉ và ảnh hưởng đến giá trị gốc.
Truyền tham chiếu (chỉ thực hiện được trong C++): Sử dụng toán tử & (tham chiếu), Khi
một hàm trả về một tham chiếu, chúng ta có thể gọi hàm ở phía bên trái của một phép
gán.
Tham số ngầm định: Khi gọi hàm có nhiều tham số có giá trị mặc định, chúng ta chỉ có thể
bỏ bớt các tham số theo thứ tự từ phải sang trái và phải bỏ liên tiếp nhau
int MyFunc(int a = 1, int b, int c = 3, int d = 4); // ✖
int MyFunc(int a, int b = 2, int c = 3, int d = 4); // ✔
Ví dụ:
int get_value (int x, int a = 2, int b = 1, int c = 0) {
return a * x * x + b * x + c;
}
int x = 5 , a = 3, b = 4, c = 2 ;
printf("a=2, b=1, c=0: %d\n", get_value(x));
printf("a=%d, b=1, c=0: %d\n", a, get_value(x, a));
printf("a=%d, b=%d, c=0: %d\n", a, b, get_value(x, a, b));
printf("a=%d, b=%d, c=%d: %d\n", a, b, c, get_value(x, a, b, c));
Từ khóa auto tự động xác định kiểu dữ liệu của tham số và hàm
Ví dụ:
auto maxval (auto x, auto y) {
return (x > y) ? x : y;
}
Ví dụ 2:
vector< vector<int> > a = {
{1, 3, 7}, {2, 3, 4, 5}, {9, 8, 15}, {10, 12},
};
// su dung ham sort san co trong thu vien algorithm tren mang vecto a
// sap xep cac vector theo thứ tự giảm dần tổng các phần tử
sort (a.begin(), a.end(), [] (vector<int> x, vector<int> y) {
// xay dung ham so sanh cho viec sap xep
int sum1 = 0;
for (unsigned int i = 0; i < x.size(); i++)
sum1 += x[i];
int sum2 = 0;
for (unsigned int j = 0; j < y.size(); j++)
sum2 += y[j];
return sum1 > sum2;
});
Bài 4 + 5: Kỹ thuật viết mã nguồn hiệu quả và Phong cách lập trình
1. Các kỹ thuật viết mã nguồn hiệu quả
Khởi tạo một lần, dùng nhiều lần
Ví dụ như giá trị sin(0.31) dùng nhiều lần thì nên khởi tạo một biến mới float s = sin(0.31);
Hàm nội tuyến (Inline Functions)
Inline functions (hàm nội tuyến) là một loại hàm trong ngôn ngữ lập trình C++. Từ
khoá inline được sử dụng để đề nghị (không phải là bắt buộc) compiler (trình biên dịch)
thực hiện inline expansion (khai triển nội tuyến) với hàm đó hay nói cách khác là chèn
code của hàm đó tại địa chỉ mà nó được gọi.
Chỉ cần thêm từ khoá “inline” phía trước của hàm
Ví dụ: inline max (int a, int b) { return a > b ? a : b; }
Trình biên dịch có thể không thực hiện nội tuyến trong các trường hợp như: Hàm chứa
vòng lặp; Hàm chứa các biến tĩnh; Hàm đệ quy; Hàm chứa câu lệnh switch hoặc goto.
Tiết kiệm chi phí gọi hàm, Tiết kiệm chi phí sao chép các biến trên ngăn xếp khi hàm
được gọi, Tiết kiệm chi phí cuộc gọi trả về từ một hàm.
Tăng kích thước file thực thi do sự trùng lặp của cùng một mã. Hàm nội tuyến có thể
không hữu ích cho nhiều hệ thống nhúng. Vì trong các hệ thống nhúng, kích thước mã
quan trọng hơn tốc độ.
Hàm macros
Ví dụ 1: #define for(i,a,b) for(int i = a; i <= b; i++)
Khi đó trong hàm main:
for(i,0,n) sum += i; for(int i = 0; i <= n; i++) sum += i;
Ví dụ 2: #define expr 2 + 5
Khi đó trong hàm main:
cout << 3 * expr; cout << 3 * 2 + 5; Kết quả là 11
Biến tĩnh (static variable)
Biến static là một kiểu biến đặc biệt trong C++ mà giá trị của nó được lưu trữ và duy
trì trong suốt quá trình chạy chương trình, bất kể phạm vi và thời gian sống của biến.
Có hai loại biến static trong C++: biến static cục bộ (local static)
và biến static toàn cục (global static).
Biến static cục bộ: Biến static cục bộ được khai báo bên trong một hàm hoặc một
khối mã (block). Điều đặc biệt về biến static cục bộ là nó chỉ được khởi tạo một lần
và giá trị của nó được duy trì qua các lần gọi hàm. Biến static cục bộ được sử dụng
để lưu trữ thông tin tạm thời hoặc tính toán trên nhiều lần gọi hàm.
Ví dụ:
Biến static toàn cục: được khai báo bên ngoài tất cả các hàm và khối mã. Biến static
toàn cục có thể truy cập từ bất kỳ hàm nào trong cùng file và giá trị của nó cũng
được duy trì trong suốt quá trình chạy chương trình.
2. Static, Stack, Heap
Khi thực hiện, vùng dữ liệu data segment của một chương trình được chia làm 3 phần:
static, stack, và heap data.
Static: global hay static variables
Stack data: các biến cục bộ của chương trình con
Heap data:
Dữ liệu được cấp phát động (ví dụ, pchar trong ví dụ trên).
Dữ liệu này sẽ còn cho đến khi ta giải phóng hoặc khi kết thúc chương trình.
3. Tính Sigmoid
Chọn số các điểm (N = 1000, 10000, ...) tùy theo độ chính xác mà bạn muốn Tốn kém
thêm không gian bộ nhớ cho mỗi điểm là 2 giá trị float hay double tức là 8 – 16 bytes
Khởi tạo giá trị cho mảng khi bắt đầu thực hiện
Tính sigmoid
Bạn đã biết X0
Tính Delta = X1 - X0
Tính Xmax = X0 + N * Delta;
Với X đã cho, nếu X > Xmax thì sigmoid(X) = 1; nếu X<X0 thì sigmoid(X) = 0
Ngược lại X0 < X < Xmax thì Tính i = (X – X0) / Delta;
1 phép trừ số thực và 1 phép chia số thực
Tính sigmoid(X)
1 phép nhân float và 1 phép cộng float
Ví dụ: Giả sử giá trị N = 10000, người ta muốn sử dụng phương pháp nội suy tuyến tính để tìm
hàm sigmoid(178.89) khi đã biết giá trị của sigmoid(0.21). X0 = 0.21 và X1 = 0.22.
Vậy theo em số lượng phép toán với số thực dấu phẩy động là bao nhiêu phép để ra được
sigmoid(178.89). Giả sử phép toán y = a*x + b được coi là 2 phép toán dấu phẩy động khác nhau.
Trả lời: 1. Tính Delta = X1 – X0 = 0.01; 2 và 3. Tính Xmax = X0 + N*Delta = 100.21
Ta cần tính sigmoid(178.89) thì X = 178.89 > 100.21 nên sigmoid(178.89) = 1. Vậy cần 3 phép toán
Bổ sung: Nếu yêu cầu tính sigmoid(1.78) thì ta cần làm như sau:
Khi chưa xây dựng được mảng thì cần tính toán X2, X3, X4…
Tính X 2= X 1+ σ ' ( X 1 )∗Delta mà σ ' ( X 1 ) =X 1 ( 1− X 1 ) cần 2 phép toán(1 cộng , 1 nhân)
Tính X2 cần 4 phép toán (2 phép toán tính σ ' ( X 1 ) và 2 phép toán tính X 1+σ ' ( X 1 )∗Delta ¿
Tính đến sigmoid(1.78) tức là X157 ta cần thiết 4.(157-2+1) + 3 = 627 phép toán
Vậy ta có công thức tổng quát:
Nếu X > Xmax thì cần 3 phép toán số thực dấu phẩy động
Nếu X < X0 thì cần 0 phép toán vì kết quả trả về là 0
Trường hợp còn lại thì cần
4∗i−1 với i=( X− X 0)/ Delta