1

1 行に 1 つずつ、最大 100 個の IP アドレスを含むテキスト ファイルがあります。各アドレスを文字列として "list" という配列に読み込む必要があります。まず、"list" は 2 次元の char 配列である必要があると想定しています。各 IP アドレスの長さは 11 文字で、'\0' を含めると 12 文字になるため、次のように list を宣言しました。

char list[100][12];

次に、fgets を使用してストリームを読み取ろうとします。

  for (i = 0; i < 100; i++)  
  {  
      if (feof(stream))  
          break;  
          for (j = 0; j < 12; j++)  
          fgets(&list[i][j], 12, stream);  
      count++;  
  }

文字列が正しく読み取られたかどうかを確認するために、出力を試みます。

  for (i = 0; i < 5; i++)  
  {  
      for (j = 0; j < 11; j++)  
          printf("%c", list[i][j]);  
      printf("\n");  
  }

プログラムを実行した後、何かが間違っていることは明らかです。初心者なのでよくわかりませんが、ファイルの読み方が間違っているのではないかと思います。エラーはありません。コンパイルはできますが、奇妙なアドレスが 2 行に出力されます。

編集:

fgets コードを次のコードに置き換えました。

for (i = 0; i < 100; i++)
  {
      if (feof(stream))
          break;
      fgets(list[i], 12, stream);
      count++;
  }

5 つの文字列を出力するようになりましたが、これらはメモリからの「ランダムな」文字です。

4

7 に答える 7

6

まず、読む:

      for (j = 0; j < 12; j++)  
      fgets(&list[i][j], 12, stream);  

ここに大きな問題があります。これは、配列内の連続する各文字に文字列を読み取ろうとしています。

全体として、これを必要以上に複雑にしていると思います。配列を 100 個の文字列と考えてくださいfgets。一度に 1 つの文字列で機能します。つまり、読み取りは次のようになります。

for (i=0; i<100 && fgets(list[i], 11, string); i++)
    ;

対処すべきもう 1 つの細かい点があります。fgets()通常、各行の末尾に改行を保持します。そのため、13 文字 (アドレス用に 11 文字、改行用に 1 文字、NUL ターミネータ用に 1 文字) の余地を残しておく必要があるかもしれませんlist。改行を削除しました。

文字列を出力するための現在のコードでは、一度に 1 文字ずつ作業しています。これは機能しますが、不必要に困難です。何人かの人々が %s printf 変換の使用を提案していますが、それ自体は問題ありません。ただし、それを行うには、インデックス作成を少し簡素化する必要があります。最初の 6 つのアドレスを印刷すると、次のようになります。

for (i=0; i<6; i++)
    printf("%s", list[i]);
于 2009-12-03T19:50:20.410 に答える
4

への呼び出しfgetsは、ストリームから配列に最大 11 文字を読み取ります。したがって、各文字列の各文字に対して 1 回ずつ呼び出す必要はありません。

これらのループについて考えてみてください。i=0 および j=0 の場合、最大 11 文字を読み取ります&list[0][0]。次に、i=0 および j=1 で、さらに 11 文字を に読み取ります&list[0][1]。これは 2 つの理由で間違っています。最後の呼び出しの結果が上書きされ、list[0] が保持できるよりも多くのバイトが書き込まれる可能性があります。

于 2009-12-03T19:46:12.743 に答える
1

行を読み取る関数を作成しました。安全だと思います。

チェック:io_readline

https://github.com/arhuaco/junkcode/blob/master/junk/misc/atail.c

于 2009-12-03T20:41:39.270 に答える
1

feof()ループ条件として使用しないでください。ファイルの最後を超えて読み込もうとするまで true を返しません。つまり、ループが何度も実行されます。入力呼び出しの結果 ( または を使用するかどうかfgets())チェックfscanf()して、成功したかどうかを確認してから、エラー状態が発生したかどうかを確認します。 feof()

