2010-10-14 191 views
1

我在CI中寫過這樣的程序,它每行按行讀取一個文件(每行只有一個字),對字母進行排序,然後在每個字符中顯示排序字和原始字線。對字符串中的字符進行排序的C程序

#include<stdio.h> 

int main() 
{ 
    char line[128]; 
    int i=0; 
    int j; 
    int length; 

    while(fgets(line,sizeof line,stdin) != NULL) 
    { 
    char word[128]; 

    for (i=0; line[i] != '\0'; i++) 
    { 
     word[i]=line[i]; 
    } 

    while (line[i] != '\0') 
     i++; 

    length=i; 

for (i=length-1; i >=0; i--) 
    { 
     for (j=0; j<i; j++) 
     { 
     if (line[j] > line[i]) 
     { 
      char temp; 
      temp = line[j]; 
      line[j] = line[i]; 
      line[i]=temp; 
     } 
     } 
    } 
    printf("%s %s",line,word); 

    } 
    return 0; 
} 

我編譯並運行它使用下面的bash命令。

gcc -o sign sign.c 
./sign < sample_file | sort > output 

原始文件(sample_file)看起來是這樣的:

computer 
test 
file 
stack 
overflow 

輸出文件是這樣的:

ackst stack 
cemoprtu computer 
efil file 
efloorvw overflow 
er 
estt test 
ter 
ter 

我有兩個問題:

  1. 輸出文件在開始處有一堆換行符(即。abou t 5-7實際文字開始前的空白行)
  2. 爲什麼在最後打印'ter'兩次?

PS - 我知道這些都是非常基本的問題,但是我只是剛開始使用C/bash進行一個類的工作,而且我不確定哪裏出錯。

+1

你允許使用'string.h'函數嗎?因爲使用'strlen'和'strcpy'會更簡單。目前,在複製之後,你並不是NUL-teriminating'word'。 – 2010-10-14 02:18:36

+0

我想我可以使用 – xbonez 2010-10-14 02:35:34

+0

這個作業嗎?你可能想標記它。如果是這樣,可惜你只限於C,它會成爲其他幾種語言的單行語言。 – Daenyth 2010-10-14 02:41:20

回答

2

問題1

此代碼後,變量line包含一行文本,包括從字符串末尾的換行符

while(fgets(line,sizeof line,stdin) != NULL) 
{ 

這就是爲什麼你所得到的「額外「換行符。換行符的ASCII值小於'A'的ASCII值。這就是爲什麼一旦你對字符進行排序,換行符就會出現在每個字符串的開頭。例如。 「computer \ n」變成「\ ncemoprtu」。

爲了解決這個問題,你可以脫掉你的字符串末尾的換行符,for循環

if(i > 0 && word[i-1] == '\n') 
{ 
    word[i-1] = '\0'; 
    line[i-1] = '\0'; 
    --i; 
} 

...

printf("%s %s\n",line,word); /* notice the addition of the newline at the end */ 

這正好解決了問題2,作爲後好吧,但請繼續閱讀,看看有什麼不對。

問題2

環路

for (i=0; line[i] != '\0'; i++) { /* */ } 

字符串word不會空終止後(通過盲運氣除外,因爲它已準備好隨機初始化的存儲器)。這就是爲什麼你得到「ter」的原因,因爲這是你在將單詞「computer」複製到word時留下的數據的一部分。

問題3

循環後

for (i=0; line[i] != '\0'; i++) { /* */ } 

line[i] != '\0'值將始終是假的。這意味着,該代碼不會做任何事

while (line[i] != '\0') 
    i++; 

這可能使問題更加明顯,如果我更換for循環和while循環使用基本相同的代碼,使用goto語句:

i=0; 
begin_for_loop: 
if(line[i] != '\0') 
{ 
    { 
    word[i]=line[i]; 
    } 
    i++; 
    goto begin_for_loop; 
} 

begin_while_loop: 
if(line[i] != '\0') 
{ 
    i++; 
    goto begin_while_loop; 
} 

(順便說一句,大多數專業程序員會做任何事情,從笑到喊你,如果你提到使用goto :)我只是在這裏用它來說明這一點)

我發現一個小貼士是繪製我的數組,變量等在一張紙上,然後追蹤我的代碼(ag ain,紙上)來調試它的工作原理。

+0

不行(因爲它是一個數組)總是以空終止?在這種情況下,爲什麼line [i]!='\ 0'總是錯誤的? – xbonez 2010-10-14 02:45:26

+0

'fgets'將空終止它寫入的任何緩衝區。正因爲如此,'line [i] =='\ 0''將成立。換個角度考慮一下:for循環只在'line [i]!='\ 0''時退出。然後你立即再次做同樣的檢查。當然你會得到同樣的答案。 – 2010-10-14 02:49:15

+0

但要回答*確切的*事情你問:「不行(因爲它是一個數組)總是以空終止?」。不,數組可以有任何值。他們絕不會保證以null結尾,除非您手動執行該操作,或者您調用的函數可以保證執行該操作。 'fgets'做出了保證,但'word [i] = line [i];'沒有。你必須自己終止'word'(只需在for循環後加':word [i] ='\ 0';')。 – 2010-10-14 02:51:59

相關問題