2016-03-02 4 views
-4

Я получаю право до такой степени, что не могу объяснить ситуацию, которую я собираюсь описать. Мне нужно ваше внимание, пожалуйста!Неопределенное поведение компьютера после запуска программы C

Вчера я написал программу на C. Программа принимает в качестве входных данных строку и если эта строка в таком виде «PKPKKKPPPKKKP», а именно состоит только «P» и «K» символов он выводит вас ДА или НЕТ , ДА, если для одного символа «P» существует совпадение с символом «K». Точно так же, как мы делаем с проблемой круглых букв '(', ')', только вместо '(' Мне пришлось использовать 'P' и вместо ')', 'K'.

С небольшой помощью отсюда мне удалось закончить программу, и она работала правильно. Я не думаю, что копирование кода поможет кому угодно, но я объясню, как это работает.

Описание программы: программа принимает строку (строка может быть до 500 Длина) в качестве входных данных, если строка состоит только «P» и символы «K» она печатает ДА ​​или НЕТ, а Я описал выше, иначе он отвергает это. Затем он считывает ввод, символ по символу, и когда он находит «P», он помещается в стек, а другой - поп. (Я реализовал стек со связанным списком, поэтому пользователь сможет дать как можно большую строку, которую он хочет (или я так думал ...)). Прежде чем пользователь набрал строку, символ «A» был в стеке. Таким образом, входные данные анализировались программой, символом по символу, и если он обнаружил, что «P» был перенесен в стек, еще раз выложите стек. Если вершина стека в конце была символом «A», программа печатала «ДА», иначе «НЕТ».

Описание проблемы: Так что я сегодня с моим другом, выполняя программу. Все было в порядке. Пока я не передаю в качестве входной строки действительно большую строку, например 300'P и 300'K (и помните, что моя строка - это строка символов [500]). Он напечатал «да». Затем я набрал строку, например 800'P + 800'K. Это не работает правильно. Вот проблема, после этого инцидента, если я нахожу строку, обычную «PKPKPK», она печатает миллионы странных символов (x └ X ╨ x └ X ╨ x). Я не трогаю код, клянусь! Я собрал снова, снова запустил, то же самое! Его как-то не так с моим компьютером (Windows 10). И проблема продолжается до другой программы ... Я попытался создать простую программу, чтобы использовать стек, реализованный со связанным списком. Я нажал на символ «a» и напечатал его. Он печатает «á». Я нажал кнопку «b». Он печатает «h». Я толкнул «d». Он печатает «L».

Очевидно, я не должен был набирать такую ​​огромную строку, потому что предел ее длины был 500. Но проблема все еще существует! Я больше не могу писать программу со связанным списком. Я в отчаянии!

Код:

#include "stdio.h" 
#define FIRST_SYMBOL_IN_STACK 'A' 
#define TRUE 1 
#define FALSE 0 
#define STR_LENGTH 50 
#define YES "YES" 
#define NO "NO" 
#define PLA 'P' 
#define KAL 'K' 

typedef struct node { 
    char simvolo_eisodou; 
    struct node *next; 
} node; 

node *top = NULL; // the top of the stack 

void push(char simvolo_eisodou); //stack function 
int isStackEmpty(); //stack function 
void pop(); //stack function 
void printStack(); //print the current stack elements 
int isInputValid(char *string); 
void printWelcome(); 

int main() { 
    char input_string[STR_LENGTH], apantisi = 'G'; //O xristis mporei na dwsei input_string mikous ews 500 xaraktires 
    push(FIRST_SYMBOL_IN_STACK); 
    int i = 0; 
    scanf("%s", input_string); 

    if (isInputValid(input_string)) { 
     while (input_string[i] != '\0') { 
      if (input_string[i] == PLA) { 
       push(PLA); 
       printStack(); 
      } else { 
       pop(); 
       printStack();; 
      } 
      i++; 
     } 
    } else { 
     printf("Den anagnwristike to %s, input_string=(P|K)*\n"); 
     _exit(-1); 
    } 

    if (top->simvolo_eisodou == FIRST_SYMBOL_IN_STACK) { 
     printf("%s\n", YES); 
    } else { 
     printf("%s\n", NO); 
    } 

    return 0; 
} 

void push(char simvolo_eisodou) { 
    node *newNode = (node*)malloc(sizeof(node)); 
    newNode->simvolo_eisodou = simvolo_eisodou; 
    newNode->next = top; 
    top = newNode; 
    free(newNode); 
} 

int isStackEmpty() { //Thewrw oti i stoiva einai adeia otan i korifi einai to arhiko simvolo 
    if (top->simvolo_eisodou == FIRST_SYMBOL_IN_STACK) { 
     return TRUE; 
    } 
    return FALSE; 
} 

