Cấu trúc (Struct) trong lập trình C

Các mảng trong C cho phép bạn định nghĩa một vài loại biến có thể giữ giá trị của một vài thành phần cùng kiểu dữ liệu. Nhưng structure – cấu trúc là một loại dữ liệu khác trong ngôn ngữ lập trình C, cho phép bạn kết hợp các dữ liệu khác kiểu nhau.

Cấu trúc được sử dụng để biểu diễn một bản ghi. Giả sử bạn muốn lưu trữ giá trị của một quyển sách trong thư viện của bạn. Bạn có thể lưu trữ các thuộc tính của sách sau đây:

  • Tiêu đề
  • Tác giả
  • Chủ đề
  • ID (giống như là mã số sinh viên của bạn)

Định nghĩa một cấu trúc trong C

Để định nghĩa cấu trúc, bạn phải sử dụng câu lệnh struct. Câu lệnh struct định nghĩa một kiểu dữ liệu mới, với hơn một thành phần trong chương trình của bạn. Dạng tổng quát của câu lệnh struct như sau đây:

struct [ten_cau_truc]
{
   phan dinh nghia thanh vien cau truc;
   phan dinh nghia thanh vien cau truc;
   ...
   phan dinh nghia thanh vien cau truc;
} [mot hoac nhieu bien cau truc];

Một ten_cau_truc có thể tùy chọn và một thành phần định nghĩa là các biến thường như int i, float j hoặc một định nghĩa biến khác… Tại phần cuối cùng của định nghĩa cấu trúc, trước dấu chấm phẩy, bạn có thể xác định một hoặc nhiều biến cấu trúc (tùy chọn). Dưới đây là cách khai báo biến structure Book:

struct Books
{
   char  tieude[50];
   char  tacgia[50];
   char  chude[100];
   int   id;
} book;

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

Để truy cập bất kỳ thành phần nào của cấu trúc, bạn sử dụng toán tử truy cập phần tử. Dưới đây là ví dụ cho cách sử dụng cấu trúc:

#include <stdio.h>
#include <string.h>
 
struct Books
{
   char  tieude[50];
   char  tacgia[50];
   char  chude[100];
   int   id;
};
 
int main( )
{
   struct Books Book1;        /* Khai bao Book1 la cua kieu Book */
   struct Books Book2;        /* Khai bao Book2 la cua kieu Book */
 
   /* thong tin chi tiet quyen sach thu nhat */
   strcpy( Book1.tieude, "Lap trinh C");
   strcpy( Book1.tacgia, "Pham Van At"); 
   strcpy( Book1.chude, "Ngon ngu lap trinh C");
   Book1.id = 1234567;

   /* thong tin chi tiet quyen sach thu hai */
   strcpy( Book2.tieude, "Toi thay hoa vang tren co xanh");
   strcpy( Book2.tacgia, "Nguyen Nhat Anh");
   strcpy( Book2.chude, "Van hoc");
   Book2.id = 6677028;
 
   /* hien thi thong tin Book1 */
   printf( "Tieu de cua Book1 la: %s\n", Book1.tieude);
   printf( "Tac gia cua Book1 la: %s\n", Book1.tacgia);
   printf( "Chu de cua Book1 la: %s\n", Book1.chude);
   printf( "ID cua Book1 la: %d\n", Book1.id);

   /* hien thi thong tin Book2 */
   printf( "Tieu de cua Book2 la: %s\n", Book2.tieude);
   printf( "Tac gia cua Book2 la: %s\n", Book2.tacgia);
   printf( "Chu de cua Book2 la: %s\n", Book2.chude);
   printf( "ID cua Book2 la: %d\n", Book2.id);
   
   printf("\n===========================\n");
   printf("QTM chuc cac ban hoc tot! \n");

   return 0;
}

Biên dịch và chạy chương trình C trên sẽ cho kết quả:

Các cấu trúc như các tham số hàm

Bạn có thể đặt cấu trúc như một tham số của hàm theo cách dễ dàng như các biến khác hay con trỏ. Truy cập biến cấu trúc như ví dụ dưới đây:

#include <stdio.h>
#include <string.h>
 
struct Books
{
   char  tieude[50];
   char  tacgia[50];
   char  chude[100];
   int   id;
};

