while(*s++ =*t++) はどのように文字列をコピーしますか?

これと同等です:

while (*t) {
    *s = *t;
    s++;
    t++;
}
*s = *t;

t という文字の場合 ポイントは '\0' です 、while ループが終了します。それまでは、t という文字をコピーします。 s という文字を指しています が指している場合、s をインクリメントします および t 配列内の次の文字を指すようにします。


これには、裏で多くのことが行われています:

while (*s++ = *t++);

st 変数はポインター (ほぼ確実に文字)、s 目的地であること。次の手順は、何が起こっているかを示しています:

  • t の内容 (*t ) は s (*s) にコピーされます )、1 文字。
  • st 両方ともインクリメントされます (++ ).
  • 割り当て (コピー) は、コピーされた文字を返します (while に) ).
  • while その文字がゼロになるまで続きます (C で文字列の終わり) ).

事実上、それは次のとおりです:

while (*t != 0) {
    *s = *t;
    s++;
    t++;
}
*s = *t;
s++;
t++;


s としましょう と t char * です 文字列を指す s (および s を想定) 少なくとも t と同じ大きさです )。 C では、文字列はすべて 0 で終わります (ASCII "NUL")、正しいですか?では、これは何をするのでしょうか:

*s++ = *t++;

まず、*s = *t を実行します 、*t の値をコピーします *s へ .次に、s++ を実行します 、だから s 次の文字を指します。そして t++ を実行します 、だから t 次の文字を指します。これは、演算子の優先順位に関係しています および接頭辞と接尾辞のインクリメント/デクリメント .

演算子の優先順位は、演算子が解決される順序です。簡単な例については、以下をご覧ください:

4 + 2 * 3

これは 4 + (2 * 3) ですか または (4 + 2) * 3 ? 優先順位により、これが最初のものであることはわかっています。 - バイナリ * (乗算演算子) はバイナリ + よりも優先されます (加算演算子) であり、最初に解決されます。

*s++ で 、単項 * があります (ポインター逆参照演算子) および単項 ++ (後置インクリメント演算子)。この場合、++ * よりも優先順位が高い (「より強くバインドする」とも呼ばれる) . ++*s と言ったら 、をインクリメントします *s が指すアドレスではなく s プレフィックスのため インクリメントは逆参照として優先度が低く*なりますが、postfix を使用しました 優先度の高い増分。接頭辞の増分を使用したい場合は、 *(++s) を実行できます 、括弧はすべての下位の優先順位を上書きし、++s を強制するため 最初に来ますが、これは文字列の先頭に空の文字を残すという望ましくない副作用があります.

優先度が高いからといって、最初に発生するわけではないことに注意してください。後置インクリメントは具体的に に発生します *s = *t の値が使用されています。 s++ の前に発生 .

これで *s++ = *t++ を理解できました .しかし、彼らはそれをループに入れました:

while(*s++ = *t++);

このループはする 何もない - アクションはすべて条件にあります。しかし、その条件を確認してください - *s の場合は "false" を返します *t を意味する常に 0 です は 0 でした。これは文字列の末尾にあることを意味します (ASCII "NUL" の場合は yay)。したがって、このループは t に文字がある限りループします 、それらを忠実に s にコピーします 、インクリメント s および t はるばる。このループが終了すると、s NUL で終了し、適切な文字列です。唯一の問題は s です 終わりを指します。 s の先頭を指す別のポインタを手元に用意してください (例:s while() の前 ループ) - それ コピーされた文字列になります:

char *s, *string = s;
while(*s++ = *t++);
printf("%s", string); // prints the string that was in *t

または、こちらをチェックしてください:

size_t i = strlen(t);
while(*s++ = *t++);
s -= i + 1;
printf("%s\n", s); // prints the string that was in *t

長さを取得することから始めたので、終了時にさらにポインター演算を行い、s を配置しました。 最初の場所に戻ります。

もちろん、このコード フラグメント (およびすべてのコード フラグメント) では、簡単にするためにバッファーの問題を無視しています。より良いバージョンはこれです:

size_t i = strlen(t);
char *c = malloc(i + 1);
while(*s++ = *t++);
s -= i + 1;
printf("%s\n", s); // prints the string that was in *t
free(c);

しかし、あなたはすでにそれを知っていました。さもなければ、すぐにみんなのお気に入りの Web サイトでそれについて質問することになるでしょう。;)

* 実際には、それらは同じ優先順位を持っていますが、それは異なるルールによって解決されます。この状況では、効果的に優先度が低くなります。