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.

Mengomentari pertanyaan (18)
Larutan

Is mungkin untuk menginisialisasi C pointer NULL?

TL;DR Ya, sangat banyak.


The sebenarnya klaim yang dibuat pada panduan membaca like

_On sisi lain, jika anda menggunakan hanya satu tugas awal, int *my_int_ptr = 2;, program akan mencoba untuk mengisi isi dari lokasi memori yang ditunjuk oleh my_int_ptr dengan nilai 2. Sejak my_int_ptr diisi dengan sampah, hal ini dapat setiap alamat. [...]_

Nah, mereka adalah salah, anda benar.

Untuk pernyataan, (ignoring, untuk saat ini, fakta bahwa pointer ke integer konversi adalah sebuah implementasi yang ditetapkan behaviour)

int * my_int_ptr = 2;

my_int_ptr adalah variabel (tipe pointer untuk int), memiliki alamat tersendiri (type: alamat dari pointer ke integer), anda menyimpan sebuah nilai 2 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 di my_int_ptr. Jadi, anda pada dasarnya menetapkan nilai of variabel pointer, bukan nilai dari lokasi memori yang ditunjuk oleh pointer.

Jadi, untuk kesimpulan

 char *x=NULL;

menginisialisasi variabel pointer x untuk NULL, bukan value di alamat memori yang ditunjuk oleh pointer.

Ini adalah sama sebagai

 char *x;
 x = NULL;    

Ekspansi:

Sekarang, yang benar-benar sesuai, pernyataan seperti

 int * my_int_ptr = 2;

adalah ilegal, karena melibatkan pelanggaran kendala. Untuk menjadi jelas,

  • my_int_ptr adalah suatu variabel pointer, ketik int *
  • sebuah konstanta integer, 2 tipe int, 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, P11

penginisialisasi untuk skalar akan menjadi sebuah ekspresi tunggal, opsional tertutup dalam kawat gigi. Yang nilai awal dari objek adalah bahwa ekspresi (setelah konversi); jenis yang sama kendala dan konversi adapun tugas sederhana berlaku, dengan tipe skalar menjadi wajar tanpa pengecualian versi dari tipe yang dideklarasikan.

Komentar (6)

Tutorial adalah salah. Dalam ISO C, int *my_int_ptr = 2; adalah sebuah kesalahan. Dalam GNU C, itu berarti sama dengan int *my_int_ptr = (int *)2; . Ini mengkonversi integer 2 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 nomor 5 di lokasi yang dituju oleh alamat tersebut.

Komentar (3)

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:

Kendala

salah Satu dari berikut ini akan mengadakan:

  • operan kiri memiliki atom, memenuhi syarat atau tidak memenuhi syarat jenis aritmatika, dan hak memiliki jenis aritmatika;
  • operan kiri memiliki atom, memenuhi syarat atau tidak memenuhi syarat versi dari struktur atau tipe union kompatibel dengan jenis yang tepat;
  • operan kiri memiliki atom, memenuhi syarat atau tidak memenuhi syarat jenis pointer, dan (mengingat jenis operan kiri akan memiliki setelah lvalue konversi) kedua operand adalah pointer untuk memenuhi syarat atau tidak memenuhi syarat versi yang kompatibel jenis, dan jenis yang ditunjukkan oleh kiri telah semua kualifikasi dari jenis yang ditunjukkan oleh hak;
  • operan kiri memiliki atom, memenuhi syarat atau tidak memenuhi syarat jenis pointer, dan (mengingat jenis operan kiri akan memiliki setelah lvalue konversi) salah satu operand adalah pointer ke jenis objek, dan lain-lain merupakan pointer ke memenuhi syarat atau tidak memenuhi syarat versi batal, dan jenis yang ditunjukkan oleh kiri memiliki semua kualifikasi dari jenis yang ditunjukkan untuk dengan tepat;
  • operan kiri adalah atom, yang memenuhi syarat, atau tidak memenuhi syarat pointer, dan kanan adalah null pointer konstan; atau
  • operan kiri memiliki jenis atom, memenuhi syarat atau tidak memenuhi syarat _Bool, dan sebelah kanan adalah penunjuk.

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.

Komentar (7)

int *my_int_ptr = 2

menyimpan nilai integer 2 untuk apapun random alamat di my_int_ptr ketika itu dialokasikan.

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 alamat 2.

*my_int_ptr = 2, yaitu tanpa int di line, toko nilai dua untuk apapun random alamat my_int_ptr menunjuk ke. Setelah mengatakan ini, anda dapat menetapkan NULL 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.

Komentar (2)

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 tidak int, 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 adalah int*, dan pointer variabel x, sehingga menjadi jelas jelas bahkan untuk yang belum tahu bahwa nilai NULL yang disimpan ke x, yang merupakan pointer ke int.

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 = ekspresimenyebabkanpointer-jenis variabel = pointer-ekspresidandereferenced-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 sebagai tipe* pointer-variabel bukan tipe *pointer-variabel; hal ini sangat legal dan lebih masuk akal.

Komentar (8)

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.

int * p = NULL;
...
if (...) {
    p = (int*) malloc(...);
    ...
}
...
free(p);

Karena menurut ISO-IEC 9899 standar gratis adalah sebuah nop ketika argumen NULL, kode di atas (atau sesuatu yang lebih bermakna sepanjang baris yang sama) adalah legit.

Komentar (13)

Ini adalah benar.

int main()
{
    char * x = NULL;

    if (x==NULL)
        printf("is NULL\n");

    return EXIT_SUCCESS;
}

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:

int main()
{
    char* x = 0;

    if ( !x )
        printf(" x points to NULL\n");

    return EXIT_SUCCESS;
}

Saya menebak seperti apa yang anda inginkan adalah:

int main()
{
    char* x = NULL;
    x = alloc( sizeof( char ));
    *x = '2';

    if ( *x == '2' )
        printf(" x points to an address/location that contains a '2' \n");

    return EXIT_SUCCESS;
}

x is the street address of a house. *x examines the contents of that house.
Komentar (2)

ini adalah null pointer

int * nullPtr = (void*) 0;
Komentar (1)

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).

Komentar (5)