C++: Bài 29. Cấu trúc

Khái niệm

Cấu trúc (Struct) trong C++ là một kiểu dữ liệu dạng tổng hợp (giống kiểu bản ghi (record) trong Pascal), cho phép nhiều kiểu dữ liệu được nhóm lại với nhau. Struct thường được dùng để tạo và lưu giữ thông tin của các đối tượng (sách, tranh, ảnh, sinh viên, học sinh, nhân viên, …).

Định nghĩa cấu trúc và khai báo biến cấu trúc

1. Không dùng typedef

Cấu trúc có thể được định nghĩa ngoài hoặc trong các hàm, nếu được định nghĩa trong hàm thì cấu trúc đó chỉ dùng được cho hàm chứa nó, còn nếu được định nghĩa ngoài các hàm thì nó có thể được sử dụng ở tất cả các hàm.

Cú pháp:

struct Tên_cấu_trúc {

  Khai báo các biến có kiểu dữ liệu khác nhau;

};

, trong đó struct là từ khoá, bên trong cặp ngoặc {} ta có thể khai báo các thành phần của cấu trúc bao gồm các loại biến và mảng có kiểu dữ liệu khác nhau, hoặc ta cũng có thể khai báo biến hoặc mảng cấu trúc khác.

Sau khi khai báo hay định nghĩa xong một cấu trúc thì Tên_cấu_trúc được coi như một kiểu dữ liệu mới, và đây chính là kiểu dữ liệu không có sẵn trong ngôn ngữ C, mà do ta tự định nghĩa. Dưới đây là một ví dụ đơn giản về việc định nghĩa một cấu trúc:

struct Student { /* Student sẽ là một kiểu dữ liệu mới sau khi khai báo xong cấu trúc */
  

char

name[

30

];

int

dateOfBirth;

float

averageMark; };

Khai báo biến cấu trúc:

Sau khi ta đã định nghĩa được cấu trúc rồi thì ta coi như nó là một kiểu dữ liệu mới, và khi đó ta có thể khai báo biến có kiểu dữ liệu này. Có 2 cách khai báo biến cấu trúc:

– Cách 1: Khai báo trực tiếp cùng định nghĩa cấu trúc. Ví dụ:

struct Student {
  

char

name[

30

];

int

dateOfBirth;

float

averageMark; } Stu1, Stu2; /* khai báo 2 biến Stu1 và Stu2 kiểu Student một cách trực tiếp */

– Cách 2: Khai báo gián tiếp sau khi đã định nghĩa xong cấu trúc. Ví dụ:

struct Student {
  

char

name[

30

];

int

dateOfBirth;

float averageMark

; }; struct Student Stu1, Stu2; //khai báo 2 biến Stu1 và Stu2 có kiểu Student

2. Dùng typedef

typedef struct {

  Khai báo các biến với những kiểu dữ liệu khác nhau;

} Kiểu_cấu_trúc;

Sau khi định nghĩa cấu trúc, Kiểu_cấu_trúc sẽ được coi là một kiểu dữ liệu (không phải là biến), và ta có thể khai báo các biến có kiểu dữ liệu là Kiểu_cấu_trúc. Ví dụ:

typedef struct {
  

char

name[

30

];

int

dateOfBirth;

float

averageMark; } Student; // Student sẽ là một kiểu dữ liệu mới Student Stu1, Stu2; //khai báo hai biến Stu1 và Stu2 có kiểu dữ liệu Student Student StuList[

50

]; //khai báo một mảng có tên StuList gồm 50 phần tử có kiểu Student Student *Stu; //khai báo một con trỏ kiểu Student

Gán giá trị cho biến và mảng cấu trúc

Giả sử ta khai báo một biến tên HV có kiểu dữ liệu HocVien đã được được định nghĩa như ở trên và tiến hành gán giá trị cho nó, ta làm như sau:

#include<

bits

/stdc++.h> using namespace std; typedef struct {

char

name[

30

];

int

dateOfBirth;

float

averageMark; } Student;

int

main(){ //gán giá trị cho biến cấu trúc: Student Stu = {

"Minh"

,

1983

,

8.5

};

return

0

; }

, trong đó “Minh” được gán cho chuỗi name, 1983 được gán cho biến dateOfbirth, 8.5 được gán cho biến averageMark. Những chuỗi và biến này là những thành phần của biến Stu.

