Saya mencoba memahami pointer dalam C tetapi saya saat ini bingung dengan yang berikut:
char *p = "hello"
Ini adalah pointer char yang menunjuk pada array karakter, mulai dari h .
char p[] = "hello"
Ini adalah array yang menyimpan halo .
Apa perbedaannya ketika saya meneruskan kedua variabel ini ke fungsi ini?
void printSomething(char *p)
{
printf("p: %s",p);
}
char p[3] = "hello";
String initializer terlalu panjang untuk ukuran array yang Anda nyatakan. Salah ketik?char p[]="hello";
sudah cukup!char
spesifik.Jawaban:
char*
danchar[]
berbagai jenis , tetapi tidak segera terlihat dalam semua kasus. Ini karena array peluruhan menjadi pointer , yang berarti bahwa jika ekspresi tipechar[]
disediakan di mana salah satu tipechar*
diharapkan, kompiler secara otomatis mengubah array menjadi pointer ke elemen pertama.Fungsi contoh Anda
printSomething
mengharapkan penunjuk, jadi jika Anda mencoba meneruskan array ke sana seperti ini:Kompiler berpura-pura bahwa Anda menulis ini:
sumber
printf
menangani%s
format string: mulai dari alamat yang disediakan dan lanjutkan sampai menemukan terminator nol. Jika Anda ingin mencetak hanya satu karakter, Anda dapat menggunakan%c
string format, misalnya.char *p = "abc";
karakter NULL\0
ditambahkan secara otomatis seperti pada array char []?char *name; name="123";
tetapi dapat melakukan hal yang sama denganint
tipe? Dan setelah menggunakan%c
untuk mencetakname
, output tidak dapat dibaca string yang:�
?Ayo lihat:
foo * dan foo [] adalah tipe yang berbeda dan mereka ditangani secara berbeda oleh kompiler (pointer = alamat + representasi dari tipe pointer, array = pointer + panjang opsional array, jika diketahui, misalnya, jika array dialokasikan secara statis ), perinciannya dapat ditemukan dalam standar. Dan pada tingkat runtime tidak ada perbedaan di antara mereka (di assembler, well, hampir, lihat di bawah).
Juga, ada pertanyaan terkait di FAQ C :
sumber
C99 N1256 konsep
Ada dua penggunaan literal string karakter yang berbeda:
Inisialisasi
char[]
:Ini "lebih banyak sihir", dan dijelaskan pada 6.7.8 / 14 "Inisialisasi":
Jadi ini hanyalah jalan pintas untuk:
Seperti array reguler lainnya,
c
dapat dimodifikasi.Di tempat lain: ia menghasilkan:
Jadi ketika Anda menulis:
Ini mirip dengan:
Perhatikan pemeran implisit dari
char[]
kechar *
, yang selalu sah.Kemudian jika Anda memodifikasi
c[0]
, Anda juga memodifikasi__unnamed
, yaitu UB.Ini didokumentasikan pada 6.4.5 "String literal":
6.7.8 / 32 "Inisialisasi" memberikan contoh langsung:
Implementasi ELF GCC 4,8 x86-64
Program:
Kompilasi dan dekompilasi:
Output berisi:
Kesimpulan: GCC menyimpannya
char*
di.rodata
bagian, bukan di.text
.Jika kami melakukan hal yang sama untuk
char[]
:kami memperoleh:
sehingga disimpan di stack (relatif terhadap
%rbp
).Namun perlu dicatat bahwa skrip tautan default menempatkan
.rodata
dan.text
di segmen yang sama, yang telah menjalankan tetapi tidak memiliki izin menulis. Ini dapat diamati dengan:yang mengandung:
sumber
Anda tidak boleh mengubah konten konstanta string, yang merupakan tujuan pertama
p
. Yang keduap
adalah array yang diinisialisasi dengan konstanta string, dan Anda dapat mengubah isinya.sumber
Untuk kasus-kasus seperti ini, efeknya sama: Anda akhirnya melewati alamat karakter pertama dalam serangkaian karakter.
Deklarasi itu jelas tidak sama.
Berikut ini menyisihkan memori untuk string dan juga pointer karakter, dan kemudian menginisialisasi pointer untuk menunjuk ke karakter pertama dalam string.
Sementara yang berikut menyisihkan memori hanya untuk string. Jadi sebenarnya bisa menggunakan memori lebih sedikit.
sumber
Sejauh yang saya ingat, sebuah array sebenarnya adalah sekelompok pointer. Sebagai contoh
adalah pernyataan yang benar
sumber
*(arr + 1)
membawa Anda ke anggota keduaarr
. Jika*(arr)
menunjuk ke alamat memori 32-bit, mis.bfbcdf5e
, Kemudian*(arr + 1)
menunjuk kebfbcdf60
(byte kedua). Karenanya mengapa keluar dari lingkup array akan menyebabkan hasil yang aneh jika OS tidak segfault. Jikaint a = 24;
ada di alamatbfbcdf62
, maka mengaksesarr[2]
mungkin kembali24
, dengan asumsi segfault tidak terjadi terlebih dahulu.Dari APUE , Bagian 5.14:
Teks yang dikutip cocok dengan penjelasan @Ciro Santilli.
sumber
char p[3] = "hello"
? haruschar p[6] = "hello"
diingat ada char '\ 0' di akhir "string" di C.toh, array dalam C hanyalah sebuah penunjuk ke objek pertama dari objek penyesuaian dalam memori. satu-satunya yang berbeda adalah dalam semantik. sementara Anda dapat mengubah nilai pointer ke titik ke lokasi yang berbeda di memori, array, setelah dibuat, akan selalu menunjuk ke lokasi yang sama.
juga ketika menggunakan array "baru" dan "hapus" secara otomatis dilakukan untuk Anda.
sumber