Tải bản đầy đủ (.pdf) (34 trang)

Giáo trình Lập trình căn bản (Nghề Kỹ thuật sửa chữa, lắp ráp máy tính): Phần 2 - CĐ nghề Vĩnh Long

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (1.89 MB, 34 trang )

44

CHƯƠNG 4: HÀM
Mục tiêu
− Trình bày được khái niệm hàm;
− Trình bày được qui tắc xây dựng hàm, thủ tục và vận dụng khi thiết kế xây dựng
chương trình;
− Phân biệt được cách sử dụng tham số, tham biến;
− Sử dụng được các lệnh kết thúc và lấy giá trị trả về của hàm
− Thực hiện các thao tác an tồn cho máy.
Nội dung
1. Khái niệm chương trình con
Hàm là một đoạn chương trình có tên và có chức năng giải quyết một số vấn đề
chuyên biệt cho chương trình chính, nó có thể được gọi nhiều lần với các tham số khác
nhau và trả lại một giá trị nào đó cho chương trình gọi nó.
Hàm thường được sử dụng khi:
- Nhu cầu tái sử dụng: có một số cơng việc được thực hiện ở nhiều nơi (cùng một
chương trình hoặc ở nhiều chương trình khác nhau), bản chất khơng đổi nhưng giá trị
các tham số cung cấp khác nhau ở từng trường hợp.
- Nhu cầu sửa lỗi và cải tiến: giúp phân đoạn chương trình để chương trình được
trong sáng, dễ hiểu và do đó rất dễ dàng phát hiện lỗi cũng như cải tiến chương trình.
1.1. Cú pháp

Trong đó:
- <kiểu trả về>: là bất kỳ kiểu dữ liệu nào của C như char, int, long, float hay
double… Nếu hàm đơn thuần chỉ thực hiện một số câu lệnh mà khơng cần trả về cho
chương trình gọi nó thì kiểu trả về này là void.
- <tên hàm>: là tên gọi của hàm và được đặt theo quy tắc đặt tên/định danh.
- <danh sách tham số>: xác định các đối số sẽ truyền cho hàm. Các tham số này
giống như khai báo biến và cách nhau bằng dấu phẩy. Hàm có thể khơng có đối số nào.
- <các câu lệnh>: là các câu lệnh sẽ được thực hiện mỗi khi hàm được gọi.


- <giá trị>: là giá trị trả về cho hàm thơng qua câu lệnh return.
Ví dụ: Hàm sau đây có tên là Tong, nhận vào hai đối số kiểu nguyên và trả về tổng của
hai số nguyên đó.
/* Hàm tên tổng


45

Nhận vào hai số nguyên và trả về một số nguyên */
int Tong(int a, int b){
return a + b;
}
Hàm sau đây có tên là Xuat, nhận vào một đối số kiểu ngun và xuất số ngun
đó ra màn hình. Hàm này khơng trả về gì cả.
void Xuat(int n){
printf(“%d”, n);
}
Hàm sau đây có tên là Nhap, khơng nhận đối số nào cả và trả về giá trị số nguyên
người dùng nhập vào.
int Nhap(){
int n;
printf(“Nhap mot so nguyen: ”); scanf(“%d”, &n);
return n;
}
1.2. Một số lưu ý
Hàm phải được khai báo và định nghĩa trước khi sử dụng và thường đặt ở trên
hàm chính (hàm main).
int Tong(int a, int b){
return a + b;
}

void main(){
int a = 2912, b = 1706;
int sum = Tong(a, b); // Loi goi ham
}
Thông thường, trước hàm main ta chỉ xác định tên hàm, các tham số và giá trị trả
về của hàm để thông báo cho các hàm bên dưới biết cách sử dụng của nó cịn phần định
nghĩa hàm sẽ được đưa xuống dưới cùng. Phần ở trên này được gọi là nguyên mẫu hàm
(function prototype). Nguyên mẫu hàm chính là tiêu đề hàm được kết thúc bằng dấu
chấm phẩy.
int Tong(int a, int b); // prototype hàm Tong
void main(){
int a = 2912, b = 1706;
int sum = Tong(a, b); // Lời gọi hàm
}
int Tong(int a, int b) // Mô tả hàm tổng
{


46

return a + b;
}
Trên thực tế, nguyên mẫu hàm không cần thiết phải giống tuyệt đối tiêu đề hàm.
Tên tham số có thể khác hoặc bỏ ln miễn là cùng kiểu. Tuy nhiên, khơng nên để chúng
khác nhau vì như vậy sẽ gây rối cho chương trình.
Ví dụ sau cho thấy có thể bỏ hẳn tên tham số:
int Tong(int, int);
// prototype ham Tong

2. Cấu trúc chương trình có sử dụng chương trình con

Ví dụ 1

Kết quả in ra màn hình

Giải thích chương trình
- Dịng 8 đến dịng 14: định nghĩa hàm line, hàm này không trả về giá trị, thực
hiện công việc in ra 19 dấu sao.


47

