Có miễn phí (ptr) nơi ptr là bộ nhớ NULL không?


112

Về mặt lý thuyết, tôi có thể nói rằng

free(ptr);
free(ptr); 

là hỏng bộ nhớ vì chúng ta đang giải phóng bộ nhớ đã được giải phóng.

Nhưng nếu

free(ptr);
ptr=NULL;
free(ptr); 

Vì hệ điều hành sẽ hoạt động theo cách không xác định, tôi không thể nhận được một phân tích lý thuyết thực tế cho điều này về những gì đang xảy ra. Dù tôi đang làm gì, bộ nhớ này có bị hỏng hay không?

Giải phóng một con trỏ NULL có hợp lệ không?


1
không chắc chắn về tiêu chuẩn miễn phí C, nhưng trong C ++ xóa (NULL) là hoàn toàn hợp lệ, vì vậy tôi đoán miễn phí (NULL) cũng nên.
Priyank Bolia

14
@Pryank: delete NULLkhông hợp lệ trong C ++. xóa có thể được áp dụng cho các giá trị con trỏ null của kiểu cụ thể, nhưng không áp dụng cho NULL. delete (int*) NULLlà hợp pháp, nhưng không phải delete NULL.
AnT

vì vậy nó có nghĩa là nếu một con trỏ trỏ đến NULL miễn phí không thực hiện bất cứ điều gì. điều đó có nghĩa là !!!!!! mọi lúc trong mã của chúng ta nếu muốn giải phóng một bộ nhớ có thể chỉ cần thay thế một (ptr) miễn phí bằng ptr = NULL?
Vijay

3
Không. Nếu ptrtrỏ đến bộ nhớ và bạn không gọi freenó, thì bộ nhớ sẽ bị rò rỉ. Đặt nó NULLchỉ làm mất khả năng xử lý của bạn trên bộ nhớ và bị rò rỉ. Nếu điều này ptr xảy raNULL , gọi freelà một thao tác không có.
GManNickG

1
@benjamin: Hả? Điều gì khiến bạn kết luận rằng bạn có thể thay thế free(ptr)bằng ptr = NULL. Không ai nói bất cứ điều gì như thế.
AnT

Câu trả lời:


224

7.20.3.2 freeChức năng

Tóm tắc

#include <stdlib.h> 
void free(void *ptr); 

Sự miêu tả

Các freechức năng làm cho không gian được trỏ đến bởi ptrđể được deallocated, đó là, làm sẵn để phân bổ thêm. Nếu ptrlà một con trỏ null, không có hành động nào xảy ra.

Xem ISO-IEC 9899 .

Điều đó đang được nói, khi nhìn vào các cơ sở mã khác nhau trong tự nhiên, bạn sẽ nhận thấy đôi khi mọi người làm:

if (ptr)
  free(ptr);

Điều này là do một số thời gian chạy C (tôi chắc chắn nhớ đó là trường hợp trên PalmOS) sẽ bị lỗi khi giải phóng một NULLcon trỏ.

Nhưng ngày nay, tôi tin rằng có thể an toàn khi giả định free(NULL)là một nop theo hướng dẫn của tiêu chuẩn.


29
Không, ptr = NULL là không có cách nào một sự thay thế miễn phí (ptr), cả hai đều hoàn toàn khác nhau
Prasoon Saurav

7
NO, nó có nghĩa là free(ptr)nơi ptrlà null không có tác dụng phụ. Nhưng trong mọi trường hợp, mỗi bộ nhớ phân bổ sử dụng malloc()hoặc calloc()phải trả tự do sau đó sử dụngfree()
Gregory Pakosz

4
ptr = NULL đảm bảo rằng ngay cả khi bạn vô tình gọi miễn phí (ptr) chương trình của bạn sẽ không mặc định.
Prasoon Saurav

2
Xin lưu ý rằng mặc dù tiêu chuẩn C nói rằng đó là không chọn, nhưng điều đó không có nghĩa là mọi thư viện C đều xử lý nó như vậy. Tôi đã thấy các sự cố miễn phí (NULL), vì vậy tốt nhất bạn nên tránh gọi miễn phí ngay từ đầu.
Derick

