Neden x [0]! = X [0] [0]! = X [0] [0] [0]?


149

Biraz C ++ okuyorum ve işaretçilerle savaşıyorum. Şunu bildirerek 3 seviye işaretine sahip olabileceğimi anlıyorum:

int *(*x)[5];

bu *xişaretçi olan 5 öğeden oluşan bir dizi için bir işaretçi int. Ayrıca biliyorum x[0] = *(x+0);, x[1] = *(x+1)vb.

Peki, yukarıdaki açıklama göz önüne alındığında, neden x[0] != x[0][0] != x[0][0][0]?


58
x[0], x[0][0]Ve x[0][0][0]farklı türleri vardır. Karşılaştırılamazlar. Ne demek istiyorsun !=?
bolov

4
@celticminstrel aynı değildir: int **x[5]5 öğeden oluşan bir dizidir. Bir öğe int işaretçisi için bir işaretçi
bolov

5
@celticminstrel int** x[5], int'e işaret eden işaretçileri işaret eden beş işaretçi dizisidir. int *(*x)[5]int işaret eden beş işaretli bir dizi işaretçisi.
emlai


5
@ Leo91: Birincisi, burada iki işaretçi seviyeniz var, üç değil. İkincisi, ne anlama x[0] != x[0][0] != x[0][0][0]geliyor? Bu C ++ 'da geçerli bir karşılaştırma değildir. Ayrılsanız x[0] != x[0][0]ve x[0][0] != x[0][0][0]hala geçerli olmasa bile. Peki, sorunuz ne anlama geliyor?
AnT

Yanıtlar:


261

x, 5 işaretçi dizisinin işaretçisi int.
x[0], 5 işaretçi dizisidirint .
x[0][0]bir int.
x[0][0][0]bir int.

                       x[0]
   Pointer to array  +------+                                 x[0][0][0]         
x -----------------> |      |         Pointer to int           +-------+
               0x500 | 0x100| x[0][0]---------------->   0x100 |  10   |
x is a pointer to    |      |                                  +-------+
an array of 5        +------+                        
pointers to int      |      |         Pointer to int                             
               0x504 | 0x222| x[0][1]---------------->   0x222                    
                     |      |                                             
                     +------+                                             
                     |      |         Pointer to int                              
               0x508 | 0x001| x[0][2]---------------->   0x001                    
                     |      |                                             
                     +------+                                             
                     |      |         Pointer to int                              
               0x50C | 0x123| x[0][3]---------------->   0x123                    
                     |      |                                             
                     +------+                                             
                     |      |         Pointer to int                              
               0x510 | 0x000| x[0][4]---------------->   0x000                    
                     |      |                                             
                     +------+                                             

Görebilirsin

  • x[0]bir dizidir ve bir ifadede (bazı istisnalar dışında) kullanıldığında işaretçiyi ilk öğesine dönüştürür. Bu nedenle x[0], ilk elemanın adresini verecektir x[0][0]olduğunu 0x500.
  • x[0][0]bir adresini içerir intolan 0x100.
  • x[0][0][0]Bir içeren intdeğerini 10.

Yani, x[0]eşittir &x[0][0]ve bu nedenle &x[0][0] != x[0][0],.
Dolayısıyla x[0] != x[0][0] != x[0][0][0],.


Bu diyagram benim için biraz kafa karıştırıcı: 0x100kutunun solunda, kutunun solunda görünen 10şekilde 0x500görünmelidir. Bunun yerine sola ve aşağıya doğru olmak.
MM

@MattMcNabb; Kafa karıştırıcı olması gerektiğini düşünmüyorum, ancak daha fazla netlik için öneriye göre değişiyor.
haccks

4
@haccks - Benim için zevk :) Bu diyagramın harika olmasının nedeni, izleyen açıklamaya bile gerek duymamasıdır. Bu şemanın kendisi, soruyu zaten cevapladığını açıklıyor. Takip eden metin sadece bir bonus.
rayryeng

1
Bir diyagram oluşturma yazılımı olan yed'i de kullanabilirsiniz. Düşüncelerimi düzenlemek için bana çok yardımcı oluyor
rpax

