Saya mengikuti tutorial ini tentang bagaimana cara kerja pointer ke pointer .
Izinkan saya mengutip bagian yang relevan:
int i = 5, j = 6, k = 7; int *ip1 = &i, *ip2 = &j;
Sekarang kita bisa atur
int **ipp = &ip1;
dan
ipp
menunjuk keip1
poin manai
.*ipp
adalahip1
, dan**ipp
sekarangi
, atau 5. Kita dapat menggambarkan situasinya, dengan notasi kotak-dan-panah yang kita kenal, seperti ini:Kalau begitu kita katakan
*ipp = ip2;
kami telah mengubah pointer yang ditunjuk oleh
ipp
(yaitu,ip1
) untuk berisi salinanip2
, sehingga (ip1
) sekarang menunjuk kej
:
Pertanyaan saya adalah: Mengapa pada gambar kedua, ipp
masih menunjuk ip1
tetapi tidak ip2
?
ipp
ketika mendefinisikannya, jadi pertanyaan Anda selesai ;-)ipp
menunjuk keip1
hal*ipp = ip2
yang sama sepertiip1 = ip2
int **ipp
jauh lebih tidak intuitif daripadaint** ipp
, terutama ketika**ipp
berarti hal yang sama sekali berbeda di luar deklarasi tipe.int **ipp
tampaknya cukup intuitif bagi saya. Artinya, saya membuat**ipp
sebuahint
. Yang mana yang benar.ipp
iniint**
, jadi hanya menulisint**
bukan magis "imp
dereference adalah int" pemahaman .Jawaban:
Lupakan sejenak tentang analogi yang menunjuk. Apa yang benar-benar berisi pointer adalah alamat memori. The
&
adalah "alamat" operator - yakni mengembalikan alamat di memori obyek. The*
Operator memberikan objek pointer mengacu, yaitu diberi pointer yang berisi alamat, ia mengembalikan objek pada alamat memori. Jadi ketika Anda melakukannya*ipp = ip2
, apa yang Anda lakukan adalah*ipp
mendapatkan objek di alamat yang disimpan diipp
manaip1
dan kemudian menetapkanip1
nilai yang disimpanip2
, yang merupakan alamatj
.Cukup
&
-> Alamat*
-> Nilai disumber
Karena Anda mengubah nilai yang ditunjukkan oleh
ipp
bukan nilaiipp
. Jadi,ipp
masih menunjuk keip1
(nilaiipp
),ip1
nilai sekarang sama denganip2
nilai, jadi keduanya menunjuk kej
.Ini:
sama dengan:
sumber
int *ip1 = &i
dan*ipp = ip2;
, yaitu jika Anda menghapusint
dari pernyataan pertama maka tugasnya terlihat sangat mirip, tetapi*
melakukan sesuatu yang sangat berbeda dalam dua kasus.Seperti kebanyakan pertanyaan pemula dalam tag C, pertanyaan ini dapat dijawab dengan kembali ke prinsip pertama:
&
Operator ternyata variabel menjadi pointer.*
Operator ternyata pointer ke variabel.(Secara teknis saya harus mengatakan "lvalue" daripada "variabel", tapi saya merasa lebih jelas untuk menggambarkan lokasi penyimpanan yang bisa berubah sebagai "variabel".)
Jadi kita punya variabel:
Variabel
ip1
berisi pointer. The&
Operator berubahi
menjadi pointer dan bahwa nilai pointer ditugaskan untukip1
. Jadiip1
mengandung pointer kei
.Variabel
ip2
berisi pointer. The&
Operator berubahj
menjadi pointer dan pointer yang ditugaskan untukip2
. Jadiip2
mengandung pointer kej
.Variabel
ipp
berisi pointer. The&
Operator ternyata variabelip1
ke pointer dan bahwa nilai pointer ditugaskan untukipp
. Jadiipp
mengandung pointer keip1
.Mari kita simpulkan ceritanya sejauh ini:
i
berisi 5j
berisi 6ip1
berisi "penunjuk kei
"ip2
berisi "penunjuk kej
"ipp
berisi "penunjuk keip1
"Sekarang kita katakan
The
*
Operator ternyata kembali pointer ke variabel. Kami mengambil nilaiipp
, yang merupakan "penunjuk keip1
dan mengubahnya menjadi variabel. Variabel apa?ip1
Tentu saja!Karena itu, ini hanyalah cara lain untuk mengatakan
Jadi kami mengambil nilai
ip2
. Apa itu? "arahkan kej
". Kami menetapkan nilai penunjuk ituip1
, jadiip1
sekarang "penunjuk kej
"Kami hanya mengubah satu hal: nilai
ip1
:i
berisi 5j
berisi 6ip1
berisi "penunjuk kej
"ip2
berisi "penunjuk kej
"ipp
berisi "penunjuk keip1
"Variabel berubah saat Anda menetapkannya. Hitung tugas; tidak mungkin ada lebih banyak perubahan pada variabel daripada ada tugas! Anda mulai dengan menetapkan untuk
i
,j
,ip1
,ip2
danipp
. Anda kemudian menugaskan ke*ipp
, yang seperti telah kita lihat artinya sama dengan "menetapkan untukip1
". Karena Anda tidak menetapkan untukipp
kedua kalinya, itu tidak berubah!Jika Anda ingin berubah
ipp
maka Anda harus benar-benar menetapkan untukipp
:misalnya.
sumber
Semoga kode ini dapat membantu.
itu output:
sumber
Pendapat saya yang sangat pribadi adalah bahwa gambar dengan panah mengarah ke sini atau itu membuat pointer lebih sulit untuk dipahami. Itu memang membuat mereka tampak seperti entitas abstrak dan misterius. Mereka tidak.
Seperti semua hal lain di komputer Anda, pointer adalah angka . Nama "pointer" hanyalah cara biasa untuk mengatakan "variabel yang berisi alamat".
Oleh karena itu, izinkan saya mengaduk berbagai hal dengan menjelaskan bagaimana komputer sebenarnya bekerja.
Kami memiliki
int
, ia memiliki namai
dan nilai 5. Ini disimpan dalam memori. Seperti semua yang tersimpan di memori, ia perlu alamat, atau kami tidak akan dapat menemukannya. Katakanlahi
berakhir di alamat 0x12345678 dan temannyaj
dengan nilai 6 berakhir tepat setelah itu. Dengan asumsi CPU 32-bit di mana int adalah 4 byte dan pointer 4 byte, maka variabel disimpan dalam memori fisik seperti ini:Sekarang kita ingin menunjukkan variabel-variabel ini. Kami membuat satu pointer ke int
int* ip1
,, dan satuint* ip2
. Seperti semua yang ada di komputer, variabel pointer ini dialokasikan di suatu tempat di memori juga. Mari kita asumsikan mereka berakhir di alamat yang berdekatan berikutnya dalam memori, segera setelah ituj
. Kami menetapkan pointer berisi alamat variabel yang sebelumnya dialokasikan:ip1=&i;
("salin alamat i ke ip1") danip2=&j
. Apa yang terjadi di antara keduanya adalah:Jadi yang kami dapatkan hanyalah beberapa byte memori yang berisi angka. Tidak ada panah mistis atau magis di mana pun terlihat.
Bahkan, hanya dengan melihat dump memori, kami tidak dapat memastikan apakah alamat 0x12345680 berisi
int
atauint*
. Perbedaannya adalah bagaimana program kami memilih untuk menggunakan konten yang disimpan di alamat ini. (Tugas program kami sebenarnya hanya memberi tahu CPU apa yang harus dilakukan dengan angka-angka ini.)Kemudian kami menambahkan satu lagi tipuan dengan
int** ipp = &ip1;
. Sekali lagi, kami hanya mendapatkan sepotong memori:Polanya memang tidak asing lagi. Namun sepotong 4 byte lainnya berisi angka.
Sekarang, jika kita memiliki memori dump RAM fiksi kecil di atas, kita bisa secara manual memeriksa di mana titik petunjuk ini. Kami mengintip apa yang disimpan di alamat
ipp
variabel dan menemukan konten 0x12345680. Yang tentu saja alamat tempatip1
penyimpanannya. Kita dapat pergi ke alamat itu, memeriksa isinya, dan menemukan alamatnyai
, dan akhirnya kita bisa pergi ke alamat itu dan menemukan nomor 5.Jadi jika kita mengambil konten ipp
*ipp
,, kita akan mendapatkan alamat variabel pointerip1
. Dengan menulis*ipp=ip2
kita menyalin IP2 ke IP1, itu setara denganip1=ip2
. Dalam kedua kasus kita akan mendapatkan(Contoh-contoh ini diberikan untuk CPU big endian)
sumber
location, value, variable
mana lokasi1,2,3,4,5
dan nilainya beradaA,1,B,C,3
, ide pointer yang sesuai dapat dijelaskan dengan mudah tanpa menggunakan panah, yang secara inheren membingungkan. Dengan implementasi apa pun yang dipilih, nilai ada di beberapa lokasi, dan ini adalah bagian dari teka-teki yang menjadi dikaburkan saat memodelkan dengan panah.&
operator pada variabel memberikan Anda koin yang mewakili variabel itu. The*
operator pada koin yang memberikan Anda kembali variabel. Tidak perlu panah!Perhatikan tugasnya:
hasil
ipp
untuk menunjuk keip1
.jadi untuk
ipp
menunjuk keip2
, kita harus berubah dengan cara yang sama,yang jelas tidak kita lakukan. Sebaliknya, kami mengubah nilai pada alamat yang ditunjuk oleh
ipp
.Dengan melakukan mengikuti
kami hanya mengganti nilai yang disimpan di
ip1
.ipp = &ip1
, berarti*ipp = ip1 = &i
,Sekarang
*ipp = ip2 = &j
,.Jadi,
*ipp = ip2
pada dasarnya sama denganip1 = ip2
.sumber
Tidak ada tugas selanjutnya yang mengubah nilai
ipp
. Ini sebabnya masih menunjuk keip1
.Apa yang Anda lakukan dengan
*ipp
, yaitu, denganip1
, tidak mengubah fakta yangipp
menunjukip1
.sumber
Anda menempatkan gambar yang bagus, saya akan mencoba membuat seni ascii yang bagus:
Seperti @ Robert-S-Barnes katakan dalam jawabannya: lupakan pointer , dan apa menunjuk ke apa, tetapi pikirkan dalam hal memori. Pada dasarnya,
int*
artinya berisi alamat variabel danint**
alamat variabel yang berisi alamat variabel. Kemudian Anda bisa menggunakan aljabar pointer untuk mengakses nilai atau alamat:&foo
meansaddress of foo
, and*foo
meansvalue of the address contained in foo
.Jadi, karena pointer adalah tentang berurusan dengan memori, cara terbaik untuk benar-benar membuat "nyata" adalah untuk menunjukkan apa yang dilakukan aljabar pointer ke memori.
Jadi, inilah memori program Anda (disederhanakan untuk tujuan contoh):
ketika Anda melakukan kode awal Anda:
seperti inilah memori Anda:
sana Anda dapat melihat
ip1
danip2
mendapatkan alamati
danj
danipp
masih tidak ada. Jangan lupa bahwa alamat hanyalah bilangan bulat yang disimpan dengan tipe khusus.Kemudian Anda mendeklarasikan dan mendefinisikan
ipp
seperti:jadi inilah ingatanmu:
dan kemudian, Anda mengubah nilai yang ditunjukkan oleh alamat yang disimpan di
ipp
dalamnya, yaitu alamat yang disimpan diip1
:memori program adalah
NB: sebagai
int*
adalah tipe khusus, saya lebih memilih untuk selalu menghindari menyatakan beberapa pointer pada baris yang sama, karena saya pikirint *x;
atauint *x, *y;
notasi dapat menyesatkan. Saya lebih suka menulisint* x; int* y;
HTH
sumber
ip2
seharusnya3
tidak4
.Karena ketika Anda mengatakannya
Anda mengatakan 'objek yang ditunjuk
ipp
' untuk menunjukkan arah memori yangip2
menunjuk.Anda tidak mengatakan
ipp
untuk menunjukkanip2
.sumber
Jika Anda menambahkan operator dereference
*
ke pointer, Anda mengarahkan dari pointer ke objek menunjuk-ke.Contoh:
Karena itu:
sumber
Jika Anda ingin
ipp
menunjukip2
, Anda harus mengatakannyaipp = &ip2;
. Namun, ini akanip1
tetap menunjuki
.sumber
Sangat awal Anda atur,
Sekarang ganti sebagai,
sumber
Pertimbangkan setiap variabel yang diwakili seperti ini:
jadi variabel Anda harus direpresentasikan seperti ini
Karena nilainya
ipp
adalah&ip1
begitu inktruksi:mengubah nilai pada addess
&ip1
ke nilaiip2
, yang artinyaip1
diubah:Tapi
ipp
tetap saja:Jadi nilai
ipp
still&ip1
yang artinya masih menunjuk keip1
.sumber
Karena Anda mengubah pointer
*ipp
. Itu berartiipp
(nama yang dapat diganti-ganti) ---- masuk ke dalam.ipp
adalah alamatip1
.*ipp
jadi pergi ke (alamat dalam)ip1
.Sekarang kita berada di
ip1
.*ipp
(ieip1
) =ip
2.ip2
mengandung alamatj
.soip1
konten akan diganti dengan berisi ip2 (yaitu alamat j), KAMI TIDAK MENGUBAHipp
KONTEN. ITU DIA.sumber
*ipp = ip2;
menyiratkan:Tetapkan
ip2
ke variabel yang ditunjuk olehipp
. Jadi ini setara dengan:Jika Anda ingin alamat
ip2
untuk disimpanipp
, cukup lakukan:Sekarang
ipp
menunjuk keip2
.sumber
ipp
dapat menyimpan nilai (yaitu menunjuk ke) pointer ke objek tipe pointer . Saat kamu melakukankemudian
ipp
berisi alamat variabel (pointer)ip2
, yaitu (&ip2
) dari tipe pointer ke pointer . Sekarang panahipp
di dalam gambar kedua akan menunjuk keip2
.Wiki mengatakan:
The
*
operator adalah operator dereference beroperasi pada variabel pointer, dan mengembalikan sebuah l-nilai (variabel) setara dengan nilai di alamat pointer. Ini disebut dereferencing pointer.Menerapkan
*
operator padaipp
derefrence ke nilai l pointer untukint
mengetik. Nilai l yang didereferensi*ipp
adalah tipe pointerint
, ia dapat menampung alamatint
tipe data. Setelah pernyataan ituipp
memegang alamatip1
dan*ipp
memegang alamat (menunjuk ke)i
. Anda dapat mengatakan bahwa itu*ipp
adalah aliasip1
. Keduanya**ipp
dan*ip1
alias untuki
.Dengan melakukan
*ipp
danip2
keduanya menunjuk ke lokasi yang sama tetapiipp
masih menunjuk keip1
.Apa yang
*ipp = ip2;
sebenarnya adalah bahwa itu menyalin isiip2
(alamatj
) keip1
(seperti*ipp
alias untukip1
), pada dasarnya membuat pointerip1
danip2
menunjuk ke objek yang sama (j
).Jadi, pada gambar kedua, panah
ip1
danip2
menunjuk kej
sementaraipp
masih menunjuk keip1
karena tidak ada modifikasi yang dilakukan untuk mengubah nilaiipp
.sumber