void pop(){ 
    if (isStackEmpty()) { 
     printf("KENO\n"); 
     printf("%s\n", NO); 
     _exit(-1); 
    } 
    node *temp = top; 
    top = top->next; 
    free(temp); 
} 

void printStack() { 
    node *current = top; 
    while (current != NULL) { 
     printf("%c ", current->simvolo_eisodou); 
     current = current->next; 
    } 
    free(current); 
    printf("\n"); 
} 

int isInputValid(char *string) { 
    int i = 0; 
    while (*(string + i) != '\0') { 
     if (!(*(string + i) == 'P' || *(string + i) == 'K')) { 
      return 0; 
     } 
     ++i; 
    } 
    return 1; 
} 

void printWelcome() { 
    printf("\n====================================================================\n"); 
    printf("Welcome\n"); 
    printf("====================================================================\n"); 
    printf("\n\n\n Plz type input_string=(P|K)*\n"); 
} 
+2

«Я не думаю, что копирование кода поможет любому». Это очень неправильное мышление. Проблема заключается почти в ошибках в коде, вызывающем Undefined Behavior. Пожалуйста, разместите код в самом вопросе (а не как внешнюю ссылку). Как вы думаете, что происходит с памятью 'top', указывается после этого кода:' top = newNode; бесплатно (newNode); '? И тогда, что вы думаете позже, когда пытаетесь получить доступ к данным, на которые указывает 'top'? – kaylum

+0

Хм, мне интересно, что произойдет, если вы попытаетесь поместить больше элементов в массив, чем массив имеет элементы, хм, интересно, почему это даст вам проблемы ... –

+0

@kaylum top = newNode; означает, что верхние указывает на newNode, поэтому мне больше не нужен newNode, и, таким образом, я освобождаю его! Верный? – Skemelio

ответ

4

Ваш код имеет неопределенное поведение (UB). Результат запуска кода с UB непредсказуем. Иногда он может работать, но нет никакой гарантии, что один и тот же результат будет происходить каждый раз.

По крайней мере, один источник вашей UB этот код:

top=newNode; 
free(newNode); 

После newNode освобождается top указатель становится недействительным и любое разыменование этого указателя приведет к UB.

2

Ваш код начинается с:

#define STR_LENGTH 50 

// ... in main 
char input_string[STR_LENGTH]; 
scanf("%s", input_string); 

В вашем вопросе вы говорите о буфере длины 500. Но в вашем коде нет такого буфера, длина равна 50.

Если вы наберете 50 или более символов, вы вызываете undefined behaviour. Это означает, что все может случиться. Невозможно, чтобы вы могли контролировать, что происходит в этом случае, и вы не должны ожидать какого-либо конкретного поведения.

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

Ваше описание программы состоит в том, что оно должно содержать до 500 символов в строке. Одним из способов достижения этой цели будет:

char input_string[501]; // +1 for terminator 
scanf("%500s", input_string); // IMPORTANT: 500 limiter 

Если вы хотите сообщить об ошибке, если они набрали слишком много, вместо того, чтобы просто игнорировать это, вы могли бы написать:

if (!isspace(getchar())) // requires #include <ctype.h> 
{ 
    fprintf(stderr, "Too many characters entered - aborting program"); 
    exit(EXIT_FAILURE); 
} 

, например.

Если вы действительно хотите поддерживать произвольную длину ввода, вам нужно будет переключиться на более сложную стратегию памяти (например, связанный список или перераспределение буфера по мере увеличения ввода).


Другие заметки о коде:

  • Вы можете использовать функции из #include <stdlib.h> поэтому вы должны иметь эту линию
  • printf("Den anagnwristike to %s, input_string=(P|K)*\n") имеет %s, но не соответствующий аргумент, это также приводит к непредсказуемому поведению
  • Использовать exit(EXIT_FAILURE) вместо _exit(-1);

NB. Могут быть и другие проблемы, я не проверял всю вашу программу.

+0

Если код OP - это весь код, следует избегать компилятора Microsoft. – Michi

+0

@ M.M спасибо за ваши усилия. Я знаю, что переполнение буфера также является проблемой, но иногда ее работой. Моя проблема заключалась в том, что я не мог понять, как работает free(). Я думал, что это освобождает пространство памяти указателя, а не там, где указывает указатель. К сожалению, я могу отметить только один вопрос правильно! – Skemelio

+1

@Michi: Поскольку MSVC не является стандартным соглашением в любом случае, это хороший совет в целом. – Olaf