Giáo trình Ngôn ngữ lập trình C++

Mục lục

Giới thiệu.6

Chương 1. Mở đầu .8

1.1. Chương trình là gì?.8

1.2. Lập trình là gì? .8

1.2.1. Mức cao độc lập với máy tính .8

1.2.2. Mức thấp phụthuộc vào máy tính .10

1.3. Ngôn ngữlập trình và chương trình dịch .10

1.4. Môi trường lập trình bậc cao.11

1.5. Lỗi và tìm lỗi.13

1.6. Lịch sửC và C++ .14

1.7. Chương trình C++ đầu tiên .15

Bài tập .19

Chương 2. Biến, kiểu dữliệu và các phép toán .20

2.1. Kiểu dữliệu.22

2.1.1. Kiểu dữliệu cơbản .22

2.1.2. Kiểu dữliệu dẫn xuất .24

2.2. Khai báo và sửdụng biến .24

2.2.1. Định danh và cách đặt tên biến .24

2.2.2. Khai báo biến .25

2.3. Hằng.25

2.4. Các phép toán cơbản.26

2.4.1. Phép gán.26

2.4.2. Các phép toán sốhọc.26

2.4.3. Các phép toán quan hệ.27

2

2.4.4. Các phép toán lô-gic.28

2.4.5. Độ ưu tiên của các phép toán.28

2.4.6. Tương thích giữa các kiểu .29

Bài tập .30

Chương 3. Các cấu trúc điều khiển .32

3.1. Luồng điều khiển.32

3.2. Các cấu trúc rẽnhánh .33

3.2.1. Lệnh if-else .33

3.2.2. Lệnh switch .39

3.3. Các cấu trúc lặp .43

3.3.1. Vòng while .43

3.3.2. Vòng do-while .46

3.3.3. Vòng for .49

3.4. Các lệnh breakvà continue .54

3.5. Biểu thức điều kiện trong các cấu trúc điều khiển.57

Bài tập .59

Chương 4. Hàm.61

4.1. Các hàm có sẵn.62

4.2. Cấu trúc chung của hàm .63

4.3. Cách sửdụng hàm .64

4.4. Biến toàn cục và biến địa phương .65

4.4.1. Phạm vi của biến .65

4.4.2. Thời gian sống của biến.67

4.5. Tham số, đối số, và cơchếtruyền tham sốcho hàm .68

4.5.1. Truyền giá trị .68

3

4.5.2. Truyền tham chiếu.69

4.5.3. Tham sốmặc định .72

4.6. Hàm trùng tên.74

4.7. Hàm đệquy .76

Bài tập .78

Chương 5. Mảng .80

5.1. Mảng một chiều.80

5.1.1. Khai báo và khởi tạo mảng .81

5.1.2. Ứng dụng của mảng .83

5.1.3. Trách nhiệm kiểm soát tính hợp lệcủa chỉsốmảng.85

5.1.4. Mảng làm tham sốcho hàm.85

5.2. Mảng nhiều chiều .86

5.3. Mảng và xâu kí tự .88

5.3.1. Khởi tạo giá trịcho xâu kí tự .90

5.3.2. Thưviện xửlý xâu kí tự .90

5.4. Tìm kiếm và sắp xếp dữliệu trong mảng .91

5.4.1. Tìm kiếm tuyến tính .91

5.4.2. Tìm kiếm nhịphân .92

5.4.3. Sắp xếp chọn .94

Bài tập .96

Chương 6. Con trỏvà bộnhớ .99

6.1. Bộnhớmáy tính .99

6.2. Biến và địa chỉcủa biến.99

6.3. Biến con trỏ .100

6.4. Mảng và con trỏ.105

4

6.5. Bộnhớ động .107

6.5.1. Cấp phát bộnhớ động.107

6.5.2. Giải phóng bộnhớ động .108

6.6. Mảng động và con trỏ .109

6.7. Truyền tham sốlà con trỏ .111

