Apa perbedaan antara const int *, const int * const, dan int const *?

1357

Aku selalu mengacaukan bagaimana menggunakan const int*, const int * constdan int const *benar. Apakah ada seperangkat aturan yang mendefinisikan apa yang bisa dan tidak bisa Anda lakukan?

Saya ingin mengetahui semua hal yang harus dan tidak boleh dilakukan dalam hal penugasan, melewati fungsi, dll.

MD XF
sumber
175
Anda dapat menggunakan "Aturan Searah Jarum Jam / Spiral" untuk menguraikan sebagian besar deklarasi C dan C ++.
James McNellis
52
cdecl.org adalah situs web hebat yang menerjemahkan secara otomatis deklarasi C untuk Anda.
Dave Gallagher
6
@Calmarius: mulailah dari mana nama-jenisnya / seharusnya, bergerak ke kanan ketika Anda bisa, ke kiri ketika Anda harus . int *(*)(char const * const). Mulai ke kanan dari kurung *maka kita harus bergerak ke kiri: pointer. Di luar parens, kita bisa bergerak kanan: pointer to function of .... Kemudian kita harus bergerak kiri: pointer to function of ... that returns pointer to int. Ulangi untuk memperluas parameter (yang ...): pointer to function of (constant pointer to constant char) that returns pointer to int. Seperti apakah deklarasi satu baris yang ekuivalen dalam bahasa yang mudah dibaca seperti Pascal?
Mark K Cowan
1
@ MarkKCowan Dalam Pascal itu akan menjadi sesuatu seperti function(x:^char):^int. Ada tipe fungsi yang menyiratkan pointer ke fungsi sehingga tidak perlu menentukannya, dan Pascal tidak menegakkan kebenaran const. Itu bisa dibaca dari kiri ke kanan.
Calmarius
5
Hal pertama di sebelah kiri "const" adalah apa yang konstan. Jika "const" adalah benda yang paling jauh ke kiri, maka hal pertama di sebelah kanannya adalah apa yang konstan.
Cupcake

Jawaban:

2209

Baca terbalik (didorong oleh Searah Jarum Jam / Spiral ):

  • int* - pointer ke int
  • int const * - pointer ke const int
  • int * const - const pointer ke int
  • int const * const - const pointer ke const int

Sekarang yang pertama constbisa berada di kedua sisi tipe jadi:

  • const int * == int const *
  • const int * const == int const * const

Jika Anda ingin menjadi sangat gila, Anda dapat melakukan hal-hal seperti ini:

  • int ** - pointer ke pointer ke int
  • int ** const - pointer const ke pointer ke int
  • int * const * - pointer ke pointer const ke int
  • int const ** - pointer ke pointer ke const int
  • int * const * const - pointer const ke pointer const ke int
  • ...

Dan untuk memastikan kami jelas tentang arti dari const:

int a = 5, b = 10, c = 15;

const int* foo;     // pointer to constant int.
foo = &a;           // assignment to where foo points to.

/* dummy statement*/
*foo = 6;           // the value of a can´t get changed through the pointer.

foo = &b;           // the pointer foo can be changed.



int *const bar = &c;  // constant pointer to int 
                      // note, you actually need to set the pointer 
                      // here because you can't change it later ;)

*bar = 16;            // the value of c can be changed through the pointer.    

/* dummy statement*/
bar = &a;             // not possible because bar is a constant pointer.           

fooadalah pointer variabel ke integer konstan. Ini memungkinkan Anda mengubah apa yang Anda tuju tetapi bukan nilai yang Anda tuju. Paling sering ini terlihat dengan string C-style di mana Anda memiliki pointer ke a const char. Anda dapat mengubah string mana yang Anda tuju tetapi Anda tidak dapat mengubah konten string ini. Ini penting ketika string itu sendiri berada di segmen data dari suatu program dan tidak boleh diubah.

baradalah pointer konstan atau tetap ke nilai yang dapat diubah. Ini seperti referensi tanpa tambahan gula sintaksis. Karena fakta ini, biasanya Anda akan menggunakan referensi di mana Anda akan menggunakan T* constpointer kecuali Anda perlu mengizinkan NULLpointer.

