30/09/2018, 16:59

Cấp phát bộ nhớ động trong C : Malloc hay Calloc

Cấp phát bộ nhớ động trong C : Malloc vs Calloc

Để cấp phát bộ nhớ động trong C, chúng ta có 2 cách:

  1. void* malloc (size_t size);
  2. void* calloc (size_t num, size_t size);

So sánh

###Sử dụng

  • Khi sử dụng malloc phải tính toán kích thước vùng nhớ cần cấp phát trước rồi truyền vào cho malloc
  • Khi sử dụng calloc chỉ cần truyền vào số phần tử và kích thước 1 phần tử, thì calloc sẽ tự động tính toán và cấp phát vùng nhớ cần thiết

Ví dụ: Cấp phát mảng 10 phần tử kiểu int:

int *a = (int *) malloc( 10 * sizeof( int ));
int *b = (int *) calloc( 10, sizeof( int ));

Hiệu suất / Perfomance

malloc nhanh hơn so với calloc. Lý do là calloc ngoài việc có nhiệm vụ cấp phát vùng nhớ như malloc, nó còn phải gán giá trị cho tất cả các phần tử của vùng nhớ vừa cấp phát = 0

int *a = (int *) calloc(10, sizeof( int ));
tương đương với

memset(b, 0, 10 * sizeof(int));

Sự an toàn

Sử dụng calloc an toàn hơn malloc vì sau khi khởi tạo vùng nhớ thì calloc sẽ khởi tạo vùng nhớ cấp phát = 0, còn vùng nhớ do malloc cấp phát vẫn chứa giá trị rác nên sẽ dễ gây ra lỗi nếu truy xuất tới vùn nhớ này trước khi gán cho nó một giá trị xác định.

Nguyễn Minh Dũng viết 19:05 ngày 30/09/2018

Sự an toàn

] Sử dụng calloc an toàn hơn malloc vì sau khi khởi tạo vùng nhớ thì calloc sẽ khởi tạo vùng nhớ cấp phát = 0, còn vùng nhớ do malloc cấp phát vẫn chứa giá trị rác nên sẽ dễ gây ra lỗi nếu truy xuất tới vùn nhớ này trước khi gán cho nó một giá trị xác định.

Bài viết hay, nhưng không đồng ý với ý này. Nên sửa lại là chọn malloc hay calloc là do mục tiêu sử dụng. Nếu mình không quan tâm đến giá mặc định của vùng nhớ được cấp thì dùng malloc còn nếu muốn tất cả là 0 thì dùng calloc.

Như vậy hợp lý hơn, đưa lựa chọn vào tay người code. Còn nếu viết về sự an toàn thì sẽ đẩy người đọc về phía chọn calloc mặc dù không phải lúc nào cũng cần thiết.


Góp ý một tí về trình bày, tại sao @Dung_Nguyen lại để thêm một dấu ] ở đầu một số dòng vậy?

Trịnh Minh Cường viết 19:12 ngày 30/09/2018

em toàn dùng new và delete , dùng lai luôn của C++

Coulson viết 19:10 ngày 30/09/2018

Thanks bác Đạt. em mới sửa lại title.
Còn dấu [ là do lúc em replace all trong markdown nó replace lộn chút

Coulson viết 19:00 ngày 30/09/2018

hôm trước phỏng vấn VNG nó còn hỏi sự khác nhau giữa malloc với new nữa mà không trả lời được nên mới phải về tìm hiểu lại.

Trịnh Minh Cường viết 19:14 ngày 30/09/2018

Cái này em cũng chưa biết tại em thấy new thì cú pháp nó gọn, ngắn hơn 2 thằng kia nên dùng lai luôn

Tên Gì viết 19:15 ngày 30/09/2018

New chỉ có trong C++ còn cái này là C mà new phải đi vs realloc chứ

Coulson viết 19:05 ngày 30/09/2018

realloc dùng để thay đổi/ xóa vùng nhớ đã được cấp phát còn malloc và calloc dùng để cấp phát vùng nhớ mới.

Chi Ngo viết 19:08 ngày 30/09/2018

malloc nhanh hơn so với calloc. Lý do là calloc ngoài việc có nhiệm vụ cấp phát vùng nhớ như malloc, nó còn phải gán giá trị cho tất cả các phần tử của vùng nhớ vừa cấp phát = 0

Tại sao không phải vì calloc phải làm 10 lần công việc của malloc nhỉ? Bạn giải thích cho mình với?

Coulson viết 19:00 ngày 30/09/2018

int *a = (int *) calloc(10, sizeof( int ));
tương đương với

int *b = (int *) malloc( 10 * sizeof( int )); 
memset(b, 0, 10 * sizeof(int));

Như bạn thấy thì calloc làm 2 bước:

  1. Cấp phát bộ nhớ giống như malloc
  2. Khởi tạo giá trị vùng nhớ = 0 tương tự như lúc sử dụng hàm memset

Nên là nó không thể gấp 10 lần được.
Vậy tại sao bạn lại nghĩ là calloc làm 10 lần công việc của malloc?

Chi Ngo viết 19:13 ngày 30/09/2018

Như bạn thấy thì calloc làm 2 bước:1. Cấp phát bộ nhớ giống như malloc2. Khởi tạo giá trị vùng nhớ = 0 tương tự như lúc sử dụng hàm memset

Thế mình lấy một ví dụ đơn giản như thế này nhé:
Mình muốn tính tổng từ 1 đến 10.
Mình sẽ có hai hàm như sau:

int tonghaso(int a, int b) {
     return a + b;
}

int tong(int start, int end) {
    int s  = 0;
    for( int i = start;i <=end;i++) {
          s+=i;
    }
    return s;
}

Như vậy, nếu mình tính tổng từ 1 đến 10 thì mình cần dùng 9 lần hàm tonghaiso và 1 lần hàm tong. Nhưng ở đây nếu không tính đến việc gọi hàm mà chỉ tính đến số phép tính để thực hiện được yêu cầu thì rõ ràng là như nhau đúng không (9 phép tính)?
Không phải vì gọi hàm một lần mà nhanh hơn so với gọi 2 hàm khác như bạn đưa ra. Nhỡ đâu ở trong cái phần một hàm ấy, người ta làm rất nhiều việc thì sao? Mà về bản chất ở đây là việc cấp phát bộ nhớ, có thể hình dung bạn có 1 cái bánh mỳ (ở BigC) chẳng hạm, một cái bạn chia thành 10 phần thì bạn phải cắt 9 lần, trong khi cái còn lại thì bạn không phải cắt mà chỉ đánh dấu lên nó 10 vách thôi (hi vọng việc đánh dấu sẽ nhanh hơn việc cắt).

Minh Hoàng viết 19:03 ngày 30/09/2018

calloc is a tiny bit slower than malloc because of the extra step of initializing the memory region allocated. However, in practice the difference in speed is very small and can be ignored.
http://www.diffen.com/difference/Calloc_vs_Malloc

Theo mình thì nên sử dụng calloc vì không nên để giá trị trong biến mà mình không kiểm soát. Tuy nhiên cũng tùy mục đích sử dụng.

Coulson viết 19:11 ngày 30/09/2018

Không phải vì gọi hàm một lần mà nhanh hơn so với gọi 2 hàm khác như bạn đưa ra. Nhỡ đâu ở trong cái phần một hàm ấy, người ta làm rất nhiều việc thì sao? Mà về bản chất ở đây là việc cấp phát bộ nhớ, có thể hình dung bạn có 1 cái bánh mỳ (ở BigC) chẳng hạm, một cái bạn chia thành 10 phần thì bạn phải cắt 9 lần, trong khi cái còn lại thì bạn không phải cắt mà chỉ đánh dấu lên nó 10 vách thôi (hi vọng việc đánh dấu sẽ nhanh hơn việc cắt).

  1. Như mình đã nói, calloc sẽ chậm hơn malloc vì nó phải set bộ nhớ = 0.
  2. Việc chia bánh mỳ như bạn nói mình không thấy nó tương tự như việc cấp phát bộ nhớ.
    Nếu như bạn muốn lấy 1/2 cái bánh mỳ:
  • calloc tương tự như việc cắt 1/2 cái bánh mì và trét bơ lên đó.
  • malloc tương tự như việc chỉ mới chia đôi cái bánh mì và lấy 1/2. bạn phải làm thêm bước trét bơ nữa.
Hưng Arsenal viết 19:05 ngày 30/09/2018

Bạn có thể đề cập đến hàm realloc được không?

Đổi Tên viết 19:07 ngày 30/09/2018

anh có thể cho em hỏi là tại sao phải cấp phát cho con trỏ k? nếu k cấp phát thì ảnh hưởng j ?

Thu Thuỷ viết 19:02 ngày 30/09/2018

con trỏ là biến đặc biệt, chỉ trỏ tùm lum, có thể lưu trữ nhiều giá trị (mảng), nên mỗi giá trị phải có 1 cái lổ chứa ==> Phải cấp phát bộ nhớ

Người bí ẩn viết 19:10 ngày 30/09/2018

realloc dùng để thay đổi/ xóa vùng nhớ đã được cấp phát

Theo mình biết thì đó chỉ là 1 trong 2 công dụng của realloc thôi mà?
Ngoài tác dụng thay đổi/xóa vùng nhớ đã được cấp phát thì realloc còn có thể Tạo mới vùng nhớ đối với những vùng nhớ chưa được khởi tạo mà ?
VD: (cấp phát bộ nhớ cho 2 con trỏ a và b)

int *a, *b;
a = (int *)realloc(0, sizeof(int *));
b = (int *)realloc(0, sizeof(int *));

P/S: Sao bạn không nói đến giải phóng con trỏ free (hay delete) luôn ? (vì mình thấy nó có liên quan đến chủ đề Topic này)

Nguyen Sy Phu viết 19:11 ngày 30/09/2018

Cho em hỏi (int *) là ép kiểu như thế nào vậy ạ?

Người bí ẩn viết 19:02 ngày 30/09/2018

Cho em hỏi (int *) là ép kiểu như thế nào vậy ạ?

2 hàm malloc và calloc đều có kiểu void *, mà void * thì bạn phải ép kiểu cho nó đúng với kiểu dữ liệu của con trỏ

Lê Văn Trọng viết 19:02 ngày 30/09/2018

Cho em hỏi nếu mình khai báo như thế này : int* x = (int *)malloc(sizeof(int)); với một biến kiểu int có kích thước 4 bytes thì nó chỉ sử dụng có 4 bytes bộ nhớ đúng không ạ?

Thân Hoàng viết 19:02 ngày 30/09/2018

Mọi người cho em hỏi về hàm malloc cụ thể của code này:

  1. main()
  2. {
  3. char *ten;
  4. ten = malloc(1);
  5. gets(ten);
  6. }

malloc(1) được cấp phát 1 byte bộ nhớ, kiểu char có kích thước 1 byte. Nhưng em có thể nhập được rất nhiều kí tự: khoảng hơn 200 kí tự. Ai giải thích giúp em với

Bài liên quan
0