Perbedaan antara char * dan const char *?

177

Apa bedanya

char* name

yang menunjuk ke string konstan literal, dan

const char* name
Tukang es
sumber
apa yang Anda maksud dengan " string konstan literal" dalam C (bukan C ++)
gbulmer
1
... char * nama dapat dibuat untuk menunjuk ke string string yang konstan
Iceman
konstanta dalam "string konstan literal" adalah mubazir, karena semua string literal dalam entitas teori konstan. Ini isi dari variabel yang dapat dibuat konstan atau bisa berubah. Deklarasi "const" hanya akan menimbulkan kesalahan waktu kompilasi jika Anda mencoba untuk mengubah konten karakter yang ditunjuk oleh "name"
Cupcake
Sederhana: nama "char * name" adalah pointer ke char, yaitu keduanya dapat diubah di sini. "const char * name" name adalah pointer ke const char yaitu pointer dapat berubah tetapi tidak char.
akD
Baca hal-hal ini dari kanan ke kiri.
Jiapeng Zhang

Jawaban:

406

char*adalah pointer yang bisa berubah ke karakter / string yang bisa berubah .

const char*adalah pointer yang bisa berubah ke karakter / string yang tidak dapat diubah . Anda tidak dapat mengubah konten lokasi yang ditunjuk oleh pointer ini. Juga, kompiler diminta untuk memberikan pesan kesalahan saat Anda mencoba melakukannya. Untuk alasan yang sama, konversi dari const char *ke char*tidak digunakan lagi.

char* constadalah pointer yang tidak dapat diubah (tidak dapat menunjuk ke lokasi lain) tetapi konten lokasi yang ditunjukkannya dapat berubah .

const char* constadalah pointer yang tidak dapat diubah ke karakter / string yang tidak dapat diubah .

ankit.karwasra
sumber
4
Kebingungan dapat diselesaikan dengan penggunaan variabel setelah pernyataan yang disebutkan di atas dan dengan memberikan referensi ke variabel itu.
ankit.karwasra
3
@ ankit.karwasra, Anda melewatkan satu lagi:char const *
Pacerier
Saya kira dua opsi dengan karakter / string yang dapat berubah sangat berbahaya, karena Anda dapat melakukan memori kesalahan segmetasi, dan jika Anda benar-benar pintar, Anda dapat meretas komputer. Itulah mengapa kompiler selalu menunjukkan peringatan dalam implementasi yang saya pikir
Daniel N.
1
Tidak akan bermutasi char *memberikan kesalahan segmentasi saat menjalankan?
Divyanshu Maithani
1
Jadi saya menggunakan constjika saya ingin kompiler memberikan kesalahan jika saya lupa dan mengubah data secara tidak sengaja, bukan?
Akuntan م
43
char *name

Anda dapat mengubah arang ke nametitik mana , dan juga arang di mana ia menunjuk.

const char* name

