c语言中的基本内存分配和释放
嗨,我是C编程新手,在内存分配方面有一些困难 尝试使用数组实现堆栈 我的SP_Stack.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
#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元素不是C类的,这意味着您拥有索引−1当堆栈为空时。我更愿意将顶层成员设为计数,这样en empty stack就表示为计数为零。这使得检查过流和下流更容易。这还意味着您可以使用(unsigned)top
类型作为索引,这是一个不错的选择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;
我已经添加了代码,我会复制它,这样即使在校准函数完成后它也会留在内存中。请!提供一个可以编译的示例有这么难吗?什么是