嗨,我是C编程的新手,并且对内存分配有一些困难
尝试使用数组
来实现堆栈我的SP_Stack.c:
#include "SP_Stack.h"
#include <stdlib.h>
#include <stdio.h>
struct sp_stack_struct {
SP_STACK_ELEMENT *elements;
int top;
};
SP_STACK* spStackCreate(){
SP_STACK *new_stack = (SP_STACK*)malloc(sizeof(SP_STACK));
SP_STACK_ELEMENT *newContents = (SP_STACK_ELEMENT*)malloc(sizeof(SP_STACK_ELEMENT)*1024);
/* make sure to return NULL if needed */
if( newContents == NULL){
return NULL;
}
new_stack->elements = newContents;
new_stack->top = -1;
return new_stack;
}
void spStackDestroy(SP_STACK* stack){
//while(!spStackIsEmpty(stack,NULL)){
//spStackPop(stack,NULL);
// }
free(stack->elements);
free(stack);
}
SP_STACK_ELEMENT* spStackTop (SP_STACK* stack){
// make sure to return NULL
if (stack == NULL || spStackIsEmpty(stack)){
return NULL;
}
return &(stack->elements[(stack->top)]);
}
SP_STACK* spStackPop(SP_STACK* stack){
if (!(stack == NULL || spStackIsEmpty(stack))){
//free(&(stack->elements[stack->top]));
//stack->top--;
}
return stack;
}
SP_STACK* spStackPush(SP_STACK* stack, SP_STACK_ELEMENT newElement){
if (stack == NULL){
return NULL;
}
// copy element so he will stay in memory
SP_STACK_ELEMENT* copyElement = (SP_STACK_ELEMENT*)malloc(sizeof(SP_STACK_ELEMENT));
copyElement->type = newElement.type ;
copyElement->value = newElement.value;
stack->elements[++stack->top] = *copyElement;
return stack;
}
bool spStackIsEmpty(SP_STACK* stack){
return stack->top < 0;
}
我的SP_Stack.h
typedef enum {
PLUS,
MINUS,
MULTIPLICATION,
DIVISION,
DOLLAR,
NUMBER,
UNKNOWN
} SP_STACK_ELEMENT_TYPE;
typedef struct {
SP_STACK_ELEMENT_TYPE type;
double value;
} SP_STACK_ELEMENT;
typedef struct sp_stack_struct SP_STACK;
SP_STACK* spStackCreate();
void spStackDestroy(SP_STACK* stack);
SP_STACK_ELEMENT* spStackTop (SP_STACK* stack);
SP_STACK* spStackPop(SP_STACK* stack);
SP_STACK* spStackPush(SP_STACK* stack, SP_STACK_ELEMENT newElement);
bool spStackIsEmpty(SP_STACK* stack);
#endif /* SP_STACK_H_ */
我的测试员:
#include "SP_Stack.h"
#include <stdlib.h>
#include <stdio.h>
#include <stdbool.h>
int main(){
SP_STACK_ELEMENT* elementPtr = NULL;
SP_STACK * stack = spStackCreate();
elementPtr = spStackTop(stack);
SP_STACK_ELEMENT newElement = {.type = NUMBER , .value = 100};
SP_STACK_ELEMENT newElement2 = {.type = NUMBER , .value = 200};
SP_STACK_ELEMENT newElement3 = {.type = NUMBER , .value = 300};
SP_STACK_ELEMENT newElement4 = {.type = NUMBER , .value = 400};
SP_STACK_ELEMENT newElement5 = {.type = NUMBER , .value = 500};
stack = spStackPush(stack,newElement);
stack = spStackPush(stack,newElement2);
stack = spStackPush(stack,newElement3);
stack = spStackPop(stack);
spStackDestroy(stack);
return 1;
}
我的问题是 - 每当我尝试弹出一个元素时,我的程序就会崩溃。
我试图检查我的堆栈 - &gt;顶部值是否正确。 我还验证它包含一个对象 通过在位置堆栈中打印对象值 - >顶部
我尝试删除数组中的特定索引:
free(&(stack->elements[0]));
可以,但是,任何其他索引:
free(&(stack->elements[1]));
即使elments [i]退出,也会崩溃。
我做错了什么? THX答案 0 :(得分:1)
您对数据在堆栈中的组织方式存在误解。
您有一系列动态条目。此数组使用malloc
创建,并由指针表示,即堆内存的句柄。
初始化堆栈后,该阵列已包含1024个未初始化的元素。按下值时,将阵列的内容复制到顶部插槽。您的代码如下所示:
SP_STACK_ELEMENT *copyElement =
(SP_STACK_ELEMENT *) malloc(sizeof(SP_STACK_ELEMENT));
copyElement->type = newElement.type;
copyElement->value = newElement.value;
stack->elements[++stack->top] = *copyElement;
您可以分配内存,将参数复制到副本,然后将副本的内容复制到数组元素。中间副本没用。更糟糕的是,分配的内存会丢失,因为会立即处理copyElement
。
代码应该只是:
stack->elements[++stack->top] = *newElement;
相反,因为推送元素的内存不是malloc
,所以你不能free
。但是因为你无法返回一个指向可能被立即覆盖的内存的指针,所以你不能将弹出的元素作为指针返回。
现在你必须做出决定:你想要存储什么?元素或指向元素的指针。如果元素是轻量级的,则存储元素是可行且容易的,例如,如果它们是整数或双精度。您的结构是轻量级的,可以按值传递。另一方面,如果存储指针,则客户端代码(使用堆栈的代码)必须管理内存。
您的代码还有其他问题:
在初始化堆栈时,您可以将堆栈数据分配给局部变量,但是从未将其分配给stack->elements
。
您应该释放在初始化时分配的内存,而不是释放单个元素。最好通过“析构函数”或清理功能来完成。
让top
索引引用top元素不是C类,意味着当堆栈为空时你有索引-1。我更喜欢使顶级成员计数,因此空堆栈由零计数表示。这使得检查上溢和下溢更容易。这也意味着您可以使用(无符号)size_t
类型作为索引,这是一个不错的选择。
下面是一个实现堆栈的示例,正如您可能想要的那样。它存储元素并将它们作为值传递。看看,除了上下溢检查外,推送和弹出功能非常简单。
#include <stdlib.h>
#include <stdio.h>
enum Type {
PLUS,
MINUS,
NUMBER,
UNKNOWN
};
typedef struct Stack Stack;
typedef struct Element Element;
struct Element {
enum Type type;
double value;
};
struct Stack {
size_t count;
Element *elem;
};
#define SP_SIZE 1024
Stack *spStackCreate(void)
{
Stack *stack = malloc(sizeof(*stack));
Element *elem = malloc(SP_SIZE * sizeof(*elem));
if (stack == NULL || elem == NULL) {
free(stack);
free(elem);
return NULL;
}
stack->elem = elem;
stack->count = 0;
return stack;
}
void spStackDestroy(Stack *stack)
{
if (stack) {
free(stack->elem);
free(stack);
}
}
void spStackPush(Stack *stack, Element elem)
{
if (stack->count >= SP_SIZE) {
fprintf(stderr, "Stack overflow!\n");
exit(1);
}
stack->elem[stack->count++] = elem;
}
Element spStackPop(Stack *stack)
{
if (stack->count == 0) {
fprintf(stderr, "Stack underflow!\n");
exit(1);
}
return stack->elem[--stack->count];
}
int spStackIsEmpty(const Stack *stack)
{
return (stack->count == 0);
}
int main()
{
Stack *stack = spStackCreate();
int i, j = 1;
if (stack == NULL) exit(1);
for (i = 0; i < 10; i++) {
Element elem = {NUMBER, j};
spStackPush(stack, elem);
j += i;
}
while (!spStackIsEmpty(stack)) {
Element elem = spStackPop(stack);
printf("%g\n", elem.value);
}
spStackDestroy(stack);
return 0;
}
答案 1 :(得分:0)
我的问题是 - 每次我尝试弹出一个元素,我的程序 崩溃。
我试图检查我的堆栈 - &gt;顶部值是否正确。我也 通过打印对象值来验证它包含一个对象 location stack-&gt; top
我尝试删除数组中的特定索引:
自由(及(重新建立了新&GT;元素[0]));但是,任何其他索引:
自由(及(重新建立了新&GT;元素[1]));即使elments [i]退出,也会崩溃。
第一个正在运行,因为&
运算符正在获取stack->elements
数组中第一个单元格的地址(该地址与malloc()
调用返回的地址匹配(当您初始化newContents
变量时,它是free()
的合法地址。
第二个是获取数组中第二个单元格的地址,这个指针不是从malloc()
调用获得的,因此当你尝试free()
时它很可能会崩溃
尝试从&
中删除free(&(stack->elements[1]))
运算符,您要释放实际元素,而不是包含指向元素的指针的单元格。