1. Trang chủ
  2. » Luận Văn - Báo Cáo

Báo cáo kết thúc học phần môn cơ sở lập trình Đề tài the c programming language

69 0 0
Tài liệu được quét OCR, nội dung có thể không chính xác
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

Tài liệu hạn chế xem trước, để xem đầy đủ mời bạn chọn Tải xuống

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Tiêu đề The C Programming Language
Tác giả Nguyen Hoang Kim Anh, Huynh Thi Le Huyen, Nguyen Thi Hong Nhu, La Mai Anh Thy, Phan Thi Tra
Người hướng dẫn ThS. Nguyen Lac
Trường học Trường Đại Học Lao Động - Xã Hội (Cơ Sở II)
Chuyên ngành Hệ thống thông tin quản lý
Thể loại báo cáo
Năm xuất bản 2024
Thành phố TP. Hồ Chí Minh
Định dạng
Số trang 69
Dung lượng 4,2 MB

Nội dung

Chúng tôi cũng sử dụng các dâu ngoặc nhọn xung quanh câu lệnh đơn tạo nên phần thân của do-while, mặc dù chúng không cần thiết, đề người đọc vội vàng sẽ không nhằm phần while với phần đầ

Trang 1

TRƯỜNG ĐẠI HỌC LAO ĐỘNG - XÃ HỘI (CƠ SỞ II) KHOA GIÁO DỤC ĐẠI CƯƠNG

i BAO CAO KET THUC HOC PHAN

Nhóm sinh viên thực hiện:

NGUYEN HOANG KIM ANH - 223404050146 HUYNH THI LE HUYEN - 223404050168 NGUYEN THỊ HỎNG NHƯ - 223404050183

LÊ MAI ANH THY - 223404050198 PHAN THỊ TRÀ — 223404050201 Ngành: Hệ thống thông tin quan ly

TP Hé Chi Minh, thang 01 năm 2024

Trang 3

3.1 Câu lệnh và khối - + t1 E211 E121 1 1 1 111 ng HH rà Hàn ryk 2

CHƯƠNG 4: HÀM VÀ CẤU TRÚC CHƯƠNG TRÌNH - 5° 5° 5 52 19 4.1 Cơ bản về hàm 2 2 SE E21 1127102 1 E1 H1 1 trau 20 4.3 Biến bên ngoài à 1c TT HH ng 1n 112gr yo 28

Trang 4

Bài tập 3-5: 0 c1 ng ng reo 59 Bài tập 3-6: 22 2 2221 n2 ng 22g reo 59 Bài tập 4-1: 222 2c 222211 n2 n1 22 re rreaee 60 Bài tập 4-2: 0c 221 n1 nung rreaee 60 Bài tập 4-3: 00 n1 ng n2 ren rreaee 62 Bài tập 4-4: 22 c2 n2 n1 22 ng greree 62

Bài tập 4-14: 22222 2211 tnn2221E 22tr ng eeegere 65

BANG PHAN CONG CONG YVIỆC 2° se csExsExsevkEEseEteeerkerererrersrerrsrrke 67

Trang 5

Trong thế giới rộng lớn của ngôn ngữ lập trình, ít ngôn ngữ nào có thể sánh bằng sức mạnh, tính linh hoạt và ý nghĩa lịch sử của C Ngôn ngữ này đã vượt qua thử thách thời gian và tiếp tục được sử dụng rộng rãi trong rất nhiều ứng dụng, từ lập trình hệ thống

và thiết bị nhúng đến phát triển game và tính toán cao cấp Nếu bạn là người mới muốn

bắt đầu hành trình khám phá thê giới lập trình, việc học C có thể là một điểm khởi đầu

tuyệt vời

Trong bài viết này, chúng tôi sẽ khám phá các khía cạnh cơ bản của C và cung cấp cho bạn kiến thức và tài nguyên cần thiết dé bước đầu học những ngôn ngữ này Bài viết này sẽ nghiên cứu tập trung hai chủ đề: luồng điều khiển (Control Flow), hàm và cầu trúc chương trinh (Functions And Program Structure); tir đó đi sâu hơn vào cách sử dụng và những lưu ý khi sử dụng Với luồng điều khiến, lập trình viên có thê tạo ra các chương trình thích ứng với các tình huỗng khác nhau, xử lý các điều kiện khác nhau và thực hiện các hành động cụ thê dựa trên những điều kiện đó Hàm cho phép lập trình viên hoàn

thành các nhiệm vụ cụ thê và cải thiện tổng thê cầu trúc chương trình Cầu trúc chương

trình bao gồm các tiêu đề, khai báo, định nghĩa hàm và các câu lệnh Bằng việc tuân đúng theo cấu trúc chương trình, chúng ta có thể đảm bảo tính rõ ràng của code, khả nang bao trì và dễ dàng sửa lỗi

Do đó, đề tài Luông điều khiển (Control Flow), Hàm và cấu trúc chương trình (Functions And Program Structure) được chúng tôi lựa chọn đề nghiên cứu Chúng tôi sẽ tìm hiểu, giải thích cú pháp cơ bản của chúng và giới thiệu cho bạn các công cụ và tải liệu cần thiết để xây dựng kỹ năng lập trình của bạn Bài viết này sẽ cung cấp những thông tin vô cùng hữu ích và là nền tảng đề các lập trình viên tập sự dựa vào và phát triển khả năng lập trình của mình

Trang 6

CHUONG 3: LUONG DIEU KHIEN

Luong điều khiển câu lệnh của một ngôn ngữ chỉ rõ trình tự thực hiện của bài toán

chúng ta đã được tiếp cận đến cấu trúc của luồng điều khiển phổ biến nhất trong ví dụ trước; trong chương này chúng ta sẽ hoàn thiện chúng và đi sâu hơn vào những gì đã