Bài tập .115

Chương 7. Các kiểu dữliệu trừu tượng .118

7.1. Định nghĩa kiểu dữliệu trừu tượng bằng cấu trúc struct .118

7.2. Định nghĩa kiểu dữliệu trừu tượng bằng cấu trúc class .124

7.2.1. Quyền truy nhập .127

7.2.2. Toán tửphạm vi và định nghĩa các hàm thành viên .128

7.2.3. Hàm khởi tạo và hàm hủy.129

7.3. Lợi ích của lập trình hướng đối tượng.132

7.4. Biên dịch riêng rẽ .133

Bài tập .137

Chương 8. Vào ra dữliệu.140

8.1. Khái niệm dòng dữliệu .140

8.2. Tệp văn bản và tệp nhịphân .141

8.3. Vào ra tệp .141

8.3.1. Mởtệp.142

8.3.2. Đóng tệp.143

8.3.3. Xửlý tệp văn bản .144

8.3.4. Xửlý tệp nhịphân .147

Bài tập .151

Phụlục A. Phong cách lập trình .153

5

Phụlục B. Dịch chương trình C++ bằng GNU C++.157

Phụlục C. Xửlý xâu bằng thưviện cstring.160

Tài liệu tham khảo .162

pdf162 trang | Chuyên mục: C/C++ | Chia sẻ: dkS00TYs | Lượt xem: 1784 | Lượt tải: 4download
Tóm tắt nội dung Giáo trình Ngôn ngữ lập trình C++, để xem tài liệu hoàn chỉnh bạn click vào nút "TẢI VỀ" ở trên
 biến 
Tên biến nên dễ đọc, và gợi nhớ đến công dụng của biến hay kiểu dữ liệu mà 
biến sẽ lưu trữ. Đối với những biến gồm nhiều từ, thì các từ nên viết liền nhau 
và chữ cái đầu tiên của các từ phía sau nên được viết hoa. Ví dụ 
numberStudents, savingAccount 
Các biến hằng nên viết hoa. Nếu biến hằng gồm nhiều từ, thì các từ nên chia 
cách bằng dấu gạch chân. Ví dụ 
 155 
PI, NUMBER_ITERATION 
A.5. Cách đặt tên hàm 
Tên hàm nên dễ đọc, và gợi nhớ đến mục đích của hàm. Tên hàm nên bắt đầu 
bằng một động từ. Đối với những hàm gồm nhiều từ, thì các từ nên viết liền 
nhau và chữ cái đầu tiên của các từ phía sau nên được viết hoa. Ví dụ 
getSum, getMin, calculateScores 
A.6. Biểu thức 
Các biểu thức cần viết đơn giản, gắn gọn và dễ hiểu. Các biểu thức dài có thể 
tách nhỏ ra sử dụng các biến trung gian. Nên sử dụng các cặp dấu ngoặc để 
trách sự nhập nhằng và nhầm lẫn về thứ tự thực hiện các phép toán trong biểu 
thức. Ví dụ: 
sum = a * b + a * b * c – d/e 
Có thể viết thành 
ab = a * b; 
sum = ab * (c + 1) – (d/e); 
Lưu ý: Biểu thức điều kiện cũng nên tuân thủ theo nguyên tắc trên. 
A.7. Vòng lặp 
Không nên sử dụng nhiều các lệnh nhảy như break, hay continue để thoát ra 
khỏi vòng lặp. Với mỗi vòng lặp, nên xác định rõ ràng điều kiện để vòng lặp kết 
thúc. 
A.8. Khối chương trình 
Các đoạn chương trình cần được trình bày theo thành từng khối (sử dụng các 
dấu cách). Việc trình bày theo khối sẽ giúp chúng ta dễ dàng hiểu được cấu trúc 
và thứ tự thực hiện các lệnh. Ví dụ: 
 156 
while (!done) 
{ 
 doSomething (); 
 done = check (); 
} 
A.9. Lớp 
Mỗi lớp (class) nên tách ra thành hai tệp riêng biệt. Tệp header (.h) chứa khai 
báo về lớp, còn tệp nguồn (.cpp) chứa định nghĩa về các phương thức của lớp. 
Việc tách này sẽ dễ dàng cho chúng ta trong việc theo dõi, tìm hiểu và phát triển 
chương trình. Ví dụ: 
time.h, time.cpp 
 157 
Phụ lục B. Dịch chương trình C++ bằng GNU C++ 
B.1. Dịch và liên kết 
Quá trình tạo tệp thực thi được từ các tệp mã nguồn có hai bước. 
Bước 1: biên dịch các tệp mã nguồn thành các tệp mã object. Các tệp có mở 
rộng .cpp hoặc .cc được dịch thành các tệp có mở rộng .o. 
Bước 2: liên kết các tệp mã object thành một tệp thực thi được. Các tệp có mở 
rộng .o được liên kết với nhau thành một tập thực thi được (đuôi .exe trong môi 
trường DOS/Windows). 
Nếu chương trình chỉ gồm một tệp mã nguồn, ví dụ count.cpp, ta chỉ cần chạy 
lệnh 
g++ -o count.exe count.cpp 
Kết quả là một tệp thực thi được có tên count.exe. Hoặc ta chỉ dùng lệnh 
g++ count.cpp 
Kết quả là một tệp thực thi được có tên mặc định (a.out trong môi trường 
Unix/Linux). 
Nếu chương trình bao gồm nhiều tệp mã nguồn, chẳng hạn time_test.cpp (chứa 
hàm main), time.cpp, time.h, ta dịch từng tệp có đuôi cpp hoặc cc bằng lệnh sau 
g++ -c file.cpp 
Sau đó liên kết lại bằng lệnh 
g++ time_test.o time.o -o time_test.exe 
B.2. Tiện ích make của GNU 
Ta có biên dịch bằng cách mỗi lần lại gõ từng lệnh như hướng dẫn ở trên. Tuy 
nhiên, với những chương trình lớn bao gồm nhiều tệp mã nguồn, dùng đến 
nhiều thư viện, việc gõ từng lệnh bằng tay mỗi khi cần dịch chương trình không 
phải là cách làm hiệu quả. Tiện ích make trong bộ công cụ GNU cho phép tự 
động hóa quy trình dịch và liên kết chương trình. make là một hệ thống được 
thiết kế để xây dựng các chương trình từ các cây mã nguồn lớn. Từ đặc tả của 
lập trình viên về cây mã nguồn, tiện ích make sẽ gọi trình biên dịch và liên kết 
 158 
một cách hiệu quả nhất để xây dựng chương trình thực thi được. Mục này là 
một hướng dẫn tối giản cho việc sử dụng tiện ích make. 
Để dùng tiện ích make cho một chương trình, lập trình viên phải tạo một tệp có 
tên Makefile nằm trong cùng thư mục với các tệp mã nguồn. Tệp này chứa các 
lệnh hướng dẫn make làm gì và làm thế nào để xây dựng được chương trình. 
Makefile gồm các bộ đặc tả, mỗi bộ quản lý việc cập nhật một tệp. 
Mỗi bộ đặc tả của một tệp Makefile gồm 3 phần: đích (target), các quan hệ phụ 
thuộc (dependency), và các chỉ thị (instruction). Công thức như sau: 
TargetFile: DependencyFile1 DependencyFile2 ... DependencyFilen 
trong đó, TargetFile là tệp cần cập nhật và mỗi DependencyFilei là một tệp 
mà TargetFile phụ thuộc vào nó. Dòng thứ hai của bộ đặc tả là một lệnh dịch 
TargetFile, lệnh này phải có một kí tự TAB đứng trước và kết thúc bằng kí tự 
xuống dòng. Ví dụ, bộ đặc tả đầu tiên trong Makefile của chúng ta như sau: 
time_test.exe: time.o time_test.o 
 g++ time.o time_test.o -o time_test.exe 
trong đó dòng đầu chỉ ra rằng time_test.exe phụ thuộc hai tệp time.o và 
time_test.o, dòng thứ hai là lệnh dùng g++ dịch ra tệp time_test.exe. 
Tiếp theo, time.o không có sẵn ngay khi biên dịch lần đầu, cho nên ta phải viết 
bộ đặc tả cho tệp này: 
time.o: time.cc time.h 
 g++ -c time.cc 
Tương tự là bộ đặc tả cho time_test.o 
time_test.o: time.cc time.h 
 g++ -c time_test.cc 
Do đó, Makefile sẽ có dạng: 
time_test: time.o time_test.o 
 g++ time.o time_test.o -o time_test 
time.o: time.cc time.h 
 g++ -c time.cc 
time_test.o: time.cc time.h 
 g++ -c time_test.cc 
Và khi ta gõ từ dấu nhắc dòng lệnh 
 159 
make 
chương trình make sẽ đọc Makefile và thực hiện các công việc sau: 
1. thấy rằng time_test.exe phụ thuộc vào time.o, và: 
a) Kiểm tra time.o, thấy nó phụ thuộc time.cc và time.h; 
b) Xác định xem time.o đã lỗi thời chưa (cũ hơn bản mới nhất của các 
tệp time.cc và time.h) 
c) nếu đã lỗi thời thì chạy lệnh g++ -c time.cc để tạo time.o 
2. thấy rằng time_test.exe cũng phụ thuộc vào time_test.o, và 
a) Kiểm tra time_test.o, thấy nó phụ thuộc time_test.cc và time.h; 
b) Xác định xem time_test.o đã lỗi thời chưa (chưa được dịch từ bản 
mới nhất của các tệp time_test.cc và time.h) 
c) nếu đã lỗi thời thì chạy lệnh g++ -c time_test.cc để tạo 
time_test.o 
3. thấy rằng tất cả các tệp mà time_test.exe phụ thuộc đều đã được cập nhật, 
nên nó chạy lệnh g++ time.o time_test.o -o time_test để tạo 
chương trình time_test.exe. 
 160 
Phụ lục C. Xử lý xâu bằng thư viện cstring 
C.1. Một số hàm xử lý xâu thông dụng 
char *strcpy( char *d, const char *s ); 
Sao chép xâu s vào mảng char d. Trả về địa chỉ của xâu d. 
char *strncpy( char *d, const char *s, size_t n ); 
Chép tối đa n kí tự từ xâu s vào mảng char d. Trả về địa chỉ mảng d. 
char *strcat( char *d, const char *s ); 
Chép xâu s vào cuối xâu d. Kí tự đầu tiên của xâu s sẽ đè lên kí tự null 
cuối xâu d. Trả về địa chỉ của xâu d. 
char *strncat( char *d, const char *s, size_t n ); 
Chép tối đa n kí tự của xâu s vào cuối xâu d. Kí tự đầu tiên của xâu s sẽ 
đè lên kí tự null cuối xâu d. Trả về địa chỉ của xâu d. 
int strcmp( const char *s1, const char *s2 ); 
So sánh xâu s1 và xâu s2. Trả về một giá trị bằng 0 nếu s1 bằng s2, nhỏ 
hơn 0 (thường là -1) nếu s1 nhỏ hơn s2, hoặc lớn hơn 0 (thường là 1) nếu 
s1 lớn hơn s2 theo thứ tự từ điển. 
int strncmp( const char *s1, const char *s2, size_t n ); 
Tương tự hàm strcmp() nhưng chỉ so sánh n kí tự đầu tiên của xâu s1 với 
n kí tự đầu tiên của xâu s2. 
char *strtok( char *s1, const char *s2 ); 
Một chuỗi các lời gọi hàm strtok có tác dụng tác xâu s1 thành các mảnh 
("token"), chẳng hạn các từ trong một dòng văn bản. Xâu kí tự được tách 
dựa theo các kí tự chứa trong xâu s2. Ví dụ, nếu ta cần tách xâu "Hello, 
how are you?" thành các từ, với ' ', '?', ',' là các kí tự ngăn cách giữa các 
từ, kết quả sẽ là các token "Hello", "how", "are", "you". Tuy nhiên, mỗi 
lần gọi hàm strtok chỉ tách được một token và trả về địa chỉ của token đó. 
Khi không còn tìm thấy token nào, hàm sẽ trả về giá trị NULL. Lần gọi 
đầu tiên trong quá trình phân tách xâu s1 sẽ cần tham số đầu tiên là s1, 
các lần gọi sau sẽ tiếp tục tách s1 nếu tham số đầu tiên là NULL. 
size_t strlen( const char *s ); 
Trả về độ dài của xâu s – là số kí tự đứng trước kí tự null. 
 161 