- Dòng 5: khai báo prototype, sau tên hàm phải có dấu chấm phẩy.
- Trong hàm line có sử dụng biến i, biến i là biến cục bộ chỉ sử dụng được trong
phạm vi hàm line.
- Dòng 18 và 20: gọi thực hiện hàm line.
Trình tự thực hiện chương trình

Khơng có dấu chấm phẩy sau tên hàm, phải có cặp dấu ngoặc ( ) sau tên hàm
nếu hàm khơng có tham số truyền vào. Phải có dấu chấm phẩy sau tên hàm khai báo
prototype. Nên khai báo prototype cho dù hàm được gọi nằm trước hay sau câu lệnh
gọi nó.
Ví dụ 2


48

Kết quả in ra màn hình
2 mu 2 = 4.
2 mu 3 = 8.
_

Giải thích chương trình
- Hàm power có hai tham số truyền vào là ix, in có kiểu int và kiểu trả về cũng
có kiểu int.
- Dịng 13: return ip: trả về giá trị sau khi tính tốn.
- Dịng 18: đối mục 2 và 3 có kiểu trả về là int sau khi thực hiện gọi power.
- Hai tham số ix, in của hàm power là dạng truyền tham trị.
Thực hiện chương trình

Quy tắc đặt tên hàm giống tên biến, hằng… Mỗi đối số cách nhau = dấu phẩy
kèm theo kiểu dữ liệu tương ứng.
Ví dụ 3


49

- Hàm time có hai tham số truyền vào là ix, in có kiểu int. 2 tham số này có toán
tử địa chỉ & đi trước cho biết 2 tham số này là dạng truyền tham biến.
Trình tự thực hiện chương trình

3. Các hàm trong ngơn ngữ lập trình
Muốn hàm thực hiện thì trong hàm gọi nó phải thực hiện lời gọi hàm. Việc này
được thực hiện bằng cách gọi tên của hàm đó đồng thời truyền biến hoặc trị cho các tham
số mà chương trình con đã khai báo, các biến hoặc trị này cách nhau bằng dấu phẩy.
Ví dụ 1: chương trình sau định nghĩa thủ tục XuatSo cho phép xuất các số từ a đến b
ra màn hình (a và b được truyền vào hàm). Các tham số đều là tham trị.
#include <stdio.h>
void XuatSo(int a, int b);
void main(){
XuatSo(5, 20);
// Goi ham lan 1

int x = 5;
XuatSo(x, x + 5); // Goi ham lan 2
}
void XuatSo(int a, int b){
for (int i = a; i <= b; i++)


50

printf(“%d\n”, i);
}
Ví dụ 2: chương trình sau định nghĩa hàm HoanVi cho phép hoán vị giá trị của 2 số a
và b truyền vào thủ tục. Các tham số đều là tham chiếu.
#include <stdio.h>
void HoanVi(int &x, int &y);
void main(){
int a, b;
printf(“Nhap 2 so a va b: ”);
scanf(“%d%d”, &a, &b);
printf(“Truoc: a = %d, b = %d”, a, b);
HoanVi(1, 5);
HoanVi(a, b);
printf(“Sau: a = %d, b = %d”, a, b);
}
void HoanVi(int &x, int &y){
int tam = x; x = y;
y = tam;
}
Nhập a = 1, b = 5. Sau khi gọi hàm HoanVi(a, b) giá trị của a = 5, b = 1. Cách gọi
HoanVi(1, 5) sai do phải là biến.

4. Tham trị và tham biến
Tham số trong hàm là kiểu đối số mà chương trình chính truyền khi gọi hàm. Có
hai cách truyền tham số sau đây:
4.1. Tham trị
- Truyền đối số cho hàm ở dạng giá trị.
- Được sử dụng khi ta khơng có nhu cầu thay đổi giá trị của tham số sau khi thực
hiện hàm.
4.2 Tham biến
- Truyền đối số cho hàm ở dạng địa chỉ.
- Tham chiếu được bắt đầu bằng ký hiệu & trong khai báo.
Ví dụ 1:
void thamtri(int n);
// Truyền giá trị
void thambien(int &n);
// Truyền dạng địa chỉ
Ví dụ 2:


51

void
{
ix
iy
}
void
{
ix
iy
}


thamtri(int ix, int iy)
+= 1;
+= 1;
thambien(int &ix, int &iy)
+= 1;
+= 1;

void main(void){
int ia=5,ib=5;
thamtri(ia,ib);
printf("a=%d,b=%d",ia,ib);
thambien(ia, ib);
printf("a=%d,b=%d",ai,ib);
}

Kết quả in ra:

a = 5, b = 5
a = 6, b = 6

5. Biến toàn cục và biến địa phương
Biến toàn cục là những biến được sử dụng mọi nơi trong chương trình. Cịn biến
địa phương chỉ có giá trị trong thời gian hoạt động, sau khi hàm kết thúc thì những biến
khai báo bên trong hàm đó cũng như các tham số của nó cũng kết thúc.
5.1. Biến tồn cục
Ví dụ:
Dịng

File


1
2
3
4
5
6
7
8
9

#include <stdio.h>
#include <conio.h>

10
11

Edit

