C – Cấu Trúc (Structure)

Học Lập Trình C - Cấu Trúc (Structure)

Mảng (array) cho phép xác định kiểu biến có thể chứa nhiều mục dữ liệu (data item) cùng loại. Tương tự cấu trúc (structure) là một kiểu dữ liệu khác, có sẵn trong C, do người dùng định nghĩa, cho phép kết hợp các mục dữ liệu thuộc các kiểu khác nhau.

Các cấu trúc được sử dụng để biểu diễn một bản ghi (record). Giả sử bạn muốn theo dõi sách của mình trong thư viện. Bạn có thể muốn theo dõi các thuộc tính sau của mỗi cuốn sách.

  • Tiêu đề (Title)
  • Tác giả (Author)
  • Tựa (Subject)
  • Book ID (ID sách)

Định Nghĩa Một Cấu Trúc

Để định nghĩa một cấu trúc, bạn phải sử dụng phát biểu struct. Phát biểu struct định nghĩa một kiểu dữ liệu mới, có hơn một member. Định dạng (format) của phát biểu struct là

struct [structure tag] {
   member definition;
   member definition;
   ...
   member definition;
} [one or more structure variables];

Thẻ structure tag là tùy chọn và mỗi định nghĩa member là một định nghĩa biến thông thường. Tại cuối định nghĩa cấu trúc, trước dấu chấm phẩy (;) cuối cùng, bạn có thể chỉ định một hoặc nhiều biến cấu trúc (one or more structure variables) hoặc không. Dưới đây là cách khai báo một cấu trúc Book

struct Books {
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
} book;  

Truy Cập Member Của Cấu Trúc

Để truy cập một member trong một cấu trúc, chúng ta sử dụng toán tử truy cập member (member access operator). Toán tử truy cập member là một dấu chấm (.) giữa tên biến cấu trúc (structure variable name) và member của cấu trúc (structure member). Bạn cần sử dụng từ khóa struct để định nghĩa các biến của kiểu structure. Ví dụ tiếp theo cho thấy cách sử dụng cấu trúc trong một chương trình.

#include <stdio.h>
#include <string.h>
 
struct Books {
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
};
 
int main( ) {
   struct Books Book1;        /* Declare Book1 of type Book */
   struct Books Book2;        /* Declare Book2 of type Book */
 
   /* book 1 specification */
   strcpy( Book1.title, "C Programming");
   strcpy( Book1.author, "Nuha Ali"); 
   strcpy( Book1.subject, "C Programming Tutorial");
   Book1.book_id = 6495407;
   /* book 2 specification */
   strcpy( Book2.title, "Telecom Billing");
   strcpy( Book2.author, "Zara Ali");
   strcpy( Book2.subject, "Telecom Billing Tutorial");
   Book2.book_id = 6495700;
 
   /* print Book1 info */
   printf( "Book 1 title : %s\n", Book1.title);
   printf( "Book 1 author : %s\n", Book1.author);
   printf( "Book 1 subject : %s\n", Book1.subject);
   printf( "Book 1 book_id : %d\n", Book1.book_id);
   /* print Book2 info */
   printf( "Book 2 title : %s\n", Book2.title);
   printf( "Book 2 author : %s\n", Book2.author);
   printf( "Book 2 subject : %s\n", Book2.subject);
   printf( "Book 2 book_id : %d\n", Book2.book_id);
   return 0;
}

Khi đoạn code được biên dịch và thực thi, kết quả nhận được là.

Book 1 title : C Programming
Book 1 author : Nuha Ali
Book 1 subject : C Programming Tutorial
Book 1 book_id : 6495407
Book 2 title : Telecom Billing
Book 2 author : Zara Ali
Book 2 subject : Telecom Billing Tutorial
Book 2 book_id : 6495700

Cấu Trúc Làm Đối Số Hàm (Structure as Function Arguments)

Bạn có thể truyền một cấu trúc như một đối số hàm (function argument) giống như khi bạn truyền một biến thông thường hoặc con trỏ.

#include <stdio.h>
#include <string.h>
 
struct Books {
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
};

/* function declaration */
void printBook( struct Books book );

int main( ) {

   struct Books Book1;        /* Declare Book1 of type Book */
   struct Books Book2;        /* Declare Book2 of type Book */
 
   /* book 1 specification */
   strcpy( Book1.title, "C Programming");
   strcpy( Book1.author, "Nuha Ali"); 
   strcpy( Book1.subject, "C Programming Tutorial");
   Book1.book_id = 6495407;

   /* book 2 specification */
   strcpy( Book2.title, "Telecom Billing");
   strcpy( Book2.author, "Zara Ali");
   strcpy( Book2.subject, "Telecom Billing Tutorial");
   Book2.book_id = 6495700;
 
   /* print Book1 info */
   printBook( Book1 );

   /* Print Book2 info */
   printBook( Book2 );

   return 0;
}

