Memory 二叉树初始化函数中的内存泄漏

Memory 二叉树初始化函数中的内存泄漏,memory,memory-leaks,stack,binary-tree,valgrind,Memory,Memory Leaks,Stack,Binary Tree,Valgrind,我试图根据C中的后缀用户输入字符串生成并计算二叉表达式树。然而,我的二叉树初始化函数导致内存泄漏。总结一下我的算法,用户输入一个后缀字符串,由函数解析并组装到树中。以下是我的完整代码: #include <stdio.h> #include <stdlib.h> #include <string.h> #define TRUE 1 #define FALSE 0 // Define binary expression tree data structure

我试图根据C中的后缀用户输入字符串生成并计算二叉表达式树。然而,我的二叉树初始化函数导致内存泄漏。总结一下我的算法,用户输入一个后缀字符串,由函数解析并组装到树中。以下是我的完整代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define TRUE 1
#define FALSE 0

// Define binary expression tree data structure
typedef struct binExpTree {

  char *val;
  struct binExpTree *left;
  struct binExpTree *right;

} expTree;

// Define expression tree stack data structure
typedef struct expTreeStack {

  int height;
  int used;
  expTree **expTreeDarr;

} treeStack;

// Function prototypes
void initStack(treeStack *stack);

expTree * getTopStack(treeStack *stack);

int isEmptyStack(treeStack *stack);

void pushStack(treeStack *stack, expTree *treeNode);

expTree * popStack(treeStack *stack);

void clearStack(treeStack *stack);

expTree * initTree(char *val);

void printCommands();

expTree * parseExpression(char *expString);

void clearTree(expTree *rootNode);

void printInfix(expTree *rootNode);

void printPrefix(expTree *rootNode);

int evalExpression(expTree *rootNode);






/* File contains all functions necessary for stack operations */

// Initialize empty binary tree stack of size 4
void initStack(treeStack *stack) {

  stack->height = 4;
  stack->used   = 0;
  stack->expTreeDarr = (expTree **)malloc(sizeof(expTree *) * stack->height);

}

// Return the tree node from the stack's top
expTree * getTopStack(treeStack *stack) {

  if (stack->used > 0) {
    return stack->expTreeDarr[stack->used - 1];
  }
  else {
    return NULL;
  }

}

// Discern whether tree stack is empty
int isEmptyStack(treeStack *stack) {

  if (stack->used == 0) {
    return TRUE;
  }
  else {
    return FALSE;
  }

}

// Push tree node pointer onto stack
void pushStack(treeStack *stack, expTree *treeNode) {

  if (stack->used == stack->height) {
    expTree **expTreeTmp = stack->expTreeDarr;
    stack->height += 4;
    stack->expTreeDarr = (expTree **)malloc(sizeof(expTree *) * stack->height);

    for (int i = 0; i < stack->used; i++) {
      stack->expTreeDarr[i] = expTreeTmp[i];
      //free(expTreeTmp[i]);
    }
    free(expTreeTmp);
  }

  stack->expTreeDarr[stack->used] = treeNode;
  stack->used = stack->used + 1;
}

// Pop tree node pointer from the stack
expTree * popStack(treeStack *stack) {
  
  expTree *stackTmp = getTopStack(stack);
  expTree *newNode = (expTree *)malloc(sizeof(expTree));
  *newNode = *stackTmp;
  
  stack->used -= 1;

  return newNode;
}

// Empty stack of all data (make sure this works)
void clearStack(treeStack *stack) {

  for (int i = 0; i < stack->used; i++) {
    clearTree(stack->expTreeDarr[i]);
  }

  free(stack->expTreeDarr);
  stack->used   = 0;
  stack->height = 0;

}

/* File contains all functions necessary for binary tree operations */

// Initialize binary expression tree with specified operator/operand

expTree * initTree(char *val) {

  expTree *newTree = (expTree *)malloc(sizeof(expTree));
  newTree->val = (char *)malloc(strlen(val) + 1);
  strcpy(newTree->val, val);
  newTree->left  = NULL;
  newTree->right = NULL;

  return newTree;

}


