2011-08-16 42 views
20

Câu hỏi đơn giản về hàm realloc trong C: Nếu tôi sử dụng realloc để thu nhỏ khối bộ nhớ mà con trỏ trỏ đến, bộ nhớ "thêm" có được giải phóng không? Hay nó cần phải được giải phóng bằng tay bằng cách nào đó?Sử dụng realloc để thu hẹp bộ nhớ phân bổ

Ví dụ, nếu tôi làm

int *myPointer = malloc(100*sizeof(int)); 
myPointer = realloc(myPointer,50*sizeof(int)); 
free(myPointer); 

Tôi có một rò rỉ bộ nhớ?

+1

Nói đúng là có rò rỉ bộ nhớ, vì bạn không ghi lại kết quả của 'realloc' và do đó bạn không thể giải phóng nó. Nhưng như câu trả lời của R .. cho thấy, bạn có thể đã may mắn về một chi tiết thực hiện. –

+1

Rất tiếc, bạn đã đúng. Tôi đã cố sửa nó. Làm thế nào về bây giờ? –

+6

Mã mới vẫn rò rỉ phân bổ ban đầu nếu 'realloc' không thành công. Tôi hy vọng hầu hết các triển khai sẽ không bao giờ thất bại trong việc thu nhỏ một khối, nhưng nó được cho phép. Cách chính xác để gọi realloc, cho dù đang phát triển hay thu hẹp khối, là 'void * tmp = realloc (myPointer, 50 * sizeof (int)); if (! tmp) {/ * xử lý lỗi bằng cách nào đó. myPointer vẫn trỏ đến khối cũ, vẫn được cấp phát * /} myPointer = tmp; '. –

Trả lời

16

Không, bạn sẽ không bị rò rỉ bộ nhớ. realloc sẽ chỉ đánh dấu phần còn lại là "có sẵn" cho các hoạt động trong tương lai malloc.

Nhưng bạn vẫn phải freemyPointer sau này. Ngoài ra, nếu bạn sử dụng 0 làm kích thước trong realloc, nó sẽ có tác dụng tương tự như freetrên một số triển khai. Như Steve Jessop và R .. cho biết trong các ý kiến, bạn không nên dựa vào nó.

+3

"nếu bạn sử dụng 0 làm kích thước trong realloc, nó sẽ có tác dụng tương tự như miễn phí." - có thể đúng trong quá trình triển khai của bạn, nhưng không được bảo đảm. Nếu 'realloc' trả về một con trỏ null từ đầu vào 0, và không đặt errno thành ENOMEM, thì bộ nhớ được giải phóng. Nhưng giống như malloc, realloc được phép cố gắng trả lại một phân bổ thực tế là 0 kích thước có thể sử dụng. Việc thực hiện được yêu cầu để ghi lại (7.20.3/1). –

+2

Steve là đúng, và hậu quả thực tế của điều này là bạn không bao giờ nên gọi 'realloc' với kích thước bằng 0. Xử lý tất cả các hành vi có thể, sự tồn tại của việc triển khai không tuân thủ, và thực tế là C và POSIX folks dường như không đồng ý về những gì phù hợp và những gì không làm cho nó một ý tưởng rất xấu để dựa vào bất cứ điều gì liên quan đến 'realloc (x, 0)'. –

+0

@Steve Jessop, R .. Cảm ơn bạn đã làm rõ :-) Tôi không bao giờ bận tâm để kiểm tra ngoài POSIX, tôi không biết nó không C-tiêu chuẩn. – cnicutar

11

Có chắc chắn không phải là một rò rỉ bộ nhớ, nhưng bất kỳ ít nhất 3 điều có thể xảy ra khi bạn gọi realloc để giảm kích thước:

  1. Việc thực hiện chia tách khối bộ nhớ được phân bổ ở độ dài yêu cầu mới và giải phóng phần không sử dụng ở cuối.
  2. Việc triển khai tạo phân bổ mới với kích thước mới, sao chép nội dung cũ sang vị trí mới và giải phóng toàn bộ phân bổ cũ.
  3. Việc triển khai không làm gì cả.