Matt Price
sumber
482
Saya ingin menambahkan aturan praktis yang dapat membantu Anda mengingat bagaimana menemukan apakah 'const' berlaku untuk pointer atau data runcing: pisahkan pernyataan pada tanda asterix, kemudian, jika kata kunci const muncul di bagian kiri (seperti di 'const int * foo') - itu milik data runcing, jika itu di bagian kanan ('int * const bar') - ini tentang pointer.
Michael
14
@Michael: Kudos to Michael untuk aturan sederhana untuk mengingat / memahami aturan const.
sivabudh
10
@ Jeffrey: membacanya mundur berfungsi dengan baik selama tidak ada tanda kurung. Lalu, yah ... gunakan
typedefs
12
+1, meskipun ringkasan yang lebih baik adalah: baca deklarasi pointer ke belakang , itu berarti, dekat dengan pernyataan @Michael: hentikan pembacaan normal kiri ke kanan pada tanda bintang pertama .
Wolf
3
@gedamial tidak, itu berfungsi dengan baik, tetapi Anda harus menetapkannya pada saat yang sama saat Anda mendeklarasikannya (karena Anda tidak dapat menetapkan ulang "pointer pointer"). const int x = 0; const int *const px = &x; const int *const *const p = &px;berfungsi dengan baik.
RastaJedi
357

Bagi mereka yang tidak tahu tentang Searah Jarum Jam / Spiral: Mulai dari nama variabel, gerakkan dengan jarum jam (dalam hal ini, pindah ke belakang) ke pointer atau jenis berikutnya . Ulangi sampai ekspresi berakhir.

Ini demo:

arahkan ke int

pointer pointer ke const const

arahkan ke int const

arahkan ke const int

pointer const ke int

Shijing Lv
sumber
8
@Jan tautan untuk contoh kompleks tidak memiliki izin. dapatkah Anda mempostingnya langsung di sini, atau menghapus batasan menonton?
R71
8
@Rog dulu semua izin akses terbuka ... Sayangnya, saya tidak menulis artikel dan tidak memiliki izin akses. Namun, ini adalah versi artikel yang diarsipkan yang masih berfungsi: archive.is/SsfMX
Jan Rüegg
8
Contoh kompleks masih tepat ke kiri, tetapi termasuk menyelesaikan tanda kurung seperti biasanya. Keseluruhan hal yang berputar searah jarum jam tidak membuatnya menjadi lebih mudah.
Matius Baca
4
Contoh terakhir: void (*signal(int, void (*fp)(int)))(int);dari archive.is/SsfMX
naXa
3
Jangan mengandalkan aturan ini. Ini tidak universal. Ada beberapa kasus gagal.
pukul
150

Saya pikir semuanya sudah dijawab di sini, tetapi saya hanya ingin menambahkan bahwa Anda harus berhati-hati typedef! Mereka BUKAN hanya penggantian teks.

Sebagai contoh:

typedef char *ASTRING;
const ASTRING astring;

Jenisnya astringadalah char * consttidak const char *. Ini adalah salah satu alasan saya selalu cenderung untuk menempatkan consthak jenis, dan tidak pernah di awal.

Kaz Dragon
sumber
20
Dan bagi saya ini adalah alasan untuk tidak pernah mengetik pointer. Saya tidak melihat manfaatnya dalam hal-hal seperti typedef int* PINT(Saya berasumsi sesuatu yang berasal dari praktik di C dan banyak pengembang terus melakukannya). Hebat, saya menggantinya *dengan a P, itu tidak mempercepat mengetik, ditambah memperkenalkan masalah yang Anda sebutkan.
Mephane
1
@ Dephane - Saya bisa melihatnya. Namun, bagi saya sepertinya mundur untuk menghindari fitur bahasa yang bagus untuk tetap menggunakan aturan sintaksis yang luar biasa (tentang penempatan "const"), daripada menghindari menggunakan aturan sintaksis yang luar biasa sehingga Anda dapat menggunakan fitur bahasa ini dengan aman. .
TED
6
@ Mephane PINTmemang penggunaan yang agak bodoh dari typedef, terutama karena itu membuat saya berpikir bahwa sistem toko menggunakan bir untuk memori. typedef s cukup berguna untuk menangani pointer ke fungsi.
ApproachingDarknessFish
5
@KazDragon TERIMA KASIH! Tanpa itu, saya akan mengacaukan semua yang diketikkan PVOID, LPTSTRhal-hal di api Win32!
David Lee
2
@Mephane: Saya harus menggunakan pSomething beberapa kali ketika menggunakan macro legacy tertentu yang ditulis untuk menerima tipe, tetapi akan pecah jika tipe itu bukan pengidentifikasi alfanumerik tunggal. :)
Groo
56