/* khai bao ham */
void inthongtinsach( struct Books book );
int main( )
{
   struct Books Book1;        /* Khai bao Book1 la cua kieu Book */
   struct Books Book2;        /* Khai bao Book2 la cua kieu Book */
 
   /* thong tin chi tiet quyen sach thu nhat */
   strcpy( Book1.tieude, "Lap trinh C");
   strcpy( Book1.tacgia, "Pham Van At"); 
   strcpy( Book1.chude, "Ngon ngu lap trinh C");
   Book1.id = 1234567;

   /* thong tin chi tiet quyen sach thu hai */
   strcpy( Book2.tieude, "Toi thay hoa vang tren co xanh");
   strcpy( Book2.tacgia, "Nguyen Nhat Anh");
   strcpy( Book2.chude, "Van hoc");
   Book2.id = 6677028;
 
   /* hien thi thong tin Book1 */
   inthongtinsach( Book1 );

   /* hien thi thong tin Book2 */
   inthongtinsach( Book2 );
   
   printf("\n===========================\n");
   printf("QTM chuc cac ban hoc tot! \n");

   return 0;
}
void inthongtinsach( struct Books book )
{
   printf( "Tieu de sach: %s\n", book.tieude);
   printf( "Tac gia: %s\n", book.tacgia);
   printf( "Chu de: %s\n", book.chude);
   printf( "Book ID: %d\n", book.id);
}

Biên dịch và chạy chương trình C trên sẽ cho kết quả:

Con trỏ tới cấu trúc

Bạn có thể định nghĩa con trỏ cấu trúc theo cách bạn định nghĩa các loại con trỏ khác như sau:

struct Books *struct_pointer;

Bây giờ bạn có thể lưu địa chỉ của biến cấu trúc trong biến con trỏ được định nghĩa ở trên. Để tìm địa chỉ của một biến cấu trúc, đặt toán tử & trước tên cấu trúc như sau:

struct_pointer = &Book1;

Để truy cập vào thành phần của một structure sử dụng con trỏ tới structure đó, bạn phải sử dụng toán tử -> như sau:

struct_pointer->tieude;

Bây giờ chúng ta viết lại ví dụ trên sử dụng con trỏ cấu trúc, hy vọng điều này sẽ dễ dàng cho bạn để hiểu khái niệm này:

#include <stdio.h>
#include <string.h>
 
struct Books
{
   char  tieude[50];
   char  tacgia[50];
   char  chude[100];
   int   id;
};

/* khai bao ham */
void inthongtinsach( struct Books *book );
int main( )
{
   struct Books Book1;        /* Khai bao Book1 la cua kieu Book */
   struct Books Book2;        /* Khai bao Book2 la cua kieu Book */
 
   /* thong tin chi tiet quyen sach thu nhat */
   strcpy( Book1.tieude, "Lap trinh C");
   strcpy( Book1.tacgia, "Pham Van At"); 
   strcpy( Book1.chude, "Ngon ngu lap trinh C");
   Book1.id = 1234567;

   /* thong tin chi tiet quyen sach thu hai */
   strcpy( Book2.tieude, "Toi thay hoa vang tren co xanh");
   strcpy( Book2.tacgia, "Nguyen Nhat Anh");
   strcpy( Book2.chude, "Van hoc");
   Book2.id = 6677028;
 
   /* in thong tin Book1 bang cach truyen dia chi cua Book1 */
   inthongtinsach( &Book1 );

   /* in thong tin Book2 bang cach truyen dia chi cua Book2 */
   inthongtinsach( &Book2 );
   
   printf("\n===========================\n");
   printf("QTM chuc cac ban hoc tot! \n");

   return 0;
}
void inthongtinsach( struct Books *book )
{
   printf( "Tieu de sach: %s\n", book->tieude);
   printf( "Tac gia: %s\n", book->tacgia);
   printf( "Chu de: %s\n", book->chude);
   printf( "Book ID: %d\n", book->id);
}

Biên dịch và chạy chương trình C trên sẽ cho kết quả:

Các trường bit (Bit Fields) trong C

Các trường bit cho phép đóng gói dữ liệu trong một cấu trúc. Nó giúp tối ưu hóa bộ nhớ.

C cho phép bạn thực hiện điều này trong một định nghĩa cấu trúc bởi việc đặt: độ dài bit sau biến. Ví dụ:

struct packed_struct {
  unsigned int f1:1;
  unsigned int f2:1;
  unsigned int f3:1;
  unsigned int f4:1;
  unsigned int type:4;
  unsigned int my_int:9;
} pack;

Ở đây, packed_struct chứa 6 phần tử: 4 phần tử f1..f4 là 1 bit, một type là 4 bit và một my_int 9 bit.

C tự động đóng gói các trường bit trên càng gọn càng tốt, miễn là chiều dài tối đa của trường này nhỏ hơn hoặc bằng với chiều dài từ nguyên của máy tính. Bạn sẽ tìm hiểu về các trường bit trong một chương riêng.