1. Trang chủ
  2. » Cao đẳng - Đại học

Giáo trình Lập trình căn bản (ĐH SPKT Vĩnh Long) - Nguồn: Internet

139 27 1

Đ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

Các giá trị này cần cách nhau bởi ít nhất một dấu trắng (ta qui ước gọi dấu trắng là một trong 3 loại dấu được nhập bởi các phím sau: phím spacebar (dấu cách), phím tab (dấu tab) hoặc [r]

(1)

TRƯỜNG ĐẠI HỌC SƯ PHẠM KỸ THUẬT VĨNH LONG KHOA CÔNG NGHỆ THÔNG TIN

Giáo trình

Dành cho bậc Cao Đẳng Kỹ Thuật

BIÊN SOẠN

(2)

TRƯỜNG ĐẠI HỌC SƯ PHẠM KỸ THUẬT VĨNH LONG KHOA CƠNG NGHỆ THƠNG TIN

Giáo trình

Dành cho bậc Cao Đẳng Kỹ Thuật

Mã số học phần: TH3202 Số tín chỉ: 03

BIÊN SOẠN

(3)

- -

Để đáp ứng nhu cầu học tập nghiên cứu bạn sinh viên, đặc biệt sinh viên chuyên ngành Công nghệ thông tin, Khoa Công nghệ thông tin - Trường Đại học Sư phạm Kỹ thuật Vĩnh Long tiến hành biên soạn giáo trình, giảng

chương trình học Giáo trình Lập trình biên soạn dựa

quyển " C++ Program Design – An Introduction to Programming and Object-Oriented Design " James P Cohoon and Jack W.Davidson Giáo trình

được biên soạn dựa kinh nghiệm giảng dạy nhiều năm mơn Lập trình

của giáo viên khoa chúng tơi Ngồi tham khảo nhiều tài liệu trường đại học nước

Tài liệu biên soạn dựa theo đề cương chi tiết mơn học Lập trình Khoa Công nghệ thông tin Trường Đại học Sư phạm Kỹ thuật Vĩnh Long dùng cho sinh viên chuyên ngành Công nghệ thông tin bao gồm chương:

Chương 1: Tổng quan ngôn ngữ C++ Chương 2: Các cấu trúc điều khiển Chương 3: Dữ liệu kiểu mảng Chương 4: Dữ liệu kiểu chuỗi Chương 5: Con trỏ hàm Chương 6: Dữ liệu kiểu cấu trúc

Mục tiêu nhằm giúp bạn sinh viên chuyên ngành có tài liệu cô đọng dùng làm tài liệu học tập nghiên cứu chúng tơi khơng loại trừ tồn đối tượng khác tham khảo Chúng nghĩ bạn sinh viên thuộc chuyên ngành khác người quan tâm đến lập trình tìm điều bổ ích giáo trình

Mặc dù cố gắng trình biên soạn chắn giáo trình cịn nhiều thiếu sót hạn chế Rất mong nhận đóng góp ý kiến quý báu sinh viên bạn đọc để giáo trình ngày hoàn thiện

Chân thành cảm ơn!

(4)

CHƯƠNG 1: TỔNG QUAN VỀ NGÔN NGỮ C++

- -

1.1 KHÁI NIỆM VỀ LẬP TRÌNH 1.1.1 Giới thiệu chung

Máy tính số cơng cụ để giải hàng loạt toán lớn Một lời giải cho tốn gọi giải thuật hay thuật tốn (algorithm); mơ tả chuỗi bước cần thực để giải tốn

Ví dụ: Bài tốn xếp danh sách số theo thứ tự tăng dần

Giải thuật toán là: Giả sử danh sách cho list1; ta tạo danh sách

rỗng list2, để lưu danh sách xếp Lặp lặp lại công việc, tìm số nhỏ

list1, xóa khỏi list1 thêm vào phần tử danh sách list2, list1

là rỗng

Giải thuật diễn giải thuật ngữ trừu tượng mang tính chất dễ hiểu Ngơn ngữ thật hiểu máy tính ngơn ngữ máy Chương trình diễn đạt ngơn ngữ máy gọi thực thi Một chương trình viết ngôn ngữ trước hết cần dịch sang ngơn ngữ máy để máy tính hiểu thực thi

Ngơn ngữ máy khó hiểu lập trình viên họ khơng thể sử dụng trực tiếp ngơn ngữ máy để viết chương trình Một trừu tượng khác ngơn ngữ assembly Nó cung cấp tên dễ nhớ cho lệnh ký hiệu dễ hiểu cho liệu Bộ dịch gọi assembler chuyển ngôn ngữ assembly sang ngôn ngữ máy Ngay ngơn ngữ assembly khó sử dụng Những ngôn ngữ cấp cao như: C, C++, Pascal, … cung cấp ký hiệu thuận tiện nhiều cho việc lập trình thi hành giải thuật

Các ngôn ngữ cấp cao giúp cho lập trình viên khơng phải nghĩ nhiều thuật ngữ cấp thấp giúp họ tập trung vào giải thuật Trình biên dịch (compiler) đảm nhiệm việc dịch chương trình viết ngơn ngữ cấp cao sang ngôn ngữ assembly Mã assembly tạo trình biên dịch sau tập hợp lại chương trình thực thi

1.1.2 Định nghĩa

Lập trình kỹ thuật tổ chức liệu xây dựng quy trình xử lý cho máy tính làm việc thơng qua ngơn ngữ lập trình chẳng hạn như: C, C++, Pascal, …

- Tổ chức liệu: xếp thông tin nhằm phục vụ cho yêu cầu

- Quy trình xử lý: bao gồm thị để thực công việc như: tạo thơng tin ban đầu, tính tốn, chép, di chuyển, tìm kiếm, in kết quả, …

1.1.3 Giải thuật (Algorithm)

(5)

Giải thuật (thuật toán) tập hợp có thứ tự bước tiến hành công việc nhằm đạt kết mong muốn

Ví dụ: Để viết chương trình giải phương trình bậc (ax2 + bx + c = 0) ta cần phải tìm bước để thực cơng việc này, giải thuật:

Bước 1: Nhập hệ số a, b c Bước 2: Tính  = b2 – 4ac Bước 3: Xét dấu 

Nếu  < phương trình vơ nghiệm

Ngược lại,  = phương trình có nghiệm kép x1 = x2 =

a b

2

 ngược lại ( > 0) phương trình có nghiệm phân biệt:

x1 =

a b

2  

 ; x =

a b

2

   1.1.4 Đặc tính giải thuật

- Phải kết thúc sau số bước hữu hạn

- Các bước giải thuật phải máy chấp nhận thực - Xét hết tất trường hợp xảy

- Áp dụng cho tất toán loại (cùng dạng) 1.1.5 Các lưu ý

- Một tốn có nhiều giải thuật khác

- Một giải thuật gọi tốt có tính chất sau: + Đơn giản, dễ hiểu

+ Tiết kiệm vùng nhớ

+ Thời gian thực nhanh 1.1.6 Các công cụ thể giải thuật

Để thể giải thuật ta dùng nhiều cơng cụ khác nhau, có cơng cụ dùng nhiều ngôn ngữ giả lưu đồ

1.1.6.1 Ngơn ngữ giả

Ta sử dụng từ ngữ, ký hiệu cho ngắn gọn, dễ hiểu có đánh số thứ tự bước thực

Ví dụ: Giải thuật giải phương trình bậc thể ngơn ngữ giả 1.1.6.2 Lưu đồ (Flow chart)

Ta sử dụng khối theo qui định để thể giải thuật, khối dùng là:

(6)

: Thi hành (Thực hiện)

: Lựa chọn (Điều kiện)

: Chương trình : Tập hợp tập tin liệu : Các ghi chú, giải thích : Nối

: Đường

Ví dụ: Giải thuật giải phương trình bậc thể lưu đồ sau:

1.2 CÁC YẾU TỐ CƠ BẢN

Một ngơn ngữ lập trình (NNLT) cấp cao cho phép người sử dụng (NSD) biểu diễn ý tưởng để giải vấn đề, tốn cách diễn đạt gần với ngôn ngữ thông thường thay phải diễn đạt theo ngơn ngữ máy (dãy ký hiệu 0, 1) Hiển nhiên, ý tưởng NSD muốn trình bày phải viết theo cấu trúc chặt chẽ thường gọi giải thuật hay thuật tốn theo qui tắc ngơn ngữ gọi cú pháp văn phạm

Đ

Đ S

S Bắt đầu

Nhập a, b, c

 <

 =

Xuất PTVN

Xuất x = -b/(2.a)

Kết thúc  = b2 – 4.a.c

(7)

1.2.1 Bảng ký tự C++

Dưới bảng ký tự dùng để tạo nên câu lệnh ngôn ngữ C++:

- Các chữ La tinh (viết thường viết hoa): a z A Z Cùng chữ viết thường phân biệt với viết hoa Ví dụ chữ 'a' khác với 'A'

- Dấu gạch dưới: _

- Các chữ số thập phân: 0, 1, 2, ,

- Các ký hiệu toán học: +, -, *, /, % , &, ||, !, >, <, = - Các ký hiệu đặc biệt khác: , ;: [ ], {}, #, dấu cách, 1.2.2 Từ khóa

Một từ khoá từ qui định trước NNLT với ý nghĩa cố định, thường dùng để loại liệu kết hợp thành câu lệnh NSD tạo từ để đối tượng khơng phép trùng với từ khóa Dưới vài từ khoá thường gặp, ý nghĩa từ trình bày dần đề mục liên quan: asm, break, case, char, continue, default, do, double, else, extern, float, for, goto, if, int, long, register, return, short, sizeof, static, struct, switch, typedef, union, unsigned, while Một đặc trưng cần nhớ C++ từ khóa ln luôn viết chữ thường

1.2.3 Tên gọi

Để phân biệt đối tượng với chúng cần có tên gọi Hầu hết đối tượng viết chương trình thuộc dạng, dạng có sẵn ngơn ngữ (chẳng hạn từ khoá, tên hàm chuẩn, ), dạng lại NSD tạo dùng để đặt tên cho hằng, biến, kiểu, hàm,

Các tên gọi NSD tự đặt phải tuân theo số qui tắc sau:

- Là dãy ký tự liên tiếp (không chứa dấu cách ký hiệu) phải bắt đầu chữ dấu gạch

- Phân biệt ký tự in hoa thường - Khơng trùng với từ khóa

- Số lượng ký tự dùng để phân biệt tên gọi tùy ý

Ví dụ:

Các tên gọi sau (được phép): i, i1, j, tinhoc, tin_hoc, luu_luong Các tên gọi sau sai (không phép): 1i, tin hoc, luu-luong

Các tên gọi sau khác nhau: ha_noi, Ha_noi, HA_Noi, HA_NOI 1.2.4 Chú thích chương trình

(8)

chương trình hay chương trình Một thích ghi nhiệm vụ, mục đích, cách thức thành phần thích biến, hằng, hàm công dụng đoạn lệnh, Các thích làm cho chương trình dễ hiểu dễ bảo trì, sửa chữa sau

Có cách báo cho chương trình biết đoạn thích:

- Nếu thích đoạn ký tự liên tiếp (trong hàng nhiều hàng) ta đặt đoạn thích cặp dấu đóng mở thích /* (mở) */ (đóng) - Nếu thích vị trí hết hàng, ta đặt dấu // vị trí Như // sử dụng cho thích hàng

Như nói trên, vai trị đoạn thích làm cho chương trình dễ hiểu người đọc, máy đoạn thích bỏ qua Lợi dụng đặc điểm thích để tạm thời bỏ qua đoạn lệnh chương trình (nhưng khơng xố hẳn để khỏi phải gõ lại cần dùng đến) ta đặt dấu thích bao quanh đoạn lệnh (ví dụ chạy thử chương trình, gỡ lỗi, ), cần sử dụng lại ta bỏ dấu thích

 Chú ý: Cặp dấu thích /* */ khơng phép viết lồng 1.2.5 Cấu trúc chương trình C++

Một chương trình C++ đặt nhiều file văn khác Mỗi file văn chứa số phần chương trình Với chương trình đơn giản ngắn thường cần đặt chúng file

Một chương trình gồm nhiều hàm, hàm phụ trách cơng việc khác chương trình Đặc biệt hàm có hàm có tên hàm main() Khi chạy chương trình, câu lệnh hàm main() thực Trong hàm main() có câu lệnh gọi đến hàm khác cần thiết, hàm chạy lại gọi đến hàm khác viết chương trình (trừ việc gọi quay lại hàm main()) Sau chạy đến lệnh cuối hàm main() chương trình kết thúc

Thơng thường chương trình gồm có nội dung sau:

- Phần khai báo tệp nguyên mẫu: Khai báo tên tệp chứa thành phần có sẵn (như chuẩn, kiểu chuẩn hàm chuẩn) mà NSD dùng chương trình

- Phần khai báo kiểu liệu, biến, hằng : Do NSD định nghĩa dùng chung tồn chương trình

- Danh sách hàm chương trình: Do NSD viết bao gồm hàm main()

Ví dụ 1: Viết chương trình nhập vào số tuổi bạn (t) in hình hàng chữ: “Bây bạn t tuổi.”

(9)

using namespace std; main()

{

int t;

cout << "Nhap vao so tuoi cua ban : "; cin >> t;

cout << "Bay gio ban da "<<t<<" tuoi "<<endl; system("PAUSE");

}

Hai hàng chương trình khai báo tiền xử lý hai tệp nguyên mẫu cstdlib iostream Đây khai báo bắt buộc chương trình có sử dụng phương thức chuẩn “cout <<” (in hình) “cin>>” (nhập liệu từ bàn

phím), phương thức khai báo định nghĩa sẵn iostream

Không riêng hàm main(), hàm khác phải bắt đầu tập hợp câu lệnh dấu { kết thúc dấu } Tập lệnh bên cặp dấu gọi khối lệnh Khối lệnh cú pháp cần thiết câu lệnh có cấu trúc ta thấy chương

Ta sử dụng cách thức nhập xuất ngôn ngữ C cách dùng phương thức scanf printf Ví dụ viết lại sau:

#include <stdio.h> #include <conio.h> main()

{

int t;

printf("Nhap vao so tuoi cua ban : "); scanf("%d",&t);

printf("Bay gio ban da %d tuoi.\n",t); getch();

}

1.3 CÁC BƯỚC ĐỂ TẠO VÀ THỰC HIỆN MỘT CHƯƠNG TRÌNH 1.3.1 Qui trình viết thực chương trình

Trước viết chạy chương trình thơng thường cần:

a Xác định yêu cầu chương trình Nghĩa xác định liệu đầu vào (input) cung

(10)

bậc dạng: ax2 + bx + c = 0, cần báo cho chương trình biết liệu đầu vào a, b, c đầu nghiệm x1 x2 phương trình Kiểu a, b, c, x1, x2 số thực

b Xác định giải thuật

c Cụ thể hóa khai báo kiểu thuật toán thành dãy lệnh. Tức viết thành chương trình thơng thường giấy, sau bắt đầu soạn thảo vào máy Quá trình gọi soạn thảo chương trình nguồn

d Dịch chương trình nguồn để tìm sửa lỗi gọi lỗi cú pháp

e Chạy chương trình, kiểm tra kết in hình. Nếu sai, sửa lại chương trình, dịch chạy lại để kiểm tra Quá trình thực lặp lặp lại chương trình chạy tốt theo yêu cầu đề NSD

1.3.2 Soạn thảo tệp chương trình nguồn

Soạn thảo chương trình nguồn cơng việc gõ nội dung chương trình (đã viết giấy) vào máy Có thể soạn chương trình nguồn soạn thảo (editor) khác phải chạy mơi trường tích hợp C++ (Dev-C++, Borland C++, Turbo C) Mục đích soạn thảo tạo văn chương trình đưa vào nhớ máy Văn chương trình cần trình bày rõ ràng, dễ hiểu Các câu lệnh cần gióng thẳng cột theo cấu trúc lệnh (các lệnh chứa lệnh cấu trúc trình bày thụt vào so với điểm bắt đầu lệnh) Các thích nên ghi ngắn gọn, rõ nghĩa phù hợp

1.3.3 Dịch chương trình

(11)

1.3.4 Thực thi chương trình

Sau sửa hết lỗi chương trình ta cho chương trình thực thi (vào menu Execute chọn Run ấn tổ hợp phím Ctrl-F10), chương trình chưa dịch sang mã máy, máy tự động dịch lại trước chạy Kết chương trình cửa sổ kết để NSD kiểm tra

Nếu kết chưa mong muốn, quay lại chương trình nguồn để chỉnh sửa chạy lại chương trình để kiểm tra kết Quá trình lặp lại chương trình chạy yêu cầu đề Khi chương trình chạy, cửa sổ kết tạm thời che khuất cửa sổ soạn thảo Sau kết thúc chạy chương trình cửa sổ soạn thảo tự động trở lại che khuất cửa sổ kết

1.4 NHẬP/XUẤT TRONG C++

Trong phần làm quen số lệnh đơn giản cho phép NSD nhập liệu vào từ bàn phím xuất kết hình

1.4.1 Nhập liệu từ bàn phím

Để nhập liệu vào cho biến có tên bien_1, bien_2, bien_3 sử dụng câu lệnh:

cin >> bien _1; cin >> bien _2; cin >> bien _3; hoặc:

cin >> bien _1 >> bien _2 >> bien _3;

(12)

Khi chạy chương trình gặp câu lệnh chương trình "tạm dừng" để chờ NSD nhập liệu vào cho biến Sau NSD nhập xong liệu, chương trình tiếp tục chạy từ câu lệnh sau câu lệnh

Cách thức nhập liệu NSD phụ thuộc vào loại giá trị biến cần nhập mà ta gọi kiểu, ví dụ nhập số có cách thức khác với nhập chuỗi ký tự Giả sử cần nhập độ dài hai cạnh hình chữ nhật, cạnh dài qui ước tên biến cdvà chiều rộng qui ước tên biến cr Câu lệnh nhập sau:

cin >> cd >> cr ;

Khi máy dừng chờ nhập liệu NSD gõ giá trị cụ thể chiều dài, rộng theo thứ tự câu lệnh Các giá trị cần cách dấu trắng (ta qui ước gọi dấu trắng loại dấu nhập phím sau: phím spacebar (dấu cách), phím tab (dấu tab) phím Enter (dấu xuống hàng)) Các giá trị NSD nhập vào hiển thị hình để NSD dễ theo dõi

Ví dụ: Nếu NSD nhập vào 23 11  chương trình gán giá trị 23 cho biến cd 11 cho biến cr

 Chú ý: Giả sử NSD nhập 23 11  (khơng có dấu cách 23 11) chương

trình xem 23 11 giá trị gán cho cd Máy tạm dừng chờ NSD nhập tiếp giá trị cho biến cr

1.4.2 Xuất liệu hình

Để xuất/in giá trị biểu thức hình ta dùng câu lệnh sau: cout << bt_1;

cout << bt_2; cout << bt_3; hoặc:

cout << bt_1 << bt_2 << bt_3;

Cũng giống câu lệnh nhập mở rộng lệnh xuất/in với nhiều biểu thức Câu lệnh cho phép in giá trị biểu thức bt_1, bt_2, bt_3 Các giá trị tên biến kết hợp tính tốn biến

Ví dụ: Để in câu "Chiều dài " số 23 chữ " mét", ta sử dụng lệnh sau đây:

cout << "Chiều dài " ; cout << 23 ;

cout << " mét";

hoặc lệnh:

cout << "Chiều dài 23 mét" ;

(13)

cin >> cd trước đó) ta cần biết giá trị sử dụng câu lệnh in hình

cout << "Chiều dài " << cd << " mét" ;

Khi hình hàng chữ: "Chiều dài 23 mét" Như trường hợp ta phải dùng đến ba lần dấu phép tốn << khơng phải câu lệnh Ngoài phụ thuộc vào giá trị lưu biến cd, chương trình in số chiều dài thích hợp không in cố định thành "Chiều dài 23 mét" Ví dụ cd nhập 15 lệnh in câu "Chiều dài 15 mét"

Một giá trị cần in không biến cd, cr, mà cịn biểu thức, điều cho phép ta dễ dàng yêu cầu máy xuất diện tích chu vi hình chữ nhật biết cd cr câu lệnh sau:

cout << "Dien tich = " << cd * cr ; cout << "Chu vi = " << * (cd + cr) ; gộp tất thành câu lệnh:

cout << "Dien tich = " << cd * cr << ‘\n’ << " Chu vi = " << * (cd + cr) ;

Ở có ký tự đặc biệt: ký tự '\n' ký hiệu cho ký tự xuống hàng (ta sử dụng cout<<endl), gặp ký tự chương trình in phần đầu hàng Do kết câu lệnh hàng sau hình:

Dien tich = 253 Chu vi = 68

Ở 253 68 giá trị mà máy tính từ biểu thức cd * cr

2 * (cd + cr) câu lệnh in

 Chú ý: Để sử dụng câu lệnh nhập xuất phần này, đầu chương trình phải có

hàng khai báo

#include <cstdlib> #include <iostream> using namespace std;

Thông thường ta hay sử dụng lệnh in để in câu thông báo nhắc NSD nhập liệu trước có câu lệnh nhập Khi hình hàng thơng báo tạm dừng chờ liệu nhập vào từ bàn phím Nhờ vào thơng báo NSD biết phải nhập liệu, nhập nội dung nào,

Ví dụ:

cout << "Hay nhap chieu dai: "; cin >> cd;

(14)

Khi máy in hàng thơng báo "Hay nhap chieu dai: " chờ sau NSD nhập xong 23  , máy thực câu lệnh tức in hàng thông báo "Hay nhap chieu rong: " chờ đến NSD nhập xong 11  chương trình tiếp tục thực câu lệnh

Ví dụ 2: Từ thảo luận ta viết cách đầy đủ chương trình tính diện tích chu vi hình chữ nhật Để chương trình tính với giá trị khác chiều dài rộng ta cần lưu giá trị vào biến chẳng hạn cd cr

#include <cstdlib> #include <iostream> using namespace std; main()

{

float cd, cr ;

cout << "Hay nhap chieu dai: " ; cin >> cd ;

cout << "Hay nhap chieu rong: " ; cin >> cr ;

cout << "Dien tich = " << cd * cr << '\n' ; cout << "Chu vi = " << * (cd + cr) << '\n'; system("PAUSE");

}

Khi chạy đến câu lệnh nhập, chương trình dừng để chờ nhận chiều dài chiều rộng, NSD nhập giá trị cụ thể, chương trình tiếp tục thực in kết Thông qua câu lệnh nhập liệu biến cd, cr NSD u cầu chương trình cho kết hình chữ nhật khơng trường hợp hình có chiều dài 23 chiều rộng 11 ví dụ cụ thể

1.4.3 Định dạng thông tin cần in hình

Một số định dạng đơn giản trình bày trước Các định dạng chi tiết phức tạp trình bày phần sau giáo trình Để sử dụng định dạng cần khai báo file nguyên mẫu <iomanip.h> đầu chương trình thị #include <iomanip.h>

- endl: Tương đương với ký tự xuống hàng '\n'

(15)

- setprecision(n): Chỉ định số chữ số thể n Số làm tròn trước in - setiosflags(ios::showpoint): Phương thức setprecision có tác dụng hàng in Để cố định giá trị đặt cho hàng in (cho đến đặt lại giá trị mới) ta sử dụng phương thức setiosflags(ios::showpoint)

Ví dụ 3: Viết chương trình in có định dạng mức chi tiêu sinh viên #include <cstdlib>

#include <iostream> #include <iomanip.h>

#include <conio.h> // De su dung ham getch() using namespace std;

main() {

cout << "=======" << "CHI TIEU" << "=======" << endl ; cout<<endl;

cout << setiosflags(ios::showpoint) << setprecision(8) ; cout << "Sach vo" << setw(15) << 123.456 << endl; cout << "Thuc an" << setw(15) << 2453.6 << endl; cout << "Quan ao" << setw(15) << 3200.0 << endl; cout <<endl;

cout << "======================" << endl ; getch();

}

(16)

 Chú ý: Toán tử nhập >> chủ yếu làm việc với liệu kiểu số Để nhập ký tự chuỗi (chuỗi) ký tự, C++ cung cấp phương thức (hàm) sau:

- cin.get(c): Cho phép nhập ký tự vào biến ký tự c

- cin.getline(s, n): Cho phép nhập tối đa n-1 ký tự vào chuỗi s

