C 无内存泄漏堆栈的Pop实现

C 无内存泄漏堆栈的Pop实现,c,pointers,stack,C,Pointers,Stack,我正在尝试创建我自己的int堆栈(struct int_stack),它是我创建的结构(struct is_节点)的链接列表。我希望这样做时不会出现内存泄漏,但我不知道如何实现pop方法。pop方法接受参数(int_堆栈)并返回一个int。假设node_容量设置为5,堆栈中有6个int(表示2个节点),一个是满的,一个只有一个int,则调用pop。它应该返回只有1的节点上的int值,但它需要释放节点上的int数组并释放节点。我不知道如何释放一个int,然后返回它,而不会导致内存泄漏。这就是我正在

我正在尝试创建我自己的int堆栈(struct int_stack),它是我创建的结构(struct is_节点)的链接列表。我希望这样做时不会出现内存泄漏,但我不知道如何实现pop方法。pop方法接受参数(int_堆栈)并返回一个int。假设node_容量设置为5,堆栈中有6个int(表示2个节点),一个是满的,一个只有一个int,则调用pop。它应该返回只有1的节点上的int值,但它需要释放节点上的int数组并释放节点。我不知道如何释放一个int,然后返回它,而不会导致内存泄漏。这就是我正在尝试的:

#include <stdio.h>
#include <stdlib.h>
#include "int_stack.h"

struct int_stack *make_stack(int node_capacity) {
  //malloc theseprintf("%d]", temp->contents[i]);
  struct is_node *head;
  struct int_stack *stacky;
  head = malloc(sizeof(struct is_node));
  stacky = malloc(sizeof(struct int_stack));
  stacky->node_capacity = node_capacity;
  head->contents = malloc(node_capacity * sizeof(int));
  head->next_index = 0;
  head->next = NULL;
  stacky->size = 0;
  stacky->head = head;
  return stacky;
}

void free_stack(struct int_stack *stk) {
  struct is_node *pointee;
  pointee = stk->head;
  while (stk->head->next != NULL) {
    pointee = stk->head->next;
    free(stk->head->contents);
    free(stk->head);
    stk->head = pointee;
  }
  free(stk->head->contents);
  free(stk->head);
  free(stk);
}

void reset_stack(struct int_stack *stk) {
  struct is_node *temp;
  while (stk->head->next != NULL) {
    temp = stk->head->next;
    free(stk->head->contents);
    free(stk->head);
    stk->head = temp;
  }
  stk->size = 0;
  stk->head->contents = NULL;
  stk->head->next_index = 0;
}

void print_stack(struct int_stack *stk) {
  struct is_node *temp;
  int i;
  temp = stk->head;
  i = temp->next_index - 1;
  if (is_empty(stk) == 1) {
    printf("(]");
  }
  while (i >= 0) {
    if (i == temp->next_index - 1) {
      if (i == stk->node_capacity - 1) {
        if (i == 0) {
          printf("[%d]",temp->contents[i]);
        } else {
          printf("[%d,",temp->contents[i]);
      }
      } else if (i == 0) {
        printf("(%d]",temp->contents[i]);
      } else {
        printf("(%d,",temp->contents[i]);
      }
    } else {
      if (i == 0) {
        printf("%d]", temp->contents[i]);
      } else {
        printf("%d,",temp->contents[i]);
      }
    }
    if (i == 0 && temp->next != NULL) {
      temp = temp->next;
      i = temp->next_index;
    }
    --i;
  }
  printf("\n");
}

int is_empty(struct int_stack *stk) {
  if (stk->size == 0) {
    return 1;
  }
  return 0;
}

void push(struct int_stack *stk, int v) {
  stk->size++;
  int i = stk->head->next_index;
  if ((stk->size % stk->node_capacity == 1 && stk->size > stk->node_capacity) || (stk->node_capacity == 1)) {
    struct is_node *new_head;
    new_head = malloc(sizeof(struct is_node));
    new_head->contents = malloc(sizeof(stk->node_capacity * sizeof(int)));
    new_head->next = stk->head;
    new_head->next_index = 1;
    new_head->contents[0] = v;
    stk->head = new_head;
  } else {
    stk->head->contents[i] = v;
    stk->head->next_index = realloc();
  }
}

int pop(struct int_stack *stk) {
  int pop_val;
  struct is_node *temp;
  if (is_empty(stk) == 1) {
    return -1;
  } else if (stk->head->next_index == 1) {
    pop_val = stk->head->contents[0];
    stk->size = stk->size - 1;
    stk->head->next_index = 0;
    if (stk->head->next != NULL) {
      temp = stk->head->next;
      free(stk->head->contents);
      free(stk->head);
      stk->head = temp;
    }
    return pop_val;
  } else {
    pop_val = stk->head->contents[stk->head->next_index - 1];
    stk->head->next_index = stk->head->next_index - 1;
    stk->size = stk->size - 1;
    return pop_val;
  }
}

int top(struct int_stack *stk) {
  if (is_empty(stk) != 1) {
    return stk->head->contents[stk->head->next_index - 1];
  }
  return -1;
}

在这种情况下,您的返回值pop_val不会泄漏。作为一个局部变量,它是在堆栈上分配的,而不是在堆上分配的,不需要释放。

问题是您希望动态分配或释放堆栈的节点

现在让我们来考虑一下这个设计,它有两个部分:-

  • 您正在创建一个head节点,它将基本上存储关于列表以及列表开头的所有元信息

  • 在使用动态创建的数组之前。现在让我们更仔细地研究一下。要删除堆栈的一个节点(堆栈节点),您必须删除整个分配的
    内容
    ,并使用所有其他元素创建一个新的。这是一种方法,但它非常低效,因为它为每个pop分配分配分配等

  • 稍微改变一下设计怎么样


    保持头部节点与之前一样。然后保留一个
    堆栈节点*
    。现在,每次推送时,创建一个新的堆栈节点,然后将其添加到
    头部
    。类似地,当您弹出时,只需从
    头部
    中删除该节点。不需要保留数组。只需将数据放在单独的节点中即可。这将使您的代码变得非常简单。

    如果它是一个链表,那么
    size
    node\u capacity
    完全没有必要;您只需浏览列表,如果没有
    下一步
    ,则您位于末尾。对于如此简单的任务,您的代码似乎过于复杂。建议您回到绘图板。如果您只存储
    int
    ,为什么要为它们分配内存?只需将
    int
    放在节点中。@PaulOgilvie我猜他们在每个节点上存储int块,以增加缓存命中的机会。不是堆堆堆栈,我首先考虑的是如何处理这个问题,但是对于这个结构有“潜在的用例”。它是一个赋值,是的,它是一个堆栈,它由保持一个数组的节点组成,用户可以通过设置节点容量来选择数组的大小。我将更新此文件以包含生成堆栈的方法。使用push更新
     struct is_node {
       int *contents;
       int next_index;
       struct is_node *next;
     };
    
     struct int_stack {
       int size;
       int node_capacity;
       struct is_node *head;
     };