Hướng dẫn gọi struct theo kiểu con trỏ năm 2024

Trong bài hướng dẫn này, bạn sẽ cùng Lập trình không khó tìm hiểu về kiểu struct trong C (kiểu cấu trúc). Bạn sẽ học cách định nghĩa và sử dụng kiểu cấu trúc với sự đi kèm của các ví dụ. Nếu dịch từ tiếng anh ra thì nghĩa của nó là kiểu cấu trúc, tuy nhiên chúng ta vẫn thường hay gọi nó là kiểu struct. Nhưng mục tiêu sau cùng của chúng ta là hiểu và biết cách sử dụng struct trong C, cùng bắt đầu nào…

NỘI DUNG BÀI VIẾT

Cách định nghĩa struct trong C

Trước khi chúng ta có thể khai báo biến với struct, bạn cần định nghĩa nó – Đó cũng là lý do tại sao struct được gọi là kiểu dữ liệu người dùng định nghĩa.

Khi nào chúng ta cần phải tự định nghĩa 1 kiểu cấu trúc? Khi bạn cần lưu trữ một đối tượng có nhiều thuộc tính. Ví dụ, đối tượng SinhVien có các thuộc tính (Mã sinh viên, họ, tên, giới tính, quê quán,…) hay đối tượng LopHoc có các thuộc tính (Mã lớp, tên lớp, giáo viên chủ nhiệm, sĩ số,…). Khi đó chúng ta nên dùng struct để quản lý chương trình.

Cú pháp định nghĩa struct trong C

struct structureName {

dataType member1;
dataType member2;
...
};

Dưới đây là 1 ví dụ:

struct SinhVien {

int maSV;
char ho[20];
char ten[20];
bool gioiTinh;
char queQuan[100];
};

Như vậy, kiểu dữ liệu

struct SinhVien {

int maSV;
char ho[20];
char ten[20];
bool gioiTinh;
char queQuan[100];
};

8 đã được định nghĩa. Từ đây chúng ta có thể khai báo các biến với kiểu dữ liệu này.

Cách khai báo biến kiểu struct trong C

Việc khai báo biến với struct cũng giống như cách khai báo biến thông thường, trong đó kiểu dữ liệu là kiểu struct trong C mà bạn vừa định nghĩa. Xem ví dụ dưới đây:

struct SinhVien {

int maSV;
char ho[20];
char ten[20];
bool gioiTinh;
char queQuan[100];
}; int main(){
// Khai báo 2 biến sv1 và sv2 có kiểu SinhVien
SinhVien sv1, sv2;
// Ta nên thêm từ khóa struct ở đầu,
// để phân biệt được biến này là biến của kiểu dữ liệu tự định nghĩa
struct SinhVien sv3, sv4;
// Khai báo mảng
struct SinhVien sv[100];
}

Truy xuất các thuộc tính của struct

Chúng ta có 2 toán tử dùng để truy xuất tới các biến thành viên của kiểu struct trong C.

  • Sử dụng `.` => Toán tử truy xuất tới thành viên khi khai báo biến bình thương.
  • Sử dụng `->` => Toán tử truy xuất tới thành viên khi biến là con trỏ.

Giả sử trong ví dụ trên, bạn muốn truy xuất

struct SinhVien {

int maSV;
char ho[20];
char ten[20];
bool gioiTinh;
char queQuan[100];
};

9 của đối tượng sinh viên, bạn làm như sau:

SinhVien sv; // to do printf("Gioi tinh: %s", sv.gioiTinh);

Từ khóa typedef

Bạn có thể sử dụng từ khóa

struct SinhVien {

int maSV;
char ho[20];
char ten[20];
bool gioiTinh;
char queQuan[100];
}; int main(){
// Khai báo 2 biến sv1 và sv2 có kiểu SinhVien
SinhVien sv1, sv2;
// Ta nên thêm từ khóa struct ở đầu,
// để phân biệt được biến này là biến của kiểu dữ liệu tự định nghĩa
struct SinhVien sv3, sv4;
// Khai báo mảng
struct SinhVien sv[100];
}

0 để tạo ra một tên thay thế cho kiểu dữ liệu đã có. Nó thường được sử dụng kiểu struct để đơn giản hóa cú pháp khai báo biến. Nhưng nó cũng có thể sử dụng với các kiểu dữ liệu nguyên thủy nhé.