// Print commands available to the user
void printCommands() {
 
  printf("The commands for this program are:\n\n");
  printf("q - to quit the program\n");
  printf("? - to list the accepted commands\n");
  printf("or any postfix mathematical expression using the operators of *, /, +, -\n");

}

// Return size of binary expression tree
int sizeTree(expTree *treeNode) {

  if (treeNode == NULL) {
    return 0;
  }
  else {
    return 1 + sizeTree(treeNode->left) + sizeTree(treeNode->right);
  }

}

// Construct a postfix binary expression tree from expression string
expTree * parseExpression(char *expString) {
  
  char *expStringCopy = (char *)malloc(strlen(expString) + 1);
  expTree *treeNode;
  treeStack expStack;
  initStack(&expStack);

  strcpy(expStringCopy, expString);
  char *expStringTok = strtok(expStringCopy, " ");

  while (expStringTok != NULL) {
    
    if (*expStringTok == '+' || *expStringTok == '-' ||
        *expStringTok == '*' || *expStringTok == '/') {
      if (expStack.used < 2) {
        return NULL;
      }
      treeNode = initTree(expStringTok);
      treeNode->right = popStack(&expStack);
      treeNode->left  = popStack(&expStack);
      pushStack(&expStack, treeNode);
    }
    else {
    
      treeNode = initTree(expStringTok);
      pushStack(&expStack, treeNode);
    
    }
    expStringTok = strtok(NULL, " ");
  }
  if (expStack.used > 1 || (*(treeNode->val) != '+' && *(treeNode->val) != '-' &&
                            *(treeNode->val) != '*' && *(treeNode->val) != '/')) {
    return NULL;
  }
  free(expStringCopy);
  treeNode = popStack(&expStack);
  clearStack(&expStack);
  return treeNode;
}

// Clear binary expression tree
void clearTree(expTree *rootNode) {
  if (rootNode == NULL) {
    return;
  }
  else {
    clearTree(rootNode->left);
    clearTree(rootNode->right);

    free(rootNode->val);
    free(rootNode);
  }
}

// Print infix notation of expression
void printInfix(expTree *rootNode) {
  if (rootNode == NULL) {
    return;
  }
  else {
    if (*(rootNode->val) == '+' || *(rootNode->val) == '-' ||
        *(rootNode->val) == '*' || *(rootNode->val) == '/') {
        printf("( ");
    }

    printInfix(rootNode->left);
    printf(" %s ", rootNode->val);
    printInfix(rootNode->right);
  
    if (*(rootNode->val) == '+' || *(rootNode->val) == '-' ||
        *(rootNode->val) == '*' || *(rootNode->val) == '/') {
        printf(" )");
    }
  }
}

// Print prefix notation of expression
void printPrefix(expTree *rootNode) {
  if (rootNode == NULL) {
    return;
  }
  else {
    printf(" %s ", rootNode->val);

    printPrefix(rootNode->left);
    printPrefix(rootNode->right);
  }
}

// Evaluate the expression tree
int evalExpression(expTree *rootNode) {
  
  char op;

  if (*(rootNode->val) == '+') {
    return evalExpression(rootNode->left) + evalExpression(rootNode->right);
  }
  else if (*(rootNode->val) == '-') {
    return evalExpression(rootNode->left) - evalExpression(rootNode->right);
  }
  else if (*(rootNode->val) == '*') {
    return evalExpression(rootNode->left) * evalExpression(rootNode->right);
  }
  else if (*(rootNode->val) == '/') {
    return evalExpression(rootNode->left) / evalExpression(rootNode->right);
  }
  else {
    return atoi(rootNode->val);
  }
}




