Harap sertakan contoh dengan penjelasan.
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.
Harap sertakan contoh dengan penjelasan.
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:
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 ++.
Pertimbangkan dalam C, diberi pointer seperti di p
bawah ini ...
const char* p = "abc";
... 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:
Memory Address (hex) Variable name Contents
1000 'a' == 97 (ASCII)
1001 'b' == 98
1002 'c' == 99
1003 0
...
2000-2003 p 1000 hex
Perhatikan bahwa tidak ada variabel nama / identifier untuk alamat 0x1000, tapi kami tidak langsung dapat merujuk ke string literal menggunakan pointer menyimpan alamat: p
.
Untuk merujuk pada p
poin karakter , kami p
menggunakan salah satu dari notasi ini (sekali lagi, untuk C):
assert(*p == 'a'); // The first character at address p will be 'a'
assert(p[1] == 'b'); // p[1] actually dereferences a pointer created by adding
// p and 1 times the size of the things to which p points:
// In this case they're char which are 1 byte in C...
assert(*(p + 1) == 'b'); // Another notation for p[1]
Anda juga dapat memindahkan pointer melalui data yang diarahkan ke, merujuknya saat Anda pergi:
++p; // Increment p so it's now 0x1001
assert(*p == 'b'); // p == 0x1001 which is where the 'b' is...
Jika Anda memiliki beberapa data yang dapat ditulis, maka Anda dapat melakukan hal-hal seperti ini:
int x = 2;
int* p_x = &x; // Put the address of the x variable into the pointer p_x
*p_x = 4; // Change the memory at the address in p_x to be 4
assert(x == 4); // Check x is now 4
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
.
Dalam C, jika Anda memiliki variabel yang merupakan penunjuk ke struktur dengan anggota data, Anda dapat mengakses anggota tersebut menggunakan ->
operator dereferencing:
typedef struct X { int i_; double d_; } X;
X x;
X* p = &x;
p->d_ = 3.14159; // Dereference and access data member x.d_
(*p).d_ *= -1; // Another equivalent notation for accessing x.d_
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:
double sizes[] = { 10.3, 13.4, 11.2, 19.4 };
double* p = sizes;
assert(p[0] == 10.3); // Knows to look at all the bytes in the first double value
assert(p[1] == 13.4); // Actually looks at bytes from address p + 1 * sizeof(double)
// (sizeof(double) is almost always eight bytes)
++p; // Advance p by sizeof(double)
assert(*p == 13.4); // The double at memory beginning at address p has value 13.4
*(p + 2) = 29.8; // Change sizes[3] from 19.4 to 29.8
// Note earlier ++p and + 2 here => sizes[3]
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 ...
int* p = (int*)malloc(sizeof(int)); // Get some memory somewhere...
*p = 10; // Dereference the pointer to the memory, then write a value in
fn(*p); // Call a function, passing it the value at address p
(*p) += 3; // Change the value, adding 3 to it
free(p); // Release the memory back to the heap allocation library
Dalam C ++, alokasi memori biasanya dilakukan dengan new
operator, dan deallokasi dengan delete
:
int* p = new int(10); // Memory for one int with initial value 10
delete p;
p = new int[10]; // Memory for ten ints with unspecified initial value
delete[] p;
p = new int[10](); // Memory for ten ints that are value initialised (to 0)
delete[] p;
Lihat juga C ++ smart pointer di bawah ini.
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()
atau delete
menghindari kebocoran memori, maka programmer harus beroperasi pada salinan pointer ...
const char* p = asprintf("name: %s", name); // Common but non-Standard printf-on-heap
// Replace non-printable characters with underscores....
for (const char* q = p; *q; ++q)
if (!isprint(*q))
*q = '_';
printf("%s\n", p); // Only q was modified
free(p);
... atau dengan hati-hati mengatur pembalikan setiap perubahan ...
const size_t n = ...;
p += n;
...
p -= n; // Restore earlier value...
free(p);
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 ...
{
std::unique_ptr<T> p{new T(42, "meaning")};
call_a_function(p);
// The function above might throw, so delete here is unreliable, but...
} // p's destructor's guaranteed to run "here", calling delete
... dan shared_ptr
untuk kepemilikan saham (menggunakan penghitungan referensi ) ...
{
auto p = std::make_shared<T>(3.14, "pi");
number_storage1.may_add(p); // Might copy p into its container
number_storage2.may_add(p); // Might copy p into its container } // p's destructor will only delete the T if neither may_add copied it
Dalam C, NULL
dan 0
- 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:
const char* p_filename = NULL; // Or "= 0", or "= nullptr" in C++
int c;
while ((c = getopt(argc, argv, "f:")) != -1)
switch (c) {
case f: p_filename = optarg; break;
}
if (p_filename) // Only NULL converts to false
... // Only get here if -f flag specified
Dalam C dan C ++, sama seperti tipe numerik bawaan tidak selalu default untuk 0
, atau bools
untuk false
, pointer tidak selalu diatur ke NULL
. Semua ini diatur ke 0 / false / NULL ketika mereka static
variabel atau (hanya C ++) variabel anggota langsung atau tidak langsung dari objek statis atau basis mereka, atau menjalani nol inisialisasi (misalnya new T();
dan new T(x, y, z);
melakukan inisialisasi nol pada anggota T termasuk pointer, sedangkan new T;
tidak).
Lebih jauh, ketika Anda menetapkan 0
, NULL
dan nullptr
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 ke 0
, 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 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 suatu int
variabel mungkin - setelah melakukan casting ke float*
- akses memori dalam memori "GPU" cukup berbeda dari memori di mana int
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 dari int*
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.
p[1]
dan *(p + 1)
identik ? Yaitu, Apakah p[1]
dan *(p + 1)
menghasilkan instruksi yang sama?
p
hanya 2000: jika Anda memiliki pointer lain untuk p
itu harus menyimpan 2000 dalam empat atau delapan byte. Semoga itu bisa membantu! Bersulang.
u
berisi array arr
, baik gcc dan dentang akan mengenali bahwa nilai u.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.
int a = 10;
int* ptr = &a;
printf("%d", *ptr); // With *ptr I'm dereferencing the pointer.
// Which means, I am asking the value pointed at by the pointer.
// ptr is pointing to the location in memory of the variable a.
// In a's location, we have 10. So, dereferencing gives this value.
// Since we have indirect control over a's location, we can modify its content using the pointer. This is an indirect way to access a.
*ptr = 20; // Now a's content is no longer 10, and has been modified to 20.
[]
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.
int a=4 ;
int *pA = &a ;
printf( "The REFERENCE/call number for the variable `a` is %p\n", pA ) ;
// The * causes pA to DEREFERENCE... `a` via "callnumber" `pA`.
printf( "%d\n", *pA ) ; // prints 4..
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.
Dengan kata sederhana, dereferencing berarti mengakses nilai dari lokasi memori tertentu yang ditunjuk oleh pointer itu.
Kode dan penjelasan dari Pointer Basics :
Operasi dereferensi dimulai pada penunjuk dan mengikuti panahnya untuk mengakses penunjuknya. Tujuannya mungkin untuk melihat status pointee atau mengubah status pointee. Operasi dereference pada pointer hanya berfungsi jika pointer memiliki pointee - pointee harus dialokasikan dan pointer harus diatur untuk menunjuk ke sana. Kesalahan paling umum dalam kode pointer lupa mengatur pointee. Kecelakaan runtime paling umum karena kesalahan dalam kode adalah operasi dereference gagal. Di Jawa dereference yang salah akan ditandai dengan sopan oleh sistem runtime. Dalam bahasa yang dikompilasi seperti C, C ++, dan Pascal, dereference yang salah terkadang akan crash, dan di lain waktu merusak memori dalam beberapa cara yang halus dan acak.
void main() {
int* x; // Allocate the pointer x
x = malloc(sizeof(int)); // Allocate an int pointee,
// and set x to point to it
*x = 42; // Dereference x to store 42 in its pointee
}
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
Ini beroperasi pada variabel pointer, dan mengembalikan nilai-l yang setara dengan nilai pada alamat pointer. Ini disebut "dereferencing" pointer.
Yang mengatakan, kita dapat melakukan dereferensi pointer tanpa pernah mengakses nilai yang ditunjukkannya. Sebagai contoh:
char *p = NULL;
*p;
Kami mendereferensi pointer NULL tanpa mengakses nilainya. Atau kita bisa melakukan:
p1 = &(*p);
sz = sizeof(*p);
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.
*p;
menyebabkan perilaku yang tidak terdefinisi. Meskipun Anda benar bahwa dereferencing tidak mengakses nilai per se , kode *p;
tersebut mengakses nilai.