Thực hành Nhập môn lập trình - Trần Ngọc Anh

pdf 39 trang phuongnguyen 5180
Bạn đang xem 20 trang mẫu của tài liệu "Thực hành Nhập môn lập trình - Trần Ngọc Anh", để 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:

  • pdfthuc_hanh_nhap_mon_lap_trinh_tran_ngoc_anh.pdf

Nội dung text: Thực hành Nhập môn lập trình - Trần Ngọc Anh

  1. TRƯỜNG ĐẠI HỌC ĐÀ LẠT KHOA TOÁN - TIN HỌC Y Z TRẦN NGỌC ANH THỰC HÀNH NHẬP MÔN LẬP TRÌNH (Bài Giảng Tóm Tắt) Lưu hành nội bộ Y Đà Lạt 2008 Z
  2. LỜI MỞ ĐẦU Học phần này nhằm cung cấp cho sinh viên các kỹ năng gỡ rối, sửa lỗi trên Visual C++, bổ sung thêm một số kiến thức về chuỗi, con trỏ và cung cấp một số lượng tương đối lớn các bài tập nhằm giúp sinh viên học tốt học phần “Nhập mơn lập trình”. Nội dung gồm 6 mục: Mục 1: Hướng dẫn viết và chạy chương trình (CT) bằng VC++ 6.0. Mục 2: Hướng dẫn sửa một số lỗi / cảnh báo thường gặp. Mục 3: Kỹ thuật chạy Debug để gỡ rối CT. Mục 4: Một kỹ thuật kiểm chứng tự động CT trên các bộ dữ liệu được sinh ngẫu nhiên. Mục 5: Con trỏ. Mục 6: Tìm hiểu một số hàm xử lý chuỗi trong thư viện string.h. Bài tập. Đà lạt, 5/2008 Tác giả
  3. MỤC LỤC Mục 1: Hướng dẫn viết và chạy chương trình (CT) bằng VC++ 6.0. 1 1.1 Chạy Visual Studio C++ 6.0. 1 1.2 Mở dự án Win32 Console Application. 1 1.3 Viết chương trình (CT). 4 1.4 Chạy và kiểm tra tính đúng của CT 5 Mục 2: Hướng dẫn sửa một số lỗi / cảnh báo thường gặp 8 Mục 3: Kỹ thuật chạy Debug để gỡ rối CT. 12 3.1 Xét CT xuất ra bảng mã ASCII của 256 ký tự. 12 3.2 Xét CT dổi số sang hệ 16 15 3.3 Xét CT dổi số từ hệ 10 sang hệ b dùng hàm 18 Mục 4: Một kỹ thuật kiểm chứng tự động CT trên các bộ dữ liệu được sinh ngẫu nhiên 22 Mục 5: Con trỏ 24 5.1 Định nghĩa, khai báo, khởi tạo và sử dụng con trỏ 24 5.2 Cấp phát và thu hồi vùng nhớ bằng con trỏ 25 5.3 Tốn tử tăng / giảm trên biến con trỏ 25 5.4 Một ứng dụng con trỏ để hốn vị giá trị hai biến 26 Mục 6: Tìm hiểu một số hàm xử lý chuỗi trong thư viện string.h 27 Bài tập 28
  4. Thực hành nhập mơn lập trình Mục 1: Hướng dẫn viết và chạy chương trình (CT) bằng VC++ 6.0 Để thực hành “Nhập mơn lập trình” trên Visual C++ 6.0, sinh viên cần thực hiện các bước: 1) Chạy Visual Studio C++ 6.0. 2) Mở dự án Win32 Console Application. 3) Viết chương trình (CT). 4) Chạy và kiểm tra tính đúng của CT: a. Nếu CT cĩ lỗi cú pháp, quay lại (3) để sửa lỗi cú pháp. b. Nếu CT cho ra kết quả khơng đúng (biểu diễn dữ liệu và thuật tốn) mong muốn, quay lại (3). c. Nếu CT cho ra kết quả đúng, tiếp tục chạy thử CT trên các bộ dữ liệu khác (ứng với nhiều trường hợp khác nhau của bài tốn). 1.1: Chạy Visual C++ 6.0 1.2: Mở dự án Win32 Console Application: File \ New \ Projects \ Win32 Console Application \ A simple application: 1
  5. Thực hành nhập mơn lập trình Bước1 Bước 3: Chọn thư mục đặt Bước2 dự án Bước 4: Đặt tên dự án Bước 5 2
  6. Thực hành nhập mơn lập trình Kích đơi chuột trái Kích đơi chuột trái Kích đơi chuột trái 3
  7. Thực hành nhập mơn lập trình 1.3: Viết CT: Xét CT in ra câu chào “Chào các bạn đến với C++. 4
  8. Thực hành nhập mơn lập trình 1.4: Chạy và kiểm tra tính đúng của CT CT này cĩ lỗi cú pháp, do đĩ trong cửa sổ thơng báo cĩ xuất hiện lỗi: Thiếu dấu ; trước lệnh getch Chưa khai báo getch vì ta khơng sử dụng đến thư viện chứa nĩ (“conio.h”) 5
  9. Thực hành nhập mơn lập trình Quay về cửa sổ soạn thảo, ta sửa lại CT như sau: Thực hiện lại Buớc 4, CT sẽ in ra kết quả “Chao cac ban den voi C++” (đúng với kết quả mong muốn). Ấn Enter để trở lại Visual C++. 1.4.1 XÉT CT GIẢI PHƯƠNG TRÌNH BẬC NHẤT: Biên dịch và chạy: nhập giá trị cho a là 10, ấn Enter nhập giá trị cho b là 0, ấn Enter. 6
  10. Thực hành nhập mơn lập trình kết quả CT hiện ra là đúng, nhưng ta khơng vội. Thử chạy lại CT với a = 10 và b = 5: nghiệm của phương trình phải là –0.5 (= –5/10), nhưng kết quả lại là 0.5. Quay lại CT, sửa lại hàm tìm nghiệm: Sai: phải là –b/a Sau khi sửa lại b/a thành –b/a, ta tiếp tục biên dịch và chạy thử CT. Nhập lại a = 10 và b = 5: ta cĩ nghiệm đúng là –0.5. Nhưng rút kinh nghiệm lần trước, ta lại biên dịch và chạy CT. Lần này, ta thử với a = 0 và b = 0: 7
  11. Thực hành nhập mơn lập trình Ta nhận được kết luận “Phương trình cĩ vơ số nghiệm”, kết luận này đúng. Lại tiếp tục thử với bộ dữ liệu a = 0 và b = 5: Ta nhận được kết luận “Phương trình vơ nghiệm”, kết luận này đúng. Lại tiếp tục thử với bộ dữ liệu a = 10 và b = 20: Ta nhận được nghiệm đúng –2. Lúc này ta tạm yên tâm về tính đúng của CT. 1.4.2 TẬP TIN THI HÀNH CỦA CT: Sau khi, cĩ được CT đúng, ta vào thư mục Debug trong thư mục lưu dự án D:\CTr inh1 để lấy tập tin thi hành cĩ tên CTrinh1 để sử dụng khi muốn giải phương trình bậc 1. Chẳng hạn: Mục 2: HƯỚNG DẪN SỬA MỘT SỐ LỖI / CẢNH BÁO THƯỜNG GẶP: 8
  12. Thực hành nhập mơn lập trình Nguyên tắc sửa lỗi (lỗi / cảnh báo – error / warning (cĩ thể bỏ qua mà khơng cần sửa, tuy nhiên một số warning nếu khơng được sửa sẽ làm cho chương trình (CT) chạy khơng đúng)): ƒ Kích đơi chuột vào thơng báo lỗi để nhảy đến vị trí cĩ lỗi trong chương trình (CT). ƒ Đọc dịng chứa con trỏ hoặc dịng trên (dưới) để sửa lỗi. ƒ Nếu khơng tìm thấy lỗi thì phải dị lỗi từ đầu CT đến dịng chứa con trỏ (cĩ thể là do lỗi ở phần trên của dịng chứa con trỏ chứ khơng phải ở dịng chứa con trỏ (hoặc dịng trên nĩ)). Các lỗi ngữ nghĩa (CT vẫn thực thi nhưng kết quả sai) trình biên dịch C++ khơng phát hiện được. 1. ( expected: thiếu ‘(‘ 2. ) expected: thiếu ‘)’ 3. , expected: thiếu ‘,’ 4. : expected after private: thiếu ‘:’ sau private 5. : expected after protected: thiếu ‘:’ sau protected 6. : expected after public: thiếu ‘:’ sau public 7. < expected: thiếu dấu < 8. { expected:thiếu dấu { 9. } expected: thiếu dấu } 10. Array bounds missing ]: thiếu ‘]’ bao dãy 11. Array must have at least one element: dãy phải cĩ ít nhất một phần tử 12. Array size too large: kích cỡ dãy quá lớn 13. Body already defined for this function: nội dung hàm này đã được viết. 14. Call of nonfunction: tên được gọi khơng được khai báo như một hàm, do khai báo hàm khơng chính xác hoặc viết sai tên hàm. 15. Cannot cast from 'type1' to 'type2': khơng thể ép từ kiểu ‘type1’ đến kiểu 'type2' 16. Cannot convert 'type1' to 'type2': khơng thể chuyển đổi 'type1' thành 'type2' 17. Cannot modify a const object: khơng thể thay đổi một đối tượng hằng (const) 18. Cannot overload 'main': khơng thể định nghĩa chồng hàm main 19. Cannot use tiny or huge memory model with Windows: khơng thể sử dụng mơ hình bộ nhớ tiny hoặc huge với Windows 20. Cannot open such file or directory “xxx”: khơng thể mở file hoặc thư mục xxx 21. Cannot open “Debug\ ” for writting: khơng thể mở file Debug\ để ghi (hãy đĩng CT đã chạy trước đây để cĩ thể chạy lại CT) 22. Case outside of switch: ‘case’ bên ngồi switch 23. Case statement missing ‘:’: ‘case’ thiếu dấu ‘:’ 24. Character constant must be one or two characters long: hằng ký tự chỉ cĩ thể là một ký tự (‘a’) hoặc hai ký tự (‘\n’) 25. Compound statement missing }: thiếu dấu } cho khối lệnh (câu lệnh phức). 26. Constant expression required: dãy phải được khai báo với kích thước là hằng số (thường là do khai báo hằng (#define) khơng đúng). 27. Constant variable 'variable' must be initialized: biến cĩ kiểu const phải được khởi tạo (vì ta khơng thể gán giá trị cho biến cĩ kiểu const trong quá trình thi hành CT). 9
  13. Thực hành nhập mơn lập trình 28. Could not find a match for argument(s): các đối số khơng phù hợp (kiểm tra lại khai báo hàm và các đối số truyền vào) 29. Could not find file 'filename': khơng thể tìm file 'filename' 30. Declaration does not specify a tag or an identifier: khai báo (kiểu struct hoặc kiểu union) khơng chứa thành phần 31. Declaration is not allowed here: khơng cho phép khai báo ở đây 32. Declaration missing ‘;’: khai báo thiếu dấu ‘;’ 33. Declaration syntax error: khai báo sai lỗi cú pháp 34. Declaration terminated incorrectly: kết thúc khai báo khơng chính xác 35. Declaration was expected: khai báo được mong muốn ở đây nhưng khơng tìm thấy 36. Default argument value redeclared: giá trị của tham số mặc định bên trong hàm bị thay đổi 37. Default argument value redeclared for parameter 'parameter': giá trị của tham số (đối số) mặc định 'parameter' bên trong hàm bị thay đổi 38. Default expression may not use local variables: một biểu thức tham số (đối số) mặc định bên trong hàm khơng được phép sử dụng tham số khác 39. Default outside of switch: default bên ngồi switch 40. Default value missing: tham số theo sau một tham số mặc định phải cĩ giá trị mặc định 41. Default value missing following parameter 'parameter': thiếu giá trị mặc định cho tham số 'parameter' (vì nĩ theo sau một tham số mặc định nên phải cĩ giá trị mặc định) 42. Define directive needs an identifier: khai báo define cần cĩ một tên 43. Delete array size missing ]: thiếu ‘]’ khi hủy một dãy 44. Division by zero: chia cho 0 45. do statement must have while: do phải cĩ while 46. do-while statement missing (: do-while thiếu dấu ‘(’ 47. do-while statement missing ): do-while thiếu dấu ‘)’ 48. do-while statement missing ;: do-while thiếu dấu ‘;’ 49. Duplicate case: mỗi case trong switch phải cĩ giá trị đi kèm 50. Enum syntax error: khai báo kiểu enum sai cú pháp 51. Expression expected: một biểu thức được mong muốn ở đây nhưng ký hiệu hiện thời khơng thể bắt đầu cho một biểu thức 52. Expression of scalar type expected: mong muốn biểu thức cĩ kiểu vơ hướng. Các tốn tử !, ++, và – yêu cầu một biểu thức cĩ kiểu vơ hướng (char, short, int, long, enum, float, double, long double, pointer) 53. Expression syntax: cú pháp biểu thức 54. File name too long: tên file qúa dài 55. For statement missing ‘(‘: câu lệnh for thiếu ‘(’ 56. For statement missing ): câu lệnh for thiếu ‘)’ 57. For statement missing ;: câu lệnh for thiếu ‘)’ 58. 'function' cannot return a value: hàm khơng thể trả về giá trị (nĩ là hàm void) 59. 'function' must be declared with no parameters: hàm phải được khai báo với khơng tham số 60. 'function' must be declared with one parameter: hàm phải được khai báo với một tham số 10
  14. Thực hành nhập mơn lập trình 61. 'function' must be declared with two paraameters: hàm phải được khai báo với một tham số 62. 'function1' cannot be distinguished from 'function2': khơng thể phân biệt 'function1' với 'function2' 63. Function 'function' should have a prototype: hàm 'function' nên cĩ tiêu đề. 64. Function call missing ): thiếu dấu ‘)’ khi gọi hàm. 65. Function should return a value: chưa trả về giá trị cho hàm 66. 'identifier' cannot start a parameter declaration: 'identifier' khơng thể bắt đầu cho khai báo một tham số 67. 'identifier' is not a member of struct: 'identifier' khơng phải là thành phần của struct 68. 'identifier' is not a non-static member and can't be initialized here: 'identifier' khơng phải là một biến tĩnh và khơng thể được khởi tạo ở đây 69. 'identifier' is not a parameter: 'identifier' khơng phải là một tham số 70. Identifier expected: mong muốn một định danh 71. If statement missing (: câu lệnh if thiếu ‘(‘ 72. If statement missing ): câu lệnh if thiếu ‘)‘ 73. Illegal character 'character' (0x'value'): hằng ký tự sai 74. Illegal structure operation: tốn tử trên struct khơng đúng (chỉ cĩ thể là: ‘.’, &, =) 75. Illegal use of floating point: tốn tử trên số thực chấm động khơng đúng (chỉ cĩ thể là: SHL, SHR, AND, OR, XOR, NOT, ? :, *, ) 76. Improper use of typedef 'identifier': kiểm tra khai báo 'identifier' ở dịng typedef 77. Incorrect number format: định dạng số khơng đúng 78. Incorrect use of default: sau default khơng cĩ dấu ‘:’ 79. Invalid use of dot: sử dụng dấu ‘.’ khơng đúng, ví dụ: struct foo { int x; int y; }p = {0,0}; int main ( ) { p.x++; /* Đúng */ p. y++; /* Sai: Invalid use of dot */ return 0; } 80. Lvalue required: thành phần bên trái của lệnh gán phải là biến 81. main must have a return type of int: hàm main phải return về kiểu int 82. Misplaced break: break khơng nằm trong switch hoặc một vịng lặp 83. Misplaced continue: continue khơng nằm trong một vịng lặp 84. Misplaced else: else khơng cĩ if 85. Missing xxx before yyy: thiếu xxx trước yyy 86. Missing function header (old-style): sai tiêu đề ở phần định nghĩa hàm (cĩ thể thừa dấu ; sau tiêu đề) 87. Multiple declaration for 'identifier': trùng khai báo cho 'identifier' 88. Need an identifer to declare: cần một định danh cho khai báo 89. No : following the ?: khơng cĩ : sau ? trong cấu trúc tam phân ( ? : ) 11
  15. Thực hành nhập mơn lập trình 90. Not an allowed type: khơng cho phép kiểu này (chẳng hạn, khơng thể trả về dữ liệu kiểu mảng tĩnh cho hàm) 91. Numeric constant too large: hằng số quá lớn 92. new line in constant: thiếu dấu ” 93. operator [] missing ]: tốn tử [] thiếu ] 94. sizeof may not be applied to a function: tốn tử sizeof khơng thể áp dụng cho hàm 95. Size of 'identifier' is unknown or zero: kích thước của 'identifier' khơng biết hoặc là 0 96. Size of the type is unknown or zero: kích thước của kiểu khơng biết hoặc là 0 97. Statement missing ‘;’: thiếu dấu ‘;’ 98. Structure size too large: kích thước của struct quá lớn 99. Switch selection expression must be of integral type: biểu thức chọn của switch phải là kiểu nguyên 100. unexpected end of file: thiếu } 101. xxx undeclared identifier: thiếu khai báo xxx Mục 3: KỸ THUẬT CHẠY DEBUG ĐỂ GỠ RỐI CHUƠNG TRÌNH 3.1 Xét CT xuất ra bảng mã ASCII của 256 ký tự: Khi chạy CT, ta cĩ kết quả sai Để gỡ rối CT, ta ấn F10 để chạy CT từng bước và quan sát giá trị của các biến ở cửa sổ bên dưới: 12
  16. Thực hành nhập mơn lập trình B1) Ấn F10 B2) Ấn F10 Ta thấy, giá trị bây giờ của k là 256 mặc dù ta muốn ứng với mỗi k từ 0 đến 255 thực hiện lệnh printf (" %c %d", k, k); Điều đĩ, chứng tỏ k lặp từ 0 đến 255 mà khơng thực hiện gì. Thật vậy, ấn F10, ta cĩ kết quả của CT chỉ là con số 256 mà khơng cĩ ký tự nào được in ra Lỗi sai của CT trên là do dấu ‘;’ ở cuối vịng lặp for: CT thực hiện 256 lần lệnh ‘;’ mà khơng làm gì cả. Kết thúc vịng lặp giá trị của k là 256, CT xuất ra số 256 (dĩ nhiên khơng cĩ ký tự nào cĩ mã ASCII là 256). Sửa: Bỏ dấu ‘;’ ở cuối for ta cĩ kết quả chạy từng bước như sau 13
  17. Thực hành nhập mơn lập trình 14
  18. Thực hành nhập mơn lập trình Ấn một phím để kết thúc CT. 3.2. Xét CT đổi số sang hệ 16: Kết quả chạy CT đổi số 23 sang hệ 16 là “7>18”: Kết quả sử dụng Calculator (một ứng dụng tính tốn của Windows) là 17. Do đĩ kết 15
  19. Thực hành nhập mơn lập trình quả của CT phải là 71 (thuật tốn xuất theo thứ tự đảo ngược). Nhưng ở đây lại là “7>18”. Ta thử tìm lý do. Ấn F10, để chạy từng bước CT. Ấn F10, Ấn F10, 16
  20. Thực hành nhập mơn lập trình Kết quả hiện tại trên màn hình: Ấn F10, CT chạy đến câu lệnh printf( "%c", 'A' + du - 10); tương ứng với default. Kết quả hiện ra màn hình là “>” chính là kết quả quy đổi số dư 7 sang ký tự tương ứng ở hệ 16. Điểm sai của CT là thiếu break để ngăn CT tiến xuống default sau khi đã rơi vào case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: Sau khi dừng việc chạy từng bước CT bằng Debug \ Stop Debugging, ta thêm vào break bị thiếu trước default, kết quả đổi số 23 là 71 17
  21. Thực hành nhập mơn lập trình 3.3 Xét CT đổi số từ hệ 10 sang hệ b dùng hàm: Kết quả chạy CT đổi số 23 sang hệ 16 là 18
  22. Thực hành nhập mơn lập trình Kết quả của CT phải là 71 (thuật tốn xuất theo thứ tự đảo ngược). Ta thử tìm lý do. . Đặt điểm debug vào hàm doi_so bằng cách ấn F9 ở bên trong hàm này. Ấn F5 để chạy CT. CT sẽ dừng ở bên trong hàm doi_so. Dùng F10, ta điều khiển CT đến: Số dư lúc này là 7. Ấn F10, ta cĩ kết quả: 19
  23. Thực hành nhập mơn lập trình Tương tự 3.2, ta biết rằng hàm xuat_ky_so khơng đúng. Stop debug (Debug/ Stop debugging). . Đặt điểm debug vào hàm doi_so bằng cách ấn F9 ở bên trong hàm xuat_ky_so. Ấn F5, và ấn F10 cho đến khi CT chạy vào trong điểm debug ở hàm xuat_ky_so Ấn F10 cho đến khi 20
  24. Thực hành nhập mơn lập trình Xem giá trị số dư bằng cách ta cĩ, Kích đơi chuột vào ơ Name và đặt vào “du”: 21
  25. Thực hành nhập mơn lập trình Ta cĩ giá trị của du là 7, CT thực hiện câu lệnh “printf( "%c", du + '0');” là hợp lý. Do đĩ kết quả xuất ra màn hình là 7. Nhưng thử ấn F10 một lần nữa, ta thấy vì hàm xuat_ky_so thiếu break; sau “printf( "%c", du + '0');” (tương tự 2.2). Stop debugging, ta thêm “break” vào sau “printf( "%c", du + '0');”. Bỏ các điểm debug trong CT, bằng cách ấn F9 vào các điểm debug. Chạy lại CT, ta cĩ (kết quả đúng) Mục 4: Một kỹ thuật kiểm chứng tự động CT trên các bộ dữ liệu được sinh ngẫu nhiên Một vấn đề quan trọng trong lập trình là kiểm tra tính đúng đắn của một giải thuật hay một CT. Về mặt lý thuyết, ta cĩ thể chứng minh được tính đúng của một CT hay một 22
  26. Thực hành nhập mơn lập trình giải thuật, tuy nhiên khơng phải lúc nào cũng dễ dàng, mà phải thực hiện các biến đổi tốn học phức tạp. Về mặt thực hành, ta cần phải thử nghiệm CT trên một số lượng lớn các bộ dữ liệu thử. Các bộ dữ liệu thử cần phải được sinh tự động một cách ngẫu nhiên, vì nếu ta nhập từ bàn phím thì mất quá nhiều thời gian. Trong mục này, ta sẽ kiểm chứng thuật tốn sắp xếp tăng dần một dãy các số nguyên trên N (đủ lớn) bộ dữ liệu được sinh ngẫu nhiên. Hoạt động của CT như sau: 0. lần_thử = 0 1. Tăng lần_thử lên 1 2. Sinh ngẫu nhiên một mảng các số nguyên A. 3. Sắp xếp tăng dần A. 4. Kiểm tra A cĩ được sắp tăng dần khơng ? 5. Nếu A khơng được sắp tăng dần thì thơng báo “thuật tốn sắp xếp tăng dần dãy khơng đúng với A”; ngược lại, nếu lần_thử = N thì dừng CT (dùng kỹ thuật debug nêu trong mục 2 để dị lỗi và sửa lại thuật tốn sắp xếp); ngược lại quay lại bước 1. CT như sau: #include #include "stdlib.h" // Chứa các hàm: srand, rand #include "time.h" // Lấy thời gian hệ thống #define MAX_SO_PHAN_TU 20 #define MAX_PHAN_TU 99 // Định nghĩa kiểu mảng và khai báo các tiêu đề hàm int main(int argc, char* argv[]) { int N, hat_giong, lan_thu = 0; mang A; int nA; printf (“Xác định một số nguyên khơng âm làm hạt giống (0: hạt giống được tính theo thời gian của hệ thống) và số lần thử nghiệm: ”); scanf (“%d%d”, &hat_giong, &N); if (hat_giong > 0) srand(hat_giong); else srand( time(0) ); for(int k=1; k<=N; k++) { sinh_mang_ngau_nhien (A, nA) ; sap_xep_tang (A, nA) ; if (!tang_dan (A, nA)) { printf (“\n Thuật tốn sắp xếp tăng khơng đúng khi áp dụng vào dãy”); xuat_mang (A, nA); break; } else printf (“ %d ”, k); } 23
  27. Thực hành nhập mơn lập trình getch(); return 0; } void sap_xep_tang (mang A, int nA) { // ??? } bool tang_dan (mang A, int nA) { for (int i=1; i A[i+1]) return false; return true; } void sinh_mang_ngau_nhien (mang A, int &nA) { nA = rand () % MAX_SO_PHAN_TU + 1; for (int i=1; i<=nA; i++) A[i] = rand () % MAX_PHAN_TU + 1; } void xuat_mang (mang A, int nA) { // ??? } Mục 5: Con trỏ 1. Định nghĩa, khai báo, khởi tạo và sử dụng con trỏ Con trỏ là một trong những cơng cụ mạnh của C/C++, cho phép LTV xử lý bộ nhớ máy tính một cách trực tiếp. Con trỏ là một biến kiểu nguyên lưu giữ địa chỉ của (trỏ đến) một biến khác. Ví dụ: ta cĩ con trỏ ctro_x trỏ đến biến x 100 101 102 103 104 105 103 75 ctro_x x Cú pháp khai báo biến con trỏ: kiểu *tênBiếnConTrỏ; trong đĩ, kiểu cĩ thể là số (nguyên, thực), ký tự, struct, mảng, Sau khi khai báo, ta cần gán địa chỉ của biến mà con trỏ trỏ đến cho biến con trỏ, nếu chưa biết chính xác địa chỉ này thì ta gán trị NULL. Ví dụ: 24
  28. Thực hành nhập mơn lập trình char *ch1, *ch2; // ch1, ch2 là hai biến con trỏ trỏ đến biến kiểu char. float *gia_tri, x; // gia_tri là con trỏ trỏ đến biến kiểu float. Con trỏ chỉ cĩ tác dụng khi nĩ đang lưu trữ địa chỉ của một biến trong CT. Để lấy địa chỉ của một biến ta dùng tốn tử &, do đĩ, câu lệnh lấy địa chỉ của biến x cho vào biến con trỏ ctro_x cĩ dạng: ctro_x = &x; Khi đặt dấu * trước biến con trỏ ta sẽ cĩ được giá trị của biến mà con trỏ đang lưu giữ địa chỉ. 2. Cấp phát và thu hồi vùng nhớ bằng con trỏ Một phần bộ nhớ RAM dành cho CT khi chạy được chia thành bốn vùng: . Stack: lưu trữ các biến cục bộ. . Heap: chứa các biến được cấp phát động bằng tốn tử new. . Static: chứa các biến ngồi hoặc biến tĩnh. . Code: chứa mã CT và các hằng. Tốn tử new cấp phát vùng nhớ cho một biến động cĩ dạng: contro = new kiểuBiếnConTrỏTrỏĐến; Khi thành cơng, tốn tử new trả về địa chỉ (của ơ nhớ đầu tiên) của vùng nhớ. Nếu thất bại, tốn tử new sẽ trả về trị NULL. Ví dụ: #include int main ( ) { int bien_cuc_bo = 5; int *p_bien_cuc_bo = &bien_cuc_bo; printf (“\nTrị của biến cục bộ: %d”, bien_cuc_bo); printf (“ \nTrị của biến cục bộ truy cập bằng con trỏ: %d”, *p_bien_cuc_bo); int *pHeap = new int; if (pHeap = = NULL) printf (“\n Het bo nho Heap.”); else { printf (“\nĐịa chỉ của vùng nhớ vừa được cấp phát bằng new: %d”, pHeap); delete pHeap; } getch() ; return 0 ; } 3. Tốn tử tăng / giảm trên biến con trỏ Khi tăng / giảm biến con trỏ n đơn vị tức là tăng / giảm giá trị của nĩ với một lượng bằng kích thước của kiểu của biến mà con trỏ trỏ đến nhân với n. Ví dụ: 25
  29. Thực hành nhập mơn lập trình int x = 10333; int *ctro_x = &x; ctro_x = ctro_x + 2; printf (“\n%d”, *ctro_x); // giá trị là 10333 100 101 102 103 104 105 106 107 108 109 10333 7567 101 x ctro_x Sau khi thực hiện lệnh: ctro_x = ctro_x + 2; ta cĩ: 100 101 102 103 104 105 106 107 108 109 10333 7567 105 x ctro_x Lệnh printf (“\n%d”, *ctro_x); sẽ in ra giá trị là 7567. 4. Một ứng dụng con trỏ để hốn vị giá trị hai biến #include void hoan_vi (int *p, int *q); int main ( ) { int x = 5, y = 7; hoanvi (&x, &y); printf (“%d, %d”, x, y); Bộ nhớ CT getch(); 100 102 return 0 ; x = 5 y = 7 Bộ nhớ của hàm hoan_vi } void hoanvi (int *p, int *q) p = &x q = &y tam = *p { Bộ nhớ CT 100 102 5 int tam; 100 102 tam = *p; *p = *q *q = tam *100 = *102 *102 = 5 *p = *q; x = 7 y = 7 *q = tam; } Bộ nhớ CT 100 102 x = 7 y = 5 26
  30. Thực hành nhập mơn lập trình Mục 6: Tìm hiểu một số hàm xử lý chuỗi trong thư viện string.h STT TÊN HÀM CHỨC NĂNG VÍ DỤ char *s = "International"; Trả về độ dài của chuỗi printf("Do dai %d",strlen(s)); 1 int strlen(char s[]); s. Kết quả: Do dai 3 char dest[10]; char *src = "abcdefghi"; Sao chép nội dung strcpy(char dest[], strcpy(dest, src); 2 chuỗi src vào chuỗi char src[]); printf("%s\n", dest); dest. Kết quả: abcdefgh strncpy(char dest[], Chép n ký tự từ chuỗi char dest[4]; char src[], int n); src sang chuỗi dest. char *src = "abcdefghi"; Nếu chiều dài src s2 ”); Kết quả: Khac nhau char *s1 = “abcd”; int strncmp(char char *s2 = "abef"; s1[], char s2[], int Tương tự như strcmp(), if(strncmp(s1, s2, 2)==0) n) nhưng chỉ so sánh n ký printf("Giong nhau"); tự đầu tiên của hai else chuỗi. printf(“Khac nhau”); Kết quả: Giong nhau 27
  31. Thực hành nhập mơn lập trình char *s1 = “abcd”; char *s2 = "abCD"; Tương tự như strcmp(), if(stricmp(s1, s2)==0) int stricmp(char nhưng printf("Giong nhau"); s1[], char s2[]) khơng phân biệt hoa else thường. 8 printf(“Khac nhau”); Kết quả: Giong nhau char *s1 = “aBcd”; Tương tự như char *s2 = "Abef"; int strnicmp(char stricmp(), if(strnicmp(s1, s2, 2)==0) s1[],char s2[], int nhưng chỉ so sánh n ký printf("Giong nhau"); n); tự đầu else 9 tiên của hai chuỗi. printf(“Khac nhau”); Kết quả: Giong nhau char s[15]; Tìm lần xuất hiện đầu char *ptr, c = 'm'; tiên của strcpy(s, "Vi du tim ky tu"); ký tư c trong chuỗi s. ptr = strchr(s, c); char *strchr(char Trả về: if (ptr) s[], char c); • NULL: nếu khơng cĩ. printf("%c tai %d", c, ptr- 10 • Địa chỉ c: nếu tìm s); thấy. else printf("Khong tim thay"); Kết quả: m tai 8 Tìm sự xuất hiện đầu char *s1 = "International"; tiên của chuỗi s2 trong char *s2 ="nation”, *ptr; char *strstr(char chuỗi s1. Trả về: ptr = strstr(s1, s2); 11 s1[], char s2[]); • NULL: nếu khơng cĩ. printf("Chuoi con: %s\n", • Ngược lại: Địa chỉ bắt ptr); đầu chuỗi s2 trong s1. Kết quả: Chuoi con: national BÀI TẬP 1. Tìm lỗi của đoạn CT sau: { int *pInt; *pInt = 9; int so = 9, *pSo = &so; 2. Cho biết kết quả (lỗi, kết quả in ra màn hình, tác động, ) của từng dịng lệnh trong các đoạn CT sau: a) int n = 1, *pi = &n; 28
  32. Thực hành nhập mơn lập trình printf (“ %d, %d, %d”, n, *(&n), *pi); b) int m, x = 1, *pi; pi = &x; m = *pi; printf (“ %d”, m); int y1 = x + 1, y2 = *(&x) + 1, y3 = *pi + 1; printf((“ %d, %d, %d”, y1, y2, y3) ; c) int x = 5, *px = &x; px = 3; d) int n = 22, *p = &n; printf((“ %d ”, p); e) int n = 22, *p = &n, *q = p; delete q; printf((“ %d ”, *p); f) int *p; *p = 5; printf (“ %d ”, *p); g) int n = 22; double x = 3.1416; int *p = &n; double *q = &x; printf((“ %d ”, q – p); h) int *p = NULL; *p = 5; printf (“ %d ”,* p); i) int *p = new int; *p = 5; printf((“ %d , %d”, * p, &(*p)); j) int *p = new int; *p = 72; printf(“ %d ”,*p); int *q = new int; *q = 84; printf (“ %d ”, q); q = p; k) float x = 5, *px = new float; px = &x; l) float x = 5, *px = &x; printf (“ %f, %f, %f, %f, %d”, x, *px, *(&(*px)), *(&(*(&(*px))), &(*px)); m) char s[] = “ABCDEFGH”; char *p = &s[3]; printf (“ %c”, *p); ++ p; printf((“ %c”, *p); p += 3; printf (“ %c”, *p); p –= 6; printf((“ %c”, *p); ––p; printf((“ %c”, *p); 3. Cho định nghĩa kiểu struct ngay { int thu; chat thang[10]; int nam; }; Hãy cho biết kết quả (lỗi, kết quả in ra màn hình, tác động, ) của từng dịng lệnh trong các đoạn CT: a) ngay x = {2, “7”, 1969}; 29
  33. Thực hành nhập mơn lập trình ngay *p = &x; printf (“ %d ”, (*p).nam); printf (“ %d ”, pỈnam); printf (“ %d ”, *p); b) ngay x = {2, “7”, 1969}, *p1, ds[4]; p1 = &ds[0]; for (int i=0; i 1) 7. Nhập vào giờ, phút, giây. Kiểm tra xem giờ, phút, giây đĩ cĩ hợp lệ hay khơng, nếu hợp lệ cho biết giờ sau và trước đĩ 1 giây là bao nhiêu. Ví dụ: Nhập 01:59:59 Giờ sau đĩ 1 giây 02:00:00 Giờ trước đĩ 1 giây 01:59:58 8. In ra bảng cửu chương từ 2 đến 9. 9. Nhập số nguyên dương n (0 <= n< 1000) và in ra cách đọc của n. Ví dụ: Nhập n = 105. In ra màn hình: Mot tram le nam. 30
  34. Thực hành nhập mơn lập trình 10. Tính tiền thuê máy dịch vụ Internet và in ra màn hình kết quả với dữ liệu nhập vào là giờ bắt đầu thuê (GBD), giờ kết thúc thuê (GKT), số máy thuê (SoMay). - Điều kiện cho dữ liệu nhập: 6<=GBD<GKT<=21. Giờ là số nguyên. - Đơn giá: 2500đ cho mỗi giờ máy trước 17:30 và 3000đ cho mỗi giờ máy sau 17:30. 11. Nhập số nguyên dương n gồm 5 chữ số, kiểm tra xem các chữ số n cĩ phải là số đối xứng hay khơng. Ví dụ: Đối xứng: 13531 Khơng đối xứng: 13921 12. Nhập số nguyên dương n gồm k chữ số (0 < k ≤ 5): a. đếm xem n cĩ bao nhiêu chữ số chẵn và bao nhiêu chữ số lẻ. b. đếm xem n cĩ bao nhiêu chữ số là số nguyên tố. c. tính tổng các ước số dương của n. d. tìm ước số lẻ lớn nhất của n. e. kiểm tra xem các chữ số của n cĩ tồn lẻ hay tồn chẵn khơng. f. sắp xếp các chữ số của n theo thứ tự tăng dần. g. tìm vị trí xuất hiện của chữ số cĩ giá trị x trong n. h. kiểm tra xem các chữ số của n cĩ được sắp thứ tự khơng. i. tính giá trị trung bình các chữ số chẵn trong n. 13. Nhập 2 số a, b sao cho: số lớn nhất trong 2 số phải là một số dương và chia hết cho 7. Nếu nhập sai phải yêu cầu nhập lại cho đến khi đúng. 14. In ra màn hình tất cả các ngày (dưới dạng ngày/tháng) của năm hiện tại, in ra màn hình thời gian trong ngày (dưới dạng giờ:phút:giây). 15. Sắp xếp mảng: a. theo thứ tự tăng dần của các phần tử là số nguyên tố. b. các phần tử lẻ tăng dần. c. các phần tử chẵn giảm dần. d. các phần tử chẵn nằm bên trái theo thứ tự tăng dần cịn các phần tử lẻ bên phải theo thứ tự giảm dần. e. các phần tử âm giảm dần từ trái sang phải, phần tử dương tăng dần từ phải sang trái. 16. Xố: a. phần tử tại vị trí lẻ trong mảng. b. phần tử cĩ giá trị lớn nhất trong mảng. c. xố tất cả các phần tử cĩ giá trị nhỏ hơn X. d. xố phần tử cĩ giá trị gần X nhất. 17. Chèn phần tử cĩ giá trị X vào: a. vị trí đầu tiên của mảng. b. phía sau phần tử cĩ giá trị lớn nhất trong mảng. c. trước phần tử cĩ giá trị là số nguyên tố đầu tiên trong mảng. d. phía sau tất cả các phần tử cĩ giá trị chẵn trong mảng. 18. Tách 1 mảng các số nguyên thành 2 mảng a và b, sao cho mảng a chứa tồn số lẻ và mảng b chứa tồn số chẵn. Ví dụ: Mảng ban đầu: 1 3 8 2 7 5 9 0 10 Mảng a: 1 3 7 5 9 31
  35. Thực hành nhập mơn lập trình Mảng b: 8 2 10 19. Cho 2 mảng số nguyên a và b kích thước lần lượt là n và m. Viết chương trình nối 2 mảng trên thành mảng c theo nguyên tắc chẵn ở đầu mảng và lẻ ở cuối mảng. Ví dụ: Mảng a: 3 2 7 5 9 Mảng b: 1 8 10 4 12 6 Mảng c: 6 12 4 10 8 2 3 7 5 9 1 20. Nhập vào mảng A gồm n phần tử, trong quá trình nhập kiểm tra các phần tử nhập vào khơng được trùng, nếu trùng thơng báo và yêu cầu nhập lại. 21. Tính tổng của từng dãy con giảm trong mảng. 22. Chỉ ra số hạng lớn thứ k của mảng. Ví dụ: Mảng a: 6 3 1 10 11 18 k = 2 Kết quả: 11 23. Liệt kê các bộ 4 số a, b, c, d trong mảng các số nguyên (cĩ ít nhất 4 phần tử và đơi một khác nhau) sao cho a + b = c + d. 24. Tính trung bình cộng của các tổng các dãy tăng dần cĩ trong mảng các số nguyên. Ví dụ: 1 2 3 4 2 3 4 5 6 4 5 6 => TB = 15. 25. Tính tổng tất cả các phần tử xung quanh trên mảng các số nguyên. (Phần tử xung quanh là hai phần tử bên cạnh cộng lại bằng chính nĩ (Ví dụ: 1 3 2 Ỉ 1,2 là hai phần tử xung quanh của 3). Ví dụ: 1 3 2 5 3 9 6 Ỉ tổng 17 26. Nhập vào hai số lớn a, b nguyên ( a, b cĩ từ 20 chữ số trở lên). Tính tổng, hiệu, tích, thương của hai số trên. 27. Tính tổng các phần tử là số Amstrong (số Amstrong là số cĩ đặc điểm như sau: số cĩ k ký số, tổng của các luỹ thừa bậc k của các ký số bằng chính số đĩ. Ví dụ: 153 là số cĩ các ký số 13+53+33= 153 là một số Amstrong). 28. Tìm và xĩa tất cả các phần tử trùng với x trong mảng một chiều các số nguyên, nếu khơng tồn tại phần tử x trong mảng thì trả về -1. 29. Tìm số lẻ nhỏ nhất lớn hơn mọi số chẵn cĩ trong mảng, giá trị chẵn nhỏ nhất nhỏ hơn mọi giá trị lẻ trong mảng các số nguyên. 30. Tìm mảng con tăng dần cĩ tổng lớn nhất trong mảng một chiều. 31. Tách 1 mảng các số nguyên thành 2 mảng a và b, sao cho kết quả thu được là: • Mảng a chứa tồn số lẻ tăng dần. • Mảng b chứa tồn số chẵn giảm dần. (Khơng dùng sắp xếp) Hướng dẫn: Tìm vị trí chèn thích hợp khi trích phần tử từ mảng ban đầu. Ví dụ: Mảng ban đầu: 9 3 8 2 7 5 1 0 10 Mảng a: 1 3 5 7 9 Mảng b: 10 8 2 32. In ra tam giác Pascal. 32
  36. Thực hành nhập mơn lập trình 33. Sinh ngẫu nhiên mảng các số nguyên gồm 10.000 phần tử, mỗi phần tử cĩ giá trị từ 0 đến 32.000 và xây dựng hàm thống kê số lần xuất hiện các phần tử trong mảng, sau đĩ cho biết phần tử nào xuất hiện nhiều lần nhất. Ví dụ: Mảng: 5 6 11 4 4 5 4 5 xuất hiện 2 lần 6 xuất hiện 1 lần 11 xuất hiện 1 lần 4 xuất hiện 3 lần 34. Cho mảng A cĩ n phần tử. Nhập vào số nguyên k ( k ≥ 0), dịch phải xoay vịng mảng A k lần. Ví dụ: Mảng A: 5 7 2 3 1 9 Nhập k = 2 Dịch phải xoay vịng mảng A: 1 9 5 7 2 3 35. Viết chương trình tìm kiếm tên trong chuỗi họ tên. Nếu cĩ thì xuất ra là tên này đã nhập đúng, ngược lại thơng báo là đã nhập sai. 36. Viết chương đảo vị trí của từ đầu và từ cuối. Ví dụ: nhập “bo an co” xuất ra “co an bo” 37. Nhập một chuỗi bất kỳ, sau đĩ hỏi người dùng cần tách bắt đầu từ đâu trong chuỗi trở về sau. Ví dụ: Nhập chuỗi S1: “trường Đại học Đà Lạt – Khoa Tốn - Tin”. Người nhập muốn tách bắt đầu từ chữ “Khoa” thì sẽ xuất ra chuỗi “Khoa Tốn - Tin”. 38. Kiểm tra xem trong chuỗi cĩ ký tự số hay khơng nếu cĩ tách ra thành một mảng số riêng. 39. Đảo ngược thứ tự các từ cĩ trong chuỗi Ví dụ: Nhập Truong CD CNTT TpHCM Xuất ra màn hình là: TpHCM CNTT CD Truong 40. Nhập một ma trận: a. in ra những phần tử cĩ ký số tận cùng là 5. b. in ra các phần tử nằm trên 2 đường chéo. c. in ra các phần tử nằm phía trên / dưới đường chéo phụ của ma trận vuơng các số nguyên. d. in ra các phần tử nằm phía trên / dưới đường chéo chính của ma trận vuơng các số nguyên. e. tính tổng các phần tử trên cùng một dịng, cùng một cột, các phần tử chẵn, số nguyên tố, nằm trên đường chéo chính của ma trận vuơng. f. tính tổng các giá trị lớn nhất trên mỗi dịng, cột. g. tính giá trị trung bình của các phần tử nhỏ nhất trên mỗi cột. 41. Khởi tạo ma trận A chứa các số thực ngẫu nhiên cĩ kích thước m× n và sắp xếp A: a. theo thứ tự tăng dần từ trên xuống dưới và từ trái qua phải. b. theo thứ tự giảm dần từ trên xuống dưới và từ trái sang phải. c. các dịng theo thứ tự tăng dần, các cột theo thứ tự giảm dần. 42. Nhập một ma trận A: a. Hốn vị 2 dịng / cột của A. b. Bỏ dịng i và cột j của A. 33
  37. Thực hành nhập mơn lập trình c. Giả sử A là ma trận vuơng cĩ kích thước n x n. Tách A thành 4 ma trận con A1,1, A1,2, A2,1, A2,2, sao cho: A1,1 A1,2 A = A2,1 A2,2 d. phát sinh ma trận B là ma trận lật ngược của ma trận A. Ví dụ: e. phát sinh ma trận B sao cho các phần tử của B là trung bình cộng các phần tử trong hình vuơng 3x3 tâm tại (i, j). Ví dụ: 43. Nhập một ma trận A, in ra tất cả các đường chéo phụ / chính. Ví dụ: các đường chéo phụ 44. Cho một mảng các phân số (PHANSO) gồm n phần tử (n≤50). Hãy viết chương trình nhập và xuất danh sách các phân số sau đĩ tìm phân số cĩ giá trị lớn nhất, tổng và tích các phân số, nghịch đảo giá trị các phân số trong mảng và sắp xếp danh sách các phân số theo thứ tự giảm dần. 45. Tổ chức dữ liệu quản lí danh mục các bộ phim VIDEO, các thơng tin liên quan đến bộ phim này như sau: - Tên phim (tựa phim). - Thể loại (3 loại : hình sự, tình cảm, hài). - Tên đạo diễn. - Tên điễn viên nam chính. - Tên diễn viên nữ chính. - Năm sản xuất. - Hãng sản xuất Viết chương trình thực hiện những cơng việc sau: • Nhập vào bộ phim mới cùng với các thơng tin liên quan đến bộ phim này. 34
  38. Thực hành nhập mơn lập trình • Nhập một thể loại. In ra danh sách các bộ phim thuộc thể loại này. • Nhập một tên nam diễn viên. In ra các bộ phim cĩ diễn viên này đĩng. • Nhập tên đạo diễn. In ra danh sách các bộ phim do đạo diễn này dàn dựng. 46. Một cửa hàng cần quản lý các mặt hàng, thơng tin một mặt hàng bao gồm: - Mã hàng. - Tên mặt hàng. - Số lượng. - Đơn giá. - Số lượng tồn. - Thời gian bảo hành (tính theo đơn vị tháng). Viết chương trình thực hiện những cơng việc sau: • Hãy nhập vào một danh sách các mặt hàng. • Tìm mặt hàng cĩ số lượng tồn nhiều nhất. • Tìm mặt hàng cĩ số lượng tồn ít nhất. • Tìm mặt hàng cĩ giá tiền cao nhất. • In ra những mặt hàng cĩ thời gian bảo hành lớn hơn 12 tháng. • Sắp xếp các mặt hàng theo thứ tự tăng dần của số lượng tồn. 47. Viết chương trình quản lý vé tàu, thơng tin một vé tàu như sau : - Ngày giờ khởi hành, ngày giờ đến. - Ga đi, ga đến. - Loại tàu, loại chỗ ngồi ( ngồi, nằm, cứng, mềm). - Số toa, số ghế. Viết chương trình thực hiện những cơng việc sau: • nhập vào danh sách các vé tàu. • In danh sách các vé tàu cĩ ga đến là Huế. • In danh sách các vé tàu cĩ ga đến là Hà Nội và đi ngày 8/6/2005. • Đếm xem cĩ bao nhiêu khách đi tàu loại chỗ ngồi là nằm cứng. 48. Tính tiền điện hàng tháng của các hộ gia đình, thơng tin các khách hàng như sau: - Kỳ thu, từ ngày đến ngày. - Tên khách hàng, mã khách hàng. - Địa chỉ. - Điện năng tiêu thụ (Kwh). Viết chương trình thực hiện những cơng việc sau: • Nhập vào danh sách các khách hàng. • Xuất danh sách hố đơn theo thứ tự tăng dần của điện năng tiêu thụ. • Tính tiền điện của các khách hàng theo quy định sau. - 100 kw đầu tiên là 550 đ / kw - 50 kw tiếp theo là 900 đ / kw - 50 kw tiếp theo là 1210 đ / kw - Thuế 10 % trên tổng số tiền phải trả • Tính tổng số tiền thu được của các khách hàng. 35
  39. TÀI LIỆU THAM KHẢO [1] A. B. Downey, How to think like a computer scientist, C++ Version, First Edition, 1999. [2] H. M. Deitel, P. J. Deitel, C++ How to Program, Fifth Edition, Prentice Hall, 2005. [3] S. R. Davis, C++ for Dummies 5th Edition, Willey Publishing, Inc, 2004. [4] Trần Minh Thái, Giáo trình bài tập kỹ thuật lập trình C, Trường CĐ Cơng Nghệ Thơng Tin Tp. Hồ Chí Minh.