Bài 14: Cấu trúc dữ liệu Struct và cách dùng Typedef trong C

Cách sử dụng cấu trúc dữ liệu với Struct, union, enum trong C

Trong bài này chúng ta sẽ học cách sử dụng cấu trúc dữ liệu Struct và định nghĩa lại dữ liệu với Typedef trong lập trình C.

Bài 14 trong serie Học lập trình C từ A tới Z

Cấu trúc dữ liệu là gì

Trong quá trình xây dựng ứng dụng, ngoài các kiểu dữ liệu do ngôn ngữ lập trình C hỗ trợ, thì C còn cho phép các lập trình viên có thể tự định nghĩa các kiểu dữ liệu riêng của mình. Các kiểu dữ liệu này được gọi là kiểu dữ liệu do người dùng định nghĩa “Kiểu dữ liệu người dùng” hay kiểu dữ liệu hướng người dùng.

Cấu trúc dữ liệu là một nhóm các phần tử dữ liệu được nhóm lại với nhau trong một tên. Các phần tử dữ liệu này còn được gọi là các thành viên, có thể là các kiểu dữ liệu khác nhau và độ dài khác nhau.

Ví dụ như SinhVien là một tập dữ liệu bao gồm : Tên, ngày sinh, giới tính và số điện thoại, cân nặng … Các phần tử này có thể khác nhau về mặt dữ liệu, thế nên không thể sử dụng 1 kiểu dữ liệu đơn thuần để lưu được.

Khai báo dữ liệu cấu trúc Struct

Structure In C

Cú pháp khai báo

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

Ví dụ, khai báo kiểu dữ liệu sinh viên, nhưng ko tạo ra biến nào.

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

Để tạo ra 2 biến sinh viên 1 ta làm như sau:

struct SinhVien sv1, sv2;

Hoặc có thể khai báo luôn 2 biến đó, khi khai báo kiểu dữ liệu Struct

struct SinhVien
{
    int maSV;
    char ho[20];
    char ten[20];
    bool gioiTinh;
    char queQuan[100];
}sv1,sv2;

Khởi tạo giá trị ban đầu cho biến Struct

Struct có thể được khởi tạo qua nhiều cách khác nhau, điều này bao gồm cả việc như gán các hằng số giá trị cho các thành phần. Ngoài ra nếu không khởi tạo giá trị thì các biến có kiểu struct cũng sẽ khởi tạo theo kiểu không tường minh.

Ví dụ với các thành phần có kiểu integer và float sẽ tự thiết lập giá trị là 0, với char và string sẽ là ‘\0’.

Cấu trúc:

struct <structure_tag_name>

{

 <data_type member_name1>;

 <data_type member_name2>;  

}<structure_variable1> = {constant1,constant2, . .};

Ví dụ:

struct SinhVien
{
    int maSV;
    char ho[20];
    char ten[20];
    bool gioiTinh;
    char queQuan[100];
    float chieucao;
}sv1 = {1, "Nguyen", "Khue", "Nam", "ABCXYZ", 1,78};

Như trong ví dụ, trình biên dịch sẽ ngầm định giá trị phần từ từ trên xuống dưới tương ứng với giá trị từ trái sang phải. Nghĩa là maSV = 1, Họ = “Nguyen” …..

Ngoài ra chúng ta có thể khởi tạo một cách tường minh hơn đó là gán giá trị cho từng phần tử trong struct.

VD:

struct SinhVien
{
    int maSV;
    char ho[20];
    char ten[20];
    bool gioiTinh;
    char queQuan[100];
    float chieucao; 
}sv1 = {maSV = 1, ho = "Nguyen", ten = "Khue", gioitinh = "Nam", queQuan = "ABCXYZ", chieucao = 1.78};

Truy cập tới từng thành viên của Struct

Truy vấn từng thành viên trong biến bằng toán tử ” . “

Cú pháp:

< structure_variable >.< member_name > ;