int main(int argc, char const *argv[])
{


  char input[300];
  expTree *expPostfix;

  /* set up an infinite loop */
  while (1)
  {


    fgets(input,300,stdin);
    /* remove the newline character from the input */
    int i = 0;

    while (input[i] != '\n' && input[i] != '\0') {
        i++;
    }   
    input[i] = '\0';

    /* check if user enter q or Q to quit program */
    if ( (strcmp (input, "q") == 0) || (strcmp (input, "Q") == 0) )
      break;
    /* check if user enter ? to see command list */
    else if ( strcmp (input, "?") == 0)
      printCommands();

    /* user enters an expression */
    else {
        // Parse the expression into a binary expression tree
    printf("%s\n", input);
    expPostfix = parseExpression(input);
        
        // Discern whether expression is valid
    if (expPostfix == NULL) {
          printf("Invalid expression. Enter a valid postfix expression \n");
          continue;
    }

    // Print the expression in infix notation
        printf("Infix notation: ");
    printInfix(expPostfix);
        printf("\n");
        
    // Print the expression in prefix notation
        printf("Prefix notation: ");
    printPrefix(expPostfix);
        printf("\n");
        
    // Print the expression in postfix notation
        printf("Postfix notation: ");
    printf("%s\n", input);

    // Evaluate expression and print result
        printf("Expression result: %d \n\n", evalExpression(expPostfix));
    
    clearTree(expPostfix);
    }
   }

  printf("\nGoodbye\n");

  return 0;
}

看来罪魁祸首是我的initTree()函数。然而,我无法理解为什么这段记忆会丢失。我希望这不是太多的代码。这是以前的编辑,有人告诉我没有足够的信息继续进行。

泄漏是由popStack引起的,因为stackTmp的目标在函数退出时泄漏:

expTree * popStack(treeStack *stack) {
  
  expTree *stackTmp = getTopStack(stack);
  expTree *newNode = (expTree *)malloc(sizeof(expTree));
  *newNode = *stackTmp;

  stack->used -= 1;

  return newNode;
}
鉴于堆栈似乎是树的独占所有者,并且不再有指向它的指针,popStack可以通过不制作副本并返回原始文件来避免泄漏:

expTree * popStack(treeStack *stack) { 
  expTree *topNode = getTopStack(stack);
  stack->used -= 1;
  return topNode;
}

您可以使用strdup而不是malloc+strcpy。不要强制转换malloc()的结果。这就是空虚的意义。在clearTree()中,如果返回,则不需要else。initTree和clearTree使用相同数量的malloc/free,所以我猜您不会在某个地方更新initTree()的结果。你的问题很好,它只是不完整,所以我们无法运行代码来调试它。proj4base_38.c:194是哪一行?请参阅从输入中删除换行符的更简洁方法*/is
input[strcspn(input,“\n”)]='\0'。您的代码不会从
fgets()
测试EOF;应该的!我建议你应该怀疑地看待
而(1)
循环。它们有时是必要的,但它们的必要性要比使用它们的频率低得多。使用
while(gets(input,sizeof(input),stdin))
修复这两个问题(并避免不必要地重复300次)。我复制的原因是我需要在退出parseExpression()时清除堆栈。如果我只是从堆栈返回同一个指针,那么一旦清除堆栈,我就不能再使用它,因为树节点parseExpression返回指向堆栈中某个节点的点。您正在弹出堆栈的顶部,因此该项不再存在以进行清除。请尝试更改。EXPTRESTACK中EXPTREDARR中的活动项目数由使用的字段确定。程序seg错误。关于我错误地使用堆栈->使用而不是堆栈->高度,你是对的。clearStack()永远不会清除堆栈,因为在调用堆栈时,stack->used为0。但是,将clearStack()中的for循环范围从used更改为height后,将无法读取从parseExpression()返回的treeNode。这就是我现在试图解决的问题。你的建议确实为我指明了正确的方向。我的观点是,使用决定了活动项目的数量,但我的意思不是说这被解释为以任何方式改变clearStack的建议。我的观点是,当popStack从堆栈中删除一个条目时,删除的条目中的值是没有意义的。高度字段的名称错误,因为它实际上表示动态分配的缓冲区存储堆栈项的容量。我的建议是,您回到问题中发布的原始程序(对clearStack没有任何更改),并按照我所描述的那样更改popStack。这很有效。
expTree * popStack(treeStack *stack) { 
  expTree *topNode = getTopStack(stack);
  stack->used -= 1;
  return topNode;
}