void printBook( struct Books book ) {

   printf( "Book title : %s\n", book.title);
   printf( "Book author : %s\n", book.author);
   printf( "Book subject : %s\n", book.subject);
   printf( "Book book_id : %d\n", book.book_id);
}

Trong ví dụ này, hàm printBook nhận một đối số là biến book có kiểu dữ liệu là cấu trúc Books và in ra các member của nó.

Book title : C Programming
Book author : Nuha Ali
Book subject : C Programming Tutorial
Book book_id : 6495407
Book title : Telecom Billing
Book author : Zara Ali
Book subject : Telecom Billing Tutorial
Book book_id : 6495700

Con Trỏ Đến Cấu Trúc (Pointer to Structure)

Bạn có thể định nghĩa con trỏ đến cấu trúc giống như cách định nghĩa một con trỏ đến kiểu dữ liệu thông thường.

struct Books *struct_pointer;

Bây giờ, bạn có thể lưu địa chỉ của một biến cấu trúc (structure variable) trong biến con trỏ (pointer variable) đã định nghĩa trên. Để lấy địa chỉ của một biến cấu trúc, hãy đặt toán tử ‘&’ trước tên cấu trúc như sau.

struct_pointer = &Book1;

Để truy cập các member của cấu trúc mà con trỏ đang trỏ tới, bạn phải dùng toán tử như sau.

struct_pointer->title;

Chúng ta hãy chỉnh sửa lại ví dụ trên bằng việc dùng con trỏ cấu trúc (structure pointer).

#include <stdio.h>
#include <string.h>
 
struct Books {
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
};

/* function declaration */
void printBook( struct Books *book );
int main( ) {

   struct Books Book1;        /* Declare Book1 of type Book */
   struct Books Book2;        /* Declare Book2 of type Book */
 
   /* book 1 specification */
   strcpy( Book1.title, "C Programming");
   strcpy( Book1.author, "Nuha Ali"); 
   strcpy( Book1.subject, "C Programming Tutorial");
   Book1.book_id = 6495407;

   /* book 2 specification */
   strcpy( Book2.title, "Telecom Billing");
   strcpy( Book2.author, "Zara Ali");
   strcpy( Book2.subject, "Telecom Billing Tutorial");
   Book2.book_id = 6495700;
 
   /* print Book1 info by passing address of Book1 */
   printBook( &Book1 );

   /* print Book2 info by passing address of Book2 */
   printBook( &Book2 );

   return 0;
}

void printBook( struct Books *book ) {

   printf( "Book title : %s\n", book->title);
   printf( "Book author : %s\n", book->author);
   printf( "Book subject : %s\n", book->subject);
   printf( "Book book_id : %d\n", book->book_id);
}

Chú ý rằng, trong hàm printBook chúng ta sử dụng toán tử -> để lấy giá trị các member. Kết quả như dưới đây.

Book title : C Programming
Book author : Nuha Ali
Book subject : C Programming Tutorial
Book book_id : 6495407
Book title : Telecom Billing
Book author : Zara Ali
Book subject : Telecom Billing Tutorial
Book book_id : 6495700

Trường Bit (Bit Fields)

Trường Bit (Bit Fields) cho phép đóng gói dữ liệu trong một cấu trúc. Điều này đặc biệt hữu ích khi bộ nhớ dữ liệu khan hiếm. Các ví dụ điển hình bao gồm:

  • Đóng gói nhiều đối tượng thành một từ máy (machine word). ví dụ. Các cờ (flag) 1 bit có thể được nén lại.
  • Đọc các định dạng file bên ngoài – các định dạng file không chuẩn có thể cần đọc, ví dụ: số nguyên 9 bit.

Ngôn ngữ lập trình C cho phép chúng ta thực hiện điều này trong một định nghĩa cấu trúc bằng cách đặt dấu hai chấm (:) và độ dài bit sau một 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 member: Bốn cờ 1 bit f1, f2, f3, f4, một type 4 bit và một my_int 9 bit.

C tự động đóng gói các trường bit trên nén (compact) nhất có thể, đảm bảo độ dài tối đa của trường nhỏ hơn hoặc bằng độ dài từ số nguyên của máy tính (integer word length of the computer). Nếu không đúng như vậy, thì một số compiler có thể cho phép chồng lấn bộ nhớ (overlap memory) các trường, hoặc những compiler khác sẽ lưu trường tiếp theo ở word kế tiếp.

(Tiếp theo)

Icons made by Freepik from www.flaticon.com