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

他の人が指摘したように、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)

resultdo while ループでNULL ポインターを参照解除しようとしているため、クラッシュしています。

于 2013-03-28T11:15:01.220 に答える
0

私は主にObjective-Cで作業しており、楽しみのためにあなたの質問を見ていましたが、解決策があるかもしれません.

最初の do-while ループの後に設定する前n=0;に、という別の変数を作成し、totalWordsそれを n に設定します。有効期間が短いため、else ブロック:

totalWords = n;

次に、n をゼロに戻すことができます。

n = 0;

最後の do-while ループの条件は次のようになります。

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

したがって、アプリケーションの背後にあるロジックは、ファイル内の単語をカウントします (ファイル内の単語数は n 個です)。プログラムが結果をコンソールに出力すると、2 番目の do-while ループが実行されます。このループは、n が totalWords の値を 1 つ超える結果になるまで実行されます (これにより、最後の単語が出力されることが保証されます)。

別の方法として、他のプログラマーがループと半分を使用する方がより適切で明確です。

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 に答える