if (fgets(buffer, sizeof buffer, stream) != NULL)
{
  // process the input buffer
}
else if (feof(stream)
{
  // handle end of file
}
else
{
  // handle read error other than EOF
}

fgets()個々の文字ではなく文字列全体を読み取るため、文字列内の個々の文字のアドレスを渡したくありません。代わりに次のように呼び出します。

if (fgets(list[i], sizeof list[i], stream) != NULL)
{
  // process input address
}

そして今、配列とポインターについてのボードのいつもの熱弁のために...

配列式がほとんどのコンテキストで出現する場合、式の型は "T の N 要素配列" から "T へのポインター" に暗黙的に変換され、式の値は配列の最初の要素のアドレスになります。この規則の例外は、配列式がsizeofor&演算子のオペランドである場合、または宣言で初期化子として使用されている文字列リテラルである場合です。「配列とポインタは同じものだ」と人々が言うのを聞くとき、彼らはそのルールを混乱させています。配列とポインターはまったく別物ですが、状況によっては同じ意味で使用できます。

上記のコードでは、最初の引数として fgets() に何も装飾 (演算子list[i]など) なしで渡したことに注意してください。&の型list[i]は「char の 12 要素配列」ですが、このコンテキストでは暗黙的に「char へのポインタ」型に変換され、値は のアドレスになりますlist[i][0]sizeof同じ式を演算子にも渡したことに注意してください。その場合、配列式の型はポインター型に変換され ず、sizeof 演算子は配列型のバイト数 (12) を返します。

それを釘付けにするだけです:

式の型 暗黙的に変換される
---------- ---- ----
list char [100][12] char (*)[12] (char の 12 要素配列へのポインタ)
リスト[i] char [12] char *
list[i][j] char 該当なし

これが意味することはfgets()、次の 12 文字まで読み取り (最初に改行または EOF にヒットしない場合)、それをlist[i][0]. fgets()文字列の末尾に終了ヌル文字 (0) を書き込むことに注意してください。また、 が改行にfgets()遭遇し、それと終端の nul のためのスペースがターゲット配列にある場合、は終端の改行を nul 文字の前に格納することにも注意してください。したがって、入力ファイルに次のような行がある場合fgets()

1.1.1.1\n

次に、読み取り後の入力バッファーの内容は、ランダムな値"1.1.1.1\n\0xxx"になります。xそこに改行が必要ない場合は、strchr()関数を使用して検索し、0 で上書きできます。

char *newline;
...
if ((newline = strchr(input[i], '\n')) != NULL)
{
  *newline = 0;
}

次の改行で停止し、fgets()入力バッファーのサイズが 12 文字であるため、ファイル内の次の入力文字として改行がある状況に遭遇する可能性があります。その場合、fgets()その改行のみが入力バッファーに書き込まれるため、空のエントリがいくつかありますが、これはおそらく必要なものではありません。そのような状況を避けるために、入力バッファーに余分なバイトを追加したい場合があります。

すべてを一緒に入れて:

char list[100][13];
...
for (i = 0; i < 100; ++)
{
  if (fgets(list[i], sizeof list[i], stream) != NULL)
  {
    char *newline = strchr(list[i], '\n');
    if (newline != NULL)
      *newline = 0;
    printf("Read address \"%s\"\n", list[i]);
    count++;
  }
  else if (feof(stream))
  {
    printf("Reached end of file\n");
    break;
  }
  else
  {
    printf("Read error on input; aborting read loop\n");
    break;
  }
}
于 2009-12-03T20:46:03.467 に答える
1

改行文字は fgets の読み取りを停止させますが、有効な文字と見なされるため、str にコピーされる文字列に含まれます。

fgets の最初の呼び出しで最初の 12 文字を読み取っている可能性があります。次に、2 番目の呼び出しで改行がキャッチされ、3 番目の呼び出しで次の行が取得されます。

fgets を 15 文字制限で使用し、バッファを拡張してみてください。

于 2009-12-03T19:50:50.863 に答える
1

2 番目のループは不要であり、メモリが破損します。あなたはこのようなことをするべきです、

for (i = 0; i < 100; i++)
{
if (feof(stream))
break;
fgets(&list[i][j], 12, stream);
count++;
}

To check to see if the strings were read properly, I attempt to output them:

for (i = 0; i < 5; i++)
{
printf("%s\n", list[i]);
}
于 2009-12-03T19:51:22.130 に答える
1

for (i = 0; i < 100; i++) {

   if (feof(fp))
       break;

   fscanf(fp,"%s\n",list[i]);

}

于 2009-12-03T19:52:27.447 に答える