我正在创建一个包含缓冲区功能的源文件,我想将其用于我正在创建的其他库。
它工作正常,但我有麻烦摆脱我在一个函数中创建的缓冲结构。下面的代码片段应该有助于说明我的问题:
C头:
//dbuffer.h
...
typedef struct{
char *pStorage;
int *pPosition;
int next_position;
int number_of_strings;
int total_size;
}DBUFF;
...
C来源://dbuffer.c
...
DBUFF* dbuffer_init(char *init_pArray)
{
//Find out how many elements the array contains
int size = sizeof_pArray(init_pArray);
//Initialize buffer structure
DBUFF *buffer = malloc(sizeof(DBUFF));
//Initialize the storage
buffer->pStorage = malloc( (sizeof(char)) * (size) );
strncpy( &(buffer->pStorage)[0] , &init_pArray[0] , size);
buffer->number_of_strings = 1;
buffer->total_size = size;
buffer->next_position = size; //size is the next position because array allocates elements from 0 to (size-1)
//Initialize the position tracker which keeps record of starting position for each string
buffer->pPosition = malloc(sizeof(int) * buffer->number_of_strings );
*(buffer->pPosition + (buffer->number_of_strings -1) ) = 0;
return buffer;
}
void dbuffer_destroy(DBUFF *buffer)
{
free(buffer->pStorage);
free(buffer);
}
...
主:#include <stdio.h>
#include <stdlib.h>
#include "dbuffer.h"
int main(int argc, char** argv)
{
DBUFF *buff;
buff = dbuffer_init("Bring the action");
dbuffer_add(buff, "Bring the apostles");
printf("BUFFER CONTENTS: ");
dbuffer_print(buff);
dbuffer_destroy(buff);
// Looks like it has been succesfully freed because output is garbage
printf("%sn", buff->pStorage);
//Why am I still able to access struct contents after the pointer has been freed ?
printf("buff total size: %dn", buff->total_size);
return (EXIT_SUCCESS);
}
输出:BUFFER CONTENTS: Bring the action/0Bring the apostles/0
��/�
buff total size: 36
RUN SUCCESSFUL (total time: 94ms)
问题:
为什么在指向结构的指针被释放后,我仍然可以使用下面的行访问结构的内容?
printf("buff total size: %dn", buff->total_size);
在分配的指针上调用free()
后,尝试使用该指针调用未定义行为。你不应该那样做。
引用C11
标准,§7.22.3.4, free()
函数
free()
函数使ptr
所指向的空间被释放,即被占用可供进一步分配。[. .]
它从来没有说过任何关于清理的事情,这可能是你(错误地)期望的。
只是为了清晰起见,调用free()
实际上并不总是释放分配的物理内存。它只是允许再次分配指针(内存空间)(例如,返回相同的指针),以便连续调用malloc()
和family。在调用free()
之后,该指针不应该再从您的程序中使用,但C
标准不保证清理分配的内存。
如果试图读取已被 free
d的内存,可能会导致程序崩溃。也可能不会。就语言而言,它的未定义行为
编译器不会警告你(或阻止你访问)。但很明显,在调用free
-
printf("buff total size: %dn", buff->total_size);
作为一个良好的实践,您可以将 free
d指针设置为NULL
。
free()调用将标记堆中的内存可用。所以你仍然有指向这个内存位置的指针但它对你来说不再可用了。因此,对malloc()的下一次调用可能会将该内存分配给新的预留。
要使这种情况失效,通常在您free()分配给指针的内存后,您应该将其设置为NULL。取消引用NULL也是UB,但至少在调试时,您可以看到不应该使用指针,因为它没有指向有效的内存地址。
[注释太长]
允许你的"析构函数"设置传递给NULL
的指针,修改你的代码如下:
void dbuffer_destroy(DBUFF ** buffer)
{
if ((NULL == buffer) || (NULL == *buffer))
{
return;
}
free((*buffer)->pPosition);
free((*buffer)->pStorage);
free(*buffer);
*buffer = NULL;
}
,并像这样命名:
...
dbuffer_destroy(&buff);
...