Seperti hampir semua orang tunjukkan:

Apa bedanya const X* p, X* const pdan const X* const p?

Anda harus membaca deklarasi pointer dari kanan ke kiri.

  • const X* p berarti "p menunjuk ke X yang merupakan const": objek X tidak dapat diubah melalui p.

  • X* const p berarti "p adalah pointer const ke X yang non-const": Anda tidak dapat mengubah pointer p itu sendiri, tetapi Anda dapat mengubah objek X melalui p.

  • const X* const p berarti "p adalah pointer const ke X yang merupakan const": Anda tidak dapat mengubah pointer p itu sendiri, Anda juga tidak dapat mengubah objek X melalui p.

Lukas
sumber
3
Jangan lupa bahwa const X* p;== X const * p;seperti pada"p points to an X that is const": the X object can't be changed via p.
Jesse Chisholm
penjelasan sederhana dan baik!
Edison Lo
50
  1. Referensi konstan:

    Referensi ke variabel (di sini int), yang konstan. Kami melewatkan variabel sebagai referensi terutama, karena ukuran referensi lebih kecil daripada nilai sebenarnya, tetapi ada efek samping dan itu karena itu seperti alias ke variabel aktual. Kami mungkin secara tidak sengaja mengubah variabel utama melalui akses penuh kami ke alias, jadi kami membuatnya konstan untuk mencegah efek samping ini.

    int var0 = 0;
    const int &ptr1 = var0;
    ptr1 = 8; // Error
    var0 = 6; // OK
  2. Pointer konstan

    Setelah pointer konstan menunjuk ke suatu variabel maka itu tidak dapat menunjuk ke variabel lain.

    int var1 = 1;
    int var2 = 0;
    
    int *const ptr2 = &var1;
    ptr2 = &var2; // Error
  3. Pointer ke konstan

    Sebuah penunjuk yang melaluinya orang tidak dapat mengubah nilai suatu variabel yang dikenal sebagai penunjuk menjadi konstan.

    int const * ptr3 = &var2;
    *ptr3 = 4; // Error
  4. Pointer konstan ke konstanta

    Pointer konstan ke konstanta adalah pointer yang tidak dapat mengubah alamat yang ditunjuknya dan juga tidak dapat mengubah nilai yang disimpan di alamat itu.

    int var3 = 0;
    int var4 = 0;
    const int * const ptr4 = &var3;
    *ptr4 = 1;     // Error
     ptr4 = &var4; // Error
Behrooz Tabesh
sumber
20

Aturan umum adalah bahwa constkata kunci berlaku untuk apa yang mendahuluinya segera. Pengecualian, permulaan constberlaku untuk hal-hal berikut.

  • const int*sama dengan int const*dan berarti "pointer ke int konstan" .
  • const int* constsama dengan int const* constdan berarti "pointer konstan ke int konstan" .

Sunting: Untuk Dos dan Larangan, jika jawaban ini tidak cukup, dapatkah Anda lebih tepat tentang apa yang Anda inginkan?

Pemrogram
sumber
19

Pertanyaan ini menunjukkan dengan tepat mengapa saya suka melakukan hal-hal seperti yang saya sebutkan dalam pertanyaan saya adalah const setelah jenis id dapat diterima?

Singkatnya, saya menemukan cara termudah untuk mengingat aturannya adalah "const" mengejar hal yang berlaku. Jadi dalam pertanyaan Anda, "int const *" berarti int adalah konstan, sedangkan "int * const" akan berarti bahwa pointernya konstan.

