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

149

Saya belajar sedikit C ++ dan saya bertarung dengan pointer. Saya mengerti bahwa saya dapat memiliki 3 level pointer dengan menyatakan:

int *(*x)[5];

jadi itu *xadalah pointer ke array 5 elemen yang pointer ke int. Saya juga tahu itu x[0] = *(x+0);, x[1] = *(x+1)dan seterusnya ....

Jadi, mengingat deklarasi di atas, mengapa x[0] != x[0][0] != x[0][0][0]?

Leo91
sumber
58
x[0], x[0][0]dan x[0][0][0]memiliki berbagai jenis. Mereka tidak bisa dibandingkan. Apa maksudmu !=?
bolov
4
@celticminstrel mereka tidak sama: int **x[5]adalah array dari 5 elemen. Sebuah elemen adalah pointer ke pointer ke int`
bolov
5
@celticminstrel int** x[5]akan menjadi array dari lima pointer yang menunjuk ke pointer yang menunjuk ke int. int *(*x)[5]adalah pointer ke array lima pointer yang mengarah ke int.
emlai
5
@celticminstrel aturan kanan-kiri , aturan spirale , C omong kosong ↔ Bahasa Inggris dan Anda 'dalam perjalanan Anda untuk menjadi programmer bintang tiga :)
bolov
5
@ Leo91: Pertama, Anda memiliki dua level pointer di sini, bukan tiga. Kedua, apa x[0] != x[0][0] != x[0][0][0]artinya? Ini bukan perbandingan yang valid di C ++. Bahkan jika Anda membaginya menjadi x[0] != x[0][0]dan x[0][0] != x[0][0][0]itu masih tidak valid. Jadi, apa maksud pertanyaan Anda?
AnT

Jawaban:

261

xadalah pointer ke array 5 pointer int.
x[0]adalah array dari 5 pointer ke int.
x[0][0]adalah pointer ke sebuah int.
x[0][0][0]adalah sebuah 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                    
                     |      |                                             
                     +------+                                             

Anda bisa melihatnya

  • x[0]adalah array dan akan dikonversi menjadi penunjuk ke elemen pertama saat digunakan dalam ekspresi (dengan beberapa pengecualian). Oleh karena itu x[0]akan memberikan alamat elemen pertamanya x[0][0]yaitu 0x500.
  • x[0][0]berisi alamat intyang merupakan 0x100.
  • x[0][0][0]mengandung intnilai 10.

Jadi, x[0]sama dengan &x[0][0]dan karenanya &x[0][0] != x[0][0],.
Karenanya x[0] != x[0][0] != x[0][0][0],.

haccks
sumber
Diagram ini agak membingungkan bagi saya: 0x100harus segera muncul di sebelah kiri kotak yang berisi 10, cara yang sama yang 0x500muncul di sebelah kiri kotaknya. Alih-alih itu jauh ke kiri, dan di bawah.
MM
@MattMcNabb; Saya tidak berpikir itu harus membingungkan, tetapi berubah sesuai saran Anda untuk kejelasan lebih lanjut.
pukul
4
@haccks - Dengan senang hati :) Alasan mengapa diagram itu hebat adalah karena Anda bahkan tidak memerlukan penjelasan yang Anda berikan yang mengikutinya. Diagram itu sendiri cukup jelas karena sudah menjawab pertanyaan. Teks yang mengikuti hanyalah bonus.
rayryeng
1
Anda juga dapat menggunakan yed, perangkat lunak diagram. Ini banyak membantu saya untuk mengatur pikiran saya
rpax
@GrijeshChauhan Saya menggunakan asciiflow untuk komentar kode, kamu untuk presentasi :)
rpax
133
x[0] != x[0][0] != x[0][0][0]

menurut posting Anda sendiri,

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

yang disederhanakan

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

Kenapa harus sama?
Yang pertama adalah alamat beberapa pointer.
Yang kedua adalah alamat pointer lain.
Dan yang ketiga adalah beberapa intnilai.

deviantfan
sumber
Saya tidak mengerti ... jika x [0], x [0] [0], x [0] [0] [0] setara dengan * (x + 0), * (x + 0 + 0) , * (x + 0 + 0 + 0), mengapa mereka harus memiliki alamat yang berbeda?
Leo91
41
@ Leo91 x[0][0]adalah (x[0])[0], yaitu *((*(x+0))+0), tidak *(x+0+0). Dereferensi terjadi sebelum yang kedua [0].
emlai
4
@ Leo91 x[0][0] != *(x+0+0)sama seperti x[2][3] != x[3][2].
özg
@ Leo91 Komentar kedua yang Anda "dapatkan sekarang" telah dihapus. Apakah Anda tidak memahami sesuatu (yang dapat dijelaskan dengan lebih baik dalam jawabannya), atau apakah ini bukan perbuatan Anda? (beberapa orang suka menghapus komentar tanpa banyak konten informatif)
deviantfan
@deviantfan maaf saya tidak mengerti maksud Anda. Saya mengerti jawabannya juga banyak komentar yang membantu saya menjelaskan konsep ini.
Leo91
50

Berikut adalah tata letak memori dari pointer Anda:

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

x[0]menghasilkan "address of array",
x[0][0]menghasilkan "pointer 0",
x[0][0][0]menghasilkan "some integer".

Saya percaya, itu harus jelas sekarang, mengapa mereka semua berbeda.


Di atas cukup dekat untuk pemahaman dasar, itulah sebabnya saya menulisnya dengan cara saya menulisnya. Namun, seperti yang ditunjukkan oleh haccks dengan tepat, baris pertama tidak 100% tepat. Jadi, inilah semua detail bagusnya:

Dari definisi bahasa C, nilai x[0]adalah seluruh array pointer integer. Namun, array adalah sesuatu yang tidak bisa Anda lakukan dengan C. Anda selalu memanipulasi alamat atau elemen mereka, tidak pernah seluruh array secara keseluruhan:

  1. Anda dapat lolos x[0]ke sizeofoperator. Tapi itu bukan penggunaan nilai, hasilnya tergantung dari jenisnya saja.

  2. Anda dapat mengambil alamatnya yang menghasilkan nilai x, yaitu "alamat array" dengan tipe int*(*)[5]. Dengan kata lain:&x[0] <=> &*(x + 0) <=> (x + 0) <=> x

  3. Dalam semua konteks lain , nilai x[0]kehancuran akan menjadi pointer ke elemen pertama dalam array. Artinya, sebuah pointer dengan nilai "address of array" dan jenisnya int**. Efeknya sama seperti jika Anda menggunakan cast xtype int**.

Karena peluruhan array-pointer dalam kasus 3., semua penggunaan x[0]akhirnya menghasilkan pointer yang menunjukkan awal array pointer; panggilan printf("%p", x[0])akan mencetak isi sel memori yang dilabeli sebagai "alamat array".

cmaster - mengembalikan monica
sumber
1
x[0]bukan alamat array.
pukul
1
@haccks Ya, mengikuti huruf standar, x[0]bukan alamat array, itu array itu sendiri. Saya telah menambahkan penjelasan mendalam tentang ini, dan mengapa saya menulis itu x[0]adalah "alamat array". Saya harap Anda menyukainya.
cmaster - mengembalikan monica
grafik mengagumkan yang menjelaskannya dengan sangat baik!
MK
"Namun, array adalah sesuatu yang tidak bisa kamu lakukan dengan C." -> Contoh penghitung: printf("%zu\n", sizeof x[0]);melaporkan ukuran array, bukan ukuran pointer.
chux
@ chux-ReinstateMonica Dan saya melanjutkan dengan mengatakan "Anda selalu memanipulasi alamat atau elemen mereka, tidak pernah seluruh array secara keseluruhan", diikuti oleh poin 1 dari enumerasi di mana saya berbicara tentang efek sizeof x[0]...
cmaster - mengembalikan monica
18
  • x[0]dereferensi pointer terluar ( pointer ke array ukuran 5 dari pointer ke int) dan menghasilkan array ukuran 5 dari pointer ke int;
  • x[0][0]dereferensi pointer terluar dan indeks array, menghasilkan pointer ke int;
  • x[0][0][0] menyangkal segala sesuatu, menghasilkan nilai yang konkret.

Ngomong-ngomong, jika Anda pernah merasa bingung dengan apa arti deklarasi ini, gunakan cdecl .

d125q
sumber
11

Biarkan mempertimbangkan langkah demi langkah ekspresi x[0], x[0][0]dan x[0][0][0].

Seperti xdidefinisikan dengan cara berikut

int *(*x)[5];

maka ekspresi x[0]adalah array tipe int *[5]. Mempertimbangkan bahwa ekspresi x[0]sama dengan ekspresi *x. Itu adalah penereferensi pointer ke array kita mendapatkan array itu sendiri. Biarkan dilambangkan seperti kamu bahwa kita memiliki deklarasi

int * y[5];

Ekspresi x[0][0]sama dengan y[0]dan memiliki tipe int *. Biarkan dilambangkan seperti z yaitu kita memiliki deklarasi

int *z;

ekspresi x[0][0][0]sama dengan ekspresi y[0][0]yang pada gilirannya sama dengan ekspresi z[0]dan memiliki tipe int.

Jadi kita punya

x[0] memiliki tipe int *[5]

x[0][0] memiliki tipe int *

x[0][0][0] memiliki tipe int

Jadi mereka adalah objek dari tipe yang berbeda dan dengan cara ukuran yang berbeda.

Jalankan misalnya

std::cout << sizeof( x[0] ) << std::endl;
std::cout << sizeof( x[0][0] ) << std::endl;
std::cout << sizeof( x[0][0][0] ) << std::endl;
Vlad dari Moskow
sumber
10

Hal pertama yang harus saya katakan itu

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

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

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

Jadi * x ≠ * * x ≠ * * * x

Dari gambar berikut semuanya jelas.

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

  x[0][0]   = 1001

  x[0]      = 10

masukkan deskripsi gambar di sini

Ini hanya sebuah contoh, di mana nilai x [0] [0] [0] = 10

dan alamat x [0] [0] [0] adalah 1001

alamat itu disimpan dalam x [0] [0] = 1001

dan alamat x [0] [0] adalah 2000

dan alamat itu disimpan di x [0] = 2000

Jadi x [0] [0] [0] x [0] [0] x [0]

.

EDITING

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);
}

Keluaran

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);
}

Keluaran

10   -1074058436   -1074058436   -1074058436 
apm
sumber
3
Jawaban Anda menyesatkan. x[0]tidak mengandung alamat semut. Ini sebuah array. Ini akan membusuk untuk menunjuk ke elemen pertama.
pukul
Ummm ... apa artinya? Hasil edit Anda seperti ceri untuk jawaban yang salah. Tidak masuk akal
haccks
@ haccks Jika menggunakan pointer saja, jawaban ini akan benar. Akan ada beberapa perubahan di bagian alamat ketika menggunakan Array
apm
7

Jika Anda melihat array dari perspektif dunia nyata, itu akan muncul sebagai berikut:

x[0]adalah wadah pengiriman yang penuh dengan peti.
x[0][0]adalah peti tunggal, penuh kotak sepatu, dalam wadah pengiriman.
x[0][0][0]adalah kotak sepatu tunggal di dalam peti, di dalam wadah pengiriman.

Sekalipun itu adalah satu-satunya kotak sepatu di satu-satunya peti dalam wadah pengiriman, itu masih kotak sepatu dan bukan wadah pengiriman

David Opsional Courtenay
sumber
1
bukankah x[0][0]akan ada satu peti penuh dengan selembar kertas yang memiliki lokasi kotak sepatu tertulis di atasnya?
wchargin
4

Ada prinsip dalam C ++ sehingga: deklarasi variabel menunjukkan dengan tepat cara menggunakan variabel. Pertimbangkan deklarasi Anda:

int *(*x)[5];

yang dapat ditulis ulang sebagai (untuk lebih jelas):

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

Karena prinsipnya, kami memiliki:

*((*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

Karena itu:

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

Jadi Anda bisa mengetahui perbedaannya.

Nghia Bui
sumber
1
x[0]adalah array 5 int, bukan pointer. (itu mungkin membusuk ke pointer di sebagian besar konteks tetapi perbedaannya penting di sini).
MM
Oke, tetapi Anda harus mengatakan: x [0] adalah array dari 5 pointer int *
Nghia Bui
Untuk memberikan derivasi yang benar per @MattMcNabb: *(*x)[5]is int, so (*x)[5]is int *, so *xan (int *)[5], so xan *((int *)[5]). Artinya, xadalah pointer ke pointer 5-array ke int.
wchargin
2

Anda mencoba membandingkan berbagai jenis berdasarkan nilai

Jika Anda mengambil alamat, Anda mungkin mendapatkan lebih dari yang Anda harapkan

Ingatlah bahwa deklarasi Anda membuat perbedaan

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

akan memungkinkan perbandingan Anda inginkan, karena y, y[0], y[0][0], y[0][0][0]akan memiliki nilai yang berbeda dan jenis tetapi alamat yang sama

int **x[5];

tidak menempati ruang yang berdekatan.

xdan x [0]memiliki alamat yang sama, tapi x[0][0]dan x[0][0][0]masing-masing di alamat yang berbeda

Glenn Teitelbaum
sumber
2
int *(*x)[5]berbeda denganint **x[5]
MM
2

Menjadi ppenunjuk: Anda menumpuk dereferensi dengan p[0][0], yang setara dengan *((*(p+0))+0).

Dalam referensi C (&) dan notasi (*):

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

Setara dengan:

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

Lihat itu, & * dapat di-refactored, cukup hapus:

p == p+0 == p+0+0 == p+0+0+0 == (((((p+0)+0)+0)+0)+0)
Luciano
sumber
Apa yang ingin Anda tunjukkan dengan segala sesuatu setelah kalimat pertama Anda? Anda hanya memiliki banyak variasi p == p . &(&p[0])[0]berbeda denganp[0][0]
MM
Orang itu bertanya mengapa 'x [0]! = X [0] [0]! = X [0] [0] [0]' ketika x adalah penunjuk, kan? Saya mencoba menunjukkan kepadanya, bahwa ia dapat terjebak oleh notasi C dereference (*) ketika ia menumpuk [0]. Jadi, ini merupakan percobaan untuk menunjukkan padanya notasi yang benar agar x sama dengan x [0], merujuk x [0] lagi dengan &, dan seterusnya.
Luciano
1

Jawaban yang lain benar, tetapi tidak satupun dari mereka yang menekankan gagasan bahwa ketiga hal itu mungkin mengandung nilai yang sama , dan karena itu mereka tidak lengkap.

Alasan ini tidak dapat dipahami dari jawaban lain adalah bahwa semua ilustrasi, meskipun bermanfaat dan jelas masuk akal dalam sebagian besar keadaan, gagal untuk menutupi situasi di mana pointer xmenunjuk ke dirinya sendiri.

Ini cukup mudah untuk dibangun, tetapi jelas agak sulit untuk dipahami. Dalam program di bawah ini, kita akan melihat bagaimana kita dapat memaksa ketiga nilai menjadi identik.

CATATAN: Perilaku dalam program ini tidak terdefinisi, tapi saya mempostingnya di sini murni sebagai demonstrasi menarik dari sesuatu yang dapat dilakukan pointer , tetapi tidak boleh .

#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]);
}

Ini mengkompilasi tanpa peringatan di C89 dan C99, dan hasilnya adalah sebagai berikut:

$ ./ptrs
0xbfd9198c
0xbfd9198c
0xbfd9198c

Cukup menarik, ketiga nilai itu identik. Tapi ini seharusnya bukan kejutan! Pertama, mari kita uraikan programnya.

Kami mendeklarasikan xsebagai pointer ke array 5 elemen di mana setiap elemen bertipe pointer ke int. Deklarasi ini mengalokasikan 4 byte pada tumpukan runtime (atau lebih tergantung pada implementasi Anda; pada pointer mesin saya adalah 4 byte), jadi xmerujuk ke lokasi memori yang sebenarnya. Dalam kelompok bahasa C, isinya xhanya sampah, sesuatu yang tersisa dari penggunaan lokasi sebelumnya, jadi xitu sendiri tidak menunjuk ke mana pun — tentu saja tidak untuk mengalokasikan ruang.

Jadi, secara alami, kita dapat mengambil alamat variabel xdan meletakkannya di suatu tempat, jadi itulah yang kita lakukan. Tapi kita akan pergi ke depan dan memasukkannya ke x sendiri Karena &xmemiliki tipe yang berbeda dengan x, kita perlu melakukan pemeran sehingga kita tidak mendapatkan peringatan.

Model memori akan terlihat seperti ini:

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

Jadi blok 4 byte memori pada alamat 0xbfd9198cberisi pola bit yang sesuai dengan nilai heksadesimal 0xbfd9198c. Cukup sederhana.

Selanjutnya, kami mencetak tiga nilai. Jawaban yang lain menjelaskan apa yang dirujuk oleh masing-masing ungkapan, sehingga hubungannya harus jelas sekarang.

Kita dapat melihat bahwa nilainya sama, tetapi hanya dalam arti yang sangat rendah ... pola bit mereka identik, tetapi tipe data yang terkait dengan setiap ekspresi berarti nilainya yang ditafsirkan berbeda. Sebagai contoh, jika kita mencetak x[0][0][0]menggunakan string format %d, kita akan mendapatkan angka negatif yang sangat besar, sehingga "nilai" dalam praktiknya berbeda, tetapi pola bitnya sama.

Ini sebenarnya sangat sederhana ... dalam diagram, panah hanya menunjuk ke alamat memori yang sama daripada yang berbeda. Namun, sementara kami dapat memaksakan hasil yang diharapkan dari perilaku yang tidak terdefinisi, hanya saja - tidak terdefinisi. Ini bukan kode produksi tetapi hanya demonstrasi demi kelengkapan.

Dalam situasi yang masuk akal, Anda akan menggunakan mallocuntuk membuat array 5 int pointer, dan lagi untuk membuat int yang diarahkan ke array itu. mallocselalu mengembalikan alamat unik (kecuali Anda kehabisan memori, dalam hal ini mengembalikan NULL atau 0), jadi Anda tidak perlu khawatir tentang petunjuk referensial diri seperti ini.

Semoga itulah jawaban lengkap yang Anda cari. Anda seharusnya tidak mengharapkan x[0],, x[0][0]dan x[0][0][0]menjadi sama, tetapi mereka bisa jika dipaksa. Jika ada yang terlintas di kepala Anda, beri tahu saya agar saya bisa mengklarifikasi!

Purag
sumber
Saya akan mengatakan bahwa penggunaan pointer yang aneh pernah saya lihat.
pukul
@haccks Ya, ini sangat aneh, tetapi ketika Anda memecahnya, itu sama mendasarnya dengan contoh lainnya. Itu hanya terjadi pada kasus di mana pola bit semua sama.
Purag
Kode Anda menyebabkan perilaku yang tidak terdefinisi. x[0]tidak benar-benar mewakili objek yang valid dari jenis yang benar
MM
@MattMcNabb tidak terdefinisi, dan saya sangat jelas tentang itu sebenarnya. Saya tidak setuju tentang jenisnya. xadalah pointer ke array, jadi kita bisa menggunakan []operator untuk menentukan offset dari pointer itu dan men-dereferensinya. Apa yang aneh di sana? Hasilnya x[0]adalah array, dan C tidak mengeluh jika Anda mencetak menggunakan itu %pkarena begitulah penerapannya di bawahnya.
Purag
Dan mengompilasinya dengan -pedanticflag tidak menghasilkan peringatan, jadi C tidak masalah dengan jenisnya ...
Purag
0

Jenis int *(*x)[5]yaitu int* (*)[5]yaitu pointer ke array dari 5 pointer ke int.

  • xadalah alamat dari array pertama dari 5 pointer ke ints (alamat dengan tipe int* (*)[5])
  • x[0]alamat array pertama dari 5 pointer ke int (alamat yang sama dengan tipe int* [5]) (alamat offset x dengan 0*sizeof(int* [5])indeks yaitu * ukuran-jenis-sedang-menunjuk-ke-dan-dereferensi)
  • x[0][0]adalah pointer pertama ke int dalam array (alamat yang sama dengan tipe int*) (alamat offset x oleh 0*sizeof(int* [5])dan dereference dan kemudian oleh 0*sizeof(int*)dan dereference)
  • x[0][0][0]adalah int pertama yang ditunjukkan oleh pointer ke int (mengimbangi alamat x oleh 0*sizeof(int* [5])dan dereference dan mengimbangi alamat itu dengan 0*sizeof(int*)dan dereference dan mengimbangi alamat itu dengan 0*sizeof(int)dan dereference)

Jenis int *(*y)[5][5][5]yaitu int* (*)[5][5][5]yaitu pointer ke array 3d dari 5x5x5 pointer ke int

  • x adalah alamat array 3d pertama dari pointer 5x5x5 ke ints dengan tipe int*(*)[5][5][5]
  • x[0]adalah alamat array 3d pertama dari pointer 5x5x5 ke ints (alamat offset x oleh 0*sizeof(int* [5][5][5])dan dereference)
  • x[0][0]adalah alamat array 2d pertama dari pointer 5x5 ke ints (alamat offset x oleh 0*sizeof(int* [5][5][5])dan dereference lalu offset alamat itu dengan 0*sizeof(int* [5][5]))
  • x[0][0][0]adalah alamat dari array pertama dari 5 pointer ke ints (alamat offset x oleh 0*sizeof(int* [5][5][5])dan dereference dan mengimbangi alamat itu dengan 0*sizeof(int* [5][5])dan mengimbangi alamat itu dengan 0*sizeof(int* [5]))
  • x[0][0][0][0]adalah pointer pertama ke int dalam array (mengimbangi alamat x dengan 0*sizeof(int* [5][5][5])dan dereference dan mengimbangi alamat itu dengan 0*sizeof(int* [5][5])dan mengimbangi alamat itu dengan 0*sizeof(int* [5])dan mengimbangi alamat itu dengan 0*sizeof(int*)dan dereference)
  • x[0][0][0][0][0]adalah int pertama yang ditunjukkan oleh pointer ke int (mengimbangi alamat x oleh 0*sizeof(int* [5][5][5])dan dereference dan mengimbangi alamat itu dengan 0*sizeof(int* [5][5])dan mengimbangi alamat itu dengan 0*sizeof(int* [5])dan mengimbangi alamat itu dengan 0*sizeof(int*)dan dereference dan mengimbangi alamat itu dengan 0*sizeof(int)dan dereference)

Adapun peluruhan array:

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
}

Ini sama dengan melewati int* x[][5][5]atau int* (*x)[5][5]artinya mereka semua membusuk ke yang terakhir. Inilah sebabnya mengapa Anda tidak akan mendapatkan peringatan kompiler untuk digunakan x[6][0][0]dalam fungsi tetapi Anda akan melakukannya x[0][6][0]karena informasi ukuran itu dipertahankan

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] adalah alamat array 3d pertama dari pointer 5x5x5 ke ints
  • x[0][0] adalah alamat array 2d pertama dari pointer 5x5 ke ints
  • x[0][0][0] adalah alamat dari array pertama dari 5 pointer ke int
  • x[0][0][0][0] adalah pointer pertama ke int dalam array
  • x[0][0][0][0][0] adalah int pertama yang ditunjukkan oleh pointer ke int

Dalam contoh terakhir, secara semantik jauh lebih jelas untuk digunakan *(*x)[0][0][0]daripada x[0][0][0][0][0], ini karena yang pertama dan terakhir di [0]sini ditafsirkan sebagai pointer dereference daripada indeks ke dalam array multidimensi, karena jenisnya. Namun mereka identik karena (*x) == x[0]terlepas dari semantik. Anda juga dapat menggunakan *****x, yang akan terlihat seperti Anda mendereferensi pointer 5 kali, tetapi sebenarnya ditafsirkan persis sama: offset, dereference, dereference, 2 offset menjadi array dan dereference, murni karena jenisnya Anda menerapkan operasi untuk.

Pada dasarnya ketika Anda [0]atau *suatu *untuk jenis non array, itu adalah offset dan dereference karena urutan prioritas dari *(a + 0).

Ketika Anda [0]atau *seorang *untuk sebuah array tipe maka itu offset maka dereference idempoten (dereference diselesaikan oleh compiler untuk menghasilkan alamat yang sama - itu operasi idempoten).

Ketika Anda [0]atau *tipe dengan tipe array 1d maka itu offset kemudian dereferensi

Jika Anda [0]atau **tipe array 2d maka itu hanya offset yaitu offset dan kemudian dereference idempoten.

Jika Anda [0][0][0]atau ***tipe array 3d maka itu dereference offset + idempoten kemudian dereferensi offset + idempoten kemudian dereferensi offset + idempoten kemudian dereferensi. Dereferensi sejati hanya terjadi ketika jenis array dilucuti sepenuhnya.

Sebagai contoh dari int* (*x)[1][2][3]jenis membuka secara berurutan.

  • x memiliki tipe int* (*)[1][2][3]
  • *xmemiliki tipe int* [1][2][3](offset 0 + idempoten dereference)
  • **xmemiliki tipe int* [2][3](offset 0 + idempoten dereference)
  • ***xmemiliki tipe int* [3](offset 0 + idempoten dereference)
  • ****xmemiliki tipe int*(offset 0 + dereferensi)
  • *****xmemiliki tipe int(offset 0 + dereferensi)
Lewis Kelsey
sumber