được bàn luận ở trước

3.1 Câu lệnh và khối

Một biểu thức như x=0 hay ¡++ hay printf ( ) trở thành một câu lệnh khi theo sau

nó là một dầu chấm phầy, như bên dưới

câu lệnh đơn Các đấu ngoặc nhọn bao quanh các câu lệnh của hàm là một ví dụ rõ ràng:

dau ngoặc nhọn xung quanh nhiều câu lệnh sau ïf, else, while hoặc for là một câu lệnh khác (Các biến có thể được khai báo bên trong bất kỳ khối nào; chủng ta sẽ nói về điều này trong Chương 4.) Không đặt dấu chấm phây sau dâu ngoặc nhọn bên phải đề kết thúc

một khối

3.2 If-else

Mệnh đề if-else được sử dụng đề thể hiện các quyết định Về mặt hình thức, cú

pháp của nó là

Trang 7

statement2

trong đó phần else là tùy chọn Biều thức được kiểm tra; nêu nó đúng (nghĩa là biêu

thức if co gia trị khác 0), câu lệnh 1 sẽ được thực thi Nếu nó sai (biêu thức bằng 0) và

nếu có phần khác thi câu lệnh 2 sẽ được thực thi thay thé

Vi if chi kiém tra gia tri số của một biểu thức nên có thể sử dụng một 36 phim tat

mã hóa nhất định Rõ ràng nhất là viết

if (expression)

thay vì viết

if (expression != 9)

Đôi khi điều này hiển nhiên và rõ ràng: đôi khi nó có thê khó hiéu

Boi vi phan else cua if-else là tùy chọn nên sẽ có sự mơ hồ khi phần else bi bỏ qua khỏi chuỗi ¡f lồng nhau Điều này được giải quyết bằng cach lién két else véi else-less if gân nhất trước đó Ví dụ, trong

phan else đi cùng với ¡f bên trong, như chúng ta đã chỉ ra bằng cách thụt lề Nếu đó

không phải là điều bạn muốn, thì phải sử dụng dấu ngoặc nhọn đề buộc có sự liên kết

phù hợp:

Trang 8

printf ("error n is negative\n");

Việc thụt lề hiển thị rõ ràng những gì bạn muốn, nhưng trình biên dịch không nhận

được thông báo và sẽ liên kết else với ¡f bên trong Loại lỗi này có thê khó tìm; bạn nên

sử dụng dau ngoặc nhọn khi có các 1f long nhau

Nhân tiện, hãy chú ý rằng có dấu chấm phẩy sau z = a trong

if (a > b)

z=a;

else

z=b;

Điều này là do về mặt ngữ pháp, một câu lệnh tuân theo 1Ý và một câu lệnh biểu

thức như "z = a;" luôn được kết thúc bằng dâu chấm phay

3.3 Else-if

Cấu trúc dưới đây

Trang 9

xay ra thuong xuyén đến mức cần có một cuộc thảo luận ngăn về nó Chuỗi câu

lệnh ¡f này là cách tổng quát nhất đề viết một quyết định đa chiều Các biểu thức được kiêm tra theo thứ tự; nêu bất kỳ biểu thức nào là đúng thì câu lệnh liên quan đến nó sẽ được thực thi và điều này sẽ chấm dứt toàn bộ chuỗi Như mọi khi, code cho mỗi câu

lệnh là một câu lệnh đơn hoặc một nhóm trong dấu ngoặc nhọn

Lệnh else cuối cùng xử lý trường hợp "không có trường hợp nào ở trên" hoặc trường hợp default, khi mà không có điều kiện nào khác được thỏa mãn Đôi khi không

có hành động rõ ràng nào cho trường hợp mặc định, khi đó

else

statement

có thể được bỏ qua hoặc có thé duoc str dung dé kiém tra 16i nham nam bat diéu

kiện "không thê"

Để minh họa quyết định ba chiều, đây là hàm tìm kiếm nhị phân quyết định xem

một giá trị x cụ thê có xuất hiện trong mảng v được sắp xép hay không Các phần tử của

v phải theo thứ tự tăng dần Hàm trả về vị trí (một số nằm giữa 0 và n-l) nêu x xuất hiện trong v, và -[ nêu không

Trước tiên, tìm kiêm nhị phân so sánh giá trị đầu vào x voi phân tử ở giữa của máng

v Nêu x nhỏ hơn giá trị ở giữa, việc tìm kiêm sẽ tập trung vào nửa dưới của bảng, nêu không thì ở nửa trên Trong cả hai trường hợp, bước tiếp theo là so sánh x với phần tử ở

Trang 10

Quyết định cơ bản là liệu x nhỏ hơn, lớn hơn hay bằng phần tử ở giữa v[mid] ở mỗi bước; đây là điều đương nhiên đối với else-if

Bai tap 3-1 Tim kiém nhị phân của chúng tôi thực hiện hai thử nghiệm bên trong

vòng lặp, khi đó chỉ cần một thử nghiệm là đủ (bỏ hết các thử nghiệm bên ngoài) Viết một phiên bản chỉ có một bài test bên trong vòng lặp và đo lường sự khác biệt về thời gian chạy

3.4 Switch

Cau lénh switch la mot quyét định nhiều chiều nhằm kiểm tra xem một biểu thức có

khớp với một trong số các giá trị nguyên không đôi và các nhánh tương ứng hay không

switch (expression)

case const-expr: statements

case const-expr: statements

Trang 11

đó Tất cả các biểu thức case phải khác nhau Default được thực thĩ nêu không có case nào khác được thỏa mãn Giá trị default là tùy chọn; nếu nó không có ở đó và nêu không

có case nào khớp thì sẽ không có hành động nào diễn ra Các case và default có thê xảy

ra theo bất kỳ thứ tự nào

Trong Chương 1, chủng ta đã viết một chương trình đếm số lần xuất hiện của mỗi chữ số, khoảng trắng và tất cả các ký tự khác, sử dụng một chuỗi if else ¡f else Đây

là chương trình tương tự được viết bằng switch:

Câu lệnh break sé giúp thoát ra ngay lập tức khỏi switch Vi các case chỉ đóng vai

trò là nhãn nên sau khi code cho một case được thực hiện xong, việc thực thi sẽ chuyển

Trang 12

trong chương này

Các case chạy liên tục không có khoảng nghỉ là một điều vui buồn lẫn lộn Về mặt tích cực, nó cho phép gắn nhiều case vào một hành động duy nhất, như với các chữ số trong ví dụ này Nhưng nó cũng hàm ý rằng thông thường mỗi case phải kết thúc bằng một khoảng nghỉ đề tránh chuyến sang case tiếp theo Việc chuyên từ case này sang case

khác khiến chương trình bị lỏng léo khi được sửa đôi Ngoại trừ nhiều nhãn cho một lần tính toán, các thông số dự phòng nên được sử dụng một cách tiết kiệm và được chủ thích

Đề đảm bảo hình thức, hãy đặt dấu ngắt sau case cuối cùng (default) mặc dù về mặt logic thì điều đó là không cần thiết Một ngày nào đó khi một case khác được thêm vào cuối, phần lập trình phòng thủ này sẽ cứu bạn

Bài tập 3-2 Viết hàm thoát ( s, t) để chuyên đôi các ký tự thành dòng mới và tab

thành các chuỗi thoát hiền thị như \n và \ t khi nó sao chép chuỗi t thành s Sử dụng lệnh switch Viết một hàm cho hướng khác, chuyên đôi chuỗi thoát thành kí tự

3.5 Vong lap While va For

Chúng ta đã gặp các vòng lặp while và for Trong

biểu thức được kiểm tra Nếu nó khác 0, câu lệnh sẽ được thực thi và biểu thức

được kiểm tra lại Chu kỳ này tiếp tục cho đến khi biêu thức trở thành 0, tại thời điểm đó

việc thực thị sẽ tiếp tục sau câu lệnh

Trang 13

ngoại trừ hành vĩ tiếp tục, được mô tả trong Phần 3.7

Về mặt ngữ pháp, ba thành phần của vòng lặp for là các biêu thức Thông thường nhất, exprl và expr3 là các phép gán hoặc lệnh gọi hàm và expr2 là một biểu thức quan

hệ Bất kỳ phần nào trong ba phần đều có thê được bỏ qua, mặc dù vẫn phải giữ lại dấu cham phẩy Nếu exprl hoặc expr3 bị bỏ qua, nó sẽ bị loại khỏi bản mở rộng Nếu phép thử expr2 không xuất hiện thì nó được coi là đúng vĩnh viễn, vì vậy

là một vòng lặp "vô hạn”, có lẽ bị phá vỡ bằng các cách khác, chăng hạn như break

hoặc return

Việc sử dụng while hay for phân lớn là một vấn đề về sở thích cá nhân Ví dụ, trong

không có khởi tạo hoặc khởi tạo lại nên while chạy tự nhiên nhất

For được ưu tiên hơn khi có sự khởi tạo và tăng dân đơn giản, vì nó giữ cho các câu lệnh điều khiển vòng lặp gần nhau và hiển thị ở đầu vòng lặp Điều này thể hiện rõ nhất ở

Trang 14

đó là thành ngữ trong C đề xử lý n phần tử đầu tiên của một mảng, tương tự như vòng lặp Fortran DO hoặc For của Pascal Tuy nhiên, sự tương tự này không hoàn hảo vì chỉ số và giới hạn của vòng lặp C for có thể được thay đổi từ bên trong vòng lặp và biến ¡ vấn giữ nguyên giá trị của nó khi vòng lặp kết thúc vì bất kỳ lý do gì Bởi vì các thành phân của for là các biêu thức tùy ý, nên các vòng lặp for không bị giới hạn ở cấp số cộng Tuy nhiên, sẽ không phù hợp nếu buộc các phép tính không liên quan vào việc khởi tạo

và tăng dần for, vốn tốt hơn nên dành cho các hoạt động điều khiển vòng lặp

Một ví dụ lớn hơn, đây là một phiên bản khác của atoi để chuyên đổi một chuỗi thành số tương đương Phần này tông quát hơn một chút so với phần ở Chương 2; nó xử

lý khoảng trăng ở đầu tùy chọn và dấu + hoặc - tùy chọn (Chương 4 trình bày atof, thực hiện chuyền đổi tương tự cho các số dấu phây động.)

Cấu trúc của chương trình phan anh dang dau vao:

bỏ qua khoảng trăng, nếu có

lay dấu, nêu có

lây phán nguyên và chuyên đổi nỗ

Mỗi bước thực hiện phan việc của minh va dé moi thứ ở trang thai chin chu cho

bước tiếp theo Toàn bộ quá trình kết thúc ở ký tự đầu tiên không thề là một phần của sô

Trang 15

Thư viện chuẩn cung cấp hàm strtol phức tap hon dé chuyền đôi chuỗi thành số

nguyên đài; xem Phần 5 của Phụ lục B

Ưu điểm của việc duy trì điều khiển vòng lặp tập trung thậm chí còn rõ ràng hơn khi có nhiều vòng lặp lồng nhau Hàm sau đây là sắp xếp Shell đề sắp xếp một mảng các

số nguyên Ý tưởng cơ bản của thuật toán sắp xếp này được phát minh vào năm 1959 bởi

D L Shell, đó là trong giai đoạn đầu, các phần tử ở xa nhau được so sánh, thay vì các phân tử liền kề như trong các loại trao đối đơn giản hơn Điều này có xu hướng loại bỏ một lượng lớn rồi loạn một cách nhanh chóng, đo đó các giai đoạn sau có ít việc phải làm hơn Khoảng cách giữa các phần tử được so sánh giảm dần xuống còn một, tại thời điểm

đó, việc sắp xếp trở thành một phương pháp trao đôi liền kề một cách hiệu quả

Trang 16

Có ba vòng lặp lồng nhau Phần ngoài cùng kiểm soát khoảng cách giữa các phần

tử được so sánh, thu nhỏ nó từ n/2 theo hệ số hai mỗi lần đi qua cho đến khi nó trở thành

0 Vòng lặp giữa bước dọc theo các phần tử Vòng lặp trong cùng so sánh từng cặp phần

tử được phân tách bằng khoảng cách và đảo ngược bất kỳ phần tử nào không theo thứ tự

Vì khoảng cách cuối cùng được giảm xuống còn một, nên tất cả các phần tử thậm chí còn được sắp xếp chính xác Lưu ý tính tổng quát của for làm cho vòng lặp bên ngoài có đạng giống như các vòng lặp khác, mặc dù nó không phải là một cấp số cộng

Toán tử C cuối cùng là dấu phẩy "„ ", thường được sử dụng nhiều nhất trong câu lệnh for Một cặp biêu thức được phân tách bằng dau phây được kiểm tra từ trái sang phải, loại và giá trị của kết quả là loại và giá trị của toán hạng bên phải Do đó, trong câu lệnh for, có thể đặt nhiều biêu thức vào các phần khác nhau, ví dụ như xử lý song song hai chỉ số Điều này được minh họa trong hàm đảo ngược ( s), đảo ngược chuỗi s tại chỗ

Dau phây phân tách các đối số hàm, biến trong khai báo, v.v., không phải là toán tử dâu phầy và không đảm bảo việc kiêm tra từ trái sang phải

Toán tử đấu phẩy nên được sử dụng một cách tiết kiệm Cách sử dụng phù hợp nhất

là cho các cấu trúc có liên quan chặt chế với nhau, như trong vòng lặp for ngược và trong macro trong đó tính toán nhiều bước phải là một biểu thức duy nhất Biểu thức dấu phây

Trang 17

cũng có thê thích hợp cho việc trao đôi các phần tử ngược lại, trong đó việc trao đổi có

thể được coi là một thao tác đơn lẻ:

Bài tập 3-3 Viết hàm mở rộng ( s I, s2) để mở rộng các ký hiệu tốc ký như a-z trong chuỗi sI thành danh sách đầy đủ tương đương abc xyz trong s2 Cho phép các chữ cái có cả chữ hoa và chữ số, đồng thời chuẩn bị xử lý các trường hợp như a-b-c và a- z0-9 và -a-z Sắp xếp sao cho đầu hoặc cuối - được hiệu theo nghĩa đen

3.6 Vong lap Do-while

Nhu chung ta da thao ludn 6 Chuong 1, vong lap while va for kiém tra điều kiện kết thúc ở trên cùng Ngược lại, vòng lặp thứ ba trong C, vòng lặp do-while, kiểm tra ở phía

dưới sau khi thực hiện mỗi lần đi qua thân vòng lặp; phan thân luôn được thực thi ít nhất

một lân

Cú pháp của do là

Câu lệnh được thực thi, sau đó biểu thức được kiểm tra Nếu nó đúng, câu lệnh sẽ được kiểm tra lại, v.v Khi biểu thức sai, vòng lặp sẽ kết thúc Ngoại trừ ý nghĩa của việc

kiêm tra, do-while tương đương với câu lệnh repeat-until của Pascal

Kinh nghiệm cho thấy do-while ít được sử dụng hơn while và for Tuy nhiên, đôi khi nó vẫn có giá trị, như trong hàm itoa sau đây, hàm này chuyên đôi một số thành một chuỗi ký tự (nghịch đáo của atoi) Công việc phức tạp hơn một chút so với những gi

Trang 18

người ta nghĩ lúc đầu, bởi vì các phương pháp tạo chữ số dễ dàng sẽ tạo ra chúng theo

thứ tự sai Chúng tôi đã chọn tạo chuỗi ngược, sau đó đảo ngược chuỗi đó

Việc do-while là cần thiết, hoặc ít nhất là thuận tiện, vì ít nhất một ký tự phải được

cài đặt trong mảng s, ngay cả khi n bằng 0 Chúng tôi cũng sử dụng các dâu ngoặc nhọn xung quanh câu lệnh đơn tạo nên phần thân của do-while, mặc dù chúng không cần thiết,

đề người đọc vội vàng sẽ không nhằm phần while với phần đầu của vòng lặp while Bài tập 3-4 Trong cách biều điễn số bù 2, phiên bản itoa của chúng tôi không xử lý

số âm lớn nhất, tức là giá trị của n bang -(2wordsize-1) Giải thích tại sao lai không Sửa

déi no dé in giá trị đó một cách chính xác bat ké may chay trén do

Bài tập 3-5 Viết hàm itob ( n, s, b) dé chuyén sé nguyén n thanh biéu dién ky ty co

số b trong chuỗi s Cụ thể, itob (n,s, 16) định dạng n dưới dạng sỐ nguyên thập lục phân trong s

Bài tập 3-6 Viết một phiên bản của itoa chấp nhận ba đối số thay vì hai Đối số thứ

ba là độ rộng trường tối thiêu; số được chuyền đôi phải được đệm bằng khoảng trống ở bên trái nêu cân thiệt dé lam cho nó đủ rộng

Trang 19

3.7 Break va Continue

Đôi khi thật thuận tiện đề có thể thoát khỏi vòng lặp ngoài việc kiểm tra ở đầu hoặc

cuối Câu lệnh break cung cấp một lối thoát sớm khỏi for, while va do, giống như switch Việc dùng break làm cho vòng lặp bao quanh bên trong hoặc lệnh switch bi thoat ra ngay lập tức

Hàm sau đây - trim - giúp loại bỏ các khoảng trống, tab và dòng mới khỏi cuối chuỗi, sử dụng break để thoát khỏi vòng lặp khi tìm thấy dòng không trông, không tab, không phải dòng mới ngoài cùng bên phải

strlen trả về độ dài của chuỗi Vòng lặp for bắt đầu ở cuối và quét ngược lại dé tìm

ký tự đầu tiên không phái là ký tự trống, tab hoặc dòng mới Vòng lặp thoát ra khi tìm thấy một chuỗi hoặc khi n trở thành số âm (nghĩa là khi toàn bộ chuỗi đã được quét) Bạn nên xác minh rằng hành vi này đúng ngay cả khi chuỗi có giá trị trồng hoặc chỉ chứa các

ký tự khoảng trắng

Câu lệnh continue có liên quan đến break nhưng ít được sử đụng hơn; nó làm cho lần lặp tiếp theo của vòng lặp for, while hoặc do bắt đầu Trong while và do, điều này nghĩa là phần kiểm tra được thực thi ngay lập tức; trong for, điều khiển chuyển sang bước tăng dần Câu lệnh continue chỉ áp dụng cho vòng lặp, không áp dụng cho switch Việc continue bên trong một switch nằm trong một vòng lặp sẽ gây ra sự lặp lại vòng lặp tiếp theo

Trang 20

Ví dụ, đoạn này chỉ xử lý các phần tử không 4m trong mang a, gia tri âm được bỏ qua

Câu lệnh continue thường được sử dụng khi phần vòng lặp tiếp theo phức tạp hơn,

do đó việc đảo ngược phép kiểm tra và thụt lề sang một cấp độ khác sẽ lồng chương trình quá sâu

3.8 Cau lénh Goto va Label

Ngôn ngữ C cung cấp câu lệnh goto có khả năng sử dụng vô hạn và gắn nhãn cho các nhánh tới Về mặt hình thức, goto không bao giờ là cần thiết, và trong thực tế, việc viết code mà không cần đến nó hầu như luôn dễ dàng Chúng tôi chưa sử dụng gotfo trong cuôn sách này

Tuy nhiên, có một số trường hợp goto có thê tìm được chỗ đứng Phô biến nhất là

từ bỏ việc xử lý trong một số câu trúc lồng nhau sâu, chăng hạn như thoát ra khỏi hai hoặc nhiều vòng lặp cùng một lúc Câu lệnh break không thể được sử dụng trực tiếp vì

nó chỉ thoát ra từ vòng lặp trong cùng Như vậy:

Trang 21

Cách tô chức nay rất hữu ích nêu code xử lý lỗi không tầm thường và nếu lỗi có thê

xảy ra ở một sô nơi

Một label có dạng giống như tên biến và được theo sau bởi dầu hai chấm Nó co thé được gắn vào bất kỳ câu lệnh nào có cùng chức năng với goto Phạm vi của label là toàn

bộ chức năng

Một ví dụ khác, hãy xem xét bài toán xác định xem hai mảng a và b có phần tử chung hay không Một khả năng là

Code liên quan đến goto luôn có thê được viết mà không cần đến goto, mặc đù có

thé bd qua một số thử nghiệm lặp lại hoặc một biến bổ sung Ví dụ, mảng tìm kiếm trở

thành

Với một vài trường hợp ngoại lệ như được trích dẫn ở đây, code dựa trên câu lệnh goto thường khó hiểu và khó duy trì hơn code không có goto Mặc đù chúng tôi không giáo điều về vần đề này, nhưng có vẻ như việc sử dung goto la kha hiém hoi

Trang 22

CHUONG 4: HAM VA CAU TRUC CHUONG TRINH

Ham phân chia những nhiệm vụ lớn trên máy tính ra từng phần nhỏ hơn, và cho

phép chúng ta dựng lên từ những gì đã có sẵn thay vì phải bắt đầu lại từ con số 0 Những hàm thích hợp sẽ ân đi những chỉ tiết trong cách thức hoạt động của một chương trình mà

chúng ta không cần thiết phải biết đến, từ đó khiến moi thir dé hiéu hon, để thay đôi hơn

Ngôn ngữ C được thiết kế để giúp các hàm trở nên hiệu quả và đễ sử dụng hơn; nhìn chung, chương trình C bao gồm nhiều hàm nhỏ thay vì các hàm lớn Một chương

trình có thê nằm trong một hoặc nhiều tập tin nguồn Cac tap tin nguon có thê được biên

dịch một cách riêng lẻ và tải đồng thời, cùng với những hàm đã được biên dịch trước đó

từ những thư viện Tuy nhiên, chúng ta sẽ không đi sâu vào quá trình đó ở chương này,

vì các chỉ tiết vô cùng đa dạng qua từng hệ thông

Những khai báo và định nghĩa về hàm là nơi mà tiêu chuẩn ANSI đã có những thay đôi rõ rệt với ngôn ngữ C Như chúng ta đã thấy ở chương l, giờ đây việc khai báo các

loại đối số khi một hàm được khai báo là khả thi Cu pháp của định nghĩa hàm cũng được thay đôi, để các khai báo và định nghĩa khớp nhau Điều này giúp bộ biên dịch có thê

phát hiện ra nhiều lỗi hơn so với trước đây Hơn thế nữa, khi một đối số được khai báo

đúng cách, các coercion dugc ty động thực hiện

Tiêu chuẩn này giải thích những quy luật của các tên gọi; trên thực tế, nó yêu cầu chỉ một định nghĩa duy nhất cho mỗi đối tượng bên ngoài Việc khởi tạo trở nên tổng quát hơn, các mảng và cầu trúc tự động bây giờ có thê được khởi tạo

Bộ xử lý trước của C cũng được nâng cao Các cơ sở xử lý mới bao gồm một bộ chỉ

thị biên dich có điều kiện hoàn chỉnh hơn, một cách đề tạo các chuỗi trích dẫn từ các đối

so macro và kiêm soát tôt hơn quá trình mở rộng macro

Trang 23

4.1 Co ban vé ham

Dé bat dau, chung ta hãy thiết kế và viết một chương trình in từng dòng đầu vào chứa một mẫu hoặc chuỗi ký tự cụ thê (Đây là trường hợp đặc biệt của UNIX grep) Ví

du: tim kiém cum “ould” trong các dòng sau

To grasp this sorry Scheme of Things entire, Would not we shatter it to bits and then

Re-mould it nearer to the Heart's Desire!

sé cho dau ra

Would not we shatter it to bits and then

Re-mould it nearer to the Heart's Desire!

Công việc được chia thành ba phân:

Mặc dù chắc chắn có thể đặt code cho tất cả những điều này trong mai, nhưng cách tốt hơn là sử dụng cấu trúc đề tận dụng lợi thế bằng cách biến phần bộ đệm thành

một hàm riêng biệt Những phần nhỏ sẽ dễ xử lý hơn một phân lớn vì các chi tiết không

liên quan có thê bị ân trong các chức năng và khả năng xảy ra các tương tác không mong muốn được giảm thiểu Và các phần thậm chí có thê hữu ích trong các chương trình khác

Trang 24

“While there's another line” là getline, mot ham ma chung ta da viét 6 Chuong | va

“print it” la printf, thir ma ai do da cung cap cho chung ta Diéu nay co nghia la chung ta chỉ cần viết một thủ tục đề quyết định xem dòng đó có chứa sự xuất hiện của mẫu hay không

Chúng ta có thê giải quyết vấn đề đó bằng cách viết hàm strindex( s.f) trả về vị trí hoặc chỉ mục trong chuỗi s nơi chuỗi t bắt đầu hoặc -I nêu s không chứa t Bởi vì mảng

C bat dau 6 vi trí 0, nên các chỉ mục sẽ bằng 0 hoặc dương và do đó, giá trị âm như -Ì sẽ

thuận tiện cho việc báo hiệu lỗi Sau này khi chúng ta cần so khớp mẫu phức tạp hơn, chúng ta chỉ phải thay thế strindex; phần còn lại của mã có thể giữ nguyên (Thư viện

chuẩn cung cấp ham sfrstr tương tự như strnndex, ngoại trừ việc nó trả về một con trỏ thay vì một chỉ mục.)

Với nhiều thiết kế như vậy, việc điền thông tin chỉ tiết của chương trình rất đơn giản Đây là toàn bộ, vì vậy bạn có thê thấy các mảnh ghép khớp với nhau như thế nào Hiện tại, mẫu cần tìm kiếm là một chuỗi ký tự, không phải là cơ chế tổng quát nhất Chúng ta sẽ sớm quay lại phần thảo luận về cách khởi tạo mảng ký tự và trong Chương 5

sẽ chỉ ra cách biến mẫu thành một tham số được thiết lập khi chương trình được chạy

Ngoài ra còn có một phiên bản hơi khác một chút của getline; bạn có thê thấy hữu ích khi

so sánh nó với cái trong Chương 1

Trang 25

Mỗi định nghĩa hàm có dạng

Trang 26

Nó không làm gì và không trả về gì Chức năng không làm gì như thế này đôi khi hữu ích với vai trò giữ chỗ trong quá trình phát triển chương trình Nếu kiểu trả về bị bỏ qua, int duoc giả định

Một chương trình chỉ là một tập hợp các định nghĩa về các biến và hàm Giao tiếp giữa các hàm được thực hiện bằng các đối số và giá trị được hàm trả về và thông qua các biến bên ngoài Các hàm có thê xuất hiện theo bất kỳ thứ tự nào trong tệp nguồn và chương trình nguồn có thê được chia thành nhiều tệp, miễn là không có hàm nảo bị phân chia

Câu lệnh return là cơ chế trả về một giá trị từ hàm được gọi cho hàm gọi nó Bat ky

biểu thức nào cũng có thé theo sau return:

Biểu thức này sẽ được chuyên đôi thành kiêu trả về của hàm nêu cân thiết Dấu ngoặc đơn thường được sử dụng xung quanh biêu thức, nhưng không bắt buộc Hàm khi gọi có thể bỏ qua giá trị trả về Hơn nữa, không cần có biểu thức nào sau return; trong trường hợp đó, không có giá trị nào được trả lại cho người gọi Điều khiển cũng trả về cho người gọi mà không có giá trị khi việc thực thi "rơi ra khỏi phần cuối"

Trang 27

của hàm bằng cách chạm đến dấu ngoặc đóng bên phải Điều này không phải là bất hợp pháp, nhưng có thể là đầu hiệu của sự cố nếu một hàm trả về một giá trị ở nơi này và không có giá trị ở nơi khác Trong mọi trường hợp, nêu một hàm không trả về một giá trị thì "giá trị" của nó chắc chăn là rác

Chương trình tìm kiếm mẫu trả về trạng thái từ main, số lượng kết quả khớp được tìm thấy Giá trị này có sẵn để sử dụng bởi môi trường được gọi là chương trình

Cơ chề biên địch và tải một chương trình C nằm trên nhiều tệp nguồn khác nhau tùy theo hệ thống Ví dụ, trên hệ thống UNIX, lệnh cc được đề cập ở Chương I sẽ thực hiện công việc này Giả sử rằng ba hàm này được lưu trữ trong ba tệp co tén main c, getline c

và strindex c Sau đó lệnh

biên dịch ba tệp, đặt code của đối tượng kết quả vào các tệp main.o, getiine.o và

strindex,.o, sau do tai tat ca chúng vào một tệp thực thi có tên là a.out Nếu có lỗi, chăng hạn như trong main.c, tệp đó có thể được tự biên dịch lại và kết quả được tải cùng với

các tệp đối tượng trước đó bằng lệnh

Lệnh cc sử đụng quy ước đặt tên " c" so với " o" để phân biệt tệp nguồn với tệp

đối tượng

Bài tập 4-1 Viết hàm strrindex ( s, t), trả về vị trí xuất hiện ngoài cùng bên phải của

t trong s hoac -1 nêu không có

4.2 Hàm trả về số không nguyên

Trang 28

Cho đến nay các ví dụ về hàm của chúng ta đều không trả về giá trị (void) hoặc int Điều gì xảy ra nếu một hàm phải trả về một số kiểu khác? Nhiều hàm số như sqrf, sin va cos return double; các hàm chuyên biệt khác trả về các kiêu khác Để minh họa cách giải quyết vấn đề này, chúng ta hãy viết và sử đụng hàm atof{s), hàm này sẽ chuyên đôi chuỗi

s thành chuỗi dâu phây động có độ chính xác kép tương đương atof là một phần mở rộng của atoi, mà chúng tôi đã trình bày các phiên bản trong Chương 2 và 3 Nó xử lý một dâu hiệu và dấu thập phân tùy chọn cũng như sự hiện diện hay vắng mặt của phần nguyên hoặc phần phân số Phiên bản của chúng tôi không phải là một quy trình chuyển đôi đầu vào chất lượng cao; điều đó sẽ chiếm nhiều không gian hơn mức chúng ta muốn sử dụng Thư viện tiêu chuẩn bao gồm atof: tiêu đề <stdlib.h> khai báo nó

Đầu tiên, bản thân atof phải khai báo kiểu giá trị mà nó trả về, vì nó không phải là

Int Tên loại đứng trước tên hàm:

Thứ hai, và cũng quan trọng không kém, quy trình gọi phải biết rằng atof trả về giá trị không phải int Một cách để đảm bảo điều này là khai báo atof một cách rõ ràng trong

Trang 29

quy trình gọi Khai báo được hiển thị trong máy tính nguyên thủy này (hầu như không đủ

để cân bằng số séc), đọc một số trên mỗi dòng, tùy ý đặt trước một dấu hiệu và cộng chúng lại, m tông hiện có sau môi đâu vảo:

nÓI rằng sum là một biến kép và atof là một hàm nhận một đối số char[] va tra về

một giá trị gấp đôi

Hàm atof phải được khai báo và xác định một cách nhất quán Nếu chính atof và

lệnh gọi nó trong main có kiều không nhất quán trong cùng một tệp nguôn, thì lỗi sẽ

được trình biên dịch phát hiện Nhưng nếu (rất có thẻ) atof được biên dịch riêng biệt thi

sự không khớp sẽ không được phát hiện, atof sẽ trả về một giá trị gấp đôi mà main sẽ coi

là immt và sẽ dân đến các câu trả lời vô nghĩa

Dựa trên những gì chúng tôi đã nói về cách các khai báo phải khớp với các định nghĩa, điều này có vẻ đáng ngạc nhiên Lý do có thê xảy ra sự không khớp là nêu không

có nguyên mẫu hàm, thì hàm sẽ được khai bảo ngầm bằng lần xuất hiện đầu tiên trong một biểu thức, chăng hạn như

Trang 30

Nếu một tên chưa được khai báo trước đó xuất hiện trong một biểu thức và được

theo sau bởi đầu ngoặc đơn bên trái, thì tên đó được khai báo theo ngữ cảnh là tên hàm, hàm đó được giả định trả về một int và không có gì được giả định về các đối số của nó Hơn nữa, nêu một khai báo hàm không bao gôm các đôi sô, như trong

điều này cũng có nghĩa là không có gì phải giả định về các lập luận của atof; tất cả

việc kiểm tra tham số đều bị tắt Ý nghĩa đặc biệt này của danh sách đối số trong nham

mục đích cho phép các chương trình C cũ hơn biên dịch với các trình biên dịch mới Nhưng sẽ là một ý tưởng tồi nếu sử dụng nó với các chương trình mới Nếu hàm này mat đôi số, khai báo chúng: nều không có đôi sô, hãy sử dụng void

Cho atof, được khai báo đúng, chúng ta có thê viết atoi (chuyên một chuỗi thành int) theo no:

Lưu ý câu trúc của các khai báo va cau lénh return Gia tri cua biéu thire trong

duoc chuyén đổi thành loại hàm trước khi trả về Do đó, giá trị của atof, một

double, được tự động chuyển đôi thành int khi nó xuất hiện trong return nay, vi hàm atoi

trả về một int Tuy nhién, thao tac nay co khả năng loại bỏ thông tin nên một số trình biên dich sẽ cảnh báo về nó

Trang 31

Bài tập 4-2 Mở rộng atof để xử lý ký hiệu khoa học dạng 123.45e-6 trong đó số dâu phẩy động có thê được theo sau bởi e hoặc E và số mũ có dấu tùy ý

4.3 Biến bên ngoài

Một chương trình C bao gồm một tập hợp các đôi tượng bên ngoài, là các biến hoặc

Ar

ham Tinh từ "bên ngoài" được sử dụng trái ngược với "nội bộ”, mô tả các đối số và biến được xác định bên trong các hàm Các biến bên ngoài được xác định bên ngoài bat ky ham nao và vì thế có khả năng sử dụng được cho nhiều hàm Bản thân các hàm luôn ở

bên ngoài, vì C không cho phép các hàm được xác định bên trong các hàm khác Theo mặc định, các biến và hàm bên ngoài có đặc tính là tất cả các tham chiếu đến chúng có cùng tên, ngay cả từ các hàm được biên dịch riêng biệt, đều là tham chiếu đến cùng một thứ (Tiêu chuẩn gọi thuộc tinh nay là liên kết ngoài.) Theo nghĩa này, các biến bên ngoài tương tự như các khối Fortran COMMON hoặc các biến ở khối ngoài cùng trong Pascal Sau này chúng ta sẽ xem cách xác định các biến và hàm bên ngoài chỉ hiển thị trong một tệp nguồn duy nhất

Bởi vì các biến bên ngoài có thể truy cập được trên toàn cầu nên chúng cung cấp một giải pháp thay thê cho các đối số của hàm và trả về các giá trị đề truyền đữ liệu giữa các hàm Bất kỳ hàm nào cũng có thê truy cập một biến ngoài bằng cách tham chiếu đến

nó theo tên, nều tên đó đã được khai báo bằng cách nào đó

Nếu một số lượng lớn các biến cần phải được chia sẻ giữa các hàm, các biến bên ngoài thuận tiện và hiệu quả hơn danh sách đối số dài Tuy nhiên, điều đã được chỉ ra ở

Chương I, lý do này nên được áp dụng một cách thận trọng, vì nó có thể có tác động xâu

đến cầu trúc chương trình và dẫn đến việc các chương trình có quá nhiều kết nói đữ liệu giữa các hàm Các biến bên ngoài cũng hữu ích vì phạm vi và thời gian tồn tại lớn hơn của chúng Các biến tự động là yếu tố bên trong của một hàm; chúng tổn tại khi chức

Trang 32

năng được nhập và biến mắt khi chức năng được bỏ lại Mặt khác, các biến bên ngoài là

vĩnh viễn, vì vậy chúng giữ lại các giá trị từ lần gọi hàm này sang lần gọi hàm tiếp theo

Do đó, nếu hai hàm phải chia sẻ một số dữ liệu, nhưng không hàm nào gọi hàm kia, thì sẽ thuận tiện nhất nếu đữ liệu dùng chung được giữ trong các biến ngoài thay vì được truyền vào và ra thông qua các đối số Chúng ta hãy xem xét vấn đề này sâu hơn bằng một ví dụ lớn hơn Vấn đề là viết một chương trình máy tính cung cấp các toán tử +, -, *

và / Vì đễ thực hiện hơn nên máy tính sẽ sử đụng ký hiệu Ba Lan ngược thay vì trung tố (Tiếng Ba Lan ngược được một số máy tính bỏ túi sử đụng và trong các ngôn ngữ như Forth va Postscript.)

Trong ký hiệu Ba Lan ngược, mỗi toán tử tuân theo toán hạng của nó; một biểu thức trung tố như

(1-2) * (4+5)

được nhập dưới dạng

12-45 +*

Dấu ngoặc đơn là không cần thiết; ký hiệu này rõ ràng miễn là chúng ta biết mỗi

toán tử mong đợi có bao nhiều toán hạng

Việc thực hiện rất đơn giản Mỗi toán hạng được đây vào một ngăn xếp; khi một toán tử xuất hiện, số lượng toán hạng thích hợp (hai toán hạng cho toán tử nhị phân) sẽ được đưa ra, toán tử được áp dụng cho chứng và kết quả được đây trở lại ngăn xếp Ví

dụ, trong ví dụ trên, I và 2 được đây lên, sau đó được thay thế bằng hiệu của chúng, -l Tiếp theo, 4 và 5 được đây lên và thay thế bằng tổng của chúng, 9 Tích của -1 và 9, bằng -9, thay thế chúng trên stack Giá trị trên cùng của stack được bật lên và in ra khi gặp phân cuôi của dòng đâu vào

Trang 33

Do do, cau tric cha chương trình là một vòng lặp thực hiện thao tác thích hợp trên mỗi toán tử và toán hạng khi nó xuât hiện:

Quá trình đây và bật một stack là bình thường, nhưng do thời gian phát hiện và phục hỏi lỗi được thêm vào, chúng đủ đài để tốt hơn nên đặt từng cái vào một hàm riêng biệt hơn là lặp lại code trong toàn bộ chương trình Và cần có một hàm riêng dé tim nap

toán tử hoặc toán hạng tiếp theo

Quyết định thiết kế chính vẫn chưa được thảo luận là stack nằm ở đâu, tức là các

thủ tục nào truy cập trực tiếp vào nó Một khả năng là giữ nó trong main và chuyền stack cũng như vị trí stack hiện tại cho các quy trình đây và bật Nhưng main không cân biết về

các biến điều khiến stack; nó chỉ thực hiện các thao tác đây và bật Vì vậy, chúng tôi đã

quyết định lưu trữ stack và thông tin liên quan của nó trong các biến bên ngoài có thể truy cập được bằng các hàm push và pop nhưng không thể truy cập được vào hàm main Việc dịch dàn ý này thành code là đủ để đàng Nếu bây giờ chúng ta coi chương trình đã ton tại trong một tệp nguồn thì nó sẽ trông như thế này:

Trang 34

Sau này chúng ta sẽ thảo luận về cách chia tệp này thành hai hoặc nhiều tệp nguồn Hàm mam là một vòng lặp chứa swItch thuộc loại toán tử hoặc toán hạng: đây là cách sử dụng switch điển hình hơn cách sử dụng được trình bày trong Phần 3.4.

Ngày đăng: 26/12/2024, 17:19

TÀI LIỆU CÙNG NGƯỜI DÙNG

TÀI LIỆU LIÊN QUAN