Làm việc với Cấp phát bộ nhớ trong lập trình c/c++

Trong bài viết này Stanford sẽ giúp các học học lập trình c++ hiểu rõ hơn về cơ chế lưu trữ trong bộ nhớ ảo cũng như cách sử dụng cấp phát động và giải phóng bộ nhớ trong c/c++

Tổ chức lưu trữ trong bộ nhớ ảo

Trong máy tính để lưu trữ được thông tin bộ nhớ ảo của máy tính sẽ được tổ chức mô tả như hình sau:

Code Segment

Code segment (text segment): Là nơi lưu trữ mã máy dạng nhị phân. Có nghĩa là các chương trình mà chúng ta code là code trên ngôn ngữ tự nhiên, nhưng khi ở phân vùng này nó sẽ ở dạng mã máy nhị phân. Code segment chỉ chịu sự chi phối của hệ điều hành, người lập trình không thể can thiệp trực tiếp đến phân vùng này.

Data Segment

Data segment (initialized data segment): Là nơi chứa các biến kiểu static, biến toàn cục (global variable).

BSS Segment

BSS segment (uninitialized data segment) cũng được dùng để lưu trữ các biến kiểu static, biến toàn cục (global variable) nhưng chưa được khởi tạo giá trị cụ thể.

Heap

Là vùng nhớ không do CPU quản lý, người lập trình phải tự quản lý vùng nhớ này. Nó được sử dụng khi thực hiện cấp phát bộ nhớ động dùng cho con trỏ.

Stack

Call Stack (thường được gọi là Stack): Là vùng nhớ do CPU quản lý, người lập trình không thể can thiệp vào vùng nhớ này. Nếu cố tình can thiệp sẽ bị lỗi (code bên dưới, bạn chạy thử xem nó hiện thông báo lỗi như thế nào nhé). Vùng nhớ Stack được dùng để cấp phát bộ nhớ cho tham số của các hàm (function parameters) và biến cục bộ (local variables).

Tại sao cần cấp phát vùng nhớ ?

Vì nếu không cấp phát bộ nhớ cho con trỏ thì chúng ta không thể nhập dữ liệu trực tiếp cho con trỏ được.
Có thể hiểu thế này: khi muốn xây nhà thì chúng ta cần phải có đất. Khi người ta bán đất cho mình thì cũng giống như việc cấp phát bộ nhớ vậy. Không có đất thì chúng ta không thể xây nhà. Có đất rồi thì mới có chỗ để xây nhà. Có bộ nhớ rồi thì mới nhập dữ liệu được.

Như các bạn đã biết thì khi dùng khai báo con trỏ trong lập trình c++, sẽ trỏ đến ô nhớ của biến khác nên không cần phải cấp phát bộ nhớ nữa, vì khi đó con trỏ đã có ô nhớ để nhập liệu cho nó rồi (đó chính là ô nhớ mà nó trỏ đến). Khi đó nó đã có nhà rồi (ở chung/ở ghép với đứa khác rồi) nên không cần phải mua đất nữa.

Sử dụng cấp phát bộ nhớ động trong c/c++

Sử dụng cấp phát và giải phóng bộ nhớ trong c

Trong lập trình c có 3 cách để tạo vùng nhớ động đó mà:

  1. malloc: Cú pháp sử dụng void* malloc (size_t size); trong đó size là kích thước cần cấp phát 
  2. calloc: Cú pháp sử dụng void* calloc (size_t num, size_t size); Cấp phát 1 vùng nhớ chứa đủ num phần tử, mỗi phần tử có kích thước là size , các giá trị của các phần tử sẽ được gán mặc định là 0.
  3. realloc: Sử dụng hàm void* realloc (void* ptr, size_t size); Có 2 trường hợp: 
    1. Đối với vùng nhớ chưa được khởi tạo thì realloc có chức năng tạo mới vùng nhớ cho nó.
    2. Đối với vùng nhớ đã có sẵn (đã được tạo từ trước rồi) thì realloc có chức năng gia tăng / giảm bớt ô nhớ trên vùng nhớ đó.

Sau đây là ví dụ minh hoạ về cách sử dụng cấp phát bộ nhớ động trong lập trình c:

//Khai báo sử dụng malloc
int* p3 = (int*)malloc(sizeof(int));
 
*p3 = 5;
 
cout <<"Gia tri p3 = "<<*p3<<endl;
 
//giải phóng vùng nhớ
free(p3);
Sử dụng mảng trong lập trình c bằng malloc:

//Sử dụng malloc
//Khai báo 1 mảng gồm 2 phần tử
int* p = (int*)malloc(3*sizeof(int));
 
//Gán giá trị cho các phần tử
p[0] = 2;
p[1] = 3;
 
cout <<"malloc: Cac phan tu cua mang la: "<<endl;
 
for(int i = 0; i<2; i++)
{
    cout <<p[i]<<endl;
}
Ví dụ sử dụng calloc trong lập trình c:

//Sử dụng calloc
 int* p1 = (int*)calloc(2, sizeof(int));
 
 //Gán các giá trị cho phần tử
 p1[0] = 6;
 p1[1] = 8;
 cout <<"calloc: Cac phan tu cua mang la: "<<endl;
 
 for(int i = 0; i<2; i++)
 {
     cout <<p1[i]<<endl;
 }
Ví dụ sử dụng realloc trong lập trình c:

int* p2 = (int*)realloc(0, 4*sizeof(int));
     //Gán các giá trị cho phần tử
    p2[0] = 5;
    p2[1] = 6;
    p2[2] = 8;
    p2[3] = 9;
    cout <<"realloc: Cac phan tu cua mang la: "<<endl;
 
    for(int i = 0; i<4; i++)
    {
        cout <<p2[i]<<endl;
    }

Tại sao cần giải phóng bộ nhớ ?

Vì bộ nhớ khi cấp phát cho con trỏ thuộc vùng nhớ HEAP(Là vùng nhớ CPU không quản lý, người lập trình phải tự quản lý vùng nhớ này) nên nếu như chúng ta không giải phóng thì những ô nhớ đó sẽ không bao giờ được giải phóng, do đó có thể đến một lúc nào đó sẽ xảy ra tình trạng tràn bộ nhớ (memory leak), dẫn đến máy bị đứng/ bị treo máy. Máy tính bây giờ cấu hình mạnh rồi nên tình trạng này chắc ít gặp. Tuy nhiên, bộ nhớ là có hạn, hãy tiết kiệm vì chính bạn, sử dụng xong thì nên giải phóng.
Vậy có nghĩa là khi giải phóng bộ nhớ thì giá trị của con trỏ đang có sẽ bị mất ? Điều này là không đúng. Nếu như ngay khi chúng ta khai báo giải phóng mà có 1 tiến trình khác chiếm hữu ô nhớ đó thì giá trị hiện tại trên ô nhớ đó sẽ không còn nữa, còn nếu như không có tiến trình nào chiếm hữu thì giá trị hiện tại trên ô nhớ đó vẫn còn.

Trong lập trình c để giải phóng vùng nhớ sử dụng chúng ta sử dụng hàm free(void*) như sau:

//Giải phóng bộ nhớ sau khi sử dụng
 free(p);
 free(p1);
 free(p2);

Sử dụng cấp phát và giải phóng bộ nhớ trong c++


Đối với lập trình c++ để cấp phát vùng nhớ chúng ta sẽ sử dụng từ khoá new và giải phóng sử dụng từ khoá delete với đoạn code minh hoạ như sau:

//Khai báo biến sử dụng vùng nhớ động
int* pr1 = new int;
 
//Gán giá trị
*pr1 = 8;
 
cout <<"Gia tri cua pr1 la: "<<*pr1<<endl;
 
//Giải phòng vùng nhớ
delete pr1;
Sử dụng cấp phát động cho mảng trong lập trình c++:

//Khai báo cấp phát vùng nhớ động trong c++
//Khai báo mảng chứa 2 phần tử
int *pr = new int[2];
 
//Gán giá trị cho các phần tử
pr[0] = 5;
pr[1] = 6;
 
//In các phần tử
cout <<"new: Cac phan tu cua mang la: "<<endl;
 
for(int i = 0; i<2; i++)
{
    cout <<pr[i]<<endl;
}
 
//Giải phóng vùng nhớ sau khi sử dụng
delete []pr;
Kết quả chạy chương trình như sau:

Hy vọng qua bài viết này sẽ giúp các bạn học lập trình c/c++ hiểu hơn về cơ chế lưu trữ trên bộ nhớ của máy tính cũng như cách thức cấp phát vùng nhớ động và giải phóng vùng nhớ trong lập trình c và lập trình c++. Bên cạnh đó bạn có thể bắt đầu học lập trình qua dự án cùng chuyên gia giàu kinh nghiệm của Stanford xem ngay: tại đây.

=============================
☎ STANFORD – ĐÀO TẠO VÀ PHÁT TRIỂN CÔNG NGHỆ
Hotline: 0963 723 236 - 0866 586 366
Website: https://stanford.com.vn
Facebook: http://bit.ly/2FN0TYb
Youtube: http://bit.ly/2TkKT7I


Tags: học c, học lập trình c, khoá c, khoá lập trình c, học c++, học lập trình c++, khoá lập trình c++, học c cơ bản, học c cho người mới