2012-06-12 19 views
3

我有一個源代碼中C.C代碼 - 不能通過putchar插入新行。

#include <stdio.h> 
#define IN_W 1 
#define OUT_W 0 
#define SPACE 32 
#define TAB 9 

int main() { 
    int c, state, temp; 
    state = OUT_W; 

    while ((c = getchar()) != EOF) { 
     if ((c != SPACE || c != TAB) && (state == OUT_W)) { 
      state = IN_W; 
      temp = c; 
      c = 13; 
      putchar(c); 
      c = 10; 
      putchar(c); 
      putchar(temp);   
     } else if (c != SPACE || c != TAB) 
      putchar(c);  
     else 
      state = OUT_W;  
    } 
    return 0; 
} 

我想要實現的是,我將鍵入一些字符/字和通過的getchar趕上那些輸入。當getchar接收到空格或製表符以外的任何字符時,它將打印一個新行,然後打印這些字符,直到找到空格或製表符(放棄它們)。例如,當我鍵入

123 eat 4bananas  in themorning 

程序將打印

123 
eat 
4bananas 
in 
themorning 

我試圖將其與CR或LF整合,但它仍然打印「123 themorning吃4bananas」。我想問的是: 1.我錯過了什麼? 2.在過去的 '其他',其中之一是對正在運行的程序更有效:

else 
     state = OUT_W; 

else if ((c == SPACE || c == TAB) && state == IN_W) 
     state = OUT_W; 
    else 
     continue;  // or can I use single ';' since we do nothing in here? 

這就是全部。感謝您的幫助。

注意:我試着玩'\ n'和'\ t'。

問候, 馬里奧

+0

不要使用像10和13這樣的「幻數」作爲字符常量。只需使用''''作爲空格,使用''t''作爲標籤,使用'\ n''作爲換行符。如果你需要返回字符,你可以使用''\ r'' - 但你沒有;將''\ n''寫入標準輸出會自動爲您的系統生成正確的行尾序列,無論是「LF」還是「CR LF」。 –

+0

除非你在一個UNIX機器上與需要DOS EOL特性的設備通話:-) – paxdiablo

回答

1

一開始:

(c != SPACE || c != TAB) 

總是正確的。一個字符不能同時爲空格和製表符,因此必須總是可以是非標籤或非空格。我懷疑你的意思是:

(c != SPACE && c != TAB) 

這就是爲什麼國家是永遠回去OUT_W,因爲第一行結束序列之後,第二if說法始終是真實的,所以它永遠不會到最後else位。

下面的代碼工作好:

#include <stdio.h> 
#define IN_W 1 
#define OUT_W 0 
#define SPACE 32 
#define TAB 9 

int main (void) { 
    int c, state, temp; 
    state = OUT_W; 

    while ((c = getchar()) != EOF) { 
     if ((c != SPACE && c != TAB) && (state == OUT_W)) { 
      state = IN_W; 
      temp = c; 
      c = 13; 
      putchar(c); 
      c = 10; 
      putchar(c); 
      putchar(temp); 
     } else if (c != SPACE && c != TAB) 
      putchar(c); 
     else 
      state = OUT_W; 
    } 
    return 0; 
} 

儘管它仍然有惱人的初始換行符,您可以通過簡單的初始狀態設置爲IN_W修復。

你的代碼中還有很多神奇的數字,有些相當不必要的值的移動。可能是更精緻的版本是:

#include <stdio.h> 

#define IN_W 1 
#define OUT_W 0 

#define SPACE ' ' 
#define TAB '\t' 
#define CR '\r' 
#define LF '\n' 

int main (void) { 
    int c, state; 

    state = IN_W; 
    while ((c = getchar()) != EOF) { 
     if ((c != SPACE) && (c != TAB) && (state == OUT_W)) { 
      putchar(CR); 
      putchar(LF); 
      putchar(c); 
      state = IN_W; 
     } else if ((c != SPACE) && (c != TAB)) 
      putchar(c); 
     else 
      state = OUT_W; 
    } 

    return 0; 
} 

有一件事我會提的是,它往往是最好的狀態機本身執行的操作分開。爲此,我會根據當前狀態而不是字符/狀態對進行主要選擇,並將狀態機中每個狀態的動作分開。

我認爲這使事情了很多更具可讀性,更容易修改:

#include <stdio.h> 

enum tState { ST_WORD, ST_SPACE }; 

static enum tState doWord (int ch) { 
    if ((ch == ' ') || (ch == '\t')) { 
     putchar ('\r'); 
     putchar ('\n'); 
     return ST_SPACE; 
    } 
    putchar (ch); 
    return ST_WORD; 
} 

static enum tState doSpace (int ch) { 
    if ((ch == ' ') || (ch == '\t')) 
     return ST_SPACE; 
    putchar (ch); 
    return ST_WORD; 
} 

int main (void) { 
    int ch; 
    enum tState state = ST_WORD; 

    while ((ch = getchar()) != EOF) { 
     switch (state) { 
      case ST_WORD: state = doWord (ch); break; 
      case ST_SPACE: state = doSpace (ch); break; 
     } 
    } 

    return 0; 
} 
+0

哇,這真的是我得到的啓示。我會玩你的建議。我想我需要更多的鍛鍊來訓練我的邏輯,並更好地理解如何使用編程來解決我的問題。謝謝。 – user1450146

3

這種表達是不是你想要的:(c != SPACE || c != TAB)

這是總是如此。如果cSPACE那麼它不是TAB,所以第二部分是對的。如果c是TAB,那麼它不是SPACE,所以第一部分將是真實的。

在這兩種情況下,你想要的是(c != SPACE && c != TAB)這隻有當c不是SPACE而且也不是TAB時纔是如此。運營商&&是布爾「和」。

此外,我建議,而不是像13幻數,你應該使用C字符常量,如'\r'

至於你的第二個問題,你的程序沒有寫得太差。我絕對不認爲你會通過加入continue來改善它,我甚至都不知道它會如何工作。 (正如你提到的,如果else continue;是在循環的最後,你可以離開了continue;其實,你可以那麼就砍掉了整個else,因爲else;什麼都不做)

你已經寫了一點狀態機器。你有三個有趣的情況:在狀態OUT_W

  • ,需要轉換到狀態IN_W(這裏是你打印CR/LF轉到下一行)
  • 狀態IN_W,發現了另一個角色,留在IN_W(在這裏你打印的字符)
  • 狀態IN_W,發現了一個選項卡或空間,因此需要過渡到狀態OUT_W

還有第四種可能性:

  • 狀態OUT_W,發現了另一個選項卡或空間,留在OUT_W(由第三種情況處理就好了)

如果你想在最高效的代碼,我認爲這將是最好的重新安排,這樣你只需要在一個地方檢查SPACETAB

while ((c = getchar()) != EOF) { 
    if (c == SPACE || c == TAB) { 
     state = OUT_W; 
    } 
    else { 
     /* c is not SPACE or TAB so we will print it */ 
     if (state == OUT_W) { 
      /* transition from OUT_W to IN_W */ 
      state = IN_W; 
      putchar('\r'); 
      putchar('\n'); 
      putchar(c); 
     } 
     else 
      putchar(c); 
    } 
} 

而且隨着代碼的這一重組版本,它變得清晰,任何時候你在IN_W打印的字符,但只有在過渡打印CR/LF。所以你可以把這個縮短到沒有else,總是叫putchar(c);,但是在檢查過渡之後這樣做。我會把它作爲你的練習。

+0

我很高興我犯了錯誤。我之前從未想過'\ r'字符,OR表達式的用法真的在我腦海中消失了。感謝您的時間。 – user1450146