Search

Run

// khai báo prototype
void oddeven();
void negative();
//khai báo biến toàn cục
int inum;
void main(void)


Compile

Debug

Project

Option

Window

Help


52

12

{

13

printf("Nhap vao 1 so nguyen : ");

14
15
16

scanf("%d", &inum);
oddeven();
negative();


17
18
19

getch();
}

20

// hàm kiểm tra chẳn lẻ

21

void oddeven()

22
23

{

24
25
26
27
28
29
30
31
32

33
34
35
36

if (inum % 2)
printf("%d la so le.\n", inum);
else
printf("%d la sochan.\n", inum);
}
//Hàm kiểm tra số âm
void negative()
{
if (inum < 0)
printf("%d la so am.\n", inum);
else
printf("%d la so duong.\n", inum);
}
F1 Help

Alt-F8 Next Msg

Alt-F7Prev Msg

Alt - F9 Compile

F9 Make

F10 Menu


Kết quả in ra màn hình

Giải thích chương trình
Chương trình trên gồm 2 hàm oddeven và negative, 2 hàm này ta thấy khơng có
tham số để truyền biến inum vào xử lý nhưng vẫn cho kết quả đúng. Do chương trình
sử dụng biến inum tồn cục (dịng 9) nên biến này có ảnh hưởng đến toàn bộ chương


53

trình mỗi khi gọi và sử dụng nó. Xét tình huống sau: Giả sử trong hàm negative ta khai
báo biến inum có kiểu int như sau:
void negative()
{
int inum;
….
}
Khi đó chương trình sẽ cho kết quả sai! Do các câu lệnh trong hàm negative sử
dụng biến inum sẽ sử dụng biến inum khai báo trong hàm negative và lúc này biến inum
tồn cục khơng có tác dụng đối với các câu lệnh trong hàm này. Biến inum khai báo
trong hàm negative chỉ có ảnh hưởng trong phạm vi hàm và chu trình sống của nó bắt
đầu từ lúc gọi hàm đến khi thực hiện xong.
5.2. Biến địa phương
Các biến trong hàm là biến địa phương. Biến địa phương chỉ tồn tại trong thời
gian hàm đó hoạt động.
Tầm tác dụng của biến địa phương chỉ hạn chế trong hàm mà nó được khai báo.
Các biến địa phương cũng sẽ khơng có mối liên hệ nào với biến tồn cục có cùng tên và
cùng kiểu.
Ví dụ
int n;

main()
{
int p;

}
ham_thi_du() {
int p
int n;
….
}
- Các biến địa phương không lưu trữ kết quả cho các lần sau. Lần nào biết lần
ấy, các biến địa phương được sinh ra rồi chết luôn khi ra khỏi hàm.
- Các tham số cũng là biến địa phương. Nghĩa là cũng chỉ hoạt động khi hàm
đó được gọi


54

BÀI TẬP
Lý thuyết
1. Hàm là gì? Tại sao phải sử dụng hàm?
2. Trình bày các thành phần của hàm.
3. Trình bày tóm tắt các cách truyền tham số? Phân biệt sự khác nhau giữa các cách này.
Cho ví dụ minh họa.
Thực hành
4. Viết hàm nhập một số nguyên bất kỳ. Hãy đọc giá trị của số nguyên đó nếu nó có giá
trị từ 0 đến 9, ngược lại thơng báo không đọc được.
5. Viết hàm hập 3 số nguyên a, b và c từ bàn phím. Hãy tìm số có giá trị nhỏ nhất ( hoặc
lớn nhất).
6. Viết hàm tính tiền đi taxi từ số km nhập vào. Biết:

- 1 km đầu giá 15000đ
- Từ km thứ 2 đến km thứ 5 giá 13500đ
- Từ km thứ 6 trở đi giá 11000đ
- Nếu đi hơn 120 km sẽ được giảm 10% trên tổng số tiền.
7. Viết hàm nhập vào tháng, in ra tháng đó có bao nhiêu ngày.
Hướng dẫn: Nhập vào tháng
Nếu là tháng 1, 3, 5, 7,8, 10, 12 thì có 30 ngày
Nếu là tháng 4, 6, 9, 11 thì có 31 ngày
Nếu là tháng 2 và là năm nhuận thì có 29 ngày ngược lại 28 ngày
(Năm nhuận là năm chia chẵn cho 4)
8. Viết chương trình nhập vào 2 số x, y và 1 trong 4 toán tử +, -, *, /. Nếu là + thì in ra
kết quả x + y, nếu là – thì in ra x – y, nếu là * thì in ra x * y, nếu là / thì in ra x / y (nếu
y = 0 thì thơng báo khơng chia được)
9. Viết hàm nhận vào một số nguyên dương n và thực hiện:
a. Có phải là số đối xứng?
Là số nghịch đảo bằng chính nó. Ví dụ: 121, …
b. Có phải là số chính phương?
Là số bằng bình phương số khác. Ví dụ: 4, 9, …
c. Có phải là số nguyên tố?
Là số lớn hơn 1 và chỉ có 2 ước số là 1 và nó. Ví dụ: 2, 3, 5, 7, 11, 13, …
d. Chữ số lớn nhất và nhỏ nhất? Ví dụ: số 1706, nhỏ nhất 0 và lớn nhất 7
e. Các chữ số có tăng dần hay giảm dần khơng? Ví dụ: 12245, 156, 442, 941, …
10. Viết hàm nhận vào một số nguyên dương n và thực hiện:
a. S = 1 + 2 + … + n
b. S = 12 + 22 + … + n2
c. S = 1 + 1/2 + … + 1/n d. S = 1! + 2! + … + n!
11. Viết hàm trả về USCLN của 2 số nguyên.
12. Viết hàm in ra n phần tử của dãy Fibonacy