Anda dapat mengubah arang ke nametitik mana , tetapi Anda tidak dapat mengubah arang di mana ia menunjuk.
koreksi: Anda dapat mengubah pointer, tetapi bukan karakter yang namemengarah ke ( https://msdn.microsoft.com/en-us/library/vstudio/whkd4k6a(v=vs.100).aspx , lihat "Contoh" ). Dalam kasus ini, constspecifier berlaku untuk char, bukan tanda bintang.

Menurut halaman MSDN dan http://en.cppreference.com/w/cpp/language/declarations , constsebelum itu *adalah bagian dari urutan decek-specifier, sedangkan constafter *adalah bagian dari deklarator.
Urutan specifier deklarasi dapat diikuti oleh beberapa deklarator, itulah sebabnya const char * c1, c2menyatakan c1sebagaiconst char * dan c2sebagai const char.

EDIT:

Dari komentar, pertanyaan Anda tampaknya bertanya tentang perbedaan antara dua deklarasi ketika pointer menunjuk ke string literal.

Dalam hal ini, Anda tidak boleh memodifikasi char ke nametitik mana , karena dapat menghasilkan Perilaku Tidak Terdefinisi . Literal string dapat dialokasikan di wilayah memori hanya baca (implementasi ditentukan) dan program pengguna tidak boleh memodifikasinya. Setiap upaya untuk melakukannya menghasilkan Perilaku Tidak Terdefinisi.

Jadi satu-satunya perbedaan dalam kasus itu (penggunaan dengan string literal) adalah bahwa deklarasi kedua memberi Anda sedikit keuntungan. Compiler biasanya akan memberi Anda peringatan jika Anda mencoba untuk memodifikasi string literal dalam kasus kedua.

Contoh Contoh Online:

#include <string.h>
int main()
{
    char *str1 = "string Literal";
    const char *str2 = "string Literal";
    char source[] = "Sample string";

    strcpy(str1,source);    //No warning or error, just Undefined Behavior
    strcpy(str2,source);    //Compiler issues a warning

    return 0;
}

Keluaran:

cc1: peringatan diperlakukan sebagai kesalahan
prog.c: Dalam fungsi 'utama':
prog.c: 9: kesalahan: meneruskan argumen 1 dari 'strcpy' membuang kualifikasi dari tipe target penunjuk

Perhatikan kompiler memperingatkan untuk kasus kedua tetapi tidak untuk yang pertama.

Alok Simpan
sumber
Terima kasih .. saya bercampur dengan string string literal, yang didefinisikan sebagai: char * name = "String Literal"; Mengubah "String Literal" tidak ditentukan ..
Iceman
@ user1279782: Err, Tunggu! Apakah Anda berbicara tentang poin yang menunjuk ke string literal di sini? Dalam hal ini Anda tidak boleh memodifikasi char yang menjadi namepoin dalam kedua kasus tersebut. Ini bisa menghasilkan UB.
Alok Simpan
Ya, itu intinya. Jadi dalam hal ini char * nama dan const char * nama berperilaku serupa, kan?
Iceman
4
Jawaban ini sangat ambigu atau hanya salah. Saya akan menafsirkan "Anda tidak dapat mengubah arang ke mana nama poin, tetapi Anda dapat mengubah arang di mana ia menunjuk." Karena tidak dapat memodifikasi pointer itu sendiri, tetapi dapat memodifikasi lokasi memori yang ditunjuknya, yang salah: ideone.com/6lUY9s sebagai alternatif untuk C murni: ideone.com/x3PcTP
shroudednight
1
@shroudednight: Anda perlu belajar sedikit tentang perilaku yang tidak terdefinisi, dan perlu membedakan antara: diizinkan dan tidak boleh dilakukan. :)
Alok Save
16
char mystring[101] = "My sample string";
const char * constcharp = mystring; // (1)
char const * charconstp = mystring; // (2) the same as (1)
char * const charpconst = mystring; // (3)

constcharp++; // ok
charconstp++; // ok
charpconst++; // compile error

constcharp[3] = '\0'; // compile error
charconstp[3] = '\0'; // compile error
charpconst[3] = '\0'; // ok

// String literals
char * lcharp = "My string literal";
const char * lconstcharp = "My string literal";

lcharp[0] = 'X';      // Segmentation fault (crash) during run-time
lconstcharp[0] = 'X'; // compile error

// *not* a string literal
const char astr[101] = "My mutable string";
astr[0] = 'X';          // compile error
((char*)astr)[0] = 'X'; // ok
Afriza N. Arief
sumber
1
Tidak satu pun dari petunjuk Anda yang menunjuk ke "literal string konstan" sesuai pertanyaan.
kaf
Perlu dicatat bahwa mengubah char *nilai memberikan kesalahan segmentasi karena kami mencoba untuk memodifikasi string literal (yang ada dalam memori hanya baca)
Divyanshu Maithani
10

Dalam kedua kasus Anda tidak dapat memodifikasi string literal, terlepas dari apakah pointer ke string literal tersebut dinyatakan sebagai char *atauconst char * .

Namun, perbedaannya adalah bahwa jika pointer const char *maka compiler harus memberikan diagnostik jika Anda mencoba untuk memodifikasi nilai menunjuk-ke, tetapi jika pointer itu char *maka tidak.

