Do máy tính chỉ hiểu ngôn ngữ máy, các chương trình viết bằng hợp ngữ khôngthể chạy ngay được mà phải qua giai đoạn hợp dịch assembler thành ngôn ngữ máy.Tuy nhiên, hợp ngữ vẫn còn phụ t
Trang 1BỘ LAO ĐỘNG - THƯƠNG BINH VÀ XÃ HỘI
TỔNG CỤC DẠY NGHỀ
GIÁO TRÌNH
Mô đun : Chuyên đề (Kỹ thuật lập trình) NGHỀ: QUẢN TRỊ MẠNG
TRÌNH ĐỘ: CAO ĐẲNG
( Ban hành kèm theo Quyết định số:120/QĐ-TCDN ngày 25 tháng 02 năm
2013 của Tổng cục trưởng Tổng cục dạy nghề)
Hà Nội, năm 2013
Trang 2TUYÊN BỐ BẢN QUYỀN:
Tài liệu này thuộc loại sách giáo trình nên các nguồn thông tin có thể được phép dùng nguyên bản hoặc trích dùng cho các mục đích về đào tạo và tham khảo.
Mọi mục đích khác mang tính lệch lạc hoặc sử dụng với mục đích kinh doanh thiếu lành mạnh sẽ bị nghiêm cấm.
Trang 3LỜI GIỚI THIỆU
Kiến thức môn học Kỹ thuật lập trình là một trong những nền tản cơ bản của những người muốn tìm hiểu sâu về Công nghệ thông tin đặt biệt đối với việc lập trình để giải quyết các bài toán trên máy tính điện tử Nắm vững các kỹ thuật lập trình là cơ sở để sinh viên tiếp cận với việc thiết kế và xây dựng phần mềm cũng như sử dụng các công cụ lập trình hiện đại
Mặc dầu có rất nhiều cố gắng, nhưng không tránh khỏi những khiếm khuyết, rất mong nhận được sự đóng góp ý kiến của độc giả để giáo trình được hoàn thiện hơn.
Hà Nội, ngày 20 tháng 1 năm 2013
Chủ biên Hồ Viết Hà
Trang 4MỤC LỤC TRANG
LỜI GIỚI THIỆU 3
- Ý nghĩa và vai trò: Đây là môn học cơ sở ngành của các ngành liên quan đến công nghệ thông tin, cung cấp cho sinh viên các kiến thức cơ bản về kỹ thậut lập trình để làm nền tản cho việc lập trình giải quyết các vấn đề cần thiết 4
BÀI 1: GIỚI THIỆU TỔNG QUAN VỀ NGÔN NGỮ LẬP TRÌNH 5
1 Lịch sử phát triển của ngôn ngữ lập trình 5
2 Sự ra đời và thúc đẩy của ngôn ngữ lập trình 5
3 Phân loại các ngôn ngữ lập trình 7
4 Vai trò và ảnh hưởng của phần cứng đối với ngôn ngữ lập trình 9
5 Các thuộc tính của ngôn ngữ lập trình tốt 10
6 Các lĩnh vực ứng dụng của ngôn ngữ lập trình 12
7 Chuẩn hoá ngôn ngữ lập trình 17
8 Các vấn đề nảy sinh từ sử dụng ngôn ngữ lập trình 17
BÀI 2:CÁC LOẠI DỮ LIỆU CẤU TRÚC 20
1 Các kiểu dữ liệu cơ sở 20
2 Kiểu mảng 23
3 Xâu kí tự 30
4 Kiểu cấu trúc 37
5 Kiểu hợp 46
6 Kiểu tập tin (file) 49
7 Các kiểu dữ liệu khác 56
BÀI 3 :HÀM THỦ TỤC 60
1 Khái niệm chương trình con 60
2 Xây dựng hàm và thủ tục 61
3 Cơ chế hoạt động của chương trình con 63
4 Biến toàn cục và biến cục bộ 64
5 Cơ chế truyền tham số 66
6 Tính ưu việt của chương trình con 71
BÀI 4: ĐẶC TRƯNG CÚ PHÁP VÀ NGỮ NGHĨA CHƯƠNG TRÌNH 73
1 Khái niệm ngôn ngữ 73
2 Cây phân tích cú pháp (parsing tree) 75
3 Các vấn đề cú pháp 75
4 Phân tích cú pháp 78
5 Ngữ nghĩa hình thức 79
6 Ngữ nghĩa tiên đề 80
Bài 5: LẬP TRÌNH THỦ TỤC 84
1 Biến và hằng 84
2 Lập trình cấu trúc 84
Trang 5BÀI 6 : LẬP TRÌNH HƯỚNG ĐỐI TƯỢNG 94
1 Trừu tượng hóa (Abstraction) 94
2 Đối tượng (object) 95
3 Lớp (Class) 96
4 Thuộc tính (Attribute) 97
5 Phương thức (Method) 98
6 Thông điệp (Message) 98
7 Tính bao gói (Encapsulation) 99
8 Tính thừa kế (Inheritance) 99
9.Tính đa hình (Polymorphism) 100
BÀI 7:LẬP TRÌNH LOGIC VÀ LẬP TRÌNH HÀM 102
1 Giới thiệu lập trình logic 102
2 Ngữ nghĩa các kí hiệu 103
3 Logic trong Prolog 109
4 Giới thiệu lập trình hàm 109
5 Ngôn ngữ hàm Scheme 110
BÀI 8 : LẬP TRÌNH SONG SONG 116
1 Một số khái niệm 116
2 Xử lý ngoại lệ 116
3 Ðề xuất một ngoại lệ 116
4 Lan truyền một ngoại lệ (Propagating an exception) 117
5 Sau khi một ngoại lệ được xử lý 117
BÀI 9: CÁC PHƯƠNG PHÁP NGÔN NGỮ LẬP TRÌNH KHÁC 118
BÀI 10: PHÂN TÍCH CÚ PHÁP VÀ CHƯƠNG TRÌNH DỊCH 123
1 Chương trình dịch là gì 123
2 Mô hình phân tích - tổng hợp của một trình biên dịch 124
3 Môi trường của trình biên dịch 124
4 Các giai đoạn dịch 125
5 Quản lý bảng ký hiệu 126
6 Xử lý lỗi 127
7 Phân tích từ vựng 127
8 Phân tích cú pháp 127
YÊU CẦU VỀ ĐÁNH GIÁ MÔĐUN 139
TÀI LIỆU THAM KHẢO 140
Trang 6MÔ ĐUN CHUYÊN ĐỀ (KỸ THUẬT LẬP TRÌNH)
Mã mô đun: MĐ 39
* VỊ TRÍ, TÍNH CHẤT, Ý NGHĨA VÀ VAI TRÒ CỦA MÔĐUN
- Vị trí: Là mô đun được bố trí trong học kỳ cuối của năm 2.
- Tính chất: Là mô đun để thực hiện một trong những chuyên đề đã nêu.
- Ý nghĩa và vai trò: Đây là môn học cơ sở ngành của các ngành liên quan đến công nghệ thông tin, cung cấp cho sinh viên các kiến thức cơ bản về kỹ thậut lập trình để làm nền tản cho việc lập trình giải quyết các vấn đề cần thiết.
* MỤC TIÊU MÔĐUN:
- Lựa chọn một chủ đề nghiên cứu và thưc hành riêng cho chuyên ngành học
- Xác định yêu cầu của đề tài, các điều kiện về kỹ thuật, tài chính, hạn chế
- Biết lập kế hoach thực hiện đề tài.
- Sử dụng được các kỹ thuật đã học để thực hiện đề tài.
- Viết được báo cáo đề tài.
- Bố trí làm việc khoa học đảm bảo an toàn cho người và phương tiện học tập
* NỘI DUNG CỦA MÔĐUN:
Trang 7BÀI 1: GIỚI THIỆU TỔNG QUAN VỀ NGÔN NGỮ LẬP TRÌNH
Mã bài : MĐ39-01 Giới thiệu
Trong lĩnh vực công nghệ thông tin, không thể không nói đến các ngôn ngữ lậptrình Bởi vì, chúng là công cụ cần thiết giúp cho chúng ta làm việc và giao tiếp vớimáy tính điện tử Vì vậy, việc nắm được các khái niệm cơ bản của các ngôn ngữ lậptrình là rất cần thiết đối với những ai làm việc trong lĩnh vực công nghệ thông tin hoặccác lĩnh vực có ứng dụng công nghệ thông tin
Mục tiêu
- Nắm được các khái niệm cơ bản về ngôn ngữ lập trình
- Hiểu được lịch sử phát triển của ngôn ngữ lập trình
- Đánh giá sơ bộ về một ngôn ngữ lập trình
- Xác định lĩnh vực ứng dụng của ngôn ngữ lập trình
Nội dung chính
Giới thiệu lịch sử phát triến của ngôn ngữ lập trình và các khái niệm của chúng.Chỉ ra các yếu tố ảnh hưởng đến sự phát triển của ngôn ngữ lập trình và các lĩnh vực ứng dụng của ngôn ngữ lập trình
1 Lịch sử phát triển của ngôn ngữ lập trình
Mục tiêu: Trình bày lịch sử phát triển của ngôn ngữ lập trình, các kỹ thuật lập
trình
Những ngôn ngữ lập trình (programming language) đầu tiên trên máy tính điện
tử là ngôn ngữ máy (machine language), tổ hợp của các con số hệ nhị phân, hay các bit
(binary digit) 0 và 1 Ngôn ngữ máy phụ thuộc vào hoàn toàn kiến trúc phần cứng của
máy tính và các quy ước khắt khe của nhà chế tạo Để giải các bài toán, những người
lậ trình phải sử dụng một tập hợp các lệnh điều khiển rất sơ cấp mà mỗi lệnh là tổ hợpcác bit nhị phân nên gặp rất nhiều khó khăn, mệt nhọc, rất dễ gặp phải sai sót, nhưngrất khó sửa lỗi
Từ những năm 1950, để giảm nhẹ việc lập trình, người ta đưa vào kỹ thuậtchương trình con (sub-program hay sub-routine) và xây dựng các thư viện chươngtrình (library) đẻ khi cần thì gọi đến hoặc dùng lại các đoạn chương trình đã viết
Như thế, chúng ta nhận thấy ở vào giai đoạn sơ khai ban đầu của máy tính điện
tử, việc sử dụng máy tính là rất khó khăn, vì ngôn ngữ lập trình là phương tiện giaotiếp lại quá phức tạp đối với người sử dụng Người sử dụng máy tính vào giai đoạn nàychỉ là các chuyên gia về tin học Như thế, ứng dụng của máy tính điện tử vẫn còn rấthạn chế
2 Sự ra đời và thúc đẩy của ngôn ngữ lập trình
Cũng từ những năm 1950, ngôn ngữ hợp dịch, hay hợp ngữ (assembly) ra đời.Trong hợp ngữ, các mã lệnh và địa chỉ các toán hạng được thay thế bằng các từ gợinhớ, như ADD, SUB, JUMP, … tương ứng với các phép toán số học +, -, lệnh chuyểnđiều khiển, …
Trang 8Do máy tính chỉ hiểu ngôn ngữ máy, các chương trình viết bằng hợp ngữ khôngthể chạy ngay được mà phải qua giai đoạn hợp dịch (assembler) thành ngôn ngữ máy.Tuy nhiên, hợp ngữ vẫn còn phụ thuộc nhiều vào phần cứng và xa lạ với ngôn ngữ tựnhiên, người lập trình vẫn gặp nhiều khó khăn khi giải các bài toán trên máy tính, đặcbiệt là các bài toán tương đối lớn.
Năm 1957, hãng IBM đưa ra ngôn ngữ FORTRAN (FORmula TRANslator).Đây là ngôn ngữ lập trình đầu tiên gần gũi với ngôn ngữ tự nhiên với cách diễn đạttoán học FORTRAN cho phép giải quyết nhiều loại bài toán khoa học, kỹ thuật và sau
đó được nhanh chóng ứng dụng rất rộng rãi cho đến ngày nay với kho tàng thư việnthuật toán rất đồ sộ và tiện dụng
Tiếp theo là sự ra đời của các ngôn ngữ ALGOL 60 (ALGOrithmic Language)vào năm 1960, COBOL (Common Business Oriented Language) vào năm 1964,Simula vào năm 1964, …
Theo sự phát triển của máy tính điện tử, các ngôn ngữ lập trình không ngừngđược cải tiến và hoàn thiện đẻ ngày càng đáp ứng nhu cầu của người sử dụng và làmgiảm nhẹ công việc lập trình Sự phát triển của ngôn ngữ lập trình đã làm xích gần lại
“khoảng cách” giữa người sử dụng và máy tính, nghĩa là máy tính không còn chỉ được
sử dụng bởi các chuyên gia tin học mà có thể được sử dụng bởi rất nhiều người trongnhiều lĩnh vực khác nhau
Rất nhiều ngôn ngữ lập trình đã được ra đời trên nền tảng lý thuyết tính toán vàhình thành nên hai loại ngôn ngữ lập trình: ngôn ngữ bậc thấp và ngôn ngữ bậc cao.Các ngôn ngữ bậc thấp (low-level language) gồm hợp ngữ và ngôn ngữ máy, thườngđược dùng để viết các chương trình điều khiển và kiểm tra thiết bị, …
Các ngôn ngữ bậc cao (high-level language) là phương tiện giúp người làm tin học giảiquyết các vấn đề thực tế đồng thời cũng là nơi mà những thành tựu mới nhất của khoahọc máy tính được đưa vào
Lĩnh vực nghiên cứu các ngôn ngữ lập trình vừa có tính truyền thống vừa cótính hiện đại Ngày nay, với các tiến bộ của khoa học công nghệ, người ta đã có thể sửdụng các công cụ hình thức cho phép giảm nhẹ công việc xây dựng các hệ thốngchương trình từ phân tích, thiết kế cho đến sử dụng ngôn ngữ lập trình
Chúng ta có thể có cài nhìn toàn cảnh hơn về lích sử của các ngôn ngữ lập trìnhqua hình vẽ dưới đây:
Trang 93 Phân loại các ngôn ngữ lập trình
Cho đến nay có hàng trăm ngôn ngữ lập trình được đề xuất nhưng trên thực tếchỉ có một số ít ngôn ngữ được sử dụng rộng rãi Ngoài cách phân loại theo bậc như đãnói ở trên, người ta còn phân loại ngôn ngữ lập trình theo phương thức (paradgm),theo mức độ quan trọng, theo thế hệ,
Cách phân loại theo mức hay bậc là dựa trên mức độ trừu tượng so với các yếu
tố phần cứng, chẳng hạn như lệnh (instruction) và cấp phát bộ nhớ (memoryallocation) dưới đây:
Thấp Lệnh máy đơn
giản
Truy cập và cấp phát trựctiếp
Hợp ngữ
Cao Biểu thức và điều
kiện tương minh Truy cập và cấp phát nhờcác phép gán C, Pascal, AdaRất cao Máy trừu tượng Truy cập ẩn và tự động cấp
phát
Prolog, Miranda
Trang 10Những năm gần đây, ngôn ngữ lập trình phát triển theo phương thức lập trình(còn được gọi là phong cách hay kiểu lập trình) Một phương thức lập trình có thểđược hiểu là một tập hợp các tính năng trừu tượng đặc trưng cho một lớp ngôn ngữ mà
có nhiều người lập trình thường xuyên sử dụng chúng Sau đây là sơ đồ minh họa sựphân cấp các phương thức lập trình:
Sau đây là một số ngôn ngữ lập trình quen thuộc liệt kê theo phương thức:
• Các ngôn ngữ thủ tục (procedural language) có Fortran (1957), Cobol(1959), Basic (1965), Pascal (1971), C (1969), Ada (1975), …
• Các ngôn ngữ hướng đối tượng (object-oriented language) có Smalltalk(1971), C++ (1985), Eiffel (1990), Java (1995), C# (2000), …
• Các ngôn ngữ hàm (functional language) có Lisp (1958), ML (1973),Scheme (1975), Caml (1987), Miranda (1982), …
• Các ngôn ngữ dựa logic (logic-based language) chủ yếu là ngôn ngữ Prolog(1972)
• Các ngôn ngữ thao tác cơ sở dữ liệu SQL (1980),…
• Các ngôn ngữ xử lý song song như Ada, Occam (1982), C-Linda, …
Ngoài ra còn có một số phương thức lập trình đang được phát triển ứng dụng như:
• Lập trình phân bổ (distributed programming)
• Lập trình ràng buộc (constraint programming)
• Lập trình hướng truy cập (access-oriented programming)
• Lập trình theo luồng dữ liệu (dataflow programming)
Việc phân loại các ngôn ngữ lập trình theo mức độ quan trọng là dựa trên cái gì(what) sẽ thao tác được, hay tính được, so với cách thao tác như thế nào (how) Mộtngôn ngữ thể hiện cái gì sẽ thao tác được mà không chỉ ra cách thao tác như thế nàođược gọi là ngôn ngữ định nghĩa (definitional) hay ngôn ngữ khai báo (declarative).Một ngôn ngữ thể hiện cách thao tác như thế nào mà không chỉ ra cái gì sẽ thao tácđược gọi là ngôn ngữ thao tác (operational) hay không khai báo (non-declarative), đó
• Thế hệ 5: ngôn ngữ suy diễn hay dựa logic
• Thế hệ 6: mạng nơ-ron (neural networks)
Logic Hàm Cơ sở dữ
liệu
Trang 114 Vai trò và ảnh hưởng của phần cứng đối với ngôn ngữ lập trình
Ngôn ngữ lập trình liên quan chặt chẽ đến kiến trúc máy tính (phần cứng) mà
nó chạy trên đó Chương trình viết bằng một ngôn ngữ, dù là ngôn ngữ đó thế nào đinữa thì cũng phải chuyển sang mã máy để thực thi Ngôn ngữ máy gắn chặt vào kiếntrúc máy tính, vì vậy hiểu quả thực thi của ngôn ngữ cũng phụ thuộc rất nhiều vào kiếntrúc máy tính
Một kiến trúc máy tính xử lý tuần tự không thể thực hiện song song thật sựnhiều phát biểu trong chương trình, dù cho dạng đặc tả trong ngôn ngữ là xử lý songsong Một kiến trúc máy tính chỉ cho phép đọc/ghi mỗi lần một từ nhớ không thể bảođảm việc xử lý đồng thời cả một đối tượng dữ liệu, dù rằng dạng đặc tả của hầu nhưtấct cả các ngôn ngữ lập trình hiện nay là thao tác trên cả một đối tượng dữ liệu
Kiến trúc may tính cũng ràng buộc quá trình thiết kế ngôn ngữ chạy trên máytính đó Ngôn ngữ lập trình càng xa ngôn ngữ máy bao nhiêu thì càng khó thực hiệnbấy nhiêu Trong trường hợp đó chương trình dich sẽ phức tạp và đòi hỏi mô phỏngnhiều Quá trình dịch cũng sẽ sinh ra những đaọn mã máy thừa, và do đó khó đạt đượchiệu quả cao trong việc sử dụng phần cứng máy tính
Kiến trúc của hầu hết máy tính hiện nay là kiến trúc Von Neumann Kiến trúcVon Neumann có hai đặc điểm đáng chú ý sau:
• Các lệnh được xử lý tuần tựtheo thứ tự sắp xếp trong bộ nhớ Đặc điểm nàythể hiện rõ ở các ngôn ngữ lập trình thủ tục, trong đó các phát biểu đượcthực hiện theo thứ tự sắp xếp trong chương trình Các quá trình mang bảnchất xử lý song song không thể được thực hiện một cách hiệu quả trên kiếntrúc Von Neumann
• Chỉ cho phép đọc/ghi mỗi lần một từ nhớ Kết quả là đối tượng dữ liệu phải
bị phân nhỏ ra trước khi đọc/ghi đối tượng dữ liệu đó Quá trình xử lý dữliệu do vậy bị chậm đi gây nên sự tắc nghẽn trong ”giao thông” các đốitượng dữ liệu
Giả sử s là một biến chuỗi, phép gán s:= ‘abc’ không làm thay đổi tức thời đốitượng mà thông qua việc cắt từng kí tự của chuỗi ở vế phải vào s
Các đối tượng dữ liệu kiểu bản ghi, như trong ngôn ngữ Pascal, không đượcxuất hiện như sự xuất hiện của nó với tư cách là một thực thể hoàn chỉnh trong chươngtrình Chẳng hạn, phép gán x := y, với x và y là hai biến cùng một kiểu bản ghi, đượcthực hiện bằng cách đọc từng thành phần của y và chi vào thành phần tương ứng của
x Bản thân mỗi thành phần x và y lại tiếp tục bị phân rã trong quá trình đọc/ghi
Ngay cả việc đọc/ghi đối tượng dữ liệu đơn giản như số nguyên dài hai từ nhớ(longint) cũng phải được thực hiện hai lần
Các phương thức lập trình mới như lập trình hàm, lập trình hướng đối tượng,lập trình logic đang từ bỏ dần dần kiến trúc Von Neumann Lisp là ngôn ngữ điển hìnhcủa họ lập trình hàm, tuy nhiên các đặc tính hàm ban đàu của Lisp cũng đã bị sửa đổi
để có thể cài đặt hiệu quả trên kiến trúc máy tính cổ điển Prolog đại diện cho họ ngônngữ lập trình logic, là một công cụ đặc tả vấn đề tốt, nhưng hiệu quả của nó chưa đượcnhư mong muốn do cách giải quyêt vấn đề trên đặc tả của ngôn ngữ bị hạn chế bởi cơchế điều khiển của kiến trúc máy tính hiện thời
Tóm lại, vì sự ảnh hưởng đáng kể của phần cứng như vừa trình bày đối vớingôn ngữ lập trình, bước nhảy vọt thật sự trong ngôn ngữ lập trình, với một ngôn ngữ
Trang 12mới thay đổi tận gốc, chỉ có khi có một kiến trúc máy tính mới bảo đảm cho sự cài đặthiệu quả của ngônngữ mới trên đó.
5 Các thuộc tính của ngôn ngữ lập trình tốt
Một ngôn ngữ lập trình tốt cần phải thỏa mãn một số yêu cầu cơ bản sau đây:
dễ viết, dễ đọc và tin cậy
Một ví dụ khác là khai niệm đệ quy Đệ quy không chỉ là một kỹ thuật để lậptrình mà còn là công cụ để tư duy Có những vấn đề mà người lập trình không nghĩ ramột cách giải quyết nào khác ngoài cách sử dụng đệ quy Vì vậy, ngôn ngữ cần chophép gọi đệ quy các chương trình con Tuy nhiên, các ngôn ngữ bậc cao đầu tiên nhưFortran, Cobol không cho phép gọi đệ quy Muốn thực hiện lời giải đệ quy trên cácngôn ngữ này phải gỡ đệ quy, tức là chuyển lời giải đệ quy thành lời giải lặp
Ngôn ngữ phải đơn giản, để dễ học, dễ nhớ và dễ nắm vững Ngôn ngữ khôngnên đưa ra quá nhiều khái niệm làm cho người sử dụng thấy rối rắm Chẳng hạn, nhưngôn ngữ C có quá nhiều toán tử Nếu như trong Pascal các toán tử Not, And và Ỏđược dùng chung cho kiểu dữ liệu logic và kiểu dữ liệu số học thì trong C lại có sựphân biệt: các toán tử !, &&, || dùng cho kiểu logic còn các toán tử ~, & và | dùng chokiểu dữ liệu số học Số lượng toán tử nhiều, các kí hiệu lại gần giống nhau và khônggợi nhớ đã làm tăng tính phức tạp của ngôn ngữ C
Ngôn ngữ phải linh hoạt, không nên quá gò bó vào một nguyên tắc nào đó.Chẳng hạn một trong những nguyên tắc của ngôn ngữ Pascal là: mỗi cấu trúc điềukhiển chỉ có một ngõ vào và một ngõ ra Nó ngăn cấm sự kết thúc bất thường từ bêntrong vòng lặp For và các vòng lặp có điều kiện như While và Repeat, cũng như khôngcho nhiều điểm trở về trong chương trình con Nguyên tắc này nhằm đảm bảo tính cấutrúc của chương trình nhưng đôi khi cũng gây trở ngại cho người lập trình Ngôn ngữ
C linh hoạt hơn với các phát biểu Break và Return Ví dụ, trong trường hợp sau, phátbiểu Return của C tránh được các phát biểu if lồng nhau:
Trang 13Ngôn ngữ cần đảm bảo cho cấu trúc chương trình phản ánh được cấu trúc củavấn đề cần giải quyết Chương trình cũng như các bộ phận của chương trình cần thểhiện được chúng làm những gì, trước khi người đọc cần biết những điều đó được thựchiện như thế nào.
Các cấu trúc điều khiển của ngôn ngữ chỉ nên có một ngõ vào và một ngõ ra đểngười đọc có thể theo dõi dễ dàng từng bộ phận của chương trình từ trên xuống dưới.Cũng do vây ngôn ngữ cần có các cấu trúc điều khiển để thay thế phát biểu goto Phátbiểu goto làm chương trình trở nên khó đọc, vì người đọc không thể đọc chương trìnhmột mạch từ trên xuống, mà luôn phải dò theo các đích của goto
Việc cho phép dấu gạch ngang dưới trong danh hiệu sẽ làm cho danh hiệu dễđọc hơn
Các từ khóa của ngôn ngữ cũng cần phải gợi nhớ
Ngoài ra, các chú thích trong chương trình là cách thức hữu hiệu để nâng caotính dễ đọc của chương trình
Với các ngôn ngữ lập trình hiện nay, tính dễ đọc của chương trình còn tùythuộc vào việc người đọc có quen thuộc với ngôn ngữ dùng để viét chương trình haykhông, cũng như phong cách và phương pháp lập trình của người viết chương trình
5.3 Tính tin cậy (reliability)
Tính tin cậy của ngôn ngữ lập trình được đánh giá trên khả năng mà ngôn ngữ
có thể bảo đảm được cho tính tin cậy của chương trình viết bằng ngôn ngữ đó Không
có một định nghĩa rõ ràng cho tính tin cậy của chương trình Một cách không hìnhthức, chương trình được xem là tin cậy nếu xác xuất chạy đúng của nó cao trong quátrình sử dụng
Nói chúng để chương trình có độ tin cậy cao, ngôn ngữ cần hạn chế sự xuấthiện của các lỗi không thể ngờ được Lỗi đó có thể sinh ra do một cấu trúc ngữ phápnhiều ngữ nghĩa Ví dụ phát biểu sau đây trong Fortran:
Sum (i, j) = i + j
Trang 14Có hai nghĩa: (1) đó là định nghĩa hàm tổng của hai đối số nguyên, (2) hoặc đó
là phép gán một biểu thức vào dãy biến Nếu người lập trình quên khai báo biến dãySum thì phát biểu trên sẽ được hiểu theo nghĩa thư nhất, chứ không phải là nghĩa thứhai như mong muốn (việc quên khai báo biến trong Fortran là bình thường vì Fortrancho phép sử dụng biến mà không cần khai báo)
Hiệu ứng lề cũng là nguồn gây ra lỗi Hiệu ứng lề, theo nghĩa rộng là hiệu ứngphụ xuất hiện thường ngoài ý muốn, khi sử dụng một cấu trúc ngôn ngữ nào đó củangôn ngữ Ví dụ, trong Pascal hiệu ứng lề nảy sinh do sự thay đổi trị của biến khôngcục bộ trong các chương trình con mà biến có ý nghĩa
Ngôn ngữ cần kiểm tra chặt chẽ sự tương hợp kiểu của các biến trong biểu thức
và phép gán, sự tương hợp của danh sách thông số của chương trình con ở nơi gọi vànơi định nghĩa Lấy ví dụ đơn giản là phép gán một giá trị thực vào biến nguyên Nếukhông có sự kiểm tra kiểu và báo lỗi, mà tự động đổi kiểu thì kết quả sau đó sẽ bị sailệch đi vì giá trị thực đã bị cắt hoặc làm tròn phần lẽ để thành giá trị nguyên
Các bộ phận của chương trình cần có tính độc lập đối với nhau cao, cho phépkiểm tra riêng rẽ tính đúng đắn từng bộ phận của chương trình Tính dễ sửa đổi cũngliên quan với tính tin cậy, vì trong quá trình sửa đổi tính tin cậy vần phải được duy trì
Sự độc lập của các bộ phận của chương trính sẽ làm cho việc sửa đổi dễ dàng hơn;việc sửa đổi ở một bộ phận sẽ không ảnh hưởng đến các bộ phận còn lại cảu chươngtrình
Tính tin cậy đôi khi lại có thể bị ảnh hưởng bởi tính dễ viết của chương trình.Bởi vì ngôn ngữ quá linh hoạt dễ viết thì có thể khó làm chủ bởi người viết chươngtrình, có nghĩa là chương trình dễ xảy ra lỗi hơn
Cuối cùng, tính tin cậy của ngôn ngữ còn phụ thuộc vào sự cài đặt ngôn ngữ ấy,tức là phụ thuộc vào chất lượng của chương trình dịch
Dưới đây là một số ngôn ngữ lập trình và lĩnh vực ứng dụng của chúng:
• Xây dựng các hệ thống thông tin quản lý trong các lĩnh vực sản xuất, xãhội, kinh tế, : Delphi, Visual Basic, Access, SQL,
• Xây dựng các hệ thống phân tán: Java, Corba, C++,
• Xử lý ảnh và mô hình hóa hình học: C++, Matlab,
• Xây dựng các hệ chuyên gia: Prolog
• Giải quyết các bài toán trong lĩnh vực trí tuệ nhân tạo: Lisp, Scheme,Prolog,
• Xây dựng các hệ thống thời gian thực: C, Ada
• Xây dựng các hệ thống nhúng, điều khiển thiết bị: C, Assembly,
Hiện nay, số người quen với máy tính, với việc lập trình ngày một nhiều, PC đãtrở nên phổ biến Nhu cầu được giao tiếp với thế giới bên trong máy tính không chỉ là
Trang 15một sở thích, hay công việc riêng tư của những người làm tin học nữa Chỉ với vốntiếng Anh tương đối, một chút trợ giúp là bạn đã có thể trở thành một nhà lập trình rồi,thế nhưng đó chỉ là các điều kiện cần mà chưa đủ Số lượng trình biên dịch, chủngloại, tính năng ngày một phong phú, để chọn cho mình một ngôn ngữ lập trình, mộttrình biên dịch phù hợp với công việc chuyên môn cũng như nhu cầu học tập, nghiêncứu, bạn không thể không khỏi có những đắn đo Những gì sau đây có thể giúp ích chobạn ?
Để có cho mình một công cụ lập trình phù hợp về cả trình độ lẫn nhu cầu, bạncần xác định xem bạn sẽ dùng nó để làm gì; tìm hiểu thế giới bên trong máy tính, chỉ
để học thêm một ngôn ngữ lập trình mới nhằm phục vụ cho quá trình học tập, hay đó
là một lựa chọn cho một hướng phát triển phần mềm chuyên nghiệp ? Hơn thế nữa bạncòn cần phải định hướng rõ ràng; môi trường thực hiện sẽ là môi trường phân tán haymôi trường cục bộ ? Có thể là hơi rắc rối nhưng những suy tính ban đầu này sẽ có ảnhhưởng rất nhiều tới các bước đi sau này
Những người có ham muốn tìm hiểu sâu thế giới bên trong máy tính thường lấyhợp ngữ (Assembly) làm công cụ, có thể nói đây là thứ ngôn ngữ đầu tiên tương đốiđộc lập đối với các quá trình thực xảy ra trong các bộ vi xử lý Qua một tập hữu hạncác lệnh được nhận biết nhờ các từ gợi nhớ sơ đẳng, người lập trình có thể trực tiếpcan thiệp vào quá trình di chuyển dữ liệu, sửa đổi dữ liệu, điều khiển thiết bị Côngviệc còn lại của trình dịch Assembler rất ít, phần lớn nhiệm vụ của nó là ánh xạ cáclệnh gợi nhớ trong chương trình nguồn tới một tập cố định các lệnh của bộ vi xử lý,một số thao tác xử lý macro
Để có được một chương trình hoàn chỉnh, người lập trình sẽ phải tìm hiểu thấuđáo tập lệnh, vì số lệnh, các chi tiết kỹ thuật cho tập lệnh có thể rất khác nhau giữa các
bộ vi xử lý; định hình rõ ràng trình tự các thao tác; khả năng mà trình dịch có thể làmđược; và nhất là xác định mức độ cần thiết của các thủ thuật lập trình Chẳng hạn,trong khi các bộ vi xử lý dòng Intel (x86 phổ dụng trong các máy PC) thường cókhoảng 8 thanh ghi đa năng, 6 thanh ghi đoạn, một thanh ghi con trỏ lệnh, cờ thì các
bộ vi xử lý dòng Motorola (MC680x0 phổ dụng trong các máy MacIntosh, các máytrạm của Sun, trong các hệ thống máy tính nhiều bộ vi xử lý, và trong rất nhiều máyPC) thì lại có tới khoảng 8 thanh ghi dữ liệu 80 bit, khoảng ngần ấy số thanh ghi địachỉ cùng hàng tá thanh ghi với rất nhiều công dụng khác nhau, chế độ làm việc khácnhau
Chính vì tính chỉ định phần cứng cao như vậy mà hiệu quả làm việc của mộtngười thông qua hợp ngữ phụ thuộc rất nhiều vào kinh nghiệm làm việc, theo đó cácchương trình này rất khó bảo trì, khó kiểm soát khi số thao tác của chương trình tăng,
và đôi khi còn khó hiểu đối với chính người viết ra nó nếu không có các văn bản bảotrì được ghi chép cẩn thận Nhưng bù lại, các chương trình thực hiện bằng hợp ngữ nóichung thường có kích thước rất khiêm tốn, chạy nhanh nhất tính trên cùng một trình tựthao tác cụ thể so với các ngôn ngữ khác
Basic vốn là một ngôn ngữ phi cấu trúc, nó được phát triển để giúp người lậptrình đỡ phần vất vả khi làm việc trên các bộ vi xử lý khác nhau Với nó, người lậptrình không phải lo lắng nhiều về sự khác nhau trong chi tiết kỹ thuật của từng bộ vi
xử lý cụ thể, họ chỉ cần bận tâm tới việc cấu trúc sao cho chương trình của họ được tối
Trang 16ưu Để có được tính khả chuyển trên nhiều loại vi xử lý, các chương trình Basic cần cómột chương trình thông dịch để kích hoạt, trình thông dịch này có nhiệm vụ ánh xạ mãđầu ra của trình dịch Basic vào tập lệnh cụ thể của bộ vi xử lý khi chạy chương trình.Người ta đã từng đưa trình thông dịch này vào trong phần cứng, lưu trữ lâu dài trongcác bộ nhớ chỉ đọc (ROM), và cung cấp các khả năng tương tác tương đối thuận tiện,giúp người lập trình thiết kế và gỡ rối nhanh chóng các chương trình Basic
Ngày nay, Basic đã được cải tiến nhiều, về cả trình dịch lẫn bản thân ngôn ngữ,các ứng dụng của Microsoft thường dùng Basic như một công cụ để người sử dụng tuỳbiến chúng theo nhu cầu Vì chạy thông dịch cho nên các ứng dụng viết bằng Basicchạy không nhanh, nhưng vì tính phổ cập, rất nhiều nhà phát triển công cụ vẫn hỗ trợ
nó Sản phẩm hỗ trợ Basic ở mức cao được nói đến ở đây là Visual Basic củaMicrosoft Đây là một công cụ phát triển được Công ty này rất ưu ái, hiện nó đangđược ưu chuộng trong lĩnh vực phát triển ứng dụng trên Windows Visual Basic được
hỗ trợ rất nhiều khả năng về cơ sở dữ liệu, các kỹ thuật phát triển phần mềm mới nhưOLE, COM, DCOM
Nếu như bạn chưa có ý định trở thành nhà phát triển phần mềm ứng dụng thìcũng nên biết tới Basic, bởi vì hầu hết các ứng dụng lớn ngày này như Notes, bao gồm
cả các phần mềm xử lý bảng tính, văn bản của Mirosoft đều có sử dụng macro lệnhđược thiết kế dựa trên Basic, cho phép người sử dụng sửa đổi, bổ sung các tính năngmới theo nhu cầu
Ngoài ra còn phải nói tới Pascal, có thể nói đây là thứ ngôn ngữ vỡ lòng chohầu hết những người bắt đầu tiếp xúc với máy tính Nó được biết tới không chỉ vì làmột trong số các ngôn ngữ cấu trúc ra đời đầu tiên trên thế giới, mà còn là vì tính dễđọc, dễ tiếp cận của nó Nếu bạn biết tiếng Anh, không nhất thiết phải biết về tin học,khi đọc một chương trình viết trong ngôn ngữ này bạn sẽ thấy ngay về cơ bản nó đangnói về một quá trình làm việc nào đó
Với thứ ngôn ngữ này, người lập trình khỏi phải đau đầu vì phải tổ chức lấychương trình, thay vào đó họ sẽ dùng các câu lệnh tiếng Anh rất dễ nhớ, dễ sử dụng.Việc xây dựng một chương trình rất giống với việc mô phỏng một quá trình hoạt động,
có đầu ra đầu vào, mã nguồn của một chương trình như thế rất dễ đọc, dễ sửa đổi Tấtnhiên, trình dịch sẽ phải làm việc vất vả hơn bởi nó phải phân giải cả một dãy lệnh vốnchỉ dễ hiểu đối với con người nhưng lại không thể hiểu nổi đối với các bộ vi xử lý.Hầu hết các ngôn ngữ lập trình cấu trúc (tất nhiên trong đó có Pascal) đều lấy việc dịchsang hợp ngữ làm một bước trung gian, theo đó các cấu trúc lệnh if then, case of,v.v được chuyển thành các khối mã nguồn Assembly Tóm lại, việc cấu trúc chi tiếtcho một chương trình cụ thể được thực hiện tự động bởi trình dịch, lúc này các thủthuật lập trình Assembly của người lập trình không còn có thể áp dụng vào đây, đôikhi nó còn máy móc làm phình to mã cho dù đã sử dụng tới cả chục thuật toán tối ưu
Hầu hết các công cụ phát triển có hỗ trợ Pascal ngày nay đều đưa ra các khả năng kếtnối mới cho nó, mã trình có thể được viết riêng rẽ trên nhiều tệp rồi kết nối, hoặc đượcnạp từ thư viện động nhưng nói chung, đây là ngôn ngữ chỉ phù hợp với các ứngdụng nhỏ và trung bình, phổ dụng trong lĩnh vực đào tạo Nếu bạn là người mới tiếpxúc với máy tính, muốn tìm hiểu cách hoạt động của một chương trình thì bạn hãychọn ngôn ngữ này
Trang 17Delphi của Borland chỉ là một công cụ phát triển ứng dụng, nó được xây dựngbằng lõi Pascal Với công cụ này, sau một vài tiếng đồng hồ đọc help, nhất là có ai đóhướng dẫn đôi chút, bạn hoàn toàn có thể tự viết cho mình các ứng dụng đơn giản nhưtrình xem tệp AVI, nghe nhạc, các thao tác tính toán, lưu trữ đơn giản Nó tỏ ra rấtthích hợp với những bạn thích khám phá nhưng không muốn tốn quá nhiều thời giannghiền ngẫm
Ngôn ngữ C là ngôn ngữ lập trình cấu trúc như Pascal và là thứ công cụ mạnh
đã từng được sử dụng để thiết kế hầu hết các hệ điều hành trên thế giới Các hệ điềuhành như UNIX, AMOEBA đều thực thi bằng C, và nói chung đây là thứ ngôn ngữ
có tính khả chuyển tương đối cao cho nên các hệ điều hành này có thể chạy trên rấtnhiều phần cứng khác nhau, ngay cả với WINDOWS cũng vậy, rất nhiều module của
nó cũng được xây dựng bằng C
C++ là một bước phát triển tiếp theo của C trong xu thế 'đối tượng hoá' ngônngữ, nói như vậy là bởi hầu hết các trình dịch C++ đều lấy C làm nền cho tất cả cácđịnh hướng nhằm tận dụng các ưu thế mà mô hình thiết kế hướng đối tượng mang lại.Vốn dĩ C vẫn chưa được chuẩn hoá mặc cho rất nhiều cố gắng đã được đưa ra, cáctrình dịch C++ lại càng khó tìm được tiếng nói chung Các nhà cung cấp trình dịch Cđều muốn rằng sản phẩm của họ được các nhà phát triển công cụ ưa dùng, thế nhưngcác nhà cung cấp công cụ phát triển lại muốn các trình dịch hướng theo mô hình thiết
kế vốn muôn hình muôn vẻ mà họ đưa ra Cứ như thế, C++ phát triển trong sự thiếunhất quán, hệ thống từ khoá không được hỗ trợ đầy đủ, đôi khi không thống nhất, cáchcấu trúc chương trình cũng không giống nhau mặc dù chúng giống nhau về mô hình
Ngày nay, hầu hết các công cụ phát triển hệ thống mạnh như Visual C++, C++Builder, Visual Age đều hỗ trợ song song cả C lẫn C++ Nói chung đây là các công
cụ mạnh, thể hiện được ưu thế của chúng trong từng môi trường phát triển cụ thể; ví
dụ Visual C++ thích hợp với những người muốn phát triển các ứng dụng nhất là cácứng dụng gắn với Windows, C++Builder thân thiện ngay cả với những người khôngnhiều kinh nghiệm trong lĩnh vực lập trình, Để tìm cho mình một trình dịch C++phù hợp hãy lựa chọn; chẳng hạn, nếu bạn cần hướng theo việc xây dựng các ứngdụng phục vụ, có liên quan tới các dịch vụ chuẩn của Windows, không nhất thiết phải
có màn hình giao tiếp phức tạp, hoặc cần có các ứng dụng can thiệp sâu vào hệ thống bạn hãy lựa chọn Visual C++ Công cụ này đưa ra khá nhiều mẫu (wizard), theo khungđịnh sẵn đó bạn chỉ cần thực thi các chi tiết là đã có một ứng dụng hoàn chỉnh rồi Cònnếu bạn không đủ thời gian cần thiết để nghiền ngẫm cả đống các văn bản công bố từMicrosoft, mà lại muốn có các ứng dụng mang tính bề mặt, nhanh, đầy tính tương tác,bạn hãy sử dụng C++Builder hay một số sản phẩm tương tự từ IBM, Symantec
Java là ngôn ngữ thế hệ mới, thế hệ năm, nó kế thừa hầu hết những 'tư chất' tốt đẹp củacác bậc tiền bối, hướng đối tượng từ mô hình thiết kế tới mô hình thực thi, hỗ trợ đaluồng một cách rất tinh tế, độ tin cậy cao, tính khả chuyển tuyệt vời Java nay khôngcòn là một cơn sốt bình thường, nó là một xu thế song song tồn tại với các mô hình lậptrình hiện có, ngày càng nhiều lĩnh vực mà nó có mặt Ban đầu, mục tiêu của các nhàthiết kế của ngôn ngữ này là "Web đi tới đâu, Java đi tới đó", nay thì sao, nó đang lenlỏi vào cả các hệ thống đầy tính thương mại như các hệ quản trị dữ liệu của ORACLE,rồi cả các hệ thống phục vụ cực lớn Với phiên bản 2, từ tên ấn bản JDK được đổi
Trang 18thành SDK, Sun dần lộ rõ những ham muốn rất lớn lao trong việc đưa Java vào đờisống tin học của mọi người trên thế giới.
Java là ngôn ngữ mạnh, về cả mô hình thiết kế lẫn tính năng Nếu bạn muốnthiết kế các trang Web sống động, bạn hãy chọn nó, một khối mã CLASS vài KB cóthể làm được nhiều điều hơn cả 100KB ảnh, nó là giải pháp cho một đường truyền tốc
độ thấp Nếu bạn muốn thiết kế các chương trình phân tán, Java là một lựa chọn tốt, nó
có một lượng thư viện mạng được tổ chức hợp lý, thân thiện với người lập trình Với
nó bạn có thể tự thiết kế lấy các giao thức (ngay cả các giao thức lạ lẫm chưa từngđược nhắc tới trong RFC), các ứng dụng phục vụ, và các ứng dụng sử dụng dịch vụ
mà không đòi hỏi mất quá nhiều thời gian tìm hiểu hệ thống, tìm kiếm các công bố kỹthuật Nếu bạn cần viết các ứng dụng mà mã của chúng có thể được sử dụng lại mộtcách linh hoạt, trên nhiều loại phần cứng, tốn ít thời gian bảo trì và hợp 'thời' nhất,bạn cũng nên chọn Java Với các ngôn ngữ khác, việc sử dụng lại mã rất khó, ví dụbạn đã có một tệp dll, cùng với hàng tá chi tiết kỹ thuật kèm theo bạn cũng rất khó sửdụng lượng thư viện có trong đó, đấy là chưa tính tới việc mã thư viện động này chỉ cóthể sử dụng được trên các hệ thống Windows Với Java thì lại khác, mô hình thiết kếcủa nó cho phép mã của mỗi lớp được gói trong một tệp CLASS riêng, được kiểmsoát trong không gian tên bởi hệ thống chạy Java, và được nạp một cách tường minhmỗi khi chương trình cần tới các hành vi của chúng Có thể xem môi trường chạy Javalúc này là một cái giỏ táo, mỗi quả táo là một đối tượng, vết kích hoạt của một chươngtrình Java rất giống như lối của các con sâu, đục xuyên từ quả này sang quả khác ứng với một con sâu, chương trình có một luồng kích hoạt, nhiều con sâu ứng với mộtchương trình Java đa luồng (multithread)
Môi trường kích hoạt Java có xu hướng phân tán, các đối tượng kích hoạt có thểkhông cùng nằm trên một máy duy nhất, theo đó nó có thể nằm rảI rác đâu đó trênmạng, chúng 'liên kết' với nhau để hình thành một chương trình thông qua mạng Thếnhưng, khi các ưu thế trên không có trong định hướng của bạn về một công cụ lậptrình, bạn đừng nên sử dụng nó Thứ nhất, Java chạy thông dịch, tốc độ chậm dù đãđược cải thiện nhờ cơ chế dịch JIT (một cơ chế nhận biết để ánh xạ một cách thôngminh khối mã đầu vào cần thông dịch và khối mã đầu ra cần kích hoạt nhằm tiết kiệmthời gian dịch), và dù có mong đợi thế nào thì Java vẫn sẽ chạy thông dịch Thứ hai,bản thân ngôn ngữ này đang trong thời gian hoàn thiện; hoàn thiện về hệ thống từkhoá, hoàn thiện về cách tổ chức máy ảo, hoàn thiện về thư viện
Có rất nhiều loại ngôn ngữ lập trình :Java,C#,VB.Net,PHP,ASP
Java thì lập trình cho các thiết bị di động nhiều hơn
Lập trình web thì có thể dùng Java hoặc PHP
Bạn có thể thiết kế web bằng ASP.NET, viết bằng ngôn ngữ C#, hoặc VB.NET
Ngoài ra còn có công nghệ NET của Microsoft, hỗ trợ rất nhiều ngôn ngữ
Về lập trình phần mềm thì có rất nhiều ngôn ngữ thông dụng tùy theo loại phần mềm
Trang 19- Phần mềm mạng : Java, Visual C++
- Lập trình hệ thống : C/C++
- Trí tuệ nhân tạo : Prolog
Ngoài ra còn nhiều ngôn ngữ khác nữa phục vụ cho nhiều mục đích khác nhau
7 Chuẩn hoá ngôn ngữ lập trình
Là việc chọn lọc một ngôn ngữ theo một chuẩn ngôn ngữ nhất định nào đó phùhợp để có thể phát triển và ứng dụng rộng rãi trong các công việc
Khi việc chuẩn hoá ngôn ngữ hoàn thành thì nó sẽ trở thành một ngôn ngữ tiêuchuẩn trên toàn thế giới với các mức khác nhau của tiêu chuẩn
8 Các vấn đề nảy sinh từ sử dụng ngôn ngữ lập trình
Mỗi ngôn ngữ, do hạn chế của môi trường và bản thân ngôn ngữ cũng như domục tiêu sử dụng, có thể có một số luật cấm mà người lập trình không thể vi phạm.Những luật cấm này có thể có những cách xử lý khác nhau như là:
Nhiều ngôn ngữ cho phép dùng các câu lệnh đặc biệt để lập trình viên có toànquyền xử lý lỗi và thường được gọi là ngoại lệ (hay exception) Những ngoại lệ nàynếu không xử lý đúng mức sẽ có thể gây ra những sai sót trong thời gian thi hành hayngay cả trong thời gian dịch Dĩ nhiên, người viết mã có thể tùy theo tình huống màviết các câu lệnh rẽ nhánh tránh không để cho mã vi phạm các lỗi Hay là dùng các câulệnh xử lý các ngoại lệ này
Một số ngôn ngữ không cung cấp khả năng xử lý ngoại lệ thì người viết mãbuộc phải tự mình phán đoán hết các tình huống có thể vi phạm lỗi và dùng câu lệnhđiều kiện để loại trừ
Các loại lỗi về ngôn ngữ khi lập trình thường xảy ra là :
Lỗi cú pháp
Vi phạm khi đặt hay gọi tên biến và hàm: Lỗi loại này thường rất dễ tìm ratrong lúc phát triển mã Thường người ta có thể đọc lại các bảng tham chiếu về ngônngữ để tránh sai cú pháp mẫu (prototype) của hàm hay tránh dùng các ký tự đặc biệt bịcấm không cho dùng trong khi đặt tên Trong không ít trường hợp người lập trình cóthể đã định nghĩa cùng một tên cho nhiều hơn một đối tượng khác nhau và lại có giá trịtoàn cục Trong nhiều trường hợp chúng tạo thành lỗi ý nghĩa
Lỗi chính tả: người viết mã có thể viết hay gọi sai tên hàm, tên biến Trongnhiều ngôn ngữ có kiểu tĩnh thì các lỗi này sẽ rất dễ bị phát hiện Còn đối với ngônngữ có kiểu động hay có kiểu yếu thì nó có thể dẫn đến sai sót nghiêm trọng vì bảnthân phần mềm dịch không hề phát hiện ra
Vượt quá khả năng tính toán: Bản thân máy tính và hệ điều hành cũng có rấtnhiều giới hạn về phần cứng, phần mềm và các đặc diểm chuyên biệt Khi người lậptrình yêu cầu máy làm quá khả năng sẽ gây ra các lỗi mà đôi khi không xác định đượcnhư :
Lỗi thời gian (timing error) thường thấy trong các hệ thống đa luồng hay đanhiệm
Trang 20Lỗi chia cho 0: Bản thân phần cứng máy tính sẽ ở trạng thái bất định khithực hiện phép chia cho 0; trong nhiều trường hợp, mã sau khi dịch mớiphát hiện ra trong lúc thi hành và được đặt tên là lỗi division by 0
Dùng hay gọi tới các địa chỉ hay các thiết bị mà bản thân máy hay hệ điềuhành đang thực thi lại không có hay không thể đạt tới Đây là trường hợprất khó lường Bởi vì thường ngưòi lập trình có thể viết mã trên một máynhưng lại cho thi hành trong các máy khác và các máy này lại khôngthỏa mãn các yêu cầu Để giảm trừ các lỗi loại này thường người lậptrình nên xác định trước các điều kiện mà phần mềm làm ra sẽ hỗ trợ Thí dụ: trong nhiều phần mềm ngày nay ở trong vỏ hộp đều được ghi rõ các yêucầu về vận tốc, bộ nhớ tối thiểu, và quan trọng là hệ điều hành nào mà phần mềm
đó hỗ trợ
Gán sai dữ liệu: Tức là dùng một dữ liệu có kiểu khác với kiểu của biến để gáncho biến đó một cách không chủ ý Đối với các ngôn ngữ tĩnh hay có kiểu mạnh thì lỗinày dể tìm thấy hơn Còn những ngôn ngữ động hay ngôn ngữ có kiểu yếu thì lỗi tạo
ra sẽ có thể khó phát hiện và thường xảy ra lúc thi hành
Các lỗi biên: Lỗi biên thường xảy ra khi người viết mã không chú ý đến các giátrị ở biên của các biến, các hàm Những lỗi để thấy có thể là:
Gán giá trị của một số (hay một chuỗi) lên một biến mà nó vượt ngoài sự chophép của định nghĩa
Thí dụ: Gán một giá trị lớn hơn 255 cho một biến có kiểu là short trong ngônngữ C
Tạo nên các lỗi khi biến chạy trong vòng lặp đạt giá trị ở biên.Thí dụ: đoạn mã C/C++ sau đây sẽ gây ra lỗi biên Chia cho 0
Sai sót trong thuật toán: Trước khi viết một chương trình, để giảm thiểu sai sót
về mặt lập luận thì người ta có nhiều biện pháp để làm giảm lỗi trong đó có cácphương pháp vẽ lưu đồ, vẽ sơ đồ khối, hay viết mã giả Những biện pháp này nhằm tạonên các thuật toán để giải quyết vấn đề Tuy nhiên, một thuật toán không chặt chẽ, xử
lý không rốt ráo mọi trường hợp có thể xảy ra, không dự đoán được sự thay đổi tronglúc thi hành thì có thể tạo nên các lỗi và các lỗi này thường khó thấy bởi vì nó chỉ xảy
ra ở những chỗ, những thời điểm mà người lập trình không ngờ trước Một trongnhững phương pháp đơn giản làm giảm thiểu lỗi thuật toán là phải chú ý xử lý mọi
Trang 21tình huống khi dùng câu lệnh điều kiện (hay chẻ nhánh) mặc dù có thể có các trườnghợp tưởng như hiển nhiên
Lỗi về lập luận: Đây có thể xem là trường hợp đặc biệt của sai sót trong thuậttoán Trong các biểu thức tính giá trị, đôi khi không quen dùng đại số Bool (nhất là khidùng luật De Morgan để phủ định một biểu thức phức tạp) nên người lập trình có thểtính toán sai, hay định nghĩa sai các phép toán Do đó, giá trị trả về của các biểu thứclogic hay biểu thức nhị phân sẽ bị sai trong một vài trường hợp hay toàn bộ biểu thức.Trong những tình huống như vậy phần mềm dịch sẽ không thể nào phát hiện ra chođến khi chương trình được thi hành và lọt vào tình huống tính sai của người lập trình
Trang 22BÀI 2:CÁC LOẠI DỮ LIỆU CẤU TRÚC
Mã bài: MĐ39-02
Giới thiệu :
Trong khi lập trình tạo ra sản phẩm, người lập trình cần phải hiểu được các kiếnthức liên quan đến các kiểu dữ liệu có cấu trúc đơn giản của công cụ (ngôn ngữ lậptrình) đang sử dụng để phát triển chương trình Mặt khác, tất cả các kiễu dữ liệu cócấu trúc phức tạp đều được hình thành bởi các thành phần chứa các cấu trúc cơ bản
Để đi sâu hơn về các vấn đề được đề cập đến trong bài học này cũng nhưng trongnhững bài học tiếp theo, chúng ta cần phải hiểu ngôn ngữ lập trình C/C++ đồng thờicần phải nghiên cứu lại các bài học đã học trong chương trình Lập trình căn bản
Mục tiêu thực hiện:
- Hiểu và nắm được các kiểu dữ liệu cơ bản: kiểu số nguyên, số thực, ký tự,chuỗi, mảng
- Nắm được cách thức tổ chức bộ nhớ để lưu trữ các kiểu dữ liệu cơ bản
- Áp dụng giải một số bài toán
Nội dung chính:
1 Các kiểu dữ liệu cơ sở
Các kiểu dữ liệu cơ sở là các kiểu dữ liệu do ngôn ngữ lập trình dựng sẵn, ở đây chúng
ta xét ngôn ngữ lập trình C++ với công cụ lập trình Borland C++ 3.0
unsign long 04 byte 0 đến 232-1
Các phép toán được trang bị để hỗ trợ cho số nguyên: Phép cộng, trừ: Cộng, trừ hai sốnguyên cho kết quả một số nguyên
Phép chia: Chia hai số nguyên cho kết quả một số nguyên là phần nguyên củaphép chia
Phép lấy dư (%): Phép toán này lấy phần dư của phép chia hai số nguyên
double
10 byte 3.4E-4932… 1.1E4932
Trang 23Số thực được hỗ trợ các phép toán: cộng, trừ, nhân, chia nhưng không tồn tại phéptoán lấy dư (%).
Kiểu ký tự
Kiểu ký tự được hỗ trợ từ khoá char dùng để lưu 256 ký tự trong bảng mãASCII mở rộng Một biến dùng kiểu ký tự để lưu trữ thực chất chỉ lưu trữ được một sốnguyên theo mã số trong bảng mã ASCII, do đó các phép toán của số nguyên đều dùngđược với cùng một quy cách với ký tự
Để gán giá trị cho một biến ký tự người dùng có thể gán giá trị số nguyên (mãASCII) của ký tự đó hoặc gán tên ký tự được đóng bởi cặp dấu nháy đơn (Ví dụ:a=’B’)
Trong quá trình lập trình, chúng ta cần phải chú ý đến các tình huống sau:
- Người lập trình có thể kết hợp các từ khoá: unsigned, long để chỉ định kiểu dữliệu có dấu hoặc để tăng giá trị có thể lưu trữ được cho một biến Ví dụ: Biến a có kiểulong int hoặc long có thể lưu trữ được giá trị số nguyên có dấu giá trị khoảng 2 tỷ; biến
b có kiểu unsigned int có thể lưu trữ được giá trị số nguyên có độ lớn từ 0 65535; biến
c có kiểu unsigned long int có thể lưu trữ được số nguyên không dấu giá trị khoảng4,2 tỷ
Kiểu logic
Borland C++ 3.0 trở lên có cung cấp một kiểu dữ liệu logic mang tên kiểu bool.Kiểu dữ liệu này chứa một trong hai giá trị TRUE (đúng), FALSE (sai) Tuy nhiên,trong C/C++, khi sử dụng giá trị bằng 0 được hiểu là FALSE, sử dụng giá trị khác 0được hiểu là FALSE
- Từ khoá long không dùng được với kiểu char
- Ngoài các các phép toán chuẩn, người sử dụng phải còn có thể sử dụng cáchàm dựng sẵn được cung cấp bởi các thư viện trong C/C++ để xử lý đối với từng kiểu
dữ liệu được yêu cầu của từng hàm
- Kiểu trả về của một biểu thức số có kiểu dữ liệu là kiểu dữ liệu cao nhất trongcác phần tử trong biểu thức
Ví dụ: Biểu thức 1/n với n là số nguyên sẽ trả về một giá trị nguyên Chẳng hạn,1/5 sẽ trả về giá trị 0
- Trong trường hợp muốn biểu thức cho ra một kết quả theo kiểu dữ liệu nào
đó, chúng ta phải thực hiện phép toán ép kiểu
Ví dụ 1: Viết chương trình thực hiện nhập vào một số nguyên dương n, sau đó in kết
quả của biểu thức 1 1 1 1
Trang 24printf("Giai thua cua %d la %ld\n", n, giaithua(n));
printf("\nTiep tuc khong? (c/k): ");
Ví dụ 3: Tính n! sử dụng biến lưu trữ là số thực long double.
Trang 25cout<<"Giai thua cua "<<n<<" la " << giaithua(n);
printf("\nTiep tuc khong? (c/k): ");
Mảng một chiều được khai báo như sau:
<tên kiểu dữ liệu> tênbiến[<kích thước>]
Ví dụ 4: Để khai báo một biến a là một mảng nguyên một chiều có 100 phần tử, chúng
ta phải khai báo như sau:
int a[100];
Để truy xuất đến các phần tử,chúng ta phải chỉ định tên và chỉ số phần tử cần truyxuất Chẳng hạn:
a[0] - Truy xuất đến phần tử đầu tiên
a[11] – Truy xuất đến phần tử thứ 12 (có chỉ số 11)
a[99] – Truy xuất đến phần tử thứ 100 (có chỉ số 99), là phần tử cuối cùng ở mảngtrên
Chúng ta cũng có thể vừa khai báo vừa gán giá trị cho một mảng như sau:
Trang 26cout<<"Tong cac phan tu khong chia het cho 2:"<<tongle<<endl;
cout<<"Tong cac phan tu chia chet cho 2:"<<tongchan;
getch();
}
Ví dụ 5: Nhập vào hai ma trận A m n× ,B m n× với m,n được nhập từ bàn phím Sau đó in ra
ma trận C là ma trận có được khi cộng ma trận A cho B
Trang 27Mảng được xử lý rất uyển chuyển nhờ phép toán truy cập trực tiếp dữ liệuthông qua chỉ số phần tử, do đó, mảng thường được dùng để lưu trữ các dữ liệu trongnhững chương trình mà khả năng lưu trữ dữ liệu không lớn Đồng thời, mảng vẫn làcấu trúc dữ liệu hay được dùng trong các giải pháp xử lý đệ quy-quay lui, hay xử lýtham lam, Chúng ta tiến hành nghiên cứu việc ứng dụng mảng trong một số phươngpháp.
Ví dụ 6: Bài toán tám quân hậu: Tìm cách đặt các quân hậu lên bàn cờ vua sao cho
không quân nào có thể ăn được quân nào Quy luật khống chế ô cờ của quân hậu đượcthể hiện theo hướng mũi tên sau:
Hình 2.1 Quy luật khống chế ô cờ của quân Hậu
Thuật toán xây dựng dựa trên việc đặt quân hậu lần lượt trên từng dòng Chúng
ta phải tìm cột thích hợp để đặt quân hậu lên dòng thứ i, tại cột j nào?
- Giá trị cột đã bị quân hậu khống chế rất dễ dàng xác định bằng cách xem cóquân hậu nào nằm trên cột đó hay không?
- Các đường chéo xuôi được xác định dễ dàng vì lấy chỉ số cột trừ chỉ số dòngtrên một đường chéo luôn luôn là một hằng số
- Cac đường chéo ngược được xác định dễ dàng vì lấy chỉ số dòng cộng chỉ sốcột trên một đường chéo luôn luôn là một hằng số
Bảng chỉ số i+j của đường chéo xuôi
Hậu
Trang 28Hinh 2.2 Bảng chỉ số i+j của đường chéo xuôi.
Bài toán này chúng ta xử lý bằng cách dùng một mảng để lưu lời giải (mảngloigiai) Hai mảng dùng để lưu đường chéo của bàn cờ (cheoxuoitrong,cheonguoctrong), một mảng lưu trữ các cột trống
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#include <iostream.h>
#define KICHTHUOC 8 // Kich thuoc cua ban co
#define SODUONGCHEO (2*KICHTHUOC-1) // So duong cheo cua ban co
#define SOGIA (KICHTHUOC-1) // so gia
Trang 29int cottrong[KICHTHUOC];
// mang cac cot co the dat hoang hau
int cheoxuoitrong[SODUONGCHEO]; // mang cac duong cheo xuoi co the dat hhauint cheonguoctrong[SODUONGCHEO]; // mang cac duong cheo nguoc co the dathhau
Trang 30else // Buoc de qui, goi dat hoang hau i+1
Ví dụ 7: Bài toán mã đi tuần: Đặt 1 quân mã vào bàn cờ vua, hãy tìm đường đi để
quân mã đi hết bàn cờ mà không đi lại bất cứ ô nào
#include <stdio.h>
#include <stdlib.h>
#include <conio.h>
#define KICHTHUOC 5 // Kich thuoc cua ban co
void nuocdi(int, int, int);
Trang 31// Ham NuocDi giup di nuoc thu n xuat phat tu o(x, y)
void nuocdi(int n, int x, int y)
if(x+a[i] >= 0 && x+a[i] < KICHTHUOC
&& y+b[i] >= 0 && y+b[i] < KICHTHUOC
else // Buoc de qui, goi di nuoc n+1
nuocdi(n+1, x+a[i], y+b[i]);
Trang 32Ví dụ, mảng sau (hay là xâu kí tự):
char alpha [20];
có thể lưu một xâu kí tự với độ dài cực đại là 20 kí tự Bạn có thể tưởng tượng tương
tự như sau:
Kích thước cực đại này không cần phải luôn luôn dùng đến
Chẳng hạn, alpha có thể lưu xâu "Hello" hay "Merry christmas" Vì các mảng kí
tự có thể lưu các xâu kí tự ngắn hơn độ dài của nó, trong C++ đã có một quy ước đểkết thúc một nội dung của một xâu kí tự bằng một kí tự null, có thể được viết là '\0'
Chúng ta có thể biểu diễn alpha (một mảng có 20 phần tử kiểu char) khi lưu trữxâu kí tự "Hello" và "Happy New Year" theo cách sau:
Hình 2.3 Biểu diễn alpha xâu kí tự HELLO và HAPPY NEW YEAR
Chú ý rằng sau nội dung của xâu, một kí tự null ('\0') được dùng để báo hiệu kếtthúc xâu Những ô màu xám biểu diễn những giá trị không xác định
Khởi tạo các xâu kí tự.
Vì những xâu kí tự là những mảng bình thường nên chúng cũng như các mảngkhác Chẳng hạn, nếu chúng ta muốn khởi tạo một xâu kí tự với những giá trị xác địnhchúng ta có thể làm điều đó tương tự như với các mảng khác:
char mystring[] = { 'H', 'e', 'l', 'l', 'o', '\0' };
Tuy nhiên, chúng ta có thể khởi tạo giá trị cho một xâu kí tự bằng cách khác: sửdụng các hằng xâu kí tự
Trong các biểu thức chúng ta đã sử dụng trong các ví dụ trong các chương trướccác hằng xâu kí tự để xuất hiện vài lần Chúng được biểu diễn trong cặp ngoặc kép ("),
Trang 33Không giống như dấu nháy đơn (') cho phép biểu diễn hằng kí tự, cặp ngoặckép (") là hằng biểu diễn một chuỗi kí tự liên tiếp, và ở cuối chuỗi một kí tự null ('\0')luôn được tự động thêm vào
Chúng ta có thể khởi tạo xâu mystring theo một trong hai cách sau đây:
char mystring [] = { 'H', 'e', 'l', 'l', 'o', '\0' };
char mystring [] = "Hello";
Trong cả hai trường hợp mảng (hay xâu kí tự) mystring được khai báo với kíchthước 6 kí tự: 5 kí tự biểu diễn Hello cộng với một kí tự null
Trước khi tiếp tục, tôi cần phải nhắc nhở bạn rằng việc gán nhiều hằng như việc sửdụng dấu ngoặc kép (") chỉ hợp lệ khi khởi tạo mảng, tức là lúc khai báo mảng Cácbiểu thức trong chương trình như:
mystring = "Hello";
mystring[] = "Hello";
là không hợp lệ, cả câu lệnh dưới đây cũng vậy:
mystring = { 'H', 'e', 'l', 'l', 'o', '\0' };
Vậy hãy nhớ: Chúng ta chỉ có thể "gán" nhiều hằng cho một mảng vào lúc khởitạo nó Nguyên nhân là một thao tác gán (=) không thể nhận vế trái là cả một mảng màchỉ có thể nhận một trong những phần tử của nó Vào thời điểm khởi tạo mảng là mộttrường hợp đặc biệt, vì nó không thực sự là một lệnh gán mặc dù nó sử dụng dấu bằng(=)
Gán giá trị cho xâu kí tự
Vế trái của một lệnh gán chỉ có thể là một phần tử của mảng chứ không thể là
cả mảng, chúng ta có thể gán một xâu kí tự cho một mảng kiểu char sử dụng mộtphương pháp như sau:
strcpy (string1, string2);
Lệnh này copy nội dung của string2 sang string1 string2 có thể là một mảng,con trỏ hay một hằng xâu kí tự, bởi vậy lệnh sau đây là một cách đúng để gán xâuhằng "Hello" cho mystring:
strcpy (mystring, "Hello");
Trang 34return 0;
}
Để ý rằng chúng ta phải include file <string.h> để có thể sử dụng hàm strcpy Mặc dù chúng ta luôn có thể viết một hàm đơn giản như hàm setstring dưới đây đểthực hiện một thao tác giống như strcpy:
Khi cin được sử dụng với các xâu kí tự nó thường được dùng với phương thứcgetline của nó, phương thức này có thể được gọi như sau:
cin.getline ( char buffer[], int length, char delimiter = ' \n');
trong đó buffer (bộ đệm) là địa chỉ nơi sẽ lưu trữ dữ liệu vào (như là một mảngchẳng hạn), length là độ dài cực đại của bộ đệm (kích thước của mảng) và delimiter là
kí tự được dùng để kết thúc việc nhập, mặc định - nếu chúng ta không dùng tham sốnày - sẽ là kí tự xuống dòng ('\n')
Ví dụ sau đây lặp lại tất cả những gì bạn gõ trên bàn phím Nó rất đơn giảnnhưng là một ví dụ cho thấy bạn có thể sử dụng cin.getline với các xâu kí tự như thếnào:
cout << "What's your name? ";
What's your name? Juan
Which is your favourite team? Inter Milan
I like Inter Milan too
Trang 35cin.getline (mybuffer,100);
cout << "Hello " << mybuffer << ".\n";
cout << "Which is your favourite team? ";
Nếu bạn còn nhớ phần nói về giao tiếp với, bạn sẽ nhớ rằng chúng ta đã sửdụng toán tử >> để nhận dữ liệu trực tiếp từ đầu vào chuẩn Phương thức này có thểđược dùng với các xâu kí tự thay cho cin.getline Ví dụ, trong chươn trình của chúng
ta, khi chúng ta muốn nhận dữ liệu từ người dùng chúng ta có thể viết:
cin >> mybuffer;
lệnh này sẽ làm việc như nó có những hạn chế sau mà cin.getline không có:
Nó chỉ có thể nhận những từ đơn (không nhận được cả câu) vì phương thức này
sử dụng kí tự trống(bao gồm cả dấu cách, dấu tab và dấu xuống dòng) làm dấu hiệukết thúc
Nó không cho phép chỉ định kích thước cho bộ đệm Chương trình của bạn cóthể chạy không ổn định nếu dữ liệu vào lớn hơn kích cỡ của mảng chứa nó
Vì những nguyên nhân trên, khi muốn nhập vào các xâu kí tự bạn nên sử dụngcin.getline thay vì cin >>
Chuyển đổi xâu kí tự sang các kiểu khác.
Vì một xâu kí tự có thể biểu diễn nhiều kiểu dữ liệu khác như dạng số nên việcchuyển đổi nội dung như vậy sang dạng số là rất hữu ích Ví dụ, một xâu có thể manggiá trị "1977"nhưng đó là một chuỗi gồm 5 kí tự (kể cả kí tự null) và không dễ gìchuyển thành một số nguyên Vì vậy thư viện cstdlib (stdlib.h) đã cung cấp 3macro/hàm hữu ích sau:
atoi: chuyển xâu thành kiểu int
atol: chuyển xâu thành kiểu long
atof: chuyển xâu thành kiểu float
Tất cả các hàm này nhận một tham số và trả về giá trị số (int, long hoặc float) Cáchàm này khi kết hợp với phương thức getline của cin là một cách đáng tin cậy hơnphương thức cin>> cổ điển khi yêu cầu người sử dụng nhập vào một số
Trang 36cin.getline (mybuffer,100);
price = atof (mybuffer);
cout << "Enter quantity: ";
cin.getline (mybuffer,100);
quantity = atoi (mybuffer);
cout << "Total price: " << price*quantity;
return 0;
}
Các hàm để thao tác trên chuỗi
Thư viện cstring (string.h) không chỉ có hàm strcpy mà còn có nhiều hàm khác
để thao tác trên chuỗi Dưới đây là giới thiệu lướt qua của các hàm thông dụng nhất: strcat: char* strcat (char* dest, const char* src);
Gắn thêm chuỗi src vào phía cuối của dest Trả về dest
strcmp: int strcmp (const char* string1, const char* string2);
So sánh hai xâu string1 và string2 Trả về 0 nếu hai xâu là bằng nhau
strcpy: char* strcpy (char* dest, const char* src);
Copy nội dung của src cho dest Trả về dest
strlen: size_t strlen (const char* string);
Trả về độ dài của string
Chú ý: char* hoàn toàn tương đương với char[]
Ví dụ 12: Chương trình sau sẽ hiển thị một dòng chữ chạy trên màn hình.
Trang 37char *thaythe(unsigned char kytu,size_t lan)
Trang 38cprintf("\n\n\r + Chuoi nguon la :");
Trang 39char mot[100]="Que huong la chum khe ngot";
char hai[100]=" Cho con treo hai moi ngay";
char ba[100]="Que huong la duong di hoc";
char bon[100]=" Con ve rop buom vang bay";
clrscr();
printf("\nCau \" %s\" Co chieu dai :%d ky tu ",mot,strlen(mot));
printf("\nCau \" %s\" Co chieu dai :%d ky tu ",hai,strlen(hai));
printf("\nCau \" %s\" Co chieu dai :%d ky tu ",ba,strlen(ba));
printf("\nCau \" %s\" Co chieu dai :%d ky tu ",bon,strlen(bon));
strcat(mot,hai);
strcat(ba,bon);
printf("\n");
printf("\n PHEP CONG CHUOI KY TU \n");
printf("\n + Dem cau 1 + cau 2");
printf("\nHai cau %s",mot);
printf("\n - Co chieu dai: %d ky tu :",strlen(mot));
printf("\n");
printf("\n + Dem cau 3 + cau 4");
printf("\nHai cau %s",ba);
printf("\n - Co chieu dai : %d ky tu",strlen(ba));
Khai báo tổng quát của kiểu cấu trúc (struct) như sau:
struct <tên kiểu cấu trúc>
{
Trang 40Ví dụ 17: Để mô tả các thông tin về một con người, chúng ta có thể khai báo một kiểu
dữ liệu và khai báo một cấu trúc như sau:
Khi khai báo biến có kiểu dữ liệu cấu trúc, chúng ta truy xuất đến các thành phần conbên trong bằng dấu chấm (.)
Ví dụ 18: Nhập danh sách các học sinh có kiểu dữ liệu nguoi như trên In ra màn hình
thông tin của các học sinh có năm sinh bé hơn 1985
cout<<"Nhap vao so hoc sinh:";cin>>n;
cout<<"Nhap thong tin cho tung hoc sinh:"<<endl;
for (i=0;i<=n-1;i++)
{