2016-11-17 40 views
0

我試圖找到詞頻率,我無法弄清楚爲什麼程序不斷崩潰..我已經嘗試了很多方法,但我仍然得到同樣的崩潰。難道我做錯了什麼? *輸入是我要創建的書籍文件和新文件。程序不會運行 - 書計算器的字母頻率

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

int main(int argc, char *argv[]) 
{ 
    FILE *fp,*fp2; 
    int ch, total, counter, totalcounter, i; 
    int letters[25], letterfrequency[25]; 
    for(i=0; i<25; i++) 
    { 
     letters[i] = 0; 
     letterfrequency[i] = 0; 
    } 
    printf("Opening: %s", argv[1]); 
    fp = fopen(argv[1], "r"); 
    if (!fp) 
     { 
      perror("fopen"); 
      exit(1); 
     } 
    while((ch=fgetc(fp)) != EOF) 
     { 
      if((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z')) 
       { 
        counter = toupper(ch); 
        ch = counter - 65; 
        letters[ch]++; 
        totalcounter++; 
       } 
     } 

    fp2 = fopen(argv[2], "w"); 
    for(i=0;i<25;i++) 
    { 
     fprintf(fp2, "%c: Times used: %s\tFrequency Used: %s", i+65, letters[i], letters[i]/totalcounter); 
    } 
    fclose(fp); 
    fclose(fp2); 
    return 0; 
} 
+2

您的代碼有很多警告。一定要用'-Wall'編譯。修復警告。然後重新發布代碼,如果它仍然無法正常工作。 – Schwern

+1

你最近如何運作?什麼是預期的輸出? – bentank

+0

您可以添加「ch」值的打印,它可以幫助識別問題 – lowtech

回答

3

您的代碼有許多問題。首先它有警告。這些警告指出了問題。不幸的是,大多數C編譯器默認情況下不會向您顯示警告。你必須打開-Wall。但-Wall並不意味着「所有警告」,哦不。如果你問爲什麼,簡單的答案是C是數十年可疑設計選擇的積累,習慣它。 : - /我跑更多的警告和檢查:-Wall -Wwrite-strings -Wextra -Wconversion -std=c99 -pedantic -g

存在一堆未使用和未初始化的變量,您的printf規範錯誤,並且您缺少toupperinclude。我會離開你去解決所有這些問題。


那麼接下來的問題是,你已經初始化letters爲25長,但字母表有26個字符。幸運的是,你也只是迭代了25次,但這意味着你會失去'Z'。這是一個容易犯的錯誤。 26個項目的長陣列從0到25,但長度爲26.

與其重複遍佈整個陣列的長度並可能錯過一個,最好是在一個地方定義它。

#define NUM_LETTERS 26 

然後有一個更快更簡單的方法來初始化一個數組。

int letters[NUM_LETTERS] = {0}; 

沒有必要指定每個元素,C會用最後一個元素填充剩下的元素。


因爲它是完全安全地調用的東西,這不是一個字符toupper,它只是返回字符不變,您可以簡化while循環。

while((ch=fgetc(fp)) != EOF) { 
    ch = toupper(ch); 
    if('A' <= ch && ch <= 'Z') { 
     ch -= 65; 
     letters[ch]++; 
     totalcounter++; 
    } 
} 

請注意我使用的風格,'A' <= ch && ch <= 'Z'。這樣可以更容易地看到它是從AZ範圍內的ch的檢查。


接下來的問題是:letters[i]/totalcounter

在C中,如果你分兩個整數,你會得到一個整數。這意味着20/1000。如果你想要一個小數,你必須將其中一個變量轉換爲浮點類型:(double)letters[i]/totalcounter)


有沒有信件被從文件中讀取和totalcounter是0。如果是letters[i]/totalcounter將導致除以零錯誤的可能性。所以你必須檢查這種情況。

if(totalcounter != 0) { 
    for(i=0; i<NUM_LETTERS; i++) { 
     printf("%c: Times used: %d\tFrequency Used: %f\n", 
       i+65, letters[i], (double)letters[i]/totalcounter 
     ); 
    } 
} 
else { 
    printf("No letters found.\n"); 
} 

您無法檢查用戶是否給了你一個文件名參數。如果他們不這樣做,你的程序會崩潰。添加使用檢查很重要。

if(argc < 2) { 
    fprintf(stderr, "Usage: %s <filename>\n", argv[0]); 
    exit(1); 
} 

而且請注意,我沒有把結果寫入一個文件,我有我的版本只取一個文件,一讀。我的版本輸出到標準輸出。

通常,最好將程序結果打印到標準輸出而不是文件。這使程序可以很好地與外殼管道配合使用,從而使其更加靈活。

./wordcount somefile      # output to the screen 
./wordcount somefile.txt > somefile.count # output to a file 
./wordcount somefile.txt | program  # output to another program 
1

更改陣列採取所有字母,即int letters[26];其他letterfrequence你似乎沒有使用任何東西

fprintf格式說明是錯誤的

你有

fprintf(fp2, "%c: Times used: %s\tFrequency Used: %s", i+65, letters[i], letters[i]/totalcounter);

letters是一個int數組,如此相關ct說明符應該是%d(int)而不是%s(字符串)

您還沒有初始化totalcounter因此可能會發生0除法或其他任意除法。

toupper位於標題ctype.h中,該標題缺失。