55

CHƯƠNG 5: DỮ LIỆU KIỂU MẢNG (ARRAY),
CHUỖI KÝ TỰ (STRING) VÀ BẢN CHI (STRUCT)
Mục tiêu
− Trình bày được khái niệm mảng, chuỗi ký tự và bản ghi;
− Thực hiện cách khai báo, gán giá trị cho mảng, chuỗi ký tự và bản ghi;
− Thực hiện các thao tác và truy xuất cho mảng, chuỗi ký tự và bản ghi;
− Thực hiện các thao tác an tồn với máy tính.
Nội dung
1. Dữ liệu kiểu mảng
1.1. Khái niệm
Mảng là một tổ chức kiểu dữ liệu có cấu trúc bao gồm một số cố định các thành phần
có cùng kiểu. Mỗi thành phần của mảng được truy xuất thông qua các chỉ số mơ tả vị
trí của thành phần đó trong mảng.
1.2. Khai báo mảng
2.2.1. Khai báo kiểu mảng
Cú pháp:
typedef <kiểu cơ sở> <tên kiểu mảng>[<số phần tử>];

Trong đó:
- <tên kiểu mảng>: tên kiểu mảng theo quy định đặt tên/định danh.
- <kiểu cơ sở> : kiểu dữ liệu của các thành phần trong mảng.
- <số phần tử> : số lượng phần tử của mảng.
Ví dụ: khai báo kiểu dữ liệu mảng một chiều có tên MangInt (gồm 20 phần tử kiểu số
nguyên) và MangFloat (gồm 30 phần tử kiểu số thực).
typedef int MangInt[20];
typedef float MangFloat[30];
2.2.2. Khai báo biến mảng
Biến mảng được khai báo trực tiếp (tường minh) như sau:

Cú pháp:
<kiểu cơ sở> <tên biến mảng>[<số phần tử>];

2.2.3. Khởi tạo giá trị cho mảng khi khai báo
Ta có thể khởi tạo giá trị cho mảng một chiều thông qua các cách sau:
- Khởi tạo giá trị cho mọi phần tử của mảng.


56

int a[4] = {2912, 1706, 1506, 1904};
Mảng a gồm 4 phần tử 2912, 1706, 1506, 1904
- Khởi tạo giá trị cho một số phần tử đầu tiên của mảng.
Các phần tử cịn lại sẽ có giá trị 0.
int a[4] = {2912, 1706};
Mảng a gồm 4 phần tử 2912, 1706, 0, 0
- Khởi tạo giá trị 0 cho tất cả các phần tử của mảng, ta chỉ cần khởi tạo phần tử
đầu bằng 0.
int a[100] = {0};
- Trình biên dịch tự xác định số phần tử của mảng thông qua danh sách khởi tạo
nếu số phần tử không được chỉ rõ.
int a[] = {2912, 1706, 1506, 1904};
Mảng a sẽ gồm 4 phần tử 2912, 1706, 1506, 1904.
1.3. Gán giá trị cho mảng
1.3.1. Truy xuất dữ liệu kiểu mảng
Truy xuất đến từng phần tử của mảng thông qua cú pháp sau:
Cú pháp:
<biến mảng>[<gt cs1>][<gt cs2>]…[<gt csn>]
Trong đó <gt cs1>, <gt cs1>, ..., <gt csn>: là các giá trị cụ thể của phần tử trong
mảng muốn truy xuất.

Lưu ý, mảng a có n phần tử thì chỉ số của mảng sẽ từ 0 đến n–1. Tức mà các phần
tử của mảng là a[0], a[1], …, a[n-1].
Ví dụ, cho hai mảng sau:
int MangSo[100]; float DiemHK[100][2];
Lúc này, phần tử thứ 3 của mảng có chỉ số là 2: MangSo[2], điểm thi môn thứ
nhất của sinh viên thứ 2: DiemHK[1, 0]…
Không thể nhập xuất trực tiếp biến kiểu mảng mà phải thông qua từng thành phần
của mảng đó.
Ví dụ:
printf(“%d”, MangSo);
// Sai
printf(“%d”, MangSo[2]);
// Dung
printf(“%f”, DiemHK);
// Sai
printf(“%f”, DiemHK[1][0]); // Dung
Không thể dùng lệnh gán thông thường để gán dữ liệu giữa hai kiểu mảng cùng
loại. Thay vào đó, ta sẽ gán dữ liệu trực tiếp giữa từng phần tử tương ứng.


