§¹i häc Th¸i Nguyªn-Tr−êng §HSP. Khoa To¸n-Tin
NguyÔn M¹nh §øc – Ng«n ng÷ lËp tr×nh C++
Ch−¬ng 6
C¸c kiÓu d÷ liÖu cã cÊu tróc
6.1. D÷ liÖu kiÓu struct
6.1.1. Khai b¸o kiÓu struct
Có ph¸p khai b¸o chung mét kiÓu d÷ liÖu cÊu tróc cã d¹ng chung nh−
sau:
struct [<struct type name>]
{
[<type> <variable name[, variable name, ...]>];
[<type> <variable name[, variable name, ...]>];
...
} [structure variable>];
VÝ dô:
struct date
{
int ngay, thang, nam;
};
struct HOSO
{
char hoten[25];
struct date ngay_sinh;
char diachi[30];
float hesoluong;
} nhansu;
struct HOSO hscb[100];
struct HOSO nguoi1, nguoi2;
54
Đại học Thái Nguyên-Trờng ĐHSP. Khoa Toán-Tin
Nguyễn Mạnh Đức Ngôn ngữ lập trình C++
6.1.2. Truy nhập vào các thành phần của cấu trúc
Để truy nhập vào các thành phần của cấu trúc, ta làm nh sau:
tên_biến_cấu_trúc.tên thành phần
tên_biến_cấu_trúc.tên_biến_cấu_trúc.tên thành phần
Ví dụ:
gets(nhansu.hoten);
nhansu.ngay_sinh.nam = 1985;
nhansu.hesoluong = 2.88;
cout << nhansu.hoten;
Ví dụ chơng trình 6.1:
# include
# include
# include
const N =
<iostream.h>
<conio.h>
<stdio.h>
100;
struct date
{
int ngay, thang, nam;
} ;
struct HOSO
{
char hoten[25];
date ngay_sinh;
char que[30];
float hesoluong;
} nhansu[N];
int sn;
void NHAP()
{
sn = 0;
while (1)
{
cout << "Ho va ten : ";
gets(nhansu[sn].hoten);
cout << "Ngay sinh : " << endl;
cout << "
ngay : ";
cin >> nhansu[sn].ngay_sinh.ngay;
55
Đại học Thái Nguyên-Trờng ĐHSP. Khoa Toán-Tin
Nguyễn Mạnh Đức Ngôn ngữ lập trình C++
cout << "
thang : ";
cin >> nhansu[sn].ngay_sinh.thang;
cout << "
nam : ";
cin >> nhansu[sn].ngay_sinh.nam;
cout << "Que quan
: ";
gets(nhansu[sn].que);
cout << "He so luong: ";
cin >> nhansu[sn].hesoluong;
char tl;
cout <<"\nNhap nua khong (C/K) ? ";
cin >> tl;
sn = sn+1;
if (tl == 'k' || tl == 'K') break;
}
}
void INRA()
{
for (int i=0; i
{
cout << nhansu[i].hoten << " "
<< nhansu[i].ngay_sinh.nam << "
<< nhansu[i].que << " "
<< nhansu[i].hesoluong << endl;
}
}
"
void main()
{
clrscr();
NHAP();
clrscr();
INRA();
getch();
}
6.1.2. Con trỏ cấu trúc và địa chỉ cấu trúc
6.1.2.1. Cỏn trỏ và địa chỉ
Khi đã có một cấu trúc, ta có thể khai báo con trỏ cấu trúc nh sau:
struct <tên cấu trúc> *<tên con trỏ cấu trúc>;
Ví dụ: giả sử đã có cấu trúc HOSO nh trong mục 6.1.1, ta có thể khai
bái các con trỏ theo cấu trúc đó nh sau:
struct HOSO *p1, *p2, *p3, nguoi1, nguoi2, list[100];
56
Đại học Thái Nguyên-Trờng ĐHSP. Khoa Toán-Tin
Nguyễn Mạnh Đức Ngôn ngữ lập trình C++
hoặc:
HOSO *p1, *p2, *p3, nguoi1, nguoi2, list[100];
Cỏn trỏ có cấu trúc để lu địa chỉ của biến có cấu trúc và mảng có cấu
trúc.
Ví dụ: tiếp theo khai báo ở trên, các lệnh sau là hợp lệ:
p1 = &nguoi1;
p2 = &list[2];
p3 = list;
6.1.2.2. Truy nhập thông qua con trỏ
Ta có thể truy nhập đến các thành phần thông qua con trỏ nh sau:
<tên con trỏ> -> <tên thành phần>;
hoặc:
(*tên con trỏ).<tên thành phần>;
Ví dụ:
p1 -> ngay_sinh.nam
(*p2).ngay_sinh.thang
Có thể dùng phép gán thông qua con trỏ:
p1 = &nguoi1;
list[4] = *p1;
//the same: list[4] = nguoi1;
p2 = &list[2];
*p2 = nguoi2;
// the same: list[2] = nguoi2;
6.1.2.3. Con trỏ và mảng
Giả sử có con trỏ p trỏ tới đầu mảng list. Có thể truy nhập tới các thành
phần của mảng bằng các cách sau:
list[i].thành_phần
p[i].thành_phần
(p+i).thành_phần
Ví dụ các cách viết nh sau có tác dụng mh nhau:
list[i].hoten
p[i].hoten
(p+i)->hoten
57
Đại học Thái Nguyên-Trờng ĐHSP. Khoa Toán-Tin
Nguyễn Mạnh Đức Ngôn ngữ lập trình C++
Chú ý rằng các cách viết nh sau là tơng đơng:
list[i]
p[i]
*(p+i)
6.1.2.4. Hàm trên các cấu trúc
Các đối của hàm có thể là:
Biến cấu trúc, khi đó tham số thực tơng ứng là giá trị của cấu
trúc.
Con trỏ cấu trúc, khi đó tham số thực tơng úng là địa chỉ của
biến cấu trúc.
Mảng cấu trúc hoặc con trỏ cấu trúc, khi đó tham số thực tơng
ứng là tên mảng cấu trúc.
Hàm có thể trả về:
Giá trị của cấu trúc.
Con trỏ cấu trúc.
Ví dụ chơng trình 6.2: Thực hiện các phép toán số phức.
# include <iostream.h>
# include <conio.h>
# include <math.h>
struct SP
{
float x, y;
};
SP
SP
SP
SP
SP
SP
SP
void
SOPHUC(float p, float q);
CONG(SP a, SP b);
TRU(SP a, SP b);
NHAN(SP a, SP b);
CHIA(SP a, SP b);
NDAO(SP a);
KCAN(SP a);
INRA(SP a);
void main()
{
clrscr();
INRA(SOPHUC(9, -2));
58
§¹i häc Th¸i Nguyªn-Tr−êng §HSP. Khoa To¸n-Tin
NguyÔn M¹nh §øc – Ng«n ng÷ lËp tr×nh C++
INRA(SOPHUC(5, 19));
INRA(CONG(SOPHUC(9, -2), SOPHUC(5,
INRA(TRU(SOPHUC(9, -2), SOPHUC(5,
INRA(NHAN(SOPHUC(9, -2), SOPHUC(5,
INRA(CHIA(SOPHUC(9, -2), SOPHUC(5,
INRA(NDAO(SOPHUC(5, 19)));
getch();
19)));
19)));
19)));
19)));
}
SP SOPHUC(float p, float q)
{
SP z;
z.x = p; z.y = q;
return z;
}
void INRA(SP a)
{
cout << "\nZ = " << a.x;
if (a.y >= 0) cout << " + " << a.y << "i";
else cout << " - " << fabs(a.y) << "i";
}
SP CONG(SP a, SP b)
{
SP t;
t.x = a.x+b.x;
t.y = a.y+b.y;
return t;
}
SP TRU(SP a, SP b)
{
SP t;
t.x = a.x-b.x;
t.y = a.y-b.y;
return t;
}
SP NHAN(SP a, SP b)
{
SP t;
t.x = a.x*b.y - a.y*b.y;
t.y = a.x*b.y + a.y*b.x;
return t;
}
59
§¹i häc Th¸i Nguyªn-Tr−êng §HSP. Khoa To¸n-Tin
NguyÔn M¹nh §øc – Ng«n ng÷ lËp tr×nh C++
SP CHIA(SP a, SP b)
{
SP t;
t.x = (a.x*b.x+a.x*b.x)/(b.x*b.x+b.y*b.y);
t.y = (b.x*a.y-a.x*b.y)/(b.x*b.x+b.y*b.y);
return t;
}
SP NDAO(SP a)
{
SP t;
t.x = a.x/(a.x*a.x+a.y*a.y);
t.y = a.y/(a.x*a.x+a.y*a.y);
return t;
}
VÝ dô ch−¬ng tr×nh 6.3:
#
#
#
#
include
include
include
include
<iostream.h>
<conio.h>
<stdio.h>
<string.h>
struct date { int
ngay, thang, nam; } ;
struct HOSO
{
char hoten[25];
date ngay_sinh;
char que[30];
float hesoluong;
};
void
void
HOSO
void
void
NHAP(HOSO *hs);
INRA(HOSO hs);
*TIM(char *ht, HOSO hoso[], int n);
HOANVI(HOSO *hs1, HOSO *hs2);
SAPXEP(HOSO *hs, int n);
void main()
{
HOSO *p, ds[50]; int i, j, n = 3;
clrscr();
for (i=0; i
SAPXEP(ds, n);
clrscr();
for (i=0; i
60
§¹i häc Th¸i Nguyªn-Tr−êng §HSP. Khoa To¸n-Tin
NguyÔn M¹nh §øc – Ng«n ng÷ lËp tr×nh C++
}
char ht[25] = "nam";
if (TIM(ht,ds,n) != NULL) INRA(*TIM(ht, ds, n));
else cout << "\Khong co " << ht;
getch();
void NHAP(HOSO *hs)
{
HOSO h;
cout << "Ho va ten :
cout << "Ngay sinh :
cout << "
ngay :
cout << "
thang :
cout << "
nam :
cout << "Que quan
:
cout << "He so luong:
*hs = h;
}
"; gets(h.hoten);
" << endl;
"; cin >> h.ngay_sinh.ngay;
"; cin >> h.ngay_sinh.thang;
"; cin >> h.ngay_sinh.nam;
"; gets(h.que);
"; cin >> h.hesoluong;
void INRA(HOSO hs)
{
cout<
<
}
"
HOSO *TIM(char *ht, HOSO hoso[], int n)
{
for (int i=0; i
if (strcmp(ht,hoso[i].hoten)==0)return &hoso[i];
return (NULL);
}
void HOANVI(HOSO *hs1, HOSO *hs2)
{ HOSO tg;
tg
= *hs1;
*hs1 = *hs2;
*hs2 = tg;
}
// Sap xep theo nam sinh
void SAPXEP(HOSO *hs, int n)
{
int i, j;
for (i=0; i
for (j=i+1; j
if (hs[i].ngay_sinh.nam>hs[j].ngay_sinh.nam)
HOANVI(&hs[i], &hs[j]);
}
61
Đại học Thái Nguyên-Trờng ĐHSP. Khoa Toán-Tin
Nguyễn Mạnh Đức Ngôn ngữ lập trình C++
6.2. Cấu trúc tự trỏ và danh sách liên kết
6.2.1. Cấp phát bộ nhớ động
Trong thực tế chúng ta gặp nhiều bài toán cha biết phải xử lý chính xác
bao nhiêu đối tợng. Thờng thì phải khai báo số lợng phần tử tối đa, nh
vậy trong nhiều trờng hợp sẽ lãng phí nhiều ô nhớ không cần thiết, chơng
trình không tối u ...
Để tối u hoá hệ thống, tăng tốc độ xử lý ... chúng ta sẽ sử dụng phơng
pháp cấp phát bộ nhớ động, các đối tợng xử lý đợc tự động cấp phát số ô
nhớ đúng theo yêu cầu thực tế.
Các hàm cấp phát bộ nhớ của C nằm trong tệp alloc.h, do đó để sử dụng
đợc các hàm này phải có khai bao sau ở đầu chơng trình:
# include <alloc.h>
Sau đây là một số hàm cấp phát bộ nhớ.
Hàm void *calloc(unsigned n, unsigned size) : Cấp phát vùng nhớ
n*size byte, nếu thành công hàm trả về địa chỉ đầu vùng nhớ đợc
cấp, nếu không đủ bộ nhớ để cấp phát hàm trả về NULL.
Hàm void *malloc(unsigned n) : Cấp phát vùng nhớ n byte, nếu
thành công hàm trả về địa chỉ đầu vùng nhớ đợc cấp, nếu không đủ
bộ nhớ để cấp phát hàm trả về NULL.
biến_con_trỏ = new data_type: Cấp phát bộ nhớ để lu trữ đối tợng
có kiểu data_type và kết quả trả lại là địa chỉ của đối tợng cho biến
con trỏ. Ví dụ: float *p = new float;
Hàm void *free(void ptr) : Giải phóng vùng nhớ đã đợc cấp phát
bởi calloc hoặc malloc do ptr trỏ tới.
delete biến_con_trỏ: Huỷ bỏ biến_con_trỏ, giải phóng bộ nhớ.
6.2.2. Cấu trúc tự trỏ và danh sách liên kết
Cấu trúc có ít nhất một thành phần là con trỏ kiểu cấu trúc đang định
nghĩa gọi là cấu trúc tự trỏ.
Ví dụ:
struct HOSO
{
62
Đại học Thái Nguyên-Trờng ĐHSP. Khoa Toán-Tin
Nguyễn Mạnh Đức Ngôn ngữ lập trình C++
char hoten[25];
int tuoi;
struct HOSO *tiep;
}
Cấu trúc tự trỏ đợc dùng để xây dựng các danh sách liên kết (móc nối),
đó là các cấu trúc có tính chất:
Biết địa chỉ của cấu trúc đầu đang đợc lu trong một con trỏ nào
đó (chẳng hạn Pdau).
Trong mỗi cấu trúc (trừ cấu trúc cuối) chứa địa chỉ của cấu trúc
tiếp theo trong danh sách.
Cấu trúc cuối cùng trong danh sách chứa hằng NULL.
Danh sách có tính chất nh trên gọi là danh sách liên kết thuận. Với cấu
trúc này ta có thể lần lợt truy nhập vào các cấu trúc trong danh sách từ đầu
tới cuối. Hình ảnh dới đây biểu diễn một liên kết thuận.
Pdau
addr(ct1)
ct1
hoten
Lê Thu Hà
tuoi
19
tiep
addr(ct2)
ct2
hoten
Nguyễn An
tuoi
25
tiep
addr(ct3)
...
ctn
hoten
Vũ Thị Vân
tuoi
22
tiep
NULL
63
§¹i häc Th¸i Nguyªn-Tr−êng §HSP. Khoa To¸n-Tin
NguyÔn M¹nh §øc – Ng«n ng÷ lËp tr×nh C++
VÝ dô ch−¬ng tr×nh 6.4: Danh s¸ch liªn kÕt thuËn.
#
#
#
#
include
include
include
include
<iostream.h>
<conio.h>
<stdio.h>
<string.h>
typedef struct HOSO
{
char hoten[25];
int tuoi;
struct HOSO *tiep;
} nhansu;
nhansu *pdau, *p, p1;
void
void
void
void
void
void
NHAP();
INRA();
THEM();
CHEN(int n);
TIM(int tuoi);
XOA(int n);
void main()
{
clrscr();
NHAP();
clrscr();
INRA();
TIM(20);
getch();
delete p;
delete pdau;
}
void NHAP()
{
char ht[25]; int t;
clrscr();
pdau = NULL;
while (1)
{
cout << "Ho va ten : "; gets(ht);
cout << "Tuoi
: "; cin >> t;
if (pdau == NULL)
{
pdau = new HOSO;
p = pdau;
64
Đại học Thái Nguyên-Trờng ĐHSP. Khoa Toán-Tin
Nguyễn Mạnh Đức Ngôn ngữ lập trình C++
}
else
{
p->tiep = new HOSO;
p = p->tiep;
}
}
strcpy(p->hoten, ht);
p->tuoi = t;
p->tiep = NULL;
char tl;
cout << "\nNhap nua khong (C/K) ? ";
cin >> tl;
if (tl == 'k' || tl == 'K') break;
}
void INRA()
{
p = pdau;
while (p != NULL)
{
cout << (*p).hoten << "
p = p->tiep;
}
}
" << (*p).tuoi << endl;
// Tim va in ra nguoi khong qua tuoi cho truoc
void TIM(int tuoi)
{
p = pdau;
cout << "\nDanh sach nhung nguoi tuoi <= "
<< tuoi << endl;
int i = 1;
while (p != NULL)
{
if (p->tuoi <= tuoi)
{
cout << i << " " << (*p).hoten << endl;
i = i+1;
}
p = p->tiep;
}
}
Tơng tự, danh sách liên kết ngợc có các tính chất sau:
Biết địa chỉ cấu trúc cuối.
Trong mỗi cấu trúc (trừ cấu trúc đầu) chứa địa chỉ của cấu trúc
trớc.
65
Đại học Thái Nguyên-Trờng ĐHSP. Khoa Toán-Tin
Nguyễn Mạnh Đức Ngôn ngữ lập trình C++
Cấu trúc đầu chứa hằng NULL.
Với danh sách liên kết ngợc, ta có thể truy nhập lần lợt từ cấu trúc cuối
tới cấu trúc đầu.
Danh sách liên kết thuận nghịch: mỗi cấu trúc trong danh sách chứa hai
địa chỉ, một địa chỉ của cấu trúc trớc và một địa chỉ của cấu trúc sau nó. Với
danh sách loại này ta có thể truy nhập theo hai chiều thuận nghịch.
6.3. Dữ liệu kiểu hợp (union)
Cũng nh kiểu struct, kiểu union gồm nhiều thành phần, nhng khác kiểu
struct ở chỗ: các thành của kiểu struct ở các vùng nhớ khác nhau còn các
thành phần của union đợc cấp phát một vùng nhớ chung, độ dài của union
bằng độ dài của thành phần lớn nhất.
Việc khai báo dữ liệu kiểu union, khai báo biến union, mảng union, con
trỏ union, cũng nh việc truy nhập đến các thành phần của union đợc thực
hiện hoàn toàn nh đối với struct. Một struct có thể có thành phần kiểu union,
ngợc lại một union cũng có thể có thành phần là struct.
Ví dụ:
struct date
{ int ngay, thang, nam; };
struct addr
{
int sonha;
char *pho;
};
union nhansu
{
char hoten[25];
struct date ngaysinh;
struct addr diachi;
} nguoi1, nguoi2;
66
Đại học Thái Nguyên-Trờng ĐHSP. Khoa Toán-Tin
Nguyễn Mạnh Đức Ngôn ngữ lập trình C++
6.4. Dữ liệu kiểu liệt kê (enum)
enum là kiểu dữ liệu mà các thành phần liệt kê trong nó đợc đánh số
mặc định lần lợt là 0, 1, 2, ...
Ví dụ:
enum mau {xanh, hong, vang, trang, den };
enum Trang_thai { on, off };
enum Gioi_tinh { nam, nu };
Khi đó ta có mau là kiểu enum, các thành phần của nó là xanh, hong,
vang, trang, den. Theo mặc định chúng có giá trị tơng ứng là: 0, 1, 2, 3, 4. Từ
đây ta có thể khai báo các biến kiểu mau, ví dụ:
mau mau1, mau2;
Gioi_tinh Gioi
Các lệnh gán sau là hợp lệ:
mau1 = xanh;
mau2 = trang;
Gioi = nu;
int m = vang; // gán giá trị màu vàng cho biến m
Nếu cần thiết ta có thể gán các giá khác mặc định cho các thành phần của
enum, ví dụ:
enum mau { xanh, hong, vang = 6, trang = 8, den };
Khi đó xanh = 0, hong =1, vang = 6, trang = 8, den = 9.
Kiểu enum có thể là thành phần của các kiếu có cấu trúc khác, nh kiểu
struct hay class.
6.5. Dữ liệu kiểu lớp (class)
6.5.1. Khái niệm kiểu class
class là một kiểu dữ liệu đặc biệt, rất quan trọng trong lập trình hớng đối
tợng. Trong chuyên đề lập trình hớng đối tợng ta sẽ thảo luận nhiều về vấn
đề này. Sau đây ta sẽ nêu lên một số đặc tính của kiểu dữ liệu này, cũng nh
việc khai báo và bớc đầu sử dụng chúng.
Lớp (class) thực chất là một kiểu dữ liệu đợc định nghĩa bởi ngời sử
dụng, nó bao gồm các thành phần là các kiểu dữ liệu chuẩn (nh int, float,
char ...) và các hàm xử lý dữ liệu trên nó.
67
Đại học Thái Nguyên-Trờng ĐHSP. Khoa Toán-Tin
Nguyễn Mạnh Đức Ngôn ngữ lập trình C++
6.5.2. Khai báo kiểu class
Việc khai báo class có dạng chung nh sau:
class tên_class
{
[private:]
<khai báo các biến>;
<khai báo các hàm>;
public:
<khai báo các biến>;
<khai báo các hàm>;
} [tên biến class];
Từ khoá class định nghĩa một kiểu dữ liệu trừu tợng có tên là tên_class,
phần nội dung khai báo gồm các biến và các hàm thành phần. Các biến và
hàm thành phần đợc tổ chức thành hai nhóm: public dùng chung và
private- sở hữu riêng. Các thnàh phần khai báo trong nhóm private chỉ đợc
truy nhập bên trong lớp, đó là nguyên lý che dấu thông tin của C++. Các thành
phần trong nhóm public có thể đợc truy nhập từ bên ngoài lớp. Từ khoá
private là tuỳ chọn, nếu mặc định thì các thành phần (không khai báo là
public) sẽ là private. Khi trong lớp không có thành phần nào khai báo public,
thì tất cả mọi thành phần trong lớp sẽ đợc che dấu với thế giới bên ngoài,
không thể truy nhập vào đợc, ngoại trừ các hàm thành phần trong lớp đó.
Ví dụ:
class HOSO
{
private:
char hoten[25];
int tuoi;
public:
void NHAP();
void INRA();
};
68
Đại học Thái Nguyên-Trờng ĐHSP. Khoa Toán-Tin
Nguyễn Mạnh Đức Ngôn ngữ lập trình C++
Chúng ta đã định một dữ liệukiểu class có tên là HOSO, trong nó có hai
thành phần dữ liệu là hoten, tuoi và hai hàm thành phần là NHAP() - để đọc
dữ liệu cho hai biến hoten và tuoi, INRA() - đa các giá trị của hoten và tuoi
ra màn hình. Nội dung của các hàm thành phần sẽ đợc xác định sau.
6.5.3. Tạo lập đối tợng
Việc khai báo HOSO ở trên mới chỉ xác định đợc các thành phần của
lớp, chứ cha tạo ra một đối tợng cụ thể. Lớp là kiểu dữ liệu trừu tợng, nên
sau khi định nghĩa lớp ta có thể khai báo các biến giống nh đối với kiểu đợc
định nghĩa bơỉ ngời sử dụng. Ví dụ:
HOSO hs; // tạo ra một vùng nhớ để lu trữ hs
Biến hs đợc khai báo kiểu HOSO. Trong C++, biến kiểu lớp đợc gọi là
đối tợng. Vì vậy, hs là đối tợng trong lớp HOSO.
6.5.4. Định nghĩa các hàm thành phần
Các hàm thành phần có thể định nghĩa bên trong hoặc bên ngoài vùng
định nghĩa lớp.
Bên trong vùng định nghĩa lớp:
Phần thân của các hàm thành phần đợc xác định ngay khi khai báo hàm,
và chúng nằm trong phần định nghĩa lớp.
Ví dụ:
class HOSO
{
private:
char hoten[25];
int tuoi;
public:
void NHAP()
{
cout << Vao ho va ten : ;
gets(hoten);
cout << Vao tuoi : ;
cin >> tuoi;
}
void INRA()
69
Đại học Thái Nguyên-Trờng ĐHSP. Khoa Toán-Tin
Nguyễn Mạnh Đức Ngôn ngữ lập trình C++
{
cout << Ho va ten : << hoten << endl;
cout << Tuoi
: << tuoi << endl;
}
};
Bên ngoài vùng định nghĩa lớp:
Các hàm thành phần nàm ngoài phần định nghĩa lớp phải dùng toán tử
phạm vi (::) có dạng chung nh sau:
type tên_class :: tên_hàm
{
// Nội dung của hàm thành phần
}
Ví dụ:
class HOSO
{
private:
char hoten[25];
int tuoi;
public:
void NHAP();
void INRA();
};
void HOSO :: NHAP()
{
cout << Vao ho va ten : ;
gets(hoten);
cout << Vao tuoi : ;
cin >> tuoi;
}
void HOSO :: INRA()
{
cout << Ho va ten : << hoten << endl;
cout << Tuoi
: << tuoi << endl;
}
70
Đại học Thái Nguyên-Trờng ĐHSP. Khoa Toán-Tin
Nguyễn Mạnh Đức Ngôn ngữ lập trình C++
6.5.5. Truy nhập vào các thành phần của lớp
Nh trên đã nói, vùng dữ liệu riêng (private) chỉ có thể truy nhập đợc
bởi những hàm thành phần của cùng một lớp, những hàm không phải là thành
phần của lớp thì không thể truy nhập đợc (trừ khi có khai báo friend mà
chúng ta sẽ nói sau).
Trong cùng một lớp, một hàm thành phần có thể gọi trực tiếp hàm thành
phần khác mà không cần toán tử xác định thành phần (.).
Dạng truy nhập tới các thành phần của lớp có dạng chung nh sau:
tên_đối_tợng.tên_hàm_thành_phần([tham số thật]);
Ví dụ:
HOSO NS;
NS.NHAP();
...
class DIEM
{
int x, y;
public:
void NHAP(int a, int b);
void INRA();
};
...
DIEM P;
P.NHAP(5, 9);
Ví dụ chơng trình 6.5:
# include <iostream.h>
# include <conio.h>
# include <stdio.h>
class HOSO
{
private:
char
int
float
char
hoten[25];
tuoi;
hesoluong;
que[20];
71
§¹i häc Th¸i Nguyªn-Tr−êng §HSP. Khoa To¸n-Tin
NguyÔn M¹nh §øc – Ng«n ng÷ lËp tr×nh C++
public:
void NHAP();
void INRA();
};
void HOSO :: NHAP()
{
cout << "Vao ho va ten: "; gets(hoten);
cout << "Vao tuoi
: "; cin >> tuoi;
cout << "He so luong : "; cin >> hesoluong;
}
void HOSO :: INRA()
{
cout << "Ho va ten: " << hoten << endl;
cout << "Tuoi
: " << tuoi << endl;
cout << "Luong CB : " << hesoluong*220000;
}
void main()
{
HOSO NS;
clrscr();
NS.NHAP();
clrscr();
NS.INRA();
getch();
}
VÝ dô ch−¬ng tr×nh 6.6:
# include <iostream.h>
class DIEM
{
int x, y;
public:
void NHAP(int a, int b)
{
x = a; y = b;
}
void INRA()
{
cout << "\nToa do x = " << x;
cout << "\nToa do y = " << y;
}
};
72
Đại học Thái Nguyên-Trờng ĐHSP. Khoa Toán-Tin
Nguyễn Mạnh Đức Ngôn ngữ lập trình C++
void main()
{
DIEM P;
P.NHAP(6, 9);
P.INRA();
}
Chú ý: Chỉ những hàm thành phần đơn giản, có ít lệnh thì mới nên đặt
trong phần định nghĩa lớp.
73
Đại học Thái Nguyên-Trờng ĐHSP. Khoa Toán-Tin
Nguyễn Mạnh Đức Ngôn ngữ lập trình C++
Chơng 7
Các thao tác với tệp tin
Khi giải quyết các bài toán phải xử lý nhiều dữ liệu chúng ta phải sử
dụng thiết bị nhớ ngoài để lu trữ chúng trong các tệp tin. Chơng trình phải
đợc thiết kế để có thể đọc hoặc ghi dữ liệu lên tệp. Sự tơng tác giữa thiết bị
ngoại vi (bàn phím, màn hình, máy in), chơng trình và các tệp trên đĩa đợc
mô tả trong hình sau.
Bộ nhớ ngoài
Các tệp dữ liệu
...
Ghi
dữ
liệu
lên
tệp
Bộ nhớ trong
Đọc
dữ
liệu
từ
tệp
Tơng tác
giữa chơng
trình và tệp
Chơng trình + Dữ liệu
cin >>
Đọc dữ
liệu từ
bàn phím
Màn hình
cout << Đa
dữ liệu ra
màn hình,
máy in
Tơng tác
giữa chơng
trình và thiết
bị ngoại vi
Bàn phím
Hình 3-4: Tơng tác giữa chơng trình-thiết bị ngoại vi-tệp tin
Dòng dữ liệu cung cấp cho chơng trình đợc gọi là dòng input, còn
dòng dữ liệu lấy ra từ chơng trình đợc gọi là dòng output, quá trình này có
thể biểu diễn nh sau :
74
Đại học Thái Nguyên-Trờng ĐHSP. Khoa Toán-Tin
Nguyễn Mạnh Đức Ngôn ngữ lập trình C++
Đĩa từ
Dòng intput
Tệp dữ liệu
Chơng trình
Tệp kết quả
Dòng output
Hình 3-5: Sơ đồ dòng dữ liệu Tệp-Chơng trình-Tệp
7.1. Các kiểu truy nhập đĩa
7.1.1. Nhập/xuất chuẩn và nhập/xuất hệ thống
Có thể phân chia nhập/xuất tệp của C thành hai loại: Nhập xuất chuẩn và
nhập xuất hệ thống.
Nhập xuất chuẩn thờng đợc dùng nhiều trong các chơng trình của C,
vì nó đợc hỗ trợ mạnh có nhiều cách xử lý ...
Nhập xuất hệ thống có cách xử lý dữ liệu hơn so với nhập xuất chuẩn.
Trong quá trình làm việc lập trình viên phải thiết lập và theo dõi từng bộ đệm
để chuyển dữ liệu; Chuyển đổi các dạng thức dữ liệu ...
7.1.2. Nhập/xuất các kiểu dữ liệu với tệp
Nhập xuất chuẩn cung cấp 4 cách đọc và ghi dữ liệu khác nhau:
Nhập xuất từng ký tự: Dùng các hàm getc() và putc().
Nhập xuất chuỗi: Dùng các hàm fgets() và fputs().
Nhập xuất dữ liệu theo khuôn dạng: Dùng các hàm fscanf() và
printf().
Nhập xuất bản ghi: Dùng các hàm fread() và fwrite().
Nhập xuất hệ thống: Dùng các hàm read() và write().
7.1.3. Nhập/xuất tệp kiểu văn bản và kiểu nhị phân
Có hai kiểu tệp có thể thao tác đợc: Tệp nhị phân và tệp văn bản (text).
Tệp văn bản dùng các ký tự của bảng ASCII khi ghi vào hay đọc ra tệp.
75
Đại học Thái Nguyên-Trờng ĐHSP. Khoa Toán-Tin
Nguyễn Mạnh Đức Ngôn ngữ lập trình C++
Tệp nhị phân dùng các chữ số nhị phân để lu giữ các dữ liệu. Bình
thơng không thể quan sát một tệp nhị phân nếu không có chơng trình đặc
biệt.
7.2. Nhập/xuất chuẩn
7.2.1. Mở, đóng tệp
Để mở và đóng một tệp , trớc hết phải khai báo biến con trỏ tệp bằng
lệnh:
FILE <con trỏ tệp>;
Ví dụ:
FILE *Fvb, *Fnp;
Để mở tệp ta dùng hàm fopen:
FILE *fopen(const char *tên_tệp, const char *kiểu);
Trong đó đối thứ nhất là tên tệp, đối thứ hai là kiểu truy nhập. Nếu mở tệp
thành công hàm trả vể con trỏ kiểu FILE ứng với tệp vừa mở, nếu có lỗi
(không mở đợc tệp) hàm trả về giá trị NULL. Kiểu truy nhập có thể có các
giá trị nh sau:
Kiểu
ý nghĩa
r rt
mở tệp chỉ đọc theo kiểu văn bản, nếu tệp không tồn tại sẽ báo lỗi.
w wt
mở tệp mới để ghi theo kiểu văn bản, nếu tệp đã tồn tại sẽ bị xoá
a at
mở tệp để bổ sung theo kiểu văn bản, nếu tệp cha có thì tạo tệp
mới.
rb
mở tệp để đọc theo kiểu nhị phân, nếu tệp cha có sẽ báo lỗi.
wb
mở tệp để ghi theo kiểu nhị phân, nếu tệp đã có thì sẽ bị xoá.
ab
mở tệp để bổ sung theo kiểu nhị phân, nếu tệp cha có thì tạo tệp
mới.
r+ r+t
mở tệp để đọc/ghi theo kiểu văn bản, nếu tệp không tồn tại sẽ báo
lỗi.
w+ w+t
mở tệp để đọc/ghi theo kiểu văn bản, nếu tệp tồn tại sẽ bị xoá.
a+ a+t
mở tệp để bổ sung theo kiểu văn bản, nếu tệp cha có thì tạo tệp
mới.
76
Đại học Thái Nguyên-Trờng ĐHSP. Khoa Toán-Tin
Nguyễn Mạnh Đức Ngôn ngữ lập trình C++
Kiểu
ý nghĩa
r+b
mở tệp để đọc/ghi theo kiểu nhị phân, nếu tệp cha có thì báo lỗi.
w+b
mở tệp để đọc/ghi theo kiểu nhị phân, nếu tệp đã có thì bị xoá.
a+b
mở tệp để đọc/ghi bổ sung theo kiểu nhị phân, nếu tệp cha có thì
tạo tệp mới.
Ví dụ:
Fvb = fopen(txtfile.txt, w);
Để đóng một tệp đang mở ta dùng hàm:
fclose(<con trỏ tệp>);
Ví dụ:
fclose(Fvb);
7.2.2. Nhập/xuất ký tự
Ghi vào tệp một ký tự có thể dùng một trong hai hàm sau:
int putc(int ch, FILE *fvar);
int fputc(int ch, FILE *fvar);
Nếu thành công hàm cho mã ký tự đợc ghi là ch%256, trái lại hàm cho EOF.
Đọc một ký tự từ tệp có thể sử dụng các hàm sau:
int getc(FILE *fvar);
int fgetc(FILE *fvar);
Nếu thành công hàm cho mã ký tự đọc đợc (từ 0 tới 255), nếu gặp vị trí kết
thúc tệp hay có lỗi hàm cho EOF.
Ví dụ:
// Nhap xuat ky tu voi tep van ban
# include <iostream.h>
# include <stdio.h>
# include <conio.h>
77
Đại học Thái Nguyên-Trờng ĐHSP. Khoa Toán-Tin
Nguyễn Mạnh Đức Ngôn ngữ lập trình C++
void main()
{
FILE *f;
char ch;
clrscr();
// Tao tep
f = fopen("TEXT_CF.TXT", "w");
//Nhập ký tự từ bàn phím,gõ phím <Enter> sẽ dừng
while ((ch = getche()) != '\r')
putc(ch, f);
// ghi ký tự vào tệp
fclose(f);
// Doc tep
printf("\nNoi dung tep TEXT_CF.TXT: ");
f = fopen("TEXT_CF.TXT", "r");
while ((ch = getc(f)) != EOF) printf("%c", ch);
fclose(f);
getch();
}
7.2.3. Nhập/xuất chuỗi
Để ghi một chuỗi vào tệp văn bản ta có thể dùng hàm:
int fputs(const char *st, FILE *Fvar);
Trong đó:
st là con trỏ trỏ tới địa chỉ đầu của một chuỗi ký tự kết thúc
bằng dấu \0.
Fvar là con trỏ tệp.
Hàm ghi chuỗi st lên tệp Fvar (dấu \0 không ghi lên tệp). Khi thành
công hàm trả về ký tự cuối cùng đợc ghi lên tệp, nếu gặp lỗi hàm cho EOF.
Để đọc một dãy ký tự từ tệp có thể dùng hàm:
char *fgets(char st, int n, FILE *Fvar);
Trong đó:
st là con trỏ kiểu char trỏ tới vùng nhớ đủ lớn để chứa
chuỗi ký tự đọc từ tệp.
78