Câu trả lời:
Theo các thông số kỹ thuật, malloc (0) sẽ trả về "một con trỏ null hoặc một con trỏ duy nhất có thể được chuyển thành công đến free ()".
Về cơ bản, điều này cho phép bạn không phân bổ gì, nhưng vẫn chuyển biến "artist" cho một cuộc gọi đến free () mà không cần lo lắng. Đối với các mục đích thực tế, nó khá giống với việc làm:
artist = NULL;
Tiêu chuẩn C (C17 7.22.3 / 1) cho biết:
Nếu kích thước của không gian được yêu cầu bằng 0, hành vi được thực hiện được xác định: con trỏ null được trả về hoặc hành vi giống như kích thước là một số giá trị khác không, ngoại trừ con trỏ trả về sẽ không được sử dụng để truy cập một đối tượng.
Vì vậy, malloc(0)
có thể trả về NULL
hoặc một con trỏ hợp lệ có thể không được tham chiếu . Trong cả hai trường hợp, hoàn toàn hợp lệ để gọi free()
nó.
Tôi không thực sự nghĩ rằng nó malloc(0)
có nhiều công dụng, ngoại trừ những trường hợp malloc(n)
được gọi trong một vòng lặp chẳng hạn, và n
có thể bằng không.
Nhìn vào đoạn mã trong liên kết, tôi tin rằng tác giả đã có hai quan niệm sai lầm:
malloc(0)
luôn luôn trả về một con trỏ hợp lệ vàfree(0)
là xấu.Vì vậy, ông đảm bảo rằng artist
và các biến khác luôn có một số giá trị "hợp lệ" trong chúng. Các bình luận nói càng nhiều: // these must always point at malloc'd data
.
malloc(0)
trả về một con trỏ hợp lệ, thì malloc()
trả về luôn NULL
có nghĩa là "thất bại" và 0
không phải là trường hợp đặc biệt nữa, điều này nhất quán hơn.
malloc
không lấy được bộ nhớ được xác định bởi việc triển khai, một triển khai có thể đơn giản xác định rằng phân bổ kích thước-0 luôn không thỏa mãn ( ENOMEM
) và bây giờ malloc(0)
trả về 0 (với errno==ENOMEM
) là nhất quán. :-)
realloc
trả lại một con trỏ malloc(0)
không? Bạn có thể realloc((char*)NULL)
?
hành vi malloc (0) là triển khai cụ thể. Thư viện có thể trả về NULL hoặc có hành vi malloc thông thường, không được cấp phát bộ nhớ. Bất cứ điều gì nó làm, nó phải được ghi lại ở đâu đó.
Thông thường, nó trả về một con trỏ hợp lệ và duy nhất nhưng KHÔNG được tham chiếu. Cũng lưu ý rằng nó CÓ THỂ sử dụng bộ nhớ mặc dù nó không thực sự cấp phát bất cứ thứ gì.
Có thể phân bổ lại một con trỏ malloc (0) không null.
Mặc dù vậy, có một nguyên văn malloc (0) không được sử dụng nhiều. Nó chủ yếu được sử dụng khi phân bổ động là byte 0 và bạn không quan tâm đến việc xác thực nó.
malloc()
phải giữ "thông tin quản lý" ở đâu đó (ví dụ như kích thước của khối được phân bổ và dữ liệu phụ trợ khác). Vì vậy, nếu malloc(0)
không trả về NULL
, nó sẽ sử dụng bộ nhớ để lưu trữ thông tin đó, và nếu không phải là free()
d, sẽ tạo thành rò rỉ bộ nhớ.
malloc()
sẽ trả lại hoặc trả về NULL
.
malloc(0)
. Tuy nhiên, trong cùng việc triển khai thư viện C chuẩn, realloc(ptr, 0)
giải phóng ptr
và trả về NULL.
Có một câu trả lời ở nơi khác trên trang này bắt đầu "malloc (0) sẽ trả về một địa chỉ bộ nhớ hợp lệ và phạm vi của nó sẽ phụ thuộc vào loại con trỏ đang được cấp phát bộ nhớ". Tuyên bố này không chính xác (Tôi không có đủ uy tín để bình luận trực tiếp về câu trả lời đó, vì vậy không thể đặt bình luận này trực tiếp dưới đó).
Thực hiện malloc (0) sẽ không tự động cấp phát bộ nhớ có kích thước chính xác. Hàm malloc không biết bạn đang truyền kết quả cho nó. Hàm malloc hoàn toàn dựa vào số kích thước mà bạn cung cấp làm đối số của nó. Bạn cần thực hiện malloc (sizeof (int)) để có đủ dung lượng lưu trữ để giữ một int, chẳng hạn như 0.
malloc(0)
không có ý nghĩa gì đối với tôi, trừ khi mã dựa trên hành vi cụ thể để triển khai. Nếu mã có nghĩa là di động, thì nó phải tính đến thực tế là trả về NULL malloc(0)
không phải là một thất bại. Vì vậy, tại sao không chỉ định NULL cho artist
dù sao, vì đó là một kết quả thành công hợp lệ và ít mã hơn, và sẽ không khiến các lập trình viên bảo trì của bạn mất thời gian tìm ra nó?
malloc(SOME_CONSTANT_THAT_MIGHT_BE_ZERO)
hoặc malloc(some_variable_which_might_be_zero)
có lẽ có thể có công dụng của chúng, mặc dù một lần nữa bạn phải hết sức cẩn thận để không coi trả về NULL là lỗi nếu giá trị là 0, nhưng kích thước 0 được cho là OK.
Có rất nhiều câu trả lời đúng một nửa ở đây, vì vậy đây là sự thật khó. Trang man cho malloc()
nói:
Nếu kích thước là 0, thì hàm malloc () trả về giá trị NULL hoặc một giá trị con trỏ duy nhất mà sau này có thể được chuyển thành công tới free ().
Điều đó có nghĩa là, hoàn toàn không có gì đảm bảo rằng kết quả của malloc(0)
là duy nhất hoặc không phải là NULL. Đảm bảo duy nhất được cung cấp bởi định nghĩa của free()
, một lần nữa, đây là những gì trang người dùng nói:
Nếu ptr là NULL, không có thao tác nào được thực hiện.
Vì vậy, bất cứ điều gì malloc(0)
trả lại, nó có thể được chuyển đến một cách an toàn free()
. Nhưng một NULL
con trỏ cũng vậy.
Do đó, viết artist = malloc(0);
không có cách nào tốt hơn viết artist = NULL;
malloc(0)
có thể trả về, chẳng hạn, 0x1, và free()
có thể kiểm tra trường hợp đặc biệt của 0x1 giống như đối với 0x0.
NULL
, hoặc một con trỏ duy nhất". thay vào đó là 'con trỏ null hoặc con trỏ tới không gian được cấp phát ". Không có yêu cầu duy nhất . OTOH, việc trả về giá trị đặc biệt không phải là duy nhất có thể làm gián đoạn mã tính trên các giá trị duy nhất. Có lẽ là một câu hỏi dạng chữ hoa cho SO.
man
cũng có thể ghi lại biểu mẫu do triển khai xác định được sử dụng trong * nix. Trong trường hợp này không, nhưng nó vẫn không phải là một nguồn kinh điển cho C. chung
Tại sao bạn không nên làm điều này ...
Vì giá trị trả về của malloc phụ thuộc vào việc triển khai, bạn có thể lấy lại con trỏ NULL hoặc một số địa chỉ khác. Điều này có thể dẫn đến việc tràn bộ đệm heap nếu mã xử lý lỗi không kiểm tra cả kích thước và giá trị trả về, dẫn đến các vấn đề ổn định (sự cố) hoặc các vấn đề bảo mật thậm chí tồi tệ hơn.
Hãy xem xét ví dụ này, trong đó việc truy cập thêm vào bộ nhớ thông qua địa chỉ trả về sẽ làm hỏng kích thước heap iff bằng 0 và việc triển khai trả về giá trị không phải NULL.
size_t size;
/* Initialize size, possibly by user-controlled input */
int *list = (int *)malloc(size);
if (list == NULL) {
/* Handle allocation error */
}
else {
/* Continue processing list */
}
Xem trang Mã hóa Bảo mật này từ Tiêu chuẩn Mã hóa CERT mà tôi đã lấy ví dụ ở trên để đọc thêm.
Phải thừa nhận rằng tôi chưa bao giờ thấy điều này trước đây, đây là lần đầu tiên tôi thấy cú pháp này, có thể nói, một trường hợp cổ điển của hàm quá mức cần thiết. Kết hợp với câu trả lời của Reed, tôi muốn chỉ ra rằng có một thứ tương tự, xuất hiện giống như một hàm quá tải realloc
:
realloc(foo, size);
,. Khi bạn chuyển một con trỏ không phải NULL và kích thước bằng 0 vào realloc, realloc hoạt động như thể bạn đã gọi là free (…)realloc(foo, size);
. Khi bạn truyền vào một con trỏ NULL và kích thước là khác 0, realloc hoạt động như thể bạn đã gọi malloc (…)Hy vọng điều này sẽ giúp, Trân trọng, Tom.
malloc (0) sẽ trả về NULL hoặc một con trỏ hợp lệ có thể được chuyển đúng sang miễn phí. Và mặc dù có vẻ như bộ nhớ mà nó trỏ đến là vô dụng hoặc nó không thể được ghi vào hoặc đọc từ đó, điều đó không phải lúc nào cũng đúng. :)
int *i = malloc(0);
*i = 100;
printf("%d", *i);
Chúng tôi mong đợi một lỗi phân đoạn ở đây, nhưng đáng ngạc nhiên, điều này in ra 100! Đó là bởi vì malloc thực sự yêu cầu một lượng lớn bộ nhớ khi chúng ta gọi malloc lần đầu tiên. Mọi cuộc gọi tới malloc sau đó, đều sử dụng bộ nhớ từ đoạn lớn đó. Chỉ sau khi phần lớn đó kết thúc, bộ nhớ mới được yêu cầu.
Sử dụng malloc (0): nếu bạn ở trong trường hợp bạn muốn các lệnh gọi malloc tiếp theo nhanh hơn, thì việc gọi malloc (0) sẽ thực hiện điều đó cho bạn (ngoại trừ trường hợp cạnh).
*i
có thể không gặp sự cố trong trường hợp của bạn, nhưng đó là hành vi không xác định. Hãy coi chừng những con quỷ mũi!
malloc(0)
điều đó không được đề cập. Trên những triển khai mà nó trả về giá trị không phải NULL, đặc biệt là trong bản dựng GỠ LỖI, nó có khả năng phân bổ NHIỀU HƠN mức bạn yêu cầu và cung cấp cho bạn con trỏ để chỉ qua tiêu đề nội bộ của nó. Điều này cho phép bạn cảm nhận được việc sử dụng bộ nhớ thực tế nếu bạn có được điều này trước và sau một loạt phân bổ. ví dụ: void* before = malloc(0); ... void* after = malloc(0); long long total = after - before;
hoặc một số như vậy.
malloc(0)
. Bạn có thể vui lòng cho biết bạn cũng đang tham khảo chương nào không? Cung cấp một báo giá chính xác cũng sẽ tốt.
Trong Windows:
void *p = malloc(0);
sẽ cấp phát một bộ đệm có độ dài bằng không trên heap cục bộ. Con trỏ được trả về là một con trỏ heap hợp lệ.malloc
cuối cùng là các cuộc gọi HeapAlloc
bằng cách sử dụng đống thời gian chạy C mặc định mà sau đó sẽ gọi RtlAllocateHeap
, v.v.free(p);
sử dụng HeapFree
để giải phóng bộ đệm có độ dài 0 trên heap. Không giải phóng nó sẽ dẫn đến rò rỉ bộ nhớ.Nó thực sự khá hữu ích và (rõ ràng là IMHO), hành vi được phép trả về một con trỏ NULL đã bị hỏng. Một con trỏ động không chỉ hữu ích cho những gì nó trỏ đến, mà còn thực tế là địa chỉ của nó là duy nhất. Trả về NULL loại bỏ thuộc tính thứ hai. Tất cả các chương trình mallocs nhúng tôi (thực tế là khá thường xuyên) đều có hiện tượng này.
Không chắc chắn, theo một số mã nguồn malloc ngẫu nhiên mà tôi tìm thấy, đầu vào 0 dẫn đến giá trị trả về là NULL. Vì vậy, đó là một cách điên rồ khi đặt con trỏ nghệ sĩ thành NULL.
http://www.raspberryginger.com/jbailey/minix/html/lib_2ansi_2malloc_8c-source.html
Đây là phân tích sau khi chạy với công cụ kiểm tra bộ nhớ valgrind.
==16740== Command: ./malloc0
==16740==
p1 = 0x5204040
==16740==
==16740== HEAP SUMMARY:
==16740== in use at exit: 0 bytes in 0 blocks
==16740== total heap usage: 2 allocs, 2 frees, 1,024 bytes allocated
==16740==
==16740== All heap blocks were freed -- no leaks are possible
và đây là mã mẫu của tôi:
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main()
{
//int i;
char *p1;
p1 = (char *)malloc(0);
printf("p1 = %p\n", p1);
free(p1);
return 0;
}
Theo mặc định 1024 byte được cấp phát. Nếu tôi tăng kích thước của malloc, các byte được phân bổ sẽ tăng thêm 1025, v.v.
Theo câu trả lời của Reed Copsey và trang người đàn ông của malloc, tôi đã viết một số ví dụ để kiểm tra. Và tôi phát hiện ra rằng malloc (0) sẽ luôn cung cấp cho nó một giá trị duy nhất. Xem ví dụ của tôi:
char *ptr;
if( (ptr = (char *) malloc(0)) == NULL )
puts("Got a null pointer");
else
puts("Got a valid pointer");
Kết quả đầu ra sẽ là "Có một con trỏ hợp lệ", có nghĩa ptr
là không rỗng.
malloc(0)
sẽ trả về một địa chỉ bộ nhớ hợp lệ và phạm vi của nó sẽ phụ thuộc vào loại con trỏ đang được cấp phát bộ nhớ. Ngoài ra, bạn có thể gán giá trị cho vùng bộ nhớ nhưng điều này phải nằm trong phạm vi với loại con trỏ đang được sử dụng. Bạn cũng có thể giải phóng bộ nhớ được cấp phát. Tôi sẽ giải thích điều này bằng một ví dụ:
int *p=NULL;
p=(int *)malloc(0);
free(p);
Đoạn mã trên sẽ hoạt động tốt trong gcc
trình biên dịch trên máy Linux. Nếu bạn có trình biên dịch 32 bit thì bạn có thể cung cấp các giá trị trong phạm vi số nguyên, tức là -2147483648 đến 2147483647. Tương tự cũng áp dụng cho các ký tự. Xin lưu ý rằng nếu kiểu con trỏ được khai báo bị thay đổi thì phạm vi giá trị sẽ thay đổi bất kể kiểu gõ nào malloc
, tức là
unsigned char *p=NULL;
p =(char *)malloc(0);
free(p);
p
sẽ nhận giá trị từ 0 đến 255 của char vì nó được khai báo là int không dấu.
malloc()
không biết gì về chất đúc (thực tế là hoàn toàn siêu lỏng trong C). Tham chiếu đến giá trị trả về của malloc(0)
sẽ gọi hành vi không xác định.
Chỉ để sửa một ấn tượng sai ở đây:
artist = (char *) malloc(0);
sẽ không bao giờ trở lại NULL
; nó không giống như artist = NULL;
. Viết một chương trình đơn giản và so sánh artist
với NULL
. if (artist == NULL)
là sai và if (artist)
là đúng.