57

Gán trực tiếp từng phần tử
<biến mảng đích>[<chỉ số thứ i>] =
<biến mảng nguồn>[<chỉ số thứ i>];
Ví dụ:
typedef int MangSo[3];
MangSo a, b = {1, 2, 3};
a = b;
for (int i=0; i<3; i++)

a[i] = b[i];

// Sai
// Dung

1.3.2. Truyền mảng cho hàm
Tham số kiểu mảng trong khai báo hàm giống khai báo mảng.
void SapXepTang(int a[100]);
Tham số kiểu mảng được truyền cho hàm chính là địa chỉ của phần tử đầu tiên
của mảng do đó số lượng phần tử trong tham số mảng có thể bỏ trống hoặc ta khai báo
dạng con trỏ.
void SapXepTang(int a[]);
// Cach 1
void SapXepTang(int *a);
// Cach 2
Do ta chỉ truyền địa chỉ của phần tử đầu tiên của mảng nên số thành phần thực
sự được sử dụng phải được truyền cho hàm thông qua một tham số khác.
// n la so phan tu thuc su duoc su dung
void SapXepTang(int a[], int n);
void SapXepTang(int *a, int n);
Do biến mảng chính là địa chỉ của phần tử đầu tiên của mảng đó nên khi gọi hàm,
ta chỉ việc truyền tên biến mảng cho hàm. Lưu ý, nội dung của mảng có thể thay đổi khi
kết thúc hàm.
void NhapMang(int a[], &n);
void SapXepTang(int a[], int n);
void XuatMang(int a[], n);
void main(){
int a[100]; int n;
NhapMang(a, n);
// Goi ham NhapMang

SapXepTang(a, n); // Goi ham SapXepTang
XuatMang(a, n);
// Goi ham XuatMang
}
1.4. Một số bài toán trên mảng
1.4.1. Một số qui ước


58

Mảng được xét là mảng các số nguyên và số phần tử tối đa của mảng là
MAX = 100.
#define MAX 100
1.4.2. Nhập mảng
Yêu cầu
Viết thủ tục nhập mảng cho phép người sử dụng nhập số lượng phần tử n thực tế
của mảng a và lần lượt nhập vào giá trị cho từng phần tử trong mảng này.
Ý tưởng
- Nhập số lượng phần tử thực tế n của mảng.
- Lần lượt nhập giá trị cho n phần tử của mảng từ chỉ số 0 đến chỉ số n – 1.
Cài đặt
Thủ tục nhập mảng
Đầu vào : mảng a, số lượng phần tử n (tham chiếu)
Đầu ra
: khơng có
void NhapMang(int a[], int &n){
// Nhap so luong phan tu n cua mang
printf(“Nhap so phan tu n: ”);
scanf(“%d”, &n);
// Nhap gia tri cho n phan tu cua mang

for (int i = 0; i < n; i++){
printf(“Nhap phan phan tu thu %d: ”, i);
scanf(“%d”, &a[i]);
}
}
Lưu ý
- Tham số n (số lượng phần tử) phải là tham chiếu (có dấu &) vì nội dung sẽ thay
đổi sau khi thực hàm.
- Vì số lượng phần tử lớn nhất là MAX nên khi cần có thể kiểm tra xem n có vượt
q MAX hay khơng trước khi cho nhập mảng.
1.4.3. Xuất mảng
Yêu cầu
Viết thủ tục xuất mảng cho phép người sử dụng xuất nội dung mảng a cho trước
với số lượng phần tử là n.
Ý tưởng
- Lần lượt xuất giá trị của n phần tử trong mảng từ chỉ số 0 đến chỉ số n – 1.


59

Cài đặt
Thủ tục xuất mảng
Đầu vào : mảng a, số lượng phần tử n
Đầu ra
: khơng có
void XuatMang(int a[], int n){
// Xuat gia tri cua N phan tu trong mang
printf(“Noi dung cua mang la: ”);
for (int i = 0; i < n; i++)
printf(“%d ”, a[i]);

printf(“\n”);
}
Lưu ý:
Tham số n không cần thiết phải là tham chiếu (khơng cần &) vì nội dung sẽ không thay
đổi sau khi thực hiện hàm.
1.5. Mảng nhiều chiều
1.5.1. Khái niệm
Ví dụ: Khảo sát ma trận:


60

1.5.2. Khai báo kiểu mảng 2 chiều
Cú pháp:
typedef <kiểu cơ sở> <tên kiểu>[<N1>][<N2>];
N1, N2: số lượng phần tử mỗi chiều
Ví dụ:
typedef int MaTran[3][4];

Cú pháp (tường minh)
<kiểu cơ sở> <tên biến> [<N1>][<N2>];

Cú pháp (không tường minh – thông qua kiểu)
Typedef <kiểu cơ sở> <tên kiểu> [<N1>][<N2>];
<tên kiểu> <tên biến>;
<tên kiểu> <tên biến 1>, <tên biến 2>;
Ví dụ: (tường minh)
int a[10][20], b[10][20];
int c[5][10];
int d[10][20];

