Harap sertakan contoh dengan penjelasan.
c++
c
pointers
dereference
asir
sumber
sumber
int *p;
akan mendefinisikan sebuah pointer ke integer, dan*p
akan melakukan dereference pada pointer itu, yang berarti bahwa itu akan benar-benar mengambil data yang ditunjukkan oleh p.Jawaban:
Meninjau terminologi dasar
Ini biasanya cukup baik - kecuali Anda pemrograman perakitan - untuk membayangkan sebuah pointer yang berisi alamat memori numerik, dengan 1 mengacu pada byte kedua dalam memori proses ini, 2 yang ketiga, 3 keempat dan seterusnya ....
Ketika Anda ingin mengakses data / nilai dalam memori yang ditunjuk oleh pointer - isi alamat dengan indeks numerik tersebut - maka Anda melakukan referensi pada pointer tersebut.
Bahasa komputer yang berbeda memiliki notasi yang berbeda untuk memberi tahu kompiler atau juru bahasa bahwa Anda sekarang tertarik pada nilai (saat ini) yang diarahkan ke objek - Saya fokus di bawah pada C dan C ++.
Skenario penunjuk
Pertimbangkan dalam C, diberi pointer seperti di
p
bawah ini ...... empat byte dengan nilai numerik yang digunakan untuk menyandikan huruf 'a', 'b', 'c', dan 0 byte untuk menunjukkan akhir data tekstual, disimpan di suatu tempat dalam memori dan alamat numeriknya data disimpan di
p
. Dengan cara ini C menyandikan teks dalam memori dikenal sebagai ASCIIZ .Misalnya, jika string literal berada di alamat 0x1000 dan
p
pointer 32-bit pada 0x2000, konten memori akan menjadi:Perhatikan bahwa tidak ada variabel nama / identifier untuk alamat 0x1000, tapi kami tidak langsung dapat merujuk ke string literal menggunakan pointer menyimpan alamat:
p
.Mendereferensi pointer
Untuk merujuk pada
p
poin karakter , kamip
menggunakan salah satu dari notasi ini (sekali lagi, untuk C):Anda juga dapat memindahkan pointer melalui data yang diarahkan ke, merujuknya saat Anda pergi:
Jika Anda memiliki beberapa data yang dapat ditulis, maka Anda dapat melakukan hal-hal seperti ini:
Di atas, Anda harus tahu pada waktu kompilasi bahwa Anda akan memerlukan variabel yang dipanggil
x
, dan kode meminta kompiler untuk mengatur di mana ia harus disimpan, memastikan alamat akan tersedia melalui&x
.Mendereferensi dan mengakses anggota struktur data
Dalam C, jika Anda memiliki variabel yang merupakan penunjuk ke struktur dengan anggota data, Anda dapat mengakses anggota tersebut menggunakan
->
operator dereferencing:Tipe data multi-byte
Untuk menggunakan sebuah pointer, sebuah program komputer juga memerlukan beberapa wawasan tentang tipe data yang ditunjukkan - jika tipe data tersebut membutuhkan lebih dari satu byte untuk diwakili, maka pointer biasanya menunjuk ke byte bernomor terendah dalam data.
Jadi, perhatikan contoh yang sedikit lebih rumit:
Pointer ke memori yang dialokasikan secara dinamis
Kadang-kadang Anda tidak tahu berapa banyak memori yang Anda butuhkan sampai program Anda berjalan dan melihat data apa yang dilemparkan ke sana ... maka Anda dapat mengalokasikan memori secara dinamis menggunakan
malloc
. Ini adalah praktik umum untuk menyimpan alamat dalam sebuah pointer ...Dalam C ++, alokasi memori biasanya dilakukan dengan
new
operator, dan deallokasi dengandelete
:Lihat juga C ++ smart pointer di bawah ini.
Kehilangan dan bocornya alamat
Seringkali pointer mungkin satu-satunya indikasi di mana beberapa data atau buffer ada dalam memori. Jika penggunaan data / buffer yang sedang berlangsung dibutuhkan, atau kemampuan untuk memanggil
free()
ataudelete
menghindari kebocoran memori, maka programmer harus beroperasi pada salinan pointer ...... atau dengan hati-hati mengatur pembalikan setiap perubahan ...
C ++ pointer cerdas
Dalam C ++, praktik terbaik untuk menggunakan objek penunjuk pintar untuk menyimpan dan mengelola pointer, secara otomatis mendelokasi mereka ketika destruktor pointer pintar berjalan. Sejak C ++ 11, Perpustakaan Standar menyediakan dua,
unique_ptr
ketika ada satu pemilik untuk objek yang dialokasikan ...... dan
shared_ptr
untuk kepemilikan saham (menggunakan penghitungan referensi ) ...Pointer kosong
Dalam C,
NULL
dan0
- dan juga dalam C ++nullptr
- dapat digunakan untuk menunjukkan bahwa pointer saat ini tidak memegang alamat memori variabel, dan tidak boleh dereferenced atau digunakan dalam aritmatika pointer. Sebagai contoh:Dalam C dan C ++, sama seperti tipe numerik bawaan tidak selalu default untuk
0
, ataubools
untukfalse
, pointer tidak selalu diatur keNULL
. Semua ini diatur ke 0 / false / NULL ketika merekastatic
variabel atau (hanya C ++) variabel anggota langsung atau tidak langsung dari objek statis atau basis mereka, atau menjalani nol inisialisasi (misalnyanew T();
dannew T(x, y, z);
melakukan inisialisasi nol pada anggota T termasuk pointer, sedangkannew T;
tidak).Lebih jauh, ketika Anda menetapkan
0
,NULL
dannullptr
ke sebuah penunjuk, bit-bit di dalam penunjuk itu tidak harus semuanya disetel ulang: penunjuk itu mungkin tidak mengandung "0" pada tingkat perangkat keras, atau merujuk ke alamat 0 dalam ruang alamat virtual Anda. Compiler diperbolehkan untuk menyimpan sesuatu yang lain di sana jika ia memiliki alasan untuk, tapi apa pun yang dilakukannya - jika Anda datang dan membandingkan pointer ke0
,NULL
,nullptr
atau pointer lain yang ditugaskan salah satu dari mereka, pekerjaan perbandingan keharusan seperti yang diharapkan. Jadi, di bawah kode sumber di tingkat kompiler, "NULL" berpotensi sedikit "ajaib" dalam bahasa C dan C ++ ...Lebih banyak tentang alamat memori, dan mengapa Anda mungkin tidak perlu tahu
Lebih tepatnya, pointer yang diinisialisasi menyimpan pola-bit yang mengidentifikasi baik
NULL
atau alamat memori (sering virtual ).Kasus sederhana adalah di mana ini adalah offset numerik ke seluruh ruang alamat virtual proses; dalam kasus yang lebih kompleks, pointer mungkin relatif terhadap beberapa area memori tertentu, yang dapat dipilih CPU berdasarkan register "segmen" CPU atau beberapa jenis id segmen yang dikodekan dalam pola bit, dan / atau mencari di tempat yang berbeda tergantung pada instruksi kode mesin menggunakan alamat.
Sebagai contoh, sebuah
int*
diinisialisasi dengan benar untuk menunjuk ke suatuint
variabel mungkin - setelah melakukan casting kefloat*
- akses memori dalam memori "GPU" cukup berbeda dari memori di manaint
variabel itu, kemudian setelah dilemparkan ke dan digunakan sebagai penunjuk fungsi itu mungkin menunjuk ke lebih lanjut opcode mesin penahan memori yang berbeda untuk program (dengan nilai numerik dariint*
penunjuk yang acak dan tidak valid secara efektif dalam wilayah memori lainnya).Bahasa pemrograman 3GL seperti C dan C ++ cenderung menyembunyikan kompleksitas ini, sehingga:
Jika kompiler memberi Anda pointer ke variabel atau fungsi, Anda dapat melakukan dereferensi secara bebas (selama variabel tidak dirusak / tidak dialokasikan sementara itu) dan itu adalah masalah kompiler apakah mis. Register segmen CPU tertentu perlu dipulihkan sebelumnya, atau instruksi kode mesin yang berbeda digunakan
Jika Anda mendapatkan pointer ke elemen dalam array, Anda bisa menggunakan pointer aritmatika untuk pindah ke tempat lain di array, atau bahkan untuk membentuk alamat satu-melewati-akhir array yang legal untuk dibandingkan dengan pointer ke elemen lainnya. dalam array (atau yang juga telah dipindahkan oleh pointer aritmatika ke nilai one-past-the-end yang sama); lagi di C dan C ++, terserah kompiler untuk memastikan ini "hanya berfungsi"
Fungsi OS tertentu, misalnya pemetaan memori bersama, dapat memberi Anda petunjuk, dan mereka akan "hanya bekerja" dalam kisaran alamat yang masuk akal bagi mereka
Upaya untuk memindahkan penunjuk hukum di luar batas ini, atau untuk melemparkan angka sewenang-wenang ke penunjuk, atau menggunakan penunjuk yang dilemparkan ke jenis yang tidak terkait, biasanya memiliki perilaku yang tidak ditentukan , sehingga harus dihindari di perpustakaan dan aplikasi tingkat tinggi, tetapi kode untuk OS, driver perangkat, dll Mungkin perlu mengandalkan perilaku yang tidak terdefinisi oleh Standar C atau C ++, yang tetap didefinisikan dengan baik oleh implementasi atau perangkat keras spesifik mereka.
sumber
p[1]
dan*(p + 1)
identik ? Yaitu, Apakahp[1]
dan*(p + 1)
menghasilkan instruksi yang sama?p
hanya 2000: jika Anda memiliki pointer lain untukp
itu harus menyimpan 2000 dalam empat atau delapan byte. Semoga itu bisa membantu! Bersulang.u
berisi arrayarr
, baik gcc dan dentang akan mengenali bahwa nilaiu.arr[i]
mungkin mengakses penyimpanan yang sama dengan anggota serikat lainnya, tetapi tidak akan mengenali bahwa nilai*(u.arr+i)
mungkin melakukannya. Saya tidak yakin apakah penulis dari kompiler tersebut berpikir bahwa yang terakhir memanggil UB, atau yang sebelumnya memanggil UB tetapi mereka harus memprosesnya dengan bermanfaat, tetapi mereka jelas melihat dua ekspresi sebagai berbeda.Mendereferensi pointer berarti mendapatkan nilai yang disimpan di lokasi memori yang ditunjuk oleh pointer. Operator * digunakan untuk melakukan ini, dan disebut operator dereferencing.
sumber
[]
juga menunjuk sebuah pointer (a[b]
didefinisikan sebagai mean*(a + b)
).Pointer adalah "referensi" ke nilai .. seperti halnya nomor panggilan perpustakaan adalah referensi ke sebuah buku. "Dereferencing" nomor panggilan secara fisik melewati dan mengambil buku itu.
Jika buku itu tidak ada, pustakawan mulai berteriak, menutup perpustakaan, dan beberapa orang ditetapkan untuk menyelidiki penyebab seseorang akan menemukan buku yang tidak ada di sana.
sumber
Dengan kata sederhana, dereferencing berarti mengakses nilai dari lokasi memori tertentu yang ditunjuk oleh pointer itu.
sumber
Kode dan penjelasan dari Pointer Basics :
sumber
Saya pikir semua jawaban sebelumnya salah, karena menyatakan bahwa dereferencing berarti mengakses nilai aktual. Wikipedia memberikan definisi yang benar sebagai gantinya: https://en.wikipedia.org/wiki/Dereference_operator
Yang mengatakan, kita dapat melakukan dereferensi pointer tanpa pernah mengakses nilai yang ditunjukkannya. Sebagai contoh:
Kami mendereferensi pointer NULL tanpa mengakses nilainya. Atau kita bisa melakukan:
Sekali lagi, dereferencing, tetapi tidak pernah mengakses nilainya. Kode seperti itu TIDAK akan macet: Kecelakaan terjadi ketika Anda benar-benar mengakses data dengan pointer yang tidak valid. Namun, sayangnya, menurut standar, penereferensian pointer yang tidak valid adalah perilaku yang tidak terdefinisi (dengan beberapa pengecualian), bahkan jika Anda tidak mencoba menyentuh data aktual.
Jadi singkatnya: mendereferensi pointer berarti menerapkan operator dereferensi untuk itu. Operator itu hanya mengembalikan nilai-l untuk penggunaan Anda di masa depan.
sumber
*p;
menyebabkan perilaku yang tidak terdefinisi. Meskipun Anda benar bahwa dereferencing tidak mengakses nilai per se , kode*p;
tersebut mengakses nilai.