it-swarm-id.com

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

Saya selalu mengacaukan cara menggunakan const int*, const int * const, dan int const * dengan benar. Apakah ada seperangkat aturan yang mendefinisikan apa yang bisa dan tidak bisa Anda lakukan?

Saya ingin tahu semua yang harus dilakukan dan yang tidak boleh dilakukan dalam hal penugasan, meneruskan ke fungsi, dll.

1126
ultraman

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

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

Sekarang const pertama dapat 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 ** - sebuah pointer ke sebuah pointer ke sebuah const int
  • int * const * const - pointer const ke pointer const ke int
  • ...

Dan untuk memastikan kami jelas tentang arti const

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

foo adalah 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 gaya-C di mana Anda memiliki pointer ke const char. Anda dapat mengubah string mana yang Anda tuju tetapi Anda tidak dapat mengubah konten string ini. Ini penting ketika string itu sendiri di segmen data dari suatu program dan tidak boleh diubah.

bar adalah 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 pointer T* const kecuali Anda perlu mengizinkan pointer NULL.

1920
Matt Price

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 ketik Ulangi sampai ekspresi berakhir.

ini demo:

pointer to int

const pointer to int const

pointer to int const

pointer to const int

const pointer to int

274
Shijing Lv

Saya pikir semuanya sudah dijawab di sini, tetapi saya hanya ingin menambahkan bahwa Anda harus waspada terhadap typedefs! Mereka BUKAN hanya penggantian teks.

Sebagai contoh:

typedef char *ASTRING;
const ASTRING astring;

Jenis astring adalah char * const, bukan const char *. Ini adalah salah satu alasan saya selalu cenderung menempatkan const di sebelah kanan tipe, dan tidak pernah di awal.

130
Kaz Dragon

Seperti hampir semua orang tunjukkan:

Apa perbedaan antara const X* p, X* const p dan const X* const p?

Anda harus membaca deklarasi pointer 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 hal.

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

47
luke
  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

    Suatu pointer yang melaluinya seseorang tidak dapat mengubah nilai dari suatu variabel yang dikenal sebagai pointer ke konstanta.

    int const * ptr3 = &var2;
    *ptr3 = 4; // Error
    
  4. Penunjuk 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
    
41
Behrooz Tabesh

Pertanyaan ini menunjukkan tepatnya mengapa saya suka melakukan hal-hal seperti yang saya sebutkan dalam pertanyaan saya apakah const setelah tipe id dapat diterima?

Singkatnya, saya menemukan cara termudah untuk mengingat aturannya adalah "const" menjadi setelah hal itu 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 ini merupakan pengecualian, dan dengan demikian membingungkan banyak hal.

16
T.E.D.

Aturan umum adalah bahwa kata kunci const berlaku untuk apa yang mendahuluinya segera. Pengecualian, const awal berlaku untuk hal-hal berikut.

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

Edit: .__ Untuk Dos dan Larangan, jika jawaban ini tidak cukup, bisakah Anda lebih tepat tentang apa yang Anda inginkan?

15
AProgrammer

Penggunaan Sederhana ‘const’

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

const int Constant1=96; 

akan membuat konstanta integer, yang secara imajinatif disebut 'Constant1', dengan nilai 96.

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

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

const int * Constant2 

menyatakan bahwa Constant2 adalah pointer variabel ke integer konstan dan

int const * Constant2

adalah sintaks alternatif yang melakukan hal yang sama, sedangkan

int * const Constant3

menyatakan bahwa Constant3 adalah pointer konstan ke integer variabel dan

int const * const Constant4

menyatakan bahwa 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

14
ufukgun

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

Ikuti saja saran ini

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

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

Sebagai gantinya, mari beri nama jenis “pointer to Type”; Saya akan menyebutnya Ptr_:

template< class Type >
using Ptr_ = Type*;

Sekarang Ptr_<char> adalah penunjuk ke char.

Ptr_<const char> adalah penunjuk ke const char.

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

Sana.

 enter image description here

Sederhana tapi rumit. Harap dicatat bahwa kami dapat menukar kualifikasi const dengan tipe data apa pun (int, char, float, dll.).

Mari kita lihat contoh di bawah ini.


const int *p ==> *p adalah read-only [p adalah pointer ke integer konstan]

int const *p ==> *p adalah read-only [p adalah pointer ke integer konstan]


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

int *const p ==> p adalah read-only [p adalah pointer konstan ke integer] ..__ Karena pointer p di sini read-only, deklarasi dan definisi harus di tempat yang sama.


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

const int const *p ==> *p hanya bisa dibaca

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


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

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

int const const *p ==> *p hanya-baca dan setara dengan int const *p

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

5
Abhijit Sahu

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

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

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

    Tetapi TYPE & const tidak 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 referensi TYPE const &. 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 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 referensi int const & sederhana dapat menyaksikan nilai yang dirujuk diubah di tempat lain.

5
Jeff Burdges

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

const int *ptr=&i;

atau 

int const *ptr=&i;

const setelah '*' akan membuat pointer konstan ke int .

int *const ptr=&i;

Dalam hal ini semua 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;
2
Hunter

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

Latihan umum. Cobalah untuk membuat segalanya const yang Anda bisa. Atau dengan kata lain, buat semuanya const untuk memulai, dan kemudian hapus set minimum consts yang 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 tidak seharusnya 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 objek const, Anda akan jauh lebih baik menemukan siapa pun yang menyatakannya const 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 adalah 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 berbeda const - jawaban lain di sini telah membahas masalah itu dengan baik, 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-kasus penggunaan untuk mendeklarasikan fungsi sebagai void func(int const param) tetapi itu tidak berpengaruh pada pemanggil, hanya pada fungsi itu sendiri, di mana nilai apa pun yang dilewatkan tidak dapat diubah oleh fungsi selama panggilan.

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

Lewati dengan penunjuk: mis. 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 memeriksa nullptr kecuali beberapa jaminan kontrak lainnya menjamin func bahwa ia tidak akan pernah menerima nullptr dalam param.

Sepotong opini tentang topik itu. Membuktikan kebenaran dalam kasus seperti ini sangat sulit, terlalu mudah untuk membuat kesalahan. Jadi jangan ambil 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 tetap akan mengabaikannya. Aktifkan Tautan Pembuatan Kode Waktu untuk MSVC, atau WOPR (saya pikir) untuk GCC, dan Anda akan membuatnya lebar program, mis. Bahkan dalam panggilan 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 hanya lebih aman.

1
dgnuff

Bagi saya, posisi const yaitu apakah muncul ke KIRI atau KANAN atau pada KIRI dan KANAN relatif terhadap * membantu saya mengetahui arti sebenarnya.

  1. Sebuah const ke KIRI dari * menunjukkan bahwa objek yang ditunjuk oleh pointer adalah objek const.

  2. Sebuah const dengan KANAN dari * menunjukkan bahwa penunjuk tersebut adalah penunjuk const.

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

 enter image description here

1
srivatsahc

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

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

Pointer

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

Pointer ke pointer

  1. data pp p - int **pp;
  2. pp p data - int ** const pp;
  3. pp p data - int * const *pp;
  4. pp p data - int const **pp;
  5. pp p data - int * const * const pp;
  6. pp p data - int const ** const pp;
  7. pp p data - int const * const *pp;
  8. pp p data - 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);

Tingkat-N Dereferensi

Teruslah berjalan, tetapi semoga umat manusia mengucilkan Anda.

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

 printf("%d \n", ****pppp);
0