2013-05-16 25 views
5

私はコードブロックがあります。while(* p2 ++ = * p1 ++)とは何ですか?平均?

int main() 
{ 
    char *p1 = "Hello"; 
    char *p2; 
    p2 = (char*)malloc (20); 
    memset (p2, 0, 20); 
    while (*p2++ = *p1++); 
    printf ("%s\n", p2); 
} 

をしかし、私はライン しばらく(* P2 ++ = * P1 ++)の作業を説明することはできません。 この数式で操作の順序を教えてください。

+1

[どのように "while(* s ++ = * t ++)"は動作しますか?](http://stackoverflow.com/q/810129/4279) – jfs

答えて

17

これは古典的なCコードで、すべてを1行に入れることで非常に巧妙に見えます。

while (*p2++ = *p1++);が言い換えれば

strcpy(p2, p1); 
p1 += strlen(p1) + 1; 
p2 += strlen(p2) + 1; 

に相当し、p1とをコピーヌルで終了する文字列は、宛先文字列の末尾を指すソース文字列の末尾とp2を指し終わります。

+6

+1は賢く見えるようにすることについてのコメントです。 –

+5

*機能的には同等*です。掲載された同等のコードには、さらにオーバーヘッドがあります。 strlen()は文字列を繰り返し呼び出す*もう一度*。 –

+18

これは狂ったことではありません。ヘック、それはKRに現れ、私はあなたが「過度に賢い」ことをしようとしていると非難するとは思わない。あなたのバージョンは不必要に高価です。 –

9

これは文字列のコピーですが、元のポインタ値は失われています。元のポインタ値を保存する必要があります。

int main() 
{ 
    char *p1 = "Hello"; 
    char *p2 = malloc(20); 
    char *p3 = p2; 
    memset (p2, 0, 20); 
    while (*p2++ = *p1++); 
    printf ("%s\n", p3); 
} 

whileループの実際の意味論的な説明は次のようなものになるだろう:

for (;;) { 
    char *q2 = p2;    // original p2 in q2 
    char *q1 = p1;    // original p1 in q1 
    char c = *q1;    // original *p1 in c 
    p2 += 1;     // complete post increment of p2 
    p1 += 1;     // complete post increment of p1 
    *q2 = c;     // copy character *q1 into *q2 
    if (c) continue;   // continue if c is not 0 
    break;      // otherwise loop ends 
} 

q1q2が保存され、p2p1がインクリメントされる順序を入れ替えてもよいという順序。 〜cの保存は、q1が保存された後にいつでも実行できます。 cから*q2への割り当ては、cが保存された後にいつでも実行できます。私の封筒の裏には、少なくとも40種類の解釈があります。

+0

元のコードでもメモリリークが発生しました。 – Lundin

+0

@ Lundin:割り当てられたメモリは 'free()'しませんでしたが、プログラムは終了しています。これはメモリデバッグツールのリークです。しかし、はい、一般的に、すべての 'malloc()'(またはそれに類するもの)は 'free()'を伴います。元のコードは、元のポインタを復元するのが難しくなります。 – jxh

+1

'memset'のために、未定義の動作ではありません。元のプログラムの 'printf'は、' \ n'だけを出力することが保証されています。 – user9876

1

whileループは、式*p2++ = *p1++を評価しています。 whileループ式:
*p2 = *p1は、*p1の結果を使用して評価されます。ただし、式がfalseまたは(0)と評価されても、この値はまだ*p2に割り当てられます。この書き換え:

char c; 

do 
{ 
    c = *p1; /* read the src byte */ 
    *p2 = c; /* write to dst byte */ 

    p2++, p1++; /* increment src, dst pointers */ 
} 
while (c != 0); 

あなたは、読み出し/書き込みが少なくとも一度を発生することに気づくでしょう。 Cの文字列p1がヌルで終了し、p2にC文字列のための十分な記憶容量がある限り、それは問題ありません。つまり、mallocは少なくともstrlen(p1) + 1バイトを割り当てる必要があります。このコードでは、これは真です。

他の人が指摘したように、最後の反復は、まだ有効なポインタですが、逆参照するときの結果は未定義とアドレス1 - 過去・エンド、でp1を残します。 p2のアドレスは、20バイトを割り当てているため、有効なポインタと有効な逆参照です。ただし、p2は、C文字列のコピーを指していません。何が欲しいのと同等です:mainからの出口にp2でメモリを解放します

char *p1 = "Hello"; 
char *p2, *tmp; 

p2 = (char*)malloc (20); 
memset (p2, 0, 20); 

tmp = p2; 
while (*tmp++ = *p1++); 

printf ("%s\n", p2); 

ほとんどのオペレーティングシステムが、への対応する呼び出しでリソースをリラックスするのに良い方法です:

free(p2); 
最後に

。適切な練習問題については、戻り値がmallocであることを確認して、割り当てが成功したことを確認する必要があります。

+1

'p2' *はヌルで終了するC文字列を指します。これは、 'p2'バッファが' p1'よりも大きく割り当てられ、 'memset'でゼロにされたためです – user9876

関連する問題