2011-12-02 20 views
8

Aşağıdaki programı:Bellek adreslerini çıkardığımda, sonuç neden beklenenden daha küçük?

#include <iostream> 

struct X 
{ 
    int a; 
    float b; 
} x[10], *p1, *p2; 

int main(int argc, char *argv[]) 
{ 
    p1 = &x[1]; 
    p2 = &x[5]; 

    int i = p2 - p1; 

    std::cout << i << std::endl; 
} 

I bellekte X 'nin düzeni, bir int ve float, p1 ihtiva eden 10 kutu ikinci kutuya başında işaret eder görselleştirmek (x[1]) ve p2 işaret 6 kutu (x[5]) başında:

X 0 1 2 3 4 5 6 7 8 9 
     _______________________________ 
    b |__|__|__|__|__|__|__|__|__|__| 
    a |__|__|__|__|__|__|__|__|__|__| 
      |   |  
      |   | 
      p1   p2 

mi benim doğru çizim? Eğer öyleyse neden i 4 sonucudur?
İki adresin çıkarılmasını anlamanın bazı zorlukları var mı?

+0

Bu soruyu 'c' olarak etiketlediniz, ancak örneğinizde 'cout' ifadesini kullandınız, bunun yerine C++. Hangisini kullanıyorsun? –

+0

Evet, sanırım bir C sorusu, ama sanırım basitlik için cout'u kullandım. – Kobe

+4

@DanielPryden Cevapta bir fark yaratmayacak, değil mi? – Szabolcs

cevap

23

pointer arithmetic bu şekilde çalışır. değeri 101 olmaz Bu noktada

p1 = (x*)100; // invalid memory address, just an example! 
p2 = p1 + 1; 

, p2 ziyade 100 + sizeof(x) (diyelim yani 108 8): düşünün. Bir tarafından değil, sizeof(x)'un bir katı ile artırılmıştır! Tersine, bir işaretçiden bir tamsayı çıkartmak aslında sizeof(the pointed to type)'un katlarını çıkarır.

Şimdi int diff = p2 - p1 yaparsanız, 1 geri almayı beklersiniz, 8'u değil! Aksi takdirde, yeni eklediğiniz sayıyı çıkarmanız orijinal değeri vermeyecektir. Bu nedenle, bir işaretçiyi diğerinden çıkarmak, bellek adreslerindeki farkı değil, iki işaretçi arasındaki öğe sayısını verir.

Üstelik iki işaretçiler (daha doğrusu, bu tanımsız davranış ve sen de bir işaretçi kullanmasına izin verilir aynı dizide elemanların işaret sürece işaretçi çıkarma anlamsız olduğunu standart görev son öğenin ardına tek" için "Orada böyle bir nesne olmasa bile".

Son olarak, eğer derleyici, sivri türünün boyutunu bilmiyorsa (yani, işaretçiler void*)? Bu durumda, işaretçi aritmetiğine hiç izin verilmez. Örneğin:

void* p = 100; 
void* x = p + 1; // does not compile¹ 

Bazı Derleyiciler dil şartnamesine bir extension olarak void* işaretçi Aritmetik sağlayabilir ¹. Bu durumda, bu ifade gerçekten derlenebilir ve sonuç, bahsedilen uzantının spesifikasyonuna bağlı olacaktır (örn., Gcc, 101 değeri ile sonuçlanacaktır).

+0

+1 Güzel açıklama – Kobe

+0

Güzel bir açıklama, ancak örneğiniz, uyarılarla da olsa, derlenecektir. olduğunu. Özel olarak yasaklandığına inandığım şey, iki işaretçi eklemektir, yani p ve x'i eklemeyi denediyseniz. –

+0

@DanFego: Bunu yakaladığınız için ve yeni bir şeyler öğrenmeme izin verdiğin için teşekkür ederim (C ve C++ 'nın farklı olduğu bazı daha ince noktalarda olduğu gibi C de çok tecrübeli değilim). Cevabı burada olan şeyin bir açıklamasıyla güncelledim. – Jon

İlgili konular