2016-12-05 5 views
2

Я пытаюсь создать балансировщик HTML-тегов, используя стек. Программа читает символ символа HTML по символу, и всякий раз, когда он встречает открытый тег, он добавляет его в стек. Если он встречает тег close, он пытается удалить его из стека. Однако код компилируется правильно, когда я выполняю его с valgrind, он производит другой и более правильный вывод, чем когда я запускаю его без valgrind. Например:Когда я запускаю этот код с valgrind, выполняется по-другому, когда я запускаю его без valgrind

<html> 
<body> 

<h1>My First Heading</h1> 

<p>My first paragraph.</p> 
<p>Hello 

</body> 
</html> 

Когда я запускаю программу предыдущего файла без Valgrind он выходит давая это сообщение:

Error: 
The stack is not empty at the end of the file 
Stack: 

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

Error: 
Line Number:9 
The close tag, body, doesn't match the most recent open tag, p 

Вот источник:

#include<stdio.h> 
    #include<stdlib.h> 
    #include<stdbool.h> 
    #include<assert.h> 
    //#define DEBUG 
    struct node 
    { 
      char* datum; 
      struct node* next; 
    }; 
    typedef struct node Node; 
    struct stack 
    { 
      Node* top; 
    }; 
    typedef struct stack Stack; 
    bool isEmpty(Stack* s); 
    char* pop(Stack* s); 
    void push(Stack* s, char* newItem); 
    char* peek(Stack* s); 
    void printStack(Node* s); 
    size_t size(Stack* s); 
    Node* makeNode(char* x); 
    void freeStack(Stack** s); 

    int lineNumber = 1; 

    int main(int argc, char** argv) 
    { 
      Stack * s = malloc(sizeof(Stack)); 
      s -> top = NULL; 
      char* tag; 
      int size; 
      if(argv[1] == NULL) 
      { 
       printf("ERROR: Filename is NULL...Bailing"); 
       exit(1); 
      } 
      FILE* htmlFile = fopen(argv[1], "r"); 
      char ch; 
      //int lineNumber = 1; 
      while((ch = fgetc(htmlFile)) != EOF && ch != '\n') 
      { 

      } 
      if(ch == EOF) 
      { 
       printf("The file id not valid"); 
       free(s); 
       free(tag); 
       fclose(htmlFile); 
       exit(3); 
      } 

      while((ch = fgetc(htmlFile)) != EOF) 
      { 
       //printf("Line Number: %d\n", lineNumber); 
       if(ch == '\n') 
       { 
        lineNumber++; 
       } 
       if(ch == '<') 
       { 
        tag = malloc(64*sizeof(char)); 
        size = 0; 
        while((ch = fgetc(htmlFile)) != EOF && ch != ' ' && 
         ch != '>' && ch != '/') 
        { 
         //printf("ch = %c\n", ch); 
         tag[size] = ch; 
         size++; 
         if(ch == '\n') 
         { 
          lineNumber++; 
         } 
        } 
        if(ch == ' ') 
        { 
         //Read through the rest of the tag and see if it is self-closing 
         while((ch = fgetc(htmlFile)) != EOF && 
          ch != '>' && ch != '/') 
         { 
          //Don't care about the rest of the tag 
         } 
         if(ch == EOF) 
         { 
          //print ERROR 
          printf("Error:\nLine Number: %d\nFile ended during the middle of a tag\n", lineNumber); 
          free(s); 
          free(tag); 
          fclose(htmlFile); 
          exit(2); 
         } 
         else if(ch == '>') 
         { 
          //Add tag to stack 
          push(s, tag); 
         } 
         else if(ch == '/') 
         { 
          //Don't worry about it 
         } 
        } 
        else if(ch == '>') 
        { 
         //Add to stack 
         push(s, tag); 
        } 
        else if(ch == '/') 
        { 
         //If size == 0 read the rest of the tag and remove it 
         //Else dont worry about it 
         if(size == 0) 
         { 
          while((ch = fgetc(htmlFile)) != EOF && ch != ' ' && 
           ch != '>') 
          { 
           //printf("ch = %c\n", ch); 
           tag[size] = ch; 
           size++; 
           if(ch == '\n') 
           { 
            lineNumber++; 
           } 
          } 
          tag[size] = '\0'; 
          //printf("Tag: %s\n", tag); 
          if(ch == EOF) 
          { 
           //Print ERROR 
           printf("Error:\nLine Number: %d\nFile ended during the middle of a tag\n", lineNumber); 
           free(s); 
           free(tag); 
           fclose(htmlFile); 
           exit(1); 
          } 
          else if(ch == ' ' || ch == '>') 
          { 
           printf("Tag: %s, Top: %s\n", tag, peek(s)); 

           //Remove tag from stack or ERROR 
           if(strncmp(peek(s), tag, size+1) == 0) 
           { 
            //Remove tag from stack 
            pop(s); 
           } 
           else 
           { 
            //Print ERROR 
            printf("Error:\nLine Number:%d\nThe close tag, %s, doesn't match the most recent open tag, %s\n", lineNumber, tag, peek(s)); 
            freeStack(&s); 
            free(tag); 
            fclose(htmlFile); 
            exit(3); 
           } 
          } 
         } 
        } 
        else if(ch == EOF) 
        { 
         //Print ERROR 
         printf("Error:\nLine Number: %d\nFile ended during the middle of a tag\n", lineNumber); 
         free(s); 
         free(tag); 
         fclose(htmlFile); 
         exit(4); 
        } 
        //printf("Tag: %s\n", tag); 
        //printStack(s->top); 
        //printf("\n"); 
        free(tag); 
       } 
       printStack(s->top); 
       printf("\n"); 
      } 
      if(!isEmpty(s)) 
      { 
       printf("Error:\nThe stack is not empty at the end of the file\nStack:"); 
       printStack(s->top); 
       printf("\n"); 
       free(s); 
       fclose(htmlFile); 
       exit(5); 
      } 
      else 
      { 
       printf("The file is valid and all tags are closed.\n"); 
      } 

      free(s); 
      fclose(htmlFile); 
      //free(htmlFile); 
      //free(tag); 
      exit(0); 
      return 0; 
    } 