Tùy chọn 3 sẽ là một triển khai khá kém, nhưng hoàn toàn hợp pháp; vẫn không có "rò rỉ bộ nhớ" vì toàn bộ mọi thứ vẫn sẽ được giải phóng nếu sau này bạn gọi free trên đó.

Đối với các tùy chọn 1 và 2, tốt hơn phụ thuộc rất nhiều vào việc bạn có ưu tiên hiệu suất hay tránh phân mảnh bộ nhớ hay không. Tôi tin rằng hầu hết các triển khai trong thế giới thực sẽ dựa vào tùy chọn thực hiện 1.

+0

Lý do đằng sau tùy chọn 2 khi bạn cần ** giảm ** bộ nhớ được cấp phát là gì? Tôi không thể hiểu được. – Jacob

+1

Giả sử bạn đã phân bổ 100 byte và muốn đổi kích thước xuống 50 byte. Phân bổ đầu tiên tuyên bố vùng tự do 100 byte và tùy chọn 1 trả lại vùng tự do 50 byte, nhưng vùng 100 byte dài hơn không còn khả dụng nữa. Tuy nhiên, nếu có một vùng miễn phí khác chỉ dài 50 byte, tùy chọn 2 có thể di chuyển dữ liệu đến vị trí đó và giải phóng vùng 100 byte, để lại bộ nhớ ít bị phân mảnh hơn. –

+0

Lưu ý rằng nếu mục tiêu của bạn là tối ưu hóa cho phân mảnh tối thiểu, nó chỉ có ý nghĩa để có tùy chọn 2 khi một khu vực tự do nhỏ đủ lớn để chứa phân bổ đã tồn tại. Nếu bạn phải nhận được nhiều bộ nhớ hơn từ hệ thống hoặc tách một vùng tự do lớn hơn, nó chỉ có thể làm cho phân mảnh tồi tệ hơn, không tốt hơn. –

3

Theo cách bạn đã cung cấp mã, có, nó có thể bị rò rỉ. Ý tưởng của realloc là nó có thể đưa bạn trở lại vị trí mới của dữ liệu của bạn. Giống như bạn làm điều đó trong câu hỏi của bạn, bạn mất con trỏ mà realloc gửi cho bạn.

int *myPointer2 = realloc(myPointer,50*sizeof(int)); 
assert(myPointer2); 
myPointer = myPointer2; 
+0

@ R .. thực sự tôi đã không chắc chắn, đó là lý do tại sao tôi không chỉ cần đặt nó trong một bình luận. Nếu bạn nghĩ về nó, họ theo cách anh * thực sự * hỏi câu hỏi của anh ấy là tự nhiên hơn nhiều để tự hỏi điều gì xảy ra với bộ nhớ "rảnh rỗi". –

4

Mã mới vẫn rò rỉ phân bổ ban đầu nếu realloc không thành công. Tôi hy vọng hầu hết các triển khai sẽ không bao giờ thất bại trong việc thu nhỏ một khối, nhưng nó được cho phép. Cách chính xác để gọi realloc, cho dù phát triển hoặc thu hẹp khối, là void * tmp = realloc (myPointer, 50 * sizeof (int)); if (! tmp) {/ * xử lý lỗi bằng cách nào đó. myPointer vẫn trỏ đến khối cũ, vẫn được cấp phát * /} myPointer = tmp ;. - Steve Jessop 48 phút trước

Xin chào, tôi không thể tìm ra cách trả lời bình luận của bạn, xin lỗi.

Tôi có cần truyền tmp vào loại myPointer không? Trong trường hợp này, tôi cần phải viết

myPointer = (int*)tmp 

Ngoài ra, trong trường hợp này, khi tôi làm miễn phí (mypointer) Bộ nhớ chỉ vào bởi tmp sẽ được trả tự do là tốt, phải không?Vì vậy, không cần phải làm

free(myPointer) 
free(tmp) 
+0

Realloc sẽ vẫn bị rò rỉ. Đây là câu trả lời chính xác. Ít nhất là trên windows 7, 64 bit (tdm-gcc64) – dns

Các vấn đề liên quan