2015-05-04 3 views
0

Я пытаюсь создать постфиксный калькулятор, используя связанный список. , когда я компилирую, он не показывает никаких ошибок, но когда он будет выполнен, будет отображаться ошибка сегментации. Я не знаю, как с этим справиться, пожалуйста, помогите. вот мой код:постфикс калькулятор, имеющий проблемы с segfaults

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

typedef struct node { 
    int num; 
    struct node *next; 
} node; 

void push(int num, node **head); 
int pop(node **head); 
void display(node **head); 
int is_empty(); 
int evaluatePostfix(); 

struct node *head; 

int main() { 
    head = NULL; 
    char exp[1000]; // = "5 1 2 + 4 * + 3 -"; 
    printf("Input expression:\t"); 
    fgets(exp, 1000, stdin); 
    for(int i = 1; i <= strlen(exp); i++) { 
     if(exp[i] == '\n') { 
      exp[i] = '\0'; 
     } 
     else if (exp[0] == '\n') { 
      printf("stack is empty\n"); 
      exit(0); 
     } 
    } 
    printf("%s = %d\n", exp, evaluatePostfix(exp)); 

    return 0; 

}

int evaluatePostfix(char* exp) { 
    char * token; 
    int counter = 0; 
    char temp[256][256]; 
    token = strtok(exp, " "); 
    while(token != NULL) { 
     strcpy(temp[counter], token); 
     counter++; 
     token = strtok(NULL, " "); 
    } 

    for (int i = 0; temp[i]; ++i) { 
     if (isdigit(*(temp[i]))) { 
      int val = atoi(temp[i]); 
      push(val, &head); 
     } 
     else { 
      int val1 = pop(&head); 
      int val2 = pop(&head); 
      switch (exp[i]) { 
       case '+': push(val2 + val1, &head); 
          printf("%d\n", (*head).num); 
          break; 
       case '-': push(val2 - val1, &head); break; 
       case '*': push(val2 * val1, &head); break; 
       case '/': push(val1/val2, &head); break; 
      } 
     } 
    } 
    return pop(&head); 
} 


void push (int item, node **head) { 
    node *temp; 
    node * get_node(int); 
    temp = get_node(item); 
    temp->next = *head; 
    *head = temp; 
} 

node *get_node(int item) { 
    node *temp; 
    temp = (node*)malloc(sizeof(node)); 
    if (temp == NULL) 
     printf("\nMemory cannot be allocated"); 
    temp->num = item; 
    temp->next = NULL; 
    return(temp); 
} 


int pop(node **head) { 
    int item; 
    node *temp; 
    item = (*head)->num; 
    temp = *head; 
    *head = (*head)->next; 
    free(temp); 
    return(item); 
} 

int is_empty(node *temp) { 
    if (temp == NULL) 
     return 1; 
    else 
     return 0; 
} 


void display(node **head) { 
    node *temp; 
    temp = *head; 
    if(head == NULL) { 
     printf("stack is empty\n"); 
     return; 
    } 
    printf("\n"); 
    printf("=========\n"); 
    while(temp!=NULL) { 
     printf("%d\n", (*temp).num); 
     temp = (*temp).next; 
    } 
    printf("=========\n"); 
} 
+1

Это довольно длинный кусок кода, чтобы увидеть проблему сразу. Вы должны использовать отладчик. –

+0

Есть более простые способы удаления новой строки из строки, считанной 'fgets', чем ваш цикл. Если (и только если) 'fgets' не возвращает указатель' NULL', то возможная новая строка будет, например, 'exp [strlen (exp) - 1]'. –

+0

Я думаю, проблема связана с методом оценкиPostfix(), но я не уверен, как это исправить. какой отладчик вы предлагаете? – pixiedust27

ответ

1

Учитывая это заявление ...

char temp[256][256]; 

... условие завершения цикла здесь не так:

