Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/55.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
c语言中的基本内存分配和释放_C_Memory Management - Fatal编程技术网

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

c语言中的基本内存分配和释放,c,memory-management,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_stac

嗨,我是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;
}
我的测试人员:

#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;
}
有效,但任何其他索引:

free(&(stack->elements[1]));
崩溃,即使elments[i]退出

我做错了什么?
thx

您对数据在堆栈中的组织方式存在误解

您有一个动态的条目数组。这个数组是用
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
ed,因此不能
free
it。但由于无法返回指向可能立即被覆盖的内存的指针,因此无法将弹出的元素作为指针返回

现在你必须做出决定:你想储存什么?元素或指向元素的指针。如果您的元素是轻量级的,那么存储元素是可行且容易的,例如,如果它们是int或double。您的结构是轻量级的,可以通过值传递。另一方面,如果存储指针,则客户端代码(使用堆栈的代码)必须管理内存

您的代码还存在其他问题:

  • 初始化堆栈时,可以将堆栈数据适当地分配给局部变量,但从不将其分配给
    stack->elements

  • 您应该释放初始化时分配的内存,而不是释放单个元素。这最好通过“析构函数”或清除函数来完成

  • top
    索引引用top元素不是C类的,这意味着您拥有索引−1当堆栈为空时。我更愿意将顶层成员设为计数,这样en empty stack就表示为计数为零。这使得检查过流和下流更容易。这还意味着您可以使用(unsigned)
    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;
}
#包括
#包括
枚举类型{
加上,
减
数字,
不为人知
};
typedef结构堆栈;
typedef结构元素;
结构元素{
枚举类型;
双重价值;
};
结构堆栈{
大小/数量;
元素*elem;
};
#定义SP_大小1024
堆栈*创建(无效)
{
Stack*Stack=malloc(sizeof(*Stack));
元素*elem=malloc(SP_大小*sizeof(*elem));
if(stack==NULL | | elem==NULL){
自由(堆叠);
免费(elem);
返回NULL;
}
堆栈->元素=元素;
堆栈->计数=0;
返回栈;
}
作废和销毁(堆栈*堆栈)
{
如果(堆栈){
自由(堆栈->元素);
自由(堆叠);
}
}
void spStackPush(堆栈*堆栈,元素元素元素)
{
如果(堆栈->计数>=SP_大小){
fprintf(stderr,“堆栈溢出!\n”);
出口(1);
}
堆栈->元素[堆栈->计数+]=elem;
}
元素spStackPop(堆栈*堆栈)
{
如果(堆栈->计数==0){
fprintf(标准,“堆栈下溢!\n”);
出口(1);
}
返回堆栈->元素[--堆栈->计数];
}
int spStackIsEmpty(常量堆栈*堆栈)
{
返回(堆栈->计数==0);
}
int main()
{
Stack*Stack=spStackCreate();
int i,j=1;
如果(stack==NULL)退出(1);
对于(i=0;i<10;i++){
元素elem={NUMBER,j};
spStackPush(堆栈、元素);
j+=i;
}
而(!spStackIsEmpty(stack)){
元素elem=spStackPop(堆栈);
printf(“%g\n”,元素值);
}
sps(堆栈);
返回0;
}
我的问题是——每次我尝试弹出一个元素时,我的程序 撞车

我试图检查我的堆栈->顶部值是否正确。我也 通过在中打印对象值来验证它是否包含对象 位置堆栈->顶部

我试图删除数组中的特定索引:

free(&(stack->elements[0]));
自由(&(堆栈->元素[0]);有效,但任何其他索引:

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

第一个是有效的,因为
&
操作符正在获取
堆栈->元素
数组中第一个单元格的地址(该地址与
malloc()
调用返回的地址匹配(初始化
newContents
变量时的地址,因此它是
free()
的合法地址)

第二个是获取数组中第二个单元格的地址,该指针不是从
malloc()
调用中获取的,因此当您尝试
free()
它时,很可能会崩溃


尝试从
空闲(&(堆栈->元素[1])中删除
&
运算符
,您希望释放实际的元素,而不是包含元素指针的单元格。

您的示例中缺少太多内容。
stack->top
在哪里初始化?我们需要
SP\u stack\u元素
定义来知道'copyElement->value=newElement.value;'是否是有效的操作…为什么要复制整个stru按值计算ct?
stack->elements[++stack->top]=*copyElement;
我已经添加了代码,我会复制它,这样即使在校准函数完成后它也会留在内存中。请!提供一个可以编译的示例有这么难吗?什么是