简体   繁体   English

c 中的基本内存分配和释放

[英]basic memory allocation and free in c

Hi I'm new to C programming and have some dificulties with memory allocation嗨,我是 C 编程的新手,在内存分配方面有一些困难

trying to implment a stack using an array尝试使用数组实现堆栈

my SP_Stack.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;
}

my SP_Stack.h我的 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_ */

my tester:我的测试员:

#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;
}

my problem is - every time I try to pop an element, my program crashes.我的问题是 - 每次我尝试弹出一个元素时,我的程序都会崩溃。

I tried to check my stack->top value is correct an it is.我试图检查我的 stack->top 值是否正确。 I also verified it contains an object by printing the object value in location stack->top我还通过在位置 stack->top 中打印对象值来验证它包含一个对象

I tried to delete a specific index in my array:我试图删除数组中的特定索引:

free(&(stack->elements[0]));

works but, any other index:有效,但是,任何其他索引:

free(&(stack->elements[1]));

crashes, even if elments[i] exits.崩溃,即使 elments[i] 退出。

what am I doing wrong?我究竟做错了什么? thx谢谢

You have a misconception about how your data is organised in the stack.您对堆栈中的数据组织方式存在误解。

You have a dynamic array of entries.您有一个动态的条目数组。 This array is created with malloc and represented by a pointer, namely the handle to the heap memory.这个数组是用malloc创建的,并由一个指针表示,即堆内存的句柄。

After you have initialised your stack, that array already contains 1024 uninitialised elements.初始化堆栈后,该数组已包含 1024 个未初始化的元素。 When you push values, you copy the contents of the array to the top slot.当您推送值时,您将数组的内容复制到顶部插槽。 Your code looks like this:您的代码如下所示:

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;

You allocate memory, copy the parameters to the copy and then copy the contents of the copy to the array element.您分配内存,将参数复制到副本,然后将副本的内容复制到数组元素。 The intermediate copy is useless.中间副本没用。 Worse, the allocated memory is lost, because the handle to copyElement immediately.更糟糕的是,分配的内存丢失了,因为立即到copyElement的句柄。

The code should be just:代码应该只是:

stack->elements[++stack->top] = *newElement; 

Conversely, because the memory for the pushed element wasn't really malloc ed, you can't free it.相反,因为被推送元素的内存并没有真正地malloc ed,所以你不能free它。 But because you can't return a pointer to memory that might be overwritten immediately, you can't return the popped element as pointer.但是因为你不能返回一个指向可能被立即覆盖的内存的指针,所以你不能将弹出的元素作为指针返回。

Now you have to make a decision: What do you want to store?现在您必须做出决定:您要存储什么? Elements or pointers to elements.元素或指向元素的指针。 Storing elements is feasible and easy if your elements are lightweight, for example if they are ints, or doubles.如果您的元素是轻量级的,例如如果它们是整数或双精度,则存储元素是可行且容易的。 Your struct is lightweight and can be passed around by value.您的结构是轻量级的,可以按值传递。 On the other hand, if you store pointers, your client code – the code that uses the stack – must manage the memory.另一方面,如果你存储指针,你的客户端代码——使用堆栈的代码——必须管理内存。

There are other issues with your code:您的代码还有其他问题:

  • You allocate the stack data proper to a local variable when you initialise the stack, but you never assign it to stack->elements .初始化堆栈时,您将堆栈数据正确分配给局部变量,但从未将其分配给stack->elements

  • Instead of freeing the individual elements, you should free the memory that you have allocated on initialisation.您应该释放在初始化时分配的内存,而不是释放单个元素。 This is best done by a "destructor" or clean-up function.这最好通过“析构函数”或清理函数来完成。

  • Having the top index refer to the top element is not C-like and means that you have the index −1 when the stack is empty. top索引指向顶部元素并不像 C 语言,这意味着当堆栈为空时索引为 -1。 I would prefer to make the top member a count, so that en empty stack is represented by a count of zero.我更愿意让顶级成员成为一个计数,以便空堆栈由零计数表示。 That makes checking against over- and underflow easier.这使得检查溢出和下溢变得更加容易。 It also means that you can use the (unsigned) size_t type as index, which is a good choice.这也意味着您可以使用(无符号) size_t类型作为索引,这是一个不错的选择。

Below is an example that implements a stack as you may have intended it.下面是一个实现堆栈的示例,如您所愿。 It stores the elements and passes them around as values.它存储元素并将它们作为值传递。 See how, except for the over- and underflow checks, the push and pop functions are very simple.看看除了上溢和下溢检查之外,push 和 pop 函数是如何非常简单的。

#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;
}

my problem is - every time I try to pop an element, my program crashes.我的问题是 - 每次我尝试弹出一个元素时,我的程序都会崩溃。

I tried to check my stack->top value is correct an it is.我试图检查我的 stack->top 值是否正确。 I also verified it contains an object by printing the object value in location stack->top我还通过在位置 stack->top 中打印对象值来验证它包含一个对象

I tried to delete a specific index in my array:我试图删除数组中的特定索引:

free(&(stack->elements[0])); free(&(stack->elements[0])); works but, any other index:有效,但是,任何其他索引:

free(&(stack->elements[1]));自由(&(堆栈->元素[1])); crashes, even if elments[i] exits.崩溃,即使 elments[i] 退出。

The first one is working because the & operator is taking the address of the first cell in your stack->elements array (that address matches the address returned by the malloc() call (the one when you initialize the newContents variable and so it is a legit address to free() .第一个正在工作,因为&运算符正在获取stack->elements数组中第一个单元格的地址(该地址与malloc()调用返回的地址相匹配(初始化newContents变量时的地址,因此它是free()的合法地址。

The second one is getting the address of the second cell in your array, this pointer was not obtained from a malloc() call, and as such is very likely to crash when you attempt to free() it.第二个是获取数组中第二个单元格的地址,该指针不是从malloc()调用中获得的,因此当您尝试free()时很可能会崩溃。

Try removing the & operator from free(&(stack->elements[1])) , you want to free the actual element, not the cell containing the pointer to the element.尝试从free(&(stack->elements[1]))删除&运算符,您想释放实际元素,而不是包含指向该元素的指针的单元格。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM