Bài giảng Ngôn ngữ lập trình C/C++ - Phạm Hồng Thái - Chương 5: Dữ liệu kiểu cấu trúc và hợp

Để tạo ra một kiểu cấu trúc NSD cần phải khai báo tên của kiểu (là một tên gọi do NSD tự đặt), tên cùng với các thành phần dữ liệu có trong kiểu cấu trúc này. Một kiểu cấu trúc được khai báo theo mẫu sau:

 struct <tên kiểu>

{

các thành phần ;

} <danh sách biến>;

 Mỗi thành phần giống như một biến riêng của kiểu, nó gồm kiểu và tên thành phần. Một thành phần cũng còn được gọi là trường.

 Phần tên của kiểu cấu trúc và phần danh sách biến có thể có hoặc không. Tuy nhiên trong khai báo kí tự kết thúc cuối cùng phải là dấu chấm phẩy (;).

 Các kiểu cấu trúc được phép khai báo lồng nhau, nghĩa là một thành phần của kiểu cấu trúc có thể lại là một trường có kiểu cấu trúc.

 Một biến có kiểu cấu trúc sẽ được phân bố bộ nhớ sao cho các thực hiện của nó được sắp liên tục theo thứ tự xuất hiện trong khai báo.

 

doc39 trang | Chuyên mục: C/C++ | Chia sẻ: dkS00TYs | Lượt xem: 3633 | Lượt tải: 2download
Tóm tắt nội dung Bài giảng Ngôn ngữ lập trình C/C++ - Phạm Hồng Thái - Chương 5: Dữ liệu kiểu cấu trúc và hợp, để xem tài liệu hoàn chỉnh bạn click vào nút "TẢI VỀ" ở trên
nth >> kq->ns.year;
	cout > kq->diem ; cin.ignore() ;
	kq->tiep = NULL;
	return kq ;
}
Bổ sung sinh viên mới vào cuối danh sách. 
void Bosung()	// Bổ sung sv mới vào cuối ds
{
	cur = Nhap1sv();
	if (sosv == 0) {dau = cuoi = cur;}
	else { cuoi->tiep = cur; cuoi = cur; }
	sosv++;
}
Chèn sv mới vào trước sinh viên thứ n.
void Chentruoc(int n)	// Chèn sv mới vào trước sv thứ n
{
	cur = Nhap1sv();
	if (sosv==0) { dau = cuoi = cur; sosv++; return; }
	if (sosv==1 || n==1) {cur->tiep = dau; dau = cur; sosv++; return;}
	Sinhvien *truoc, *sau;
	truoc = dau;
	sau = dau -> tiep;
	for (int i=1; itiep;
	sau = truoc->tiep;
	truoc->tiep = cur;
	cur -> tiep = sau;
	sosv ++;
}
Chèn sv mới vào sau sinh viên thứ n.
void Chensau(int n) 	// Chèn sv mới vào sau sv thứ n
{
	cur = Nhap1sv();
	if (sosv==0 || sosv<n) { dau = cuoi = cur; sosv++; return; }
	Sinhvien *truoc, *sau;
	truoc = dau; sau = dau -> tiep;
	for (int i=1; itiep;
	sau = truoc->tiep;
	truoc->tiep = cur;
	cur -> tiep = sau;
	sosv ++;
}
Xoá sinh viên thứ n.
void Xoa(int n) 	// Xoá sinh viên thứ n
{
	if (sosv==1&&n==1) { delete dau ; dau = cuoi = NULL; sosv--; return; }
	if (n==1) { cur = dau; dau = cur->tiep; delete cur; sosv--; return; }
	Sinhvien *truoc, *sau;
	truoc = dau;
	sau = dau -> tiep;
	for (int i=1; itiep;
	cur = truoc->tiep; sau = cur->tiep; truoc->tiep = sau;
	delete cur ;
	sosv --;
}
Tạo danh sách sinh viên.
void Taods()	// Tạo danh sách
{
	int tiep = 1;
	while (tiep) {
	Bosung();
	cout > tiep ;
	}
}
In danh sách sinh viên.
void Inds()	// In danh sách
{
	cur = dau; 	int i=1;
	while (cur != NULL) {
	cout << "\nSinh vien thu " << i << " ----------------------------\n") ;
	cout hoten ;
	cout << "Ngay sinh: " 
cout ns.day << "/" ;
cout ns.month << "/" ;
cout ns.year ;
	cout diem ;
	cur = cur->tiep; i++;
	}
}
Hàm chính.
void main()
{
	clrscr();
	Taods();
	Inds();
	getch();
}
KIỂU HỢP
Khai báo
Giống như cấu trúc, kiểu hợp cũng có nhiều thành phần nhưng các thành phần của chúng sử dụng chung nhau một vùng nhớ. Do vậy kích thước của một kiểu hợp là độ dài của trường lớn nhất và việc thay đổi một thành phần sẽ ảnh hưởng đến tất cả các thành phần còn lại. 
union { 
Danh sách các thành phần; 
}; 
Truy cập 
Cú pháp truy cập đến các thành phần của hợp cũng tương tự như kiểu cấu trúc, tức cũng sử dụng toán tử lấy thành phần (dấu chấm . hoặc ® cho biến con trỏ kiểu hợp). 
Dưới đây là một ví dụ minh hoạ việc sử dụng khai báo kiểu hợp để tách byte thấp, byte cao của một số nguyên.
:
void main()
{
union songuyen {
int n;	
unsigned char c[2];	
} x;
cout > x.n ;
cout << "Byte thấp của x = " << x.c[0] << endl ;
cout << "Byte cao của x = " << x.c[1] << endl;
}
: Kết hợp cùng kiểu nhóm bit trong cấu trúc, chúng ta có thể tìm được các bit của một số như chương trình sau. Trong chương trình ta sử dụng một biến u có kiểu hợp. Trong kiểu hợp này có 2 thành phần là 2 cấu trúc lần lượt có tên s và f.
	union {
	struct { unsigned a, b ; } s;
	struct {
	unsigned n1: 1;
	unsigned: 15;
unsigned n2: 1;
unsigned: 7;
unsigned n3: 8;
	} t ;
	} u;
với khai báo trên đây khi nhập u.s thì nó cũng ảnh hưởng đến u.t, cụ thể
u.t.n1 là bit đầu tiên (0) của thành phần u.s.a
u.t.n2 là bit 0 của thành phần u.s.b
u.t.n3 là byte cao của u.s.b
KIỂU LIỆT KÊ
Có thể gán các giá trị nguyên liên tiếp (tính từ 0) cho các tên gọi cụ thể bằng kiểu liệt kê theo khai báo sau đây:
enum tên_kiểu { d/s tên các giá trị };	
Ví dụ: 
enum Bool {false, true};	
khai báo kiểu mới đặt tên Bool chỉ nhận 1 trong 2 giá trị đặt tên false và true, trong đó false ứng với giá trị 0 và true ứng với giá trị 1. Cách khai báo kiểu enum trên cũng tương đương với dãy các macro sau:
#define false 0
#define true 1
Với kiểu Bool ta có thể khai báo một số biến như sau:
Bool Ok, found;
hai biến Ok và found sẽ chỉ nhận 1 trong 2 giá trị false (thay cho 0) hoặc true (thay cho 1). Có nghĩa có thể gán:
	Ok = true;
hoặc:	found = false; 	
Tuy nhiên không thể gán các giá trị nguyên trực tiếp cho các biến enum mà phải thông qua ép kiểu. Ví dụ:
	Ok = 0;	// sai
	Ok = Bool(0) ;	// đúng
hoặc Ok = false ;	// đúng
Bài tẬp
Có thể truy nhập thành phần của cấu trúc thông qua con trỏ như sau (với p là con trỏ cấu trúc và a là thành phần của cấu trúc):
A: (*p).a	B: *p®a	C: a và b sai	D: a và b đúng
Cho khai báo struct T {int x; float y;} t, *p, a[10]; Câu lệnh nào trong các câu sau là 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, 2 và 3	B: 4, 5 và 6	C: 1, 3 và 5	D: 2, 4 và 6
Cho các khai báo sau: 
struct ngay {int ng, th, nam;} vaotruong, ratruong; 
typedef struct {char hoten[25]; ngay ngaysinh;} sinhvien; 
Hãy chọn câu đúng nhất 
A: Không được phép gán: ratruong = vaotruong;
B: sinhvien là tên cấu trúc, vaotruong, ratruong là biến cấu trúc
C: Có thể viết: vaotruong.ng, ratruong.th, sinhvien.vaotruong.nam để truy nhập đến các thành phần tương ứng.
D: a, b, c đúng
Trong các khởi tạo giá trị cho các cấu trúc sau, khởi tạo nào đúng:
struct S1 {
int ngay, thang, nam;
} s1 = {2,3}; 
struct S2 {
char hoten[10]; 
struct S1 ngaysinh;
} s2 = {"Ly Ly",1,2,3}; 
struct S3 {
struct S2 sinhvien; 
float diem;
} s3 = {{{"Cốc cốc", {4,5,6}}, 7}; 
A: S1 và S2 đúng 	B: S2 và S3 đúng 	C: S3 và S1 đúng 	D: Cả 3 cùng đúng 
Đối với kiểu cấu trúc, cách gán nào dưới đây là không được phép: 
A: Gán hai biến cho nhau.
B: Gán hai phần tử mảng (kiểu cấu trúc) cho nhau 
C: Gán một phần tử mảng (kiểu cấu trúc) cho một biến và ngược lại
D: Gán hai mảng cấu trúc cùng số phần tử cho nhau 
Cho đoạn chương trình sau: 
struct {
int to ; 
float soluong;
} x[10]; 
for (int i = 0; i > x[i].to >> x[i].soluong ; 
Chọn câu đúng nhất trong các câu sau: 
A: Đoạn chương trình trên có lỗi cú pháp
B: Không được phép sử dụng toán tử lấy địa chỉ đối với các thành phần to và soluong
C: Lấy địa chỉ thành phần soluong dẫn đến chương trình hoạt động không đúng đắn 
D: Cả a, b, c đều sai
Chọn câu đúng nhất trong các câu sau: 
A: Các thành phần của kiểu hợp (union) được cấp phát một vùng nhớ chung
B: Kích thước của kiểu hợp bằng kích thước của thành phần lớn nhất
C: Một biến kiểu hợp có thể được tổ chức để cho phép thay đổi được kiểu dữ liệu của biến trong qua trình chạy chương trình 
D: a, b, c đúng
Cho khai báo: 
union {
unsigned x; 
unsigned char y[2]; 
} z = {0xabcd}; 
Chọn câu đúng nhất trong các câu sau: 
A: Khai báo trên là sai vì thiếu tên kiểu
B: Khởi tạo biến z là sai vì chỉ có một giá trị (0xabcd)
C: z.y[0] = 0xab
D: z.y[1] = 0xab
Cho kiểu hợp: 
union U {
char x[1]; 
int y[2]; float z[3]; 
} u; 
Chọn câu đúng nhất trong các câu sau: 
A: sizeof(U) = 1+2+3 = 6
B: sizeof(U) = max(sizeof(char), sizeof(int), sizeof(float))
C: sizeof(u) = max(sizeof(u.x), sizeof(u.y), sizeof(u.z))	
D: b và c đúng
Cho khai báo: 
union {
unsigned x; 
struct {
unsigned char a, b;
} y; 
} z = {0xabcd}; 
Giá trị của z.y.a và z.y.b tương ứng: 
A: 0xab, 0xcd	B: 0xcd, 0xab	C: 0xabcd, 0	D: 0, 0xabcd
Cho khai báo: 
union {
struct {
unsigned char a, b;
} y; 
unsigned x; 
} z = {{1,2}}; 
Giá trị của z.x bằng: 
A: 513	B: 258	
C: Không xác định vì khởi tạo sai	D: Khởi tạo đúng nhưng z.x chưa có giá trị
Xét đoạn lệnh: 
union U {
int x; char y; 
} u; 
u.x = 0; u.y = 200; 
Tìm giá trị của u.x + u.y ? 
A: 122	B: 144	C: 200	D: 400
Cho số phức dưới dạng cấu trúc gồm 2 thành phần là thực và ảo. Viết chương trình nhập 2 số phức và in ra tổng, tích, hiệu, thương của chúng. 
Cho phân số dưới dạng cấu trúc gồm 2 thành phần là tử và mẫu. Viết chương trình nhập 2 phân số, in ra tổng, tích, hiệu, thương của chúng dưới dạng tối giản.
Tính số ngày đã qua kể từ đầu năm cho đến ngày hiện tại. Qui ước ngày được khai báo dưới dạng cấu trúc và để đơn giản một năm bất kỳ được tính 365 ngày và tháng bất kỳ có 30 ngày.
Nhập một ngày tháng năm dưới dạng cấu trúc. Tính chính xác (kể cả năm nhuận) số ngày đã qua kể từ ngày 1/1/1 cho đến ngày đó. 
Tính khoảng cách giữa 2 ngày tháng bất kỳ.
Hiện thứ của một ngày bất kỳ nào đó, biết rằng ngày 1/1/1 là thứ hai.
Hiện thứ của một ngày bất kỳ nào đó, lấy ngày thứ hiện tại để làm chuẩn.
Viết chương trình nhập một mảng sinh viên, thông tin về mỗi sinh viên gồm họ tên và ngày sinh (kiểu cấu trúc). Sắp xếp mảng theo tuổi và in ra màn hình
Để biểu diễn số phức có thể sử dụng định nghĩa sau:
typedef struct { 	float re, im; } sophuc;
Cần bổ sung thêm trường nào vào cấu trúc để có thể lập được một danh sách liên kết các số phức.
Để tạo danh sách liên kết, theo bạn sinh viên nào dưới đây khai báo đúng cấu trúc tự trỏ sẽ được dùng: 
Sinh viên 1: struct SV {char ht[25]; int tuoi; struct SV *tiep;}; 
Sinh viên 2: typedef struct SV node; struct SV {char ht[25]; int tuoi; node *tiep;}; 
Sinh viên 3: typedef struct SV {char ht[25]; int tuoi; struct SV *tiep;} node; 
A: Sinh viên 1	B: Sinh viên 2	C: Sinh viên 2 và 3	D: Sinh viên 1, 2 và 3
Lập danh sách liên kết chứa bảng chữ cái A, B, C … Hãy đảo phần đầu từ A .. M xuống cuối thành N, O, … Z, A, …M.
Viết chương trình tìm người cuối cùng trong trò chơi: 30 người xếp vòng tròn. Đếm vòng tròn (bắt đầu từ người số 1) cứ đến người thứ 7 thì người này bị loại ra khỏi vòng. Hỏi người còn lại cuối cùng ?
Giả sử có danh sách liên kết mà mỗi nốt của nó lưu một giá trị nguyên. Viết chương trình sắp xếp danh sách theo thứ tự giảm dần.
Giả sử có danh sách liên kết mà mỗi nốt của nó lưu một giá trị nguyên được sắp giảm dần. Viết chương trình cho phép chèn thêm một phần tử vào danh sách sao cho danh sách vẫn được sắp giảm dần. 
Tạo danh sách liên kết các số thực x1, x2, ..., xn. Gọi m là trung bình cộng: . 
Hãy in lần lượt ra màn hình các giá trị: m, x1 - m, x2 - m, ..., xn - m.
Sử dụng kiểu union để in ra byte thấp, byte cao của một số nguyên.

File đính kèm:

  • docBài giảng Ngôn ngữ lập trình CC++ - Phạm Hồng Thái - Chương 5 Dữ liệu kiểu cấu trúc và hợp.doc
Tài liệu liên quan