2014-02-23 59 views
3

我目前正在嘗試編寫一個應用程序來計算ASCII文件中的單詞出現次數(標點符號被剝離並忽略空格)。應用程序應該將單詞和單詞計數存儲在數據結構中,該數據結構最終將按降序排序,然後打印到CSV文件。字數應用程序 - C

我已經開始了這個程序,但是當我嘗試保存一個新單詞時,我遇到了分段錯誤。這裏是我的代碼(我知道,這不是一個完美的執行,我不打算煉化吧):

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

#define TRUE 1 
#define FALSE 0 

/* This program is designed to take an ASCII input file, count the occurrences of words in it 
* and write an output file displaying the data. I intend for it to convert uppercase to 
* lowercase, so as not to generate duplicate words in the data structure. It should also 
* ignore whitespace and punctuation. 
*/ 

void getWords(void); 
void printFile(void); 
void save(char *input); 

struct word { 
    char *str; 
    int wc; 
}; 

struct word *warray = NULL; 

FILE *infile; 
FILE *outfile; 

void getWords(void) 
{ 

    rewind(infile); 
    char cw[100]; // Current word storage 
    int i = 0, j = 0, c; 

    while((c = fgetc(infile)) != EOF) 
    { 
     if(isalpha(c)) 
     { 
      if(isupper(c)) 
      { 
       cw[i] = tolower(c); 
       ++i; 
      } 
      else 
      { 
       cw[i] = c; 
       ++i; 
      } 
     } 
     else 
     { 
      if(c == '\n' || c == '\t' || c == ' ') 
      { 
       cw[i] = '\0'; 
       i = 0; 
       save(cw); 

       for(j = 0; j < cw[99]; j++) 
       { 
        printf("%c", cw[j]); 
       } 
      } 
     } 

    } 

} 

void printFile(void) 
{ 

    int i, c; 

    printf("Printing the file to be counted in lowercase...\n"); 
    for(i = 0; (c = fgetc(infile)) != EOF; i++) 
    { 
     if(ispunct(c) || isdigit(c)) 
     { 
      ++i; 
     } 
     else 
     { 
      putchar(tolower(c)); 
     } 

    } 
} 

void save(char *input) 
{ 

    int exists = FALSE, i = 0; 
    int elements = sizeof(warray)/sizeof(struct word); 

    if(!warray) 
    { 
     warray = malloc(sizeof(struct word)); 
     printf("Made array.\n"); 
    } 
    else 
    { 
     printf("New.\n"); 
     warray = realloc(warray, (elements++)*sizeof(struct word)); 
    } 

    while(i < elements) 
    { 
     printf("in while loop\n"); 
     if(strcmp(input, warray[i].str) == 0) 
     { 
      warray[i].wc++; 
     } 
     else 
     { 
      ++i; 
     } 

    } 
    printf("Out while loop\n"); 

    if(strcmp(input, warray[i].str) == 1) 
    { 
     printf("Inside save if statement\n"); 

     warray[elements].str = malloc(strlen(input)+1); 

     strcpy(warray[elements].str, input); 

     warray[elements].wc = 1; 

     elements++; 
    } 


} 

int main (int argc, char *argv[]) 
{ 


    if (argc < 3) 
    { 
     puts("Please supply the input filename and desired output filename as arguments."); 
     return 1; 
    } 

    infile = fopen(argv[1], "r"); 
    if(infile == NULL) 
    { 
     printf("File failed to open. Error: %d\n", errno); 
     return 1; 
    } 
    else 
    { 
     puts("File opened successfully."); 
     printFile(); 
     getWords(); 
    } 

    return 0; 

} 

我已經把一些打印語句,試圖找出問題,並似乎運行到這裏的問題時,save(char *input)函數內部:

if(strcmp(input, warray[i].str) == 1) 
{ 
    printf("Inside save if statement\n"); 

    warray[elements].str = malloc(strlen(input)+1); 

    strcpy(warray[elements].str, input); 

    warray[elements].wc = 1; 

    elements++; 
} 

我確實有一種感覺,那是因爲我問STRCMP檢查,如果它的價值== 1,當或許我應該只檢查對於任何非零值,但我已經嘗試過,我仍然遇到分段錯誤。

我會很感激,如果任何人都可以指出我在正確的方向,並提前致謝!

+0

首先要做的是:使用調試器並確定哪條線路導致錯誤。檢查變量並試圖弄清楚它們如何發揮它們的價值。如果需要,請逐步重新運行,觀察每個步驟的變量。如果不確定如何執行上述任何操作,請提出有關這些操作的問題。 –