VD:

struct myStruct
{
   int a;
   int b;
   int c;
} s1, s2;

Để truy vấn chúng là sử dụng : s1.a; s1.b

Xét theo kía cạnh lưu trữ trên bố nhớ (Giả sử int lưu trữ 2 bytes “thực tế có thể 4 bytes” và a, b, c được lưu trữ tại các ô nhớ liên tiếp “a, b, c không nhất thiết phải lưu trữ tại các ô nhớ liên tiếp” khi đó hình ảnh thể hiện như sau:

struct phan tu
Truy cập vào từng phần tử trong Struct

Có thể thiết lập các giá trị cho các thành phần của struct.

s1.b = 12;

Để in giá trị các thành phần thì tùy thuộc vào kiểu dữ liệu của các thành ví dụ chúng ta muốn in thông tin của thành phần b thì chúng ta sử dụng câu lệnh :

printf(“%d”, s1.b);

Các thành phần có kiểu string, kiểu mảng thì chúng ta xử lý tương tự như chúng ta đã làm.

Con trỏ Struct

Một con trỏ trỏ đến cấu trúc hay biến con trỏ có kiểu cấu trúc (struct) chỉ đơn thuần là con trỏ đó trỏ đến địa chỉ của cấu trúc đó. Lưu ý con trỏ có kiểu struct không thể tự biến đổi biến con trỏ đó thành struct được.

Cú pháp:

struct <structure_tag_name >   /* Khai báo cấu trúc */
{
  <data_type member_name_1>;
  <data_type member_name_2>;
    .
    .
  <data_type member_name_n>;
} *ptr;

Để truy vấn đến các thành phần của cấu trúc. Chúng ta sử dụng cú pháp sau :

Cú pháp

(*ptr).member_name;

Hoặc

ptr-> member_name;

Copy và so sánh Struct

Một biến được khai báo có kiểu struct có thể gán cho một biến khác có cùng kiểu struct.

Ví dụ:

struct employee
{
  char grade;
  int basic;
  float allowance;
};

struct employee nam={‘b’, 6500, 812.5};

struct employee hung;

hung = nam; // Thực hiện phép gán biến hung = nam

Thực chất khi thực hiện phép gán hung = nam đó chính là quá trình sao chép dữ liệu các thành phần tương ứng của nam cho hung.

Phép so sánh cũng tương tự

Từ khóa typedef

Từ khóa typedef cho phép lập trình viên định nghĩa kiểu dữ liệu mới từ kiểu dữ liệu đã có trong chương trình.

Cú pháp

typedef <existing data type> <new data type ,….>;

Trong đó

existing data typeKiểu dữ liệu đã tồn tại trong chương trình

new data typeKiểu dữ liệu mới

VD:

typedef struct
{
    int maSV;
    char ho[20];
    char ten[20];
    bool gioiTinh;
    char queQuan[100];
}SinhVien;

Khi khai báo, chúng ta sẽ sử dụng.

SinhVien Sv1;

SinhVien Sv2;

Trong lập trình, nhiều khi các bạn sẽ thấy người ta sử dụng kiểu dữ liệu uint8_t, uint16_t, uint32_1, …. đó là kiểu dữ liệu được định nghĩa là từ unsigned int, unsigned long, ….

Bài tập về cấu trúc dữ liệu Struct

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

#include <stdio.h>
#include <string.h>
#include <math.h>
 
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ả

ket qua

Quản lý sách

#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;
}

Kết quả

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

Quản lý sách bằng 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 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);
}

Kết quả

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

Kết

Cấu trúc dữ liệu Struct được sử dụng rất nhiều trong lập trình C. Với Struct chúng ta có thể quản lý thông tin một cách đơn giản hơn rất nhiều.

Nếu thấy có ích hãy chia sẻ bài viết và tham gia nhóm Nghiện Lập Trình để giao lưu và học hỏi nhé

Trả lời

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *