1. Cấu trúc (structure) là gì?

  • Trong C, cấu trúc là kiểu dữ liệu do người dùng định nghĩa, có thể lưu trữ một tập hợp các biến thuộc các kiểu dữ liệu khác nhau dưới một tên duy nhất. Đây là một ví dụ định nghĩa một cấu trúc có tên là point chứa hai biến kiểu int, x và y:

struct Point {
  int x;
  int y;
};

  • Để tạo một thể hiện của một cấu trúc, bạn có thể khai báo một biến kiểu cấu trúc và gán giá trị cho các thành viên của nó.

struct Point p1;
p1.x = 10;
p1.y = 20;

  • Bạn cũng có thể khởi tạo một cấu trúc như sau: struct point p2 = {30, 40};

Cấu trúc dùng để lưu trữ dữ liệu liên quan, chẳng hạn như tọa độ của một điểm trong không gian 2D hoặc thông tin về một người, chẳng hạn như tên, tuổi và địa chỉ của họ.

2. Tại sao phải dùng structure?

Cấu trúc trong C cung cấp một số ưu điểm:

  • Tổ chức dữ liệu: Các cấu trúc cho phép bạn nhóm các dữ liệu liên quan thành một đơn vị duy nhất, giúp cho việc quản lý và thao tác dữ liệu dễ dàng hơn.
  • Khả năng tái sử dụng lại code: Bằng cách đóng gói dữ liệu vào một cấu trúc, bạn có thể sử dụng lại cấu trúc ở nhiều vị trí trong code của mình. Điều này làm cho code của bạn có nhiều mô-đun hơn và dễ bảo trì hơn.
  • Cải thiện khả năng đọc: Các cấu trúc làm cho mã của bạn dễ đọc hơn bằng cách làm rõ dữ liệu nào đang được sử dụng và dữ liệu đó có liên quan như thế nào.
  • Quản lý bộ nhớ tốt hơn: Bằng cách nhóm dữ liệu thành các cấu trúc, bạn có thể phân bổ và quản lý bộ nhớ hiệu quả hơn.
  • Cải thiện kiểm tra kiểu: Sử dụng các cấu trúc cho phép trình biên dịch thực thi kiểm tra kiểu, giúp ngăn chặn kiểu không khớp và các lỗi khác.
  • Đơn giản hóa các cấu trúc dữ liệu phức tạp: Các cấu trúc có thể được sử dụng để xây dựng các cấu trúc dữ liệu phức tạp hơn, chẳng hạn như danh sách liên kết, cây và đồ thị, có thể được sử dụng để biểu diễn và giải quyết các vấn đề trong thế giới thực.

Tóm lại, các cấu trúc trong C cung cấp một cách để tổ chức dữ liệu và làm cho việc quản lý, tái sử dụng và thao tác trở nên dễ dàng hơn. Chúng là một phần quan trọng của ngôn ngữ C và được sử dụng rộng rãi trong nhiều ứng dụng.

3. Truy cập các phần tử của cấu trúc

Bạn có thể truy cập các phần tử của một cấu trúc trong C bằng toán tử dấu chấm (.). Toán tử dấu chấm được sử dụng để truy cập các thành viên của một cấu trúc. Ví dụ, đưa ra định nghĩa cấu trúc sau:

struct Point {
  int x;
  int y;
};
Bạn có thể truy cập các phần tử của một cấu trúc như sau:
struct Point p;
p.x = 10;
p.y = 20;
Ở đây, p.x truy cập đến phần tử x của cấu trúc p và p.y truy cập đến phần tử y.

Bạn cũng có thể truy cập các phần tử của cấu trúc bằng cách sử dụng con trỏ tới cấu trúc. Để truy cập các phần tử của cấu trúc bằng con trỏ, bạn sử dụng toán tử mũi tên (->). Ví dụ:
struct Point p;
struct Point *ptr = &p;
ptr->x = 10;
ptr->y = 20;
Ở đây, ptr->x truy cập đến thành viên x của cấu trúc được trỏ bởi ptr, và ptr->y truy cập đến thành viên y.

4. Từ khóa typedef 

Từ khóa typedef trong C được sử dụng để đặt tên mới cho một kiểu (dữ liệu). Với typedef, bạn có thể tạo bí danh cho một kiểu dữ liệu hiện có, giúp code của bạn dễ đọc hơn và dễ bảo trì hơn. Ví dụ: bạn có thể sử dụng typedef để tạo bí danh cho kiểu cấu trúc:

typedef struct Point {
  int x;
  int y;
} Pt;
Điều này tạo ra một bí danh cho cấu trúc Point, là 1 cấu trúc có tên là Point. Sau này, bạn có thể sử dụng Point như thể nó là một loại tích hợp sẵn trong C:
Pt p;
p.x = 10;
p.y = 20;

5. Cấu trúc lồng nhau

Cấu trúc lồng nhau trong C là cấu trúc được định nghĩa bên trong cấu trúc khác. Nó cho phép bạn tạo các cấu trúc dữ liệu phức tạp bằng cách kết hợp các phần tử dữ liệu liên quan. Ví dụ, bạn có thể tạo một cấu trúc để biểu diễn một hình chữ nhật, trong đó mỗi hình chữ nhật có hai điểm xác định các góc của nó. Hai điểm có thể được biểu diễn dưới dạng các cấu trúc lồng nhau bên trong cấu trúc hình chữ nhật. Đây là một ví dụ:

struct Point {
  int x;
  int y;
};

struct Rectangle {
  struct Point top_left;
  struct Point bottom_right;
};
Trong ví dụ này, cấu trúc Point biểu thị một điểm trong không gian 2D và cấu trúc Rectangle biểu thị hình chữ nhật được xác định bởi hai điểm. Cấu trúc rectangle chứa hai phần tử, top_left và bottom_right, cả hai đều là point.

Bạn có thể truy cập các phần tử của cấu trúc lồng nhau bằng toán tử dấu chấm. Ví dụ:
struct Rectangle r;
r.top_left.x = 10;
r.top_left.y = 20;
r.bottom_right.x = 30;
r.bottom_right.y = 40;
Bạn cũng có thể sử dụng typedef để đặt tên mới cho cấu trúc lồng nhau, giúp mã của bạn dễ đọc hơn và dễ bảo trì hơn. Ví dụ:
typedef struct {
  int x;
  int y;
} Point;

typedef struct {
  Point top_left;
  Point bottom_right;
} Rectangle;
Với định nghĩa này, bạn có thể sử dụng Rectangle giống như bất kỳ kiểu dữ liệu nào trong C:
Rectangle r;
r.top_left.x = 10;
r.top_left.y = 20;
r.bottom_right.x = 30;
r.bottom_right.y = 40;
6. Một vài ví dụ dùng structure

Ví dụ 1:

#include <stdio.h>
#include <string.h>
struct Employee {
char name[50];
int id;
struct Address {
char street[50];
char city[50];
} address;
};

int main() {
struct Employee employes[2];
int i, j;

for (i = 0; i < 2; i++) {
printf("Enter employe name: ");
scanf("%s", employes[i].name);

printf("Enter employe ID: ");
scanf("%d", &employes[i].id);

printf("Enter street: ");
scanf("%s", employes[i].address.street);
printf("Enter city: ");
scanf("%s", employes[i].address.city);
}

for (i = 0; i < 2; i++) {
printf("\nStudent name: %s\n", employes[i].name);
printf("Student ID: %d\n", employes[i].id);
printf("Address: %s - %s\n", employes[i].address.street, employes[i].address.city);
}

return 0;
}

Ví dụ 2:

#include <stdio.h>
#include <string.h>

struct Employee {
char name[50];
int id;
float salary;
};

void inputEmployeeData(struct Employee *employee) {

printf("Enter employee ID: ");
scanf("%d", &employee->id);
printf("Enter employee name: ");
scanf("%s", employee->name);

printf("Enter employee salary: ");
scanf("%f", &employee->salary);
}

float calculateAverageSalary(struct Employee employees[], int size) {
int i;
float total = 0;

for (i = 0; i < size; i++) {
total += employees[i].salary;
}

return total / size;
}

int main() {
struct Employee employees[5];
int i;
float averageSalary;

for (i = 0; i < 5; i++) {
printf("\n***Input information for employee %d:\n", (i+1));
inputEmployeeData(&employees[i]);
}

averageSalary = calculateAverageSalary(employees, 5);

printf("\nThe average salary of all employees is: %.2f\n", averageSalary);

return 0;
}