0

Cấp phát bộ nhớ struct

Tron bài viết này, mình sẽ hướng dẫn các bạn các kiến trúc liên quan tới cấp phát struct trong C. Và mình sẽ ghi lại những vấn đề thường gặp trong quá trình làm việc.

I. Tổng quan

Sử dụng malloc() trong thư viện stdlib.h để thực hiện điều này.

Cú pháp

#include <stdlib.h>

// định nghĩa một cấu trúc
typedef struct name {
    ....
};

// Cấp phát memory cho cấu trúc được định nghĩa
name* new = (name *)malloc(sizeof(name));

// Đưng quên kiểm tra lại: Đảm bảo cấp phát memory thành công
if(new == NULL)
    Fail;

Ví dụ: Cấp phát vùng nhớ cho struct student.

#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>

struct student
{
  char name;
  int mssv;
  int age;
};

struct student* Init()
{
  struct student * newStudent = (struct student *)malloc(sizeof(struct student));
  if(newStudent == NULL)
    return NULL; // cáp phát thất bại
    
  return newStudent;
}

int main()
{
  struct student* A = Init();
  
  printf("địa chỉ bắt đầu vùng nhớ: %p\n", A);
  printf("Kích thước vùng nhớ A đang trỏ tới: %d", sizeof(*A));
  
  return 0;
}

Output:

địa chỉ bắt đầu vùng nhớ: 0x560ed1e8d2a0
Kích thước vùng nhớ A đang trỏ tới: 12

II. Vấn đề

1. Vấn đề 1

Mình sẽ tạo một mẫu để có thể mô tả vấn đề gặp trong dự án như sau

#include <stdio.h>
#include <stdlib.h>

typedef struct Student {
  int  mssv;
  int  age;
} Student_t;

typedef struct ListStudent {
  int number;           // só lương học sinh
  int current;          // số lượng hộc sinh hiện tại
  Student_t* Students;  // mảng quản lí các học sinh
} List_t;

void Add(List_t* list, Student_t* student) {
  list->Students[list->current] = student; // ❌ sai
  list->current++;
}

int main()
{
  List_t list;
  list.number = 5;
  list.current = 0;
  list.Students = (Student_t *)malloc(sizeof(Student_t) * 5);
  
  Student_t A = {
    .mssv = 1,
    .age  = 20 
  };
  
  Student_t B = {
    .mssv = 2,
    .age  = 21
  };
  
  Add(&list, &A);
  Add(&list, &B);
  
  printf("So luong sinh vien: %d\n", list.current);
}

Khi biên dịch có kết quả như sau:

Main.c:7:1: warning: no semicolon at end of struct or union
    7 | } Student_t;
      | ^
Main.c: In function ‘Add’:
Main.c:16:35: error: incompatible types when assigning to type ‘Student_t’ {aka ‘struct Student’} from type ‘Student_t *’ {aka ‘struct Student *’}
   16 |   list->Students[list->current] = student;
      |                                   ^~~~~~~

Có thể thấy đoạn mã trên bị lỗi ở dòng thứ 16: lỗi ở đây là do mình đã gán con trỏ struct cho một biến kiểu struct.

list->Students[list->current] = student;

student ở đây là một con trỏ struct.

🤔 Tại vì sao xuất hiện lỗi này?

Nếu các bạn để ý ở đây lúc ban đầu, mình có khai báo

// Member trong struct list
Student_t* Students;  // mảng quản lí các học sinh 

// hàm main()
// cấp phát mảng để quản lí 5 học sinh
list.Students = (Student_t *)malloc(sizeof(Student_t) * 5); 

Khi thực thi câu lệnh này nó sẽ tạo ra một mảng có 5 phần tử, mỗi phần tử là một struct student.

Nhưng khi thực hiện hàm add(), tham số thứ hai của hàm truyền vào là một con trỏ.

👉 Rõ ràng lúc này, mk không thể gán địa chỉ mà con trỏ đang giữ cho phần tử của mảng được.

Giải quyết thế nào ?

  • Phương án 1: Thay vì truyền địa chỉ, thì ta cần phải truyền giá trị
list->Students[list->current] = *student; 

Phương án này sẽ giúp ta copy dữ liệu từ struct và truyền vào mảng. Điều nây sẽ gây tốn memory để tiến hành thao tác copy.

  • Phương án 2: Thay đổi kiểu member trong struct ListStudent.
typedef struct ListStudent {
    int number;
    int current;
    Student_t** Students;   // mảng con trỏ
} List_t;

Lúc này member Students sẽ là mảng các con trỏ có kiểu là struct Student. Mỗi con trỏ sẽ trỏ tới vùng nhớ lưu trữ thông tin của học sinh.


All rights reserved

Viblo
Hãy đăng ký một tài khoản Viblo để nhận được nhiều bài viết thú vị hơn.
Đăng kí