6
@WereWolfBoy ông có nghĩa là tránh free(NULL)bằng cách kiểm tra con trỏ chống lại NULLtrước khi gọifree()
Gregory Pakosz

22

Tất cả các phiên bản tuân thủ tiêu chuẩn của thư viện C đều coi miễn phí (NULL) là không cần chọn.

Điều đó nói rằng, tại một thời điểm có một số phiên bản miễn phí sẽ bị lỗi khi miễn phí (NULL), đó là lý do tại sao bạn có thể thấy một số kỹ thuật lập trình phòng thủ được khuyến nghị:

if (ptr != NULL)
    free(ptr);

8
-1 [cần dẫn nguồn]. Thay đổi kiểu mã vì một số lý thuyết về việc triển khai tin đồn cổ xưa là một ý tưởng tồi.
Tomas

41
@Tomas - Tôi không bao giờ khuyên bạn nên thay đổi kiểu, tôi chỉ giải thích tại sao bạn vẫn có thể thấy đề xuất này trong một số kiểu.
R Samuel Klatchko 21/12/09

5
@Tomas 3BSD ( winehq.org/pipermail/wine-patches/2006-October/031544.html ) và PalmOS cho cả hai (mặt thứ hai cho cả hai).
Douglas Leeder

7
@Tomas: vấn đề là ở những thứ như Unix phiên bản 7. Khi tôi đang học, miễn phí (xyz) trong đó xyz == NULL là công thức gây ra thảm họa tức thì trên máy mà tôi đã học (ICL Perq chạy PNX, dựa trên Unix phiên bản 7 với một số tính năng bổ sung của Hệ thống III). Nhưng tôi đã không viết mã theo cách đó trong một thời gian dài.
Jonathan Leffler

2
Tai nạn Netware trên NULL miễn phí-ing quá ... (chỉ cần sửa lỗi một vụ tai nạn trên nó ...)
Calmarius

13

Nếu ptr là NULL, không có thao tác nào được thực hiện.

cho biết tài liệu.


ý bạn là taht miễn phí sẽ không có tác dụng gì?
Vijay

2
benjamin, đó chính xác là ý nghĩa của nó. Bạn sẽ mong đợi nó thực hiện điều gì nếu nó biết về tính vô hiệu của đối số?
Michael Krelin - hacker

12

Tôi nhớ đã làm việc trên PalmOS nơi free(NULL)bị lỗi.


4
Thật thú vị - điều đó khiến nền tảng thứ hai (sau 3BSD) gặp sự cố.
Douglas Leeder

2
Nếu tôi nhớ không lầm, trên Palm Thư viện tiêu chuẩn C không tồn tại. Thay vào đó, có một tệp tiêu đề chủ yếu không được hỗ trợ ánh xạ các lệnh gọi thư viện tiêu chuẩn thông qua Palm OS SDK. Rất nhiều thứ hành động bất ngờ. Đập vào NULLlà một trong những khác biệt lớn khi chạy của hộp công cụ Palm so với thư viện tiêu chuẩn.
Steven Fisher

8
free(ptr);
ptr=NULL;
free(ptr);/*This is perfectly safe */

Bạn có thể xóa một con trỏ NULL một cách an toàn. Không có thao tác nào được thực hiện trong trường hợp đó, nói cách khác free () không thực hiện gì trên con trỏ NULL.


8

Cách sử dụng được đề xuất:

free(ptr);
ptr = NULL;

Xem:

man free

     The free() function deallocates the memory allocation pointed to by ptr.
     If ptr is a NULL pointer, no operation is performed.

Khi bạn đặt con trỏ thành NULLsau khi free()bạn có thể gọi free()lại nó và sẽ không có thao tác nào được thực hiện.


