c

时间:2015-11-26 18:42:47

标签: c memory-management

嗨,我是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

2 个答案:

答案 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]))运算符,您要释放实际元素,而不是包含指向元素的指针的单元格。