Các hàm thực lấy ký tự lại nhớ đệm (của lần nhập trước) để gán cho c s Do toán tử cin >> x để lại ký tự xuống hàng đệm nên ký tự làm trôi lệnh sau cin.get(c), cin.getline(s,n) (máy khơng dừng để nhập cho c s)

Vì trước sử dụng phương thức cin.get(c) cin.getline(s, n) ta nên sử dụng phương thức cin.ignore(1) để lấy ký tự xuống hàng cịn sót lại đệm

- gets(st): cho phép nhập vào chuỗi ký tự tùy ý cho biến st

Ví dụ 4: Viết chương trình nhập giá trị cho biến kiểu số nguyên, ký tự, số thực chuỗi Sau in kết giá trị biến

#include <cstdlib> #include <iostream> #include <conio.h> using namespace std; main()

{

int x; char c; float y; char st[20];

cout << "Nhap so nguyen x = "; cin >> x;

cin.ignore(1);

cout << "Nhap ky tu c = "; cin.get(c);

cout << "Nhap so thuc y = "; cin >> y;

cin.ignore(1);

cout << "Nhap chuoi st = "; gets(st);

(17)

cout << "So nguyen x = " << x << endl; cout << "Ky tu c = " << c << endl; cout << "So thuc y = " << y << endl; cout << "Chuoi st = " << st << endl; getch();

}

1.5 CÁC KIỂU DỮ LIỆU CƠ BẢN 1.5.1 Khái niệm kiểu liệu

Thông thường liệu hay dùng số chữ Tuy nhiên việc phân chia loại liệu không đủ Để dễ dàng cho lập trình, hầu hết NNLT phân chia liệu thành nhiều kiểu khác gọi kiểu hay kiểu chuẩn Trên sở kết hợp kiểu liệu chuẩn, NSD tự đặt kiểu liệu để phục vụ cho chương trình giải tốn Có nghĩa lúc đối tượng quản lý chương trình tập hợp nhiều thông tin tạo thành từ nhiều loại (kiểu) liệu khác

Một biến biết số ô nhớ liên tiếp nhớ dùng để lưu trữ liệu (vào, hay kết trung gian) trình họat động chương trình Để quản lý chặt chẽ biến, NSD cần khai báo cho chương trình biết trước tên biến kiểu liệu chứa biến Việc khai báo làm chương trình quản lý biến dễ dàng việc cấp phát nhớ quản lý tính tốn biến theo ngun tắc: có liệu kiểu với phép làm tốn với Do đó, đề cập đến kiểu chuẩn NNLT, thông thường xét đến yếu tố sau:

- Tên kiểu: từ dành riêng để định kiểu liệu

Ví dụ: Kiểu số ngun có tên int

- Kích thước: số byte vùng nhớ cần thiết để lưu trữ đơn vị liệu thuộc kiểu Thông thường số byte phụ thuộc vào trình biên dịch hệ thống máy tính khác nhau, ta xét đến hệ thống máy PC thông dụng

Ví dụ: Kiểu số ngun (int)có kích thước bytes

- Miền giá trị: tập giá trị mà biến thuộc kiểu liệu nhận được, người ta thường ghi giá trị nhỏ lớn Hiển nhiên giá trị phụ thuộc vào số byte mà hệ thống máy tính qui định cho kiểu NSD cần nhớ đến miền giá trị để khai báo kiểu cho biến cần sử dụng cách thích hợp

Ví dụ: Kiểu số ngun (int)có miền giá trị -32768 32767

(18)

LOẠI DỮ LIỆU TÊN KIỂU KÍCH THƯỚC MIỀN GIÁ TRỊ

Ký tự

[signed] char byte -128 127

unsigned char byte 255

Số nguyên

int bytes -32768 32767

unsigned int bytes 65535

short bytes -32768 32767

long [int] bytes -231 231 - unsigned long bytes 232 -

Số thực

float bytes 3.4*10-38 3.4*10+38 double bytes 1.7*10-308 1.7*10+308 long double 10 bytes 3.4*10-4932 1.1*10+4932 1.5.2 Kiểu ký tự

Một ký tự ký hiệu bảng mã ASCII Như biết số ký tự có mặt chữ bàn phím (ví dụ chữ cái, chữ số) số ký tự lại khơng (ví dụ ký tự biểu diễn việc lùi lại ô văn bản, ký tự việc kết thúc hàng hay kết thúc văn bản) Do để biểu diễn ký tự người ta dùng mã ASCII ký tự bảng mã ASCII thường gọi giá trị ký tự Ví dụ phát biểu "Cho ký tự 'A'" tương đương với phát biểu "Cho ký tự 65" (65 mã ASCII ký tự 'A') hay "Xóa ký tự xuống hàng" tương đương với phát biểu "Xoá ký tự 13" 13 mã ASCII ký tự xuống hàng

Như biến kiểu ký tự nhận giá trị theo cách tương đương chữ giá trị số

Ví dụ: Giả sử c biến ký tự câu lệnh gán c = 'A' tương đương với câu lệnh gán c = 65 Tuy nhiên để sử dụng giá trị số ký tự c ta phải yêu cầu đổi c sang giá trị số câu lệnh int(c).

1.5.3 Kiểu số nguyên

(19)

Ta thường sử dụng kiểu int cho số nguyên toán với miền giá trị vừa phải chẳng hạn biến đếm vòng lặp, năm sinh người, 1.5.4 Kiểu số thực

Để sử dụng số thực ta cần khai báo kiểu float double mà miền giá trị chúng cho bảng 1.1 Các giá trị số kiểu double gọi số thực với độ xác kép với kiểu liệu máy tính có cách biểu diễn khác so với kiểu float để đảm bảo số số lẻ sau số thực tăng lên đảm bảo tính xác cao so với số kiểu float Tuy nhiên, tốn thơng dụng thường ngày độ xác số kiểu float đủ

Như nhắc đến phần nhập/xuất, liên quan đến việc in ấn số thực ta có vài cách thiết lập dạng in theo ý muốn, ví dụ độ rộng tối thiểu để in số hay số chữ số cần in bao nhiêu,

Ví dụ 5: Chương trình sau in diện tích chu vi hình trịn có bán kính 3cm với số chữ số in

#include <cstdlib> #include <iostream> #include <conio.h> #include <iomanip.h> using namespace std; main()

{

float r = 3;

cout<< setiosflags(ios::showpoint);

cout<< "DT = "<<setprecision(6)<<r*r*3.1416<<endl; cout<< "CV = "<<setprecision(6)<<2*3.1416*r<<endl;

getch(); }

1.6 HẰNG 1.6.1 Định nghĩa

Hằng (constant) giá trị cố định suốt trình thực thi chương trình

Ví dụ:

3 số ngun 'A' ký tự 5.0 số thực

(20)

Một giá trị hiểu nhiều kiểu khác nhau, viết ta cần có dạng viết thích hợp

1.6.2 Một số thông dụng

Đối với số ký tự thường dùng mặt chữ tương ứng, ký tự dành riêng với nhiệm vụ khác, thay phải nhớ giá trị viết theo qui ước sau:

'\n' : biểu thị ký tự xuống hàng (cũng tương đương với endl)

'\t' : ký tự tab

'\a' : ký tự chuông (tức thay in ký tự, loa phát tiếng 'bíp')

'\r' : xuống hàng

'\f' : kéo trang

'\\' : dấu \

'\?' : dấu chấm hỏi ?

'\'' : dấu nháy đơn '

'\"' : dấu nháy kép "

'\kkk' : ký tự có mã kkk hệ

'\xkk' : ký tự có mã kk hệ 16

Ví dụ: cout << "Hom troi \t nang \a \a \a \n" ; in hình hàng chữ "Hơm trời" sau bỏ khoảng cách tab (khoảng dấu cách) in tiếp chữ "nắng", phát tiếng chuông cuối trỏ hình nhảy xuống đầu hàng

1.6.3 Khai báo

Một giá trị cố định (hằng) sử dụng nhiều lần chương trình đơi thuận lợi ta đặt cho tên gọi, thao tác gọi khai báo Ví dụ chương trình quản lý sinh viên với giả thiết số sinh viên tối đa 50 Nếu số sinh viên tối đa không thay đổi chương trình ta đặt cho tên gọi sosv chẳng hạn Trong suốt chương trình chỗ xuất giá trị 50 ta thay sosv

Việc sử dụng tên thay cho có nhiều điểm thuận lợi sau:

- Chương trình dễ đọc hơn, thay cho số có ý nghĩa, tên gọi làm NSD dễ hình dung vai trị, nội dung Ví dụ, gặp tên gọi sosv NSD hình dung chẳng hạn, "đây số sinh viên tối đa lớp", số 50 số sinh viên mà số thứ tự sinh viên

(21)

khác số thứ tự sinh viên chẳng hạn Nếu chương trình sử dụng sosv, việc thay trở nên xác dễ dàng thao tác khai báo lại giá trị sosv 60 Lúc chương trình nơi gặp tên sosv chương trình hiểu với giá trị 60

Để khai báo ta dùng câu khai báo sau: #define tên_hằng giá_trị_hằng;

hoặc:

const tên_hằng = giá_trị_hằng;

Ví dụ:

#define sosv 50; #define MAX 100; const sosv = 50;

Như ví dụ giá trị chưa nói lên kiểu sử dụng ta cần khai báo rõ ràng cách thêm tên kiểu trước tên khai báo const, khai báo gọi có kiểu

Ví dụ:

const int sosv = 50; const float MAX = 100.0; 1.7 BIẾN

1.7.1 Định nghĩa

Biến (variable – biến số) tên gọi để lưu giá trị làm việc chương trình Các giá trị lưu giá trị liệu ban đầu, giá trị trung gian tạm thời q trình tính tốn giá trị kết cuối Khác với hằng, giá trị biến thay đổi q trình làm việc lệnh đọc vào từ bàn phím lệnh gán Hình ảnh cụ thể biến số ô nhớ nhớ sử dụng để lưu giá trị biến

1.7.2 Khai báo biến

Mọi biến phải khai báo trước sử dụng Một khai báo báo cho chương trình biết biến gồm có: tên biến, kiểu biến (tức kiểu giá trị liệu mà biến lưu giữ) Thông thường với nhiều NNLT tất biến phải khai báo từ đầu chương trình hay đầu hàm, nhiên để thuận tiện cho người lập trình C++ cho phép khai báo biến bên chương trình hàm, có nghĩa lúc NSD thấy cần thiết sử dụng biến mới, họ có quyền khai báo sử dụng từ trở

(22)

1.7.2.1 Khai báo không khởi tạo

tên_kiểu tên_biến_1; tên_kiểu tên_biến_2; tên_kiểu tên_biến_3;

Nhiều biến kiểu khai báo hàng: tên_kiểu tên_biến_1, tên_biến_2, tên_biến_3;

Ví dụ:

int i, j; float x;

char c, d[100];

1.7.2.2 Khai báo có khởi tạo

Trong câu lệnh khai báo, biến gán giá trị ban đầu phép toán gán (=) theo cú pháp:

tên_kiểu tên_biến_1 = gt_1; tên_kiểu tên_biến_2 = gt_2, tên_kiểu tên_biến_3 = gt_3;

Trong giá trị gt_1, gt_2, gt_3 hằng, biến biểu thức Nhiều biến kiểu khai báo hàng:

tên_kiểu tên_biến_1 = gt_1, tên_biến_2 = gt_2, tên_biến_3 = gt_3;

Ví dụ:

int i = 2, j , k = (i + 5) * 4; float eps = 1.0e-6;

char d[100] = "Cong nghe thong tin"; 1.7.3 Phạm vi biến

Như biết chương trình tập hợp hàm, câu lệnh khai báo Phạm vi tác dụng biến nơi mà biến có tác dụng, tức hàm nào, câu lệnh phép sử dụng biến Một biến xuất chương trình sử dụng hàm khơng hàm khác hai, điều phụ thuộc chặt chẽ vào vị trí nơi biến khai báo Một nguyên tắc biến có tác dụng kể từ vị trí khai báo hết khối lệnh chứa

1.7.4 Gán giá trị cho biến

(23)

Cú pháp phép gán sau: tên_biến = biểu thức;

Khi gặp phép gán chương trình tính tốn giá trị biểu thức bên vế phải sau gán giá trị cho biến bên vế trái

Ví dụ:

int n, i = 3; // khởi tạo i

n = 10; // gán cho n giá trị 10 hay gán giá trị 10 vào biến n cout << n <<", " << i << endl; // in ra: 10,

i = n / 2; // gán lại giá trị i n/2 =

cout << n <<", " << i << endl; // in ra: 10, 1.7.5 Một số điểm lưu ý phép gán

- Với ý nghĩa thông thường phép tốn (nghĩa tính tốn cho lại giá trị) phép gán cịn nhiệm vụ trả lại giá trị Giá trị trả lại phép gán giá trị biểu thức sau dấu Lợi dụng điều C++ cho phép gán "kép" cho nhiều biến nhận giá trị cú pháp:

biến_1 = biến_2 = … = biến_n = gt;

Với cách gán tất biến nhận giá trị gt

Ví dụ:

int i, j, k; i = j = k = 1;

Biểu thức gán viết lại (i = (j = (k = 1))), có nghĩa để thực phép gán giá trị cho biến i chương trình phải tính biểu thức (j = (k = 1)), tức phải tính k = 1, phép gán, gán giá trị cho k trả lại giá trị 1, giá trị trả lại gán cho j trả lại giá trị để tiếp tục gán cho i

- Ngồi việc gán kép trên, phép gán cịn phép xuất biểu thức nào, điều cho phép biểu thức có phép gán, khơng tính tốn mà cịn gán giá trị cho biến Ví dụ n = + (i = 2) cho ta i = n =

Việc sử dụng nhiều chức câu lệnh làm cho chương trình gọn gàng (trong số trường hợp) trở nên khó đọc, chẳng hạn câu lệnh viết tách thành câu lệnh i = 2; n = + i; dễ đọc người bắt đầu tìm hiểu lập trình

1.8 PHÉP TỐN, BIỂU THỨC VÀ CÂU LỆNH 1.8.1 Phép toán

1.8.1.1 Các phép toán số học: +, -, *, /, %

(24)

- Phép toán a / b (chia) thực theo kiểu toán hạng, tức hai tốn hạng số ngun kết phép chia lấy phần nguyên, ngược lại tốn hạng số thực kết số thực

Ví dụ:

13/5 = // 13 số nguyên

13.0/5 = 13/5.0 = 13.0/5.0 = 2.6 // có tốn hạng thực

- Phép toán a % b (lấy phần dư) trả lại phần dư phép chia a / b, a b số nguyên

Ví dụ:

13%5 = // phần dư 13/5

5%13 = // phần dư 5/13

1.8.1.2 Các phép toán tự tăng, tự giảm: i++, ++i, i , i

- Phép toán ++i i++ tăng i lên đơn vị tức tương đương với câu lệnh i = i+1 Tuy nhiên phép toán nằm câu lệnh biểu thức ++i khác với i++ Cụ thể ++i tăng i, sau i tham gia vào tính tốn biểu thức, ngược lại i++ tăng i sau biểu thức tính toán xong (với giá trị i cũ) Điểm khác biệt minh họa thơng qua ví dụ sau với giả sử i = 3, j = 15

Phép toán Tương đương Kết

i = ++j ; // tăng trước j = j + ; i = j ; i = 16 , j = 16

i= j++ ; // tăng sau i = j ; j = j + ; i = 15 , j = 16

j = ++i + ; i = i + ; j = i + 5; i = 4, j =

j = i++ + ; j = i + 5; i = i + 1; i = 4, j =

 Ghi chú: Việc kết hợp phép toán tự tăng, tự giảm vào biểu thức câu lệnh

sẽ làm cho chương trình ngắn gọn khó hiểu

1.8.1.3 Các phép toán so sánh logic

Đây phép toán mà giá trị trả lại (true) sai (false) Nếu giá trị biểu thức nhận giá trị 1, ngược lại sai biểu thức nhận giá trị Nói cách khác giá trị cụ thể khái niệm "đúng" "sai" Mở rộng C++ quan niệm giá trị khác "đúng" giá trị "sai"

- Các phép toán so sánh: == (bằng nhau), != (khác nhau), > (lớn hơn), < (nhỏ hơn), >= (lớn bằng), <= (nhỏ bằng)

Hai toán hạng phép toán phải kiểu

 Chú ý: Cần phân biệt phép toán gán (=) phép toán so sánh (==) Phép gán vừa gán

(25)

- Các phép toán logic: && (và), || (hoặc ), ! (khơng, phủ định)

Hai tốn hạng loại phép tốn phải có kiểu logic tức nhận hai giá trị "đúng" (được thể số nguyên khác 0) "sai" (thể 0) Khi giá trị trả lại phép toán cho bảng sau:

A B A && B A || B ! A

1 1

1 0

0 1

0 0

 Chú ý: Việc đánh giá biểu thức tiến hành từ trái sang phải dừng biết

kết mà không chờ đánh giá hết biểu thức Cách đánh giá cho kết phụ khác biểu thức ta "tranh thủ" đưa thêm vào phép toán tự tăng, tự giảm

Ví dụ: Cho i = 2, j = 3, xét biểu thức sau đây:

x = (++i < && ++j > 5) cho kết x = , i = , j = y = (++j > && ++i < 4) cho kết y = , i = , j =

Cách viết hai biểu thức (ngoại trừ hoán đổi vị trí tốn hạng phép tốn &&) Với giả thiết i = j = ta thấy hai biểu thức nhận giá trị Tuy nhiên giá trị i j sau thực xong hai biểu thức có kết khác Cụ thể với biểu thức đầu ++i < nên chương trình phải tiếp tục tính tiếp ++j > để đánh giá biểu thức Do sau đánh giá xong i j tăng lên nên ta có i = 3, j = Trong với biểu thức sau ++j > sai nên chương trình kết luận tồn biểu thức sai mà khơng cần tính tiếp ++i < Có nghĩa chương trình sau đánh giá xong ++j > dừng có biến j tăng 1, từ ta có i = 2, j = khác với kết biểu thức Ví dụ lần nhắc ta ý kiểm soát kỹ việc sử dụng phép toán tự tăng, tự giảm biểu thức câu lệnh

1.8.2 Các phép gán

- Phép gán thơng thường: Đây phép gán trình bày mục trước - Phép gán có điều kiện:

biến = (Điều_kiện) ? a : b ;

(26)

Ví dụ:

x = (3 + < 7) ? 10 : 20 // x = 20 + < sai

x = (3 + 4) ? 10 : 20 // x = 10 + khác 0, tức điều kiện

x = (a > b) ? a : b // x = số lớn số a, b

- Cách viết gọn phép gán: Một phép gán dạng x = x @ a ; viết gọn dạng x @= a @ phép tốn số học, xử lý bit

Ví dụ:

Thay cho viết x = x + viết x += 2;

hoặc x = x / 2; x = x * viết lại x /= 2; x *= 2; 1.8.3 Biểu thức

Biểu thức (expression) dãy ký hiệu kết hợp toán hạng, phép toán cặp dấu () theo qui tắc định Các toán hạng hằng, biến, hàm Biểu thức cung cấp cách thức để tính giá trị dựa toán hạng toán tử biểu thức

Ví dụ:

(x + y) * - - x + sqrt(y)

(-b + sqrt(delta)) / (2*a)

1.8.3.1 Thứ tự ưu tiên phép tốn

Để tính giá trị biểu thức cần có trật tự tính tốn cụ thể thống

Ví dụ:

Xét biểu thức x = + * +

- Nếu tính theo trật tự từ trái sang phải, x = ((3 + 4) * 2) + = 21 - Nếu ưu tiên dấu + thực trước dấu *, x = (3 + 4) * (2 + 7) = 63 - Nếu ưu tiên dấu * thực trước dấu +, x = + (4 * 2) + = 18 C++ qui định trật tự tính tốn theo mức độ ưu tiên sau:

1 Các biểu thức cặp dấu ngoặc ()

2 Các phép tốn ngơi (tự tăng, tự giảm, lấy địa chỉ, lấy nội dung trỏ, …) Các phép toán số học

4 Các phép toán so sánh, logic Các phép gán

(27)

Ví dụ:

Theo mức ưu tiên qui định, biểu thức tính x ví dụ có giá trị 18

Phần lớn trường hợp muốn tính tốn theo trật tự ta nên sử dụng cụ thể dấu ngoặc (vì biểu thức dấu ngoặc tính trước)

1.8.3.2 Phép chuyển đổi kiểu

Khi tính tốn biểu thức phần lớn phép toán yêu cầu toán hạng phải kiểu Chẳng hạn để phép gán thực giá trị biểu thức phải có kiểu với biến Trong trường hợp kiểu giá trị biểu thức khác với kiểu biến chương trình tự động chuyển kiểu giá trị biểu thức thành kiểu biến gán (nếu được) báo lỗi Do cần thiết NSD phải sử dụng câu lệnh để chuyển kiểu biểu thức cho phù hợp với kiểu biến Có cách chuyển đổi kiểu chuyển kiểu tự động ép kiểu

- Chuyển kiểu tự động: Về mặt nguyên tắc, cần thiết kiểu có giá trị thấp chương trình tự động chuyển lên kiểu cao cho phù hợp với phép tốn Cụ thể phép chuyển kiểu thực theo sơ đồ sau:

char ↔ int → long int → float → double

Ví dụ:

int i = 3; float f ; f = i + 2;

Trong ví dụ i có kiểu ngun i + có kiểu nguyên f có kiểu thực Tuy nhiên phép tốn gán hợp lệ chương trình tự động chuyển kiểu i + (bằng 5) sang kiểu thực (bằng 5.0) gán cho f

- Ép kiểu: Trong chuyển kiểu tự động, chương trình chuyển kiểu từ thấp lên cao, nhiên chiều ngược lại thực gây liệu Do cần thiết NSD phải lệnh cho chương trình chuyển kiểu từ cao xuống thấp

Ví dụ: int i;

float f = ; // tự động chuyển thành 3.0 gán cho f

i = f + ; // sai (báo lỗi) f + = khơng gán cho i

Trong ví dụ để câu lệnh i = f + thực (không báo lỗi) ta phải ép kiểu biểu thức f + thành kiểu nguyên Cú pháp tổng quát sau:

(tên_kiểu)biểu_thức hoặc:

tên_kiểu(biểu_thức)

(28)

- Phép ép kiểu từ số thực số nguyên cắt bỏ tất phần lẻ số thực, giữ lại phần nguyên Như để tính phần nguyên số thực x ta cần ép kiểu x thành kiểu nguyên, có nghĩa int(x) phần nguyên số thực x

Ví dụ 6:

Để kiểm tra số nguyên n có phải số phương, ta cần tính bậc hai n Nếu bậc hai n số ngun x n số phương, tức int(x) = x x nguyên n phương Chương trình cụ thể sau:

#include <cstdlib> #include <iostream> #include <conio.h> #include <math.h> using namespace std; main()

{

int n;

cout << "Nhap n = "; cin >> n;

float x = sqrt(n); // Ham sqrt de tinh can bac hai if (int(x) == x)

cout << n << " la so chinh phuong" << endl; else

cout << n << " khong la so chinh phuong" << endl; system("PAUSE");

}

1.8.4 Câu lệnh khối lệnh

Một câu lệnh C++ thiết lập từ từ khóa biểu thức,… luôn kết thúc dấu chấm phẩy Các ví dụ nhập/xuất phép gán tạo thành câu lệnh đơn giản như:

cin >> x >> y ; x = x + ; y = sqrt(x) ;

(29)

Các câu lệnh phép viết dòng nhiều dòng Một số câu lệnh gọi lệnh có cấu trúc, tức bên lại chứa dãy lệnh khác Dãy lệnh phải bao cặp dấu ngoặc {} gọi khối lệnh

Ví dụ tất lệnh hàm (như hàm main()) luôn khối lệnh Một đặc điểm khối lệnh biến khai báo khối lệnh có tác dụng khối lệnh Chi tiết đặc điểm lệnh khối lệnh trình bày chương giáo trình

1.9 MỘT SỐ HÀM THƠNG DỤNG 1.9.1 Nhóm hàm tốn học

Các hàm khai báo file nguyên mẫu math.h

- abs(x), labs(x), fabs(x) : trả lại giá trị tuyệt đối số nguyên, số nguyên dài số thực

- pow(x, y) : hàm mũ, trả lại giá trị x lũy thừa y (xy) - exp(x) : hàm mũ, trả lại giá trị e mũ x (ex)

- log(x), log10(x) : trả lại lôgarit số e logarit thập phân x (lnx, logx) - sqrt(x) : trả lại bậc x

- sin(x), cos(x), tan(x), asin(x), acos(x), atan(x) : trả lại giá trị sinx, cosx, tgx, arcsinx, arccosx, arctgx

1.9.2 Nhóm hàm kiểm tra ký tự

Các hàm khai báo file nguyên mẫu ctype.h

- isalnum(kt) : kiểm tra ký tự kt có phải chữ chữ số hay không - isalpha(kt) : kiểm tra ký tự kt có phải chữ hay khơng

- isdigit(kt) : kiểm tra ký tự kt có phải chữ số hay không

- islower(kt) : kiểm tra ký tự kt có phải chữ thường (a z) hay không - isupper(kt) : kiểm tra ký tự kt có phải chữ hoa (A Z) hay không - isspace(kt) : kiểm tra ký tự kt có phải ký tự trống hay khơng

1.9.3 Nhóm hàm chuyển đổi liệu

Các hàm khai báo file nguyên mẫu ctype.h

(30)

BÀI TẬP CHƯƠNG 1

- -

1 Viết chương trình in nội dung thơ mà bạn thích

2 Viết chương trình nhập vào cạnh hình vng, in chu vi diện tích

3 Viết chương trình nhập vào giá trị số thực, nguyên, nguyên dài ký tự In hình giá trị

4 Viết chương trình nhập vào ký tự, in ký tự mã ASCII

5 Viết chương trình nhập số thực a, b, c, in hình hàng chữ phương trình có dạng ax^2 + bx + c = 0, giá trị a, b, c in số lẻ (ví dụ với a = 5.141, b = −2, c = 0.8 in 5.14 x^2 −2.00 x + 0.80)

6 Viết chương trình in tổng, tích, hiệu thương số thực nhập vào từ bàn phím

7 Viết chương trình in trung bình cộng, trung bình nhân số nguyên nhập vào từ bàn phím

8 Viết chương trình nhập vào bán kính hình trịn, in diện tích, chu vi Viết chương trình nhập vào chữ số In tổng chữ số chữ số hàng chục, hàng đơn vị tổng (ví dụ chữ số 3, 1, 8, có tổng 17 chữ số hàng chục hàng đơn vị 7, in 17, 1, 7)

10 Viết chương trình nhập vào số ngun (có chữ số) In tổng chữ số chữ số đầu, chữ số cuối (ví dụ số 3185 có tổng chữ số 17, chữ số đầu cuối 5, in 17, 3, 5)

11 Viết chương trình nhập số nguyên a b, đổi giá trị a b theo cách: - Dùng biến phụ t: t = a; a = b; b = t;

- Không dùng biến phụ: a = a + b; b = a - b; a = a - b; In kết hình giá trị a b trước sau đổi

12 Viết chương trình nhập vào hệ số lương (là số thực có chữ số lẻ) nhân viên In lương nhân viên đó, với lương = 1.150.000 * hệ số lương

13 Viết chương trình nhập vào năm sinh người Cho biết người năm tuổi

14 Viết chương trình tính số pignet người biết chiều cao (cm), vịng ngực trung bình (cm) trọng lượng (kg)

Với: số pignet = chiều cao - (vịng ngực trung bình + trọng lượng)

15 Viết chương trình nhập vào chiều dài cạnh a, b, c tam giác Tính chu vi diện tích tam giác theo cơng thức sau:

Chu vi : CV = a + b + c

(31)

CHƯƠNG 2: CÁC CẤU TRÚC ĐIỀU KHIỂN

- -

2.1 CẤU TRÚC RẼ NHÁNH

Nói chung việc thực chương trình hoạt động tuần tự, tức thực lệnh từ câu lệnh bắt đầu chương trình câu lệnh cuối Tuy nhiên, để việc lập trình hiệu hầu hết NNLT cấp cao có câu lệnh rẽ nhánh câu lệnh lặp cho phép thực câu lệnh chương trình khơng theo cấu trúc

2.1.1 Cấu trúc if 2.1.1.1 Ý nghĩa

Một câu lệnh if cho phép chương trình thực khối lệnh hay khối lệnh khác phụ thuộc vào điều kiện viết câu lệnh hay sai Nói cách khác câu lệnh if cho phép chương trình rẽ nhánh (chỉ thực nhánh) 2.1.1.2 Cú pháp

if (điều kiện) khối lệnh 1; [else

khối lệnh 2;]

Trong cú pháp câu lệnh if có hai dạng: có else khơng có else Điều kiện biểu thức logic tức có giá trị (khác 0) sai (bằng 0)

Khi chương trình thực câu lệnh if tính biểu thức điều kiện Nếu điều kiện chương trình tiếp tục thực lệnh khối lệnh 1, ngược lại điều kiện sai chương trình thực khối lệnh (nếu có else) khơng làm (nếu khơng có else)

2.1.1.3 Lưu đồ cú pháp

điều kiện

khối lệnh

S Đ

(32)

2.1.1.4 Đặc điểm

- Đặc điểm chung câu lệnh có cấu trúc thân chứa câu lệnh khác Điều cho phép câu lệnh if lồng

- Nếu nhiều câu lệnh if (có else không else) lồng việc hiểu if else với cần phải ý Qui tắc else với if gần mà chưa ghép cặp với else khác

Ví dụ: Câu lệnh:

if (n > 0) if (a > b)

c = a; else

c = b; Tương đương với câu lệnh:

if (n > 0) {

if (a > b) c = a; else

c = b; }

2.1.1.5 Các lưu ý

- Điều kiện (hay biểu thức) sau if phải đặt cặp dấu ngoặc đơn ( )

- Nếu khối lệnh có nhiều câu lệnh phải bao chúng cặp dấu ngoặc móc { } - Nếu khối lệnh có câu lệnh ta viết sau if else mà không cần phải xuống hàng

2.1.1.6 Ví dụ minh họa

Ví dụ 1: Viết chương trình nhập vào số nguyên, in số lớn số #include <cstdlib>

#include <iostream> using namespace std; main()

{

(33)

cout<<"Nhap vao so nguyen a va b : "; cin>>a>>b;

if (a > b)

max = a;

else

max = b;

cout<<"So lon hon la : "<<max<<endl; system("PAUSE");

}

Ví dụ 2: Viết chương trình nhập vào năm bất kỳ, cho biết năm có phải năm nhuận không Biết năm thứ n nhuận chia hết cho 4, khơng chia hết cho 100 chia hết cho 400

#include <cstdlib> #include <iostream> using namespace std; main()

{

int n;

cout<<"Nhap vao mot nam bat ky : "; cin>>n;

if (n % == && n % 100 !=0 || n % 400 == 0) cout<<n<<" la nam nhuan"<<endl;

else

cout<<n<<" la nam khong nhuan"<<endl; system("PAUSE");

}

Ví dụ 3: Viết chương trình giải phương trình bậc hai: ax2 + bx + c = (a ≠ 0) #include <cstdlib>

#include <iostream> #include <math.h> using namespace std; main()

{ float a, b, c;

(34)

cin>>a>>b>>c; float delta;

delta = b*b - 4*a*c ;

if (delta < 0) cout << "Phuong trinh vo nghiem"<<endl; else

if (delta == 0) {

cout<<"Phuong trinh co nghiem kep x = "; cout<<-b/(2*a)<<endl;

} else

{

float x1, x2;

x1=(-b+sqrt(delta))/(2*a); x2 = (-b-sqrt(delta))/(2*a);

cout<<"Phuong trinh co nghiem phan biet"<<endl; cout<<"x1 = " <<x1<<" va x2 = "<<x2<<endl;

}

system("PAUSE"); }

2.1.2 Cấu trúc switch 2.1.2.1 Ý nghĩa

Câu lệnh if cho ta khả lựa chọn hai nhánh để thực hiện, muốn rẽ theo nhiều nhánh ta phải sử dụng cấu trúc if lồng Tuy nhiên trường hợp chương trình phức tạp khó đọc hơn, C++ cung cấp thêm câu lệnh cấu trúc khác cho phép chương trình chọn nhiều nhánh để thực hiện, câu lệnh switch

2.1.2.2 Cú pháp

switch (biểu thức) {

(35)

case biểu_thức_n: khối lệnh n; [default: khối lệnh n+1;]

}

- Biểu thức: phải có kiểu nguyên ký tự

- Các biểu_thức_i: phải có kiểu nguyên ký tự tương ứng

- Các dãy lệnh rỗng khơng cần bao dãy lệnh cặp dấu ngoặc móc { }

- Nhánh default có khơng vị trí nằm câu lệnh (giữa nhánh case) thông thường người ta đặt nằm cuối

2.1.2.3 Lưu đồ cú pháp

2.1.2.4 Cách thực

Để thực câu lệnh switch chương trình tính giá trị biểu thức điều khiển (btđk), sau so sánh kết btđk với giá trị biểu_thức_i bên từ biểu thức (thứ nhất) biểu thức cuối (thứ n), giá trị btđk giá trị biểu thức thứ i chương trình thực dãy lệnh thứ i tiếp tục thực tất dãy lệnh lại (từ dãy lệnh thứ i+1) hết (gặp dấu ngoặc đóng } lệnh switch) Nếu q trình so sánh không gặp biểu thức

khối lệnh biểu thức

biểu_thức_1

biểu thức biểu_thức_2

khối lệnh

biểu thức

biểu_thức_n khối lệnh n Đ

Đ

Đ S

S

S

(36)

(nhánh case) với giá trị btđk chương trình thực dãy lệnh default tiếp tục hết (sau default cịn nhánh case khác) Trường hợp câu lệnh switch khơng có nhánh default btđk không khớp với nhánh case chương trình khơng làm gì, coi thực xong lệnh switch

Nếu muốn lệnh switch thực nhánh thứ i (khi btđk == biểu_thức_i) mà khơng phải thực thêm lệnh cịn lại nhánh khác cuối dãy lệnh thứ i thông thường ta đặt thêm lệnh break; lệnh cho phép thoát khỏi lệnh cấu trúc

2.1.2.5 Ví dụ minh họa

Ví dụ 1: Viết chương trình in số ngày tháng nhập từ bàn phím, tháng cho biết thêm năm

#include <cstdlib> #include <iostream> using namespace std; main()

