2015-04-25 50 views
0

我正在寫一個計算器從C從頭開始(家庭作業),並有內存的地方麻煩..算法完美,但我得到一組Valgrind錯誤/警告,例如:在C計算器memcheck的問題

echo -n「1」|的valgrind ./a.out --track-起源=是

==14261== Conditional jump or move depends on uninitialised value(s) 
==14261== at 0x400B9F: create_rpn (main.c:53) 
==14261== by 0x400742: main (main.c:253) 

我生成文件:

all: 
    gcc main.c -g -O2 -Wall -Werror -std=c99 

我的源代碼是下面(and on GitHub)。你能幫忙嗎?先謝謝你!

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

#define MAX_LEN 1024 

// needs to check priority 
int get_power(char op) { 
    if (op == '+') { 
     return 2; 
    } else if (op == '-') { 
     return 2; 
    } else if (op == '*') { 
     return 4; 
    } else if (op == '/') { 
     return 4; 
    } else { 
     return 0; 
    } 
} 


// checks if current char is operator 
int is_operator(char op) { 
    if (op == '+' || op == '-' || op == '*' || op == '/') { 
     return 1; 
    } else { 
     return 0; 
    } 
} 


// checks if current char is digit 
int is_digit(char op) { 
    if ((op >= '0' && op <= '9') || op == '.') { 
     return 1; 
    } else { 
     return 0; 
    } 
} 


// evaulates array in Postfix 
double evaulate_rpn(char** exp, size_t len) { 
    double* stack = (double*) malloc(len*sizeof(double)); // stack for operands 
    double a1 = 0.0; 
    double a2 = 0.0; // buffers to save stack items 
    size_t place = 0; // current stack size 
    for (size_t i = 0; i < len; ++i) { 
     if (is_operator(*exp[i]) == 1) { 
      // takes out last 2 operands, processes 
      if (place > 1) { 
       a1 = stack[place - 2]; 
       a2 = stack[place - 1]; 

       if (strncmp(exp[i], "+", 1) == 0) { 
        stack[place - 2] = a1 + a2; 
       } else if (strncmp(exp[i], "-", 1) == 0) { 
        stack[place - 2] = a1 - a2; 
       } else if (strncmp(exp[i], "*", 1) == 0) { 
        stack[place - 2] = a1 * a2; 
       } else if (strncmp(exp[i], "/", 1) == 0) { 
        stack[place - 2] = a1/a2; 
       } 
       place -= 1; 

      } else if (place == 1) { 
       // unary minus, unary plus.. 
       a1 = stack[place - 1]; 

       if (strncmp(exp[i], "-", 1) == 0) { 
        stack[place - 1] = 0 - a1; 
       } else if (strncmp(exp[i], "+", 1) == 0) { 
        stack[place - 1] = a1; 
       } 

      } else { 
       // wrong order/anything else 
       printf("[error]"); 
       exit(0); 
      } 
     } else { 
      // is operand -> convert char to double -> save double to stack 
      stack[place] = atof(exp[i]); 
      place++ ; 
     } 
    } 
    float res = stack[0]; 
    free(stack); 
    return res; // result here 
} 


void push_to_stack(char*** reverse, size_t* inited_lines, size_t* used_lines, char* item, size_t size) { 
    if(*inited_lines <= *used_lines){ 
     *inited_lines *= 2; 
     char** buf = (char**) realloc(*reverse, (*inited_lines)*sizeof(char**)); 
     if (buf) { 
      *reverse = buf; 
     } else { 
      printf("[error]"); 
      exit(0); 
     } 
    } 
    char* str = calloc(size + 1, sizeof(char)); 
    if (str) { 
     memcpy(str, item, size + 1); 
     str[size] = '\0'; 

     (*reverse)[*used_lines] = str; 
     (*used_lines)++ ; 
    } else { 
     printf("[error]"); 
     exit(0); 
    } 
} 


