在c中使用malloc实现堆栈[初学者]

在c中使用malloc实现堆栈[初学者],c,stack,malloc,C,Stack,Malloc,为了便于学习,我用c语言实现了一个函数堆栈。 我在第一次使用malloc时添加了一些小的附加功能,并试图正确理解它 我编写了一个函数,它最初创建堆栈结构。函数的返回值是一个具有已分配内存的新结构。在返回值应为结构的函数中,处理malloc异常的最佳方法是什么?也许我应该设计不同的功能?我知道printf没有完成它的工作;) 我的堆栈结构: typedef struct Stack { int count; int capacity; int *data; } Stack;

为了便于学习,我用c语言实现了一个函数堆栈。 我在第一次使用malloc时添加了一些小的附加功能,并试图正确理解它

我编写了一个函数,它最初创建堆栈结构。函数的返回值是一个具有已分配内存的新结构。在返回值应为结构的函数中,处理malloc异常的最佳方法是什么?也许我应该设计不同的功能?我知道printf没有完成它的工作;)

我的堆栈结构:

typedef struct Stack
{
    int count;
    int capacity;
    int *data;
} Stack;
创建堆栈实例:

Stack create_stack(int initialcapacity)
{
    Stack new_stack;
    new_stack.count = 0;
    new_stack.capacity = initialcapacity;

    if (!(new_stack.data = malloc(initialcapacity * sizeof(int))))
        printf("not enough memory!");

    return new_stack;
}
使用堆栈的初始容量调用函数:

Stack stack = create_stack(10);
在我编写删除堆栈实例的函数时,出现了第二个问题

int delete_stack(Stack *stack)
{
    stack->count = 0;
    stack->capacity = 0;
    free(stack->data);
    stack->data = NULL;
    return 0;
}
我是否也可以删除结构实例本身?仅仅将值设置回0并将int*直接设置为NULL感觉不完整

最后但并非最不重要的一点是,我对推送函数有一个问题。在这里,我还添加了一些功能,允许我在堆栈已满时将其推送到堆栈上:

void push(int value, Stack *stack)
{   
    if (stack->count == stack->capacity)
    {   
        int *temp = malloc(stack->capacity * sizeof(int));

        int i;
        for (i = 0; i < stack->count; i++)
            temp[i] = stack->data[i];

        free(stack->data);
        stack->data = NULL;

        stack->data = malloc(stack->capacity * 2 * sizeof(int));

        for (i; i > -1; i--)
            stack->data[i] = temp[i];

        free(temp);
        temp = NULL;
        stack->data[stack->count] = value;
        stack->count++;
        stack->capacity = stack->capacity * 2;
    }
    else
    {
        stack->data[stack->count] = value;
        stack->count++;
    }
}
void push(int值,堆栈*Stack)
{   
如果(堆栈->计数==堆栈->容量)
{   
int*temp=malloc(堆栈->容量*sizeof(int));
int i;
对于(i=0;icount;i++)
温度[i]=堆栈->数据[i];
自由(堆栈->数据);
堆栈->数据=NULL;
堆栈->数据=malloc(堆栈->容量*2*sizeof(int));
对于(i;i>-1;i--)
堆栈->数据[i]=temp[i];
免费(临时);
温度=零;
堆栈->数据[堆栈->计数]=值;
堆栈->计数++;
堆栈->容量=堆栈->容量*2;
}
其他的
{
堆栈->数据[堆栈->计数]=值;
堆栈->计数++;
}
}
在我分配一个大小为原来两倍的新数组之前,是否有必要“释放”较小的数组并将指针指向NULL

如果我的代码中有任何不必要或编写不正确的地方,请让我知道,我非常感谢任何能让我变得更好的提示

奇尔斯,

我会用指针来做。也就是说,您的
create_stack()
将使用
malloc
分配一个新的堆栈结构,然后将值设置为该结构,并再次使用malloc为
堆栈->数据分配空间。像这样:

Stack* create_stack(int initialcapacity) {
    Stack* new_stack = malloc(sizeof(Stack));

    if (new_stack == NULL)
        return NULL; // return null to tell the caller that we failed

    new_stack->count = 0;
    new_stack->capacity = initialcapacity;
    new_stack->data = malloc(initialcapacity * sizeof(int))

    if (new_stack->data == NULL)
    {
        free(new_stack);
        return NULL;
    }

    return new_stack;
}
这样,我们通过返回NULL来“处理”malloc错误,以便调用方知道我们失败了

