2016-03-02 73 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

相關問題