2013-03-28 106 views
0

我對C很陌生,我仍在學習基礎知識。我正在創建一個應用程序,它讀入一個文本文件並單獨分解這些單詞。我的意圖是計算每個單詞出現的次數。C中的循環崩潰

無論如何,下面代碼中的最後一個do-while循環執行得很好,然後崩潰。這個循環打印這個單詞(指針)的內存地址,然後打印這個單詞。它完成了這一點,然後在最後一次迭代中崩潰。我的意圖是將這個內存地址推入一個單獨的鏈表中,儘管它一旦停止崩潰。

此外,關於下面的數組大小隻是一個快速提及;我還沒有想出如何設置正確的大小來容納單詞字符數組等,因爲你必須在數組填充前定義大小,我不知道該怎麼做。因此,爲什麼我已經將它們設置爲1024

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

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

    FILE * pFile; 
    int c; 
    int n = 0; 
    char *wp; 
    char wordArray[1024]; 
    char delims[] = " "; // delims spaces in the word array. 
    char *result = NULL; 
      result = strtok(wordArray, delims); 
    char holder[1024]; 

    pFile=fopen (argv[1],"r"); 
    if (pFile == NULL) perror ("Error opening file"); 
    else { 
      do { 
       c = fgetc (pFile); 
       wordArray[n] = c; 
       n++; 
      } while (c != EOF); 
      n = 0; 
      fclose (pFile); 

      do { 
       result = strtok(NULL, delims); 
       holder[n] = *result; // holder stores the value of 'result', which should be a word. 
       wp = &holder[n]; // wp points to the address of 'holder' which holds the 'result'. 
       n++; 
       printf("Pointer value = %d\n", wp); // Prints the address of holder. 
       printf("Result is \"%s\"\n", result); // Prints the 'result' which is a word from the array. 
       //sl_push_front(&wp); // Push address onto stack. 
      } while (result != NULL); 
    }  
    return 0; 

}

請忽略壞的程序結構,正如我所說,我是新來的!

感謝

+0

首先,這樣的:'持有人[N] = *結果;'可能是*不是*做你認爲的事。其次,當'strtok(NULL,delims)'由於結束標記條件而返回NULL時,你認爲這樣做是什麼? – WhozCraig 2013-03-28 11:47:19

回答

2

正如其他人所指出的那樣,你的第二個循環嘗試取消引用result之前,你檢查它是NULL。調整你的代碼如下:

result = strtok(wordArray, delims); // do this *after* you have read data into 
             // wordArray 
while(result != NULL) 
{ 
    holder[n] = *result; 
    ... 
    result = strtok(NULL, delims); 
} 

雖然...

您正在嘗試之前,將其分成詞來讀取文件的全部內容複製到內存;這對於大於緩衝區大小的文件(當前爲1K)不起作用。如果我可以提出建議,請更改您的代碼,以便隨時閱讀單個單詞。下面是打破輸入的示例流成由空格分隔單詞(空格,新行,製表符,等)和標點符號(句號,逗號等):

#include <stdio.h> 
#include <ctype.h> 

int main(int argc, char **argv) 
{ 
    char buffer[1024]; 
    int c; 
    size_t n = 0; 

    FILE *input = stdin; 

    if(argc > 1) 
    { 
    input = fopen(argv[1], "r"); 
    if (!input) 
     input = stdin; 
    } 

    while((c = fgetc(input)) != EOF) 
    { 
    if (isspace(c) || ispunct(c)) 
    { 
     if (n > 0) 
     { 
     buffer[n] = 0; 
     printf("read word %s\n", buffer); 
     n = 0; 
     } 
    } 
    else 
    { 
     buffer[n++] = c; 
    } 
    } 
    if (n > 0) 
    { 
    buffer[n] = 0; 
    printf("read word %s\n", buffer); 
    } 
    fclose(input); 
    return 0; 
} 

無擔保明示或暗示的(具有搗這在上午7點之前)。但它應該給你一個如何解析文件的風味。如果沒有別的,它會避免使用strtok,這是而不是解析輸入的最大工具。你應該能夠使這個通用結構適應你的代碼。爲了達到最佳效果,你應該抽象他們趕出自己的功能:

int getNextWord(FILE *stream, char *buf, size_t bufsize) 
{ 
    int c; 
    size_t n = 0; 

    while((c = fgetc(input)) != EOF && n < bufsize) 
    { 
    if (isspace(c) || ispunct(c)) 
    { 
     if (n > 0) 
     { 
     buf[n] = 0; 
     n = 0; 
     } 
    } 
    else 
    { 
     buffer[n++] = c; 
    } 
    } 
    if (n > 0) 
    { 
    buffer[n] = 0; 
    printf("read word %s\n", buffer); 
    } 

    if (n == 0) 
    return 0; 
    else 
    return 1; 
} 

,你會這樣稱呼它

void foo(void) 
{ 
    char word[SOME_SIZE]; 
    ... 
    while (getNextWord(inFile, word, sizeof word)) 
    { 
    do_something_with(word); 
    } 
    ... 
} 
+0

非常感謝您的支持!這是一個非常有用的評論! – drizzy 2013-03-28 13:33:35

1

如果您在do...while代碼,這result可能是null(這是迴路斷線的情況)預期,您怎麼看待這個代碼行:

holder[n] = *result;

必須工作?在我看來,這是在你的程序崩潰的原因。

1

變化do while環路while

使用

while (condition) 
{ 
} 

代替

do { 
}while(condition) 

它崩潰,因爲你試圖derefrance NULL指針result在do while循環。

0

我主要用Objective-C工作,只是看着你的問題尋求樂趣,但我可能有一個解決方案。

之前,你的第一個do-while循環後設置n=0;,創建一個名爲totalWords另一個變量,並設置它等於n,totalWords可以聲明文件中的任何地方(之一DO-while循環內的除外),但可以在頂部else塊定義,因爲它的生命週期短:

totalWords = n; 

那麼你可以設置N回零:

n = 0; 

您的條件爲最終do-while循環則應該說:

... 
} while (n <= ++totalWords); 

應用程序背後的邏輯將這樣說,計數文件中的單詞(有n個單詞,它是文件中的全部單詞)。當程序將結果打印到控制檯時,它將運行第二個do-while循環,該循環將一直運行,直到n爲超過totalWords值的一個結果(這可確保打印最終詞)。

或者,它是更好的做法和清晰的其他程序員使用循環半:

do { 
result = strtok(NULL, delims); 
holder[n] = *result; 
wp = &holder[n]; 
printf("Pointer value = %d\n", wp); 
printf("Result is \"%s\"\n", result); 
//sl_push_front(&wp); // Push address onto stack. 
if (n == totalWords) break; // This forces the program to exit the do-while after we have printed the last word 
n++; // We only need to increment if we have not reached the last word 
// if our logic is bad, we will enter an infinite loop, which will tell us while testing that our logic is bad. 
} while (true);