0

我对 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;

}

请忽略糟糕的程序结构,正如我所提到的,我是新手!

谢谢

4

4 回答 4

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:00 之前敲定了这一点)。但它应该让您了解如何在执行过程中解析文件。如果不出意外,它会避免使用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);
  }
  ...
}
于 2013-03-28T12:11:09.903 回答
1

如果您期望在您的do...while代码中,那result可能是null(这是循环中断的条件),您如何看待这个代码行:

holder[n] = *result;

必须工作吗?在我看来,这是您的程序崩溃的原因。

于 2013-03-28T11:13:23.133 回答
1

do while将循环更改为while

采用

while (condition)
{
}

代替

do {
}while(condition)

它正在崩溃,因为您试图result在 do while 循环中取消对 NULL 指针的引用。

于 2013-03-28T11:15:01.220 回答
0

我主要使用Objective-C,只是为了好玩而看你的问题,但我可能有一个解决方案。

n=0;在你的第一个 do-while 循环之后设置之前,创建另一个名为的变量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);
于 2013-03-28T11:42:28.463 回答