for (int i = 0; temp[i]; ++i) { 

C multi-dimens циональные массивы: не Java-массивы массива ссылки. Это массивы реальных массивов. Выражение temp[i] не будет ложным, если i превысит количество элементов temp[], в которые вы написали данные.

Похоже, что вы хотите просто

for (int i = 0; i < counter; ++i) { 

. Кроме того, нет особой необходимости в токенизации перед началом вычислений. Вы могли бы легко объединить две петли в функции evaluatePostfix() в один. Это было бы немного проще и удалило бы любое фиксированное ограничение на количество терминов в выражении.

Update: Это может выглядеть следующим образом:

for (token = strtok(exp, " "); token; token = strtok(NULL, " ")) { 

    /* ... use token instead of temp[i] ... */ 

} 

Вполне возможно, что есть и другие ошибки в коде, а также, хотя я не заметил какой-либо на моем сканировании через него.

+0

Да, я также пытался использовать for (int i = 0; i pixiedust27

+0

Я не сказал, что вы можете оценить без токенизации.Я сказал, что вы можете оценить без токенизации * отдельно *. Я обновил свой ответ, чтобы показать, как это сделать. –

+0

Можно предположить, что у вас есть одна или несколько других ошибок, которые также вызывают segfault, несмотря на то, что я был обнаружен. В этом случае лучшим способом разобраться в этом будет отладчик вашего инструментария и/или инструмент, специфичный для идентификации проблем памяти, таких как valgrind. –

0

«Кстати, все идентификаторы для функций в стандартной библиотеке защищены. Существует функция ехр() в math.h, так ехр попадает в эту категорию. Технически, используя зарезервированный идентификатор в результатах кода в неопределенное поведение ".

Спасибо за помощь, ребята! Изменение exp на другое имя переменной сделало трюк. вот рабочий код до сих пор:

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

typedef struct node { 
    int num; 
    struct node *next; 
} node; 

void push(int num, node **head); 
int pop(node **head); 
void display(node **head); 
int is_empty(node *temp); 
int evaluate(char *expression); 

struct node *head; 

int main() { 
    head = NULL; 
    char expression[1000]; // = "5 1 2 + 4 * + 3 -"; 
    printf("Input expression:\t"); 
    fgets(expression, 1000, stdin); 
    for(int i = 1; i <= strlen(expression); i++) { 
     if(expression[i] == '\n') { 
      expression[i] = '\0'; 
     } 
     else if (expression[0] == '\n') { 
      printf("empty stack\n"); 
      exit(0); 
     } 
    } 

    printf("Answer: %d\n", evaluate(expression)); 
    return 0; 

}

int evaluate(char* expression) { 
    char * token; 
    int counter = 0; 
    char temp[256][256]; 
    token = strtok(expression, " "); 
    while(token != NULL) { 
     strcpy(temp[counter], token); 
     token = strtok(NULL, " "); 
     counter++; 
    } 

    for (int i = 0; i < counter; i++) { 
     if (isdigit(*(temp[i]))) { 
      int val = atoi(temp[i]); 
      push(val, &head); 
     } 
     else { 
      int val1 = pop(&head); //pop the last two values from stack 
      int val2 = pop(&head); 
      switch (*(temp[i])) { //perform operation 
       case '+': push(val2 + val1, &head); break; 
       case '-': push(val2 - val1, &head); break; 
       case '*': push(val2 * val1, &head); break; 
       case '/': push(val1/val2, &head); break; 
      } 
     } 
    } 
    return pop(&head); 
} 

void push (int item, node **head) { 
    node *temp; 
    node * get_node(int); 
    temp = get_node(item); 
    temp->next = *head; 
    *head = temp; 
} 

node *get_node(int item) { 
    node *temp; 
    temp = (node*)malloc(sizeof(node)); 
    if (temp == NULL) 
     printf("\nMemory cannot be allocated"); 
    temp->num = item; 
    temp->next = NULL; 
    return(temp); 
} 

int pop(node **head) { 
    int item; 
    node *temp; 
    item = (*head)->num; 
    temp = *head; 
    *head = (*head)->next; 
    free(temp); 
    return(item); 
} 

int is_empty(node *temp) { 
    if (temp == NULL) 
     return 1; 
    else 
     return 0; 
} 

void display(node **head) { 
    node *temp; 
    temp = *head; 
    if(head == NULL) { 
     printf("stack is empty\n"); 
     return; 
    } 
    printf("\n"); 
    printf("=========\n"); 
    while(temp!=NULL) { 
     printf("%d\n", (*temp).num); 
     temp = (*temp).next; 
    } 
    printf("=========\n"); 
} 
+0

«Технически, использование зарезервированного идентификатора в вашем коде приводит к неопределенному поведению». Да, но имя стандартной библиотечной функции 'exp()' зарезервировано * только * как идентификатор с внешней связью. Аргументы функции и локальные переменные имеют * no * linkage. Использование 'exp' в качестве имени локальной переменной не создает UB. –