C.2. Khuyến cáo về việc sử dụng thư viện cstring 
Một số hàm trong thư viện cstring nếu sử dụng không cẩn thận có thể dẫn đến 
việc truy nhập ra ngoài không gian đã được khai báo của mảng hoặc tình trạng 
xâu kí tự không được kết thúc đúng cách bằng kí tự null. Đối với những hàm 
này, lập trình viên phải sử dụng một cách cẩn trọng để đảm bảo không gây ra lỗi 
dữ liệu. Mục này đưa ra một số khuyến cáo về việc sử dụng các hàm này. 
Các hàm strcpy và strncpy sao chép toàn bộ xâu kí tự là tham số thứ hai vào 
mảng char đích mà không quan tâm không gian khai báo của mảng đích có đủ 
chỗ chứa hay không. Lập trình viên phải tự đảm bảo rằng mảng đích có đủ chỗ 
cho xâu nguồn cũng như kí tự null kết thúc xâu đó. Một lời khuyên là nên dùng 
strncpy thay cho strcpy, vì strncpy cho phép kiểm soát được số lượng kí tự 
sẽ được chép vào mảng đích. 
Tương tự, các hàm strcat và strncat chép xâu kí tự là tham số thứ hai vào 
cuối xâu kí tự là tham số thứ nhất mà cũng không quan tâm không gian khai báo 
của mảng đích có đủ chỗ chứa cả hai xâu hay không. Lập trình viên phải tự đảm 
bảo rằng mảng đích có đủ chỗ cho cả hai xâu cũng như kí tự null kết thúc xâu 
thứ hai. strncat cũng được khuyên dùng hơn vì nó cho phép kiểm soát số 
lượng kí tự sẽ được chép vào mảng đích. 
Khi sử dụng strncpy, nếu số kí tự cần chép (tham số thứ ba) không lớn hơn độ 
dài của xâu nguồn (tham số thứ hai), thì kí tự null sẽ không được chép vào 
mảng đích. strncpy cũng không tự chèn thêm một kí tự null vào cuối đoạn vừa 
chép. Trong trường hợp này, nếu lập trình viên không tự gắn kí tự null đánh dấu 
kết thúc xâu kết quả, xâu này có thể trở thành xâu có độ dài không xác định với 
nguy cơ dẫn đến lỗi nghiêm trọng khi chạy chương trình. Tình trạng tương tự 
cũng xảy ra đối với hàm strncat. 
 162 
Tài liệu tham khảo 
[1]. Bjarne Stroustrup, The C++ Programming Language, 3rd edition, 
Addison-Wesley, 1997. 
[2]. Deitel & Deitel, C++ How to Program, 5th edition, Prentice Hall, 2005. 
[3]. ISO/IEC JTC1/SC22/WG21. Stable release, ISO/IEC 14882:2003 (2003) 
[4]. Juan Soulie, C++ Language Tutorial,  

File đính kèm:

  • pdfGiáo trình Ngôn ngữ lập trình C++.pdf
Tài liệu liên quan