Từ ví dụ trên ta thấy rằng bản chất của việc gán giá trị cho biến Stu thực chất là gán các giá trị cho các biến thành phần của Stu, trong đó các thành phần của biến Stu trong phần định nghĩa được khai báo theo trật tự nào thì khi tiến hành gán các giá trị cũng phải được đặt theo trật tự đó. Như ví dụ trên ta thấy chuỗi name được khai báo đầu tiên thì trong phần gán giá trị cho biến Stu, chuỗi “Minh” cũng phải được đặt đầu tiên (vị trí thứ nhất), không được đặt ở vị trí khác; dateOfBirth được khai báo ở vị trí thứ hai thì giá trị nó được gán phải là 1983 (vị trí gán thứ hai) chứ không phải là 8.5 (vị trí thứ 3), mà 8.5 là giá trị được gán cho biến averageMark vì biến này được khai báo ở vị trí thứ 3 trong phần định nghĩa cấu trúc.

Đối với việc gán giá trị cho mảng cấu trúc, ta thực hiện như ví dụ sau:

#include<

bits

/stdc++.h> using namespace std; typedef struct {

char

name[

30

];

int

dateOfBirth;

float

averageMark; } Student;

int

main(){ //gán giá trị cho mảng cấu trúc: Student StuList[]={{

"Minh"

,

1983

,

8.5

}, {

"Phong"

,

1988

,

8.0

}, {

"Lan"

,

1986

,

9.0

}};

return

0

; }

Truy cập các thành phần của cấu trúc

Truy cập vào biến cấu trúc

Để truy cập các thành phần của một biến cấu trúc thì ta sử dụng cú pháp như sau:

Tên_biến_cấu_trúc.Tên_biến_thành_phần

Ta sử dụng toán tử dấu chấm (.) để truy cập đến các biến thành phần của biến cấu trúc. Lư­u ý rằng mỗi lần truy cập ta chỉ có thể truy cập đến một biến thành phần duy nhất. Ví dụ như Stu.name, Stu.dateOfBirth, Stu.averageMark.

Ví dụ:

#include<

bits

/stdc++.h> using namespace std; typedef struct {

char

name[

30

];

int

dateOfBirth;

float

averageMark; } Student;

int

main(){ Student Stu; //thiết lập (set) dữ liệu cho biến cấu trúc: strcpy(Stu.name,

"ABCD"

); Stu.dateOfBirth=

2002

; Stu.averageMark=

8.5

; //hiển thị dữ liệu cho biến cấu trúc: cout <<

"Name: "

<< Stu.name << endl; cout <<

"Date of birth: "

<< Stu.dateOfBirth << endl; cout <<

"Average mark: "

<< Stu.averageMark;

return

0

; }

Truy cập vào con trỏ cấu trúc

Để truy cập các thành phần của một con trỏ cấu trúc thì ta sử dụng cú pháp như sau:

Tên_con_trỏ_cấu_trúc->Tên_biến_thành_phần

Ví dụ:

#include<

bits

/stdc++.h> using namespace std; typedef struct {

char

name[

30

];

int

dateOfBirth;

float

averageMark; } Student;

int

main(){ Student Stu, *pStu; //trước khi được sử dụng thì con trỏ phải được //trỏ tới một biến. pStu=&Stu; //thiết lập (set) dữ liệu cho biến cấu trúc: strcpy(pStu->name,

"ABCD"

); pStu->dateOfBirth=

2002

; pStu->averageMark=

8.5

; //hiển thị dữ liệu cho biến cấu trúc: cout <<

"Name: "

<< pStu->name << endl; cout <<

"Date of birth: "

<< pStu->dateOfBirth << endl; cout <<

"Average mark: "

<< pStu->averageMark;

return

0

; }

Nhập liệu và hiển thị cho biến cấu trúc

Để nhập liệu và hiển thị cho một cấu trúc nào đó, ta làm như ví dụ sau:

#include<

bits

/stdc++.h> #include<

cstring

> using namespace std; typedef struct { string name;

int

dateOfBirth;

float

averageMark; } Student;

int

main(){ Student Stu; //nhập thông tin cho học viên Stu: cout <<

"Input name: "

; getline(cin,Stu.name); cout <<

"Input date of birth: "

; cin>>Stu.dateOfBirth; cout <<

"Input average mark: "

; cin >> Stu.averageMark; //hiển thị dữ liệu cấu trúc: cout <<

"Name: "

<< Stu.name << endl; cout <<

"Date of birth: "

<< Stu.dateOfBirth << endl; cout <<

"Average mark: "

<< Stu.averageMark;

return

0

; }

Trường hợp nếu ta muốn tách thành các hàm nhập liệu và hiển thị riêng thì ta làm như sau:

#include<

bits

/stdc++.h> #include<

cstring

> using namespace std; typedef struct { string name;

int

dateOfBirth;

float

averageMark; } Student;

void