struct Distance{

int feet;
float inch;
}; int main() {
structure Distance d1, d2;
}

Code trên tương đương với:

typedef struct SinhVien{

int feet;
float inch;
} distances; int main() {
distances d1, d2;
}

Hoặc:

struct PhanSo{

int tu;
int mau;
}; typedef struct PhanSo PS;

Hoặc bạn có thể dùng với kiểu nguyên thủy như sau:

typedef int U_INT8; // Khai báo biến kiểu int U_INT8 value;

Tuy nhiên, nếu không có nhu cầu thực tế thì ta cũng không nên bày vẽ làm gì. Trong một số code đặc thù ta muốn có quy chuẩn riêng thì nên dùng.

Cấu trúc struct lồng nhau

Giả sử bạn muốn xây dựng kiểu dữ liệu để lưu trữ đối tượng Tam giác, khi đó chúng ta có thể xây dựng struct mô tả tọa độ của 1 điểm, khi đó đối tượng tam giác sẽ là 3 đối tượng điểm. Cụ thể:

struct Point{

int x; // hoành độ
int y; // tung độ
}; struct Triangle{
Point a; // đỉnh thứ 1
Point b; // đỉnh thứ 2
Point c; // đỉnh thứ 3
} int main(){
Triangle tg;
// truy xuất hoành độ của điểm thứ nhất
tg.a.x = 5;
}

Sau đây là các ví dụ sử dụng kiểu cấu trúc struct trong C vào các bài tập thực tế. Các bạn tham khảo và chạy thử cũng như thử sửa đổi các code mẫu này để hiểu hơn về struct nhé.

Chương trình cộng trừ nhân chia phân số trong C

Code này mình giả sử các bạn nhập mẫu số cho phân số khác 0 nhé. Bạn có thể kiểm tra bổ sung thêm các tùy chọn/ chức năng để code tối ưu hơn.

Phần thuật toán tìm ước chung lớn nhất, bạn có thể xem tại bài tìm ước chung lớn nhất.

include

include

include

int UCLN(int a, int b) {

a = abs(a);
b = abs(b);
while (a * b != 0)
{
    if (a > b)
        a %= b;
    else
        b %= a;
}
return a + b;
} int BSCNN(int a, int b) {
return a * b / UCLN(a, b);
} typedef struct PhanSo {
int tuso, mauso;
} PS; PS rutGon(PS a) {
PS c;
c.tuso = a.tuso / UCLN(a.tuso, a.mauso);
c.mauso = a.mauso / UCLN(a.tuso, a.mauso);
return c;
} PS cong(PS a, PS b) {
PS c;
c.tuso = a.tuso * b.mauso + a.mauso * b.tuso;
c.mauso = a.mauso * b.mauso;
c = rutGon(c);
return c;
} PS tru(PS a, PS b) {
PS c;
c.tuso = a.tuso * b.mauso - a.mauso * b.tuso;
c.mauso = a.mauso * b.mauso;
c = rutGon(c);
return c;
} PS nhan(PS a, PS b) {
PS c;
c.tuso = a.tuso * b.tuso;
c.mauso = a.mauso * b.mauso;
c = rutGon(c);
return c;
} PS chia(PS a, PS b) {
PS c;
c.tuso = a.tuso * b.mauso;
c.mauso = a.mauso * b.tuso;
c = rutGon(c);
return c;
} void print(PS a) {
printf("%d/%d", a.tuso, a.mauso);
} int main() {
PS a, b, c;
printf("\nNhap phan so a : ");
scanf("%d%d", &a.tuso, &a.mauso);
printf("\nNhap phan so b : ");
scanf("%d%d", &b.tuso, &b.mauso);
printf("\nToi gian a ta duoc : ");
a = rutGon(a);
print(a);
printf("\nToi gian b ta duoc : ");
b = rutGon(b);
print(b);
printf("\nTong cua hai phan so = ");
c = cong(a, b);
print(c);
printf("\nHieu cua hai phan so = ");
c = tru(a, b);
print(c);
printf("\nTich cua hai phan so = ");
c = nhan(a, b);
print(c);
printf("\nThuong cua hai phan so = ");
c = chia(a, b);
print(c);
}

Kết quả chạy:

struct SinhVien {

int maSV;
char ho[20];
char ten[20];
bool gioiTinh;
char queQuan[100];
};

