Apakah mungkin untuk menginisialisasi C pointer NULL?
Saya telah menulis hal-hal seperti
char *x=NULL;
pada asumsi bahwa
char *x=2;
akan membuat char
pointer ke alamat 2.
Tapi, di GNU C Tutorial Pemrograman ia mengatakan bahwa int *my_int_ptr = 2;
menyimpan nilai integer 2
untuk apa pun yang random alamat di my_int_ptr
ketika itu dialokasikan.
Hal ini akan tampak menyiratkan bahwa saya sendiri char *x=NULL
adalah menetapkan apapun nilai dari NOL
dilemparkan ke char
adalah beberapa alamat acak pada memori.
Sementara
#include <stdlib.h>
#include <stdio.h>
int main()
{
char *x=NULL;
if (x==NULL)
printf("is NULL\n");
return EXIT_SUCCESS;
}
tidak, pada kenyataannya, cetak
adalah NULL
ketika saya mengkompilasi dan menjalankan itu, saya khawatir bahwa saya mengandalkan terdefinisi perilaku, atau setidaknya di bawah-perilaku tertentu, dan bahwa saya harus menulis
char *x;
x=NULL;
sebaliknya.
88
9
TL;DR Ya, sangat banyak.
The sebenarnya klaim yang dibuat pada panduan membaca like
Nah, mereka adalah salah, anda benar.
Untuk pernyataan, (ignoring, untuk saat ini, fakta bahwa pointer ke integer konversi adalah sebuah implementasi yang ditetapkan behaviour)
my_int_ptr
adalah variabel (tipe pointer untukint
), memiliki alamat tersendiri (type: alamat dari pointer ke integer), anda menyimpan sebuah nilai2
ke that alamat.Sekarang,
my_int_ptr
, menjadi tipe pointer, kita dapat mengatakan, itu points to nilai "type" pada lokasi memori pointed by nilai yang diadakan dimy_int_ptr
. Jadi, anda pada dasarnya menetapkan nilai of variabel pointer, bukan nilai dari lokasi memori yang ditunjuk oleh pointer.Jadi, untuk kesimpulan
menginisialisasi variabel pointer
x
untukNULL
, bukan value di alamat memori yang ditunjuk oleh pointer.Ini adalah sama sebagai
Ekspansi:
Sekarang, yang benar-benar sesuai, pernyataan seperti
adalah ilegal, karena melibatkan pelanggaran kendala. Untuk menjadi jelas,
my_int_ptr
adalah suatu variabel pointer, ketikint *
2
tipeint
, oleh definisi.dan mereka tidak "kompatibel" jenis, jadi ini inisialisasi adalah valid karena itu's melanggar aturan sederhana tugas, disebutkan dalam bab §6.5.16.1/P1, yang dijelaskan dalam Lundin's jawaban.
Dalam kasus orang's tertarik bagaimana inisialisasi terkait dengan tugas sederhana kendala, mengutip
C11
, bab §6.7.9, P11Tutorial adalah salah. Dalam ISO C,
int *my_int_ptr = 2;
adalah sebuah kesalahan. Dalam GNU C, itu berarti sama denganint *my_int_ptr = (int *)2;
. Ini mengkonversi integer2
ke alamat memori, dalam beberapa mode seperti yang ditentukan oleh compiler.Tidak mencoba untuk menyimpan apa pun di lokasi yang ditujukan dengan alamat tersebut (jika ada). Jika anda melanjutkan untuk menulis
*my_int_ptr = 5;
, maka itu akan mencoba untuk menyimpan nomor5
di lokasi yang dituju oleh alamat tersebut.Untuk memperjelas mengapa tutorial adalah salah,
int *my_int_ptr = 2;
adalah "pelanggaran kendala", itu adalah kode yang tidak diperbolehkan untuk mengkompilasi dan compiler harus memberikan diagnostik saat menghadapi itu.Sesuai 6.5.16.1 Sederhana tugas:
Dalam hal ini operan kiri adalah wajar tanpa pengecualian pointer. Tempat apakah itu menyebutkan bahwa hak operan diperbolehkan untuk menjadi integer (hitung jenis). Jadi kode melanggar C standar.
GCC dikenal berperilaku buruk kecuali anda secara eksplisit mengatakan itu untuk menjadi standar C compiler. Jika anda mengkompilasi kode sebagai
std=c11 -bertele-tele-kesalahan
, itu benar akan memberikan diagnostik seperti itu harus dilakukan.int *my_int_ptr = 2
Ini adalah benar-benar salah. Jika hal ini benar-benar ditulis maka silakan mendapatkan yang lebih baik buku atau tutorial.
int *my_int_ptr = 2
mendefinisikan integer pointer yang menunjuk ke alamat 2. Kemungkinan besar anda akan mendapatkan kecelakaan jika anda mencoba mengakses alamat2
.*my_int_ptr = 2
, yaitu tanpaint
di line, toko nilai dua untuk apapun random alamatmy_int_ptr
menunjuk ke. Setelah mengatakan ini, anda dapat menetapkanNULL
untuk pointer ketika didefinisikan.char *x=NULL;
benar-benar valid C.Edit: Saat menulis ini saya didn't tahu bahwa integer pointer konversi adalah implementasi perilaku didefinisikan. Silakan lihat jawaban yang baik oleh @M. M dan @SouravGhosh untuk rincian.
Banyak kebingungan tentang C pointer berasal dari pilihan yang sangat buruk yang pada awalnya dibuat mengenai coding style, dikuatkan oleh sangat sedikit pilihan dalam sintaks bahasa.
int *x = NULL;
benar C, tapi itu sangat menyesatkan, saya bahkan akan mengatakan tidak masuk akal, dan itu telah menghambat pemahaman bahasa bagi banyak pemula. Hal itu membuat orang berpikir bahwa di kemudian hari kita bisa melakukan*x = NULL;
yang tentu saja tidak mungkin. Anda lihat, jenis variabel tidakint
, dan nama variabel tidak*x
, juga tidak*
dalam deklarasi memainkan peran fungsional dalam bekerja sama dengan=
. Itu adalah murni deklaratif. Jadi, apa yang membuat banyak lebih masuk akal adalah:int* x = NULL;
yang juga benar C, meskipun tidak mematuhi asli K&R coding style. Hal itu membuatnya sangat jelas bahwa jenis adalahint*
, dan pointer variabelx
, sehingga menjadi jelas jelas bahkan untuk yang belum tahu bahwa nilaiNULL
yang disimpan kex
, yang merupakan pointer keint
.Selain itu, itu membuat lebih mudah untuk memperoleh aturan: ketika bintang yang lebih jauh dari nama variabel maka itu adalah deklarasi, sedangkan bintang yang melekat pada nama pointer dereferencing.
Jadi, sekarang ini menjadi jauh lebih dapat dimengerti bahwa lebih jauh ke bawah kita bisa melakukan
x = NULL;
atau*x = 2;
di lain kata-kata itu membuat lebih mudah bagi pemula untuk melihat bagaimana variabel = ekspresimenyebabkan
pointer-jenis variabel = pointer-ekspresidan
dereferenced-pointer-variabel = ekspresi`. (Untuk dimulai, dengan 'ekspresi' maksudku 'rvalue'.)Malang pilihan dalam sintaks dari bahasa adalah bahwa ketika mendeklarasikan variabel lokal yang anda bisa mengatakan
int i, *p;
yang menyatakan integer dan pointer ke integer, sehingga menyebabkan orang untuk percaya bahwa*
adalah bagian yang berguna dari nama. Tapi itu tidak, dan sintaks ini hanya unik kasus khusus, ditambahkan untuk kenyamanan anda, dan menurut pendapat saya seharusnya tidak pernah ada, karena hal itu membatalkan aturan yang saya usulkan di atas. Sejauh yang saya tahu, di tempat lain dalam bahasa sintaks ini bermakna, tetapi bahkan jika itu adalah, itu menunjuk ke sebuah perbedaan dalam cara penunjuk jenis yang didefinisikan dalam C. di tempat lain, dalam satu deklarasi variabel, dalam daftar parameter, dalam struct anggota, dll. anda dapat mendeklarasikan pointer anda sebagaitipe* pointer-variabel
bukantipe *pointer-variabel
; hal ini sangat legal dan lebih masuk akal.Saya ingin menambahkan sesuatu yang ortogonal terhadap banyak jawaban yang sangat baik. Sebenarnya, inisialisasi untuk
NULL
jauh dari praktek yang buruk dan mungkin berguna jika pointer itu mungkin atau mungkin tidak dapat digunakan untuk menyimpan secara dinamis dialokasikan blok memori.Karena menurut ISO-IEC 9899 standar
gratis
adalah sebuah nop ketika argumenNULL
, kode di atas (atau sesuatu yang lebih bermakna sepanjang baris yang sama) adalah legit.Ini adalah benar.
Fungsi ini adalah benar untuk apa yang dilakukannya. Memberikan alamat dari 0 untuk char pointer x. Artinya, poin pointer x ke alamat memori 0.
Alternatif:
Saya menebak seperti apa yang anda inginkan adalah:
ini adalah null pointer
Hanya ingat:
Dalam C, sisi kiri dengan nilai selalu mengevaluasi ke lokasi memori, sementara sisi kanan selalu mengevaluasi nilai(baik itu int atau alamat atau class Foo).