2016-03-02 43 views
-4

我越来越重要,因为我无法解释我将要描述的情况。我需要你的关注!运行C程序后未定义的计算机行为

昨天我写了一个程序C.程序需要输入一个字符串,如果该字符串就是以这种形式“PKPKKKPPPKKKP”,即由只有“P”和“K”字符它打印你YES或NO 。是,如果一个'P'字符与'K'字符匹配。正如我们对括号字符问题'(',')'所做的那样,只能用'('我不得不用'P'而不用')','K'来代替。

从这里得到一点帮助,我设法完成了程序,它运行正常。我不认为复制代码会帮助任何人,但我会解释它是如何工作的。

程序说明: 该方案需要一个字符串(的字符串可以是高达500长度)作为输入,如果字符串仅包括“P”和“K”字符它打印YES或NO,如我上面描述过,否则它拒绝它。然后它逐个字符地读取输入,并且当它发现'P'时它被推入堆栈,否则弹出。 (我用链表实现了堆栈,所以用户可以给他想要的一个字符串(或者我认为是这样)。 在用户键入一个字符串之前,符号'A'在堆栈中。所以输入是由程序分析,逐个字符地进行分析,如果它找到'P'则将它推入堆栈,否则弹出堆栈。如果最后堆栈的顶部是'A'字符,则程序打印YES,否则NO。

问题描述: 所以我今天和我的一个朋友一起执行这个程序。一切都很好。直到我输入一个非常大的字符串,比如300'P和300'K(并且记住我的字符串是一个char字符串[500])。它打印是的。然后我输入一个800'P's + 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

“我不认为复制代码会帮助任何人”。这是一个非常错误的想法。问题几乎可以肯定是代码中的错误导致了未定义的行为。请在问题本身发布代码(而不是作为外部链接)。在代码运行后,你认为'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);

注意。也可能有其他问题,我没有检查你的整个程序。

+0

如果OP的代码是整个代码,那么应该避免使用Microsoft的编译器。 – Michi

+0

@ M.M感谢您的努力。我知道溢出缓冲区也是一个问题,但有时它的工作。我的问题是我无法理解free()是如何工作的。我认为它释放了指针的内存空间,而不是指针所指向的内存空间。不幸的是,我只能标记一个正确的问题! – Skemelio

+1

@Michi:由于MSVC不符合标准,所以这是一个很好的建议。 – Olaf

相关问题