0

Struct và con trỏ

Tương tự như khai báo con trỏ với các kiểu dữ liệu có sẵn trong C. Chúng ta cũng có thể khai báo biến con trỏ, cấp phát động cho biến con trỏ kiểu struct.

Sau đây là cách chúng ta khai báo biến con trỏ kiểu struct trong C:

struct SinhVien {

int maSV;
char ho[20];
char ten[20];
bool gioiTinh;
char queQuan[100];
};

1

Khi đó

struct SinhVien {

int maSV;
char ho[20];
char ten[20];
bool gioiTinh;
char queQuan[100];
}; int main(){
// Khai báo 2 biến sv1 và sv2 có kiểu SinhVien
SinhVien sv1, sv2;
// Ta nên thêm từ khóa struct ở đầu,
// để phân biệt được biến này là biến của kiểu dữ liệu tự định nghĩa
struct SinhVien sv3, sv4;
// Khai báo mảng
struct SinhVien sv[100];
}

1 là con trỏ kiểu

struct SinhVien {

int maSV;
char ho[20];
char ten[20];
bool gioiTinh;
char queQuan[100];
}; int main(){
// Khai báo 2 biến sv1 và sv2 có kiểu SinhVien
SinhVien sv1, sv2;
// Ta nên thêm từ khóa struct ở đầu,
// để phân biệt được biến này là biến của kiểu dữ liệu tự định nghĩa
struct SinhVien sv3, sv4;
// Khai báo mảng
struct SinhVien sv[100];
}

2, còn

struct SinhVien {

int maSV;
char ho[20];
char ten[20];
bool gioiTinh;
char queQuan[100];
}; int main(){
// Khai báo 2 biến sv1 và sv2 có kiểu SinhVien
SinhVien sv1, sv2;
// Ta nên thêm từ khóa struct ở đầu,
// để phân biệt được biến này là biến của kiểu dữ liệu tự định nghĩa
struct SinhVien sv3, sv4;
// Khai báo mảng
struct SinhVien sv[100];
}

3 là biến kiểu

struct SinhVien {

int maSV;
char ho[20];
char ten[20];
bool gioiTinh;
char queQuan[100];
}; int main(){
// Khai báo 2 biến sv1 và sv2 có kiểu SinhVien
SinhVien sv1, sv2;
// Ta nên thêm từ khóa struct ở đầu,
// để phân biệt được biến này là biến của kiểu dữ liệu tự định nghĩa
struct SinhVien sv3, sv4;
// Khai báo mảng
struct SinhVien sv[100];
}

2.

Để truy cập vào các biến thành viên sử dụng biến con trỏ của struct trong C, bạn dùng

struct SinhVien {

int maSV;
char ho[20];
char ten[20];
bool gioiTinh;
char queQuan[100];
}; int main(){
// Khai báo 2 biến sv1 và sv2 có kiểu SinhVien
SinhVien sv1, sv2;
// Ta nên thêm từ khóa struct ở đầu,
// để phân biệt được biến này là biến của kiểu dữ liệu tự định nghĩa
struct SinhVien sv3, sv4;
// Khai báo mảng
struct SinhVien sv[100];
}

5, ví dụ:

struct SinhVien {

int maSV;
char ho[20];
char ten[20];
bool gioiTinh;
char queQuan[100];
};

2

Trong ví dụ này, địa chỉ của biến

struct SinhVien {

int maSV;
char ho[20];
char ten[20];
bool gioiTinh;
char queQuan[100];
}; int main(){
// Khai báo 2 biến sv1 và sv2 có kiểu SinhVien
SinhVien sv1, sv2;
// Ta nên thêm từ khóa struct ở đầu,
// để phân biệt được biến này là biến của kiểu dữ liệu tự định nghĩa
struct SinhVien sv3, sv4;
// Khai báo mảng
struct SinhVien sv[100];
}

6 được lưu giữ bởi con trỏ

struct SinhVien {

int maSV;
char ho[20];
char ten[20];
bool gioiTinh;
char queQuan[100];
}; int main(){
// Khai báo 2 biến sv1 và sv2 có kiểu SinhVien
SinhVien sv1, sv2;
// Ta nên thêm từ khóa struct ở đầu,
// để phân biệt được biến này là biến của kiểu dữ liệu tự định nghĩa
struct SinhVien sv3, sv4;
// Khai báo mảng
struct SinhVien sv[100];
}