@GrijeshChauhan Kodun yorumları için saniyeler kullanıyorum, sunumlar için yeD :)
rpax

133
x[0] != x[0][0] != x[0][0][0]

kendi yazınıza göre,

*(x+0) != *(*(x+0)+0) != *(*(*(x+0)+0)+0)`  

bu basitleştirilmiş

*x != **x != ***x

Neden eşit olmalı?
Birincisi bazı işaretçilerin adresidir.
İkincisi, başka bir işaretçinin adresidir.
Üçüncüsü de bir intdeğer.


Anlayamıyorum ... x [0], x [0] [0], x [0] [0] [0] * (x + 0), * (x + 0 + 0) ile eşdeğerse , * (x + 0 + 0 + 0), neden farklı adresleri olmalı?
Leo91

41
@ Leo91 x[0][0]olduğu (x[0])[0], yani *((*(x+0))+0)değil *(x+0+0). Dereference ikinci saniyeden önce olur [0].
emlai

4
@ Leo91 x[0][0] != *(x+0+0)gibi x[2][3] != x[3][2].
özg

@ Leo91 "Şimdi anladınız" ikinci yorum kaldırıldı. (Yanıtta daha iyi açıklanabilecek) bir şey anlamıyor musunuz yoksa bu sizin yaptığınız şey değil mi? (bazı insanlar çok fazla bilgilendirici içerik olmadan yorumları silmek ister)
deviantfan

@deviantfan üzgünüm ne demek istediğini anlayamıyorum. Cevabı açıklığa kavuşturmaya yardımcı olan birçok yorumu ve yanıtları anlıyorum.
Leo91

50

İşaretçinizin bellek düzeni:

   +------------------+
x: | address of array |
   +------------------+
            |
            V
            +-----------+-----------+-----------+-----------+-----------+
            | pointer 0 | pointer 1 | pointer 2 | pointer 3 | pointer 4 |
            +-----------+-----------+-----------+-----------+-----------+
                  |
                  V
                  +--------------+
                  | some integer |
                  +--------------+

x[0]"dizi adresi"
x[0][0]verir, "işaretçi 0"
x[0][0][0]verir, "biraz tamsayı" verir.

İnanıyorum ki, şimdi hepsinin neden farklı olduğu açık olmalı.


Yukarıdakiler temel anlayış için yeterince yakın, bu yüzden onu yazdığım şekilde yazdım. Bununla birlikte, haccks'in haklı olarak işaret ettiği gibi, ilk satır% 100 kesin değildir. İşte tüm ince detaylar:

C dilinin tanımından, değeri x[0]tamsayı işaretleyicilerinin tüm dizisidir. Ancak, diziler C'de gerçekten hiçbir şey yapamayacağınız bir şeydir. Her zaman adreslerini veya öğelerini manipüle edersiniz, asla bir bütün olarak bütün diziyi manipüle edemezsiniz:

  1. Sen geçebilir x[0]için sizeofoperatör. Ama bu gerçekten değerin bir kullanımı değil, sonucu sadece türüne bağlıdır.

  2. xTürü ile "dizinin adresi" değerini veren adresini alabilirsiniz int*(*)[5]. Diğer bir deyişle:&x[0] <=> &*(x + 0) <=> (x + 0) <=> x

  3. Diğer tüm bağlamlarda , değeri x[0]dizideki ilk öğenin işaretçisine dönüşür. Yani, "dizi adresi" değerine ve türüne sahip bir işaretçi int**. Efekt, xbir tür işaretçiye yayınlamış gibi aynıdır int**.

Durum 3'teki dizi-işaretçi bozulması nedeniyle, x[0]sonuçta tüm kullanımları işaretçi dizisinin başlangıcını gösteren bir işaretçi ile sonuçlanır; çağrı printf("%p", x[0])"dizinin adresi" olarak etiketlenen bellek hücrelerinin içeriğini yazdıracaktır.


1
x[0]dizinin adresi değil.
haccks

1
@haccks Evet, standardın harfini izleyen x[0]dizinin adresi değil, dizinin kendisidir. Ben bu ve x[0]"dizinin adresi" olduğunu neden yazdı derinlemesine bir açıklama ekledim . Umarım beğenmişsindir.
cmaster - reinstate monica

mükemmel iyi açıklayan harika grafikler!
MK

"Ancak, diziler gerçekten C ile hiçbir şey yapamayacağınız bir şeydir." -> Sayaç örneği: printf("%zu\n", sizeof x[0]);bir işaretçinin boyutunu değil, dizinin boyutunu bildirir.
chux - Monica'yı yeniden haziran

@ chux-ReinstateMonica Ben de "Hep söylemeye devam etti manipüle Ben etkisiyle söz numaralandırma noktası 1, ardından kendi adresini veya kendi elemanları, bir bütün olarak asla dizinin tamamı ya" sizeof x[0]...
cmaster - reinstate monica

18
  • x[0]en dıştaki işaretçiyi ( işaretçi -int arası 5 boyutlu diziye işaret eder) ve işaretçi 5 büyüklüğünde bir diziye neden olur int;
  • x[0][0]en dıştaki işaretçiyi dereferences ve dizini indeksler int;
  • x[0][0][0] her şeyi dereferences, somut bir değer ile sonuçlanır.

Bu arada, bu tür bildirimlerin ne anlama geldiğini düşünüyorsanız, cdecl kullanın .


11

Adım ifadeler adım ele alalım x[0], x[0][0]ve x[0][0][0].

xAşağıdaki şekilde tanımlandığı gibi

int *(*x)[5];

ifade x[0]bir tür dizisidir int *[5]. İfadenin ifadeye x[0]eşdeğer olduğunu dikkate alın *x. Bu, bir dizinin işaretçisi olan diziyi kendisinin elde ettiğidir. Bırakın y gibi ifade edelim ki bir deklarasyonumuz var

int * y[5];

İfade x[0][0]eşdeğerdir y[0]ve türü vardır int *. Izin vermek z gibi göstermek bir beyan var

int *z;

ifade x[0][0][0], ifadeye y[0][0]eşdeğer olan z[0]ve türe sahip olan ifadeye eşdeğerdir int.

Böylece sahibiz

x[0] türü var int *[5]

x[0][0] türü var int *

x[0][0][0] türü var int

Yani farklı tipte ve farklı boyutlardaki nesnelerdir.

Örneğin çalıştırın

std::cout << sizeof( x[0] ) << std::endl;
std::cout << sizeof( x[0][0] ) << std::endl;
std::cout << sizeof( x[0][0][0] ) << std::endl;

10

Bunu söylemem gereken ilk şey

x [0] = * (x + 0) = * x;

x [0] [0] = * (* (x + 0) + 0) = * * x;

x [0] [0] [0] = * (* (* (x + 0) + 0)) = * * * x;

Yani * x ≠ * * x ≠ * * * x

Aşağıdaki resimden her şey açıktır.

  x[0][0][0]= 2000

  x[0][0]   = 1001

  x[0]      = 10

resim açıklamasını buraya girin

Bu sadece bir örnektir, burada x [0] [0] [0] = 10

ve adres x [0] [0] [0] olan 1001

bu adres x [0] [0] = 1001 içinde saklanır

ve x [0] [0] ' ın adresi 2000'dir

ve bu adres saklanır x [0] = 2000

Yani x [0] [0] [0] x [0] [0] x [0]

.

Düzenlemeler

Program 1:

{
int ***x;
x=(int***)malloc(sizeof(int***));
*x=(int**)malloc(sizeof(int**));
**x=(int*)malloc(sizeof(int*));
***x=10;
printf("%d   %d   %d   %d\n",x,*x,**x,***x);
printf("%d   %d   %d   %d   %d",x[0][0][0],x[0][0],x[0],x,&x);
}

Çıktı

142041096 142041112 142041128 10
10 142041128 142041112 142041096 -1076392836

Program 2:

{
int x[1][1][1]={10};
printf("%d   %d   %d   %d \n ",x[0][0][0],x[0][0],x[0],&x);
}

Çıktı

10   -1074058436   -1074058436   -1074058436 

3
Cevabınız yanıltıcı. x[0]karınca adresi içermiyor. Bu bir dizi. İlk öğesine işaret etmek için bozunur.
haccks

Hımm ... bu ne anlama geliyor? Düzenlemeniz yanlış cevabınıza kek kiraz gibi. Hiç mantıklı değil
haccks

@haccks Yalnızca işaretçiler kullanıyorsa, bu yanıt doğru olacaktır. Array
apm

7

Dizileri gerçek dünya perspektifinden görseydiniz, şöyle görünecektir:

x[0]sandıklarla dolu bir yük konteyneri.
x[0][0]yük konteyneri içinde ayakkabı kutusu ile dolu tek bir sandıktır.
x[0][0][0]sandık içinde, yük konteynerinin içinde tek bir ayakkabı kutusudur.

Yük konteynerindeki tek sandıktaki tek ayakkabı kutusu olsa bile, yine de bir yük konteyneri değil, bir ayakkabı kutusu


1
x[0][0]üzerinde ayakkabı kutusu yerleri yazılı kağıt parçaları ile dolu tek bir sandık olmaz mıydı ?
wchargin

4

C ++ 'da bir ilke vardır, böylece: bir değişkenin bildirimi tam olarak değişkeni kullanma şeklini gösterir. Beyanınızı dikkate alın:

int *(*x)[5];

(daha açık olarak) olarak yeniden yazılabilir:

int *((*x)[5]);

İlke gereği:

*((*x)[i]) is treated as an int value (i = 0..4)
 (*x)[i] is treated as an int* pointer (i = 0..4)
 *x is treated as an int** pointer
 x is treated as an int*** pointer

Bu nedenle:

x[0] is an int** pointer
 x[0][0] = (x[0]) [0] is an int* pointer
 x[0][0][0] = (x[0][0]) [0] is an int value

Böylece farkı anlayabilirsiniz.


1
x[0]bir işaretçi değil, 5 inçlik bir dizidir. (çoğu bağlamda bir işaretçiye bozulabilir, ancak burada ayrım önemlidir).
MM

Tamam, ama şunu söylemelisiniz: x [0] 5 göstericiden oluşan bir dizi int *
Nghia Bui

@MattMcNabb başına doğru derivasyonu vermek için: *(*x)[5]bir int, yani (*x)[5]bir int *, yani *xbir (int *)[5], yani xbir *((int *)[5]). Yani, xişaretçiler 5-dizi işaretçi int.
wchargin

2

Farklı türleri değere göre karşılaştırmaya çalışıyorsunuz

Adresleri alırsanız beklediğinizden daha fazlasını elde edebilirsiniz

Beyanınızın bir fark yarattığını unutmayın

 int y [5][5][5];

çünkü, istediğiniz karşılaştırmaları sağlayacak y, y[0], y[0][0], y[0][0][0]farklı değerler ve türleri fakat aynı adrese olurdu

int **x[5];

bitişik alan işgal etmez.

xve x [0]aynı adrese sahip, ancak x[0][0]ve x[0][0][0]farklı adreslerde her biri


2
int *(*x)[5]farklıdırint **x[5]
MM

2

pBir işaretçi olmak : p[0][0]eşdeğerlerini içeren yığınları istiflersiniz *((*(p+0))+0).

C referansı (&) ve dereference (*) gösterimlerinde:

p == &p[0] == &(&p[0])[0] == &(&(&p[0])[0])[0])

Şuna eşittir:

p == &*(p+0) == &*(&*(p+0))+0 == &*(&*(&*(p+0))+0)+0

Bakın, & * yeniden kaldırılabilir, sadece kaldırılabilir:

p == p+0 == p+0+0 == p+0+0+0 == (((((p+0)+0)+0)+0)+0)

İlk cümleden sonra her şeyle ne göstermeye çalışıyorsun? Üzerinde çok fazla varyasyon var p == p . &(&p[0])[0]farklıdırp[0][0]
MM

Adam, x bir işaretçi olduğunda neden 'x [0]! = X [0] [0]! = X [0] [0] [0]' diye sordu, değil mi? Ona göstermeye çalıştım, [0] 'ları yığıldığında dereference (*) C gösterimi ile sıkışabildiğini göstermeye çalıştım. Bu nedenle, x'in x [0] eşit olması ve x [0] 'a tekrar & ile başvurması vb. İçin doğru gösterimi göstermeye çalışmaktır.
Luciano

1

Diğer cevaplar doğrudur, ancak hiçbiri üçünün de aynı değeri içermesinin mümkün olduğunu düşünmemektedir ve bu yüzden bir şekilde eksiktirler.

Bunun diğer cevaplardan anlaşılamamasının nedeni, tüm örneklerin, yararlı ve kesinlikle makul olsa da, işaretçinin xkendisine işaret ettiği durumu kapsamamaktadır .

Bu inşa etmek oldukça kolay, ama anlaşılması biraz daha zor. Aşağıdaki programda, üç değerin tümünü aynı olmaya nasıl zorlayabileceğimizi göreceğiz.

NOT: Bu programda davranış tanımlanmamış, ama ben işaretçileri bir şeye ilginç bir göstergesi olarak tamamen buradan post ediyorum edebilir , ama olmamalı .

#include <stdio.h>

int main () {
  int *(*x)[5];

  x = (int *(*)[5]) &x;

  printf("%p\n", x[0]);
  printf("%p\n", x[0][0]);
  printf("%p\n", x[0][0][0]);
}

Bu, hem C89 hem de C99'da uyarı olmadan derlenir ve çıktı aşağıdaki gibidir:

$ ./ptrs
0xbfd9198c
0xbfd9198c
0xbfd9198c

İlginçtir, her üç değer de aynıdır. Ama bu bir sürpriz olmamalı! İlk olarak, programı yıkalım.

Biz beyan xher bir eleman int türü işaretçisi olan 5 elemanlı bir dizi için bir işaretçi olarak. Bu bildirim, çalışma zamanı yığınına 4 bayt xayırır (veya uygulamanıza bağlı olarak daha fazla; makine işaretçilerimde 4 bayttır), bu nedenle gerçek bir bellek konumuna atıfta bulunur. C dil ailesinde, içeriği xsadece çöptür, konumun önceki kullanımından kalan bir şeydir, bu yüzden xkendisi hiçbir yere işaret etmez - kesinlikle ayrılmış alana değil.

Yani, doğal olarak, değişkenin adresini alabilir xve bir yere koyabiliriz, bu yüzden tam olarak bunu yaparız. Ama devam edip x'in içine koyacağız. Yana &xfarklı bir türe sahip x, biz uyarıları alamadım bu yüzden bir döküm yapmak gerekir.

Bellek modeli şöyle görünecektir:

0xbfd9198c
+------------+
| 0xbfd9198c |
+------------+

Böylece adresteki 4 baytlık bellek bloğu 0xbfd9198c, onaltılı değere karşılık gelen bit desenini içerir 0xbfd9198c. Yeterince basit.

Ardından, üç değeri yazdırıyoruz. Diğer cevaplar her ifadenin neyi ifade ettiğini açıklar, bu yüzden ilişki şimdi açık olmalıdır.

Değerlerin aynı olduğunu, ancak sadece çok düşük bir düzeyde olduğunu görebiliriz ... bit kalıpları aynıdır, ancak her bir ifadeyle ilişkili tip verileri yorumlanmış değerlerinin farklı olduğu anlamına gelir. Örneğin x[0][0][0], biçim dizesini kullanarak yazdırırsak %d, çok büyük bir negatif sayı elde ederiz, bu nedenle "değerler" pratikte farklıdır, ancak bit modeli aynıdır.

Bu gerçekten çok basit ... şemalarda, oklar farklı bellek yerine aynı bellek adresini gösteriyor. Ancak, tanımlanmamış bir davranıştan beklenen bir sonucu zorlayabilmemizle birlikte, bu sadece tanımsızdır. Bu üretim kodu değil, sadece bir bütünlük uğruna bir gösteri.

Makul bir durumda, malloc5 int işaretçisi dizisini oluşturmak için ve yine o dizide işaret edilen girişleri oluşturmak için kullanırsınız. mallocher zaman benzersiz bir adres döndürür (bellekte kalmadığınız sürece, bu durumda NULL veya 0 döndürür), bu nedenle böyle kendinden referanslı işaretçiler hakkında asla endişelenmenize gerek kalmaz.

Umarım aradığınız tam yanıt budur. Sen beklememelisiniz x[0], x[0][0]ve x[0][0][0]eşit olmak, ama zorla eğer onlar olabilir. Başının üstünde bir şey olursa, açıklığa kavuşturmak için bana haber ver!


Şimdiye kadar gördüğüm işaretçilerin bir başka garip kullanımı olduğunu söyleyebilirim.
haccks

@haccks Evet, oldukça garip, ama onu parçaladığınızda, diğer örnekler kadar basit. Sadece bit desenlerinin aynı olduğu bir durum olur.
Purag

Kodunuz tanımlanmamış davranışa neden oluyor. x[0]aslında doğru türde geçerli bir nesneyi temsil etmiyor
MM

@MattMcNabb tanımsız ve bu konuda çok netim. Türüne katılmıyorum. xdiziye bir işaretçi olduğundan [], bu işaretçiden bir ofset belirtmek ve dizini silmek için operatörü kullanabiliriz . Orada garip olan ne? Sonucu x[0]bir dizidir ve kullanmakta olduğu yazdırırsanız C şikayet etmiyor %po altında zaten nasıl uygulandığı beri.
Purag

Ve bunu -pedanticbayrakla derlemek hiçbir uyarı üretmez, bu nedenle C, türlerle iyi ...
Purag

0

Türü int *(*x)[5], int* (*)[5]yani 5 göstericiden oluşan bir dizinin işaretçisidir.

  • xints'a 5 göstericiden oluşan ilk dizinin adresidir (türünde bir adres int* (*)[5])
  • x[0]5 göstericiden oluşan ilk dizinin (ints ile aynı adres int* [5]) adresi (ofset adresi x, 0*sizeof(int* [5])yani index * tip-tipi-işaret-işaret ve dereference)
  • x[0][0]dizideki bir int'in ilk göstergesidir (tür ile aynı adres int*) (ofset adresi x by 0*sizeof(int* [5])ve dereference ve sonra by 0*sizeof(int*)ve dereference)
  • x[0][0][0]bir int işaretçisi tarafından işaret edilen ilk int'tir (adres x 0*sizeof(int* [5])ile ofset ve dereference ile bu adresi by 0*sizeof(int*)ve dereference ile ofset ve bu adres by 0*sizeof(int)ve dereference tarafından ofset )

Türü int *(*y)[5][5][5], int* (*)[5][5][5]yani 5x5x5'lik işaretçilerin bir 3d dizisine işaret eder

  • x 5x5x5 işaretçiler içeren ilk 3 boyutlu dizinin türüne sahip giriş int*(*)[5][5][5]
  • x[0]5x5x5 işaretçi değerinin ilk 3 boyutlu dizisinin adresidir (x adresi ve kayıttan ayrılma adresi 0*sizeof(int* [5][5][5]))
  • x[0][0]5x5 işaretçi değerinin ilk 2d dizisinin adresidir (x ile ofset 0*sizeof(int* [5][5][5])ve dereference sonra bu adresi byset 0*sizeof(int* [5][5]))
  • x[0][0][0]ints için 5 işaretçi içeren ilk dizinin adresidir (x 0*sizeof(int* [5][5][5])ile ofset ve adresi atla ve bu adresi by 0*sizeof(int* [5][5])ve byset ile değiştir 0*sizeof(int* [5]))
  • x[0][0][0][0]dizideki bir int için ilk işaretçi (x 0*sizeof(int* [5][5][5])ile ofset ve dereference ile bu adresi 0*sizeof(int* [5][5])ofset 0*sizeof(int* [5])ve bu adres ile 0*sizeof(int*)ve dereference tarafından ofset ve ofset )
  • x[0][0][0][0][0]bir int işaretçisi tarafından işaret edilen ilk int'tir (adres x tarafından 0*sizeof(int* [5][5][5])ve kayıttan ayrılma ve bu adres tarafından 0*sizeof(int* [5][5])bu adresle 0*sizeof(int* [5])ofset ve ofset ve adrese göre 0*sizeof(int*)kayıttan ayrılma ve bu adrese göre kayıttan ayrılma ve ofset 0*sizeof(int))

Dizi bozulmasına gelince:

void function (int* x[5][5][5]){
  printf("%p",&x[0][0][0][0]); //get the address of the first int pointed to by the 3d array
}

Bu geçen eşdeğerdir int* x[][5][5]ya int* (*x)[5][5]onlar ikincisi için tüm çürüme yani. Bu nedenle x[6][0][0]işlevde kullanmak için bir derleyici uyarısı almayacaksınız, ancak x[0][6][0]bu boyut bilgileri korunduğu için alacaksınız

void function (int* (*x)[5][5][5]){
  printf("%p",&x[0][0][0][0][0]); //get the address of the first int pointed to by the 3d array
}
  • x[0] 5x5x5 işaretçilerin ints'a ilk 3 boyutlu dizisinin adresi
  • x[0][0] 5x5'lik işaretçiler için ilk 2d dizisinin adresidir.
  • x[0][0][0] ints'a 5 göstericiden oluşan ilk dizinin adresidir
  • x[0][0][0][0] dizideki int için ilk işaretçi
  • x[0][0][0][0][0] bir int işaretçisi tarafından ilk int gösterilmektedir

Son örnekte, kullanmak *(*x)[0][0][0]yerine anlamsal olarak çok daha x[0][0][0][0][0]açıktır, çünkü buradaki ilk ve son [0], tür nedeniyle çok boyutlu bir diziye bir indeks yerine bir işaretçi dereference olarak yorumlanır. Ancak (*x) == x[0]semantikten bağımsız olarak aynıdırlar . Ayrıca *****x, işaretçiyi 5 kez silme işlemi yaptığınız gibi görünebilir, ancak aslında tamamen aynı olarak yorumlanır: bir ofset, bir dereference, bir dereference, bir diziye 2 ofset ve sadece tür nedeniyle bir dereference operasyonu uyguluyorsunuz.

Esasen siz [0]veya *bir *dizi olmayan tipte olduğunda, bu bir ofset ve öncelik sırasına göre bir dereference *(a + 0).

Ne zaman [0]ya da *bir *dizi tipine ardından bir ardından bir İdempotent dereference ofset var (- bir İdempotent operasyon KQUEUE aynı adresi elde etmek için derleyici tarafından çözülebilir).

Siz [0]veya *1d dizi türüne sahip bir tür olduğunda, o zaman bir ofset sonra bir dereference

Siz [0]veya **bir 2d dizi türü ise, o zaman bir ofset yani bir ofset ve sonra bir idempotent dereference'dir.

Siz [0][0][0]veya ***bir 3d dizi türü ise, o zaman bir ofset + idempotent dereference sonra bir ofset + idempotent dereference sonra bir ofset + idempotent dereference sonra bir dereference. Gerçek dereference yalnızca dizi türü tamamen çıkarıldığında oluşur.

Örneğin örneği int* (*x)[1][2][3]sırayla paketlenmemiş.

  • x bir türü var int* (*)[1][2][3]
  • *xbir türü vardır int* [1][2][3](ofset 0 + idempotent dereference)
  • **xbir türü vardır int* [2][3](ofset 0 + idempotent dereference)
  • ***xbir türü vardır int* [3](ofset 0 + idempotent dereference)
  • ****xbir türü vardır int*(ofset 0 + dereference)
  • *****xtürü var int(ofset 0 + dereference)
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.