{

int th, n;

cout<<"Nhap vao mot thang bat ky : "; cin>>th;

switch (th) {

case 1: case 3: case 5: case 7: case 8: case 10: case 12: cout<<"Thang co 31 ngay"; break;

case 4: case 6:

case 9: case 11: cout<<"Thang co 30 ngay"; break; case 2:

cout<<"Cho biet nam nao : "; cin>>n;

if (n % == && n % 100 !=0 || n % 400 == 0) cout<<"Thang co 29 ngay";

else cout<<"Thang co 28 ngay"; break;

(37)

cout<<endl;

system("PAUSE"); }

Ví dụ 2: Viết chương trình nhập vào số thực a b từ bàn phím, sau nhập ký tự thể phép toán: cộng, trừ, nhân, chia In kết thực phép tốn số a, b

#include <cstdlib> #include <iostream> #include <iomanip.h> using namespace std; main()

{

float a, b, kq; char pt;

cout<<"Hay nhap so thuc a, b: "; cin>>a>>b;

cout<<"Hay nhap phep toan: "; cin>>pt;

switch (pt) {

case '+': kq = a + b; break; case '-': kq = a - b; break;

case 'x': case '.': case '*': kq = a * b ; break ; case ':': case '/':

if (b != 0) {

kq = a / b; break;

} else {

cout<<"Khong chia duoc"; goto kt;

(38)

default:

cout<<"Nhap phep toan sai"; goto kt;

}

cout<<"Ket qua la: "<<setprecision(6)<<kq<<endl; kt: system("PAUSE");

}

2.1.3 Lệnh nhảy goto 2.1.3.1 Ý nghĩa

Một dạng khác rẽ nhánh lệnh nhảy goto cho phép chương trình chuyển đến thực đoạn lệnh khác điểm đánh dấu nhãn chương trình Nhãn tên gọi NSD tự đặt theo qui tắt đặt tên Lệnh goto thường sử dụng để nhảy qua số câu lệnh thực tiếp câu lệnh sau chương trình, kết hợp với cấu trúc if để tạo vòng lặp Tuy nhiên việc xuất nhiều lệnh goto dẫn đến việc khó theo dõi trình tự thực chương trình, lệnh nên hạn chế sử dụng không cần thiết

2.1.3.2 Cú pháp Goto <nhãn>;

Vị trí chương trình chuyển đến thực đoạn lệnh đứng sau nhãn dấu hai chấm (:) Ví dụ cấu trúc switch có sử dụng lệnh nhảy goto

2.2 CẤU TRÚC LẶP

Một cấu trúc quan trọng lập trình cấu trúc câu lệnh cho phép lặp nhiều lần đoạn lệnh chương trình Đó cấu trúc lặp 2.2.1 Cấu trúc for

2.2.1.1 Cú pháp

for (dãy biểu thức 1; điều kiện lặp; dãy biểu thức 2) khối lệnh lặp;

- Các biểu thức dãy biểu thức 1, cách dấu phẩy (,) Có thể có nhiều biểu thức dãy dãy biểu thức trống

- Điều kiện lặp: biểu thức logic (có giá trị đúng, sai)

 Các dãy biểu thức điều kiện trống nhiên giữ lại dấu chấm phẩy

(;) để ngăn cách thành phần với 2.2.1.2 Cách thực

Khi gặp câu lệnh for trình tự thực chương trình sau:

(39)

- Kiểm tra điều kiện lặp, thực khối lệnh lặp → thực dãy biểu thức → quay lại kiểm tra điều kiện lặp lặp lại trình việc kiểm tra điều kiện lặp cho kết sai dừng

Tóm lại, dãy biểu thức thực lần từ đầu trình lặp sau thực câu lệnh khối lệnh lặp dãy biểu thức không cịn thỏa điều kiện lặp dừng

Tương tự cấu trúc if, khối lệnh lặp có nhiều câu lệnh phải bao chúng cặp ngoặc móc { }

2.2.1.3 Ví dụ minh họa

Ví dụ 1: Viết chương trình tính tổng N số nguyên dương đầu tiên, với N nhập từ bàn phím

Chương trình dùng biến đếm i khởi tạo từ 1, biến kq để chứa tổng Mỗi bước lặp chương trình cộng dồn i vào kq sau tăng i lên đơn vị Chương trình cịn lặp i chưa vượt N Khi i lớn N chương trình dừng #include <cstdlib>

#include <iostream> using namespace std; main()

{

int n, i; long kq = 0;

cout<<"Nhap vao so nguyen n = "; cin>>n;

for (i = 1; i <= n; i++)

kq = kq + i; // Co the viet kq += i;

cout<<"Tong "<<n<<" so nguyen duong dau tien la : "; cout<<kq<<endl;

system("PAUSE"); }

Ví dụ 2: Viết chương trình tính tổng #include <cstdlib>

#include <iostream> using namespace std;

n

i i

1 S

(40)

main() {

int n, i; float kq = 0;

cout<<"Nhap vao so nguyen n = "; cin>>n;

for (i = 1; i <= n; i++)

kq += 1.0/i; // Co the viet kq = kq + 1.0/i; cout<<"Tong S = "<<kq<<endl;

system("PAUSE"); }

Ví dụ 3: Viết chương trình in hình dãy giảm dần số lẻ bé số n nhập vào từ bàn phím

#include <cstdlib> #include <iostream> using namespace std; main()

{

int n, i;

cout<<"Nhap vao so nguyen n = "; cin>>n;

if (n % == 0) i = n - 1; else i = n - 2;

for ( ; i >= 1; i = i - 2) cout<<i<<" ";

cout<<endl; system("PAUSE"); }

2.2.1.4 Đặc điểm

(41)

2.2.1.5 Lệnh for lồng

Trong khối lệnh lặp chứa lệnh for, tức lệnh for phép lồng câu lệnh có cấu trúc khác

Ví dụ 4: Bài tốn cổ: vừa gà vừa chó, bó lại cho trịn, 36 con, 100 chân chẵn Hỏi có gà chó

Để giải toán ta gọi g số gà c số chó Theo điều kiện tốn ta thấy g từ (khơng có nào) đến tối đa 50 (vì có 100 chân), tương tự c từ đến 25 Như ta cho g chạy từ đến 50 với giá trị cụ thể g lại cho c chạy từ đến 25, với cặp (g, c) cụ thể ta kiểm tra điều kiện: g + c == 36? (số con) 2g + 4c == 100? (số chân) Nếu điều kiện thỏa cặp (g, c) cụ thể nghiệm cần tìm Từ ta có chương trình với vòng for lồng nhau, vòng for cho g vòng for cho c

#include <cstdlib> #include <iostream> using namespace std; main()

{

int g, c;

for (g = 0; g <= 50; g++) for (c = 0; c <= 25; c++)

if (g + c == 36 && * g + * c == 100)

cout<<"Ga = "<<g<<" Cho = "<<c<<endl; system("PAUSE");

}

Ví dụ 5: Viết chương trình tìm tất phương án để đổi 100$ tờ giấy bạc loại 10$, 20$ 50$

#include <cstdlib> #include <iostream> using namespace std; main()

{

int st10, st20, st50;

int sopa = 0; // So phuong an

(42)

for (st50 = ; st50 <= ; st50++)

if (st10 * 10 + st20 * 20 + st50 * 50 == 100) {

sopa++;

cout<<"Phuong an "<<sopa<<" : "; if (st10) cout << st10 << " to 10$";

if (st20) cout << " " << st20 << " to 20$"; if (st50) cout << " " << st50 << " to 50$"; cout << endl ;

}

cout << "Tong so phuong an la : " << sopa <<endl; system("PAUSE");

}

2.2.2 Cấu trúc while 2.2.2.1 Cú pháp

while (điều kiện) khối lệnh lặp; 2.2.2.2 Lưu đồ cú pháp

2.2.2.3 Thực

Khi gặp lệnh while chương trình thực sau: chương trình kiểm tra điều kiện, thực khối lệnh lặp, sau quay lại kiểm tra điều kiện tiếp tục, điều kiện sai dừng vịng lặp Tóm lại mơ tả cách ngắn gọn câu lệnh while sau: lặp lại khối lệnh điều kiện

điều kiện

khối lệnh lặp Đ

(43)

2.2.2.4 Đặc điểm

- Khối lệnh lặp khơng thực lần điều kiện sai từ đầu - Để vòng lặp khơng lặp vơ tận khối lệnh thơng thường phải có câu lệnh gây ảnh hưởng đến kết điều kiện, tức làm cho điều kiện trở thành sai

- Nếu điều kiện luôn nhận giá trị (ví dụ biểu thức điều kiện 1) khối lệnh lặp phải có câu lệnh kiểm tra dừng lệnh break

- Nếu khối lệnh lặp có nhiều câu lệnh phải bao chúng cặp ngoặc móc { } 2.2.2.5 Ví dụ minh họa

Ví dụ 1: Bài tốn cổ: vừa gà vừa chó, bó lại cho trịn, 36 con, 100 chân chẵn Hỏi có gà chó

#include <cstdlib> #include <iostream> using namespace std; main()

{

int g, c; g = 0;

while (g <= 36) //số gà tối đa 50 đề cho 36 {

c = 0;

while (c <= 25) //số chó tối đa 25 đủ 100 chân {

if (g + c == 36 && * g + * c == 100) cout<<"Ga = "<<g<<" Cho = "<<c<<endl; c++;

} g++; }

(44)

Ví dụ 2: Viết chương trình nhập vào số nguyên dương (giả sử m n), in ước chung lớn (UCLN) số

Áp dụng thuật toán Euclide cách liên tiếp lấy số lớn trừ số nhỏ số UCLN Trong chương trình ta qui ước m số lớn n số nhỏ Thêm biến phụ r để tính hiệu số Sau đặt lại m n r cho m > n lặp lại Vòng lặp dừng m = n

#include <cstdlib> #include <iostream> using namespace std; main()

{

int m, n, r;

cout<<"Nhap m, n: " ; cin>>m>>n ;

if (m < n) // Nếu m < n đổi vai trò hai số {

int t = m;

m = n;

n = t;

}

while (m != n) {

r = m - n; if (r > n)

m = r;

else {

m = n;

n = r; }

}

cout<<"UCLN = "<<m<<endl; system("PAUSE");

(45)

2.2.3 Lệnh lặp while 2.2.3.1 Cú pháp

do

khối lệnh lặp; while (điều kiện); 2.2.3.2 Lưu đồ cú pháp

2.2.3.3 Thực

Đầu tiên chương trình thực khối lệnh lặp, kiểm tra điều kiện, điều kiện cịn quay lại thực khối lệnh trình tiếp tục điều kiện trở thành sai dừng

2.2.3.4 Đặc điểm

Các đặc điểm câu lệnh … while giống với câu lệnh lặp while trừ điểm khác biệt, khối lệnh … while thực lần điều kiện kiểm tra sau, trong câu lệnh while khơng thực lần

2.2.3.5 Ví dụ minh họa

Ví dụ 1: Viết chương trình kiểm tra số nguyên n (n > 1) có phải số nguyên tố khơng, với n nhập từ bàn phím

Để kiểm tra số n > có phải số nguyên tố hay không ta chia n cho số i từ đến nửa n Nếu có i cho n chia hết cho i n hợp số (khơng phải số nguyên tố) ngược lại n số nguyên tố

#include <cstdlib> #include <iostream> using namespace std;

điều kiện khối lệnh lặp

Đ

(46)

main() {

int i, n;

cout<<"Nhap so n can kiem tra: "; cin>>n;

i = 2; {

if (n % i == 0) {

cout<<n<<" la hop so"; goto kt;

break; }

i++;

} while (i <= n/2);

cout<<n<<" la so nguyen to"; kt: system("PAUSE");

}

Chương trình viết cách khác sau: #include <cstdlib>

#include <iostream> using namespace std; main()

{

int n, i=1;

cout<<"Nhap so n can kiem tra: "; cin>>n;

do {

i++;

(47)

if (i > n/2)

cout<<n<<" la so nguyen to"<<endl; else

cout<<n<<" la hop so"<<endl; system("PAUSE");

}

Ví dụ 2: Viết chương trình nhập vào dãy ký tự thống kê loại chữ hoa, chữ thường, chữ số ký tự khác đến gặp dấu chấm câu dừng

#include <cstdlib> #include <iostream> using namespace std; main()

{

char kt;

int ch, ct, cs, ck ; ch = ct = cs = ck = 0;

cout << "Hay nhap day ky tu:"<<endl;

{

cin>>kt;

if ('A' <= kt && kt <= 'Z') ch++;

else if ('a' <= kt && kt <= 'z') ct++;

else if ('0' <= kt && kt <= '9') cs++; else ck++;

} while (kt != 46);

cout<<"Trong day co:"<<endl; cout<<ch<<" chu hoa"<<endl; cout<<ct<<" chu thuong"<<endl; cout<<cs<<" chu so"<<endl; cout<<ck<<" ky tu khac"<<endl; system("PAUSE");

(48)

2.2.4 Lối vòng lặp 2.2.4.1 Lệnh break

Lệnh break xuất bên vòng lặp (for, while hay … while) lệnh switch Nó tạo nên bước nhảy bên ngồi lệnh kết thúc chúng Lệnh break có tác dụng cho vịng lặp lệnh switch gần Sử dụng lệnh break bên ngồi vòng lặp hay lệnh switch gây lỗi

Ví dụ: Đoạn chương trình sau dùng để kiểm tra việc nhập password hay sai

chỉ phép nhập sai tối đa n lần for (i = 1; i <= n; i++) {

cout << "Nhap vao password: "; cin>> password;

if (Kiemtra(password)) // Nếu password

break; // Thốt khỏi vịng lặp

cout<< "Password sai!"<<endl; }

Ở phải giả sử có hàm gọi Kiemtra dùng để kiểm tra password trả true password ngược lại false

Chúng ta viết lại vịng lặp mà không cần lệnh break cách sử dụng thêm biến luận lý (kt) thêm vào điều kiện lặp:

kt = 0;

for (i = 1; i < = n && !kt; i++) {

cout << "Nhap vao password: "; cin>> password;

kt = Kiemtra(password));

if (!kt) cout<< " Password sai!"<<endl; }

 Người ta cho phiên có sử dụng lệnh break đơn giản nên thường

ưa chuộng

2.2.4.2 Lệnh continue

(49)

Trong vòng lặp while vòng lặp … while, vòng lặp mở đầu từ điều kiện lặp Trong vòng lặp for, lần lặp dãy biểu thức vòng lặp

Ví dụ: Một vịng lặp thực nhập số, xử lý bỏ qua số âm, dừng số 0, diễn giải sau:

do {

cin>>num;

if (num < 0) continue; // xử lý số } while (num != 0);

Điều tương đương với:

{

cin >> num; if (num >= 0)

// xử lý số } while (num != 0);

Một biến thể vịng lặp để đọc xác số n lần (hơn số

là 0) diễn giải sau: for (i = 1; i <= n; i++) {

cin>>num;

if (num < 0) continue; // làm cho nhảy tới i++ // xử lý số

}

Khi lệnh continue xuất bên vòng lặp lồng vào áp dụng trực tiếp lên vịng lặp gần khơng áp dụng cho vịng lặp bên ngồi Ví dụ, tập vòng lặp lồng sau đây, lệnh continue áp dụng cho vịng lặp for khơng áp dụng cho vòng lặp while

while (more) {

for (i = 1; i <= n; i++) {

(50)

if (num < 0) continue; //làm cho nhảy tới i++

// xử lý số }

// Các câu lệnh while }

BÀI TẬP CHƯƠNG 2

- -

1 Viết chương trình nhập ký tự, cho biết ký tự có phải chữ hay khơng

2 Viết chương trình nhập vào số nguyên, cho biết số âm hay dương, chẵn hay lẻ

3 Viết chương trình nhập số a, b, c in max, số

4 Viết chương trình nhập số a, b, c, cho biết số độ dài cạnh tam giác

5 Viết chương trình nhập vào điểm (đcb) điểm nâng cao (đnc) cho học viên Cho biết học viên xếp loại gì, với cách xếp loại dựa vào điểm trung bình (đtb) sau:

- Nếu đtb >= khơng có điểm xếp loại xuất sắc - Nếu đtb >= khơng có điểm xếp loại giỏi - Nếu đtb >= khơng có điểm xếp loại

- Nếu đtb >= khơng có điểm xếp loại trung bình - Cịn lại ghi khơng đạt

6 Viết chương trình làm việc máy tính bỏ túi: - Nhập vào số

- Hỏi toán tử +, -, * hay /, tương ứng in tổng, hiệu, tích, thương - Nếu khơng phải tốn tử kết thúc chương trình

7 Viết chương trình tính tích N số nguyên dương đầu tiên, với N nhập từ bàn phím

8 Viết chương trình tính tổng S = 1/2 + 2/3 + 3/4 + … + n/(n+1), với n số nguyên dương nhập từ bàn phím

9 Viết chương trình tính tổng S = + - + + - + + - + … +/- n, với n số nguyên dương nhập từ bàn phím

10 Viết chương trình tính tổng S = , với n, m số nguyên dương nhập từ bàn phím



 

n

i m

j

j i

1

(51)

11 Viết chương trình tính ! ) ( ! ! ! ! 1 n x x x x x e n n       

 , với n số nguyên

dương, x số thực nhập từ bàn phím

12 Viết chương trình tính e = + 1/1! + 1/2! + 1/3! + … + 1/n!, 1/(n+1)! nhỏ Epsilon, với Epsilon lượng nhỏ nhập từ bàn phím

13 Viết chương trình nhập vào chiều dài chiều rộng cho hình chữ nhật In hình chữ nhật dấu * Giả sử ta nhập cd = 6, cr = in:

* * * * * * * * * * * * * * * * * * * * * * * *

14 Viết chương trình nhập vào số nguyên dương n In tam giác có dạng sau: @

@ @ @ @ @ @ @ @ @

(Nếu n nhập vào 4)

15 Viết chương trình nhập vào số nguyên, trình nhập kết thúc nhập số nguyên Cho biết có số dương, số âm số nguyên nhập

16 Viết chương trình nhập vào số thực, trình nhập kết thúc nhập số thực Cho biết trị trung bình số nhập

17 Viết chương trình làm nhiều lần cơng việc sau: Nhập số thực, in số đối số thực Chương trình kết thúc số thực nhập vào

18 Viết chương trình nhập vào số nguyên dương, in ước số lẻ lớn Ví dụ ta nhập số 60 in 15

19 Viết chương trình in tất số nguyên tố < N, N trị nhập

20 Viết chương trình tính số hạng thứ n dãy Fibonaci Hướng dẫn: Dãy Fibonaci dãy số gồm số hạng F(n) vói F(n) = F(n - 1) + F(n - 2) F(1) = F(2) =

Ví dụ: Dãy Fibonaci gồm 10 số hạng là: 1 13 21 34

21 Viết chương trình phân tích số nguyên dương n thành tích thừa số nguyên tố

22 Viết chương trình đổi số nguyên dương n hệ 10 sang hệ 16 23 Viết lại chương trình lệnh nhảy goto

(52)

CHƯƠNG 3: DỮ LIỆU KIỂU MẢNG

- -

Mảng (array) gọi dãy hay véc-tơ, tập hợp phần tử cố định có kiểu gọi kiểu phần tử Kiểu phần tử kiểu bản, kiểu cấu trúc (struct),… Có loại mảng mảng chiều mảng nhiều chiều (2 chiều trở lên) 3.1 MẢNG MỘT CHIỀU

3.1.1 Ý nghĩa

Mảng dãy phần tử có kiểu kề liên tục nhớ Tất phần tử có tên tên mảng Để phân biệt phần tử với nhau, phần tử đánh số thứ tự từ hết mảng Khi cần nói đến phần tử cụ thể mảng ta dùng tên mảng kèm theo số thứ tự phần tử

Dưới hình ảnh mảng gồm có 10 phần tử, thành phần đánh số từ đến

3.1.2 Khai báo

<tên kiểu> <tên mảng>[số phần tử] ; // không khởi tạo

<tên kiểu> <tên mảng>[số phần tử] = { dãy giá trị }; // có khởi tạo

<tên kiểu> <tên mảng>[ ] = { dãy giá trị }; // có khởi tạo

- Tên kiểu kiểu liệu phần tử, phần tử có kiểu giống Thỉnh thoảng ta gọi phần tử thành phần

- Cách khai báo giống khai báo tên biến bình thường thêm số phần tử mảng cặp dấu ngoặc vng [ ], cịn gọi kích thước mảng Mỗi tên mảng biến để phân biệt với biến thông thường ta gọi biến mảng - Dữ liệu hay giá trị phần tử mảng lưu nhớ dãy ô nhớ liên tiếp Số lượng ô nhớ với số phần tử mảng kích thước (được tính byte) ô nhớ đủ để chứa thông tin phần tử Ô đánh thứ tự 0, ô 1, ô tiếp tục hết Như mảng có N phần tử cuối mảng đánh số N -

- Dạng khai báo thứ cho phép khởi tạo mảng dãy giá trị cặp dấu { }, giá trị cách dấu phẩy (,), giá trị gán cho phần tử mảng phần tử thứ hết dãy Số giá trị bé số phần tử Các phần tử mảng chưa có giá trị khơng xác định chương trình gán giá trị

a Vị trí

(53)

- Dạng khai báo thứ cho phép vắng mặt số phần tử, trường hợp số phần tử xác định số giá trị dãy khởi tạo Do vắng mặt dãy khởi tạo không phép (chẳng hạn khai báo int a[ ] sai)

Ví dụ:

- Khai báo biến chứa véc-tơ a, b không gian chiều: float a[2], b[2];

- Khai báo phân số a, b, c; a = 1/3 b = 3/5:

int a[2] = {1, 3} , b[2] = {3, 5} , c[2];

Ở ta ngầm qui ước phần tử (số thứ tự 0) tử số phần tử thứ hai (số thứ tự 1) mẫu số phân số

- Khai báo mảng L chứa tối đa 100 số nguyên dài: long L[100];

- Khai báo mảng dong (hàng), hàng chứa tối đa 80 ký tự: char dong[80];

3.1.3 Cách sử dụng

- Để phần tử thứ i (hay số i) mảng ta viết tên mảng kèm theo số cặp ngoặc vng [ ]

Ví dụ với phân số a[0], b[0], c[0] để tử số a[1], b[1], c[1] để mẫu số phân số a, b, c

- Tuy mảng biểu diễn đối tượng áp dụng thao tác lên toàn mảng mà phải thực thao tác thông qua phần tử mảng Ví dụ khơng thể nhập liệu cho mảng a[10] câu lệnh:

cin >> a ; //sai

Để nhập liệu cho mảng a[10] ta phải nhập cho phần tử từ a[0] đến a[9] a Dĩ nhiên trường hợp ta phải cần đến lệnh lặp for:

int i;

for (i = ; i < 10 ; i++) cin >> a[i];

Tương tự, giả sử cần cộng phân số a, b đặt kết vào c Ta viết:

c = a + b ; //sai

Ta cần phải tính thành phần cho c sau:

c[0] = a[0] * b[1] + a[1] * b[0] ; //tử số

(54)

3.1.4 Ví dụ minh họa

Ví dụ 1: Viết chương trình nhập vào phân số, tìm tổng tích phân số #include <cstdlib>

#include <iostream> using namespace std; main()

{

int a[2], b[2], tong[2], tich[2]; cout<<"Nhap tu cua phan so a = "; cin>>a[0];

cout<<"Nhap mau cua phan so a = "; cin>>a[1];

cout<<"Nhap tu cua phan so b = "; cin>>b[0];

cout<<"Nhap mau cua phan so b = "; cin>>b[1];

tong[0] = a[0] * b[1] + a[1] * b[0]; tong[1] = a[1] * b[1];

tich[0] = a[0] * b[0]; tich[1] = a[1] * b[1];

cout<<"Phan so Tong = "<<tong[0]<<'/'<<tong[1]<<endl; cout<<"Phan so Tich = "<<tich[0]<<'/'<<tich[1]<<endl; system("PAUSE");

}

Ví dụ 2: Viết chương trình nhập vào mảng chiều gồm n phần tử kiểu số thực, in mảng vừa nhập, thống kê số phần tử dương, âm khơng có mảng

#include <cstdlib> #include <iostream> using namespace std; main()

{ float a[50];

(55)

cout<<"Nhap so phan tu cua mang: "; cin>>n;

for (i = 0; i < n; i++) {

cout<<"a["<<i<<"] = "; cin>>a[i];

}

cout<<"Mang vua nhap la:"<<endl; for (i = 0; i < n; i++)

cout<<a[i]<<'\t'; cout<<endl;

sd = sa = s0 = 0;

for (i = 0; i < n; i++) {

if (a[i] > ) sd++;

else if (a[i] < ) sa++; else s0++;

}

cout << "So so duong = "<<sd<<endl; cout << "So so am = "<<sa<<endl; cout << "So so khong = "<<s0<<endl; system("PAUSE");

}

Ví dụ 3: Viết chương trình nhập vào mảng chiều gồm n phần tử kiểu số nguyên In mảng vừa nhập Cho biết có phần tử có nội dung lẻ Tính tổng phần tử bội số k, với k nhập từ bàn phím Cho biết phần tử x xuất vị trí thứ mấy, với x nhập từ bàn phím Sắp xếp mảng theo thứ tự tăng dần In mảng sau xếp

#include <cstdlib> #include <iostream> using namespace std; main()

(56)

int n, i, j, d, s, k, x, tam;

//Nhap va kiem tra so phan tu cua mang

{

cout<<"Nhap so phan tu n = "; cin>>n;

} while (n <= || n > 20); //Nhap mang

for (i = 0; i < n; i++) {

cout<<"Nhap phan tu thu "<<i+1<<" : "; cin>>a[i];

}

//In mang vua nhap

cout<<"Mang vua nhap la :"<<endl; for (i = 0; i < n; i++)

cout<<a[i]<<'\t'; cout<<endl;

//Dem so phan tu co noi dung la le d = 0;

for (i = 0; i < n; i++)

if(a[i]%2 != 0) d++;

cout<<"Co "<<d<<" phan tu co noi dung la le"<<endl; //Tinh tong cac phan tu la boi so cua k

cout<<"Nhap k = "; cin>>k;

s = 0;

for (i = 0; i < n; i++) if (a[i]%k == 0)

s = s + a[i];

(57)

//Xac dinh vi tri xuat hien dau tien cua x cout<<"Nhap x : ";

cin>>x; i = 0;

while (i < n && a[i]!= x) i++;

if (i < n) {

cout<<"Phan tu "<<x<<" xuat hien dau tien"; cout<<" o vi tri thu "<<i<<endl;

} else

cout<<"Khong co phan tu "<<x<<" mang"<<endl; //Sap xep mang theo thu tu tang dan

for (i = 0; i < n-1; i++)

for (j = i+1; j < n; j++)

if (a[i] > a[j])

{

tam = a[i];

a[i] = a[j];

a[j] = tam;

}

//In mang sau sap xep

cout<<"Mang sau sap xep tang dan la :"<<endl; for (i = 0; i < n; i++)

cout<<a[i]<<'\t'; cout<<endl;

system("PAUSE"); }

(58)

#include <cstdlib> #include <iostream> using namespace std; main()

{

float a[20], x, y, max, tich; int n, i, j, vt;

//Nhap va kiem tra so phan tu cua mang

{

cout<<"Nhap so phan tu n = "; cin>>n;

} while (n <= || n > 20); //Nhap mang

for (i = 0; i < n; i++) {

cout<<"Nhap phan tu thu "<<i+1<<" : "; cin>>a[i];

}

//In mang vua nhap

cout<<"Mang vua nhap la :"<<endl; for (i = 0; i < n; i++)

cout<<a[i]<<'\t'; cout<<endl;

//Them phan tu vao vi tri vt

cout<<"Nhap phan tu can them : "; cin>>x;

do {

cout<<"Nhap vi tri can them : "; cin>>vt;

(59)

for (i = n - 1; i >= vt; i )

a[i+1] = a[i];

a[vt] = x; n = n + 1;

cout<<"Mang vua them la : "<<endl; for (i = 0; i < n; i++)

cout<<a[i]<<'\t'; cout<<endl;

//Tim phan tu lon nhat xuat hien sau cung max = a[0];

for (i = 1; i < n; i++)

if (max < a[i]) max = a[i];

i = n - 1;

while (a[i] != max)

i ;

cout<<"Vi tri xuat hien sau cung cua "; cout<<"phan tu lon nhat la : "<<i<<endl;

//Tinh tich cac phan tu duong o vi tri le tich = 1;

for (i = 0; i < n; i++)

if (i % != && a[i] > 0)

tich = tich * a[i];

cout<<"Tich cac phan tu duong nam o cac vi tri le "; cout<<"la : "<<tich<<endl;

//Xoa tat ca cac phan tu co noi dung la y cout<<"Nhap phan tu can xoa : ";

cin>>y; i = 0;

while (i <= n - 1)

if (a[i] == y)

{

(60)

a[j] = a[j + 1];

n ;

}

else i = i + 1;

cout<<"Mang sau xoa la : "<<endl; for (i = 0; i < n; i++)

cout<<a[i]<<'\t'; cout<<endl;

system("PAUSE"); }

3.2 MẢNG NHIỀU CHIỀU 3.2.1 Giới thiệu

Để thuận tiện việc biểu diễn loại liệu phức tạp ma trận bảng biểu có nhiều tiêu, C++ đưa kiểu liệu mảng nhiều chiều Tuy nhiên, việc sử dụng mảng nhiều chiều khó lập trình giáo trình bàn đến mảng hai chiều Đối với mảng chiều m phần tử, phần tử lại mảng chiều n phần tử ta gọi mảng hai chiều với số phần tử (hay kích thước) chiều m n Ma trận minh họa cho hình ảnh mảng hai chiều, gồm m hàng n cột, tức chứa m x n phần tử, hiển nhiên phần tử có kiểu liệu Tuy nhiên, mặt chất mảng hai chiều tập hợp với m x n phần tử kiểu mà tập hợp với m thành phần, thành phần mảng chiều với n phần tử

0

0

Hình minh họa hình thức mảng hai chiều với hàng, cột Thực chất nhớ tất 12 phần tử mảng liên hàng mảng minh họa hình

hàng hàng hàng

(61)

3.2.2 Khai báo

<kiểu phần tử> <tên mảng> [m][n]; - m số hàng, n số cột mảng

- kiểu phần tử kiểu m x n phần tử mảng

- Trong khai báo khởi tạo dãy hàng giá trị, hàng cách dấu phẩy, hàng bao cặp ngoặc { } toàn giá trị khởi tạo nằm cặp dấu { }

3.2.3 Sử dụng

- Tương tự mảng chiều chiều mảng đánh số từ

- Không sử dụng thao tác toàn mảng mà phải thực thông qua phần tử mảng

- Để truy nhập phần tử mảng ta sử dụng tên mảng kèm theo số vị trí hàng cột phần tử Các số biểu thức thực C++ tự chuyển kiểu sang nguyên

Ví dụ:

- Khai báo ma trận A, B gồm hàng cột chứa số nguyên: int A[2][3], B[2][3];

- Khai báo có khởi tạo:

int A[2][3] = {{1, 2, 3, 4},{3, 2, 1, 4},{0, 1, 1, 0}}; với khởi tạo ta có ma trận:

0

0 1 2 3 4

1 3 2 1 4

2 0 1 1 0

Trong đó: A[0][0] = 1, A[0][1] = 2, A[1][0] = 3, A[2][3] = 0, …

Trong khai báo vắng số hàng (không vắng số cột), số hàng xác định thơng qua khởi tạo

Ví dụ: float A[][3] = {{1, 2, 3}, {0, 1, 0}}; khai báo chương trình tự động xác định số hàng

- Phép khai báo khởi tạo sau hợp lệ:

(62)

Với khai báo NNLT xác định số hàng số cột (bắt buộc phải khai báo) khởi tạo xác định số cột Các phần tử chưa khởi tạo chưa xác định nhập gán giá trị cụ thể Trong ví dụ phần tử A[0][2], A[1][1] A[1][2] chưa xác định

3.2.4 Ví dụ minh họa

Ví dụ 1: Viết chương trình nhập vào ma trận m hàng, n cột, phần tử kiểu số thực, in ma trận vừa nhập, cho biết giá trị nhỏ lớn phần tử ma trận #include <cstdlib>

#include <iostream> using namespace std; main()

{

float a[10][10], max, min; int m, n, i, j;

cout<<"Nhap so hang va so cot: "; cin>>m>>n;

//Nhap ma tran

for (i = 0; i < m; i++) for (j = 0; j < n; j++) {

cout<<"a["<<i<<","<<j<<"] = "; cin>>a[i][j];

}

//In ma tran

for (i = 0; i < m; i++) {

for (j = 0; j < n; j++) cout<<a[i][j]<<'\t'; cout<<endl;

}

(63)

for (i = 0; i < m; i++) for (j = 0; j < n; j++) {

if (max < a[i][j]) max = a[i][j]; if (min > a[i][j]) = a[i][j]; }

cout<<"Phan tu lon nhat la "<<max<<'\n'; cout<<"Phan tu nho nhat la "<<min<<'\n'; system("PAUSE");

}

Ví dụ 2: Viết chương trình nhập vào ma trận a gồm m hàng, n cột, phần tử kiểu số nguyên In ma trận vừa nhập Cho biết ma trận có phần tử số phương Tính tích phần tử khác nằm cột c, với c nhập từ bàn phím Sắp xếp phần tử nằm hàng h theo thứ tự giảm dần, với h nhập từ bàn phím In ma trận sau xếp

#include <cstdlib> #include <iostream> #include <math.h> using namespace std; main()

{

int a[10][10];

int m, n, i, j, d, c, h, tam; long t;

//Nhap va kiem tra so hang, so cot

{

cout<<"Nhap so hang va so cot : "; cin>>m>>n;

}

while (m<0 || m>=10 || n<0 || n>=10); //Nhap ma tran

(64)

for (j=0; j<n; j++) {

cout<<"Nhap a["<<i<<","<<j<<"]= "; cin>>a[i][j];

}

//In ma tran

for (i=0; i<m; i++) {

for (j=0; j<n; j++)

cout<<a[i][j]<<'\t'; cout<<endl;

}

//Dem so phan tu la so chinh phuong d=0;

for (i=0; i<m; i++) for (j=0; j<n; j++)

if (sqrt(a[i][j])==(int)sqrt(a[i][j])) d++;

cout<<"Trong ma tran co "<<d;

cout<<" phan tu la so chinh phuong"<<endl; //Nhap va tinh tich cac phan tu tren cot c

{

cout<<"Nhap cot can tinh tich : "; cin>>c;

}

while (c<0 || c>=n); t=1;

for (i=0; i<m; i++) if (a[i][c]!=0)

t=t*a[i][c];

(65)

cout<<" la: "<<t<<endl;

//Nhap va sap xep giam dan cac phan tu tren hang h

{

cout<<"Nhap hang can sap xep : "; cin>>h;

}

while (h<0 || h>=m); for (i=0; i<n-1; i++)

for (j=i+1; j<n; j++) if (a[h][i]<a[h][j]) {

tam=a[h][i]; a[h][i]=a[h][j]; a[h][j]=tam; }

//In ma tran sau sap xep} for (i=0; i<m; i++)

{

for (j=0; j<n; j++)

cout<<a[i][j]<<'\t'; cout<<endl;

}

system("PAUSE"); }

Ghi chú: Khi làm việc với ma trận thói quen thường tính số từ (thay 0), ma trận ta bỏ qua hàng 0, cột cách khai báo số hàng cột tăng lên so với số hàng, cột thực tế ma trận từ làm việc từ hàng 1, cột trở

(66)

#include <cstdlib> #include <iostream> using namespace std; main()

{

float a[11][11]; int n, i, j, d; float s, min;

{

cout<<"Nhap so hang va so cot : "; cin>>n;

} while (n<=0 || n>10); for (i=1; i<=n; i++) for (j=1; j<=n; j++)

{

cout<<"Nhap a["<<i<<","<<j<<"]= "; cin>>a[i][j];

}

for (i=1; i<=n; i++) {

for (j=1; j<=n; j++) cout<<a[i][j]<<" "; cout<<endl;

} d=0;

for (i=1; i<=n; i++) for (j=1; j<=n; j++)

if (int(a[i][j])%2==0) d++;

(67)

cout<<"Cac phan tu nam tren duong cheo chinh : "; for (i=1; i<=n; i++)

cout<<a[i][i]<<'\t'; cout<<endl;

s=0;

for (i=1; i<=n; i++) for (j=1; j<=n; j++)

if (i+j == n+1) s += a[i][j];

cout<<"Tong cac p.tu nam tren duong cheo phu "; cout<<"la :"<<s<<endl;

for (i=1; i<=n; i++) {

for (j=1; j<=n; j++)

if (i==1 || i==n || j==1 || j==n) cout<<a[i][j]<<" ";

else cout<<" "; cout<<endl;

}

min=a[1][1];

for (i=1; i<=n; i++) for (j=1; j<=n; j++)

if (min>a[i][j]) min=a[i][j];

cout<<"Cac p.tu nho nhat nam o cac vi tri : "<<endl; for (i=1; i<=n; i++)

for (j=1; j<=n; j++) if (a[i][j] == min)

cout<<"Hang "<<i<<" Cot "<<j<<endl; system("PAUSE");

(68)

BÀI TẬP CHƯƠNG 3

- -

1 Viết chương trình nhập vào mảng chiều gồm n phần tử kiểu số nguyên In mảng vừa nhập theo thứ tự ngược Cho biết có phần tử có nội dung số ngun tố Tính tích phần tử ước số k, với k nhập từ bàn phím Cho biết phần tử X xuất lần thứ m vị trí thứ mấy, với X m nhập từ bàn phím Sắp xếp mảng theo thứ tự giảm dần In mảng sau xếp

2 Viết chương trình nhập vào mảng chiều có số phần tử nội dung phần tử kiểu số thực Tạo mảng thứ tổng dãy (c[ i ] = a[ i ] + b[ i ]) in dãy vừa tạo

3 Viết chương trình nhập vào mảng chiều có số phần tử nội dung phần tử kiểu boolean In mảng vừa nhập hàng khác Tạo mảng thứ kết việc thực phép toán AND phần tử mảng nhập Tạo mảng thứ kết việc thực phép toán OR phần tử mảng nhập In mảng vừa tạo hàng khác

4 Viết chương trình thực cơng việc sau:

- Nhập mảng chiều gồm n phần tử kiểu số nguyên

- In mảng vừa nhập

- In vị trí phần tử lớn có dãy

- Tính trị trung bình phần tử dương có dãy

- Đếm số phần tử lũy thừa K, với K nhập từ bàn phím

5 Viết chương trình thực cơng việc sau:

- Nhập mảng chiều gồm n phần tử kiểu số nguyên

- In phần tử nằm vị trí chẵn

- Kiểm tra xem dãy có thứ tự hay khơng?

- Kiểm tra xem dãy có đối xứng khơng?

- Tạo mảng copy từ mảng nhập gồm M phần tử phần

tử thứ K, với M K nhập từ bàn phím

- In mảng vừa tạo

(69)

7 Viết chương trình nhập vào ma trận vng cấp n, phần tử kiểu ký tự In ma trận vừa nhập Cho biết ma trận có ký tự ‘T’ In phần tử nằm đường chéo phụ Cho biết ký tự lớn nằm đường chéo Cho biết ma trận có hàng có thứ tự tăng dần khơng?

8 Viết chương trình nhập vào ma trận vng cấp n, phần tử kiểu số nguyên In ma trận vừa nhập In phần tử nằm đường đường biên ma trận Cho biết phần tử nhỏ nằm vị trí Cho biết hàng có tổng phần tử lớn Tính giá trị trung bình tất phần tử dương có ma trận

9 Viết chương trình nhập vào ma trận gồm m hàng, n cột, phần tử kiểu số nguyên Tạo ma trận thứ ma trận tổng ma trận vừa nhập Tạo ma trận thứ ma trận hiệu ma trận vừa nhập

(70)

CHƯƠNG 4: DỮ LIỆU KIỂU CHUỖI

- -

4.1 GIỚI THIỆU

Một chuỗi ký tự dãy ký tự (kể dấu cách) lưu mảng với phần tử chứa ký tự Tuy nhiên để máy nhận biết mảng ký tự chuỗi, cần thiết phải có ký tự kết thúc chuỗi, theo qui ước ký tự có mã (tức '\0') vị trí mảng Khi chuỗi dãy ký tự phần tử (thứ 0) đến ký tự kết thúc chuỗi (khơng kể ký tự cịn lại mảng)

Ví dụ:

0

H E L L O \0

H E L \0

\0

Ví dụ minh họa chuỗi, chuỗi chứa mảng ký tự có độ dài tối đa Nội dung chuỗi thứ "HELLO" có độ dài thực ký tự, chiếm ô mảng (thêm ô chứa ký tự kết thúc '\0') Chuỗi thứ hai có nội dung "HEL" với độ dài (chiếm ô) chuỗi cuối biểu thị chuỗi rỗng (chiếm ô) Chú ý mảng ký tự khai báo với độ dài nhiên chuỗi chiếm số ký tự mảng tối đa ký tự

4.2 KHAI BÁO

char <tên chuỗi>[độ dài] ; // không khởi tạo char <tên chuỗi>[độ dài] = chuỗi ký tự ; // có khởi tạo char <tên chuỗi>[] = chuỗi ký tự ; // có khởi tạo

- Độ dài chuỗi số ký tự tối đa có chuỗi Độ dài thực chuỗi tính từ đầu chuỗi đến dấu kết thúc chuỗi (không kể dấu kết thúc chuỗi ‘\0’)

- Do chuỗi phải có dấu kết thúc chuỗi nên khai báo độ dài chuỗi cần phải khai báo thừa phần tử Thực chất độ dài tối đa chuỗi = độ dài mảng -

Ví dụ: Nếu muốn khai báo mảng s chứa chuỗi có độ dài tối đa 80 ký tự, ta cần phải

khai báo char s[81];

- Cách khai báo thứ hai có kèm theo khởi tạo chuỗi, dãy ký tự đặt cặp dấu nháy kép

Ví dụ: char hoten[40]; // chuỗi họ tên chứa tối đa 39 ký tự char monhoc[31] = "NNLT C++" ;

(71)

- Cách khai báo thứ tự chương trình định độ dài mảng chuỗi khởi tạo (bằng độ dài chuỗi + 1)

Ví dụ: char thang[] = "Muoi hai" ; // độ dài mảng = + = 4.3 CÁCH SỬ DỤNG

Tương tự mảng liệu khác, chuỗi ký tự có đặc trưng mảng, nhiên chúng có điểm khác biệt Dưới điểm giống khác chuỗi ký tự mảng thông thường

- Truy cập ký tự chuỗi: cú pháp giống mảng

Ví dụ:

char s[50] = "I\'m a student"; // ký tự ' phải viết \' cout << s[0]; // in ký tự đầu tiên, tức ký tự 'I'

s[1] = 'a'; // đặt lại ký tự thứ 'a'

- Khơng thực phép tốn trực tiếp chuỗi phép gán, phép so sánh

Ví dụ:

char s[20] = "Hello", t[20] ;

t = "Hello" ; // ISO C++ forbids assignment of arrays

t = s ; // ISO C++ forbids assignment of arrays

if (s < t) cout<<"s nho hon t"; //khong bao loi nhung else cout<<"s khong nho hon t"; //cho ket qua sai - Toán tử nhập liệu >> dùng có nhiều hạn chế

Ví dụ:

char s[60];

cout << "Nhap chuoi s : "; cin >> s;

cout << s;

Nếu chuỗi nhập vào "Tin hoc" chẳng hạn tốn tử >> nhập "Tin" cho s (bỏ tất ký tự đứng sau dấu trắng), in hình có từ "Tin" 4.4 PHƯƠNG THỨC NHẬP CHUỖI

Do tốn tử nhập >> có nhiều hạn chế việc nhập chuỗi ký tự nên C++ người ta thường sử dụng hàm (còn gọi phương thức) cin.getline(s, n) để nhập chuỗi ký tự

(72)

NSD nhập liệu (dãy ký tự) vào từ bàn phím NSD nhập vào dãy với độ dài nhấn Enter, chương trình lấy n-1 ký tự gán cho s, phần lại bị bỏ qua (nếu chuỗi nhập có nhiều n-1 ký tự) Hiển nhiên, sau gán ký tự cho s, chương trình tự động đặt ký tự kết thúc chuỗi vào ô chuỗi

Ví dụ: Xét đoạn lệnh sau: char s[10];

cin.getline(s, 10); cout << s << endl;

Giả sử ta nhập vào bàn phím hàng ký tự: 1234567890abcd↵ Khi lệnh cin.getline(s, 10) gán chuỗi "123456789" (9 ký tự) cho s, phần lại bị bỏ qua, s in hình Như hình xuất kết là:

123456789

4.5 MỘT SỐ HÀM XỬ LÝ CHUỖI 4.5.1 Hàm strcpy(s, t)

Gán nội dung chuỗi t cho chuỗi s (thay cho phép gán “=” không sử dụng) Hàm chép toàn nội dung chuỗi t (kể ký tự kết thúc chuỗi) vào cho chuỗi s Để sử dụng hàm cần đảm bảo độ dài chuỗi s độ dài chuỗi t Trong trường hợp ngược lại ký tự kết thúc chuỗi không ghi vào s điều gây treo máy thực thi chương trình

Ví dụ:

char s[10], t[10]; strcpy(t, "Face"); strcpy(s, t);

cout << s << " to " << t << endl; 4.5.2 Hàm strncpy(s, t, n)

Sao chép n ký tự t vào s Hàm làm nhiệm vụ chép, không tự động gắn ký tự kết thúc chuỗi cho s Do NSD phải thêm câu lệnh đặt ký tự '\0' vào cuối chuỗi s sau chép xong

Ví dụ:

char s[10], t[10] = "Steven"; strncpy(s, t, 5);

s[5] = '\0';

(73)

 Nếu ta muốn chép n ký tự tính từ ký tự thứ k t vào s ta sử dụng hàm strncpy(s, t+k, n)

Ví dụ:

char s[10], t[10] = "Steven"; strncpy(s, t+2, 4);

s[4] = '\0';

cout << s << endl; // in la: even 4.5.3 Hàm strcat(s, t)

Ghép (nối) t vào sau s (thay cho phép +) Hiển nhiên hàm loại bỏ ký tự kết thúc chuỗi s trước ghép t vào Việc nối đảm bảo lấy ký tự kết thúc chuỗi t vào cho s (nếu s đủ chỗ) Vì NSD khơng cần thêm ký tự vào cuối chuỗi Tuy nhiên, hàm không kiểm tra xem liệu độ dài s có đủ chỗ để ghép thêm t hay không, việc kiểm tra phải NSD đảm nhiệm

Ví dụ 1:

char a[40] = "Thanh", b[5] = "Minh"; strcat(a, " va ");

strcat(a, b);

cout << a << endl;

Hai câu lệnh gọi hàm strcat gom chung lại thành câu lệnh sau: strcat(strcat(a, " va "), b);

Ví dụ 2:

char s[10], t[10] = "Steve"; strncpy(s, t, 3);

s[3] = '\0'; strcat(s, "p");

cout << t << " goes "<< s << " by " << s << endl; 4.5.4 Hàm strncat(s, t, n)

Ghép n ký tự chuỗi t vào sau chuỗi s Hàm tự động đặt thêm dấu kết thúc chuỗi vào s sau ghép xong (tương phản với strncpy()) Cũng giống hàm strcat hàm đòi hỏi độ dài s phải đủ chứa kết Tương tự, sử dụng cách viết strncat(s, t+k, n) để ghép n ký tự từ vị trí thứ k chuỗi t cho s

Ví dụ:

char s[20] = "Khoa ";

(74)

strncat(s, t, 9); // s = "Khoa cong nghe" strcpy(s,"Khoa ");

strncat(s, t+10, 9); // s = "Khoa thong tin" 4.5.5 Hàm strcmp(s, t)

Hàm so sánh chuỗi s t (thay cho phép toán so sánh) Giá trị trả hiệu ký tự khác s t Từ đó, s < t hàm trả giá trị -1, s==t hàm trả giá trị 0, s > t hàm trả giá trị

Tiêu chí để so sánh số nguyên tương ứng bảng mã ASCII Vì hàm có phân biệt chữ hoa chữ thường (tức ‘A’ khác với ‘a’) ‘A’ < ‘a’ (vì 65 < 97) Trong trường hợp quan tâm đến so sánh bằng, hàm trả giá trị là chuỗi giá trị trả khác chuỗi khác

Ví dụ:

char s[] = "Ha Noi" , t[] = "ha noi" ; cout << strcmp(s, t)<<endl; // in -1 strcpy(s, "VIET NAM");

strcpy(t, s);

cout << strcmp(s, t)<<endl; // in strcpy(s, "THONG TIN");

strcpy(t, "CONG NGHE");

cout << strcmp(s, t)<<endl; // in 4.5.6 Hàm strncmp(s, t, n)

Giống hàm strcmp(s, t) so sánh tối đa n ký tự hai chuỗi

Ví dụ:

char s[] = "Ha Noi" , t[] = "Ha noi" ; cout << strcmp(s, t)<<endl; // in -1 cout << strncmp(s, t, 3)<<endl; // in 4.5.7 Hàm strcmpi(s, t)

Giống hàm strcmp(s, t) khơng phân biệt chữ hoa, thường Ví dụ:

char s[] = "Ha Noi" , t[] = "ha noi" ; cout << strcmpi(s, t)<<endl; // in 4.5.8 Hàm strupr(s)

(75)

Ví dụ:

char s[10] = "Ha Noi";

cout << s << endl; // Ha Noi

cout << strupr(s) << endl; // HA NOI

cout << s << endl; // HA NOI (s cung thay doi) 4.5.9 Hàm strlwr(s)

Hàm đổi chuỗi s thành in thường, kết trả chuỗi in thường

Ví dụ:

char s[10] = "Ha Noi";

cout << s << endl; // Ha Noi

cout << strlwr(s) << endl; // noi

cout << s << endl; // noi (s cung thay doi) 4.5.10 Hàm strlen(s)

Hàm trả giá trị độ dài thực chuỗi s

Ví dụ:

char s[10] = "Ha Noi";

cout << strlen(s) << endl; // in 4.6 CÁC CHƯƠNG TRÌNH ỨNG DỤNG

4.6.1 Chương trình

Viết chương trình nhập vào chuỗi bất kỳ, thống kê số chữ cái, số chữ số, số khoảng trắng có chuỗi

#include <cstdlib> #include <iostream> using namespace std; main()

{ char s[100];

int i, cd, dc, ds, dt; dc=ds=dt=0;

cout<<"Nhap vao chuoi khong qua 99 ky tu:"; cin.getline(s, 100);

(76)

for(i=0; i<cd; i++)

if(isalpha(s[i])) dc++;

else if(isdigit(s[i])) ds++; else if (int(s[i])==32) dt++;

cout<<"Trong chuoi co "<<dc<<" chu cai, ";

cout<<ds<<" chu so va "<<dt<<" khoang trang"<<endl; system("pause");

}

4.6.2 Chương trình

Viết chương trình nhập vào mật (khơng q 12 ký tự) In "Đúng Mời vào!" "VinhLong2013", "Sai Nhập lại!" ngược lại chưa hết hết số lần thử, hết số lần thử in “Bạn hết quyền nhập mật khẩu!” Chương trình cho phép nhập tối đa lần Nhập riêng rẽ ký tự (bằng hàm getch()) cho mật Hàm getch() không ký tự NSD nhập vào mà thay vào chương trình hiển thị ký tự 'X' để che giấu mật

#include <cstdlib> #include <iostream> #include <conio.h> using namespace std; main()

{ char pw[13], kt;

int i, solan = 0; //Cho phep nhap lan

{ cout<<"Nhap mat khau vao:"; i = 0;

{

kt=getch();

if(kt != 13) pw[i]=kt; else pw[i]= '\0';

cout<<'X' ; i++;

(77)

cout<<endl;

if (strcmp(pw, "VinhLong2013")==0) {

cout<<"Dung roi Moi vao!"<<endl; break;

} else {

solan++ ; if(solan < 3)

cout<<"Sai roi Nhap lai!"<<endl; }

} while (solan < 3); if (solan == 3)

cout<<"Ban da het quyen nhap mat khau!"<<endl; system("pause");

}

4.6.3 Chương trình

Viết chương trình nhập vào chuỗi bất kỳ, cho biết chuỗi có ký tự khơng phải chữ Đổi tất chữ thành dạng chuẩn Upper (toàn ký tự hoa) Cho biết chuỗi chữ số xuất nhiều chúng xuất lần

#include <cstdlib> #include <iostream> using namespace std; main()

{

char st[100];

int i, max, dkt=0, a[10]; cout<<"Nhap chuoi:";

cin.getline(st,100);

for (i=0; i<strlen(st); i++)

(78)

cout<<"Co "<<dkt<<" ky tu khong phai la chu cai"<<endl; for (i=0; i<strlen(st); i++)

if (islower(st[i])) st[i]=toupper(st[i]); cout<<"Chuoi sau doi la:"<<endl;

cout<<st<<endl;

for (i=0; i<=9; i++) a[i]=0;

for (i=0; i<strlen(st); i++) if (isdigit(st[i]))

a[(int)st[i]-48]=a[(int)st[i]-48]+1; max=a[0];

for (i=0; i<=9; i++)

if (max<a[i]) max=a[i];

cout<<"Cac chu so xuan hien nhieu nhat la: "; for (i=0; i<=9; i++)

if (a[i]==max) cout<<i<<'\t';

cout<<"\nChung xuat hien "<<max<<" lan."<<endl; system("pause");

}

4.6.4 Chương trình

Viết chương trình nhập vào họ tên người, kiểm tra tính hợp lệ họ tên nhập (chỉ gồm chữ khoảng trắng khơng tồn khoảng trắng), cắt bỏ khoảng trắng thừa đầu cuối, cho biết họ tên có ký tự kt với kt nhập từ bàn phím, in tên người

#include <cstdlib> #include <iostream> using namespace std; main()

{ char ht[40], ten[10], tam[40], kt; int i, dc, dt, dkt;

(79)

dc=dt=0;

for (i=0; i<strlen(ht); i++) if (isalpha(ht[i])) dc++; else if (ht[i]==' ')dt++; } while (dc+dt!=strlen(ht) || dc==0); i=0;

while (ht[i]==' ') i++; strcpy(tam, "");

strncpy(tam, ht+i, strlen(ht)); tam[strlen(ht)-i]='\0';

i=strlen(tam)-1;

while (tam[i]==' ') i ; strcpy(ht,"");

strncpy(ht, tam, i+1); ht[i+1]='\0';

cout<<"Ho ten sau cat bo khoang trang la:"; cout<<ht<<endl;

cout<<"Nhap ky tu kt:"; cin>>kt;

dkt=0;

for (i=0; i<strlen(ht); i++) if (ht[i]==kt) dkt++;

cout<<"Trong ho ten co "<<dkt<<" ky tu "<<kt<<endl; i=strlen(ht)-1;

while(ht[i]!=' ') i ;

strncpy(ten, ht+i+1, strlen(ht)-1-i); ten[strlen(ht)-1-i]='\0';

cout<<"Ten cua nguoi la:"<<ten<<endl; system("pause");

(80)

BÀI TẬP CHƯƠNG 4

- -

1 Viết chương trình nhập vào số nguyên hệ thập phân (cơ số 10), đổi số sang hệ nhị phân (cơ số 2)

2 Viết chương trình nhập vào số nguyên hệ thập phân (cơ số 10), đổi số sang hệ thập lục phân (cơ số 16)

3 Viết chương trình nhập vào số nguyên hệ bát phân (cơ số 8), đổi số sang hệ thập lục phân (cơ số 16)

4 Viết chương trình nhập vào số nguyên hệ nhị phân (cơ số 2), đổi số sang hệ bát phân (cơ số 8)

5 Viết chương trình nhập vào chuỗi, in chuỗi đảo ngược theo ký tự

Ví dụ: Nhập chuỗi ‘ABCD’  Chuỗi đảo là: ‘DCBA’

6 Viết chương trình nhập vào chuỗi, in chuỗi đảo ngược theo từ

Ví dụ: Nhập chuỗi ‘Cấm Không Được Câu Cá’

 Chuỗi đảo là: ‘Cá Câu Được Không Cấm’

7 Viết chương trình nhập vào số nguyên dương nhỏ 1000, đọc số chữ

Ví dụ: Nhập số 125  Đọc ‘Một trăm hai mươi lăm’

8 Viết chương trình nhập vào chuỗi ký số (các ký tự từ đến 9), cho biết chuỗi có dãy tăng dần, in dãy tăng dần dài có chuỗi

9 Xây dựng hàm thực chức sau: a Trả chiều dài chuỗi

b Trả vị trí chuỗi stc chuỗi st

c Trả chuỗi stc từ chuỗi st gồm num ký tự vị trí thứ pos d Trả chuỗi sau ghép chuỗi lại với

10 Xây dựng hàm thực chức sau: a Chèn chuỗi stc vào chuỗi st vị trí thứ pos b Xóa num ký tự chuỗi st vị trí thứ pos c Đổi số nguyên thành chuỗi số tương ứng

(81)

CHƯƠNG 5: CON TRỎ VÀ HÀM

- -

5.1 CON TRỎ

Biến trỏ đặc trưng mạnh C++, cho phép thâm nhập trực tiếp vào nhớ để xử lý tốn khó vài câu lệnh đơn giản chương trình 5.1.1 Ý nghĩa

- Con trỏ biến chứa địa biến khác Nếu p trỏ chứa địa biến x ta gọi p trỏ tới x x trỏ p Thơng qua trỏ ta làm việc với nội dung ô nhớ mà p trỏ đến

- Để trỏ p trỏ tới x ta phải gán địa x cho p

- Để làm việc với địa biến cần phải thông qua biến trỏ trỏ đến biến

5.1.2 Khai báo biến trỏ

<Kiểu trỏ> <*Tên biến trỏ> ; <Kiểu trỏ*> <Tên biến trỏ> ;

Địa biến địa byte nhớ biến Vì để lấy nội dung biến, trỏ phải biết số byte biến, tức kiểu biến mà trỏ trỏ tới Kiểu gọi kiểu trỏ Như khai báo biến trỏ giống khai báo biến thường ngoại trừ cần thêm dấu * trước tên biến (hoặc sau tên kiểu)

Ví dụ:

int *p ; // khai báo biến p biến trỏ trỏ đến kiểu số nguyên float *q, *r ; // khai báo trỏ thực q r

5.1.3 Cách sử dụng

- Để trỏ p trỏ đến biến x ta phải dùng phép gán p = địa x Nếu x khơng phải biến mảng ta viết: p = &x Cịn x biến mảng ta viết: p = x p = &x[0] - Ta gán p cho địa cụ thể Chẳng hạn ta viết p = 200 sai

- Phép toán * cho phép lấy nội dung nơi p trỏ đến, ví dụ để gán nội dung nơi p trỏ đến cho biến f ta viết f = *p

- Phép toán & phép toán * phép toán ngược Cụ thể p = &x x = *p Từ p trỏ đến x nơi xuất x thay *p ngược lại

Ví dụ 1:

(82)

using namespace std; main()

{

int i, j; // khai báo biến nguyên i, j

int *p, *q; // khai báo trỏ nguyên p, q p = &i; // cho p trỏ tới i

q = &j; // cho q trỏ tới j

cout << &i; // hỏi địa biến i

cout << q; // hỏi địa biến j (thông qua q) i = 2; // gán i

*q = 5; // gán j (thông qua q)

i++ ; cout << i; // tăng i in i =

(*q)++ ; cout << j;// tăng j (thông qua q) in j = (*p) = (*q) * + 1; // gán lại i (thông qua p)

cout << i; // i = 13 system("pause"); }

Qua ví dụ ta thấy thao tác với i tương đương với *p, với j tương đương với *q ngược lại

5.1.4 Các phép toán với trỏ 5.1.4.1 Phép toán gán

- Gán trỏ với địa biến: p = &x ;

- Gán trỏ với trỏ khác: p = q ; (sau phép toán gán p, q chứa địa hay trỏ đến nơi)

Ví dụ 2:

#include <cstdlib> #include <iostream> using namespace std; main()

{

(83)

p = q = r = &i; *p = *q + 3; *q = *r * 2;

cout << i << endl; system("pause"); }

5.1.4.2 Phép toán tăng, giảm địa

p ± n: trỏ trỏ đến thành phần thứ n sau (trước) p

Một đơn vị tăng giảm trỏ kích thước biến trỏ

Ví dụ: Giả sử p trỏ nguyên (2 bytes) trỏ đến địa 200 p+1 trỏ trỏ đến địa 202; tương tự, p + trỏ trỏ đến địa 210; p − chứa địa 194

194 195 196 197 198 199 200 201 202

p − p p +

Như vậy, phép toán tăng, giảm trỏ cho phép làm việc thuận lợi mảng Nếu trỏ trỏ đến mảng (tức chứa địa mảng), việc tăng trỏ lên đơn vị dịch chuyển trỏ trỏ đến phần tử thứ hai, tiếp tục Từ ta cho trỏ chạy từ đầu đến cuối mảng cách tăng trỏ lên đơn vị câu lệnh for ví dụ

Ví dụ 3:

#include <cstdlib> #include <iostream> using namespace std; main()

{

int a[10] = { 1, 2, 3, 4, 5, 6, }, *p, *q; p = a; // cho p trỏ đến mảng a

cout << *p ; // *p = a[0] = p += 5;

cout << *p ; // *p = a[5] = q = p - ;

(84)

for (int i = 0; i < 10; i++)

cout << *(p + i) << ‘\t’ ; // in toàn mảng a system("pause");

}

5.1.4.3 Phép toán tự tăng, tự giảm

p++, p , ++p, p: Tương tự p + p - 1, có ý đến tăng (giảm) trước, sau

Ví dụ sau minh họa kết kết hợp phép tự tăng, tự giảm với việc lấy giá trị nơi trỏ trỏ đến a mảng gồm số, p trỏ trỏ đến mảng a

Ví dụ 4:

#include <cstdlib> #include <iostream> using namespace std; main()

{

int a[2] = {3, 7}, *p = a;

cout << (*p)++ << endl; // in cout << *p << endl; // in cout << ++(*p) << endl; // in cout << *p << endl; // in cout << *(p++) << endl; // in cout << *p << endl; // in system("pause");

}

 Chú ý: Ta phải phân biệt p + p++ (hoặc ++p):

- p + xem trỏ khác với trỏ p Con trỏ p + trỏ đến phần tử sau p - p++ trỏ p trỏ đến phần tử khác Con trỏ p++ trỏ đến phần tử đứng sau phần tử p trỏ đến ban đầu

5.1.4.4 Phép hiệu trỏ

Phép toán thực p q trỏ trỏ đến phần tử dãy liệu nhớ (chẳng hạn trỏ đến mảng liệu)

(85)

Ví dụ:

Giả sử p q trỏ số nguyên có kích thước bytes, p có địa 200 q có địa 208 Khi p - q = - q - p = (4 số phần tử nguyên từ địa 200 đến 208) 5.1.4.5 Phép toán so sánh

Các phép toán so sánh áp dụng đối số với trỏ, thực chất so sánh địa hai nơi trỏ trỏ Thông thường phép so sánh <, <=, >, >= áp dụng cho hai trỏ trỏ đến phần tử mảng liệu Thực chất phép so sánh so sánh số phần tử trỏ trỏ

Ví dụ 5:

#include <cstdlib> #include <iostream> using namespace std; main()

{

float a[5] = {1, 2, 3, 4, 5}, *p, *q;

p = a; // p trỏ đến mảng (tức p trỏ đến a[0])

q = &a[3]; // q trỏ đến phần tử thứ (a[3]) mảng cout << (p < q) << endl; // in (true)

cout << (p + == q) << endl; // in (true) cout << (p > q - 1) << endl; // in (false) cout << (p >= q - 2) << endl; // in (false) for (p = a ; p < a + 5; p++)

cout << *p << '\t'; // in toàn mảng a cout << endl;

system("pause"); }

5.1.5 Cấp phát động, toán tử cấp phát thu hồi vùng nhớ 5.1.5.1 Cấp phát động

(86)

trong suốt trình chạy chương trình)

Ví dụ ta khai báo mảng nguyên chứa 1000 phần tử nhớ có vùng nhớ liên tục 2000 bytes để chứa liệu mảng Khi dù chương trình ta nhập vào mảng làm việc với vài phần tử phần mảng rỗi cịn lại khơng sử dụng vào việc khác Đây hạn chế thứ kiểu mảng Ở hướng khác, lần chạy chương trình ta lại cần làm việc với 1000 số nguyên Khi vùng nhớ mà chương trình dịch dành cho mảng khơng đủ để sử dụng Đây hạn chế thứ hai mảng khai báo trước

Để khắc phục hạn chế kiểu mảng, không khai báo (bố trí) trước mảng liệu với kích thước cố định Kích thước cụ thể cấp phát trình chạy chương trình theo yêu cầu NSD Nhờ có đủ số ô nhớ để làm việc mà tiết kiệm nhớ, khơng dùng ta thu hồi (cịn gọi giải phóng) số nhớ để chương trình sử dụng vào việc khác Hai công việc cấp phát thu hồi thực thơng qua tốn tử new delete, để thực điều ta cần phải sử dụng biến kiểu trỏ Thông qua biến trỏ ta làm việc với địa vùng nhớ cấp phát Cách thức bố trí nhớ gọi cấp phát động

5.1.5.2 Toán tử cấp phát vùng nhớ (new)

Cú pháp:

p = new <kiểu> ; p = new <kiểu>[n] ; Với p biến trỏ

Ví dụ:

int *p;

p = new int; p = new int[10];

Khi gặp tốn tử new, chương trình tìm nhớ lượng nhớ cịn rỗi liên tục với số lượng đủ theo yêu cầu cho p trỏ đến địa (byte đầu tiên) vùng nhớ Nếu khơng có vùng nhớ với số lượng việc cấp phát thất bại p = NULL (NULL địa rỗng, khơng xác định) Do ta kiểm tra việc cấp phát có thành cơng hay khơng thơng qua việc kiểm tra trỏ p hay khác NULL

Ví dụ 6:

(87)

main() {

float *p; int n;

cout << "So luong can cap phat = "; cin >> n;

p = new float[n]; if (p == NULL) {

cout << "Khong du bo nho"; exit(0);

}

system("pause"); }

 Ghi chú: Lệnh exit(0) cho phép khỏi chương trình, phiên cũ để

sử dụng lệnh ta cần khai báo file tiêu đề <process.h> 5.1.5.3 Toán tử thu hồi vùng nhớ (delete)

Để thu hồi hay giải phóng vùng nhớ cấp phát cho biến (khi không cần sử dụng nữa) ta sử dụng toán tử delete

Cú pháp: delete p ;

Với p trỏ cấp phát vùng nhớ tốn tử new

Để giải phóng tồn mảng cấp phát thơng qua trỏ p ta dùng câu lệnh: delete[] p ;

Với p trỏ trỏ đến mảng 5.1.6 Chương trình minh họa

Viết chương trình nhập vào dãy số nguyên (không dùng mảng) In dãy nhập Sắp xếp dãy tăng dần in dãy kết

(88)

#include <cstdlib> #include <iostream> using namespace std; main()

{

int *head, *p, *q, n, tam;

// head trỏ đến (đánh dấu) đầu dãy cout << "Cho biet so phan tu cua day: ";

cin >> n ;

head = new int[n] ;// cấp phát nhớ chứa n số nguyên

for (p = head; p < head + n; p++) // nhập dãy

{

cout << "Nhap p.tu thu " << p-head+1 << ": " ; cin >> *p ;

}

cout << "Day vua nhap la : " << endl; for (p = head; p < head + n; p++) cout << *p << '\t';

cout << endl;

// Sắp xếp dãy tăng dần

for (p = head; p < head + n - 1; p++) for (q = p + 1; q < head + n; q++) if (*q < *p)

{

tam = *p; *p = *q; *q = tam; }

cout << "Day sau sap xep la : " << endl; for (p = head; p < head + n; p++)

cout << *p << '\t'; cout << endl;

(89)

5.1.7 Con trỏ chuỗi ký tự

Một trỏ ký tự xem biến chuỗi ký tự, chuỗi tất ký tự kể từ byte trỏ trỏ đến byte '\0' gặp Vì ta khai báo chuỗi dạng trỏ ký tự sau:

char *s ;

char *s = "Hello" ;

Các hàm chuỗi sử dụng ta khai báo dạng mảng ký tự Bên cạnh ta phép sử dụng phép gán cho chuỗi dạng trỏ

Ví dụ:

char *s, *t = "Cong nghe thong tin";

s = t; // thay cho hàm strcpy(s, t);

Thực chất phép gán gán trỏ với nhau, cho phép s trỏ đến nơi mà t trỏ (tức dãy ký tự "Cong nghe thong tin" bố trí sẵn nhớ)

Khi khai báo chuỗi dạng trỏ chưa có nhớ cụ thể, thơng thường kèm theo khai báo ta cần phải xin cấp phát nhớ cho chuỗi với độ dài cần thiết

Ví dụ:

#include <cstdlib> #include <iostream> using namespace std; main()

{

char *s = new char[30], *t; strcpy(s, "Hello");

t = s;

cout << "Chuoi s la : " << s << endl; cout << "Chuoi t la : " << t << endl; system("pause");

}

Nếu khơng có lệnh cấp phát vùng nhớ cho t ta gán s vào t mà khơng thể gọi hàm strcpy Vì để gọi strcpy(t, s); ta cần phải có thêm câu lệnh t = new char[30];vào chương trình

Chương trình viết lại sau: #include <cstdlib>

(90)

using namespace std; main()

{

char *s = new char[30], *t; strcpy(s, "Hello");

t = new char[30];

strcpy(t, s);

cout << "Chuoi s la : " << s << endl; cout << "Chuoi t la : " << t << endl; system("pause");

}

5.2 HÀM

5.2.1 Định nghĩa

Hàm (Function) chương trình chương trình lớn Hàm nhận (hoặc khơng) đối số (tham số) trả lại (hoặc không) giá trị cho chương trình gọi Trong trường hợp không trả lại giá trị, hàm hoạt động thủ tục NNLT khác Một chương trình tập hàm, có hàm với tên gọi main(), chạy chương trình, hàm main() chạy gọi đến hàm khác Kết thúc hàm main() kết thúc chương trình

Hàm giúp cho việc phân đoạn chương trình thành mơ-đun riêng lẻ, hoạt động độc lập với ngữ nghĩa chương trình lớn, có nghĩa hàm sử dụng chương trình mà sử dụng chương trình khác, dễ cho việc kiểm tra bảo trì chương trình

5.2.2 Các đặc trưng

- Nằm ngồi văn có chương trình gọi đến hàm, văn chứa nhiều hàm

- Được gọi từ chương trình (hàm main()), từ hàm khác từ (tính đệ quy)

- Không lồng 5.2.3 Khai báo

(91)

Do đó, để sử dụng hàm này, cần có thị #include <*.h> đầu chương trình, *.h tên file cụ thể có chứa khai báo hàm sử dụng (chẳng hạn để sử dụng hàm toán học ta cần khai báo #include <math.h>) Đối số với hàm người lập trình tự viết, cần phải khai báo

Khai báo hàm sau:

<Kiểu giá trị trả về> <Tên hàm> (Danh sách đối số) ;

Trong đó, kiểu giá trị trả gọi kiểu hàm nhận kiểu chuẩn C++ kiểu người lập trình khai báo Đặc biệt hàm không trả giá trị kiểu giá trị trả khai báo void

Ví dụ:

long LapPhuong(int); int NgauNhien();

void ChuoiHoa(char[ ]); int Cong(int, int);

5.2.4 Cấu trúc chung

Cấu trúc chung hàm bố trí giống hàm main() phần trước

<Kiểu giá trị trả về> <Tên hàm> (Danh sách đối số hình thức)

{

Các khai báo cục hàm ; // dùng riêng cho hàm

Dãy lệnh hàm ; // câu lệnh xử lý

return <Biểu thức trả về> ; // nằm dãy lệnh

}

- Danh sách đối số hình thức cịn gọi ngắn gọn danh sách đối số gồm dãy đối số cách dấu phẩy, đối số biến thường, biến tham chiếu biến trỏ Mỗi đối số khai báo giống khai báo biến, tức cặp gồm <kiểu đối số> <tên đối số>

- Với hàm có trả lại giá trị cần có câu lệnh return kèm theo sau biểu thức

Kiểu giá trị biểu thức kiểu hàm khai báo phần tên hàm Câu lệnh return nằm vị trí phần dãy lệnh hàm Khi gặp câu lệnh return chương trình tức khắc khỏi hàm trả lại giá trị biểu thức sau return giá trị hàm

(92)

Ví dụ 1: Ví dụ sau định nghĩa hàm tính lập phương số nguyên n (với n nguyên) hàm đổi chuỗi dạng chuẩn upper

#include <cstdlib> #include <iostream> using namespace std; long LapPhuong(int); void ChuoiHoa(char *s); main()

{

int n;

cout<<"Nhap so nguyen n = "; cin>>n;

cout<<"Lap phuong cua "<<n<<" la : " cout<<LapPhuong(n)<<endl;

cin.ignore(1);

char *s = new char[100];

cout<<"Nhap vao chuoi bat ky : "; cin.getline(s, 100);

ChuoiHoa(s);

cout<<"Chuoi dang upper la : "<<s<<endl; system("pause");

}

long LapPhuong(int n) {

return n*n*n; }

void ChuoiHoa(char *s) {

int i;

for(i = 0; i < strlen(s); i++) s[i] = toupper(s[i]); return;

(93)

 Các ý:

- Danh sách đối số khai báo hàm chứa khơng chứa tên đối số, thông thường ta khai báo kiểu đối số không cần khai báo tên đối số, hàng định nghĩa hàm phải có tên đối số đầy đủ

- Cuối khai báo hàm phải có dấu chấm phẩy (;), cuối hàng định nghĩa hàm khơng có dấu chấm phẩy

- Hàm khơng có đối số(danh sách đối số rỗng), nhiên cặp dấu ngoặc sau tên hàm phải viết Chẳng hạn như: NgauNhien(), InTho(), …

- Một hàm khơng cần phải khai báo định nghĩa trước có hàm gọi đến

5.2.5 Lời gọi hàm

Lời gọi hàm phép xuất biểu thức, câu lệnh hàm khác … Nếu lời gọi hàm lại nằm thân hàm ta gọi đệ quy Để gọi hàm ta cần viết tên hàm danh sách giá trị cụ thể truyền cho đối số đặt cặp dấu ngoặc tròn ()

Tên hàm(danh sách đối số thực tế) ;

- Danh sách đối số (tham số) thực tế gọi danh sách giá trị gồm giá trị cụ thể để gán cho đối số hình thức hàm Khi hàm gọi thực tất vị trí xuất đối số hình thức gán cho giá trị cụ thể đối số thực tế tương ứng danh sách, sau hàm tiến hành thực câu lệnh hàm (để tính kết quả)

- Danh sách đối số thực tế truyền cho đối số hình thức có số lượng với số lượng đối số hàm truyền cho đối số theo thứ tự tương ứng Các đối số thực tế hằng, biến biểu thức Biến giá trị trùng với tên đối số Ví

dụ ta có hàm in n lần ký tự c với tên hàm inkitu(int n, char c); lời gọi

hàm inkitu(12, 'A'); n c đối số hình thức, 12 'A' đối số thực tế giá trị Các đối số hình thức n c gán giá trị tương ứng 12 'A' trước tiến hành câu lệnh phần thân hàm Giả sử

hàm in ký tự khai báo lại thành inkitu(char c, int n); lời gọi hàm

cũng phải thay lại thành inkitu('A', 12);

- Các giá trị tương ứng truyền cho đối số phải có kiểu với kiểu đối số (hoặc C++ tự động chuyển kiểu đối số)

- Khi hàm gọi, nơi gọi tạm thời chuyển điều khiển đến thực câu lệnh hàm gọi Sau kết thúc thực hàm, điều khiển lại trả thực tiếp câu lệnh sau lệnh gọi hàm nơi gọi

(94)

#include <cstdlib> #include <iostream> using namespace std;

double LuyThua(float x, int n) {

int i;

double kq = 1;

for (i = 1; i <= n; i++) kq *= x;

return kq; }

main() {

float x; double f;

cout << "Nhap x = "; cin >> x;

f = 2*LuyThua(x,3) - 5*LuyThua(x,2) - 4*x + 1; cout << "Gia tri cua ham f = " << f << endl ; system("pause");

}

5.2.6 Hàm với đối số mặc định

Trong phần trước khẳng định số lượng đối số thực tế phải số lượng đối số hình thức gọi hàm Tuy nhiên, thực tế nhiều lần hàm gọi với giá trị số đối số hình thức lặp lặp lại Trong trường hợp lúc phải viết danh sách dài đối số thực tế giống cho lần gọi công việc không thú vị Từ thực tế C++ đưa cú pháp hàm cho danh sách đối số thực tế lời gọi không thiết phải viết đầy đủ số chúng có sẵn giá trị định trước Cú pháp gọi hàm với đối số mặc định khai báo với cú pháp sau:

<Kiểu hàm> <Tên hàm>(đs1, …, đsn, đsmđ1 = gt1, …, đsmđm = gtm) ;

- Các đối số đs1, …, đsn đối số mặc định đsmđ1, …, đsmđm khai báo cũ nghĩa gồm có kiểu đối số tên đối số

(95)

ứng với đs1, …, đsn có khơng đối số thực tế ứng với đối số mặc định đsmđ1, …, đsmđm Nếu đối số khơng có đối số thực tế tự động gán giá trị mặc định khai báo

Ví dụ: Xét hàm double LuyThua(float x, int n = 2); Hàm có đối số mặc định số mũ n, lời gọi hàm bỏ qua số mũ chương trình hiểu

tính bình phương x (n = 2) Chẳng hạn lời gọi LuyThua(4, 3) hiểu tính

43, lời gọi LuyThua(4, 2)hay LuyThua(4) hiểu tính 42

 Lưu ý: Các đối số mặc định phải nằm bên phải đối số không mặc định

5.2.7 Khai báo hàm trùng tên (Quá tải hàm)

Hàm trùng tên gọi hàm chồng (đè) hay tải hàm (function overload) Đây kỹ thuật cho phép sử dụng tên gọi cho hàm "giống nhau" (cùng mục đích) xử lý kiểu liệu khác số lượng liệu khác

Ví dụ:

Hàm sau tìm số lớn số nguyên: int Max(int a, int b)

{

return (a > b) ? a: b; }

Chúng ta định nghĩa chồng hàm để tìm số lớn số thực: float Max(float a, float b)

{

return (a > b) ? a: b; }

Khi tùy theo giá trị nhận vào đối số a b thuộc kiểu int hay float mà phiên hàm Max chọn để thực

5.2.8 Các cách truyền đối số

Có cách truyền đối số thực tế cho đối số hình thức lời gọi hàm Trong cách ta dùng thời điểm gọi truyền theo tham trị, tức đối số hình thức nhận giá trị cụ thể từ lời gọi hàm tiến hành tính tốn trả lại giá trị 5.2.8.1 Truyền theo tham trị

Ta xét lại ví dụ hàm LuyThua(float x, int n) dùng để tính tính xn Giả sử

chương trình (hàm main()) ta có biến a, b, f chứa giá trị a = 2, b = 3, f chưa có giá trị Để tính ab gán giá trị trả vào f, ta gọi f = LuyThua(a,b);

(96)

- Tạo biến (tức nhớ nhớ) có tên x n Gán nội dung ô nhớ giá trị lời gọi, tức gán (a) cho x (b) cho n

- Tới phần khai báo (của hàm), chương trình tạo thêm ô nhớ mang tên i kq - Tiến hành tính tốn (gán lại kết cho kq)

- Cuối lấy kết kq gán cho ô nhớ f (là ô nhớ có sẵn khai báo trước, nằm bên ngồi hàm)

- Kết thúc hàm quay chương trình gọi Do hàm LuyThua hồn thành xong việc tính tốn nên nhớ tạo thực hàm (x, n, i, kq) xóa khỏi nhớ Kết tính tốn lưu giữ nhớ f (khơng bị xóa khơng liên quan đến hàm)

Trên truyền đối số theo cách thông thường Vấn đề đặt giả sử ngồi việc tính f, ta cịn muốn thay đổi giá trị ô nhớ a, b (khi truyền cho hàm) thực không? Để giải vấn đề ta cần thực theo kỹ thuật khác, nhờ vào vai trò biến trỏ tham chiếu

5.2.8.2 Truyền theo trỏ

Xét ví dụ hoán đổi giá trị biến Đây yêu cầu nhỏ gặp nhiều lần chương trình, ví dụ để xếp mảng hay danh sách Do cần viết hàm để thực yêu cầu Hàm không trả kết mà hoán đổi giá trị đối số Do biến cần hoán đổi chưa biết trước thời điểm viết hàm, nên ta phải đưa chúng vào hàm đối số, tức hàm có đối số (có thể đặt x, y) đại diện cho biến thay đổi giá trị sau

Từ vài nhận xét trên, theo thơng thường hàm hốn đổi viết sau: void Swap(int x, int y)

{

int t ; t = x ; x = y ; y = t ; }

Giả sử chương trình ta có biến x, y chứa giá trị Ta cần hoán đổi nội dung biến cho x = y = cách gọi đến hàm Swap(x, y)

main() {

(97)

Swap(x, y) ;

cout << "x = " << x << "va y = " << y << endl;

// in x = va y = (x, y không đổi)

system("pause"); }

Thực tế sau chạy xong chương trình ta thấy giá trị x y khơng thay đổi !? Như giải thích mục (gọi hàm LuyThua), việc chương trình thực hàm tạo biến (các ô nhớ mới, độc lập với ô nhớ x, y có sẵn) tương ứng với đối số, trường hợp có tên x, y gán nội dung x, y (ngoài hàm) cho x, y (mới) Và việc cuối chương trình sau thực xong hàm xóa biến Do nội dung biến thực tế có thay đổi, khơng ảnh hưởng đến biến x, y cũ (ngoài hàm) Như hàm Swap cần viết lại cho việc thay đổi giá trị không thực biến tạm mà phải thực biến ngồi Muốn thay truyền giá trị biến cho đối số, ta truyền địa cho đối số, thay đổi phải thực nội dung địa Đó lý ta phải sử dụng trỏ để làm đối số thay cho biến thường

Cụ thể hàm swap viết lại sau: void Swap(int *p, int *q) {

int t; t = *p; *p = *q; *q = t; }

Với cách tổ chức hàm rõ ràng ta cho p trỏ tới biến x q trỏ tới biến y hàm Swap thực tế làm thay đổi nội dung x, y p, q

Từ lời gọi hàm Swap(&x, &y) (tức truyền địa x cho p, p trỏ tới x tương tự q trỏ tới y)

5.2.8.3 Truyền theo tham chiếu

Một hàm viết dạng đối số tham chiếu đơn giản nhiều so với đối số trỏ giống với cách viết bình thường (truyền theo tham trị), có điểm khác biệt đối số khai báo dạng tham chiếu

(98)

- Đối số hàm phải trỏ (ví dụ int *p)

- Các thao tác liên quan đến đối số thân hàm phải thực nơi trỏ đến (ví dụ *p = …)

- Lời gọi hàm phải chuyển địa cho p (ví dụ &x)

Hãy so sánh với cách viết hàm truyền theo tham chiếu, cụ thể: - Đối số hàm phải tham chiếu (ví dụ int &p)

- Các thao tác liên quan đến đối số phải thực nơi trỏ đến, tức địa cần thao tác Vì thao tác biến tham chiếu thực chất thao tác biến tham chiếu nên hàm cần viết p thao tác (thay *p trỏ) - Lời gọi hàm phải chuyển địa cho p Vì thân p tham chiếu đến biến chứa địa biến đó, lời gọi hàm cần ghi tên biến, ví dụ x (thay &x đối số với trỏ)

Tóm lại, đối số với hàm viết theo tham chiếu thay đổi đối số (là tham chiếu) lại nơi khác viết đơn giản cách viết truyền theo tham trị

Hàm Swap viết theo đối số tham chiếu sau: void Swap(int &x, int &y)

{

int t ; t = x ; x = y ; y = t ; }

Và lời gọi hàm đơn giản truyền đối số theo tham trị main()

{

int x = 2; int y = 5; Swap(x, y) ;

cout << "x = " << x << "va y = " << y << endl;

// in x = va y = (x, y không đổi)

(99)

5.3 ĐỆ QUI

5.3.1 Khái niệm đệ qui

Một hàm gọi đến hàm khác việc gọi hàm cách thông thường, nhiên hàm lại gọi đến thân ta gọi hàm đệ qui Khi thực hàm đệ qui, hàm phải chạy nhiều lần, lần chạy chương trình tạo nên tập biến cục ngăn xếp (các đối số, biến riêng khai báo hàm) độc lập với lần chạy trước đó, từ dễ gây tràn ngăn xếp Vì tốn giải phương pháp lặp khơng nên dùng đệ qui

Để minh họa ta xét hàm tính n giai thừa Để tính n! ta dùng phương pháp lặp sau:

#include <cstdlib> #include <iostream> using namespace std; long GiaiThua(int n) {

int i;

long kq = 1;

for (i = 1; i <= n; i++) kq = kq * i;

return kq; }

main() {

int n; long kq;

cout << "n = " ; cin >> n;

kq = GiaiThua(n);

cout << n << "! = " << kq << endl; system("pause");

}

Mặt khác, n! tính thơng qua (n-1)! cơng thức truy hồi sau: n! = n =

(100)

Do ta xây dựng hàm đệ qui tính n! sau: #include <cstdlib>

#include <iostream> using namespace std; long GiaiThuaDQ(int n) {

if(n == 0) return 1; else

return GiaiThuaDQ(n - 1) * n; }

main() {

int n; long kq;

cout << "n = " ; cin >> n;

kq = GiaiThuaDQ(n);

cout << n << "! = " << kq << endl; system("pause");

}

5.3.2 Các đặc điểm hàm đệ qui - Chương trình viết ngắn gọn

- Việc thực gọi gọi lại hàm nhiều lần phụ thuộc vào độ lớn đầu vào Chẳng hạn ví dụ hàm gọi n lần, lần chương trình thời gian để lưu giữ thông tin hàm gọi trước chuyển điều khiển đến thực hàm gọi Mặt khác thông tin lưu giữ nhiều lần ngăn xếp tốn nhiều vùng nhớ dẫn đến tràn ngăn xếp n lớn

- Chương trình dễ viết dễ đọc khó hiểu Trên thực tế có nhiều tốn tìm thuật tốn lặp cho khó viết theo thuật tốn đệ qui lại dễ dàng

5.3.3 Lớp toán giải đệ qui

Phương pháp đệ qui thường dùng để giải tốn có đặc điểm:

(101)

- Đối với trường hợp tổng qt, tốn giải toán dạng với đối số khác có kích thước hay giá trị nhỏ đối số ban đầu Và sau số bước hữu hạn biến đổi dạng, toán đưa trường hợp suy biến

Như trường hợp tính n! n = hàm cho giá trị mà khơng cần phải gọi lại nó, trường hợp suy biến Trường hợp n > hàm gọi lại với n giảm đơn vị Việc gọi lặp lại n = Một lớp rộng toán dạng tốn định nghĩa dạng đệ qui toán lặp với số bước hữu hạn biết trước, toán UCLN, tháp Hà Nội, … Đặc biệt ứng dụng cấu trúc liệu giải thuật

5.3.4 Cấu trúc chung hàm đệ qui

Dạng thức chung chương trình đệ qui sau: if (trường hợp suy biến)

{ trình bày cách giải // thường trả kết quả }

else // trường hợp tổng quát

{ gọi lại hàm với đối số "bé" } 5.3.5 Các ví dụ

Ví dụ 1: Tìm UCLN số ngun dương a, b Bài tốn định nghĩa dạng đệ qui sau:

- Nếu a = b UCLN = a

- Nếu a < b UCLN(a, b) = UCLN(a, b - a) - Nếu a > b UCLN(a, b) = UCLN(a - b, b)

Từ ta có chương trình đệ qui để tính UCLN a b sau: #include <cstdlib>

#include <iostream> using namespace std; int UCLN(int a, int b) {

if (a == b) return a; else

if (a < b)

return UCLN(a, b-a); else

(102)

main() {

int a, b;

cout << "Nhap so nguyen duong a va b = " ; cin >> a >> b;

cout << "UCLN(" << a << "," << b << ")= "; cout << UCLN(a,b) << endl;

system("pause"); }

Ví dụ 2: Tính số hạng thứ n dãy Fibonaci dãy f(n) định nghĩa: - f(0) = f(1) =

- f(n) = f(n - 1) + f(n - 2) với ∀ n ≥ Chương trình viết sau:

#include <cstdlib> #include <iostream> using namespace std; long Fibo(int n) {

long kq;

if (n==0 || n==1) kq = 1;

else

kq = Fibo(n-1) + Fibo(n-2); return kq;

} main() {

int n; long kq;

cout << "n = " ; cin >> n;

(103)

cout << "So hang thu " <<n<< " day Fibonaci la "; cout << kq << endl;

system("pause"); }

Ví dụ 3: Viết chương trình tính #include <cstdlib> #include <iostream> using namespace std; long Tohop(int n, int k) {

if (k==0 || k==n) return 1;

else

return Tohop(n-1,k-1) + Tohop(n-1,k); }

main() {

int n, k;

cout << "Nhap n va k : " ; cin >> n >> k;

cout << "To hop " << n << " chap " << k << " = "; cout << Tohop(n,k) << endl;

system("pause"); }

Ví dụ 4: Viết chương trình in số lẻ nhỏ n #include <cstdlib>

#include <iostream> using namespace std; void InLe(int n) {

(104)

if (n%2 != 0) {

cout << n <<'\t'; InLe(n-2);

} else

InLe(n-1); }

main() {

int n;

cout << "Nhap n = " ; cin >> n ;

cout << "Cac so le la : "; InLe(n);

cout << endl;

system("pause"); }

 Hàm đệ qui InLe(int n) in số lẻ theo thứ tự giảm dần Nếu muốn in số

lẻ theo thứ tự tăng dần ta hiệu chỉnh hàm InLe lại sau: void InLe(int n, int i)

{

if (n==1) cout << n; else

if (i <= n) {

cout << i <<'\t'; InLe(n,i+2);

} }

(105)

BÀI TẬP CHƯƠNG 5

- -

1 Hãy khai báo biến ký tự ch trỏ kiểu ký tự pc trỏ vào biến ch Viết cách gán giá trị ‘A’ cho biến ch

2 Cho mảng nguyên cost Viết cách gán giá trị 100 cho phần tử thứ mảng Cho p, q trỏ trỏ đến biến nguyên x = Đặt *p = *q + 1; Hỏi *q ?

4 Cho p, q, r, s trỏ trỏ đến biến nguyên x = 10 Đặt *q = *p + 1; *r = *q +1; *s = *r + Hỏi giá trị biến x ?

5 Xét chương trình sau: #include <cstdlib> #include <iostream> using namespace std; char st[] = "tin hoc"; main()

{

char *p;

p = new char[10];

for (int i=0; st[i] != '\0'; i++) p[i] = st[i];

cout << p << endl; system("pause"); }

Chương trình chưa hồn chỉnh vì:

A: Chương trình chưa hồn chỉnh sử dụng sai cú pháp toán tử new

B: Chương trình chưa hồn chỉnh sử dụng sai cú pháp p[i] (đúng *(p+i))

C: Chương trình hồn chỉnh p chuỗi rỗng D: Chương trình hồn chỉnh p chuỗi “tin hoc” Để tính độ dài chuỗi, sinh viên viết chương trình sau: #include <cstdlib>

(106)

char *st; main() {

int len = 0; gets(st);

while(st[len] != '\0') {

cout<<st[len]<<'\t'; len++;

}

cout<<len<<endl; system("pause"); }

Hãy chọn câu nhất:

A: Chương trình hồn chỉnh B: Cần thay len++ ++len

C: Cần thay st[len]!= '\0' st[len] == '\0' D: Cần cấp phát vùng nhớ cho biến st Chọn câu sai câu sau đây:

A: Hàm khơng trả lại giá trị không cần khai báo kiểu giá trị hàm B: Các biến khai báo hàm cục bộ, tự xóa hàm thực xong C: Hàm khơng trả lại giá trị có kiểu giá trị ngầm định void

D: Hàm đơn vị độc lập, không khai báo hàm lồng

8 Viết chương trình nhập vào chuỗi ký tự s(dạng trỏ), in hình chuỗi đảo ngược

9 Viết chương trình nhập vào chuỗi ký tự s(dạng trỏ), copy từ chuỗi s sang chuỗi t đoạn bắt đầu vị trí m với độ dài n

10 Xây dựng hàm tìm UCLN số nguyên Áp dụng hàm để tìm UCLN số nguyên nhập từ bàn phím

11 Xây dựng hàm tìm BCNN số nguyên Áp dụng hàm để tìm UCLN số nguyên nhập từ bàn phím

(107)

13 Xây dựng hàm kiểm tra năm có năm nhuận khơng Áp dụng hàm in năm nhuận từ năm 1000 đến 2035

14 Xây dựng hàm chuẩn hoá chuỗi dạng Proper (cắt bỏ khoảng trắng đầu, cắt bớt dấu trắng thừa từ (chỉ để lại 1), viết hoa đầu từ)

15 Xây dựng hàm đệ qui tính n! Áp dụng hàm để tính tổ hợp n chập k theo công thức truy hồi: C(n, k) = n!/(k! (n-k)!) Viết hàm main() minh họa tính đắn hàm xây dựng

16 Xây dựng hàm sau giải thuật không đệ qui: a Kiểm tra xem số n có phải số phương khơng? b Tìm số lớn số thực

c In n phần tử dãy Fibonaci

d Đếm xem có số nguyên tố n số nguyên dương e In ước số số nguyên dương n

Viết hàm main() minh họa tính đắn hàm 17 Xây dựng hàm sau giải thuật đệ qui:

a Tính tổng N số nguyên dương b Tính xn với x số thực n số nguyên

c Tìm bội số chung nhỏ số nguyên dương d In ước số số nguyên dương n

Viết hàm main() minh họa tính đắn hàm

18 Xây dựng hàm sau cho liệu kiểu mảng chiều có n phần tử kiểu số nguyên: a Nhập mảng

b Xuất mảng

c Đếm số phần tử số ngun tố có mảng d Tính tổng phần tử ước số K

e Tìm BCNN phần tử đầu cuối mảng f Sắp xếp mảng theo thứ tự tăng dần

(108)

CHƯƠNG 6: DỮ LIỆU KIỂU CẤU TRÚC

- -

6.1 GIỚI THIỆU

Dữ liệu kiểu mảng tập hợp nhiều phần tử có kiểu khả sử dụng hạn chế Vấn đề đặt liệu có kiểu liệu gồm nhiều phần tử có kiểu khác lại có liên quan với không? Chẳng hạn để quản lý sinh viên lớp ta cần thông tin như: mã số, họ tên, năm sinh, giới tính, điểm trung bình, … Để giải vấn đề ngôn ngữ C/C++ cho ta định nghĩa liệu kiểu cấu trúc mà chúng gọi kiểu mẩu tin hay ghi (record) thành phần gọi trường (field)

6.2 KHAI BÁO

Để tạo kiểu cấu trúc NSD cần phải khai báo tên kiểu (là tên gọi NSD tự đặt) thành phần liệu có kiểu cấu trúc Một kiểu cấu trúc khai báo theo mẫu sau:

struct <tên kiểu cấu trúc> {

thành phần 1; thành phần 2;

thành phần n; } [danh sách biến];

- Mỗi thành phần giống biến riêng kiểu, gồm kiểu tên thành phần Một thành phần cịn gọi trường Nếu thành phần có kiểu liệu ta khai báo chung

- Phần danh sách biến có khơng Tuy nhiên khai báo ký tự kết thúc cuối phải dấu chấm phẩy (;)

- Các kiểu cấu trúc phép khai báo lồng nhau, nghĩa thành phần kiểu cấu trúc có kiểu kiểu cấu trúc khác

- Một biến có kiểu cấu trúc phân bố nhớ cho thành phần liên tục theo thứ tự xuất khai báo

- Ta khai báo biến kiểu cấu trúc giống khai báo biến kiểu sở dạng sau:

<tên kiểu cấu trúc> <danh sách biến> ; Các biến khai báo kèm khởi tạo:

(109)

Ví dụ:

- Khai báo kiểu cấu trúc chứa phân số gồm thành phần nguyên chứa tử số mẫu số: struct Phanso

{

int tu; int mau; } a, b, c;

Vì tử số mẫu số có kiểu liệu nên ta khai báo: struct Phanso

{

int tu, mau; } a, b, c;

- Để quản lý sinh viên lớp ta khai báo sau: struct Sinhvien

{

char ms[9]; char ht[40]; int ns, gt; float dtb; };

- Kiểu ngày tháng gồm thành phần nguyên chứa ngày, tháng, năm struct Ngaythang

{

int ng; int th; int nam;

} holiday = { 31, 12, 2013 };

Một biến holiday khai báo kèm theo kiểu khởi tạo giá trị 31, 12, 2013 Các giá trị khởi tạo gán cho thành phần theo thứ tự khai báo, tức ng = 31, th = 12 nam = 2013

6.3 CÁCH SỬ DỤNG

(110)

6.3.1 Đối với biến thường

<tên biến> <tên thành phần>

Ví dụ:

struct Sinhvien {

char ms[9]; char ht[40]; int ns, gt; float dtb; };

Sinhvien sv1, sv2;

strcpy(sv1.ht, “Nguyen Thanh Liem”); sv1.dtb = 5.5;

sv2.dtb = sv1.dtb + 1;

cout<<sv1.ht<<'\t'<<sv2.ht<<endl; cout<<sv1.dtb<<'\t'<<sv2.dtb<<endl; 6.3.2 Đối với biến trỏ

<tên biến> → <tên thành phần>

Ví dụ:

struct Sinhvien {

char ms[9]; char ht[40]; int ns, gt; float dtb; }x, *p;

Sinhvien y = {"CNTT3801", "Le Trung Truc", 1995, 1, 5.5}; x.ns = y.ns;

p = new Sinhvien; strcpy(p->ht, y.ht); p->ns = x.ns - 1; p->dtb = y.dtb + 2;

(111)

6.3.3 Đối với biến mảng

Ta phải truy xuất thành phần mảng trước đến thành phần cấu trúc sau

Ví dụ:

struct Sinhvien {

char ms[9]; char ht[40]; int ns, gt; float dtb; }cntt13[80];

Sinhvien y = {"CNTT3801", "Le Trung Truc", 1995, 1, 5.5}; strcpy(cntt13[1].ht, “Nguyen Quoc An”);

cntt13[1].ns = y.ns; cntt13[1].dtb = 9.5;

cout<<cntt13[1].ht<<'\t'<<cntt13[1].ns<<'\t'; cout<<cntt13[1].dtb<<endl;

6.3.4 Đối với cấu trúc lồng

Ta phải truy xuất thành phần cấu trúc trước đến thành phần cấu trúc sau; ta phải sử dụng phép toán → (các phép toán lấy thành phần) cách thích hợp

struct date {

int ngay, thang, nam; };

struct Sinhvien {

char ms[9]; char ht[40]; date ngaysinh; float dtb; };

(112)

cout<<"Sinh vien "<<sv3.ht<<" co sinh la : "; cout<<sv3.ngaysinh.ngay<<'/'<<sv3.ngaysinh.thang<<'/'; cout<<sv3.ngaysinh.nam<<endl;

6.4 CÁC THAO TÁC CƠ BẢN 6.4.1 Thao tác nhập/xuất

Cũng giống biến mảng, để làm việc với biến cấu trúc phải thực thao tác thành phần chúng Chẳng hạn muốn nhập/xuất biến cấu trúc ta phải viết câu lệnh nhập/xuất cho thành phần biến

Ví dụ:

struct Sinhvien {

char ms[9]; char ht[40]; int ns, gt; float dtb; } x;

cout << " Nhap du lieu cho sinh vien x:" << endl; cout << "Nhap ma so:"; cin.getline(x.ms, 9);

cout << "Nhap ho ten:"; cin.getline(x.ht, 40); cout << "Nhap nam sinh:"; cin >> x.ns;

cout << "Nhap gioi tinh:"; cin >> x.gt;

cout << "Nhap diem trung binh:"; cin >> x.dtb;

cout << "Thong tin ve sinh vien vua nhap la:" << endl; cout << "Ma so: " << x.ms << endl;

cout << "Ho ten: " << x.ht << endl; cout << "Nam sinh: " << x.ns << endl;

cout << "Gioi tinh: " << (x.gt == ? "Nam" : "Nu") << endl; cout << "Diem trung binh: " << x.dtb << endl;

6.4.2 Phép gán

(113)

Ví dụ:

struct Sinhvien {

char ms[9]; char ht[40]; int ns, gt; float dtb; } x, y, *p;

cout << " Nhap du lieu cho sinh vien x:" << endl; cout << "Nhap ma so:"; cin.getline(x.ms, 9);

cout << "Nhap ho ten:"; cin.getline(x.ht, 40); cout << "Nhap nam sinh:"; cin >> x.ns;

cout << "Nhap gioi tinh:"; cin >> x.gt;

cout << "Nhap diem trung binh:"; cin >> x.dtb;

y = x;

cout << "Thong tin ve sinh vien y la:" << endl; cout << "Ma so: " << y.ms << endl;

cout << "Ho ten: " << y.ht << endl; cout << "Nam sinh: " << y.ns << endl;

cout << "Gioi tinh: " << (y.gt == ? "Nam" : "Nu") << endl; cout << "Diem trung binh: " << y.dtb << endl;

p = new Sinhvien; *p = y;

cout << "Thong tin ve sinh vien p la:" << endl; cout << "Ma so: " << p->ms << endl;

cout << "Ho ten: " << p->ht << endl; cout << "Nam sinh: " << p->ns << endl;

(114)

Chú ý: Ta gán giá trị cụ thể cho biến cấu trúc được, cách gán thực khởi tạo

Ví dụ:

Sinhvien y = {"CNTT3801", "Le Trung Truc", 1995, 1, 5.5};

Nhưng:

Sinhvien z;

z = {"CNTT3801", "Le Trung Truc", 1995, 1, 5.5}; sai

Và: z = y;

6.5 CÁC CHƯƠNG TRÌNH ỨNG DỤNG 6.5.1 Chương trình

Viết chương trình nhập vào phân số, tính hiệu thương phân số #include <cstdlib>

#include <iostream> using namespace std; main()

{

struct Phanso {

int tu; int mau; } a, b, h, t;

cout<<"Nhap tu so cua phan so a:"; cin>>a.tu; cout<<"Nhap mau so cua phan so a:"; cin>>a.mau; cout<<"Nhap tu so cua phan so b:"; cin>>b.tu; cout<<"Nhap mau so cua phan so b:"; cin>>b.mau;

cout<<"Phan so a da nhap la:"<<a.tu<<'/'<<a.mau<<endl; cout<<"Phan so b da nhap la:"<<b.tu<<'/'<<b.mau<<endl; h.tu=a.tu*b.mau-a.mau*b.tu;

h.mau=a.mau*b.mau;

(115)

t.tu=a.tu*b.mau; t.mau=a.mau*b.tu;

cout<<"Thuong cua phan so a va b la:"; cout<<t.tu<<'/'<<t.mau<<endl;

system("pause"); }

Tuy nhiên ta khai báo kiểu cấu trúc bên hàm main() để đơn giản ta xây dựng hàm để thực cơng việc cụ thể chương trình như: nhập/xuất phân số, tính hiệu thương phân số Khi chương trình viết lại sau:

#include <cstdlib> #include <iostream> using namespace std; struct Phanso

{

int tu; int mau; };

void NhapPS(Phanso &p) {

cout<<"Nhap tu so :"; cin>>p.tu; cout<<"Nhap mau so :"; cin>>p.mau; }

void XuatPS(Phanso p) {

cout<<p.tu<<'/'<<p.mau<<endl; }

Phanso Hieu(Phanso a, Phanso b) {

Phanso h;

h.tu=a.tu*b.mau-a.mau*b.tu; h.mau=a.mau*b.mau;

(116)

Phanso Thuong(Phanso a, Phanso b) {

Phanso t;

t.tu=a.tu*b.mau; t.mau=a.mau*b.tu; return t;

}

main() {

Phanso a, b;

cout<<"Nhap phan so a:"<<endl; NhapPS(a);

cout<<"Nhap phan so b:"<<endl; NhapPS(b);

cout<<"Phan so a la: "; XuatPS(a); cout<<"Phan so b la: "; XuatPS(b);

cout<<"Hieu cua phan so a va b la: "; XuatPS(Hieu(a, b));

cout<<"Thuong cua phan so a va b la: "; XuatPS(Thuong(a, b));

system("pause"); }

6.5.2 Chương trình

Viết chương trình quản lý sách cho thư viện Thông tin sách gồm: tựa sách, tên tác giả, tên nhà xuất bản, năm xuất số trang Nhập danh sách n sách, với n nhập từ bàn phím In danh sách sách nhập Cho biết có sách tác giả X, với X nhập từ bàn phím Tính tổng số trang sách xuất vào năm 2013 Cho biết sách dày có trang In tựa sách, tên tác giả sách có số trang P, với P nhập từ bàn phím

(117)

struct sach {

char tua[40],ttg[40]; char nxb[60];

int namxb,trang; } s[1000];

main() {

int n, i, P; char X[40];

//Nhap va kiem tra n

{

cout<<"Nhap so sach co thu vien : "; cin>>n;

}while (n<=0 || n>1000); //Nhap sach

for (i=0; i<n; i++) {

cout<<"Nhap quyen sach thu "<<i+1<<" : "<<endl; cin.ignore(1);

cout<<"Nhap tua sach :"; cin.getline(s[i].tua,40); cout<<"Nhap ten tac gia :";

cin.getline(s[i].ttg,40);

cout<<"Nhap ten nha xuat ban :"; cin.getline(s[i].nxb,60);

cout<<"Nhap nam xuat ban :"; cin>>s[i].namxb;

cout<<"Nhap so trang :"; cin>>s[i].trang;

(118)

//In cac quyen sach da nhap for (i=0; i<n; i++)

{

cout<<"Thong tin ve qs thu "<<i+1<< " la : "<<endl; cout<<"Tua : "<<s[i].tua<<endl;

cout<<"Tac gia : "<<s[i].ttg<<endl; cout<<"Nha xuat ban : "<<s[i].nxb<<endl; cout<<"Nam xuat ban : "<<s[i].namxb<<endl; cout<<"So trang : "<<s[i].trang<<endl; }

//Dem so sach duoc viet boi tac gia X cin.ignore(1);

cout<<"Ban muon dem so sach cua tac gia nao? "; cin.getline(X,40);

int d=0;

for (i=0; i<n; i++)

if (strcmpi(s[i].ttg,X)==0) d++; cout<<"Tac gia "<<X<<" co "<<d;

cout<<" quyen sach thu vien"<<endl;

//Tinh tong so trang cua cac qs duoc xb nam 2013 long ts=0;

for (i=0; i<n; i++)

if (s[i].namxb==2013) ts=ts+s[i].trang;

cout<<"Tong so trang cac qs duoc xb nam 2013 la : "; cout<<ts<<endl;

//Tim so trang cua quyen sach day nhat int pmax=s[0].trang;

for (i=1; i<n; i++)

if (pmax<s[i].trang) pmax=s[i].trang;

(119)

//In tua va tac gia cua cac quyen sach co so trang la P cout<<"Nhap so trang cua cac quyen sach can in : ";

cin>>P;

cout<<"Cac quyen sach co so trang la "<<P<<" : "<<endl; for (i=0; i<n; i++)

if (s[i].trang==P) {

cout<<"Tua sach : "<<s[i].tua<<endl; cout<<"Tac gia : "<<s[i].ttg<<endl; }

system("pause"); }

6.5.3 Chương trình

Viết chương trình nhập vào danh sách sinh viên lớp, có tối đa 80 sinh viên Mỗi sinh viên gồm thơng tin: mã số, họ tên, q qn, giới tính, năm sinh, điểm trung bình xếp loại Kiểm tra liệu nhập: mã số phải đủ ký tự ký tự đầu chữ ký tự cuối chữ số, họ tên tồn chữ khoảng trắng khơng tồn khoảng trắng, năm sinh từ 1985 đến 1995, điểm trung bình từ 0.0 đến 4.0 xếp loại dựa vào điểm trung bình In danh sách sinh viên nhập Cho biết lớp có sinh viên nữ In họ tên sinh viên có điểm trung bình cao Sắp xếp danh sách sinh viên giảm dần theo điểm trung bình

#include <cstdlib> #include <iostream> using namespace std; struct sinhvien

{

(120)

main() {

int n,i,j,p,d1,d2,dc,dt,dnu; float dmax;

sinhvien tam;

{

cout<<"Nhap so luong sinh vien : "; cin>>n;

}while (n <=0 || n > 80); for (i=0; i<n; i++)

{

cout<<"Nhap sinh vien thu "<<i+1<<" : "<<endl; cin.ignore(1);

{

cout<<"Nhap ma so:"; cin.getline(sv[i].ms,7); d1=0;

for (j=0; j<3; j++)

if (isalpha(sv[i].ms[j])) d1++; d2=0;

for (j=3; j<6; j++)

if (isdigit(sv[i].ms[j])) d2++;

}while(strlen(sv[i].ms)!=6 || d1!=3 || d2!=3);

{

cout<<"Nhap ho ten:"; cin.getline(sv[i].ht,40); dc=0; dt=0;

(121)

else if (isspace(sv[i].ht[j]))dt++; }while(dc+dt!=strlen(sv[i].ht) ||dc==0); cout<<"Nhap que quan:";

cin.getline(sv[i].qq,20);

cout<<"Nhap gioi tinh (Nam:1, Nu:0):"; cin>>sv[i].gt;

do {

cout<<"Nhap nam sinh:"; cin>>sv[i].ns;

}while (sv[i].ns<1985 || sv[i].ns>1995);

{

cout<<"Nhap diem trung binh:"; cin>>sv[i].dtb;

}while (sv[i].dtb<0 || sv[i].dtb>4); if (sv[i].dtb>=3.6)

strcpy(sv[i].xl,"Xuat sac"); else if (sv[i].dtb>=3.2)

strcpy(sv[i].xl,"Gioi"); else if (sv[i].dtb>=2.5)

strcpy(sv[i].xl,"Kha"); else if (sv[i].dtb>=2)

strcpy(sv[i].xl,"Trung binh"); else strcpy(sv[i].xl,"Khong dat"); }

for (i=0; i<n; i++) {

cout<<"Thong tin ve sv thu "<<i+1<<" la : "<<endl; cout<<"Ma so : "<<sv[i].ms<<endl;

(122)

cout<<"Gioi tinh : ";

if (sv[i].gt==0) cout<<"Nu"<<endl; else cout<<"Nam"<<endl;

cout<<"Nam sinh : "<<sv[i].ns<<endl;

cout<<"Diem trung binh : "<<sv[i].dtb<<endl; cout<<"Xep loai : "<<sv[i].xl<<endl;

}

dnu=0;

for (i=0; i<n; i++)

if (sv[i].gt==0) dnu++;

cout<<"Trong lop co "<<dnu<<" sinh vien nu"; dmax=sv[0].dtb;

for (i=1; i<n; i++) if (dmax<sv[i].dtb)

dmax=sv[i].dtb;

cout<<"Ho ten cac sinh vien co dtb cao nhat la : "; for (i=0; i<n; i++)

if (sv[i].dtb==dmax)

cout<<sv[i].ht<<endl; for (i=0; i<n-1; i++)

for (j=i+1; j<n; j++)

if (sv[i].dtb<sv[j].dtb) {

tam=sv[i]; sv[i]=sv[j]; sv[j]=tam; }

cout<<"Danh sach sv sau sap xep la : "<<endl; for (i=0; i<n; i++)

{

(123)

cout<<"Ho ten : "<<sv[i].ht<<endl; cout<<"Que quan : "<<sv[i].qq<<endl; cout<<"Gioi tinh : ";

if (sv[i].gt==0) cout<<"Nu"<<endl; else cout<<"Nam"<<endl;

cout<<"Nam sinh : "<<sv[i].ns<<endl;

cout<<"Diem trung binh : "<<sv[i].dtb<<endl; cout<<"Xep loai : "<<sv[i].xl<<endl;

}

system("pause"); }

BÀI TẬP CHƯƠNG 6

- -

1 Có thể truy cập thành phần cấu trúc thông qua trỏ sau (với p trỏ cấu trúc a thành phần cấu trúc):

A: (*p).a B: *p→a C: a b sai D: a b

2 Cho khai báo struct T {int x; float y;} t, *p, a[10]; Câu lệnh câu sau không hợp lệ:

(1) p = &t; (2) p = &t.x; (3) p = a;

(4) p = &a (5) p = &a[5]; (6) p = &a[5].y;

A: 1, B: 4, C: 1, D: 2,

4 Trong khởi tạo giá trị cho cấu trúc sau, khởi tạo đúng: struct S1

{

int ngay, thang, nam; } s1 = {2, 3};

struct S2 {

(124)

struct S3 {

struct S2 sinhvien; float diem;

} s3 = {{{"Cốc cốc", {4, ,6}}, 7};

A: S1 S2 B: S2 S3

C: S3 S1 D: Cả

5 Đối số với kiểu cấu trúc, cách gán không phép: A: Gán hai biến cho

B: Gán hai phần tử mảng (kiểu cấu trúc) cho

C: Gán phần tử mảng (kiểu cấu trúc) cho biến ngược lại D: Gán hai mảng cấu trúc số phần tử cho

6 Một phân số gồm trường tử số mẫu số Viết chương trình nhập vào phân số In kết phép toán cộng, trừ, nhân chia phân số

7 Giả sử để quản lý thông tin họ tên, ngày sinh (phải bao gồm ngày, tháng, năm sinh) người ta định nghĩa cấu trúc NgaySinh SinhVien Từ cấu trúc viết chương trình nhập N sinh viên, in thơng tin sinh viên, cho biết sinh viên sinh vào ngày 15, đếm số sinh viên sinh vào mùa xuân (tháng 1, 2, 3), in họ tên sinh viên có tuổi đời trẻ

8 Viết chương trình quản lý học sinh lớp Mỗi học sinh gồm thông tin: họ tên, năm sinh, điểm HK1, điểm HK2 In họ tên, năm sinh điểm năm tất học sinh, với điểm năm = (điểm HK1 + điểm HK2)/2 In tuổi lớn nhỏ lớp Cho biết học sinh có điểm năm lớn Tìm điểm trung bình năm lớp Sắp xếp danh sách giảm dần theo điểm năm, trùng xếp giản dần theo điểm HK2 In danh sách sau xếp

(125)

10 Viết chương trình quản lý nhân viên quan, nhân viên thông tin: mã số, họ tên, quê quán, ngày sinh, chức vụ, phụ cấp chức vụ, hệ số lương, tạm ứng thực lĩnh Chương trình cần thực chức sau:

- Nhập danh sách nhân viên có kiểm tra liệu nhập

+ Mã số gồm ký số phải tạo thành từ ký số khác + Họ tên gồm chữ khoảng trắng khơng tồn khoảng trắng sau nhập đổi sang dạng chuẩn upper

+ Hệ số lương từ 2.1 đến 6.8, tạm ứng phải không âm

- In danh sách nhân viên

- Tính thực lĩnh cho nhân viên,

với thực lĩnh = hệ số lương * 1.050.000 + phụ cấp chức vụ - tạm ứng

- In họ tên nhân viên có hệ số lương cao

- Đếm số nhân viên có thực lĩnh 1500000

- Tính tổng tạm ứng tất nhân viên có chức vụ nhập từ bàn phím

- Sắp xếp giảm dần theo thực lĩnh

(126)

CÁC PHỤ LỤC

- -

PHỤ LỤC 1: Bảng mã ASCII với 128 ký tự đầu tiên

Hex 0 1 2 3 4 5 6 7

(127)

PHỤ LỤC 2: Bảng mã ASCII với ký tự số 128 - số 255

Hex 8 9 A B C D E F

(128)

PHỤ LỤC 3: Các nguyên tắc chung sửa lỗi

Khi biên dịch chương trình thơng thường ta nhận thơng báo error (lỗi) warning (cảnh báo) Nguyên tắc chung gặp lỗi người lập trình bắt buộc phải sửa lại cho đúng, gặp cảnh báo bỏ qua Tuy nhiên số cảnh báo không sửa làm cho chương trình chạy khơng

Khi gặp thơng báo lỗi ta nên tiến hành theo bước sau để sửa lỗi:

1 Nhắp đúp chuột vào thơng báo lỗi để nhảy đến vị trí có lỗi chương trình Đọc dịng chứa trỏ để sửa lỗi

3 Nếu dòng chứa trỏ khơng phát lỗi đọc dịng để tìm lỗi sửa

4 Nếu khơng phát lỗi phải dị lỗi từ đầu chương trình đến dịng chứa trỏ (vì lỗi xuất dịng phía nữa)

 Lưu ý: Các lỗi mà ta phát sửa theo bước gọi lỗi cú

pháp (syntax error) Tuy nhiên lập trình cịn loại lỗi mà trình biên dịch khơng phát lỗi ngữ nghĩa hay lỗi giải thuật (chương trình thực thi kết sai) Để xử lý lỗi người lập trình phải xem xét lại tồn giải thuật để tìm nơi phát sinh lỗi (làm cho chương trình trả kết sai) sửa lại cho

Một số từ tiếng Anh thông dụng lập trình:

undeclared: khơng khai báo unable: khơng thể

undefined: khơng xác định incorrectly: ko xác symbol: biểu tượng statement: câu lệnh

parameter/ argument: tham số, đối số declaration: kê khai, khai báo

(129)

PHỤ LỤC 4: Các thông báo lỗi thường gặp STT Thông báo lỗi gốc Ý nghĩa

1 ( expected

Thiếu dấu …

Các lỗi thường xảy ta sơ sót, dẫn đến thiếu dấu mở đóng ngoặc, … ) expected

3 ; expected { expected } expected

6 286/287 instructions not enabled

Tập lệnh Vi xử lí 80286 xử lí tốn học chưa kích hoạt

Vào Options/Compiler/Advanced Code generation… để điều chỉnh lại

7 Ambiguity between 'function1' and 'function2'

2 hàm function1 function2 giống nhau, phân biệt

8 Array bounds missing ] Thiếu dấu đóng ngoặc ] truy xuất đến phần tử mảng

9 Array must have at least one element

Khi khai báo mảng phải có phần tử Xảy khai báo mảng mà SPT tối đa âm

10 Array size too large Kích thước mảng lớn, vượt dung lượng vùng nhớ quy ước 64K

11 Bit field cannot be static Kiểu liệu bit field khơng thể có kiểu static 12 Bit field too large Kích thước bit field lớn

13 Bit fields must be signed or

unsigned int Kiểu liệu bit field phải số nguyên 14 Bit fields must contain at least one bit Kích thước bit field phải ≥ bit 15 Body already defined for this function Hàm định nghĩa Lỗi xảy

ta viết phần thân hàm ≥ lần 16 Call of nonfunction Câu lệnh gọi hàm ta sai Tên hàm mà

ta gọi tên kiểu/hằng/biến,… 17 Cannot call 'main' from within the

program

Không thể gọi thực hàm main() chương trình, hàm đặc biệt, tự động thực lần lần chạy CT 18 Cannot cast from 'type1' to 'type2' Không thể ép kiểu liệu từ kiểu sang kiểu

2

19 Cannot convert 'type1' to 'type2' Không thể chuyển đổi kiểu liệu từ kiểu sang kiểu

20 Cannot initialize 'type1' with 'type2' Không thể khởi gán liệu thuộc kiểu cho biến thuộc kiểu

21 Cannot modify a const object

Không thể thay đổi giá trị số Xảy ta thực phép gán giá trị cho

(130)

23 Case statement missing : Lệnh CASE thiếu dấu chấm (:) 24 Character constant must be one or

two characters long

Kích thước kí tự khơng Xảy ta ghi chuỗi dài kí tự vào cặp dấu nháy đơn ‘’

25 Compound statement missing } Thiếu dấu } kết thúc khối lệnh

26 Constant expression required Vị trí lẽ phải biểu thức hằng, có giá trị khơng đổi

27 Could not find a match for

argument(s) Khơng tìm thấy đối số thích hợp

28 Could not find file 'filename' Khơng tìm thấy tập tin

29 Declaration is not allowed here Vị trí khai báo sai Không khai báo

30 Declaration missing ; Khai báo thiếu dấu chấm phẩy (;) 31 Declaration syntax error Khai báo không cú pháp 32 Declaration terminated incorrectly Khai báo sai (gần giống lỗi trên) 33 Declaration was expected Thiếu khai báo

34 Default outside of switch Lệnh mặc định DEFAULT nằm bên khối lệnh SWITCH 35 Default value missing Thiếu giá trị mặc định

36 Division by zero Chia cho 0, lỗi xảy mẫu số phần số có giá trị

37 statement must have while Lệnh phải với while Xảy thiếu while câu lệnh do…

38 do-while statement missing (

Thiếu … câu lệnh do…while 39 do-while statement missing )

40 do-while statement missing ; 41 Duplicate case

Lệnh CASE bị trùng, xảy ta viết dòng case khác giá trị

42 Expression expected Vị trí phải biểu thức 43 Expression syntax Sai cú pháp xây dựng biểu thức

44 Extra parameter in call to function Gọi thực hàm lại truyền dư tham số

45 File name too long Tên tập tin dài 46 For statement missing (

Thiếu … câu lệnh for 47 For statement missing )

48 For statement missing ;

49 'function' cannot return a value

(131)

50 'function' must be declared with no parameters

Hàm có tên ‘function’ phải khai báo khơng có tham số, xảy phần khai báo (prototype) phần thân hàm không giống số tham số

51 'function' must be declared with one parameter

Tương tự lỗi 52 'function' must be declared with two

parameters

53 Function 'function' should have a prototype

Hàm có tên ‘function’ cần phải khai báo Lỗi thường gặp trình biên dịch C khơng hiểu tên hàm mà ta sử dụng, thiếu #include tập tin tiêu đề tương ứng, gõ sai tên

54 Function call missing ) Gọi thực hàm thiếu )

55 Function calls not supported Không thể gọi hàm dạng này/kiểu 56 Function should return a value

Hàm cần phải trả giá trị, xảy ta khai báo hàm có kiểu trả lại thiếu câu lệnh return…

57 Goto statement missing label Dùng lệnh goto mà khơng có nhãn

58 'identifier' is not a member of struct Tên … thành phần cấu trúc, xảy ta viết tên thành phần sai

59 'identifier' is not a parameter Tên … tham số 60 Identifier expected Thiếu tên biến

61 If statement missing (

Câu lệnh if thiếu mở hay đóng ngoặc 62 If statement missing )

63 Illegal character 'character' (0x'value')

Kí tự khơng hợp lệ, thường xảy ta biểu diễn số hệ hexa, lại sử dụng chữ khác A F hay a f

64 Illegal octal digit Không phải số hệ hợp lệ

65 Illegal pointer subtraction Thực phép trừ không hợp lệ trỏ 66 Illegal use of floating point Dùng dấu chấm động khơng đúng, ví dụ sử

dụng phép toán % số thực chẳng hạn 67 Illegal use of pointer Dùng trỏ không hợp lệ

68 Implicit conversion of 'type1' to 'type2' not allowed

Không cho phép ngầm chuyển từ kiểu sang kiểu

(132)

71 Incorrect number format

Không phải liệu dạng số, thường xảy ta gõ kí tự khác liệu kiểu số

72 Incorrect use of default Dùng DEFAULT không 73 Invalid use of dot Dùng dấu chấm (.) khơng vị trí 74 Lvalue required Vế trái phép gán phải tên biến,

lỗi xảy ta gán giá trị cho 75 Main must have a return type of int Hàm main phải trả giá trị kiểu int 76 Misplaced break Dùng break vịng lặp ngồi

SWITCH

77 Misplaced continue Dùng continue ngồi vịng lặp 78 Misplaced decimal point Dấu chấm thập phân sai vị trí 79 Misplaced else Dùng else sai vị trí (thiếu if, …)

80 'new' and 'delete' not supported Không phép dùng new delete cấp phát vùng nhớ động

81 No : following the ? Toán tử điều kiện thiếu dấu chấm (:) 82 No file name ending Khơng có phần kết thúc tên tập tin 83 No file names given Khơng có tên tập tin

84 No type information Khơng tìm thấy thơng tin kiểu liệu 85 Not an allowed type Kiểu liệu không cho phép dùng 86 Numeric constant too large Hằng số có giá trị lớn

87 Pointer to structure required on left side of -> or ->*

Xảy dùng trỏ cấu trúc không cách để truy xuất thành phần cấu trúc 88 sizeof may not be applied to a bit field Tốn tử sizeof() khơng dùng cho kiểu bit field 89 sizeof may not be applied to a function Tốn tử sizeof() khơng dùng cho hàm

90 Size of 'identifier' is unknown or zero Kích thước … không xác định

91 Size of the type is unknown or zero Kích thước kiểu liệu không xác định

92 Statement missing ; Thiếu dấu chấm phẩy (;), thông thường thiếu dấu ; tai dòng dòng báo lỗi 93 Structure required on left side of or * Xảy truy xuất thành phần cấu

trúc không cách

(133)

95 Switch statement missing (

Câu lệnh switch thiếu ngoặc Phần giá trị lệnh switch phải đặt cặp dấu ngoặc 96 Switch statement missing )

97 The value for 'identifier' is not within the range of an int

Giá trị biến … không nằm phạm vi biến kiểu nguyên (int)

98 Too few parameters in call to function Gọi thực hàm lại truyền không đủ số lượng tham số

99 Too many decimal points Biểu diễn số thực dùng nhiều dấu chấm thập phân 100 Too many default cases Trong câu lệnh switch có nhiều lệnh

default 101 Too many errors or warning messages

Có nhiều lỗi cảnh báo chương trình Xảy chương trình có nhiều 25 lỗi

102 Too many types in declaration Khai báo nhiều kiểu liệu (ít gặp) 103 Too much global data defined in file

Có q nhiều biến tồn cục chương trình, gây tràn vùng nhớ dành riêng cho biến

104 Type mismatch in default argument value

Giá trị mặc định tham số truyền cho CT bị sai kiểu

105 Type mismatch in default value for

parameter 'parameter' Giá trị mặc định tham số … bị sai kiểu 106 Type mismatch in parameter 'number'

in call to 'function'

Truyền tham số cho hàm ‘function’ bị sai kiểu tham số ‘number’

107 Type mismatch in parameter

'parameter' Tham số … bị sai kiểu

108 Type mismatch in parameter

'parameter' in call to 'function' Gần giống lỗi 106

109 Type name expected Thiếu tên kiểu vị trí báo lỗi 110 Type 'typename' may not be defined

here

Kiểu liệu … khơng thể định nghĩa vị trí

được 111 Unable to create turboc.$ln

Không thể tạo tập tin turboc.1$n Thường xảy ta chạy TurboC đĩa mềm hay đĩa CD

112 Unable to execute command

'command' Không thể thực lệnh …

113 Unable to open include file 'filename'

(134)

114 Undefined label 'identifier' Nhãn … chưa khai báo 115 Undefined structure 'structure' Cấu trúc … chưa khai báo 116 Undefined symbol 'identifier'

Ký hiệu … chưa khai báo, thường xảy trường hợp ta sử dụng biến mà chưa khai báo

117 Unexpected } Dư dấu đóng ngoặc }

118 Unexpected end of file in comment

started on 'line number' Thường xảy trường hợp thiếu dấu đóng ngoặc } hàm main()

119 Unexpected end of file in conditional started on 'line number'

120 Unknown language, must be C or C++ Một cú pháp lạ, cú pháp C hay C++

121 User break Chương trình bị ngắt người sử dụng 122 Value of type void is not allowed Không phép gán liệu cho biến

kiểu void 123 Variable 'identifier' is initialized more

than once Biến … khởi tạo nhiều lần

124 void & is not a valid type Không chấp nhận tham chiếu đến biến kiểu void 125 While statement missing (

Câu lệnh while thiếu ngoặc Phần điều kiện lệnh while phải đặt dấu ngoặc 126 While statement missing )

TÀI LIỆU THAM KHẢO

-

-[1] Phạm Văn Ất, Nguyễn Hiếu Cường, Đỗ Văn Tuấn, Lê Trường Thơng, Giáo trình Kỹ thuật lập trình C, NXB Hồng Đức, 2009

[2] Trần Đình Quế, Nguyễn Mạnh Hùng, Ngơn ngữ lập trình C++, Học viện cơng

nghệ bưu viễn thơng, 2006

[3] James P Cohoon and Jack W.Davidson, C++ Program Design – An Introduction to Programming and Object-Oriented Design, 2nd edition, WCB McGraw-Hill, 1999

[4] Robert Sedgewick, Cẩm nang Thuật Toán Vol.1, Nhà xuất Khoa học Kỹ thuật

(135)

MỤC LỤC

- -

CHƯƠNG 1: TỔNG QUAN VỀ NGÔN NGỮ C++ 1

1.1 KHÁI NIỆM VỀ LẬP TRÌNH

1.1.1 Giới thiệu chung

1.1.2 Định nghĩa

1.1.3 Giải thuật (Algorithm)

1.1.4 Đặc tính giải thuật

1.1.5 Các lưu ý

1.1.6 Các công cụ thể giải thuật

1.2 CÁC YẾU TỐ CƠ BẢN

1.2.1 Bảng ký tự C++

1.2.2 Từ khóa

1.2.3 Tên gọi

1.2.4 Chú thích chương trình

1.2.5 Cấu trúc chương trình C++

1.3 CÁC BƯỚC ĐỂ TẠO VÀ THỰC HIỆN MỘT CHƯƠNG TRÌNH

1.3.1 Qui trình viết thực chương trình

1.3.2 Soạn thảo tệp chương trình nguồn

1.3.3 Dịch chương trình

1.3.4 Thực thi chương trình

1.4 NHẬP/XUẤT TRONG C++

1.4.1 Nhập liệu từ bàn phím

1.4.2 Xuất liệu hình

1.4.3 Định dạng thông tin cần in hình 11

1.5 CÁC KIỂU DỮ LIỆU CƠ BẢN 14

1.5.1 Khái niệm kiểu liệu 14

1.5.2 Kiểu ký tự 15

1.5.3 Kiểu số nguyên 15

(136)

1.6 HẰNG SỐ 16

1.6.1 Định nghĩa 16

1.6.2 Một số thông dụng 17

1.6.3 Khai báo 17

1.7 BIẾN 18

1.7.1 Định nghĩa 18

1.7.2 Khai báo biến 18

1.7.3 Phạm vi biến 19

1.7.4 Gán giá trị cho biến 19

1.7.5 Một số điểm lưu ý phép gán 20

1.8 PHÉP TOÁN, BIỂU THỨC VÀ CÂU LỆNH 20

1.8.1 Phép toán 20

1.8.2 Các phép gán 22

1.8.3 Biểu thức 23

1.8.4 Câu lệnh khối lệnh 25

1.9 MỘT SỐ HÀM THÔNG DỤNG 26

1.9.1 Nhóm hàm tốn học 26

1.9.2 Nhóm hàm kiểm tra ký tự 26

1.9.3 Nhóm hàm chuyển đổi liệu 26

BÀI TẬP CHƯƠNG 27

CHƯƠNG 2: CÁC CẤU TRÚC ĐIỀU KHIỂN 28

2.1 CẤU TRÚC RẼ NHÁNH 28

2.1.1 Cấu trúc if 28

2.1.2 Cấu trúc switch 31

2.1.3 Lệnh nhảy goto 35

2.2 CẤU TRÚC LẶP 35

2.2.1 Cấu trúc for 35

2.2.2 Cấu trúc while 39

2.2.3 Lệnh lặp while 42

2.2.4 Lối vòng lặp 45

(137)

CHƯƠNG 3: DỮ LIỆU KIỂU MẢNG 49

3.1 MẢNG MỘT CHIỀU 49

3.1.1 Ý nghĩa 49

3.1.2 Khai báo 49

3.1.3 Cách sử dụng 50

3.1.4 Ví dụ minh họa 51

3.2 MẢNG NHIỀU CHIỀU .57

3.2.1 Giới thiệu 57

3.2.2 Khai báo 58

3.2.3 Sử dụng 58

3.2.4 Ví dụ minh họa 59

BÀI TẬP CHƯƠNG 65

CHƯƠNG 4: DỮ LIỆU KIỂU CHUỖI 67

4.1 GIỚI THIỆU 67

4.2 KHAI BÁO 67

4.3 CÁCH SỬ DỤNG 68

4.4 PHƯƠNG THỨC NHẬP CHUỖI 68

4.5 MỘT SỐ HÀM XỬ LÝ CHUỖI 69

4.5.1 Hàm strcpy(s, t) 69

4.5.2 Hàm strncpy(s, t, n) 69

4.5.3 Hàm strcat(s, t) 70

4.5.4 Hàm strncat(s, t, n) 70

4.5.5 Hàm strcmp(s, t) 71

4.5.6 Hàm strncmp(s, t, n) 71

4.5.7 Hàm strcmpi(s, t) 71

4.5.8 Hàm strupr(s) 71

4.5.9 Hàm strlwr(s) 72

4.5.10 Hàm strlen(s) 72

4.6 CÁC CHƯƠNG TRÌNH ỨNG DỤNG 72

4.6.1 Chương trình 72

(138)

4.6.3 Chương trình 74

4.6.4 Chương trình 75

BÀI TẬP CHƯƠNG 77

CHƯƠNG 5: CON TRỎ VÀ HÀM 78

5.1 CON TRỎ 78

5.1.1 Ý nghĩa 78

5.1.2 Khai báo biến trỏ 78

5.1.3 Cách sử dụng 78

5.1.4 Các phép toán với trỏ 79

5.1.5 Cấp phát động, toán tử cấp phát thu hồi vùng nhớ 82

5.1.6 Chương trình minh họa 84

5.1.7 Con trỏ chuỗi ký tự 86

5.2 HÀM 87

5.2.1 Định nghĩa 87

5.2.2 Các đặc trưng 87

5.2.3 Khai báo 87

5.2.4 Cấu trúc chung 88

5.2.5 Lời gọi hàm 90

5.2.6 Hàm với đối số mặc định 91

5.2.7 Khai báo hàm trùng tên (Quá tải hàm) 92

5.2.8 Các cách truyền đối số 92

5.3 ĐỆ QUI 96

5.3.1 Khái niệm đệ qui 96

5.3.2 Các đặc điểm hàm đệ qui 97

5.3.3 Lớp toán giải đệ qui 97

5.3.4 Cấu trúc chung hàm đệ qui 98

5.3.5 Các ví dụ 98

BÀI TẬP CHƯƠNG 102

CHƯƠNG 6: DỮ LIỆU KIỂU CẤU TRÚC 105

6.1 GIỚI THIỆU 105

(139)

6.3 CÁCH SỬ DỤNG 106

6.3.1 Đối với biến thường 107

6.3.2 Đối với biến trỏ 107

6.3.3 Đối với biến mảng 108

6.3.4 Đối với cấu trúc lồng 108

6.4 CÁC THAO TÁC CƠ BẢN 109

6.4.1 Thao tác nhập/xuất 109

6.4.2 Phép gán 109

6.5 CÁC CHƯƠNG TRÌNH ỨNG DỤNG 111

6.5.1 Chương trình 111

6.5.2 Chương trình 113

6.5.3 Chương trình 116

BÀI TẬP CHƯƠNG 120

CÁC PHỤ LỤC 123

PHỤ LỤC 1: Bảng mã ASCII với 128 ký tự 123

PHỤ LỤC 2: Bảng mã ASCII với ký tự số 128 - số 255 124

PHỤ LỤC 3: Các nguyên tắc chung sửa lỗi 125

PHỤ LỤC 4: Các thông báo lỗi thường gặp 126

Ngày đăng: 10/03/2021, 17:25

Xem thêm:

TỪ KHÓA LIÊN QUAN

w