7. Và bạn có thể thao tác với biến con trỏ giống như chúng ta đã học ở bài Con trỏ trong C.

Ta có:

  • struct SinhVien {
    int maSV;  
    char ho[20];  
    char ten[20];  
    bool gioiTinh;  
    char queQuan[100];  
    
    }; int main(){
    // Khai báo 2 biến sv1 và sv2 có kiểu SinhVien  
    SinhVien sv1, sv2;  
    // Ta nên thêm từ khóa struct ở đầu,  
    // để phân biệt được biến này là biến của kiểu dữ liệu tự định nghĩa  
    struct SinhVien sv3, sv4;  
    // Khai báo mảng  
    struct SinhVien sv[100];  
    
    } 8 cho kết quả giống với struct SinhVien {
    int maSV;  
    char ho[20];  
    char ten[20];  
    bool gioiTinh;  
    char queQuan[100];  
    
    }; int main(){
    // Khai báo 2 biến sv1 và sv2 có kiểu SinhVien  
    SinhVien sv1, sv2;  
    // Ta nên thêm từ khóa struct ở đầu,  
    // để phân biệt được biến này là biến của kiểu dữ liệu tự định nghĩa  
    struct SinhVien sv3, sv4;  
    // Khai báo mảng  
    struct SinhVien sv[100];  
    
    } 9
  • SinhVien sv; // to do printf("Gioi tinh: %s", sv.gioiTinh); 0 cho kết quả giống với SinhVien sv; // to do printf("Gioi tinh: %s", sv.gioiTinh); 1

Cấp phát bộ nhớ động

Trước khi bạn đọc phần này, mình hi vọng các bạn đã có kiến thức về cấp phát động trong C.

Đôi khi, số lượng biến struct trong C mà chúng ta cần có thể lớn. Khi đó có thể bạn sẽ cần tới cấp phát động trong quá trình chương trình thực thi. Dưới đây là cách để cấp phát bộ nhớ động với kiểu cấu trúc:

struct SinhVien {

int maSV;
char ho[20];
char ten[20];
bool gioiTinh;
char queQuan[100];
};

3

Kết quả khi chạy chương trình:

struct SinhVien {

int maSV;
char ho[20];
char ten[20];
bool gioiTinh;
char queQuan[100];
};

4

Trong ví dụ trên, sau khi người dùng nhập số lượng

SinhVien sv; // to do printf("Gioi tinh: %s", sv.gioiTinh);

2 thì ta mới tiến hành cấp phát đúng

SinhVien sv; // to do printf("Gioi tinh: %s", sv.gioiTinh);

2 ô nhớ sử dụng dòng lệnh này:

struct SinhVien {

int maSV;
char ho[20];
char ten[20];
bool gioiTinh;
char queQuan[100];
};

5

Và sau đó, ta dùng con trỏ

struct SinhVien {

int maSV;
char ho[20];
char ten[20];
bool gioiTinh;
char queQuan[100];
}; int main(){
// Khai báo 2 biến sv1 và sv2 có kiểu SinhVien
SinhVien sv1, sv2;
// Ta nên thêm từ khóa struct ở đầu,
// để phân biệt được biến này là biến của kiểu dữ liệu tự định nghĩa
struct SinhVien sv3, sv4;
// Khai báo mảng
struct SinhVien sv[100];
}

1 để truy cập vào các thành viên của

SinhVien sv; // to do printf("Gioi tinh: %s", sv.gioiTinh);

5.

Hoặc bài tập cấp phát động cho kiểu cấu trúc sinh viên dưới đây, ta thực hiện nhập, xuất và sắp xếp danh sách sinh viên theo điểm sử dụng cấp phát động cho con trỏ trong C++ (new và delete):

struct SinhVien {

int maSV;
char ho[20];
char ten[20];
bool gioiTinh;
char queQuan[100];
};

6

Kết quả chạy:

struct SinhVien {

int maSV;
char ho[20];
char ten[20];
bool gioiTinh;
char queQuan[100];
};

7

Ngoài ra, mình cũng có một bài hướng dẫn chi tiết và nâng cao hơn: Bài tập quản lý sinh viên sử dụng struct trong C. Các bạn tiếp tục tham khảo bài viết này nhé!