其思想是在main开头插入垃圾堆,使用gmalloc、gcalloc和grealloc包装器,并在main末尾释放所有分配的内存。在为电子判断系统编写程序时,它有助于避免内存泄漏。希望听取关于如何改进代码(C语言初学者)的想法和建议的一般反馈意见。
main.c
/*
Example of usage of garbage heap.
No free() call but no memory leak.
*/
#include "garbage_heap.h"
int main() {
init_garbage_heap();
for (int i = 0; i < 1000; ++i)
{
char* str = gmalloc(1000*sizeof(char));
str = grealloc(str, 2000*sizeof(char));
}
free_garbage_heap();
return 0;
}garbage_heap.h
#ifndef GARBAGE_HEAP_H
#define GARBAGE_HEAP_H
#include <stddef.h>
void init_garbage_heap (void);
void free_garbage_heap (void);
void* gmalloc (size_t sizemem);
void* gcalloc (size_t number, size_t size);
void* grealloc (void* ptrmem, size_t sizemem);
#endif // GARBAGE_HEAP_Hgarbage_heap.c
#include <stdlib.h>
#include "garbage_heap.h"
typedef struct
{
void** buffer;
int len;
int capacity;
}
GarbageHeap;
static GarbageHeap garbage_heap;
void init_garbage_heap(void)
{
int len = 32;
garbage_heap.len = 0;
garbage_heap.capacity = len;
garbage_heap.buffer = (void**)malloc(sizeof(void*)*len);
for (int i = 0; i < len; ++i)
garbage_heap.buffer[i] = NULL;
}
void free_garbage_heap(void)
{
for (int i = 0; i < garbage_heap.len; ++i)
if (garbage_heap.buffer[i] != NULL)
free(garbage_heap.buffer[i]);
free(garbage_heap.buffer);
}
void resize_garbage_heap(void)
{
garbage_heap.capacity *= 2;
garbage_heap.buffer = (void**)realloc(garbage_heap.buffer, sizeof(void*) * garbage_heap.capacity);
for (int i = garbage_heap.len; i < garbage_heap.capacity; ++i)
garbage_heap.buffer[i] = NULL;
}
void* gmalloc(size_t sizemem)
{
if (garbage_heap.len == garbage_heap.capacity)
resize_garbage_heap();
garbage_heap.buffer[garbage_heap.len] = malloc(sizemem);
++garbage_heap.len;
return garbage_heap.buffer[garbage_heap.len - 1];
}
void* gcalloc(size_t number, size_t size)
{
if (garbage_heap.len == garbage_heap.capacity)
resize_garbage_heap();
garbage_heap.buffer[garbage_heap.len] = calloc(number, size);
++garbage_heap.len;
return garbage_heap.buffer[garbage_heap.len - 1];
}
void* grealloc(void* ptrmem, size_t sizemem)
{
if (ptrmem == NULL)
return gmalloc(sizemem);
int i = 0;
while (garbage_heap.buffer[i] != ptrmem)
++i;
void* tmp_ptr = realloc(ptrmem, sizemem);
if (tmp_ptr != NULL)
garbage_heap.buffer[i] = tmp_ptr;
return tmp_ptr;
}发布于 2019-10-04 16:00:05
有趣的概念,我猜C不是您的第一种编程语言,您的第一语言不需要显式的内存管理。
代码非常好,但是这里有一些需要考虑的事项:
良好的编程实践
在大多数if语句和循环中,问题中的代码很难维护,因为它没有为贯穿代码的每条路径提供复杂的语句。复杂语句是由{和}封装在C语言中的代码块。
一个复杂语句的例子是:{语句;语句;}
缺少这种良好编程实践的代码的一个例子是
void free_garbage_heap(void)
{
for (int i = 0; i < garbage_heap.len; ++i)
if (garbage_heap.buffer[i] != NULL)
free(garbage_heap.buffer[i]);
free(garbage_heap.buffer);
}假设维护代码的人必须在循环中的if语句中添加一条语句,并且他们希望快速地这样做,或者他们来自一种定位的编程语言,而不是使用大括号来表示一个复杂的语句。如果他们直接在free(garbage_heap.buffer[i]);下面添加它而不添加大括号,那么不仅新语句不在if语句中,新语句甚至不在for循环中。
在C和C++等语言中,以下代码是一种更安全的编程实践:
void free_garbage_heap(void)
{
for (int i = 0; i < garbage_heap.len; ++i)
{
if (garbage_heap.buffer[i] != NULL)
{
free(garbage_heap.buffer[i]);
}
}
free(garbage_heap.buffer);
}添加新语句的位置变得更加清晰。
函数init_garbage_heap的可能改进
在init_garbage_heap()中要注意的第一件事是,在调用void* malloc(int number_of_bytes_to_allocate)之后没有错误检查。对malloc()的调用可能失败,如果调用失败,则返回的值为NULL。如果malloc()返回一个错误,那么如果代码继续处理,那么garbage_heap.buffer[i] = NULL;的for循环中就会出现内存访问错误,这可能会导致程序崩溃(退出不当)。在C++中,如果new()失败,它将引发异常,C编程语言没有异常,因此需要进行测试。
下面的代码中要注意的第二件事是,在(void**)的C99或更高版本的C中,在原始的C malloc()返回char*和必需的强制转换中,不需要强制转换,因为它现在返回了void.it不需要。
void init_garbage_heap(void)
{
int len = 32;
garbage_heap.len = 0;
garbage_heap.capacity = len;
garbage_heap.buffer = (void**)malloc(sizeof(void*)*len);
for (int i = 0; i < len; ++i)
garbage_heap.buffer[i] = NULL;
}要注意的第三件事是,garbage_heap.buffer的类型可以改变,所以如果使用sizeof(*garbage_heap.buffer) * len而不是说明sizeof(void*)*len,可能会更好。这样,如果buffer的类型发生变化,代码只需要更改声明buffer的位置,而不需要在多个地方更改。
将garbage_heap.buffer的内容初始化为NULL的for循环可以替换为调用(*ptr,int值,大小_));:
memset(garbage_heap.buffer, 0, sizeof(*garbage_heap.buffer) * len);这可能会比for循环执行更快的速度,这取决于memset()的编写方式。它也是用代码的其余部分编写的。
如果将对malloc()的调用替换为对calloc()的调用,则不需要for循环或对memset()的调用,因为calloc()将将被返回的内存内容设置为NULL。
`init_garbage_heap的可能改进版本(Void):
void init_garbage_heap(void)
{
int len = 32;
garbage_heap.len = 0;
garbage_heap.capacity = len;
garbage_heap.buffer = calloc(sizeof(*garbage_heap.buffer), len);
if (!garbage_heap.buffer)
{
fprintf(stderr, "Unable to allocate memory for garbage_heap.buffer, exiting program");
exit(EXIT_FAILURE);
}
}尚不清楚len为什么要被分配32,最好使用一个符号常量而不是32。如果这些例程的用户能够设置初始分配容量,也可能会更好。如果初始缓冲区大小大于32,则更好,以减少调整大小的需要。
间距
如果函数中有垂直间距,garbage_heap.c中的代码可能更易读。
https://codereview.stackexchange.com/questions/230119
复制相似问题