Ví dụ: (khơng tường minh – thơng qua kiểu)
typedef int MaTran10x20[10][20];
typedef int MaTran5x10[5][10];
MaTran10x20 a, b;
MaTran11x11 c;
MaTran10x20 d;
1.5.3. Truy xuất đến một phần tử
Thông qua chỉ số
<tên biến mảng>[<giá trị cs1>][<giá trị cơ sở 2>]


61

Ví dụ:

Cho mảng 2 chiều như sau:
int a[3][4];
Các truy xuất
Hợp lệ: a[0][0], a[0][1], ..., a[2][2],
a[2][3]
Không hợp lệ: a[-1][0], a[2][4], a[3][3]
Gán dữ liệu kiểu mảng
Không được sử dụng phép gán thông thường mà phải gán trực tiếp giữa các phần tử.

<biến mảng đích> = <biến mảng nguồn>;
// sai
<biến mảng đích>[<giá trị cs1>][<giá trị cơ sở 2>] = <giá trị>

Ví dụ:
int

b =
int
for

a[5][10], b[5][10];
a;
//sai
i, j;
(i = 0; i < 5; i++)
for (j = 0; j< 10; j++ )
b[i][j] = a[i][j];

Truyền tham số cho hàm
- Tham số kiểu mảng trong khai báo hàm giống như khai báo biến mảng
void NhapMaTran(int a[50][100]);
- Tham số kiểu mảng truyền cho hàm chính là địa chỉ của phần tử đầu tiên của mảng.
• Có thể bỏ số lượng phần tử chiều thứ 2 hoặc con trỏ.
• Mảng có thể thay đổi nội dung sau khi thực hiện hàm.
void NhapMaTran(int a[][100]);
void NhapMaTran(int (*a)[100]);
Truyền mảng cho hàm
- Số lượng phần tử thực sự truyền qua biến khác.
void XuatMaTran(int a[50][100], int m, int n);
void XuatMaTran(int a[][100], int m, int n);
void XuatMaTran(int (*a)[100], int m, int n);
- Lời gọi hàm
void XuatMaTran(int a[][100], int &m, int &n);
void XuatMaTran(int a[][100], int m, int n);
void main(){
int a[50][100], m, n;

NhapMaTran(a, m , n);
XuatMaTran(a, m, n);
}


62