+1

Возможно, это не ваша главная проблема, но 'char ch' должно быть' int ch' для сравнения EOF, чтобы быть уверенным в правильной работе, –

+0

Также вы не проверяете ошибку при вызове 'fopen'. –

+0

при компиляции всегда включайте все предупреждения, затем исправьте эти предупреждения. (для 'gcc', при минимальном использовании:' -Wall -Wextra -pedantic' Я также использую: '-Wconversion -std = gnu99') – user3629249

ответ

1

Проблема заключается в том, что ваш код имеет неопределенное поведение и повреждение памяти. Как только это произойдет, все ожидания последовательного поведения разных компиляторов и времени выполнения (например, valgrind) отключены.

Если вы включите предупреждения (-Wall), вы обнаружите, что у вас есть неопределенное поведение.

test.c:52:18: warning: variable 'tag' is uninitialized when used here [-Wuninitialized] 
      free(tag); 
       ^~~ 
test.c:34:18: note: initialize the variable 'tag' to silence this warning 
     char* tag; 
       ^
        = NULL 

Вы также не в состоянии загрузить string.h для strncmp.

test.c:143:32: warning: implicitly declaring library function 'strncmp' with type 'int (const char *, 
     const char *, unsigned long)' [-Wimplicit-function-declaration] 
          if(strncmp(peek(s), tag, size+1) == 0) 
          ^
test.c:143:32: note: include the header <string.h> or explicitly provide a declaration for 'strncmp' 

Возможно, в различных функциях стека существует неопределенное поведение.

Вы также освобождаете стек по всему месту, и по-разному это, вероятно, приводит к освобождению одного и того же указателя несколько раз. И вы часто не можете освободить s->top и все узлы, на которые он указывает, и они указывают.

Как только у вас есть неопределенное поведение и повреждение памяти, все ставки отключены. Странные вещи будут происходить в соответствии с причудами компилятора и его управлением памятью.

Valgrind представляет свою собственную виртуальную машину и управление памятью для выполнения вашего кода. Это будет интерпретировать любое неопределенное поведение по-разному.

Исправьте все ваши предупреждения и исправьте все жалобы на память, которые есть у Valgrind. Затем код должен работать последовательно или без Valgrind.


Как правило, каждая структура должна иметь функцию для ее создания и уничтожения. Это инкапсулирует заботу обо всех различных состояниях, в которых может существовать структура, а также для того, чтобы уничтожить любую прикрепленную к ней память. Так делают Stack_new, Stack_destroy, Node_new, и Node_destroy и никогда malloc или free a Стек иначе.

Например, ...

void Node_destroy(Node *node) { 
    if(node->datum != NULL) { 
     free(node->datum); 
    } 
    if(node->next != NULL && node->next != node) { 
     Node_destroy(node->next); 
    } 
    free(node); 
} 

void Stack_destroy(Stack *stack) { 
    if(stack->top != NULL) { 
     Node_destroy(stack->top); 
    } 
    free(stack); 
} 
+1

Благодарим вас за информацию о -Wall при компиляции –

0

Проблема возникла из моего освобождения «метки» в конце цикла в то время как перед я проверил, если список был пуст. Поскольку я хранил адрес в стеке, я случайно удалил его из стека, когда освободил блок памяти.