2013-05-16 15 views
5

bir kod bloğu vardır:Ne yapar (* p2 ++ = * p1 ++); anlamına gelmek?

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

Ama hattı süre (* p2 ++ = * p1 ++) çalışmasını açıklar olamaz; Bu formülde işlem sırasını bana bildirir misiniz?

+1

[while (* s ++ = * t ++) ”nasıl çalışır? (Http://stackoverflow.com/q/810129/4279) – jfs

cevap

17

Her şeyi bir satıra yerleştirerek son derece akıllı görünmeye çalışan klasik C kodu.

while (*p2++ = *p1++); başka deyişle

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

eşdeğerdir, p1 ile kopyalar boş sonlandırılmış dize, hedef dizenin sonuna işaret kaynak dize sonu ve p2 işaret kadar biten.

+6

+1 akıllı görünmeye çalışmakla ilgili yorum için. –

+5

Sadece * işlevsel olarak * eşdeğerdir. Gönderilen eşdeğer kod ek yüke sahiptir. strlen(), dizeleri tekrar tekrar arar * tekrar *. –

+18

Evet, bu delilik bir şey değil. Heck, KR'da görünüyor ve onları "aşırı zeki" olmaya çalışmakla suçlayacağını sanmıyorum. Sürümünüz gereksiz yere pahalı. –

9

Bu bir dize kopyasıdır, ancak özgün işaretçi değerini kaybediyorsunuz. Orijinal işaretçi değerini kaydetmelisiniz.

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 
} 
q1 ve q2 kaydedilir olduğunu

düzen ve p2 ve p1 değiştirmiş olabildikleri artırılır sırayla:

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

while döngüsünde gerçek anlamsal açıklama gibi bir şey olurdu. 'un c'a kaydedilmesi, q1 kaydedildikten sonra herhangi bir zamanda oluşabilir. c'un *q2'a atanması, c kaydedildikten sonra herhangi bir zamanda oluşabilir. Zarfın arkasında, bu en az 40 farklı yorum için çalışıyor.

+0

Orijinal kod ayrıca bir bellek sızıntısı yarattı. – Lundin

+0

@Lundin: Tahsis edilen belleği serbest bırakmadı, ancak program çıkıyor. Bellek hata ayıklama araçlarına sadece bir sızıntı. Ancak, evet, genellikle, her 'malloc()' (ya da benzeri) bir 'özgür()' ile eşlik etmelidir. Orijinal kod, orijinal işaretçiyi kurtarmayı zorlaştırır. – jxh

+1

Bu 'memset' nedeniyle tanımlanmamış bir davranış değil. Orijinal programdaki 'printf' sadece' \ n' yazdırmak için garantilidir. – user9876

1

while döngü, şu ifadeyi değerlendiriyor: *p2++ = *p1++. while döngü ifadesi:
*p2 = *p1, *p1 sonucu kullanılarak değerlendirilir. Ancak, ifade false veya (0) olarak değerlendirilse bile bu değer hala *p2'a atanır. Bu Yeniden Yazma:

char c; 

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

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

Bir okuma/yazma kez en azoluşacak göreceksiniz. Tamam, C string p1 nul sonlandırıldı ve p2 C dizesi için yeterli depolama alanı olduğu sürece. Yani, malloc en az strlen(p1) + 1 bayt ayırmalıdır. Sağlanan bu kodda, bu doğrudur. Diğerleri işaret gibi

, son yineleme bir adrese hala geçerli bir işaretçi, ancak indirgenmedikleri zaman sonuçları tanımlanmamış olan tek geçmiş uç en p1 bırakacaktır. 20 bayt ayırdığınız için p2 adresinin geçerli bir işaretçisidir ve geçerli bir değerdir. Ancak, p2 artık C dizesi kopyasına işaret etmiyor.İstediğin bir eşdeğerdir: main çıkılırken p2 hafızayı yayınlayacak

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

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

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

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

Çoğu işletim sistemleri, ancak karşılık gelen bir çağrıyla kaynaklarını gevşemeye iyi bir uygulamadır:

free(p2); 
Sonunda

. İyi uygulama konusunda, tahsinin başarılı olmasını sağlamak için malloc dönüş değerini de kontrol etmelisiniz.

+1

'p2' * * bir nul sonlandırılmış C dizesine işaret eder. Çünkü 'p2' tamponu 'p1' den daha büyük ayrılmış ve 'memset' ile sıfırlandı – user9876