// transform from Infix to Postfix notation 
double create_rpn(char* exp, size_t len){ 

    // stack of chars for operands()+-*/ 
    char* stack = (char*) malloc(len); 
    if (stack == NULL) { 
     printf("[error]"); 
     exit(0); 
    } 
    size_t stack_top = 0; // position of last item in stack 

    // array of numbers 
    size_t inited_lines = 1; 
    size_t used_lines = 0; 
    char** reverse = (char**) malloc(inited_lines*sizeof(char*)); 
    if (reverse == NULL) { 
     printf("[error]"); 
     exit(0); 
    } 

    char buffer = 0; 
    int bracket_deep = 0; 
    int digit = 0; // flag to start parsing Numbers/digits 
    size_t start_index = 0; // for parsing Long-Vals 
    size_t index = 0; 
    while (index <= len) { 
     buffer = exp[index]; // buffer constats only 1 char but it is a string 
     if (is_digit(buffer) == 1) { 
      // save first digit place 
      if (digit == 0) { 
       start_index = index; 
       digit = 1; 
      } 
     } else { 
      // push to stack when Num is over 
      if (digit == 1) { 
       digit = 0; 
       size_t size = index - start_index; // size of str 
       push_to_stack(&reverse, &inited_lines, &used_lines, exp + start_index, size); 
      } 

      // push Operands + check priority 
      if (is_operator(buffer) == 1) { 
       size_t power = get_power(buffer); 
       for (int i = stack_top - 1; i >= 0; --i) { 
        if (stack[i] == '(') { 
         break; 
        } 
        if (get_power(stack[i]) >= power) { 
         push_to_stack(&reverse, &inited_lines, &used_lines, &stack[i], 1); 
         stack_top-- ; 
        } 
       } 
       // push current Operand to stack 
       stack[stack_top++ ] = buffer; 

      } else if (buffer == '(') { 
       stack[stack_top++ ] = buffer; 
       bracket_deep++ ; 

      } else if (buffer == ')') { 
       // push operands to result 
       bracket_deep-- ; 
       stack_top-- ; // if no, '' will be added to output 
       while (stack[stack_top] != '(') { 
        push_to_stack(&reverse, &inited_lines, &used_lines, &stack[stack_top], 1); 
        if (stack_top > 0) { 
         stack_top-- ; 
        } else { 
         break; 
        } 
       } 
      } else if (buffer == ' ' || buffer == '\n') { 
       // ignore this case 

      } else if (buffer == '\0') { 
       for (int i = stack_top - 1; i >= 0; --i) { 
        push_to_stack(&reverse, &inited_lines, &used_lines, &stack[i], 1); 
       } 
       stack_top = 0; 
      } else { 
       printf("[error]"); // - wrong char: '%s', %c\n", buffer, *buffer); // wrong char! 
       exit(0); 
      } 
     } 
     if (bracket_deep < 0) { 
      printf("[error]"); // wrong bracket expr 
      exit(0); 
     } 
     index++ ; 
    } 
    free(stack); 

    if (bracket_deep == 0) { 
     double res = evaulate_rpn(reverse, used_lines); 
     for (int i = 0; i < inited_lines; i++) { 
      free(reverse[i]); 
     } 
     free(reverse); 
     return res; 
    } else { 
     printf("[error]"); // wrong brackets 
     exit(0); 
    } 
} 


int main() { 
    char* expression = (char*) malloc(MAX_LEN*sizeof(char)); 
    if (expression) { 
     size_t len = 0; 
     while (scanf("%c", &expression[len]) != -1) { // switch to getch ??? 
      if (expression[len] != ' ') { // save everything except spaces 
       len++ ; 
      } 
     } 
     double result = create_rpn(expression, len); 
     printf("%.2f", result); 
     free(expression); 
    } else { 
     printf("[error]"); 
     exit(0); 
    } 
    return 0; 
} 
+0

不要[鑄造的malloc'()的結果'](http://stackoverflow.com/a/605858/1983495) –

回答

3

你正在讀1個字節綁定的數組超越,因爲你while迴路create_rpn()

while (index <= len) 

而應該是

while (index < len) 
    /*  ^without the = */ 

因爲數組是0索引,exp[len]超出陣列。

而且

  1. 避免多餘的括號,他們使代碼醜陋,因此,難以閱讀和理解。

  2. 不要cast the return value of malloc(),閱讀鏈接,你會明白爲什麼。

  3. 使代碼更清晰的另一個技巧是避免將代碼與聲明混合在一起,對於編譯器來說,很容易看到變量的作用域,而不是眼睛。

+0

exp爲一個字符串,所以EXP [長度] = '\ 0' – Vladimir

+0

@Vladimir它不是,檢查你的代碼,它是你的代碼?即使它是,爲什麼你會做一個額外的迭代?如果你是對的,那麼'while(exp [index]!= 0)'會更好。 –

+0

是的,它是我的。我已經調試過這一刻,而exp [len]實際上返回字符串尾部 – Vladimir