Struct la gi

Khái niệm

Cấu trúc (Struct) 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, 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 HocVien { /* HocVien sẽ là một kiểu dữ liệu mới sau khi khai báo xong cấu trúc */ char Ten[30]; int Namsinh; float DiemTB; };

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 HocVien { char Ten[30]; int Namsinh; float DiemTB; } HV1, HV2; /* khai báo 2 biến HV1 và HV2 kiểu HocVien 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 HocVien { char Ten[30]; int Namsinh; float DiemTB; }; struct HocVien HV1, HV2; //khai báo 2 biến HV1 và HV2 có kiểu HocVien

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 Ten[30]; int Namsinh; float DiemTB; } HocVien; //HocVien sẽ là một kiểu dữ liệu mới HocVien HV1, HV2; //khai báo hai biến HV1 và HV2 có kiểu dữ liệu HocVien HocVien DSHV[50]; //khai báo một mảng có tên DSHV gồm 50 phần tử có kiểu HocVien HocVien *HV; //khai báo một con trỏ kiểu HocVien

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<stdio.h> typedef struct { char Ten[30]; int Namsinh; float DiemTB; } HocVien; //HocVien sẽ là một kiểu dữ liệu mới int main(){ //gán giá trị cho biến cấu trúc: HocVien HV = {"Minh", 1983, 8.5}; return 0; }

, trong đó "Minh" được gán cho chuỗi Ten, 1983 được gán cho biến Namsinh, 8.5 được gán cho biến DiemTB. Những chuỗi và biến này là những thành phần của biến HV.

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 HV thực chất là gán các giá trị cho các biến thành phần của HV, trong đó các thành phần của biến HV 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 Ten được khai báo đầu tiên thì trong phần gán giá trị cho biến HV, 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; Namsinh đượ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 DiemTB 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<stdio.h> typedef struct { char Ten[30]; int Namsinh; float DiemTB; } HocVien; //HocVien sẽ là một kiểu dữ liệu mới int main(){ //gán giá trị cho mảng cấu trúc: HocVien DSHV[]={{"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ư HV.Ten, HV.Namsinh, HV.DiemTB.

Ví dụ:

#include<stdio.h> #include<string.h> typedef struct { char ten[30]; int namSinh; float diemTB; } HocVien; int main(){ HocVien HV; //thiết lập (set) dữ liệu cho biến cấu trúc: strcpy(HV.ten,"ABCD"); HV.namSinh=2002; HV.diemTB=8.5; //hiển thị dữ liệu cho biến cấu trúc: printf("\nTen: %s",HV.ten); printf("\nNam sinh: %d",HV.namSinh); printf("\nDiem trung binh: %g",HV.diemTB); 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<stdio.h> #include<string.h> typedef struct { char ten[30]; int namSinh; float diemTB; } HocVien; int main(){ HocVien* pHV, HV; //trước khi được sử dụng thì con trỏ phải được //trỏ tới một biến. pHV=&HV; //thiết lập (set) dữ liệu cho biến trỏ cấu trúc: strcpy(pHV->ten,"ABCD"); pHV->namSinh=2002; pHV->diemTB=8.5; //hiển thị dữ liệu cho biến trỏ cấu trúc: printf("\nTen: %s",pHV->ten); printf("\nNam sinh: %d",pHV->namSinh); printf("\nDiem trung binh: %g",pHV->diemTB); return 0; }

Nhập liệu và hiển thị cho 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<stdio.h> typedef struct { char ten[30]; int namSinh; float diemTB; } HocVien; int main(){ HocVien HV; //nhập thông tin cho học viên HV: printf("Moi nhap ten: "); gets(HV.ten); printf("Moi nhap nam sinh: "); scanf("%d",&HV.namSinh); printf("Moi nhap diem trung binh: "); scanf("%f",&HV.diemTB); //hiển thị dữ liệu cấu trúc: printf("\nTen: %s",HV.ten); printf("\nNam sinh: %d",HV.namSinh); printf("\nDiem trung binh: %g",HV.diemTB); 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<stdio.h> typedef struct { char ten[30]; int namSinh; float diemTB; } HocVien; void nhapLieu(HocVien* HV){ printf("Moi nhap ten: "); gets(HV->ten);//dùng mũi tên thay cho dấu chấm printf("Moi nhap nam sinh: "); scanf("%d", &HV->namSinh); printf("Moi nhap diem trung binh: "); scanf("%f", &HV->diemTB); } void hienThi(HocVien HV){ printf("\nTen: %s",HV.ten); printf("\nNam sinh: %d",HV.namSinh); printf("\nDiem trung binh: %g",HV.diemTB); } int main(){ HocVien HV; //nhập thông tin cho học viên HV: nhapLieu(&HV); //hiển thị dữ liệu cấu trúc: hienThi(HV); 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 <stdio.h> #include<stdlib.h> #include<string.h> typedef struct{ char hoTen[30]; int tuoi; float diemTB; } SinhVien; int main(){ int n, i, search; char sv[30]; SinhVien *SV; do{ printf("\nMoi ban nhap so luong sinh vien: "); scanf("%d",&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++){ printf("\nNhap thong tin cho sinh vien %d",i+1); printf("\nHo va ten: "); fflush(stdin); gets(SV[i].hoTen); gets(SV[i].hoTen); do{ printf("Nhap tuoi: "); scanf("%d",&SV[i].tuoi); }while(SV[i].tuoi<18); do{ printf("Diem trung binh: "); scanf("%f",&SV[i].diemTB); }while(!(SV[i].diemTB>=0 && SV[i].diemTB<=10)); } //Tìm kiếm theo tên sinh viên printf("\nMoi ban nhap ho ten cua sinh vien can tim: "); gets(sv); gets(sv); search=0; for(i=0; i<n; i++){ if(strcmp(SV[i].hoTen,sv)==0){ printf("\nTim thay!"); search=1; break; } } if(search==0) printf("\nKhong 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 yêu cầu của ví dụ trên. Chương trình được viết như sau:

#include <stdio.h> #include<stdlib.h> #include<string.h> typedef struct{ char hoTen[30]; int tuoi; float diemTB; } SinhVien; int nhapKichThuocMang(){ int n; do{ printf("\nMoi ban nhap so luong sinh vien: "); scanf("%d",&n); }while(n<=0); return n; } void nhapLieu(SinhVien SV[],int n){ int i; for(i=0; i<n; i++){ printf("\nNhap thong tin cho sinh vien %d",i+1); printf("\nHo va ten: "); fflush(stdin); gets(SV[i].hoTen); gets(SV[i].hoTen); do{ printf("Nhap tuoi: "); scanf("%d",&SV[i].tuoi); }while(SV[i].tuoi<18); do{ printf("Diem trung binh: "); scanf("%f",&SV[i].diemTB); }while(!(SV[i].diemTB>=0 && SV[i].diemTB<=10)); } } void timKiemTheoTen(SinhVien SV[],int n){ char sv[30]; int search, i; printf("\nMoi ban nhap ho ten cua sinh vien can tim: "); gets(sv); gets(sv); search=0; for(i=0; i<n; i++){ if(strcmp(SV[i].hoTen,sv)==0){ printf("\nTim thay!"); search=1; break; } } if(search==0) printf("\nKhong 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:

  • Bài tập phần cấu trúc