Jika seseorang memutuskan untuk meletakkannya di bagian paling depan (misalnya: "const int *"), sebagai pengecualian khusus dalam kasus itu berlaku untuk hal setelah itu.

Banyak orang suka menggunakan pengecualian khusus itu karena mereka pikir itu terlihat lebih bagus. Saya tidak menyukainya, karena itu pengecualian, dan karenanya membingungkan banyak hal.

TED
sumber
2
Saya terpecah masalah ini. Logikanya masuk akal. Namun sebagian besar pengembang c ++ akan menulis const T*dan itu menjadi lebih alami. Seberapa sering Anda menggunakan T* constanyways, biasanya referensi akan baik-baik saja. Saya mendapat sedikit dari semua ini ketika ingin boost::shared_ptr<const T>dan bukannya menulis const boost::shared_ptr<T>. Masalah yang sama dalam konteks yang sedikit berbeda.
Harga Matt
Sebenarnya, saya sering menggunakan pointer konstan daripada menggunakan konstanta. Juga, Anda harus berpikir tentang bagaimana Anda akan bereaksi di hadapan pointer ke pointer (dll.) Memang itu lebih jarang, tetapi akan lebih baik untuk memikirkan hal-hal dengan cara di mana Anda dapat menangani situasi ini dengan applomb.
TED
1
Satu keuntungan bagus lainnya menempatkan const di sebelah kanan tipe adalah bahwa sekarang semua yang ada di sebelah kiri constadalah tipe yang const, dan segala yang di sebelah kanan adalah const yang sebenarnya. Ambil int const * const * p;sebagai contoh. Tidak, saya biasanya tidak menulis seperti itu, ini hanya sebuah contoh. Pertama const: ketik int, Dan int yang adalah const adalah isi dari pointer const yang merupakan isi dari p. Kedua const: type adalah pointer ke constint, const oblect adalah isi darip
denganuff
18

Penggunaan Sederhana const.

Penggunaan paling sederhana adalah mendeklarasikan konstanta bernama. Untuk melakukan ini, satu menyatakan konstanta seolah-olah itu variabel tetapi tambahkanconst sebelumnya. Kita harus segera menginisialisasi di konstruktor karena, tentu saja, kita tidak dapat menetapkan nilai nanti karena itu akan mengubahnya. Sebagai contoh:

const int Constant1=96; 

akan membuat konstanta integer, tidak terbayangkan dipanggil Constant1 , dengan nilai 96.

Konstanta semacam itu berguna untuk parameter yang digunakan dalam program tetapi tidak perlu diubah setelah program dikompilasi. Ini memiliki keuntungan bagi programmer daripada preprocessor C#define perintah dalam hal itu dipahami & digunakan oleh kompiler itu sendiri, tidak hanya diganti ke dalam teks program oleh preprocessor sebelum mencapai kompilator utama, sehingga pesan kesalahan jauh lebih bermanfaat.

Ini juga berfungsi dengan pointer tetapi kita harus berhati-hati di mana const menentukan apakah pointer atau apa yang menunjuk adalah konstan atau keduanya. Sebagai contoh:

const int * Constant2 

menyatakan bahwa Constant2pointer variabel ke integer konstan dan:

int const * Constant2

adalah sintaks alternatif yang melakukan hal yang sama, sedangkan

int * const Constant3

menyatakan bahwa Constant3adalah pointer konstan ke variabel integer dan

int const * const Constant4

menyatakan itu Constant4 adalah pointer konstan ke integer konstan. Pada dasarnya 'const' berlaku untuk apa pun yang ada di sebelah kirinya (selain jika tidak ada di sana dalam hal ini berlaku untuk apa pun yang merupakan hak langsungnya).

ref: http://duramecho.com/ComputerInformation/WhyHowCppConst.html

ufukgun
sumber
9

Saya memiliki keraguan yang sama seperti Anda sampai saya menemukan buku ini oleh C ++ Guru Scott Meyers. Rujuk Item ketiga dalam buku ini di mana ia berbicara secara rinci tentang penggunaan const.

Ikuti saja saran ini

  1. Jika kata constmuncul di sebelah kiri tanda bintang, yang ditunjukkan adalah konstan
  2. Jika kata constmuncul di sebelah kanan tanda bintang, penunjuk itu sendiri konstan
  3. Jika constmuncul di kedua sisi, keduanya konstan
rgk
sumber
7

Sederhana tapi rumit. Harap dicatat bahwa kami dapat menukar constkualifikasi dengan jenis data ( int, char,float , dll).

Mari kita lihat contoh di bawah ini.


const int *p==> *pread-only [ padalah pointer ke integer konstan]

int const *p==> *pread-only [ padalah pointer ke integer konstan]


int *p const==> Pernyataan Salah . Compiler melempar kesalahan sintaksis.

int *const p==> pread-only [ padalah pointer konstan ke integer]. Karena pointer di psini hanya baca, deklarasi dan definisi harus berada di tempat yang sama.


const int *p const ==> Pernyataan Salah . Compiler melempar kesalahan sintaksis.

const int const *p ==> *phanya-baca

const int *const p1 ==> *pdan phanya-baca [ padalah pointer konstan ke integer konstan]. Karena pointer di psini hanya baca, deklarasi dan definisi harus berada di tempat yang sama.


int const *p const ==> Pernyataan Salah . Compiler melempar kesalahan sintaksis.

int const int *p ==> Pernyataan Salah . Compiler melempar kesalahan sintaksis.

int const const *p ==> *phanya-baca dan setara denganint const *p

int const *const p ==> *pdan phanya-baca [ padalah pointer konstan ke integer konstan]. Karena pointer di psini hanya baca, deklarasi dan definisi harus berada di tempat yang sama.

Abhijit Sahu
sumber
6

Ada banyak titik halus lainnya seputar kebenaran const di C ++. Saya kira pertanyaan di sini hanyalah tentang C, tapi saya akan memberikan beberapa contoh terkait karena tag tersebut adalah C ++:

  • Anda sering memberikan argumen besar seperti string TYPE const &yang mencegah objek dari modifikasi atau disalin. Contoh:

    TYPE& TYPE::operator=(const TYPE &rhs) { ... return *this; }

    Tetapi TYPE & consttidak ada artinya karena referensi selalu const.

  • Anda harus selalu memberi label metode kelas yang tidak mengubah kelas sebagai const, jika tidak, Anda tidak dapat memanggil metode dari TYPE const &referensi. Contoh:

    bool TYPE::operator==(const TYPE &rhs) const { ... }

  • Ada situasi umum di mana nilai pengembalian dan metode harus berupa const. Contoh:

    const TYPE TYPE::operator+(const TYPE &rhs) const { ... }

    Bahkan, metode const tidak boleh mengembalikan data kelas internal sebagai referensi-ke-non-const.

  • Akibatnya, kita harus sering membuat kedua metode const dan non-const menggunakan overloading const. Misalnya, jika Anda mendefinisikan T const& operator[] (unsigned i) const;, maka Anda mungkin juga menginginkan versi non-const yang diberikan oleh:

    inline T& operator[] (unsigned i) { return const_cast<char&>( static_cast<const TYPE&>(*this)[](i) ); }

Afaik, tidak ada fungsi const di C, fungsi non-anggota tidak dapat dengan sendirinya menjadi const di C ++, metode const mungkin memiliki efek samping, dan kompiler tidak dapat menggunakan fungsi const untuk menghindari panggilan fungsi ganda. Bahkan, bahkan int const &referensi sederhana dapat menyaksikan nilai yang dirujuk diubah di tempat lain.

Jeff Burdges
sumber
6

Sintaks deklarasi C dan C ++ telah berulang kali dideskripsikan sebagai percobaan yang gagal, oleh desainer asli.

Sebagai gantinya, beri nama tipe "pointer to Type"; Saya akan menyebutnya Ptr_:

template< class Type >
using Ptr_ = Type*;

Sekarang Ptr_<char>adalah pointer ke char.

Ptr_<const char>adalah penunjuk ke const char.

Dan const Ptr_<const char>adalah constpointer ke const char.

Sana.

masukkan deskripsi gambar di sini

Ceria dan hth. - Alf
sumber
3
apakah Anda memiliki kutipan untuk kalimat pertama?
sp2danny
@ sp2danny: Googling “C sintaks gagal percobaan” hanya batuk sejumlah wawancara dengan Bjarne Stroustrup tempat dia mengungkapkan nya pendapat arah itu, misalnya “Saya menganggap sintaks C declarator percobaan yang gagal” dalam wawancara Slashdot. Jadi saya tidak memiliki referensi untuk klaim tentang sudut pandang desainer asli C. Saya kira itu dapat ditemukan oleh upaya penelitian yang cukup kuat, atau mungkin dibantah hanya dengan bertanya kepada mereka, tapi saya pikir lebih baik seperti sekarang. dengan bagian klaim itu, masih ragu-ragu dan kemungkinan benar :)
Ceria dan hth. - Alf
1
"Sintaks deklarasi C dan C ++ telah berulang kali dideskripsikan sebagai percobaan yang gagal, oleh desainer asli." salah untuk C tolong ubah kalimat Anda tentang C atau berikan beberapa kutipan.
Stargateur
3
@Stargateur: Rupanya Anda telah membaca komentar sebelumnya dan menemukan sesuatu yang dapat Anda manfaatkan untuk hiburan. Semoga beruntung dengan hidupmu. Bagaimanapun, orang-orang tua seperti saya ingat banyak hal yang tidak dapat kita buktikan tanpa terlibat dalam penelitian yang sangat memakan waktu. Anda bisa mengambil kata saya.
Ceria dan hth. - Alf
1
@Stargateur "Sethi (...) mengamati bahwa banyak deklarasi dan ekspresi bersarang akan menjadi lebih sederhana jika operator tipuan telah diambil sebagai operator postfix alih-alih awalan, tetapi pada saat itu sudah terlambat untuk berubah." berasal dari DMR. Tentu saja DMR tidak menemukan kata kunci const dan volatile, mereka berasal dari C ++ / X3J11, sebagaimana dibuktikan pada halaman itu.
Antti Haapala
6

Bagi saya, posisi constyaitu apakah muncul ke KIRI atau KANAN atau pada KIRI dan KANAN relatif terhadap *membantu saya mencari tahu arti sebenarnya.

  1. A constke KIRI dari *menunjukkan bahwa objek yang ditunjuk oleh pointer adalah constobjek.

  2. A consthingga HAK *menunjukkan bahwa pointer adalah constpointer.

Tabel berikut diambil dari Stanford CS106L Standard C ++ Programming Laboratory Reader Reader.

masukkan deskripsi gambar di sini

sri
sumber
3

Ini sebagian besar membahas baris kedua: praktik terbaik, tugas, parameter fungsi dll.

Latihan umum. Cobalah untuk membuat segala constyang Anda bisa. Atau dengan kata lain, buat semuanya constuntuk memulai, dan kemudian hapus set minimumconst diperlukan untuk memungkinkan program berfungsi. Ini akan sangat membantu dalam mencapai pembenaran yang benar, dan akan membantu memastikan bahwa bug halus tidak diperkenalkan ketika orang mencoba dan menetapkan hal-hal yang seharusnya tidak mereka modifikasi.

Hindari const_cast <> seperti wabah. Ada satu atau dua kasus penggunaan yang sah untuk itu, tetapi mereka sangat sedikit dan jarang. Jika Anda mencoba mengubah constobjek, Anda akan melakukan jauh lebih baik untuk menemukan siapa pun yang menyatakannyaconst pada langkah pertama dan membicarakannya dengan mereka untuk mencapai konsensus tentang apa yang harus terjadi.

Yang mengarah ke tugas dengan sangat rapi. Anda dapat menetapkan ke dalam sesuatu hanya jika itu non-const. Jika Anda ingin menetapkan sesuatu yang const, lihat di atas. Ingatlah bahwa dalam deklarasi int const *foo;dan int * const bar;hal-hal yang berbedaconst - jawaban lain di sini telah membahas masalah itu dengan mengagumkan, jadi saya tidak akan membahasnya.

Parameter fungsi:

Lewati nilai: mis. void func(int param)Anda tidak peduli dengan satu atau lain cara di situs panggilan. Argumen dapat dibuat bahwa ada kasus penggunaan untuk mendeklarasikan fungsi sebagai void func(int const param)tetapi yang tidak berpengaruh pada pemanggil, hanya pada fungsi itu sendiri, dalam nilai apa pun yang dilewatkan tidak dapat diubah oleh fungsi selama panggilan.

Lulus dengan referensi: mis. void func(int &param)Sekarang itu membuat perbedaan. Seperti yang baru saja dinyatakan funcdiizinkan untuk berubah param, dan situs panggilan apa pun harus siap untuk menghadapi konsekuensinya. Mengubah deklarasi untuk void func(int const &param)mengubah kontrak, dan jaminan yang funcsekarang tidak dapat berubahparam , berarti apa yang disahkan adalah apa yang akan keluar. Seperti yang telah dicatat orang lain, ini sangat berguna untuk melewati benda besar yang tidak ingin Anda ubah dengan murah. Melewati referensi jauh lebih murah daripada melewatkan objek besar berdasarkan nilai.

Lewati dengan penunjuk: misalnya void func(int *param)dan void func(int const *param)Keduanya cukup identik dengan rekan referensi mereka, dengan peringatan bahwa fungsi yang dipanggil sekarang perlu diperiksa nullptrkecuali beberapa jaminan kontrak lainnya memastikan funcbahwa ia tidak akan pernah menerima nullptrin param.

Sepotong opini tentang topik itu. Membuktikan kebenaran dalam kasus seperti ini sangat sulit, terlalu mudah untuk membuat kesalahan. Jadi jangan mengambil risiko, dan selalu periksa parameter pointer untuk nullptr. Anda akan menyelamatkan diri dari rasa sakit dan penderitaan dan sulit menemukan serangga dalam jangka panjang. Dan untuk biaya pemeriksaan, ini sangat murah, dan dalam kasus-kasus di mana analisis statis yang dibangun dalam kompiler dapat mengelolanya, pengoptimal akan tetap melakukannya. Aktifkan Tautan Pembuatan Kode Waktu untuk MSVC, atau WOPR (saya pikir) untuk GCC, dan Anda akan membuatnya lebar program, yaitu bahkan dalam pemanggilan fungsi yang melintasi batas modul kode sumber.

Pada akhir hari semua hal di atas membuat kasus yang sangat solid untuk selalu lebih suka referensi ke petunjuk. Mereka semua lebih aman.

dengan sungguh-sungguh
sumber
3

Const dengan int di kedua sisi akan membuat pointer ke int konstan :

const int *ptr=&i;

atau:

int const *ptr=&i;

constsetelah itu *akan membuat pointer konstan ke int :

int *const ptr=&i;

Dalam hal ini semua ini adalah pointer ke integer konstan , tetapi tidak satupun dari ini adalah pointer konstan:

 const int *ptr1=&i, *ptr2=&j;

Dalam hal ini semua adalah pointer ke integer konstan dan ptr2 adalah pointer konstan ke integer konstan . Tapi ptr1 bukan pointer konstan:

int const *ptr1=&i, *const ptr2=&j;
Pemburu
sumber
3
  • jika constadalah ke kiri dari *, mengacu pada nilai (tidak peduli apakah itu const intatau int const)
  • jika constadalah di sebelah kanan dari *, itu mengacu pada pointer itu sendiri
  • keduanya bisa sekaligus

Poin penting: const int *p tidak berarti nilai yang Anda maksud adalah konstan !! . Ini berarti bahwa Anda tidak dapat mengubahnya melalui pointer itu (artinya, Anda tidak dapat menetapkan $ * p = ... `). Nilai itu sendiri dapat diubah dengan cara lain. Misalnya

int x = 5;
const int *p = &x;
x = 6; //legal
printf("%d", *p) // prints 6
*p = 7; //error 

Ini dimaksudkan untuk digunakan sebagian besar dalam tanda tangan fungsi, untuk menjamin bahwa fungsi tidak dapat secara tidak sengaja mengubah argumen yang disahkan.

blue_note
sumber
2

Hanya demi kelengkapan untuk C mengikuti penjelasan yang lain, tidak yakin untuk C ++.

  • pp - pointer ke pointer
  • p - pointer
  • data - hal yang runcing, dalam contoh x
  • bold - variabel read-only

Pointer

  • data p - int *p;
  • data p -int const *p;
  • data p -int * const p;
  • data p -int const * const p;

Pointer ke pointer

  1. data pp p - int **pp;
  2. data pp p -int ** const pp;
  3. data pp p -int * const *pp;
  4. data pp p -int const **pp;
  5. data pp p -int * const * const pp;
  6. data pp p -int const ** const pp;
  7. data pp p -int const * const *pp;
  8. data pp p -int const * const * const pp;
// Example 1
int x;
x = 10;
int *p = NULL;
p = &x;
int **pp = NULL;
pp = &p;
printf("%d\n", **pp);

// Example 2
int x;
x = 10;
int *p = NULL;
p = &x;
int ** const pp = &p; // Definition must happen during declaration
printf("%d\n", **pp);

// Example 3
int x;
x = 10;
int * const p = &x; // Definition must happen during declaration
int * const *pp = NULL;
pp = &p;
printf("%d\n", **pp);

// Example 4
int const x = 10; // Definition must happen during declaration
int const * p = NULL;
p = &x;
int const **pp = NULL;
pp = &p;
printf("%d\n", **pp);

// Example 5
int x;
x = 10;
int * const p = &x; // Definition must happen during declaration
int * const * const pp = &p; // Definition must happen during declaration
printf("%d\n", **pp);

// Example 6
int const x = 10; // Definition must happen during declaration
int const *p = NULL;
p = &x;
int const ** const pp = &p; // Definition must happen during declaration
printf("%d\n", **pp);

// Example 7
int const x = 10; // Definition must happen during declaration
int const * const p = &x; // Definition must happen during declaration
int const * const *pp = NULL;
pp = &p;
printf("%d\n", **pp);

// Example 8
int const x = 10; // Definition must happen during declaration
int const * const p = &x; // Definition must happen during declaration
int const * const * const pp = &p; // Definition must happen during declaration
printf("%d\n", **pp);

N-level Dereferensi

Teruslah berjalan, tetapi semoga manusia mengucilkan Anda.

int x = 10;
int *p = &x;
int **pp = &p;
int ***ppp = &pp;
int ****pppp = &ppp;

printf("%d \n", ****pppp);
Perilaku tidak terdefinisi
sumber
0
  1. const int*- penunjuk ke intobjek konstan .

Anda dapat mengubah nilai pointer; Anda tidak dapat mengubah nilai intobjek, pointer menunjuk ke.


  1. const int * const- pointer konstan ke intobjek konstan .

Anda tidak dapat mengubah nilai pointer atau nilai intobjek yang ditunjuk pointer.


  1. int const *- penunjuk ke intobjek konstan .

Pernyataan ini setara dengan 1. const int*- Anda dapat mengubah nilai pointer tetapi Anda tidak dapat mengubah nilai intobjek, pointer menunjuk ke.


Sebenarnya, ada opsi ke-4:

  1. int * const- pointer konstan ke intobjek.

Anda dapat mengubah nilai objek yang ditunjuk oleh pointer tetapi Anda tidak dapat mengubah nilai pointer itu sendiri. Pointer akan selalu mengarah ke intobjek yang sama tetapi nilai intobjek ini dapat diubah.


Jika Anda ingin menentukan tipe C atau C ++ construct tertentu, Anda dapat menggunakan Aturan Searah / Spiral yang dibuat oleh David Anderson; tetapi tidak bingung dengan Anderson`s Rule yang dibuat oleh Ross J. Anderson, yang merupakan sesuatu yang sangat berbeda.

RobertS mendukung Monica Cellio
sumber