出于学习目的,我正在在c中实现其功能。我添加了一些小的其他功能,以便第一次使用malloc并尝试正确理解它。
我写了一个最初创建我的堆栈结构的函数。该函数的返回值是具有已分配内存的新结构。处理返回值的函数中,处理malloc异常的最佳方法应该是结构?也许我应该设计不同的功能?我知道printf没有做工作;)
我的堆栈结构:
typedef struct Stack
{
int count;
int capacity;
int *data;
} Stack;
创建一个堆栈实例:
Stack create_stack(int initialcapacity)
{
Stack new_stack;
new_stack.count = 0;
new_stack.capacity = initialcapacity;
if (!(new_stack.data = malloc(initialcapacity * sizeof(int))))
printf("not enough memory!");
return new_stack;
}
该函数以堆栈的初始容量为单位:
Stack stack = create_stack(10);
当我编写函数以删除堆栈实例时,第二个问题出现了。
int delete_stack(Stack *stack)
{
stack->count = 0;
stack->capacity = 0;
free(stack->data);
stack->data = NULL;
return 0;
}
我还可以删除结构实例本身吗?仅将值设置回0并将int*直接为null感到不完整。
最后但并非最不重要的一点是,我对推动功能有疑问。另外,我添加了一些功能,使我可以在堆栈上推出一些功能:
void push(int value, Stack *stack)
{
if (stack->count == stack->capacity)
{
int *temp = malloc(stack->capacity * sizeof(int));
int i;
for (i = 0; i < stack->count; i++)
temp[i] = stack->data[i];
free(stack->data);
stack->data = NULL;
stack->data = malloc(stack->capacity * 2 * sizeof(int));
for (i; i > -1; i--)
stack->data[i] = temp[i];
free(temp);
temp = NULL;
stack->data[stack->count] = value;
stack->count++;
stack->capacity = stack->capacity * 2;
}
else
{
stack->data[stack->count] = value;
stack->count++;
}
}
是否有必要"释放"较小的数组,然后将指针放在null之前,然后再分配新数组的大小?
如果我的代码中有任何不必要或不正确写的东西,请让我知道,我很感激任何提示,这使我变得更好。
cheeers,我
我会用指针做。也就是说,您的create_stack()
将使用malloc
分配新的堆栈结构,然后将值设置为struct,然后再次使用Malloc为Stack->data
分配空间。这样:
Stack* create_stack(int initialcapacity) {
Stack* new_stack = malloc(sizeof(Stack));
if (new_stack == NULL)
return NULL; // return null to tell the caller that we failed
new_stack->count = 0;
new_stack->capacity = initialcapacity;
new_stack->data = malloc(initialcapacity * sizeof(int))
if (new_stack->data == NULL)
{
free(new_stack);
return NULL;
}
return new_stack;
}
这样,我们通过返回null来"处理" malloc错误,因此呼叫者知道我们失败了。
现在,我们已经使用malloc分配了堆栈结构,您可以(读:必须)使用delete_stack()
中的free(stack);
释放其空间。
在push()
中,不需要临时数组,也就是说,您可以立即分配一个较大的数组,将内容从原始stack->data
复制到其上,免费stack->data
并将其设置为新的malloc'd数组:
int *temp = malloc(stack->capacity * 2 * sizeof(int));
// TODO: what if malloc fails?
int i;
for (i = 0; i < stack->count; i++)
temp[i] = stack->data[i];
free(stack->data);
stack->data = temp;
stack->data[stack->count] = value;
stack->count++;
stack->capacity = stack->capacity * 2;
q。在函数中处理malloc异常的最佳方法是什么?
至少有三种方式:
1)而不是返回结构本身,而是返回指针。这意味着两个malloc
S:一个是用于结构本身,另一个用于data
字段。返回零指针意味着在施工期间出现问题。
struct Stack* create_stack(int initialcapacity) {
struct Stack* stack = malloc(sizeof(struct Stack));
...
return stack;
}
2)更灵活的方法是将指针传递给已经分配的结构。灵活性来自呼叫代码控制在何处分配结构的想法:在堆栈或动态内存中。函数的返回值只能仅用于通知有关错误的通话代码:
bool create_stack(int initialcapacity, struct Stack* stack) {
...
}
// if calling code wants structure on stack (yeah, "stack" on stack)
struct Stack stack;
if (!create_stack(50, &stack)) {
die();
}
// if calling code wants it in dynamic memory
struct Stack* stack = malloc(sizeof(struct Stack));
if (!stack) {
die();
}
if (!create_stack(50, stack)) {
die();
}
3)如果您的程序不是10,000 的LOC生产代码,则最简单的方法是简单地打印错误消息并立即流产程序,如果分配失败。通常,分配错误是致命的:如果记忆不足,您将无法以任何有意义的方式恢复。您甚至可以通过malloc
创建包装器功能以自动捕获此类错误并退出:
void* my_malloc(size_t count) {
void* ptr = malloc(count);
if (ptr == NULL) {
fprintf(stderr, "Allocation failed");
exit(EXIT_FAILURE);
}
return ptr;
}
q。我还可以删除结构实例本身吗?
不,你不能。因为将其分配在堆栈上(结构本身,而不是data
)。如果要删除结构本身,则需要从上方使用方法1。
,顺便说一句,无需将零和空设置为字段。它没有删除任何内容。这种方法很少使用,只有目的是捕获错误(当调用代码首先删除某些结构时,然后尝试以后使用它)。
q。是否有必要"释放"较小的数组,并在我分配新数组的大小之前将指针放在null上?
再次,您不需要无效任何东西 - 它不会删除任何内容。而不是两个malloc
S和手动复制使用realloc
,它将为您完成大部分工作。
通常,您应该能够声明一个结构,然后有一个sase 64的数组,并说出哪个条目在顶部。非常简单,没有动态分配。但是64很低,这是因为堆栈,递归和嵌套水平密切相关。通常,应该看到64是一个疯狂的筑巢水平,甚至没有任何合法的输入将接近它。然后,您可能需要一个警卫来防止恶意或损坏的输入,但这只是终止了程序或子规范。
如果您无法在堆栈上建立低理智,则可能仍然需要一个。要么是筑巢非常深的罕见情况,要么是您没有以最好的方式解决问题,但是一个不错的程序比没有程序要好。
因此,您使用相同的结构,但是堆栈是用调用的malloc(),如果它从范围内生长,请呼叫realloc()。您可能要保持理智检查,但是现在的理智检查是高得多,一百万左右,而不是64。您还必须检查Realloc不会失败。
typedef struct
{
int x;
char astring[32];
} ENTRY;
static ENTRY *stack = 0;;
static int top = -1;
static int N = 0;
void push(const ENTRY *e)
{
/* grow logic like this */
ENTRY *temp = realloc(stack, newsize * sizeof(ENTRY));
if(temp)
stack = temp;
else
{
/* reallocation has failed but stack still valid */
free(stack);
N = 0;
top = -1;
/* for the sake of argument do this. We need temp to avoid
a memory leak */
fprintf(stderr, "out of memoryn");
}
/* push here, trivial */
}
int pop(ENTRY *e)
{
/* e is a non-const pointer. Fill and reset stack top */
}
您可能想要示例中的堆栈全局将其包裹在您传递的结构中。通常你想要任何一个指针或堆栈上的结构,但有时您可能需要一个堆栈整数或浮点值。
没有很好的方法来处理C中的内存分配错误,尤其是无法发生的那些(安装了几GB内存的计算机比用完的更有可能发展电气故障当被要求使用几千字节时)。通常的规则是分支。但这使得呼叫很困难,因为每次推动可能会将计算机从内存中淘汰(但实际上不能,只是您的封装允许功能失败)。