1.5.4. Một số bài toán cơ bản
Một số qui ước
Kiểu dữ liệu:
#define MAXD 50
#define MAXC 50
Nhập ma trận
Yêu cầu: Cho phép nhập mảng a, m dòng, n cột.
Ý tưởng:
- Cho trước một mảng 2 chiều có dịng tối đa là MAXD, số cột tối đa là MAXC.
- Nhập số lượng phần tử thực sự m, n của mỗi chiều.
- Nhập từng phần tử từ [0][0] đến [m-1][n-1].
Hàm nhập ma trận
void NhapMaTran(int a[][MaxC], int &m, int &n){
printf(“Nhap so dong, so cot cua ma tran: ”);
scanf(“%d%d”,&m, &n);
int i, j;
for (i = 0; ifor (j = 0; jprintf(“Nhap a[%d][%d]: ”,i,j);
scanf(“%d”,&a[i][j]);
}
}
Xuất ma trận

Yêu cầu: cho phép nhập mảng a, m dòng, n cột.
Ý tưởng: xuất giá trị từng phần tử của mảng 2 chiều từ dịng có 0 đến dịng
m -1, mỗi dòng xuất giá trị của cột 0 đến cột n-1 trên dịng đó.
Hàm xuất ma trận:
void XuatMaTran(int a[][MAXC], int m, int n){
int i, j;
for (i = 0; ifor (j = 0; jprintf(“%d”,a[i][j]);
printf(“\n”);
}
}


63

2. Dữ liệu kiểu chuỗi ký tự
2.1. Khái niệm
Chuỗi ký tự là một dãy gồm các ký tự hoặc một mảng các ký tự được kết thúc
bằng ký tự '\0' (còn được gọi là ký tự NULL trong bảng mã Ascii).
Các hằng chuỗi ký tự được đặt trong cặp dấu nháy kép "".
2.2. Khai báo chuỗi
2.2.1. Khai báo theo mảng
Cú pháp:
char <Biến> [Chiều dài tối đa]
Ví dụ: Trong chương trình, ta có khai báo:
char Ten[12];
Trong khai báo này, bộ nhớ sẽ cung cấp 12-1 bytes để lưu trữ nội dung của chuỗi
ký tự Ten; byte cuối cùng lưu trữ ký tự ‘\0’ để chấm dứt chuỗi.
Ghi chú:

Chiều dài tối đa khơng nên khai báo thừa để tránh lãng phí bộ nhớ, nhưng cũng
không nên khai báo thiếu.
2.2.2. Khai báo theo con trỏ
Cú pháp:
char *<Biến>
Ví dụ: Trong chương trình, ta có khai báo:
char *Ten;
Trong khai báo này, bộ nhớ sẽ dành 2 byte để lưu trữ địa chỉ của biến con trỏ Ten
đang chỉ đến, chưa cung cấp nơi để lưu trữ dữ liệu. Muốn có chỗ để lưu trữ dữ liệu, ta phải
gọi đến hàm malloc() hoặc calloc() có trong “alloc.h”, sau đó mới gán dữ liệu cho biến.
2.2.3. Vừa khai báo vừa gán giá trị
Ví dụ:
#include<stdio.h>
#include<conio.h>
int main(){
char Chuoi[]="Mau nang hay la mau mat em" ;
printf("Vua khai bao vua gan trị : %s",Chuoi) ;
getch();
return 0;
}
Ghi chú: Chuỗi được khai báo là một mảng các ký tự nên các thao tác trên mảng có thể
áp dụng đối với chuỗi ký tự.


64

2.3. Các thao tác trên chuỗi
Không thể gán giá trị hay sử dụng phép toán + (ghép chuỗi) và các phép toán so
sánh như: > (lớn hơn), < (nhỏ hơn),… mà phải gọi các hàm thư viện trong <string.h>;
2.3.1. Cộng chuỗi - Hàm strcat()

Cú pháp:
char *strcat(char *des, const char *source)
Hàm này có tác dụng ghép chuỗi nguồn vào chuỗi đích.
Ví dụ: Nhập vào họ lót và tên của một người, sau đó in cả họ và tên của họ lên màn
hình.
#include<conio.h>
#include<stdio.h>
#include<string.h>
int main(){
char HoLot[30], Ten[12];
printf("Nhap Ho Lot: ");gets(HoLot);
printf("Nhap Ten: ");gets(Ten);
strcat(HoLot,Ten); /* Ghep Ten vao HoLot*/
printf("Ho ten la: ");puts(HoLot);
getch();
return 0;
}
2.3.2 Xác định độ dài chuỗi - Hàm strlen()
Cú pháp:
int strlen(const char* s);
Ví dụ: Sử dụng hàm strlen xác định độ dài một chuỗi nhập từ bàn phím.
#include<conio.h>
#include<stdio.h>
#include<string.h>
int main(){
char Chuoi[255];
int Dodai;
printf("Nhap chuoi: ");gets(Chuoi);
Dodai = strlen(Chuoi)
printf("Chuoi vua nhap: ");puts(Chuoi);

printf("Co do dai %d",Dodai);
getch();


65

return 0;
}
2.3.3. Đổi một ký tự thường thành ký tự hoa - Hàm toupper()
Hàm toupper() (trong ctype.h) được dùng để chuyển đổi một ký tự thường thành
ký tự hoa.
Cú pháp:
char toupper(char c)
2.3.4. Đổi chuỗi chữ thường thành chuỗi chữ hoa, hàm strupr()
Hàm struppr() được dùng để chuyển đổi chuỗi chữ thường thành chuỗi chữ hoa,
kết quả trả về của hàm là một con trỏ chỉ đến địa chỉ chuỗi được chuyển đổi.
Cú pháp:
char* strupr(char *s)
Ví dụ: Viết chương trình nhập vào một chuỗi ký tự từ bàn phím. Sau đó sử dụng hàm
strupr() để chuyển đổi chúng thành chuỗi chữ hoa.
#include<conio.h>
#include<stdio.h>
#include<string.h>
int main(){
char Chuoi[255],*s;
printf("Nhap chuoi: ");gets(Chuoi);
s=strupr(Chuoi) ;
printf(“Chuoi chu hoa: ”);puts(s);
getch();
return 0;

}
2.3.5. Đổi chuỗi chữ hoa thành chuỗi chữ thường, hàm strlwr()
Muốn chuyển đổi chuỗi chữ hoa thành chuỗi toàn chữ thường, ta sử dụng hàm
strlwr(), các tham số của hàm tương tự như hàm strupr();
Cú pháp:
char *strlwr(char *s)

2.4. Nhập, xuất chuỗi
Để xuất chuỗi, ta có thể sử dụng hàm printf với đặc tả “%s” hoặc hàm puts như
sau:


66

Hàm xuất dữ liệu ra màn hình (#include <stdio.h>)
int puts(const char *s);
Hàm puts xuất chuỗi s ra màn hình và tự động xuống dịng.
Nếu thành cơng sẽ trả về giá trị khơng âm, ngược lại sẽ
trả về EOF.

Ví dụ:
char ten[] = “THCS A”;
printf(“%s”, ten); // Khong xuong dong
puts(ten);
// Tu dong xuong dong
Để nhập chuỗi, ta có thể sử dụng hàm scanf( ) với đặc tả “%s” nhưng hàm này
chỉ đọc các ký tự từ bàn phím đến khi gặp ký tự khoảng trắng.
Ví dụ:
char ten[100; scanf(“%s”, &ten);
puts(ten);

Nếu nhập vào “THCS A” thì chỉ nhận được chuỗi “THCS”
Để nhập được một chuỗi đầy đủ, ta sử dụng hàm sau:
Hàm nhập dữ liệu từ bàn phím (#include <stdio.h>)
char *gets(char *s);
Hàm gets đọc tất cả các ký tự nhập từ bàn phím đến
khi gặp ký tự sang dòng mới (khi ta nhấn enter). Hàm
gets sẽ loại bỏ ký tự enter và thêm vào chuỗi ký tự
kết thúc chuỗi ‘\0’. Hàm gets trả về địa chỉ của chuỗi
nhận được.
Ví dụ:
char ten[100];
gets(ten);
puts(ten);
2.5. Các hàm làm việc với chuỗi
2.5.1. Sao chép một phần chuỗi, hàm strncpy()
Hàm này cho phép chép n ký tự đầu tiên của chuỗi nguồn sang chuỗi đích.
Cú pháp:
char *strncpy(char *Des, const char *Source, size_t n)

2.5.2. Trích một phần chuỗi, hàm strchr()
Để trích một chuỗi con của một chuỗi ký tự bắt đầu từ một ký tự được chỉ định
trong chuỗi cho đến hết chuỗi, ta sử dụng hàm strchr().


67

Cú pháp:
char *strchr(const char *str, int c)
Ghi chú:
- Nếu ký tự đã chỉ định khơng có trong chuỗi, kết quả trả về là NULL.

- Kết quả trả về của hàm là một con trỏ, con trỏ này chỉ đến ký tự c được tìm thấy
đầu tiên trong chuỗi str.
2.5.3. Tìm kiếm nội dung chuỗi, hàm strstr()
Hàm strstr() được sử dụng để tìm kiếm sự xuất hiện đầu tiên của chuỗi s2 trong
chuỗi s1.
Cú pháp:
char* strstr(const char *s1, const char *s2)
Kết quả trả về của hàm là một con trỏ chỉ đến phần tử đầu tiên của chuỗi s1 có
chứa chuỗi s2 hoặc giá trị NULL nếu chuỗi s2 khơng có trong chuỗi s1.
Ví dụ: Viết chương trình sử dụng hàm strstr() để lấy ra một phần của chuỗi gốc bắt đầu
từ chuỗi "hoc".
1.
#include<conio.h>
2.
#include<stdio.h>
3.
#include<string.h>
4.
int main()
5.
{
6.
char Chuoi[255],*s;
7.
printf("Nhap chuoi: ");gets(Chuoi);
8.
s=strstr(Chuoi,"hoc");
9.
printf("Chuoi trich ra: ");puts(s);
10.

getch();
11.
return 0;
12. }
2.5.4. So sánh chuỗi, hàm strcmp()
Để so sánh hai chuỗi theo từng ký tự trong bảng mã Ascii, ta có thể sử dụng hàm
strcmp().
Cú pháp:
int strcmp(const char *s1, const char *s2)
Hai chuỗi s1 và s2 được so sánh với nhau, kết quả trả về là một số nguyên (số này
có được bằng cách lấy ký tự của s1 trừ ký tự của s2 tại vị trí đầu tiên xảy ra sự khác nhau).
- Nếu kết quả là số âm, chuỗi s1 nhỏ hơn chuỗi s2.
- Nếu kết quả là 0, hai chuỗi bằng nhau.
- Nếu kết quả là số dương, chuỗi s1 lớn hơn chuỗi s2.


68

2.5.5. So sánh chuỗi, hàm stricmp()
Hàm này thực hiện việc so sánh trong n ký tự đầu tiên của 2 chuỗi s1 và s2, giữa
chữ thường và chữ hoa không phân biệt.
Cú pháp:
int stricmp(const char*s1, const char *s2)
Kết quả trả về tương tự như kết quả trả về của hàm strcmp().
2.5.6. Khởi tạo chuỗi, hàm memset()
Hàm này được sử dụng để đặt n ký tự đầu tiên của chuỗi là ký tự c.
Cú pháp:
memset(char *Des, int c, size_t n)
2.5.7. Đổi từ chuỗi ra số, hàm atoi(), atof(), atol() (trong stdlib.h)
Để chuyển đổi chuỗi ra số, ta sử dụng các hàm trên.

Cú pháp:
− int atoi(const char *s): chuyển chuỗi thành số nguyên
− long atol(const char *s): chuyển chuỗi thành số nguyên
dài

− float atof(const char *s): chuyển chuỗi thành số thực
Nếu chuyển đổi không thành công, kết quả trả về của các hàm là 0.
Ngồi ra, thư viện string.h cịn hỗ trợ các hàm xử lý chuỗi khác, ta có thể đọc
thêm trong phần trợ giúp.
3. Dữ liệu kiểu bản ghi
3.1. Khái niệm
Kiểu cấu trúc (Structure) là kiểu dữ liệu bao gồm nhiều thành phần có kiểu khác
nhau, mỗi thành phần được gọi là một trường (field).
Sự khác biệt giữa kiểu cấu trúc và kiểu mảng là: các phần tử của mảng là cùng
kiểu còn các phần tử của kiểu cấu trúc có thể có kiểu khác nhau.

Định nghĩa kiểu cấu trúc
Cách 1:
struct <tên kiểu cấu trúc>


×