kaf
sumber
1
"Dalam kedua kasus Anda tidak dapat memodifikasi string literal, terlepas dari apakah ... [itu] dinyatakan sebagai char * atau const char *" Saya setuju bahwa programmer tidak boleh mencoba, tetapi apakah Anda mengatakan bahwa setiap kompiler C, pada setiap platform akan menolak kode tersebut, mengatur agar kode gagal pada waktu berjalan, atau yang lainnya? Saya percaya, satu file dapat memiliki definisi dan inisialisasi, dan file lain mungkin berisi extern ... namedan memiliki *name = 'X';. Pada 'sistem operasi yang tepat', itu mungkin gagal, tetapi pada sistem embedded, saya berharap untuk melakukan sesuatu platform / kompiler spesifik.
gbulmer
@ gbulmer: Anda tidak dapat mengubah string literal dalam program C yang benar. Apa program C yang salah yang mencoba dapat mengakibatkan tidak ada di sini atau di sana.
kafe
@ gbulmer: Salah satu definisi yang berguna adalah program yang tidak melanggar batasan apa pun yang ditentukan oleh standar bahasa C. Dengan kata lain, sebuah program yang memodifikasi string literal tidak benar dengan cara yang sama seperti program yang mereferensi pointer nol atau melakukan pembagian dengan 0 tidak benar.
caf
caf - saya pikir itu mungkin yang Anda maksud. Kemudian "Dalam kedua kasus Anda tidak dapat memodifikasi string literal" tampaknya lebih menyatakannya. Akan akurat untuk mengatakan "Dalam kedua kasus kendala yang ditentukan oleh standar bahasa C telah rusak, terlepas .... Tidak mungkin bagi kompiler atau sistem waktu berjalan untuk mengidentifikasi pelanggaran standar dalam semua kasus." Saya menganggap standar mengambil posisi bahwa efeknya tidak terdefinisi?
gbulmer
1
Ketika sebuah standar tidak dapat menyatakan apa pun, saya pikir mendefinisikan perilaku sebagai 'tidak terdefinisi' tampaknya menjadi batas yang tepat dan bermanfaat. Untuk menegaskan hubungan, 'program C yang benar' ' tidak dapat melakukan dereferensi penunjuk nol' sama dengan membuktikan masalah penghentian. Tapi saya tidak keberatan. Saya tidak akan melakukannya dan berharap untuk lolos dengan 'scott free' :-)
gbulmer
4

KASUS 1:

char *str = "Hello";
str[0] = 'M'  //Warning may be issued by compiler, and will cause segmentation fault upon running the programme

Set di atas str untuk menunjuk ke nilai literal "Hello" yang dikodekan dalam gambar biner program, yang ditandai sebagai hanya-baca dalam memori, berarti setiap perubahan dalam string literal ini ilegal dan yang akan menyebabkan kesalahan segmentasi.

KASUS 2:

const char *str = "Hello";
str[0] = 'M'  //Compile time error

KASUS 3:

char str[] = "Hello";
str[0] = 'M'; // legal and change the str = "Mello".
Mohit
sumber
2

Yang pertama Anda benar-benar dapat berubah jika Anda mau, yang kedua Anda tidak bisa. Baca tentang constkebenaran (ada beberapa panduan bagus tentang perbedaannya). Ada juga di char const * namemana Anda tidak bisa mengulanginya.

chikuba
sumber
Apa sebenarnya yang bisa berubah?
Antti Haapala
2

Pertanyaannya adalah apa bedanya

char *name

yang menunjuk ke string konstan literal, dan

const char *cname

Yaitu diberikan

char *name = "foo";

dan

const char *cname = "foo";

Tidak ada banyak perbedaan antara 2 dan keduanya dapat dilihat sebagai benar. Karena warisan yang lama dari kode C, string literal memiliki tipe char[], tidak const char[], dan ada banyak kode lama yang juga menerimachar * alih-alihconst char * , bahkan ketika mereka tidak mengubah argumen.

Perbedaan utama dari 2 secara umum adalah bahwa *cnameatau cname[n]akan mengevaluasi ke nilai tipe const char, sedangkan *nameatau name[n]akan mengevaluasi ke tipe nilai char, yang merupakan nilai yang dapat dimodifikasi . Compiler yang sesuai diperlukan untuk menghasilkan pesan diagnostik jika target penugasan bukan nilai yang dapat dimodifikasi ; itu tidak perlu menghasilkan peringatan tentang penugasan ke nilai jenis char:

name[0] = 'x'; // no diagnostics *needed*
cname[0] = 'x'; // a conforming compiler *must* produce a diagnostics message

Kompiler tidak diharuskan untuk menghentikan kompilasi dalam kedua kasus; cukup itu menghasilkan peringatan untuk tugas cname[0]. Program yang dihasilkan bukan program yang benar . Perilaku konstruk tidak terdefinisi . Mungkin macet, atau bahkan lebih buruk, mungkin tidak macet, dan mungkin mengubah string literal dalam memori.

Antti Haapala
sumber