Bài giảng Cơ sở lập trình (Phần 1) - Nguyễn Văn Huân

pdf 64 trang ngocly 1220
Bạn đang xem 20 trang mẫu của tài liệu "Bài giảng Cơ sở lập trình (Phần 1) - Nguyễn Văn Huân", để tải tài liệu gốc về máy bạn click vào nút DOWNLOAD ở trên

Tài liệu đính kèm:

  • pdfbai_giang_co_so_lap_trinh_phan_1_nguyen_van_huan.pdf

Nội dung text: Bài giảng Cơ sở lập trình (Phần 1) - Nguyễn Văn Huân

  1. TRƯỜNG ĐẠI HỌC CÔNG NGHỆ THÔNG TIN VÀ TRUYỀN THÔNG KHOA HỆ THỐNG THÔNG TIN KINH TẾ NGUYỄN VĂN HUÂN VŨ XUÂN NAM NGUYỄN VĂN GIÁP ĐỖ VĂN ĐẠI BÀI GIẢNG CƠ SỞ LẬP TRÌNH NGÀNH HỆ THỐNG THÔNG TIN QUẢN LÝ THÁI NGUYÊN, NĂM 2012
  2. MỤC LỤC Chương 1: GIỚI THIỆU CƠ SỞ LẬP TRÌNH TRONG KINH TẾ 5 1.1. Các khái niệm cơ bản 5 1.1.1. Ngôn ngữ máy 5 1.1.2. Ngôn ngữ lập trình 5 1.1.3. Chương trình 6 1.2. Sơ lược về cơ sở lập trình trong kinh tế 8 1.2.1. Khái niệm 8 1.2.2. Tìm hiểu một số bài toán kinh tế điển hình 9 1.2.3. Bài toán phục vụ đám đông 11 1.2.4. Bài toán dự trữ 12 Chương 2: CƠ SỞ LẬP TRÌNH NGÔN NGỮ C 15 2.1. Giới thiệu về ngôn ngữ C 15 2.1.1. Lịch sử hình thành và phát triển ngôn ngữ C 15 2.1.2. Các tính chất đặc trưng của ngôn ngữ C 16 2.2. Những khái niệm và nguyên lý cơ bản của lập trình 20 2.2.1. Hệ thống ký hiệu và từ khoá 20 2.2.2. Khái niệm biến, hằng, biểu thức, câu lệnh 22 2.2.3. Các kiểu dữ liệu 27 2.2.4 Các phép toán 34 2.3. Các cấu trúc điều khiển 37 2.3.1. Lệnh vào/ra 37 2.3.2. Lệnh lựa chọn if 41 2.3.3. Lệnh switch 44 2.3.4. Vòng lặp xác định for (biết trước số lần lặp) 45 2.3.5. Vòng lặp không xác định do while 49 2.3.6. Vòng lặp không xác định while 51 2.3.7. Các lệnh rẽ nhánh vô điều kiện 53 2.4. Cấu trúc mảng 56 2.4.1. Khái niệm 56 2.4.2. Truy nhập đến các phần tử của mảng 57 2.4.3. Xâu kí tự và mảng 59 2.5. Con trỏ 64 2.5.1. Khái niệm con trỏ 64 2.5.2. Khai báo con trỏ 64 2.5.3. Các phép toán trên con trỏ 67 2.5.4. Con trỏ và xâu ký tự 68 2.6. Liên hệ giữa con trỏ và mảng 70 2.6.1. Con trỏ và mảng một chiều 70 2.6.2. Con trỏ và mảng hai chiều 71 2.6.3. Con trỏ và mảng nhiều chiều 72 2.6.4. Sử dụng biến trung gian 73 2.6.5. Mảng các con trỏ 74 2.6.5. Cấp phát động con trỏ 76 2.7. Kiểu cấu trúc 83 2.7.1. Khái niệm và định nghĩa cấu trúc 83 2.7.2. Khai báo cấu trúc 84 2.7.3. Truy cập các phần tử của cấu trúc 86 2
  3. 2.7.4. Mảng các cấu trúc 87 2.7.5. Con trỏ cấu trúc 90 2.8. Hàm và chương trình con 92 2.8.1. Giới thiệu 92 2.8.2. Các module chương trình trong C 93 2.8.3. Thư viện các hàm chuẩn 93 2.8.4. Các hàm 95 2.8.5. Các cơ chế truyền tham số 99 2.8.6. Cấp lưu trữ và phạm vi hoạt động của các đối tượng 100 2.8.7. Con trỏ hàm 101 2.8.8. Hàm đệ qui 103 2.9. Các thao tác trên file văn bản 105 2.9.1. Mở file văn bản mới để cất dữ liệu 106 2.9.2. Đọc một file văn bản đã có 106 2.9.3. Các thao tác vào/ra file mức thấp 109 2.9.4. Tạo file nhị phân để ghi 110 2.9.5. Đọc một file dữ liệu nhị phân 112 2.9.6. Ghi file dữ liệu có cấu trúc (struct) 113 2.9.7. Đọc file dữ liệu cấu trúc 115 2.9.8. Truy nhập trực tiếp file dữ liệu nhị phân 116 2.9.9. So sánh và chọn phương án sử dụng 118 Chương 3: LẬP TRÌNH TRONG KINH TẾ 120 3.1. Bài toán lãi suất 120 3.1.1. Phát biểu bài toán 120 3.1.2. Xây dựng chương trình 120 3.2. Bài toán dự trữ 123 3.2.1. Mô hình quản lý dự trữ Wilson (tiêu thụ đều, bổ sung tức thời) 123 3.2.2. Mô hình dự trữ tiêu thụ đều, bổ sung dần 125 3.3. Bài toán quy hoạch tuyến tính 126 3.4. Bài toán phục vụ công cộng 128 3
  4. Lời nói đầu Cơ sở lập trình là môn học quan trọng đối với sinh viên ngành Hệ thống thông tin quản lý. Nhằm giúp các em sinh viên lam quen dần với lập trình và định hướng vào các bài toán kinh tế, môn học này trang bị cho sinh viên những kiến thức và kỹ năng lập trình và sử dụng nó như một công cụ để giải quyết những bài toán kinh tế phổ biến hiện nay. Mặc dù đã ra đời và phát triển qua nhiều thế hệ, song ngôn ngữ lập trình C là ngôn ngữ rất phù hợp cho việc thiết kế và phát triển các chương trình tính từ đơn giản đến phức tạp, từ những bài toán đơn thuần đến những tính toán khoa học phức tạp. Đặc trưng cơ bản của C là tốc độ thực hiện chương trình nhanh, linh hoạt và dễ dàng cài đặt cũng như sử dụng. Với thời lượng chương trình cho phép không nhiều nên bài giảng này chỉ tập trung vào những vấn đề rất cơ bản của cơ cở lập trình trong kinh tế với 3 chương : Chương 1 : Nghiên cứu tổng quan về cơ sở lập trình và giới thiệu sơ lược một số dạng toán kinh tế cơ bản. Chương 2 : Nghiên cứu về ngôn ngữ lập trình C từ cơ bản đến chuyên sâu. Chương 3 : Tìm hiểu những bài toán kinh tế phổ biến và xây dựng chương trình cho những bài toán dựa trên việc sử dụng ngôn ngữ lập trình C. Đây là bài giảng phục vụ cho sinh viên ngành Hệ thống thông tin quản lý với mục tiêu là hướng dẫn sinh viên nắm vững một ngôn ngữ lập trình cơ sở và cách thức vận dụng nó để lập trình giải các bài toán kinh tế phổ biến nên mang tính chất đặc thu riêng. Tuy nhiên, trong quá trình học tập sinh viên có thể tham khảo giáo trình và bài giảng liên quan khác để xây dựng và giải quyết bài toán của mình một cách tối ưu nhất. Mặc dù các tác giả đã có nhiều cố gắng nhưng chắc chắn không tránh khỏi những sai sót, những phần chưa được hoàn chỉnh trong bài giảng này. Chúng tôi rất mong nhận được các ý kiến đóng góp của bạn đọc để chúng tôi có thể chỉnh sửa, bổ sung giáo trình hoàn chỉnh phục vụ tốt hơn cho công tác giảng dạy, học tập của giáo viên và sinh viên. Thái Nguyên, tháng 02 năm 2012 Bộ môn Thương mại điện tử 4
  5. Chương 1 GIỚI THIỆU CƠ SỞ LẬP TRÌNH TRONG KINH TẾ 1.1. Các khái niệm cơ bản 1.1.1. Ngôn ngữ máy Ngôn ngữ máy (machine language hay machine code) là một loại ngôn ngữ lập trình trong đó, mọi chỉ thị đều được biểu diễn bằng các con số nhị phân 0 và 1. Đây là ngôn ngữ lập trình thế hệ đầu tiên. Tuy khó đọc và khó sử dụng, nhưng ngôn ngữ máy là ngôn ngữ duy nhất mà bộ vi xử lí có thể nhận biết và thực hiện một cách trực tiếp (tức không cần dịch sang bất kì ngôn ngữ nào khác). Lợi điểm chính của các chương trình viết bằng ngôn ngữ máy là có thể được thực thi một cách nhanh chóng (nhờ vi xử lí có thể xử lí các chỉ thị viết bằng ngôn ngữ máy một cách trực tiếp), dù vậy, nó lại không độc lập nền (platform-independent) – tức khi đem qua một máy có loại vi xử lí khác, chương trình có thể không thực thi được, do vi xử lí khác loại có thể có các tập lệnh khác. 1.1.2. Ngôn ngữ lập trình Ngôn ngữ lập trình (programming language) là một tập con của ngôn ngữ máy tính. Đây là một dạng ngôn ngữ được chuẩn hóa (đối lập với ngôn ngữ tự nhiên). Nó được dùng để miêu tả những quá trình, những ngữ cảnh một cách rất chi tiết. Định nghĩa (theo [Loud 94], T.3): Ngôn ngữ lập trình là một hệ thống được ký hiệu hóa để miêu tả những tính toán (qua máy tính) trong một dạng mà cả con người và máy đều có thể đọc và hiểu được. Theo định nghĩa ở trên thì một ngôn ngữ lập trình phải thỏa mãn được hai điều kiện cơ bản là: 1. Nó phải dễ hiểu và dễ sử dụng đối với người lập trình, để con người có thể dùng nó giải quyết các bài toán khác. 2. Nó phải miêu tả một cách đầy đủ và rõ ràng các tiến trình (process), để có thể chạy được trên các máy tính khác. Một tập hợp các chỉ thị được biểu thị nhờ ngôn ngữ lập trình để thực hiện các thao tác máy tính nào đó thông qua một chương trình. Các tên khác của khái niệm này nếu không bị lầm lẫn là chương trình máy tính hay chương trình điện toán. Lưu ý: Khái niệm chương trình (program) viết cho máy vi tính nhằm giải quyết một vấn đế nào đó thường được gọi là phần mềm máy tính. (Thí dụ chương 5
  6. trình MS Word là một cách gọi chung chung, chính xác hơn là phần mềm MS Word thì rõ hơn đó là một chương trình ứng dụng.) Chữ lập trình dùng để chỉ thao tác của con người nhằm kiến tạo nên các chương trình máy tính thông qua các ngôn ngữ lập trình. Người ta còn gọi quá trình lập trình đó là quá trình mã hoá thông tin tự nhiên thành ngôn ngữ máy. Trong các trường hợp xác định thì chữ lập trình còn được viết là "viết mã" (cho chương trình máy tính). Như vậy, theo định nghĩa, mỗi ngôn ngữ lập trình cũng chính là một chương trình, nhưng có thể được dùng để tạo nên các chương trình khác. Một chương trình máy tính được viết bằng một ngôn ngữ lập trình thì những chỉ thị (của riêng ngôn ngữ ấy) góp phần tạo nên chương trình được gọi là mã nguồn của chương trình ấy. 1.1.3. Chương trình 1.1.3.1. Khái niệm Chương trình được xem như là một dãy các phát biểu (các lệnh) có thể thực hiện được theo một thứ tự nhất định để đạt được mục đích. Việc lập thành một chuỗi các lệnh được sắp xếp theo một trình tự xác định mô tả một lớp các quá trình tính toán nào đó được gọi là lập trình. 1.1.3.2. Đặc trưng của chương trình Một chương trình có thể được đánh giá theo ba đặc trưng sau a. Tính cấu trúc của chương trình: cách viết và tổ chức các thành phần của chương trình bao gồm: + Tính đơn thể: thường một chương trình được tổ chức thành nhiều đơn thể (chương trình con – subroutine hay còn gọi là thủ tục hay hàm) và có liên kết với nhau thông qua các lời gọi hàm. + Chương trình là một thể thống nhất: sự liên kết giữa các đơn thể bằng cơ chế truyền tham số của các thủ tục, hàm trong chương trình. + Phong thái lập trình: cách lập trình phải rõ ràng, dễ đọc, ngắn gọn, súc tích và nhất quán. Chương trình nguồn phải có các chú thích và có các hướng dẫn để những người khác có thể sử dụng một cách dễ dàng. b. Tính chức năng của chương trình: chỉ ra cách một chương trình đúng đắn có thể thực hiện được những công việc đặt ra và mức độ dễ sử dụng chương trình đó để giải quyết những bài toán tương tự hay thực hiện được trên nhiều máy khác nhau. Đó là các tính chất: + Tính tin cậy: chương trình đúng đắn và thực hiện cho kết quả chính xác, 6
  7. + Tính phổ dụng: chương trình áp dụng được cho một lớp nhiều bài toán tương tự có liên quan, + Tính tương thích: chương trình có thể dịch và thực hiện trên nhiều hệ máy tính khác nhau. c. Tính hiệu suất của chương trình: Một chương trình tốt có thể tương tác với người sử dụng, với nhiều thiết bị khác, quản lý hiệu quả các tài nguyên của máy tính (bộ nhớ, thời gian xử lý – bộ xử lý) và xử lý được các tình huống ngoại lệ khi chương trình thực hiện. Tính hiệu quả của chương trình được thể hiện qua: + Thân thiện với người sử dụng: chương trình dễ sử dụng và thân thiện với mọi người sử dụng, + Tính hiệu quả: chương trình sử hợp lý các tài nguyên của máy tính như bộ nhớ, bộ xử lý (thời gian thực hiện) và các thiết bị ngoại vi, v.v. + Bố cục trong sáng, rõ ràng: chương trình có thể tự xử lý được các trương hợp đặc biệt như các dữ liệu vào/ra không thích hợp hay những vấn đề tràn ô bộ nhớ, v.v. Thông thường, máy tính chỉ thực hiện được một nhóm các lệnh sơ cấp mà nó “hiểu” được và tuân theo các lệnh đó không biết mệt mỏi và rất tin cậy. 1.1.3.3. Quá trình phát triển chương trình Quá trình viết và thực hiện một chương trình truyền thống được thực hiện theo qui trình sau: + Sử dụng một hệ soạn thảo (editor) như turbo C hay turbo pascal để viết chương trình. + Dịch và gỡ lỗi cú pháp của chương trình, + Liên kết với các thư viện hay các mô đun chương trình khác + Thực hiện và kiểm thử chương trình: tìm lỗi ngữ nghĩa và lỗi thiết kế chương trình. + Xây dựng các bộ dữ liệu mẫu và chạy kiểm nghiệm kết quả. Quá trình này được mô tả như hình sau. 7
  8. bài toán soạn thảo chương trình dịch chương trình mã thực tế nguồn đích .obj có lỗi gỡ lỗi có lỗi? có lỗi hết lỗi có lỗi? chương trình liên kết thực hiện .exe hết lỗi chương trình thư thực hiện bài viện toán có lỗi có lỗi thưc hết lỗi kết quả tính hiện? toán Hình 1-1 Các bước lập trình 1.2. Sơ lược về cơ sở lập trình trong kinh tế 1.2.1. Khái niệm Cơ sở lập trình trong kinh tế là một môn học nghiên cứu và vận dụng những công cụ lập trình cơ sở của công nghệ thông tin vào giải quyết các bài toán kinh tế. Môn học này trang bị cho sinh viên những kiến thức cơ bản về kỹ thuật lập trình và sử dụng ngôn ngữ lập trình đó để giải các bài toán kinh tế như: Bài toán trong kinh tế, Bài toán tối ưu, bài toán phục vụ đám đông, Bài toán dự trữ, Từ khi máy tính điện tử ra đời đến nay, việc tính toán của con người đã thu được những kết quả đáng kinh ngạc. Những thành tựu mà máy tính điện tử nói riêng và ngành công nghệ thông tin và truyền thông nói chung đem lại đã làm thay đổi diện mạo của toàn bộ đời sống kinh tế - xã hội và chính trị của tất cả các nước, các khu vực trên toàn thế giới. Nhất là sự ảnh hưởng của nó đối với các hoạt động kinh tế. Nhiều bài toán kinh tế thuộc các lĩnh vực tính toán phức tạp như: Toán Kinh tế, mô hình tối ưu, lý thuyết hệ thống và điều khiển học ứng dụng trong kinh tế, lý thuyết phục vụ đám đông trước khi mày tính ra đời khó giải thậm chí là chưa thể giải được thì nay với các các công cụ lập trình cơ sở như C/C++, Pascal, đã xây 8
  9. dựng và giải những bài toán này một cách nhanh chóng, chính xác góp phần to lớn vào sự phát triển và cuộc sống kinh tế của con người. Các bước nghiên cứu và ứng dụng lập trình cơ sở đối với các bài toán kinh tế bao gồm: a- Xác định vấn đề cần giải quyết, thu thập dữ liệu. b- Áp dụng các mô hình toán học. c- Xây dựng các thuật toán để giải bài toán đã mô hình hoá bằng ngôn ngữ thuận lợi cho việc lập trình cho máy tính. d- Tính toán thử và điều chỉnh mô hình nếu cần. e- Áp dụng giải các bài toán thực tế. 1.2.2. Tìm hiểu một số bài toán kinh tế điển hình 1.2.2.1. Bài toán về lãi suất Trong hoạt động kinh tế doanh nghiệp thì mảng kế toán - tài chính luôn được quan tâm hàng đầu. Giả sử doanh nghiệp ABC trong khoảng thời gian t có một khoản tiền nhàn rỗi là m và đem gửi ngân hàng với lãi suất là i%/năm. Tính xem trong khoảng thời gian t đó doanh nghiệp thu được bao nhiêu lãi? Ngược lại, một doanh nghiệp trong khoảng thời gian t’ có nhu cầu về vốn để đầu tư sản xuất kinh doanh và doanh nghiệp đi vay ngân hàng với số tiền m’ và lãi suất là i%/năm. Tính lãi mà doanh nghiệp phải trả cho ngân hàng? Trên đây là một ví dụ cụ thể về bài toán lãi suất mà mỗi doanh nghiệp khi thực hiện các kế hoạch sản xuất kinh doanh đều phải tính toán được. Tuy nhiên, với mỗi dạng vay hay cho vay thì sẽ có tương ứng những cách tính lãi khác nhau. Các cách tính lãi suất phổ biến hiện nay là: a. Tính lãi đơn Tính lãi đơn là cách tính lãi suất mà lãi thu được không được tính gộp vào gốc cho kỳ tính lãi sau. Thông thường cách tính lãi này có kỳ hạn trả lãi và lãi suất thường cao hơn các hình thức tính lãi khác. b. Tính lãi kép Tính lãi kép là cách tính lãi suất mà lãi suất thu được ở kỳ trước được tính gộp với gốc để tính lãi tiếp cho kỳ tính lãi sau. Tính lãi kép thường có lãi suất thấp hơn lãi đơn. 1.2.2.2. Bài toán về khấu hao tài sản Khấu hao TSCĐ là một yếu tố chi phí trong giá thành sản phẩm của doanh nghiệp nên việc lập kế hoạch khấu hao TSCĐ nằm trong nội dung của công tác lập kế hoạch tài chính của doanh nghiệp và có ý nghĩa vô cùng quan trọng đối với 9
  10. doanh nghiệp. Để hiểu rõ về bài toán khấu hao tài sản, chúng ta đi tìm hiểu một số khái niệm cơ bản và các dạng khấu hao được áp dụng phố biến hiện nay. Nguyên giá tài sản cố định hữu hình: là toàn bộ các chi phí mà doanh nghiệp phải bỏ ra để có tài sản cố định tính đến thời điểm đưa tài sản đó vào trạng thái sẵn sàng sử dụng. Khấu hao tài sản cố định: là việc tính toán và phân bổ một cách có hệ thống nguyên giá của tài sản cố định vào chi phí sản xuất, kinh doanh trong thời gian sử dụng của tài sản cố định. Một số dạng khấu hao: - Phương pháp khấu hao tuyến tính cố định Phương pháp khấu hao này có ưu điểm là việc tính toán đơn giản, tổng mức khấu hao của TSCĐ được phân bổ đều đặn trong các năm sử dụng TSCĐ và không gây ra sự đột biến trong giá thành sản phẩm hàng năm. Nhưng phương pháp này có nhược điểm là trong nhiều trường hợp không thu hồi vốn kịp thời do không tính hết được sự hao mòn vô hình của TSCĐ. Trong thực tế, để tính khấu hao cho toàn bộ TSCĐ của doanh nghiệp, người ta thường xác định tỷ lệ khấu hao tổng hợp bình quân chung. Có nhiều cách xác định tỷ lệ khấu hao tổng hợp bình quân của doanh nghiệp nhưng cách xác định thông dụng nhất là theo phương pháp bình quân gia quyền - Phương pháp khấu hao nhanh Để thu hồi vốn nhanh, người ta có thể áp dụng các phương pháp khấu hao nhanh trong quá trình tính toán. Hai phương pháp khấu hao nhanh thường được sử dụng là phương pháp khấu hao theo số dư giảm dần và phương pháp khấu hao theo tổng số các năm, gọi tắt là phương pháp khấu hao theo tổng số 1.2.2.1. Bài toán quy hoạch tuyến tính Có thể tạm định nghĩa quy hoạch tuyến tính là lĩnh vực toán học nghiên cứu các bài toán tối ưu mà hàm mục tiêu (vấn đề được quan tâm) và các ràng buộc (điều kiện của bài toán) đều là hàm và các phương trình hoặc bất phương trình tuyến tính. Hiện nay, với sự phát triển không ngừng khoa học công nghệ, với lợi ích và mức độ ứng dụng của dạng toán quy hoạch tuyến tính hiện nay là rất rộng. Sự hiện 10
  11. diện của các mô hình quy hoạch tuyến tính ở khắp nơi, bao trùm nhiều ngành khoa học khác. Toán học ứng dụng coi quy hoạch tuyến tính là một ngành quan trọng nhất và ngành càng có nhiều cống hiến cho xã hội. Trong kinh tế quy hoạch tuyến tính lại có vị trí hết sức quan trọng đối với các bài toán về lập kế hoạch sản xuât, các bài toán về cung cầu với hàm mục tiêu là cực đại lợi ích và cực tiểu nguồn lực. Không chỉ dừng ở đó, quy hoạch tuyến tính còn được sử dụng để nghiên cứu một loạt các ngành khoa học khác như: Điện tử viễn thông, Môi trường, Vật lý Đối với mỗi bài toán quy hoạch tuyến bao gồm hai thành phần chính: 1. Hàm mục tiêu: Hàm mục tiêu là vấn đề mà chúng ta cần nghiên cứu. Hàm mục tiêu Max/min. 2. Các ràng buộc: Các ràng buộc là những điều kiện mà phương án chúng ta cần tìm phải thỏa mãn. 3. Phương án tối ưu: là nghiệm của bài toán quy hoạch tuyến tính. Nghiệm này có dạng một vector với những thành phần là các nhân tố có trong mô hình. Một số bài toán về quy hoạch tuyến tinh: - Bài toán lập kế hoạch sản xuất. - Bài toán về vận tải - Bài toán vốn đầu tư 1.2.3. Bài toán phục vụ đám đông 1.2.3.1. Mô tả hệ thống Chúng ta có thể mô tả hệ thống phục vụ đám đông bằng phương pháp "hộp đen" hoặc phương pháp “hộp trắng”. Sau đây ta mô tả hệ thống phục vụ đám đông bằng phương pháp “hộp đen” như sau: Dòng vào Hàng chờ Dòng ra (đã được phục vụ) Các kênh phục vụ và nguyên tắc phục vụ Các yêu cầu không thảo mãn Các yêu cầu phục vụ Hình 1.2. Mô hình phục vụ đám đông 11
  12. 1.2.3.2. Các yếu tố của hệ thống phục vụ Một hệ thống phục vụ, dù ở qui mô nào, tính chất hoạt động ra sao, đều được đặc trưng bởi các yếu tố chủ yếu sau: a. Dòng vào. Dòng vào là dòng các yêu cầu đến hệ thống phục vụ, đòi hỏi được thoả mãn một yêu cầu nào đó: Ví dụ: Khách hàng đến một cửa hàng siêu thị để mua hàng, các đơn vị quân đội chờ qua phà để vượt sông, các khí tài chờ để được sửa chữa, bảo dưỡng v.v. - Tại các thời điểm khác nhau, các yêu cầu đến hệ thống phục vụ là ngẫu nhiên nên các dòng yêu cầu là những đại lượng ngẫu nhiên, tuân theo luật phân bố xác suất nào đó, do vậy nó có nhiều loại dòng vào. Trong khuôn khổ môn học này chúng ta chỉ xét hai loại dòng yêu cầu quan trọng, thường gặp nhất ở mọi hệ thống phục vụ, đó là: Dòng vào tiền định và Dòng vào Poát xông. b. Hàng chờ Hàng chờ là tập hợp các yêu cầu sắp xếp theo nguyên tắc nào đó để chờ được vào phục vụ trong hệ thống. c. Kênh phục vụ Kênh phục vụ là toàn bộ thiết bị kỹ thuật, con người hoặc một tổ hợp gồm các thiết bị kỹ Thuật cùng công nghệ tương ứng mà hệ thống sử dụng để phục vụ yêu cầu khách hàng. Đặc trưng quan trọng nhất là của kênh phục vụ là thời gian phục vụ. Đó là thời gian mỗi Kênh phải tiêu phí để phục vụ một yêu cầu. Thời gian phục vụ là một đại lượng ngẫu nhiên tuân theo một quy luật xác suất nào đó. Các dòng yêu cầu được phục vụ trong kênh phục vụ gọi là "dòng phục vụ". Khi dòng yêu cầu được phục vụ trên các kênh phục vụ (dòng phục vụ) là tối giản thì khoảng thời gian giữa các lần xuất hiện liên tiếp các yêu cầu là một đại lượng ngẫu nhiên tuân theo luật chỉ số, nghĩa là đại lượng ngẫu nhiên có phân bố xác suất dạng: 1.2.4. Bài toán dự trữ 1.2.4.1. Các định nghĩa 1. Hàng hoá: Hàng hoá là đối tượng vật chất được sử dụng, dự trữ cho hoạt động của hệ thống kinh tế - xã hội nào đó. 12
  13. 2. Nhu cầu: Nhu cầu là khối lượng hàng hoá cần thiết sẽ được hệ thống tiêu thụ trong một khoảng thời gian T (giả thiết T=1 đơn vị). Nhu cầu thông thường là một biến ngẫu nhiên nên nó tuân theo qui luật phân phối xác suất nào đó. 3. Cung cấp: Cung cấp là khả năng đáp ứng hàng hoá cho quá trình dự trữ và tiêu thụ của hệ thống. Trong các trường hợp cụ thể, cách thức cung cấp có thể khác nhau: Cung cấp theo từng đợt tập trung cường độ lớn, cung cấp đều đặn trong các khoảng thời gian v.v 4. Thời gian đặt hàng: Thời gian đặt hàng là khoảng thời gian từ khi bắt đầu đặt hàng đến khi hàng bắt đầu được dự trữ và tiêu thụ. Khoảng thời gian này cũng là một đại lượng ngẫu nhiên, do vậy sẽ tuân theo luật phân phối xác suất nào đó. 5. Chu kỳ dự trữ - tiêu thụ: Chu kỳ dự trữ - tiêu thụ là khoảng thời gian dự trữ và tiêu thụ khối lượng hàng của một lần đặt mua. 6. Điểm đặt hàng: Điểm đặt hàng là mốc mà lượng hàng dự trữ còn nhưng cần bắt đầu đặt hàng cho chu kỳ “dự trữ - tiêu thụ” sau đó. 7. Các loại chi phí. a. Chi phí mua hàng: Chi phí mua hàng là chi phí trực tiếp cho một đơn vị hàng về đến kho ( bao gồm: giá hàng, chi phí vận chuyển, bốc xếp lên xuống ) chi phí mua hàng còn gọi là giá hàng. b. Chi phí đặt hàng: Chi phí đặt hàng là chi phí cố định cho một lần đặt hàng, bao gồm chi phí giao dịch, chi phí cho các nghiệp vụ khác. c. Chi phí dự trữ (Chi phí kho) Chi phí dự trữ là chi phí cho việc bảo quản một đơn vị hang hoá trong một đơn vị thời gian. Chi phí dự trữ tỷ lệ với giá hàng qua một hệ số gọi là hệ số chi phí dự trữ (hay còn gọi là hệ số bảo quản). d. Chi phí do không đảm bảo nhu cầu: Chi phí do không đảm bảo nhu cầu là chi phí phải chịu thiệt thòi khi thiếu một đơn vị hàng hoá trong một đơn vị thời ian. e. Chi phí do dư thừa hàng: Chi phí do dư thừa hàng (dư thừa so với nhu cầu thực tế) là chi phí phát sinh khi chúng ta dự trữ quá mức cần thiết. Chẳng hạn, tổn thất do ứ đọng vốn, do hang quá thời gian sử dụng, do hàng giảm chất lượng v.v 1.2.4.2. Các lớp mô hình quản lý dự trữ Có 2 lớp mô hình quản lý dự trữ chủ yếu sau: - Lớp mô hình quản lý dự trữ với các yếu tố phi ngẫu nhiên. - Lớp mô hình quản lý dự trữ với các yếu tố ngẫu nhiên. Trong hầu hết các hoạt động kinh tế - xã hội người ta phải giải quyết bài toán dự trữ, thực chất là bài toán lựa chọn phương án dự trữ các nguồn lực sao cho chi phí ít tốn kém nhất. Trong phần này chúng ta xét một lớp bài toán cụ thể giải quyết 13
  14. các mối quan hệ kinh tế trong quá trình sự trữ. Việc thể hiện bài toán dưới dạng mô hình cho phép mở rộng khả năng ứng dụng trong những tình huống tương tự, hoặc khi có thể quy vấn đề cần giải quyết về dạng bài toán dự trữ. Mô hình điều khiểu dữ trữ như tên gọi ban đầu của mô hình này, xuất phát từ bài toán quản lý một hệ thống kho. Tuy nhiên trong thực tế, mô hình này không chỉ được sử dụng để phân tích, điều khiển dự trự mà còn được dùng như một công cụ mô hình hóa nhiều vấn đề trong các lĩnh vực quản lý sản xuất, kinh doanh dịch vụ. Các đối tượng được mô hình hóa cũng theo đó mà ngày càng phức tạp hơn. Với một số mô hình được giới thiệu sau đây chúng ta sẽ lần lượt nghiên cứu từ các mô hình đơn giản. Với các yếu tố tất định, diễn biến đều đặn đến các mô hình trong đó các yếu tố có tính ngẫu nhiên. Mặt khác, ta sẽ nghiên cứu từ các mô hình thuần túy dự trữ đến các mô hình sản xuất kinh doanh. 14
  15. Chương 2 CƠ SỞ LẬP TRÌNH NGÔN NGỮ C 2.1. Giới thiệu về ngôn ngữ C 2.1.1. Lịch sử hình thành và phát triển ngôn ngữ C Ngôn ngữ C do Brian W. Kemighan và Dennis M. Ritchie phát triển vào đầu những năm 70 tại phòng thí nghiệm Bell (thuộc công ty viễn thông T &T của hoa kỳ) với mục đích ban đầu để phát triển hệ điều hành Unix. Song nhờ tính ưu việt và mền dẻo nên nó đã được giới tin học nhanh chóng chấp nhận như là một ngôn ngữ chính thống nhà nghề. Đến năm 1978, bản in đầu tiên về ngôn ngữ C đã được in thành sách “The Programming Language” do Kernighan và Richie viết. C cũng mau chóng được Viện tiêu chuẩn hoá của Mỹ (ANSI: American National Standard Institute) làm thành tiêu chuẩn với tên gọi “ANSI C” vào năm 1983. Tổ chức tiêu chuẩn quốc tế ISO (International Standard Ogranization) cũng xây dựng chuẩn cho C. Phần lớn các ý tưởng quan trọng nhất của C xuất phát từ một ngôn ngữ cũ hơn có tên là BCPL do Martin Richards nghiên cứu ảnh hưởng của BCPL lên C gián tiếp thông qua ngôn ngữ BCPL, do Ken Thompson viết năm 1970 cho hệ Unix chạy trên họ máy tính PDP-7. Ngoài việc C được dùng để viết hệ điều hành Unix (hiện nay trên 90% chương trình nguồn của các hệ điều hành Unix (được viết bằng c, chưa đầy 10% bằng hợp ngữ), người ta nhanh chóng nhận ra sức mạnh của C trong việc xử lý các vấn đề hiện đại của tin học: xử lý số, văn bản, cơ sở dữ liệu, lập trình hướng đối tượng. Thực tế C đã tổ hợp được các thành tựu tiên tiến của tin học và đã trở thành một chuẩn mặc nhiên. Liên quan đến sự hình thành và phát triển của ngôn ngữ, có một số sự kiện đáng quan tâm sau: Năm l978, cuốn giáo trình dạy lập trình bằng ngôn ngữ C với tên “The C Programming Language” do chính hai tác giả của ngôn ngữ Brian W. Kemighan và Dennis M. Ritchie biên soạn đã được xuất bản và được phổ biến rộng rãi. Năm 1983 một tiểu ban của Viện tiêu chuẩn quốc gia Mỹ (ANSI) được thành lập nhằm đề xuất ra một chuẩn cho ngôn ngữ. 15
  16. Năm l988 chuẩn ANSI C chính thức được ban hành. Chuẩn này bao gồm các mô tả về ngôn ngữ và quy định các thư viện chuẩn của ngôn ngữ C, nhờ đó tăng tính khả chuyển của chương trình viết bằng C. Trong thế giới PC, có các hệ chương trình dịch C nổi tiếng như là: Turbo c, Borland C của Borland inc. MSC, VC của Microsoft Corp. Lattice C của Lattice Sự phát triển của ngôn ngữ lập trình trong những năm 80 đã đưa đến phong cách lập trình hướng đối tượng mà một trong những ngôn ngữ rất được ưa dùng là C++, bổ sung mới các yếu tố hướng đối tượng vào ngôn ngữ C. 2.1.2. Các tính chất đặc trưng của ngôn ngữ C 2.1.2.1. Các tính chất đặc trưng của ngôn ngữ C C là ngôn ngữ lập trình vạn năng được dùng để viết các hệ điều hành như Unix cũng như các chương trình ứng dụng như qlvb (quản lý văn bản), csdl (cơ sở dữ liệu), v . C là ngôn ngữ có mức độ thích nghi cao. Do các kiểu dữ liệu và cấu trúc điều khiển của C có hầu hết trên các máy tính nên thư viện lúc chạy cần để cài đặt chương trình là khá gọn. Hơn nữa vì ngôn ngữ phản ánh khả năng của máy tính hiện đại nên chương trình C tỏ ra là đủ hữu hiệu, tức là không nhất thiết phải cần tới hợp ngữ. Mặc dù vậy C vẫn độc lập với bất kỳ kiến trúc máy đặc thù nào và với một chút thận trọng vẫn dễ dàng viết các chương trình khả chuyển (portability) tức là những chương trình có thể chạy mà không cần phải thay đổi gì khi có thay đổi về phần cứng. Ưu điểm C là ngôn ngữ mạnh và mềm dẻo C là ngôn ngữ được các nhà tin học chuyên nghiệp dùng phổ biến, nhất là trong sản xuất phần mềm hệ thống (hệ điều hành, chương trình dịch, soạn thảo văn bản, cơ sở dữ liệu , bảng tính ). một trong các lý do này là tính hiệu quả của chương trình được dịch ra. một chương trình C khi dịch ra có thể đạt tới 80% tính năng của chương trình đó viết bằng mã máy. Có khá nhiều thư viện và chương trình tiện ích khác cho C có thể khai thác được C là ngôn ngữ có thể chuyển dịch được hay còn gọi là dẽ thích nghi. Tính thích nghi hay tính di chuyển được hiểu là chương trình viết bằng C cho máy ibm 16
  17. có thể chạy trên máy vax của công ty digital cho dịch lại vẫn chạy được ngay sau khi có một vài chỉnh sửa nhỏ. C là ngôn ngữ có ít từ khoá, là các từ dùng riêng cho ngôn ngữ khi viết chương trình. C là ngôn ngữ có cấu trúc Modul, đó chính là việc sử dụng các chương trình con loại hàm (Function). Các hàm này có thể sử dụng nhiều lần trong chương trình hay trong chương trình khác. Nhược điểm Cú pháp của ngôn ngữ C thuộc loại lạ và khó học. Một số ký hiệu của C có nhiều nghĩa khác nhau. Thí dụ ký hiệu * là toán tử nhân, là toán tử không định hướng, là toán tử thay thế Việc sử dụng các ký hiệu này phụ thuộc vào ngữ cảnh sử dụng. 2.1.2.2. Cấu trúc cơ bản của một chương trình trong C Hãy xem các thành phần của chương trình xinchao.c sau đây chương trình hiện lên dòng “chao cac ban!” trên màn hình: /*xinchao.c*/ #include #include void main(){ printf("chao cac ban SV nganh HTTTKT!\n"); getch(); } Thực hiện chương trình Các bước để thực hiện chương trình này như sau: trước tiên bạn phải tạo ra chương trình nguồn có tên xinchao.c trên một hệ soạn thảo nào đó; bước tiếp theo là dịch chương trình để tạo ra một file chương trình ( xinchao.exe); sau bước thứ hai nếu không có lỗi biên dịch, bạn đã có thể thực hiện được chương trình từ dấu nhắc của hệ điều hành. Định nghĩa hàm Một chương trình C, với bất kỳ kích thước nào cũng đều bao gồm một hay nhiều hàm, các hàm này sẽ xác định các thao tác tính toán thực tế cần phải thực hiện. Các hàm của C cũng tương tự như các hàm và thủ tục của chương trình viết bằng Pascal. Trong chương trình ví dụ trên, main() là một hàm như vậy. Thông 17
  18. thường chúng ta có thể lấy bất kỳ tên nào để đặt cho hàm, nhưng main() là một hàm đặc biệt - chương trình C luôn luôn bắt đầu thực hiện tại điểm đầu của hàm này. Điều này có nghĩa mọi chương trình trong C đều phải có một (và chỉ một) hàm main() ở đâu đó trong chương trình. Hàm main() này thường gọi tới các hàm khác để thực hiện công việc của nó, một số hàm nằm trong chương trình, số khác nằm trong các thư viện của các hàm chuẩn. Khai báo File tiêu đề Khi sử dụng các hàm trong các thư viện chuẩn, chúng ta phải khai báo file tiêu đề (header file) chứa hàm nguyên mẫu tương ứng của hàm đó, câu lệnh được bắt đầu bằng #include theo sau là tên header file. Trong ví dụ trên, chúng ta có sử dụng hàm printf() là hàm chuẩn được khai báo trong file stdio.h và hàm getch() được khai báo trong conio.h do đó trong chương trình có hai dòng sau ở trên đầu # include #include Dòng chú thích Dòng chú thích giải thích mục đích của chương trình. Mọi ký tự nằm giữa /* và */ đều được chương trình dịch bỏ qua; ta được phép dùng chúng để làm cho chương trình dễ hiểu. Lời chú thích có thể xuất hiện ở bất kỳ đâu trong chương trình, chứa được tất cả các ký tự và có thể trải dài trên nhiều dòng khác nhau. Dấu kết thúc câu lệnh Trong chương trình mỗi câu lệnh được kết thúc bằng dấu chấm phẩy (;). Ví dụ: printf (“ xin chao cac ban\n “) ; Mô hình tổng thể của một chương trình trong C 18
  19. lời gọi các thư viện chương trình # include # define Khai báo tên các hàm với các tham số: function Khai báo các biến ngoài: Định nghĩa kiểu dữ liệu : typedeft phần mô tả của các hàm thành phần function{ khai báo các biến, hằng sử dụng các hàm khác } 2.2.3 Các bước cơ bản khi viết một chương trình Bước 1: Bước thảo chương Dùng các hệ soạn thảo văn bản (text editor) để viết chương trình. Có thể dùng bất cứ một hệ soạn thảo văn bản nào để soạn thảo, song mỗi ngôn ngữ đều có một hệ soạn thảo riêng của mình, điều đó rất thuận lợi, nó giúp người lập trình sửa lỗi cập nhật một cách dễ dàng. Sau khi soạn thảo xong thì cất chương trình lên đĩa. Các file chương trình của C hay C++ có dạng *.cpp. Bước 2: Dịch chương trình Gọi chương trình dịch C. Chương trình dịch có nhiệm vụ dịch chương trình viết bằng C của người lập trình sang mã máy với 2 giai đoạn: dich ra file obj và liên kết các file obj lại với nhau qua chương trình liên kết linker. Kết quả dịch được chứa trong các file *.com, *.exe, *.obj. Giai đoạn này cho phép ta phát hiện các lỗi về cú pháp khi viết chương trình. Nếu có lỗi, chương trình dịch sẽ báo lỗi. Ta phải quay về bước 1, dùng Editor để sửa. Bước 3: Cho chạy chương trình và thử 19
  20. Nếu các kết quả nhận được là sai thì ta phải tự tìm lỗi vì đây là lỗi logic, lỗi về thuật toán giải, máy tính không thể phát hiện được các lỗi này như là các lỗi cú pháp của chương trình. Chương trình dịch có 2 kiểu: Biên dịch (compiler) Thông dịch (interpreter) Biên dịch nghĩa là dịch toàn bộ chương trình đã được viết sẵn theo một ngôn ngữ nào đó. Thông dịch sẽ dịch và thực hiện ngay lập tức từng dòng lệnh trong quá trình lập trình. Có thể so sánh chương trình biên dịch như là người dịch sách, còn chương trình thông dịch ví như người phiên dịch hay thông ngôn. C, Pascal là loại ngôn ngữ được dịch theo kiểu biên dịch. Ghi nhớ: Các chú thích bắt đầu bằng /* và kết thúc bởi */. Người lập trình có thể chèn các chú thêm vào bất kì chỗ nào có thể đặt dấu phân cách trong chương trình. Các chú thích đưa chương trình dịch bỏ qua. Việc thêm các chú thích làm cho chương trình dễ đọc hơn Chỉ thị tiền xử lý # include báo cho chương trình dịch kết hợp file tiêu đề chứa các khai báo của các hàm vào ra chuẩn trong chương trình. Chương trình C bao gồm một hoặc nhiều hàm, trong số đó nhất định phải có một và chỉ một hàm main(). Mọi chương trình C bắt đầu được thực hiện tại điểm bắt đầu của hàm main(). 2.2. Những khái niệm và nguyên lý cơ bản của lập trình 2.2.1. Hệ thống ký hiệu và từ khoá 2.2.1.1. Bộ ký tự Mọi ngôn ngữ lập trình đều được xây dựng từ một bộ ký tự nào đó. Các ký tự được nhóm lại theo nhiều cách khác nhau để lập nên các từ. Đến lượt mình, các từ lại được liên kết theo một qui tắc (đó là cú pháp của ngôn ngữ lập trình) nào đó để tạo thành các câu lệnh. Một chương trình bao gồm nhiều câu lệnh diễn đạt một thuật toán nào đó. Ngôn ngữ lập trình C được xây dựng trên bộ ký tự sau: Các chữ cái hoa : a z Các chữ cái thường: a z 20
  21. Các chữ số : 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 Các dấu chấm câu: , . ; : / ? [ ] { } ! @ # $ & * ( ) + - = ‘ Các dấu ngăn cách không nhìn thấy như dấu cách, dấu nhảy cách (tab), dấu xuống dòng (return). Dấu nối dưới Không được dùng các ký hiệu khác cũng như là các chữ cái Tiếng Việt trong khi viết các câu lệnh, tuy nhiên ta vẫn có thể dùng nó trong các lời giải thích, trong các câu thuyết minh, trong các câu hiển thị văn bản lên màn hình hay lên máy in. 2.2.1.2. Các từ khoá Cũng như các ngôn ngữ khác, ngôn ngữ C cũng có các từ khoá riêng của mình, các từ khoá là các từ dành riêng của C và mỗi từ có một tác dụng, ý nghĩa cụ thể, chúng không được định nghĩa lại. Trong C có nhiều từ khoá, dưới đây là một số từ khoá thông dụng: auto break case char continue defaul do double else extern float for goto if int long register return short sizeof static struct switch typedef union unsigned void volatile while _cs _ds _es _ss _ah _al _ax _bh _bl _bx _ch _cl _cx _dh _dl _dx _bp _di _si _sp 2.2.1.3. Tên và cách đặt tên Tên (định danh) được dùng rất nhiều trong chương trình như tên hằng (hằng số, hằng ký tự ), tên biến, tên chương trình, tên hàm, mọi tên trước khi sử dụng đều phải khai báo. 21
  22. Các ký tự dùng để đặt tên bao gồm: các chữ cái hoa A Z, các chữ cái thường a z, chữ số 0 9 và dấu nối dưới tên là một dãy các ký tự liền nhau, độ dài không hạn chế (tuy nhiên tên không nên đặt quá dài), phải được bắt đầu bằng chữ cái hoặc dấu nối dưới, không được chứa các ký tự đặc biệt như dấu cách, dấu chấm câu, Ngôn ngữ C phân biệt giữa chữ hoa và chữ thường. Các tên abc, ABC, Abc, aBc, abC là khác nhau. Theo thói quen người ta thường dùng chữ hoa đặt tên cho các hằng, còn chữ thường được dùng để đặt tên cho các biến, các hàm, các cấu trúc v.v. . . Tên phải phản ánh được bản chất của đối tượng được đặt tên. 2.2.1.4. Cách ghi lời giải thích Mỗi khi viết chương trình, bạn nên viết thêm lời giải thích cho chương trình thêm sáng sủa và dễ hiểu. Lời giải thích không có tác dụng tạo ra mã chương tình, nó chỉ đơn giản là lời thuyết minh cho chương trình thêm dễ hiểu. Phần văn bản nằm giữa hai cặp dấu /* và */ chính là phần thuyết minh. Trong C++ lời giải thích trên một dòng còn được viết sau cặp dấu //. Sự khác nhau giữa cặp dấu /* , */ và //: trong trường hợp thứ nhất các lời giải thích có thể nằm trên nhiều dòng, còn trong trường hợp thứ hai thì lời giải thích chỉ là phần nằm sau dấu // và trên một dòng. 2.2.1.5. Câu lệnh và dấu chấm câu Mỗi câu lệnh trong chương trình được kết thúc bằng dấu chấm phẩy “;”. Dấu “;” được dùng để ngăn cách giữa các câu lệnh và bắt buộc phải viết vào, nếu không máy sẽ báo lỗi khi dịch. 2.2.2. Khái niệm biến, hằng, biểu thức, câu lệnh 2.2.2.1. Biến a. Khai báo Mọi biến cần khai báo trước khi sử dụng. Việc khai báo biến được thực hiện theo mẫu sau : Type tên biến ; Ví dụ : Main() { int a,b,c ; 22
  23. long ad,bd,cd; char beta,alfa; float x,y; double xd,yd; } Biến kiểu int chỉ nhận được các giá trị kiểu int. Các biến khác cũng có ý nghĩa tương tự, chẳng hạn biến kiểu char chỉ chứa được một ký tự. Để lưu trữ một xâu ký tự cần sử dụng một mảng kiểu char. b. Vị trí của các khai báo. Các khai báo cần đặt ngay sau dấu { đầu tiên của thân hàm và cần đứng trước mọi câu lệnh khác. Như vậy, sau một câu lệnh gán chẳng hạn thì không được khai báo nữa. c. Việc khởi đầu cho các biến. Nếu trong khai báo, ngay sau tên biến ta đặt dấu = và một giá trị nào đó thì đây chính là cách vừa khai báo vừa khởi đầu cho một biến sử dụng cho chương trình. Ví dụ: int a,b = 1,c,d=2; float e = -12.3, x = 15.5, y,z=30.0; Ta cũng có thể khởi đầu cho các biến bằng toán tử gán. Vậy để đạt được ý định như ví dụ trên ta có thể dùng các lệnh: int a,b,c,d; float e,x,y,z,t; a=1 ; b=3 ; c=4 ;d=5 ;e=3.2 ;x=-3.6 ; y=45.6 ; z=-123.0 ; t=100.12 ; d. Lấy địa chỉ của biến. Mỗi biến được cấp phát một vùng nhớ gồm một số byte liên tiếp. Số liệu của byte đầu chính là địa chỉ của biến. Địa chỉ biến dùng trong một số hàm như hàm scanf. Để nhận địa chỉ biến ta dùng phép toán : &tên biến 2.2.2.2. Hằng Hằng là các đại lượng mà giá trị của nó không thay đổi trong quá trình tính toán. Dưới đây trình bày các loại hằng được sử dụng trong C : a. Hằng dấu phẩy động (float và double) được viết theo hai cách Cách 1: (dạng thập phân) : Số gồm phần nguyên, dấu chấm thập phân và phần phân. Ví dụ : 123.45 -12345.67 1234.0 23
  24. Chú ý: Phần nguyên hay phần phân có thể vắng mặt nhưng dấu chấm không thể thiếu. Ví dụ: .34 hay 12. Cách 2 (dạng khoa học hay dạng mũ) : Số được tách thành 2 phần là định trị và phần bậc. Phần định trị là một số nguyên hoặc số thực dạng thập phân, phần bậc là một số nguyên. Hai phần này cách nhau bởi ký tự e hoặc E. Ví dụ : 123.46E-4: Biểu diễn giá trị 0.012346 0.12E3: Biểu diễn giá trị 120.0 -12.5e-3: Biểu diễn giá trị -0.125 1E8: Biểu diễn giá trị 100000000.0 b. Hằng int: Là số nguyên có giá trị trong khoảng từ -32768 đến 32767. Ví dụ : -45 1234 Chú ý : phân biệt 123 và 123.0 : Số 123 là hằng nguyên còn 123.0 là hằng thực (dấu phẩy động) c. Hằng long được biết theo hai cách: -4893L hoặc -4893l (thêm L hoặc l vào đuôi). Một số số nguyên vượt ra ngoài miền xác định của int cũng được xem là hằng long. Ví dụ : 453946L và 4563946 là hai hằng long có cùng giá trị. d. Hằng int hệ 8 được viết theo cách: 0c1c2c3 . Ở đây ci là một số nguyên trong khoảng từ 0 đến 7. Hằng nguyên hệ 8 luôn luôn nhận giá trị dương. Ví dụ : 0345 là một hằng nguyên hệ 8. Giá trị của nó trong hệ 10 là 3*8*8 + 4*8 + 5 =229 e. Hằng nguyên hệ 16. Trong hệ này sử dụng 16 ký tự: 0,1,2,3,4, ,15. Để tránh nhầm lẫn giữa chữ số 11 và hai số 1 người ta dùng quy ước sau: Cách viết Ý nghĩa A hoặc a 10 B hoặc b 11 C hoặc c 12 24
  25. D hoặc d 13 E hoặc e 14 F hoặc f 15 Hằng số hệ 16 có dạng : 0xc1c2c3 hoặc 0Xc1c2c3 trong đó ci là một chữ số hệ 16. Ví dụ : 0xa9, 0Xa9, 0XA9 là 4 hằng số hệ 16 như nhau. Giá trị của chúng trong hệ 10 là : 10*16+9=169 ; f. Hằng ký tự là một ký tự riêng biệt được viết trong 2 dấu nháy đơn, ví dụ ‘a’. Giá trị của ‘a’ chính là mã ASCII của chữ a. Như vậy, giá trị của ‘a’ là 97 (xem bảng mã ASCII). Hằng ký tự có thể tham gia vào các phép toán như mọi số nguyên khác. Ví dụ ‘9’-‘0’=57-48=9 Hằng ký tự còn có thể được viết theo cách ‘\1c2c3’ Trong đó, c1c2c3 là một số hệ 8 mà giá trị của nó bằng mã ASCII của ký tự cần biểu diễn. Ví dụ : chữ a có hệ 10 là 97 đổi hệ 8 là 0141. Vậy hằng ký tự ‘a’ có thể viết dưới dụng’\144’. Đối với một vài hằng ký tự đặc biệt ta cần sử dụng cách viết sau (thêm dấu \) : Cách viết Ký tự ‘\’’ ’ ‘\’’’ ’’ ‘\\’ \ ‘\n’ Chuyển dòng ‘\0’ (Null) ‘\t’ Tab ‘\b’ Backspace ‘\r’ CR (về đầu dòng) ‘\f’ LF (sang trang) 25
  26. Chú ý : Cần phân biệt các hằng ký tự ‘0’ và ‘\0’. Hằng ‘0’ ứng với chữ số 0 có mã 48, còn hằng ‘\0’ ứng với ký tự 0 (ký tự null) có mã 0. Hằng ký tự thực sự là một số nguyên, vì vậy có thể dùng các số nguyên hệ 10 để biểu diễn ký tự. Ví dụ : - Lệnh printf(‘‘%c%c’’,65,66) ; sẽ in ra AB - Lệnh prinf(‘‘%c%c%c’’,7,7,7) ; phát ra 3 tiếng chuông. g. Hằng xâu ký tự là một dãy ký tự bất kỳ đặt trong hai dấu nháy kép. Ví dụ : “Ha noi” “Hai Phong” “” /* xâu rỗng*/ Xâu ký tự được lưu trữ trong máy dưới dạng một mảng có các phần tử là các ký tự riêng biệt. Trình biên dịch tự động thêm ký tự xóa \0 vào cuỗi mỗi xâu – Ký tự \0 được xem là dấu hiệu kết thúc của một xâu ký tự. Chú ý: Cần phân biệt ‘a’ và “a”, ‘a’ là hằng ký tự được lưu trữ trong một byte, còn “a” là hằng xâu ký tự được lưu trữ trong một mảng hai phần tử: phần tử thứ nhất chứa mã chữ a còn phần tử thứ hai chứa \0. h. Tên hằng #define MaX 1000 Nghĩa là: tất cả các tên MAX trong chương trình xuất hiện sau toán tử này đều được thay thế bằng 1000. Vì vậy, ta thường gọi MAX là tên hằng (hay macro), nó biểu diễn số 1000. Một ví dụ khác, cho toán tử sau đây: #define Pi 3.141593 đặt tên cho hằng float 3.141593 là Pi. i. Một số ứng dụng của các hằng ký tự. Các hằng kiểu int, long, float, double thường dùng trong tính toán, còn các hằng ký tự và hằng xâu ký tự thường dùng trong in ấn. #include"stdio.h" main() { printf("\n hang dau phay dong: %10.2f %10.2f %10.2f %10.2f",1456.456,123E4,-2.123,2345.5); printf("\n\n hang nguyen: %10ld %10ld %10ld %10ld",1456.456,123E4,-2.123,2345.5); } 26
  27. 2.2.3. Các kiểu dữ liệu 2.2.3.1. Khái niệm về kiểu dữ liệu Dữ liệu là tất cả những gì được máy tính xử lý. Kiểu dữ liệu là một tập hợp các giá trị và một tập hợp các phép toán trên các giá trị đó Các kiểu dữ liệu cần tới máy xử lý có rất nhiều, tồn tại ở nhiều dạng khác nhau về bản chất, về ý nghĩa. Một kiểu dữ liệu được định nghĩa với 2 điểm chính là: - Một tập hợp các giá trị mà một biến thuộc kiểu đó có thể nhận được - Trên đó xác định một số phép toán Dữ liệu được chứa trong bộ nhớ máy tính với một số lượng ô nhớ nhất định tính theo đơn vị byte, ví dụ số nguyên loại int được lưu trữ trong 2 byte bộ nhớ. Phân loại các kiểu dữ liệu các kiểu số kiểu cơ sở nguyên các kiểu số thực kiểu ký tự kiểu vô kiểu logic boolean hướng kiểu vô hướng kiểu liệt do người lập kê trình tự định nghĩa kiểu kiểu array kiểu dữ liệu dữ có cấu trúc kiểu struct liệu kiểu file kiểu con trỏ 2.2.3.2 . Kiểu số nguyên Một giá trị thuộc kiểu số nguyên là một phần tử thuộc tập các số nguyên mà ta có thể biểu diễn được trên máy. Trong C có nhiều kiểu số nguyên với các giá trị khác nhau. Kiểu số nguyên cơ bản nhất trong C là kiểu số nguyên có dấu được định nghĩa với từ khoá int chiếm 2 bytes, phạm vi biểu diễn của nó là -32768 đến 32767. Cách biểu diễn một số nguyên int như sau: 27
  28. bit số 1: bit dấu Nếu bit dấu =0 thì biểu diễn số dương Nếu bit dấu =1 thì biểu diễn số âm Các bit 2 ,3 , , 16 biểu diễn giá trị của số dưới dạng số nhị phân ví dụ Biểu diễn cho số -653 Các hằng số nguyên được viết ra dưới dạng 0, 1, 2, 3 Với dấu dương + hoặc dấu âm – hoặc không có dấu. Trong C có nhiều kiểu số nguyên, với các dải giá trị khác nhau. Đặc biệt kiểu char thực chất là kiểu kí tự, trong C cho phép dùng kiểu kí tự này như là kiểu số nguyên. Nghĩa là trong các biểu thức số học thì kiểu char được sử dụng là số nguyên. Bảng sau cho biết các kiểu số nguyên với các dải giá trị của nó Kiểu biến Từ khoá Số byte Dải giá trị character char 1 -128  127 integer int 2 -32768  32767 short integer short 2 - 32768 32767 long integer long 4 -21474836582147483647 unsigned character unsigned char 1 0255 unsigned integer unsigned int 2 065535 Unsigned short unsigned short 2 064535 integer unsigned long unsigned long 4 04294967295 integer Các phép toán trên số nguyên Các phép tính số học: + (phép cộng ), - (phép trừ), * (phép nhân), / (phép chia lấy nguyên), % (phép chia lấy dư) 28
  29. Các phép tính logic số học & (phép and theo bit), | (phép or theo bit), ^ (phép xor theo bit), ~ (phép phủ định theo bit, còn gọi là đảo bit) Các phép so sánh: = (lớn hơn hay bằng), == (bằng nhau), != (khác nhau), (lớn hơn). Chú ý: Phép chia 2 số nguyên là số nguyên, không phải là số thực (điều này khác với ngôn ngữ lập trình pascal), muốn viết nó dưới dạng chính xác thì cần phải viết (float) x/y (đây còn gọi là đổi kiểu). Khi thực hiện các phép tính số học với các số nguyên cần lưu ý tránh sự tràn số. Ngoài cách viết số dưới dạng thập phân, C còn cho phép biểu diễn các số dưới dạng hexa (hệ 16) hoặc số hệ 8 với quy định: số hexa được viết bắt đầu là 0x hoặc 0x. Ví dụ số 65 (thập phân) được viết là 0x41 hay 0x41, số 15 được viết là 0xf hay 0xf. Còn số hệ 8 được viết bắt đầu là số 0. Ví dụ số 15 thập phân được viết là 017, số 34 được viết là 042 Tuy nhiên các cách dùng này thường được sử dụng trong lập trình hệ thống vì rất có lợi, còn thông thường ta nên hạn chế. Khởi tạo giá trị cho một biến nguyên: trong một số trường hợp ta cần gán giá trị ban đầu cho một biến nguyên, khi đó ta viết như sau: int tên_biến=giá_trị; ví dụ: int i, j=3; thay bởi cách viết thông thường int i,j; j=3; Hằng số nguyên có định trước kiểu: để đảm bảo độ chính xác của hằng số khi sử dụng, ta có thể định trước kiểu tường minh cho các hằng số nguyên theo quy định là thêm một ký tự vào cuối dãy các chữ số, chữ l cho kiểu long integer; chữ u cho kiểu unsigned; chữ ul cho kiểu unsigned long ví dụ: 20000u: là số nguyên kiểu unsigned 123455660l : là số nguyên kiểu long integer 560ul là số nguyên kiểu unsigned long integer 0x3000l : là số nguyên kiểu long integer viết dưới dạng số hexa 012345u: là số nguyên kiểu unsigned viết dưới dạng hệ cơ số 8. 2.2.3.3. Kiểu số thực Kiểu số thực là tập hợp các số thực có thể biểu diễn được trong máy tính và được máy định nghĩa sẵn với từ khoá: float, double, long double Bảng sau cho biết các kiểu số thực và dải giá trị của chúng 29
  30. Kiểu biến Từ Số byte dải giá trị khoá số thực với độ chính xác đơn float 4 1.2e-38 – 3.4e38 single-precision floating-point độ dài chính xác khoảng 7 chữ số số thực với độ chính xác kép doubl 8 2.2e-308 – 1.8e308 double-precision floating-point e độ dài chính xác khoảng 15 chữ số số thực với độ chính xác kép float 10 3.4e-4932 – 3.4e4932 long double-precision floating- độ dài chính xác khoảng 19 chữ point. Độ dài lớn số Cách viết số thực: * Cách viết dưới dạng thập phân bình thường (số thực dấu phẩy tĩnh): dùng dấu chấm để phân cách giữa phần nguyên và phần thập phân. Ví dụ: 3.1416; -0.2234; 2.0 * Dạng viết có phần mũ hay dạng viết khoa học (số thực dấu phẩy động): gồm 2 phần, phần định trị và phần mũ Ví dụ: 456.576e+3 = 4.56576x102 sẽ được viết lại cho máy tính là 4.56576 e +2 phần định trị phần mũ Phần định trị và phần mũ đều có thể có dấu đi kèm Phạm vi biểu diễn của số thực lớn hơn rất nhiều so với số nguyên, nên số thực thích hợp đối với những đại lượng có giá trị lớn với độ chính xác cao Cách viết các hằng số thực trong c Viết không cần phần thập phân: ví dụ 4. Không cần dấu chấm (.) ở phần định trị nếu có phần mũ: 2e-3 Viết bình thường: 5.9 Không cần có số 0 đầu tiên: .987 Có thể dùng chữ e: 6.0e45 Chú ý: 30
  31. Nhất thiết phải có dấu chấm (.) Không được viết dấu cách ở phần mũ Không dùng dấu phẩy (,). Các phép toán các phép toán +, -, *, / đều có thể áp dụng cho các toán hạng là các số thực, phép chia hai số thực cho kết quả là số thực. Không tồn tại phép % cho kiểu số thực. Khởi tạo giá trị đầu cho biến số thực tương tự số nguyên Hằng số thực định trước kiểu: ta có thể viết trước hằng số thực định trước kiểu tương tự như số nguyên bằng cách viết thêm một ký tự vào cuối dãy số theo nguyên tắc: chữ l cho kiểu long; chữ f cho kiểu float. Ví dụ: 0.908f là hằng số thực kiểu float 8756.908e-2l là hằng số thực kiểu long double 2.2.3.4. Kiểu kí tự (kiểu Char) Các kí tự là tất cả các chữ viết mà ta thường dùng như các chữ cái a,b, , các chữ số 0, 1, 2, Các dấu phân đoạn câu như ; , ! Kiểu kí tự trong C được định nghĩa với từ khoá char. Một giá trị kiểu kí tự là một phần tử thuộc tập hữu hạn các kí tự được xếp có thứ tự và một trong các sắp xếp đó là bảng mã ASCII, trong đó các kí tự được mã hoá bằng 1 byte, vì vậy bảng mã có thể mã hoá được 256 kí tự, tuy vậy số kí tự cơ bản được gói trong 128 số đầu, còn các số sau được gọi là phần mã mở rộng dùng để mã hoá các kí tự riêng của các ngôn ngữ. Trong bảng mã ASCII, các kí tự từ 0 đến 31 là các kí tự điều khiển, không in ra được, dùng để điều khiển các thiết bị ngoại vi. Phần còn lại bố trí toàn bộ các chữ cái, các chữ số và các kí tự đặc biệt. riêng kí tự 127 lại là kí tự điều khiển xoá. Các kí tự điều khiển không nhìn thấy được mã hoá bằng dãy escape với cách dùng dấu ‘\’. Biểu diễn một hằng kí tự ta có thể dùng: - Viết kí tự đó trong cặp ‘ ‘. Ví dụ ‘a’; ‘2’ \ x hhh trong đó hhh là giá trị hexa- deciment của kí tự trong bảng mã ASCII \ ddd trong đó ddd là giá trị giá trị số viết dưới dạng hệ cơ số 8 của kí tự trong bảng mã ASCII. 31
  32. Sau đây là bảng liệt kê các các kí tự điều khiển được mã hoá Kí tự Dã Giá trị trong bảng ASCII y mã đổ chuông (bel) \ a x07 7 xoá trái (backsspace) \ b x08 8 nhảy cách ngang \ t x09 9 nhảy cách đứng \ v x0b 11 xuống dòng mới \ n x0a 10 xuống dòng dưới \ f x0c 12 về đầu dòng \ x x0d 13 dấu “ \ “ x22 34 dấu ‘ / ‘ x27 39 dấu ? / ? x3f 39 dấu \ \ \ x5c 92 mã null (không) \ 0 x00 00 Bảng mã ASCII với 128 kí tự đầu hexa- 0 1 2 3 4 5 6 7 decimal 0 0 @ p ` p 0 16 32 48 64 80 96 112 1 ! 1 a q a q 1 17 33 49 65 81 97 113 2 " 2 b r b r 2 18 34 50 66 82 98 114 3 # 3 c s c s 3 19 35 51 67 83 99 115 4 $ 4 d t d t 32
  33. 4 20 36 52 68 84 100 116 5 % 5 e u e u 5 21 37 53 69 85 101 117 6 & 6 f v f v 6 22 38 54 70 86 102 118 7 ' 7 g w g w 7 23 39 55 71 87 103 119 8 ( 8 h x h x 8 24 40 56 72 88 104 120 9 ) 9 i y i y 9 25 41 57 73 89 105 121 a * : j z j z 10 26 42 58 74 90 106 122 b + ; k [ k { 11 27 43 59 75 91 107 123 c , - = m ] m } 13 29 45 61 77 93 109 125 e . > n ^ n ~ 14 30 46 62 78 94 110 126 f / ? o _ o 15 31 47 63 79 95 111 127 33
  34. 2.2.4 Các phép toán Trong C người ta phân biệt các loại phép toán sau: a. Các phép toán số học: phép toán ý nghĩa ví dụ - đổi dấu một số thực hoặc nguyên -12 ; -a + cộng hai số thực hoặc nguyên 12+13.5 ; a+b - trừ hai số thực hoặc nguyên 15-10; l2.l-3.2; a-b * nhân hai số thực hoặc nguyên a*b; 12*5; 12.3 *2 / chia hai số thực hoặc nguyên a/b; 23/3 ;23.3/2 % lấy phần dư của phép chia hai số nguyên a%b ;12%5 bằng 2 Các phép toán + và - (hai ngôi) có cùng độ ưu tiên, và nhỏ hơn số ưu tiên của hai phép toán * và /. Bốn phép toán này lại có độ ưu tiên thấp hơn so với phép trừ một ngôi. b. Các phép toán quan hệ: Phép toán Ý nghĩa Ví dụ > so sánh lớn hơn, toán hạng là số a>b nguyên hay số thực 3>7 có giá trị 0 >= so sánh lớn hơn hoặc bằng, toán hạng a>=b là số nguyên hoặc số thực 7>=7 có giá trị 0 < so sánh nhỏ hơn, toán hạng là số a<b nguyên hay số thực 6<7 có giá trị 1 <= so sánh nhỏ hơn hoặc bằng, toán hạng a<b là số nguyên hay số thực 3<=7 có giá trị 1 == so sánh bằng nhau, toán hạng có thể là a==b số nguyên hay số thực 7= =7 có giá trị 1 != so sánh không bằng nhau a!=b 7!=7 có giá trị 0 c. Các phép toán logic: Trong C sử dụng 3 phép toán logic: 34
  35. Liên từ ý nghĩa ví dụ && liên kết hai biểu thức logic. Giá trị cả hai ch >=’0’ && ch 6 có giá trị 1 || liên kết hai biểu thức quan hệ. Giá trị của n =100 có giá trị biểu thức là 1 khi một trong hai toán là l hạng bằng 1 ! phép phủ định một ngôi. !a !12 có giá trị 0 !0 có giá trị là l Hai phép toán && và || có số ưu tiên thấp hơn so với các phép toán quan hệ. Tất cả các phép toán này lại có số ưu tiên thấp hơn phép phủ định một ngôi. Các phép toán quan hệ và logic được sử dụng để thiết lập điều kiện rẽ nhánh trong lệnh if và điều kiện kết thúc chu trình trong các câu lệnh for, while, do while. Giá trị của toán hạng khác 0 sẽ được coi là true và ngược lại giá trị bằng 0 sẽ được coi là false. Giá trị biểu thức quan hệ và lôgic sẽ bằng l nếu đúng và bằng 0 nếu sai. d. Các phép toán tăng, giảm: Giả định có câu lệnh: so = so+ 1; Ta có thể viết gọn như sau: so++ ; Toán tử ++ cho phép tăng giá trị của biến so (kiểu số nguyên hay con trỏ) thêm 1 đơn vị. Trong C có hai phép toán một ngôi để tăng và giảm các biến. Toán tử tăng ++ sẽ cộng thêm 1 vào toán hạng của nó, toán tử giảm sẽ trừ toán hạng đi 1. Toán hạng ở đây có thể là biến nguyên, biến thực hoặc biến con trỏ (sẽ đề cập trong chương 3). Các dấu phép toán ++ và có thể đứng trước hoặc đứng sau toán hạng, như vậy chúng ta có thể viết: toán tử trước khi dùng sau khi dùng tăng 1 đơn vị ++ n n ++ giảm 1 đơn vị n n 35
  36. Sự khác nhau của n++ và ++n là ở chỗ: trong phép n++ thì n được tăng sau khi giá trị của nó được sử dụng, còn trong phép ++n thì giá trị của n được tăng trước khi nó được sử dụng. Đối với n và n cũng vậy. Bảng sau tổng kết các nhận định trên. Giả sử trước mỗi phép tính i=3 và j =15 Phép toán Tương đương Kết quả i = ++j; tăng trước j =j+1; i = j; i=16 và j =16 i = j++; tăng sau i = j; j = j+l; i =15 và j = 16 i++ ; i = i + l; i = 4 j = ++ i + 5; i= i + l; j = i + 5; i = 4 và j = 9 j = i++ +5; j = i + 5; i = i + l; i = 4 và i = 8 Các phép toán thao tác trên bit: đây là các phép toán thường gặp ở hợp ngữ hơn là ở ngôn ngữ cấp cao, chúng cho phép xử lý đến từng bit của một số nguyên. Các phép toán này không được dùng cho float hay double. Phép toán ý nghĩa & và nhị phân | hoặc nhị phân ^ hoặc có loại trừ > dịch phải ~ bù 1 Ta nhắc lại rằng: 1&1 =1 1|1 = 1 1^1 = 0 ~1 = 0 1&0 = 0 1|0 = 1 1^0 =1 ~0 = 1 0&1 = 0 0|1 = 1 0^1 = 1 a >n = a/2n 36
  37. Chú ý về các phép chuyển dịch. Cũng như hợp ngữ, C phân biệt: Các phép dịch chuyển số học, thực hiện trên các giá trị nguyên, bảo toàn bit dấu, các phép dịch chuyển logic, thực hiện trên các giá trị unsigned, bít dấu không đóng vai trò gì cả, cũng bị dịch chuyển như các bit khác. e. Thứ tự thực hiện các phép toán Dưới đây là bảng tổng hợp về thứ tự thực hiện các phép toán số học và quan hệ trong C. toán tử chiều tính toán () [ ] -> trái -> phải - ++ ! sizeof() là các toán tử một ngôi phải -> trái * / % trái -> phải + - trái -> phải > trái -> phải >= trái -> phải == != trái -> phải & trái -> phải ^ trái -> phải | trái -> phải && trái -> phải | | trái -> phải ?: phải -> trái = += -= *= /= %= &= ^= >= phải – trái 2.3. Các cấu trúc điều khiển 2.3.1. Lệnh vào/ra 2.3.1.1. Lệnh nhận giá trị cho biến từ bàn phím (hàm scanf()) Là lệnh cho phép đọc dữ liệu từ bàn phím và gán cho các biến trong chương trình khi chương trình thực thi. Trong ngôn ngữ C, sử dụng hàm scanf, hàm này nằm trong thư viện stdio.h. 37
  38. Cú pháp: scanf(“Chuỗi định dạng”, địa chỉ của các biến); Giải thích:- Chuỗi định dạng: dùng để qui định kiểu dữ liệu, cách biểu diễn, độ rộng, số chữ số thập phân Một số định dạng khi nhập kiểu số nguyên, số thực, ký tự. - Địa chỉ của các biến: là địa chỉ (&) của các biến mà chúng ta cần nhập giá trị cho nó. Được viết như sau: & . Ví dụ: scanf(“%d”,&bien1);/*Doc gia tri cho bien1 co kieu nguyen*/ scanf(“%f”,&bien2); /*Doc gia tri cho bien2 co kieu thưc*/ scanf(“%d%f”,&bien1,&bien2); /*Doc gia tri cho bien1 co kieu nguyen, bien2 co kieu thuc*/ scanf(“%d%f%c”,&bien1,&bien2,&bien3);/*bien3 co kieu char*/ Lưu ý: Chuỗi định dạng phải đặt trong cặp dấu nháy kép (“”). Các biến (địa chỉ biến) phải cách nhau bởi dấu phẩy (,). Có bao nhiêu biến thì phải có bấy nhiêu định dạng. Thứ tự của các định dạng phải phù hợp với thứ tự của các biến. Để nhập giá trị kiểu char được chính xác, nên dùng hàm fflush(stdin) để loại bỏ các ký tự còn nằm trong vùng đệm bàn phím trước hàm scanf(). Để nhập vào một chuỗi ký tự (không chứa khoảng trắng hay kết thúc bằng khoảng trắng), chúng ta phải khai báo kiểu mảng ký tự hay con trỏ ký tự, sử dụng định dạng %s và tên biến thay cho địa chỉ biến. Để đọc vào một chuỗi ký tự có chứa khoảng trắng (kết thúc bằng phím Enter) thì phải dùng hàm gets(). Ví dụ: int biennguyen; float bienthuc; char bienchar; char chuoi1[20], *chuoi2; 38
  39. Nhập giá trị cho các biến: scanf(“%3d”,&biennguyen); Nếu ta nhập 1234455 thì giá trị của biennguyen là 3 ký số đầu tiên (123). Các ký số còn lại sẽ còn nằm lại trong vùng đệm. scanf(“%5f”,&bienthuc); Nếu ta nhập 123.446 thì giá trị của bienthuc là 123.4, các ký số còn lại sẽ còn nằm trong vùng đệm. scanf(“%2d%5f”,&biennguyen, &bienthuc); Nếu ta nhập liên tiếp 2 số cách nhau bởi khoảng trắng như sau: 1223 3.142325- 2 ký số đầu tiên (12) sẽ được đọc vào cho biennguyen.- 2 ký số tiếp theo trước khoảng trắng (23) sẽ được đọc vào cho bienthuc. scanf(“%2d%5f%c”,&biennguyen, &bienthuc,&bienchar); Nếu ta nhập liên tiếp 2 số cách nhau bởi khoảng trắng như sau: 12345 3.142325: - 2 ký số đầu tiên (12) sẽ được đọc vào cho biennguyen. - 3 ký số tiếp theo trước khoảng trắng (345) sẽ được đọc vào cho bienthuc. - Khoảng trắng sẽ được đọc cho bienchar. Nếu ta chỉ nhập 1 số gồm nhiều ký số như sau: 123456789: - 2 ký số đầu tiên (12) sẽ được đọc vào cho biennguyen. - 5 ký số tiếp theo (34567) sẽ được đọc vào cho bienthuc. - bienchar sẽ có giá trị là ký số tiếp theo ‘8’. scanf(“%s”,chuoi1); hoặc scanf(“%s”,chuoi2) Nếu ta nhập chuỗi như sau: Nguyen Van Linh thì giá trị của biến chuoi1 hay chuoi2 chỉ là Nguyen . scanf(“%s%s”,chuoi1, chuoi2); Nếu ta nhập chuỗi như sau: Duong Van Hieu thì giá trị của biến chuoi1 là Duong và giá trị của biến chuoi2 là Van.Vì sao như vậy? C sẽ đọc từ đầu đến khi gặp khoảng trắng và gán giá trị cho biến đầu tiên, phần còn lại sau khoảng trắng là giá trị của các biến tiếp theo.gets(chuoi1); Nếu nhập chuỗi : Nguyen Van Linh thì giá trị của biến chuoi1 là Nguyen Van Linh 2.3.1.2. Lệnh xuất của biểu thức lên màn hình (hàm printf) Là lệnh xuất giá trị của biểu thức lên màn hình. Trong C sử dụng hàm printf để thực hiện lệnh này. Hàm này có trong thư viện stdio.h. Cú pháp:printf(“Chuỗi định dạng ”, Các biểu thức); Giải thích: 39
  40. - Chuỗi định dạng: dùng để qui định kiểu dữ liệu, cách biểu diễn, độ rộng, số chữ số thập phân Một số định dạng khi đối với số nguyên, số thực, ký tự. Định dạng Ý nghĩa %d Xuất số nguyên %[.số chữ số Xuất số thực có theo quy tắc làm thập phân] f tròn số. %o Xuất số nguyên hệ bát phân %x Xuất số nguyên hệ thập lục phân %c Xuất một ký tự %s Xuất chuỗi ký tự %e hoặc %E Xuất số nguyên dạng khoa học (nhân 10 mũ x) hoặc %g hoặc %G Ví dụ %d In ra số nguyên %4d In số nguyên tối đa 4 ký số, nếu số cần in nhiều hơn 4 ký số thì in hết %f In số thực %6f In số thực tối đa 6 ký số (tính luôn dấu chấm), nếu số cần in nhiều hơn 6 ký số thì in hết - Các biểu thức: là các biểu thức mà chúng ta cần xuất giá trị của nó lên màn hình, mỗi biểu thức phân cách nhau bởi dấu phẩy (,). Ví dụ:include int main(){ int bien_nguyen=1234, i=65;float bien_thuc=123.456703; printf(“Gia tri nguyen cua bien nguyen =%d\n”,bien_nguyen); printf(“Gia tri thuc cua bien thuc =%f\n”,bien_thuc); printf(“Truoc khi lam tron=%f \n Sau khi lam tron=%.2f”,bien_thuc, bien_thuc); return 0;} Lưu ý: Đối với các ký tự điều khiển, ta không thể sử dụng cách viết thông thường để hiển thị chúng.Ký tự điều khiển là các ký tự dùng để điều khiển các thao tác xuất, nhập dữ liệu. Một số ký tự điều khiển được mô tả trong bảng: 40
  41. Ký tự điều Giá trị thập Ký tự Ý nghĩa khiển lục phân được hiển thị \a 0x07 BEL Phát ra tiếng chuông \b 0x08 BS Di chuyển con trỏ sang trái 1 ký tự và xóa ký tự bên trái (backspace) \f 0x0C FF Sang trang \n 0x0A LF Xuống dòng \r 0x0D CR Trở về đầu dòng \t 0x09 HT Tab theo cột (giống gõ phím Tab) \\ 0x5C \ Dấu \ \ddd ddd Ký tự có mã ACSII trong hệ bát phân là số ddd \xHHH oxHHH Ký tự có mã ACSII trong hệ thập lục phân là HHH Ví dụ: #include #include int main () { clrscr(); printf("\n Tieng Beep \a"); printf("\n Doi con tro sang trai 1 ky tu\b"); printf("\n Dau Tab \tva dau backslash \\"); printf("\n Dau nhay don \' va dau nhay kep \""); printf("\n Dau cham hoi \?"); printf("\n Ky tu co ma bat phan 101 la \101"); printf("\n Ky tu co ma thap luc phan 41 la \x041"); printf("\n Dong hien tai, xin go enter"); getch(); printf("\rVe dau dong"); getch(); return 0; } 2.3.2. Lệnh lựa chọn if Toán tử if cho phép lựa chọn một trong hai nhánh tuỳ thuộc vào sự bằng không hay khác không của một biểu thức: Mẫu lệnh 1: if (biểu thức) lệnh_1 else lệnh_2; 41
  42. Hoạt động: khi gặp lệnh này, máy sẽ tính giá trị biểu thức, nếu biểu thức cho giá trị khác không thì máy sẽ thực hiện lệnh_1, nếu biểu thức cho giá trị bằng 0 thì máy sẽ thực hiện lệnh_2. Mẫu lệnh 2: if (biểu thức) lệnh_1 ; Hoạt động: khi gặp lệnh này, máy sẽ kiểm tra biểu thức, nếu biểu thức cho giá trị khác không thì máy sẽ thực hiện lệnh_1, ngược lại thì thoát khỏi lệnh if. Lệnh_1, lệnh_2 có thể là: Một câu lệnh đơn giản, kết thúc bằng dấu chấm phẩy Một khối lệnh nằm giữa cặp dấu { } Câu lệnh có cấu trúc Ví dụ: Nhập vào hai số, đưa ra màn hình giá trị lớn nhất, nhỏ nhất của hai số đó #include #include void main(){ int x,y,min,max; clrscr(); printf(“hay go vao so nguyen thu nhat: “); scanf("%d",&x); printf(“\nhay go vao so nguyen thu hai: “); scanf("%d",&y); if (x>y) { max=x; min=y; } else { max=y; min=x; } printf(“gia tri lon nhat la: %d”,max); 42
  43. printf(“\ngia tri nho nhat la: %d”,min); getch(); } Ta có thể thay thế câu lệnh if else Bằng toán tử điều kiện max= (x>y)?x:y min= (x 1000 000 đồng và #include #define vat 18.6 void main(){ clrscr(); double nguyen_gia, gia_ban, ty_le, chiet_khau,gia_tra; 43
  44. printf("cho gia hang nguyen goc chua tinh thue:"); scanf("%lf",&nguyen_gia); gia_ban=nguyen_gia*(1+vat/100); if (gia_ban 50000000.) ty_le=6; chiet_khau=gia_ban*ty_le/100; gia_tra=gia_ban-chiet_khau; printf("\ngia ban: %10.2lf",gia_ban); printf("\nchiet khau: %10.2lf",chiet_khau); printf("\ngia phai tra: %10.2lf",gia_tra); getch(); } 2.3.3. Lệnh switch Lệnh switch cho phép chọn một trong nhiều phương án Mẫu lệnh switch (biểu thức){ case hằng_1: {dãy lệnh 1}; case hằng_2: {dãy lệnh 2}; case hằng_n: {dãy lệnh n}; [default : {dãy lệnh n+1}] } Trong đó: - biểu thức: là một biểu thức nguyên bất kì - hằng_i: là các giá trị mà biểu thức có thể nhận được - dãy lệnh i: một dãy các lệnh có thể thực hiện khi biểu thức nhận giá trị hằng_i. Hoạt động: khi gặp lệnh này, máy sẽ tính giá trị biểu thức, nếu biểu thức nhận giá trị là hằng_1 thì máy sẽ thực hiện dãy lệnh_1, nếu biểu thức nhận giá trị là hằng_2 thì máy sẽ thực hiện dãy lệnh 2, nếu trong câu lệnh có dùng tuỳ chọn 44
  45. defaul: {dãy lệnh n+1} thì nếu máy không nhận giá trị nào trong các hằng_i , máy sẽ tự động thực hiện dãy lệnh n+1 Ví dụ: Viết chương trình nhập vào một số có một chữ số, đưa ra màn hình tên của chữ số đó. #include #include void main(){ clrscr(); char ch; ch=getchar(); switch (ch){ case '1': {printf("\nmot"); break;} case '2': {printf("\nhai"); break;} case '3': {printf("\nba"); break;} case '4': {printf("\nbon"); break;} case '5': {printf("\nnam"); break;} case '6': {printf("\nsau"); break;} case '7': {printf("\nbay"); break;} case '8': {printf("\ntam"); break;} case '9': {printf("\nchin"); break;} case '0': {printf("\nkhong"); break;} default: printf("\nkhong phai chu so"); } getch(); return; } 2.3.4. Vòng lặp xác định for (biết trước số lần lặp) Mẫu lệnh for dạng 1: dạng biểu thức for ([biểu thức 1]; [biểu thức 2]; [biểu thức 3] ) câu lệnh; Dạng chức năng: 45
  46. for ([khởi tạo]; [điều kiện]; [thay đổi điều kiện] ) câu lệnh; Trong đó: + Các phần để trong ngoặc vuông là các phần tuỳ ý. + Các dấu “;” và dấu ngoặc đơn bắt buộc phải có. + Câu lệnh có thể là lệnh đơn, lệnh ghép hay lệnh có cấu trúc khác, như vậy ta có thể có các vòng for lồng nhau. nếu câu lệnh là lệnh ghép thì phải đặt trong cặp dấu “{” và “}”. + Câu lệnh có thể không có. bắt đầu công việc biểu thức 1 0 kết thúc - Hoạt động: khi gặp lệnh này, máy xác định giá trị khởi tạo của biến, sau đó kiểm tra biểu thức điều kiện, nếu điều kiện cho giá trị khác 0 thì máy sẽ thực hiện câu lệnh rồi tăng giá trị của biến điều khiển và quay lại chương trình. nếu điều kiện cho giá trị là 0 thì máy sẽ thoát khỏi vòng lặp. Ví dụ 1: Viết chương trình in ra màn hình các số từ 1 đến 24, mỗi số một dòng. #include #include void main(){ clrscr(); int i; for (i=1;i<=24;i++) printf("\n%d",i); getch(); return; 46
  47. } Nếu ta sử dụng lệnh for dưới dạng chức năng thì chương trình trên có thể viết như sau: #include #include void main(){ clrscr(); int i; i=1; for (;i #include #include #define eol '\n' void main(){ clrscr(); char chu[80]; int tong,dem; for (dem=0;(chu[dem]=getchar())!=eol;++dem); tong=dem; for(dem=0;dem<tong;++dem) putchar(toupper(chu[dem])); getch(); return; } 47
  48. Chú ý: Dòng lệnh for (dem=0;(chu[dem]=getchar())!=eol;++dem); không có câu lệnh, trong trường hợp này dòng lệnh có tác dụng làm bộ đếm (vì kết thúc lệnh này, ta nhận được giá trị của biến dem) Ví dụ 3: Viết chương trình nhập vào n số nguyên, sau đó đưa ra màn hình giá trị trung bình cộng của các số đó. #include #include void main(){ clrscr(); int n,i; float x,tbc,tong=0.; printf("cho biet can tinh bao nhieu so: "); scanf("%d",&n); for (i=1;i<=n;++i){ printf("x%d=",i); scanf("%f",&x); tong+=x; } tbc=tong/n; printf("\ntrung binh cong la: %f",tbc); getch(); } Nhận xét: + Biểu thức 1 bao giờ cũng chỉ được tính một lần. + Biểu thức 2, biểu thức 3 và công việc được thực hiện lặp đi lặp lại nhiều lần trong chương trình. Chú ý: + Khi biểu thức 2 vắng mặt thì nó luôn được được xem là đúng. trong trường hợp này, muốn thoát khỏi vòng lặp thì cần phải có lệnh break, goto hoặc return. + Trong phần ngoặc tròn sau từ khoá for gồm 3 phần phân cách nhau bởi dấu “;”. Có thể viết thiếu một biểu thức nhưng cũng có quyền viết một dãy biểu thức phân cách nhau bởi dấu phảy trong mỗi biểu thức, khi đó các biểu thức trong mỗi 48
  49. phần được xác định từ trái sang phải. tính đúng sai của dãy biểu thức trong phần thứ hai được hiểu là tính đúng sai của biểu thức cuối cùng trong dãy. Ví dụ: đảo ngược một dãy số cho trước #include #include float x[]={63.2,-45.6,70.1,3.6,14.5}; int n=sizeof(x)/sizeof(float); main(){ clrscr(); int i,j; float c; for (i=0,j=n-1;i while (biểu thức); Trong đó + Công việc là một hay nhiều lệnh, nếu có nhiều lệnh thì các lệnh phải đặt trong cặp dấu “{” và “}”. + Dấu ngoặc đơn trong biểu thức là bắt buộc. + Biểu thức là một biểu thức logic hay biểu thức nguyên. 49
  50. Hoạt động: khi gặp lệnh này, máy sẽ thực hiện công việc, sau đó kiểm tra biểu thức, nếu biểu thức cho giá trị khác 0 thì máy còn lặp lại công việc. nếu biểu thức cho giá trị bằng 0 thì máy sẽ thoát khỏi vòng lặp. Ví dụ : nhập vào các kí tự cho đến khi gặp kí tự ‘*’ #include #include void main() { char c; clrscr(); do c=getchar(); while (c!='*'); getch(); } Dòng lệnh do c=getchar(); while (c!='*'); còn có thể thay bởi dòng lệnh: do while ((c=getchar()) !=’*’) Lưu đồ minh hoạ lệnh do while (biểu thức) bắt đầu công việc sai biểu thức đúng kết thúc Vòng lặp vô tận: do while (1); Để thoát khỏi vòng lặp mà không cần điều kiện, dùng lệnh break 50
  51. Ví dụ: viết chương trình tính ex theo công thức xấp xỉ taylor ex= 1 + t(1) + t(2) + + t(n). Trong đó số hạng thứ n của chuỗi t(n) = xn/n! Nhận xét: ta thấy số hạng thứ k của chuỗi được xác định bởi công thức truy hồi t(t) = t(k-1)*x/k Chương trình: #include #include void main(){ float e_mu,epsilon,x,t; int n; clrscr(); printf("nhap gia tri cua x= "); scanf("%f",&x); printf("nhap gia tri sai so epsilon= "); scanf("%f",&epsilon); e_mu=1; n=1; t=x; do{ e_mu+=t; n++; t=t*x/n; }while (t>epsilon); printf("e mu %5.3f=%f ",x,e_mu); getch(); } 2.3.6. Vòng lặp không xác định while Mẫu lệnh: while (biểu thức) ; 51
  52. Trong đó: + Biểu thức là một biểu thức logic hay biểu thức nguyên + Công việc: có thể là một lệnh đơn giản hay một lệnh có cấu trúc khác. nếu công việc gồm nhiều lệnh thì các lệnh phải để trong cặp dấu { }, khi này không có dấu “;” kết thúc. Để kết thúc công việc phải dùng dấu “;”. Công việc có thể rỗng. Hoạt động: khi gặp lệnh này, máy sẽ tính giá trị của biểu thức, nếu biểu thức cho giá trị khác 0 thì máy sẽ thực hiện công việc, ngược lại thì sẽ thoát khỏi vòng lặp chuyển sang câu lệnh sau thân lặp. Chú ý: + Biểu thức phải được đặt trong cặp (). + Biểu thức luôn được tính toán đầu tiên nên cần phải có giá trị xác định cho biểu thức đó. Lưu đồ minh hoạ lệnh while (biểu thức) ; bắt đầu sai biểu thức đúng kết thúc công việc Ví dụ 1: Ta sử dụng lại ví dụ “ viết chương trình tính ex theo công thức xấp xỉ taylor”. Đoạn code của chương trình như sau: #include #include void main(){ 52
  53. float e_mu,epsilon,x,t; int n; clrscr(); printf("nhap gia tri cua x= "); scanf("%f",&x); printf("nhap gia tri sai so epsilon= "); scanf("%f",&epsilon); e_mu=1; n=1; t=x; while (t<epsilon){ e_mu+=t; n++; t=t*x/n; } printf("e mu %5.3f=%f ",x,e_mu); getch(); } Nhận xét: + Các biểu thức trong ngoặc tròn sau các lệnh while hay do while chẳng những có thể đặt một biểu thức mà còn có thể đặt một dãy biểu thức phân cách nhau bởi dấu phảy, tính đúng sai của dãy biểu thức được hiểu là tính đúng sai của biểu thức cuối cùng. + Bên trong thân của một toán tử while hay do while Lại có thể sử dụng các toán tử lặp khác, bằng cách đó ta có thể có các vòng lặp lồng nhau. + Phân biệt giữa lệnh while và do while Trong lệnh do while công việc bao giờ cũng được thực hiện ít nhất là một lần, còn trong lệnh while, công việc có thể không được thực hiện lần nào. 2.3.7. Các lệnh rẽ nhánh vô điều kiện a. Lệnh break: Dùng để kết thúc câu lệnh điều khiển đang thực hiện. nghĩa là khi gặp lệnh này, máy sẽ dừng lặp để sang câu lệnh tiếp theo. 53
  54. Khi gặp lệnh break trong thân các vòng lặp lồng nhau, máy sẽ thoát khỏi vòng lặp sâu nhất chứa lệnh này. b. Lệnh continue: Cho phép chuyển sang vòng lặp tiếp theo mà không cần thực hiện phần còn lại của vòng lặp đang thực hiện. ví dụ: #include main(){ int i; for (i=1;i #include main(){ clrscr(); int i; for (i=1;i<=10;i++){ printf("bat dau vong %d\n",i); printf("chao ban\n"); if (i==3) goto ra; printf("ket thuc vong %d\n",i); 54
  55. } ra: printf("ket thuc vong lap!"); getch(); return 0; } Ghi nhớ Khai báo biến bắt đầu bằng tên kiểu dữ liệu của biến, tiếp theo là tên biến; nếu có thiếu biến, tên các biến được cách nhau bởi các dấu phẩy. Câu lệnh khai báo được kết thúc bằng dấu chấm phẩy. Định nghĩa hằng bằng toán tử #define. Câu lệnh lựa chọn if chỉ thực hiện câu lệnh đi kèm khi điều kiện đưa mô tả trong nó là đúng. Câu if else có thể kiểm tra để thực hiện nhiều lựa chọn khác nhau. nếu có nhiều điều kiện đúng, chỉ có câu lệnh đi sau điều kiện thỏa mãn lần đầu tiên được thực hiện. Một câu lệnh ghép có thể đặt ở bất cứ đâu, tại đó một câu lệnh để có thể có mặt. một câu lệnh rỗng không làm gì. Biểu thức câu lệnh rỗng bằng cách đặt dấu chấm phẩy thay thế cho cả câu lệnh. Một câu lệnh lặp mô tả rằng một hành động được lặp lặp lại chừng nào biểu thức vẫn còn đúng. Thông thường một vài thao tác bên trong phần thân câu lệnh lặp có xu hướng làm cho điều kiện của câu lệnh lặp trở lên bị sau. Một giá trị có chứa phần không nguyên được xem là một số thực dấu phẩy động được biểu thị bằng kiểu dữ liệu float. Các lỗi thường gặp khi lập trình Quên một hoặc cả hai dấu { và } để bắt đầu và kết thúc một câu lệnh ghép. Đặt một dấu chấm phẩy sau điều kiện trong câu lệnh điều kiện if , điều đó dẫn tới một lỗi logic. Trong phần thân của câu lệnh while không có các câu lệnh nhằm làm cho điều kiện trong while trở nên sai. thông thường, cấu trúc lặp như vậy sẽ không bao giờ kết thúc. Chúng ta gọi đây là lỗi lặp vô hạn. Viết các từ khoá với chữ hoa, ví dụ: while thay vì while. Chia một số cho 0 - lỗi nặng. 55
  56. Sử dụng phép toán (toán tử) tăng hoặc giảm số học đối với các hằng hoặc biểu thức ví dụ ++ ( i+1 ) - lỗi cú pháp. Một số thói quen lập trình tốt cần học tập Tập thói quen viết chương trình có căn chỉnh lề để tăng tính dễ đọc. Nếu có nhiều mức căn lề, mỗi mức phải được căn lề với cùng số khoảng trống một cách rõ ràng. Trước khi viết chương trình, nên viết sơ đồ khối mô tả thuật toán. Một số lập trình viên thích viết trước các dấu { và } bắt đầu và kết thúc của một câu lệnh ghép trước khi viết các câu lệnh thành phần bên trong câu lệnh ghép. Khi thực hiện phép chia cho một biểu thức mà giá trị của biểu thức có thể bằng 0. trong trường hợp đó phải kiểm tra trước khi chia để tránh gây lỗi cho chương trình (fatal error). Các toán tử một ngôi phải được đặt bên cạnh toán hạng của chúng không nên đặt thêm các dấu trắng vào giữa. Không nên so sánh bằng nhau các giá trị số thực. 2.4. Cấu trúc mảng 2.4.1. Khái niệm Mảng (array) là một dãy liên tiếp các phần tử, mỗi phần tử chứa (hay có thể chứa) một dữ liệu cùng một kiểu. một mảng các số nguyên gồm các phần tử là các số nguyên. một mảng các con trỏ số nguyên bao gồm các thành phần, mỗi thành phần là địa chỉ của một số nguyên. Kích thước của mảng là số các phần tử. Kích thước này phải được khai báo tường minh trong phần khai báo mảng, vì nó xác định vị trí và kích thước của vùng nhớ được cấp phát cho mảng. Mảng có thể có một hay nhiều chiều. Chúng ta có thể khai báo mảng với số chiều là một, hai hay tùy ý. Ngôn ngữ C không giới hạn số chiều của mảng (nếu như khả năng của máy cho phép). Khai báo mảng Một mảng cần khai báo để định rõ + loại mảng (int, float, double, ) + tên mảng + số chiều và số phần tử của mỗi chiều - Khai báo mảng một chiều kiểu_phần_tử tên_mảng[số phần tử của mảng]; 56
  57. ví dụ: int x[100] khai báo mảng hai chiều ví dụ: float y[3][5]; số phần tử của mảng là 100 tên mảng là x kiểu_phần_tử là int Là một mảng có 15 phần tử là số thực có số dòng là 3 và số cột là 5. Các phần tử của mảng được đánh số theo sơ đồ sau kiểu_phần_tử tên_mảng[số phần tửdòng][số phần tử cột]; y[0,0] y[0,1] y[0,2] y[0,3] y[0,4] y[1,0] y[1,1] y[1,2] y[1,3] y[1,4] y[2,0] y[2,1] y[2,2] y[2,3] y[2,4] Khi khai báo mảng, có thể khởi tạo ngay giá trị cho mảng Ví dụ: int x[3]={4, 2, 6}. Nghĩa là x[0]=4; x[1]=2; x[2]=6; float y[2][3]={{0.1, 0.5, 9.8}, {4.6, 3.6, 2.7}} hay float y[2][3]={0.1, 0.5, 9.8, 4.6, 3.6, 2.7} 2.4.2. Truy nhập đến các phần tử của mảng Các phần tử của mảng được cấp phát các khoảng nhớ liên tiếp nhau trong bộ nhớ, điều đó có nghĩa là các phần tử của mảng có địa chỉ liên tiếp nhau. mỗi phần tử của mảng được truy nhập trực tiếp thông qua tên mảng cùng chỉ dẫn truy nhập được để trong cặp ngoặc vuông []. Các phần tử của mảng luôn được đánh số từ 0 đến số phần tử của mảng - 1 Với khai báo int x[100], x là tên một mảng gồm 100 số nguyên, các phần tử được xếp như sau: x x x x . . . . x [0] [1] [2] [3] [98] [99] 57
  58. Chỉ số của mảng bắt buộc phải có kiểu int và không vượt quá kích thước của chiều tương ứng. Tuy nhiên biểu thức dùng làm chỉ số có thể là thực, khi đó giá trị chỉ số là phần nguyên của biểu thức đó. Khi chỉ số vượt ra ngoài kích thước của mảng máy sẽ không báo lỗi, nhưng sẽ truy nhập đến một vùng nhớ ngoài vùng nhớ của mảng, điều đó có thể làm rối chương trình. ví dụ: Đọc các giá trị cho mảng x từ bàn phím #include #include #define kichthuoc 5 void main(){ clrscr(); int x[kichthuoc]; int i; for (i=0;i 58
  59. #include main(){ clrscr(); int tab[3][2],i,j; for (i=0;i<3;i++) for (j=0;j<2;j++) tab[i][j]=i*2+j+1; for (i=0;i<3;i++) printf("%d %d\n",tab[i][0],tab[i][1]); getch(); return 0; } 2.4.3. Xâu kí tự và mảng Xâu kí tự trong C được định nghĩa như là một mảng các kí tự và có độ dài của xâu kết thúc bằng kí tự “\0” hay còn gọi là kí tự null. Khai báo xâu kí tự char tên_xâu[số kí tự tối đa]; ví dụ: char line[80]; thì line có thể chứa tối đa là 80 kí tự. Nếu ta dùng lệnh gets(line) rồi ta nhập vào một xâu “chao cac ban” thì các kí tự của xâu được bố trí như sau: 0 1 8 9 0 Độ dài thực của xâu là 12, dãy trên được đánh số theo chỉ số của mảng, nghĩa là bắt đầu từ 0. Độ dài thực của xâu bằng số các kí tự trong xâu +1. Khi khai báo xâu kí tự có thể khởi tạo cho xâu luôn và không có khai báo kích thước cụ thể, khi đó chương trình dịch tự động bố trí đủ một mảng ô nhớ để chứa dãy kí tự trên và kí tự kết thúc ‘\0’ 59
  60. ví dụ: char xau[]=”cong hoa xa hoi chu nghia viet nam”; Ta cũng có thể khai báo như sau: char xau[40]=”cong hoa xa hoi chu nghia viet nam”; Đây là cách khai báo có khởi tạo và dự trữ 40 byte ô nhớ, tuy nhiên hiện tại máy không sử dụng hết số ô nhớ đó, nhưng với cách này ta có thể thay đổi nội dung của xâu kí tự với tối đa là 39 kí tự. Xác định độ dài xâu kí tự Có thể xác định độ dài xâu kí tự bằng cách đếm, song C cung cấp cho ta hàm strlen( xâu) dùng để xác định độ dài của xâu, hàm này được đặt trong file string.h. ví dụ: nhập vào một xâu kí tự, cho biết độ dài của xâu #include #include #include void main(){ clrscr(); char str1[40]=”khoa cong nghe thong tin “; printf(“do dai xau str1 la %d ki tu”,strlen(str1)); getch(); return; } Truy nhập vào các phần tử của xâu kí tự Ta có thể truy nhập vào các phần tử của xâu thông qua tên biến và chỉ dẫn truy nhập được đặt trong cặp [] như khi truy nhập vào các phần tử của mảng, chỉ cần lưu ý rằng chỉ dẫn này bắt đầu từ 0. Nếu chỉ dẫn nằm ngoài độ dài thực của xâu kí tự thì phần tử đó không xác định. Vì vậy khi truy nhập vào phần tử của xâu ta cần kiểm tra xem vị trí đó có nằm trong khoảng độ dài thực của xâu hay không. Một số hàm cơ bản xử lý xâu ký tự Ngôn ngữ lập trình C xây dựng lớp các hàm mẫu để xử lý xâu ký tự, các hàm này được đặt trong file tiêu đề string.h 60
  61. #include mô tả tóm tắt chức năng của hàm strcpy(char dest[], char source[] ) sao chép nội dung xâu source vào xâu dest strncpy(char dest[], char source[]) tương tự như strcpy(), nhưng ngừng sao chép sau n ký tự. Trong trường hợp không có đủ số ký tự trong source thì hàm sẽ điền thêm các ký tự trắng vào xâu dest. strcat(char ch1[], char ch2[] nối xâu ch2 vào cuối xâu ch1. sau lời gọi hàm này độ dài xâu ch1 bằng tổng độ dài của cả hai xâu ch1 và ch2 trước lời gọi hàm. strncat(char ch1[], char ch2[],int tương tự như strcat nhưng chỉ giới hạn với n n) ký tự đầu tiên của ch2 int strcmp(char ch1[], char ch2[]) so sánh hai xâu ch1 và ch2. Nguyên tắc so sánh theo kiểu từ điển. Giá trị trả về: 0 nếu xâu ch1 bằng xâu ch2 >0 nếu xâu lớn hơn xâu ch2 61
  62. #include void main(){ clrscr(); char str1[40]=”xau thu nhat”; char str2[40]=” xau thu hai”; int dem1=0,dem2=0; while (str1[dem1]!='\0') dem1++; while (str2[dem2]!='\0') dem2++; if ((sizeof(str1)/sizeof(str1[0]))<(dem1+dem2+1)) printf("khong the ghep vi thieu bo nho!"); else { dem2=0; while (str2[dem2] !='\0') str1[dem1++]=str2[dem2++]; str1[dem1]='\0'; printf("\n%s",str1); } getch(); } Copy xâu kí tự Vì xâu kí tự là một mảng nên không thể gán một xâu cho một biến, vì vậy muốn thực hiện việc này thì phải viết một vòng lặp để copy từng kí tự một. Tuy nhiên C cung cấp cho chúng ta một hàm strcpy(xâu1,xâu2) để copy xâu 2 lên xâu1. Tuy nhiên hàm này không kiểm tra tính đúng đắn về kích thước ô nhớ của xâu1 có đủ chứa xâu2 hay không, vì vậy khi sử dụng bạn phải kiểm tra vấn đề này. So sánh xâu kí tự Khi so sánh hai xâu kí tự, các kí tự của hai xâu được so sánh theo từng cặp một từ trái qua phải theo giá trị của bảng mã ASCII. Nếu hai xâu có độ dài khác nhau song số kí tự giống nhau đến độ dài xâu ngắn hơn thì xâu có độ dài ngắn hơn được coi là bé hơn. Hai xâu kí tự bằng nhau nếu cả về nội dung và độ dài của chúng là giống nhau. 62
  63. Nếu hai xâu không bằng nhau thì hàm cho giá trị là hiệu số của mã ASCII của hai kí tự đầu tiên khác nhau. Ví dụ: nhập vào hai từ, sau đó đưa ra màn hình xem từ nào đứng trước #include #include #include void main(){ clrscr(); char tu1[20],tu2[20]; printf("\nhay go vao hai tu:\n 1:"); scanf("%s",&tu1); printf("2:"); scanf("%s",&tu2); if (strcmp(tu1,tu2)==0) printf("hai tu bang nhau hoan toan"); else printf("%s di truoc %s" ,(strcmp(tu1,tu2) #include void thucdon(char *tieude,char *lua[],int kichthuoc); main() { clrscr(); static char *chon[]={ "a>dd an address", 63
  64. "e>dit an address", "d>isplay an address" }; static char tieude[40]="main menu\n\n"; thucdon(tieude,chon,3); getch(); return 0; } void thucdon(char *tieude,char *lua[],int kichthuoc) { int i; printf(tieude); for (i=0;i<kichthuoc;i++) printf("%s\n",*(lua +i)); } 2.5. Con trỏ 2.5.1. Khái niệm con trỏ Con trỏ là một biến chứa địa chỉ của một biến. Vì có nhiều loại địa chỉ nên cũng có nhiều kiểu con trỏ tương ứng. Con trỏ int chứa địa chỉ của các biến kiểu int, con trỏ kiểu float, kiểu double, Cũng tương tự như vậy. Trong C, con trỏ thường được sử dụng vì với con trỏ thì chương trình có thể được viết ngắn gọn hơn và hiệu quả hơn những cấu trúc khác. 2.5.2. Khai báo con trỏ Cũng như các biến khác, một con trỏ phải được khai báo trước khi sử dụng. Người lập trình phải chỉ ra kiểu của biến được trỏ tới. Mẫu khai báo kiểu_của_biến_được_trỏ *tên_biến_trỏ; 64