3
Điều đó cũng giúp phát hiện các giá trị mặc định bằng trình gỡ lỗi. Rõ ràng là segfault tại p-> do () với p = 0 là ai đó đang sử dụng con trỏ giải phóng. Ít rõ ràng hơn khi bạn thấy p = 0xbfade12 trong trình gỡ lỗi :)
neuro

6

free(NULL)hoàn toàn hợp pháp trong C cũng như delete (void *)0delete[] (void *)0hợp pháp trong C ++.

BTW, giải phóng bộ nhớ hai lần thường gây ra một số loại lỗi thời gian chạy, vì vậy nó không làm hỏng bất cứ điều gì.


2
delete 0không hợp pháp trong C ++. deleteyêu cầu rõ ràng một biểu thức của kiểu con trỏ. Việc áp dụng deletecho giá trị con trỏ null đã nhập là hợp pháp , nhưng không áp dụng cho 0(và không cho NULL).
AnT

1
Bạn cũng không thể xóa void*: P Nó nên chạy (các) hàm hủy nào?
GManNickG

1
@GMan: Bạn có thể xóa void *miễn là nó là con trỏ null.
AnT 21/12/09

Được rồi. Tôi quên rằng chúng tôi chỉ giải quyết cụ thể với null.
GManNickG

thường không làm hỏng bất cứ điều gì, nhưng không được đảm bảo. ASLR làm cho điều này khá khó xảy ra, nhưng vẫn không phải là không thể: buf1=malloc(X); free(buf1);buf2=malloc(X);free(buf1); - ở đây nếu bạn không may mắn, buf2 có địa chỉ chính xác giống như buf1 và bạn đã vô tình giải phóng buf1 hai lần, vì vậy trong lần giải phóng buf1 thứ hai, bạn đã thực sự giải phóng buf2 một cách âm thầm, không tính tiền bất kỳ lỗi (nguyên nhân) nào / sự cố / bất cứ điều gì. (nhưng bạn vẫn có thể có được một lần sau khi vụ tai nạn bạn cố gắng sử dụng buf2 - và kịch bản này là rất khó xảy ra nếu bạn đang chạy trên ASLR)
hanshenrik

3

free(ptr)là lưu trong C nếu ptrNULL, tuy nhiên, điều mà hầu hết mọi người không biết là NULLkhông cần phải bằng 0. Tôi có một ví dụ cũ rất hay: Trên C64, trên địa chỉ 0, có một IO-Port. Nếu bạn đã viết một chương trình trong C truy cập vào cổng này, bạn cần một con trỏ có giá trị bằng 0. Thư viện C tương ứng sẽ phải phân biệt giữa 0 và NULLsau đó.

Trân trọng.


Thực tế thú vị, làm tôi ngạc nhiên. Khiến tôi cảm thấy bị bắt buộc phải thực hiện một chuyến khám phá các câu hỏi / câu trả lời của con trỏ NULL.
động vật chân đốt

0

không tham nhũng bộ nhớ, nhưng hành vi phụ thuộc vào việc thực hiện. Theo tiêu chuẩn, nó phải là một mã hợp pháp.


-3

ptr đang trỏ đến một số vị trí bộ nhớ, giả sử 0x100.

Khi bạn giải phóng (ptr), về cơ bản, bạn đang cho phép 0x100 được sử dụng bởi trình quản lý bộ nhớ để sử dụng cho hoạt động hoặc quy trình khác và nói một cách đơn giản đó là việc phân bổ tài nguyên.

Khi bạn thực hiện ptr = NULL, bạn đang làm cho ptr trỏ đến vị trí mới (đừng lo lắng về NULL là gì). Làm điều này bạn đã mất dấu dữ liệu bộ nhớ 0x100. Đây là hiện tượng rò rỉ bộ nhớ.

Vì vậy, không nên sử dụng ptr = NULL trên một ptr hợp lệ.

Thay vào đó, bạn có thể thực hiện một số kiểm tra an toàn bằng cách sử dụng:

if (ptr! = NULL) {free (ptr);}

Khi bạn giải phóng (ptr) trong đó ptr đã trỏ tới NULL, nó sẽ không thực hiện thao tác nào.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.