inputData(Student* Stu){ cout <<

"Input name: "

; getline(cin,Stu->name);//dùng mũi tên thay cho dấu chấm cout <<

"Input date of birth: "

; cin >> Stu->dateOfBirth; cout <<

"Input average mark: "

; cin >> Stu->averageMark; }

void

showData(Student Stu){ cout <<

"Name: "

<< Stu.name << endl; cout <<

"Date of birth: "

<< Stu.dateOfBirth << endl; cout <<

"Average mark: "

<< Stu.averageMark; }

int

main(){ Student Stu; //nhập thông tin cho học viên HV: inputData(&Stu); //hiển thị dữ liệu cấu trúc: showData(Stu);

return

0

; }

Ví dụ về cấu trúc

Viết chương trình nhập một danh sách gồm n sinh viên (n nhập từ bàn phím) gồm các trường họ tên, tuổi, điểm trung bình, sau đó nhập vào họ tên của một sinh viên từ bàn phím và tìm kiếm xem trong danh sách có ai có họ tên như vậy không.

Chương trình được viết như sau:

#include<

bits

/stdc++.h> using namespace std; typedef struct{

char

hoTen[

30

];

int

tuoi;

float

diemTB; } SinhVien;

int

main(){

int

n, i, search;

char

sv[

30

]; SinhVien *SV;

do

{ cout<<

"Moi ban nhap so luong sinh vien: "

; cin>>n; }

while

(n<=

0

); //Cấp phát vùng nhớ cho n sinh viên SV=(SinhVien*)malloc(n*sizeof(SinhVien)); //Nhập liệu cho n sinh viên

for

(i=

0

; i<

n

; i++){ cin.ignore(); cout<<

"Nhap thong tin cho sinh vien "

<<i+

1

<<

":"

<<endl; cout<<

"Ho va ten: "

; gets(SV[i].hoTen);

do

{ cout<<

"Nhap tuoi: "

; cin>>SV[i].tuoi; }

while

(SV[i].tuoi<

18

);

do

{ cout<<

"Diem trung binh: "

; cin>>SV[i].diemTB; }

while

(!(SV[i].diemTB>=

0

&& SV[i].diemTB<=

10

)); } //Tìm kiếm theo tên sinh viên cout<<

"Moi ban nhap ho ten cua sinh vien can tim: "

; cin.ignore(); gets(sv); search=

0

;

for

(i=

0

; i<

n

; i++){

if

(strcmp(SV[i].hoTen,sv)==

0

){ cout<<

"Tim thay!"

; search=

1

;

break

; } }

if

(search==

0

) cout<<

"Khong tim thay!"

; //giải phóng vùng nhớ free(SV);

return

0

; }

Ví dụ dưới đây sẽ sử dụng các hàm để giải quyết các yêu cầu của ví dụ trên. Chương trình được viết như sau:

#include<

bits

/stdc++.h> using namespace std; typedef struct{

char

hoTen[

30

];

int

tuoi;

float

diemTB; } SinhVien;

int

nhapKichThuocMang(){

int

n;

do

{ cout<<

"Moi ban nhap so luong sinh vien: "

; cin>>n; }

while

(n<=

0

);

return

n; }

void

nhapLieu(SinhVien SV[],

int

n){

int

i;

for

(i=

0

; i<

n

; i++){ cout<<

"Nhap thong tin cho sinh vien "

<<i+

1

<<

":"

<<endl; cout<<

"Ho va ten: "

; cin.ignore(); gets(SV[i].hoTen);

do

{ cout<<

"Nhap tuoi: "

; cin>>SV[i].tuoi; }

while

(SV[i].tuoi<

18

);

do

{ cout<<

"Diem trung binh: "

; cin>>SV[i].diemTB; }

while

(!(SV[i].diemTB>=

0

&& SV[i].diemTB<=

10

)); } }

void

timKiemTheoTen(SinhVien SV[],

int

n){

char

sv[

30

];

int

search; cout<<

"Moi ban nhap ho ten cua sinh vien can tim: "

; cin.ignore(); gets(sv); search=

0

;

for

(

int

i=

0

; i<

n

; i++){

if

(strcmp(SV[i].hoTen,sv)==

0

){ cout<<

"Tim thay!"

; search=

1

;

break

; } }

if

(search==

0

) cout<<

"Khong tim thay!"

; }

int

main(){

int

n; SinhVien *SV; n=nhapKichThuocMang(); //Cấp phát vùng nhớ cho n sinh viên SV=(SinhVien*)malloc(n*sizeof(SinhVien)); //Nhập liệu cho n sinh viên nhapLieu(SV,n); //Tìm kiếm theo tên sinh viên timKiemTheoTen(SV,n); //giải phóng vùng nhớ free(SV);

return

0

; }

Xem thêm: