在c中使用malloc实现堆栈[初学者]
为了便于学习,我用c语言实现了一个函数堆栈。 我在第一次使用malloc时添加了一些小的附加功能,并试图正确理解它 我编写了一个函数,它最初创建堆栈结构。函数的返回值是一个具有已分配内存的新结构。在返回值应为结构的函数中,处理malloc异常的最佳方法是什么?也许我应该设计不同的功能?我知道printf没有完成它的工作;) 我的堆栈结构:在c中使用malloc实现堆栈[初学者],c,stack,malloc,C,Stack,Malloc,为了便于学习,我用c语言实现了一个函数堆栈。 我在第一次使用malloc时添加了一些小的附加功能,并试图正确理解它 我编写了一个函数,它最初创建堆栈结构。函数的返回值是一个具有已分配内存的新结构。在返回值应为结构的函数中,处理malloc异常的最佳方法是什么?也许我应该设计不同的功能?我知道printf没有完成它的工作;) 我的堆栈结构: typedef struct Stack { int count; int capacity; int *data; } Stack;
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++;
}
}
void push(int值,堆栈*Stack)
{
如果(堆栈->计数==堆栈->容量)
{
int*temp=malloc(堆栈->容量*sizeof(int));
int i;
对于(i=0;icount;i++)
温度[i]=堆栈->数据[i];
自由(堆栈->数据);
堆栈->数据=NULL;
堆栈->数据=malloc(堆栈->容量*2*sizeof(int));
对于(i;i>-1;i--)
堆栈->数据[i]=temp[i];
免费(临时);
温度=零;
堆栈->数据[堆栈->计数]=值;
堆栈->计数++;
堆栈->容量=堆栈->容量*2;
}
其他的
{
堆栈->数据[堆栈->计数]=值;
堆栈->计数++;
}
}
在我分配一个大小为原来两倍的新数组之前,是否有必要“释放”较小的数组并将指针指向NULL
如果我的代码中有任何不必要或编写不正确的地方,请让我知道,我非常感谢任何能让我变得更好的提示
奇尔斯,
我我会用指针来做。也就是说,您的
create_stack()
将使用malloc
分配一个新的堆栈结构,然后将值设置为该结构,并再次使用malloc为堆栈->数据分配空间。像这样:
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来分配Stack结构,您可以(读取:必须)使用free(Stack)释放它占用的空间代码>在中删除堆栈()
在push()
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;
int*temp=malloc(堆栈->容量*2*sizeof(int));
//TODO:如果malloc失败怎么办?
int i;
对于(i=0;icount;i++)
温度[i]=堆栈->数据[i];
自由(堆栈->数据);
堆栈->数据=温度;
堆栈->数据[堆栈->计数]=值;
堆栈->计数++;
堆栈->容量=堆栈->容量*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) 如果您的程序不是10000+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.我是否也可以删除结构实例本身?
不,你不能。因为它是在堆栈上分配的(结构本身,而不是数据
)。如果要删除结构本身,需要使用上面的方法#1
而且,顺便说一下,不需要为字段设置零和空。它不会删除任何内容。这种方法很少使用,而且只用于捕获bug(当调用代码时,首先删除一些结构,然后尝试使用它)
Q.在我分配一个新数组(大小为原来的两倍)之前,是否需要“释放”较小的数组并将指针指向NULL?
同样,您不需要取消任何内容——它不会删除任何内容。与使用两个malloc
s和手动复制不同,使用realloc
,这将为您完成大部分工作。通常,您应该能够声明一个结构,然后拥有一个包含64个结构的数组,其中一个整数表示哪个条目位于顶部。非常简单,没有动态分配。但64是相当低的,这是因为堆栈、递归和嵌套级别紧密相连。通常情况下,应该可以看到64是一个疯狂的嵌套级别,甚至没有合法的输入会接近它。然后,您可能需要一个防护装置来防止恶意或损坏的输入,但这只会终止程序或子程序
如果无法在堆栈上建立低健全性绑定,则可能仍然需要一个。要么是嵌套非常深入的罕见情况,要么是您没有以最佳方式处理问题,但仍然有效的次优程序总比没有程序好
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 memory\n");
}
/* push here, trivial */
}
int pop(ENTRY *e)
{
/* e is a non-const pointer. Fill and reset stack top */
}