回答

2

,我們在您執行幾個邏輯上的缺陷。從您的代碼中,我認爲您需要執行以下操作:

  • 檢查warray是否爲空。如果爲空,則分配一個元素。
  • 如果不爲空,則檢查該單詞是否已經存在。如果是這樣,然後增加計數器。
  • 如果單詞不在數組中,則在數組中分配一個新元素並將該單詞保存在那裏。

但是,您的代碼執行以下操作。

if(!warray) 
{ 
    warray = malloc(sizeof(struct word)); 
    printf("Made array.\n"); 
} 

這部分沒有問題。

else 
{ 
    printf("New.\n"); 
    warray = realloc(warray, (elements++)*sizeof(struct word)); 
} 

這不應該在這裏。您應該先檢查重複,然後根據需要進行分配。

while(i < elements) 
{ 
    printf("in while loop\n"); 
    if(strcmp(input, warray[i].str) == 0) 
    { 
     warray[i].wc++; 
    } 
    else 
    { 
     ++i; 
    } 
} 

這是。如果這個詞已經存在,那麼它會卡在warray[i].wc++;行。你應該在增加計數器後返回。

if(strcmp(input, warray[i].str) == 1) 
{ 
    printf("Inside save if statement\n"); 
    warray[elements].str = malloc(strlen(input)+1); 
    strcpy(warray[elements].str, input); 
    warray[elements].wc = 1; 
    elements++; 
} 

這也是。在上一個循環之後,i的值將等於elements的值。但是數組索引從0elements-1。所以warray[i]warray[elements]都會導致分段錯誤。 (您遞增elements值早些時候線warray = realloc(warray, (elements++)*sizeof(struct word));

for(j = 0; j < cw[99]; j++)在功能getwords也可能會導致段錯誤。

編輯:我之前沒有注意到後遞增問題。這應該是

warray = realloc(warray, (++elements)*sizeof(struct word)); 

代替

warray = realloc(warray, (elements++)*sizeof(struct word)); 

感謝的Chronos。

+0

非常感謝!修復這些錯誤並移動一些東西后,我的程序現在似乎正常運行。沒有更多的分段錯誤(現在;))!再次感謝! – arevans

1

一個問題是,你一直沒有重新分配的話的事實:

int elements = sizeof(warray)/sizeof(struct word); 

sizeof(warray)將是一個指針,它永遠不會改變的大小。由於sizeof(struct word)sizeof(pointer)+padding+sizeof(int),因此您正在執行sizeof(pointer)/(sizeof(pointer)+padding+sizeof(int)),這可能類似於在平凡的情況下說4/(4+0+4)4/8。由於整數除法的規則,每次調用save函數時,都會有效地將elements設置爲0,因此,您正在執行未定義的行爲malloc(0)。如果它返回NULL,則使用warray[i]的任何行都會導致段錯誤。它可能會返回一個非NULL值,但返回的指針可能指向未分配的內存。

存儲save函數以外的元素數量將允許您跟蹤數組中元素的數量。

此外,您的realloc行是錯誤的。通過做elements++,你是說如果元素的數量先前是1,那麼你應該只分配1,而elements會在下一個序列點之前的某個時間增加。你想要的是++elements,它在分配之前遞增元素的數量(例如,你有1,現在你想要2)。

可能還有其他的bug,但那些是我注意到的。

2

好吧,讓我看看我能否幫忙。在快速運行中,我看到三個明顯的主要問題!

首先,在getWords,在過去的for循環(「for(j = 0;...‘),終止條件爲’j < cw[99]」 ......我懷疑你的意思是‘j < 100’。我們不知道c [99]中的值是多少,或者如果輸入的字符串足夠長,以至達到數組的最後一個元素!

其次,在save,在第一個else子句中,看起來你試圖增加一個元素的大小warray ......但是,因爲您正在POST減量變量elements,所以數組不會調整大小。如果您預先增加elements,它應該解決問題。

warray = realloc(warray, (++elements)*sizeof(struct word)); 

第三,也是在save,看來你的意圖是隻增加與以前出現了一個詞的個性化......但是,你已經在這一點增加了數組的大小,所以您不必要地佔用內存資源。

前兩項將導致您的程序訪問您的程序的目標範圍之外的內存,並可能導致系統崩潰或至少出現非常不可預知的系統行爲。

有可能更多,但是這應該讓你前進......