现在我们已经使用malloc来分配Stack结构,您可以(读取:必须)使用
free(Stack)释放它占用的空间
中删除堆栈()

push()

int *temp = malloc(stack->capacity * 2 * sizeof(int));
// TODO: what if malloc fails?

int i;
for (i = 0; i < stack->count; i++)
    temp[i] = stack->data[i];

free(stack->data);
stack->data = temp;

stack->data[stack->count] = value;
stack->count++;
stack->capacity = stack->capacity * 2;
int*temp=malloc(堆栈->容量*2*sizeof(int));
//TODO:如果malloc失败怎么办?
int i;
对于(i=0;icount;i++)
温度[i]=堆栈->数据[i];
自由(堆栈->数据);
堆栈->数据=温度;
堆栈->数据[堆栈->计数]=值;
堆栈->计数++;
堆栈->容量=堆栈->容量*2;

Q.在返回值应为结构的函数中,处理malloc异常的最佳方法是什么?

至少有三种方法:

1) 不是返回结构本身,而是返回指向它的指针。这意味着有两个
malloc
s:一个用于结构本身,另一个用于
data
字段。返回空指针意味着在构造过程中出错

struct Stack* create_stack(int initialcapacity) {
    struct Stack* stack = malloc(sizeof(struct Stack));
    ...
    return stack;
}
2) 更灵活的方法是将指针传递给已分配的结构。灵活性来自于调用代码控制结构分配的位置:在堆栈上还是在动态内存中。函数的返回值可仅用于通知调用代码有关错误:

bool create_stack(int initialcapacity, struct Stack* stack) {
  ...
}

// if calling code wants structure on stack (yeah, "stack" on stack)
struct Stack stack;
if (!create_stack(50, &stack)) {
  die();
}

// if calling code wants it in dynamic memory
struct Stack* stack = malloc(sizeof(struct Stack));
if (!stack) {
  die();
}
if (!create_stack(50, stack)) {
  die();
}
3) 如果您的程序不是10000+LOC生产代码,最简单的方法可能是简单地打印错误消息,并在分配失败时立即中止程序。通常,分配错误是致命的:如果内存不足,则无法以任何有意义的方式进行恢复。您甚至可以在
malloc
上创建包装函数,以自动捕获此类错误并退出:

void* my_malloc(size_t count) {
    void* ptr = malloc(count);
    if (ptr == NULL) {
      fprintf(stderr, "Allocation failed");
      exit(EXIT_FAILURE);
    }
    return ptr;
}
Q.我是否也可以删除结构实例本身?

不,你不能。因为它是在堆栈上分配的(结构本身,而不是
数据
)。如果要删除结构本身,需要使用上面的方法#1

而且,顺便说一下,不需要为字段设置零和空。它不会删除任何内容。这种方法很少使用,而且只用于捕获bug(当调用代码时,首先删除一些结构,然后尝试使用它)

Q.在我分配一个新数组(大小为原来的两倍)之前,是否需要“释放”较小的数组并将指针指向NULL?


同样,您不需要取消任何内容——它不会删除任何内容。与使用两个
malloc
s和手动复制不同,使用
realloc
,这将为您完成大部分工作。

通常,您应该能够声明一个结构,然后拥有一个包含64个结构的数组,其中一个整数表示哪个条目位于顶部。非常简单,没有动态分配。但64是相当低的,这是因为堆栈、递归和嵌套级别紧密相连。通常情况下,应该可以看到64是一个疯狂的嵌套级别,甚至没有合法的输入会接近它。然后,您可能需要一个防护装置来防止恶意或损坏的输入,但这只会终止程序或子程序

如果无法在堆栈上建立低健全性绑定,则可能仍然需要一个。要么是嵌套非常深入的罕见情况,要么是您没有以最佳方式处理问题,但仍然有效的次优程序总比没有程序好
typedef struct
{
    int x;
    char astring[32];
} ENTRY;

static ENTRY *stack = 0;;
static int top = -1;
static int N = 0; 

void push(const ENTRY *e)
{
   /* grow logic like this */
   ENTRY *temp = realloc(stack, newsize * sizeof(ENTRY));
   if(temp)
     stack = temp;
   else
   {
      /* reallocation has failed but stack still valid */
      free(stack);
      N = 0;
      top = -1;
      /* for the sake of argument do this. We need temp to avoid
         a memory leak */
      fprintf(stderr, "out of memory\n");
   }

    /* push here, trivial */
}

int pop(ENTRY *e)
{
    /* e is a non-const pointer. Fill and reset stack top */ 
}