5

ページで。K&R の 109 では、次のように表示されます。

void writelines(char *lineptr[], int nlines)
{
  while (nlines -- > 0) printf("%s\n", *lineptr++);
}

*lineptr++ が正確に何をするのか混乱しています。私の理解では、printf には char ポインターが必要なので、*lineptr で提供しています。次に、配列内の次の char ポインターまで lineptr をインクリメントしますか? これは違法ではありませんか?

99 ページで、K&R は次のように書いています。

4

5 に答える 5

7

読み続けます!pの一番下にあります。99

関数定義の仮パラメータとして、

 char s[];

 char *s;

同等です。パラメータがポインタであることをより明示的に示しているため、後者を優先します。

つまり、配列 (変数ではない) を関数に渡すことはできません。配列を取るように見える関数を宣言すると、実際にはポインター (変数) を取ります。意味あり。関数の引数が変数でないのは奇妙です。関数を呼び出すたびに異なる値を持つ可能性があるため、定数ではないことは確かです!

于 2009-05-08T03:21:06.030 に答える
6

lineptr実際には配列ではありません。それはポインタへのポインタです。ポストインクリメント演算子++は逆参照演算子よりも優先順位が高いことに注意してください*。したがって、次のようになりlineptr++ます。

  1. lineptr配列内の次の要素を指すようにインクリメントされます
  2. の結果lineptr++は の古い値lineptr、つまり配列内の現在の要素へのポインタです。
  3. *lineptr++それを逆参照したので、配列内の現在の要素の値です

lineptrしたがって、 while ループは、 が指す配列内のすべての要素(各要素は a )を繰り返し処理し、char*それらを出力します。

于 2009-05-08T02:57:37.520 に答える
5

*lineptr++次のように想像しやすいかもしれません。

*(lineptr++)

そこで、s の配列へのポインターが配列char*の次の要素に移動されます。つまり、 からlineptr[0]に移動しlineptr[1]ます。(ポインターのインクリメントは、ポインターの後置インクリメントにより、逆参照の後に発生します。)

したがって、基本的には、次のことが起こります。

  1. lineptr[0](タイプ のchar*) は参照によって取得されます。
  2. ポインターは、配列の次の要素にインクリメントされます。(ポインタの接尾辞インクリメントによってlineptr。)
  3. ポインターが を指すようlineptr[1]になったら、手順 1 からプロセスをもう一度繰り返します。
于 2009-05-08T02:58:18.830 に答える
4

アダムローゼンフィールドの選択された答えは間違っています。クーバードの答えも。そのため、私は両方の回答に反対票を投じました。

Adam Markowitzの解釈*lineptr++は正しいですが、これが合法的なC99コードであるかどうかという主な質問には答えていません。トムフューチャーだけがそうします。残念ながら、彼は説明していません*lineptr++。私は彼らにそれぞれポイントを与えました。

つまり、lineptrは変数であり、ポインタとして操作できます。したがって、ポインタをインクリメントすることは合法です。

lineptr文字のシーケンスへのポインタのシーケンスへのポインタです。つまり、文字列配列の最初の文字列へのポインタです。コードによると、文字列はnull('\ 0')で終了するcharシーケンスであると想定できます。 nlines配列内の文字列の数です。

whileテスト式はnlines-- > 0です。nlines--はポストデクリメントです(--変数の右側にあるため)。したがって、テストが実行された後、テスト結果に関係なく実行されます。

したがって、nlines引数として指定された値がであった0場合、テストが最初に実行され、false;が返されます。ループ内の命令は実行されません。nlinesはとにかくデクリメントされるので、ループnlines後の値は。になることに注意してください。while-1

の場合nlines == 1、テストは戻りtruenlinesデクリメントされます。ループ内の命令は1回実行されます。これらの命令が実行されている間、の値nlinesは。であることに注意してください0。テストを再度実行すると、の場合に戻りnlines == 0ます。

printf命令は式を使用します*lineptr++。これは、ポインターのポストインクリメントです(++変数の右側にあります)。これは、式が最初に評価され、使用にインクリメントが実行されることを意味します。したがって、最初の実行printfで、文字列配列の最初の要素のコピーを受け取ります。これは、文字列の最初の文字へのポインタです。その後lineptrのみインクリメントされます。次回printf実行されるときは、lineptr2番目の要素をポイントし、2番目の文字列が印刷されると3番目の要素に移動します。明らかに最初の文字列を出力したいので、これは理にかなっています。Adam Rosenfieldが正しければ、最初の文字列はスキップされ、最後に最後の文字列を超えて文字列を印刷しようとしますが、これは明らかに悪いことです。

したがって、このprintf手順は、次の2つの手順の簡潔な形式です。

printf("%s\n", *lineptr);
++lineptr; // or lineptr++, which is equivalent but not as good. lineptr += 1; is ok too.

経験則として、プレインクリメントとポストインクリメントのアクションが同等である場合、パフォーマンス上の理由からプレインクリメントの方が望ましいことに注意してください。コンパイラはあなたのためにそれを切り替えるように注意を払います。まあ、ほとんどの場合。可能な場合はいつでも、プレオペレーター自身が良いので、常に使用されます。C ++でポストインクリメントとプレインクリメントを実装すると、その理由がより明確になります。

于 2009-05-08T06:42:10.523 に答える