Apa gunanya malloc (0)?

Jawaban:

121

Menurut spesifikasinya, malloc (0) akan mengembalikan "pointer nol atau pointer unik yang berhasil diteruskan ke free ()".

Ini pada dasarnya memungkinkan Anda tidak mengalokasikan apa pun, tetapi tetap meneruskan variabel "artist" ke panggilan ke free () tanpa khawatir. Untuk tujuan praktis, ini hampir sama dengan melakukan:

artist = NULL;
Reed Copsey
sumber
51
Secara pribadi, menurut saya pengaturan ke NULL adalah strategi lintas platform yang lebih baik, karena free () dijamin (oleh spesifikasi) untuk bekerja dengan baik pada NULL sebagai input.
Reed Copsey
2
Seperti yang disebutkan oleh C. Ross, beberapa platform, secara teknis, dapat mengembalikan penunjuk di sini (yaitu "penunjuk unik yang dapat diteruskan ke gratis"), tetapi jika Anda memperlakukan ini sebagai karakter *, itu mungkin memberi Anda karakter tidak valid, tidak dihentikan. Mungkin berbahaya untuk mengandalkan ini dalam situasi lintas platform.
Reed Copsey
9
Benar-benar berharap spesifikasi akan mengatakan "lolos dengan aman ke realokasi" juga -.-
hanshenrik
1
@NSAddict "struct kosong dimana sizeof akan mengembalikan 0", berikan contoh, terdengar seperti ekstensi bahasa.
chux - Kembalikan Monica
1
@ Hanshenrik Siapa bilang Anda tidak bisa? realloc()memungkinkan Anda untuk melewatkan penunjuk valid apa pun yang dikembalikan oleh malloc(). Seharusnya cukup.
glglgl
51

Standar C (C17 7.22.3 / 1) mengatakan:

Jika ukuran ruang yang diminta adalah nol, perilaku implementasi didefinisikan: baik pointer nol dikembalikan, atau perilaku seolah-olah ukurannya adalah beberapa nilai bukan nol, kecuali bahwa pointer yang dikembalikan tidak boleh digunakan untuk mengakses objek.

Jadi, malloc(0)bisa kembali NULLatau penunjuk yang valid yang mungkin tidak dereferensi . Dalam kedua kasus, itu sangat valid untuk memanggilnya free().

Menurut saya tidak malloc(0)banyak gunanya, kecuali dalam kasus ketika malloc(n)dipanggil dalam loop misalnya, dan nmungkin nol.

Melihat kode di tautan, saya yakin bahwa penulis memiliki dua kesalahpahaman:

  • malloc(0) mengembalikan pointer yang valid selalu , dan
  • free(0) buruk.

Jadi, dia memastikan bahwa artistdan variabel lain selalu memiliki nilai "valid" di dalamnya. Komentar mengatakan sebanyak: // these must always point at malloc'd data.

Alok Singhal
sumber
10
Fakta bahwa itu tergantung pada implementasi membuatnya kurang lebih sama sekali tidak berguna - ini adalah salah satu bagian yang lebih buruk dari standar C, dan beberapa komite standar (misalnya PJ Plauger) telah mengeluhkannya.
10
Saya setuju. Jika malloc(0)mengembalikan pointer yang valid, malloc()mengembalikan NULLberarti selalu "gagal", dan 0bukan kasus khusus lagi, yang lebih konsisten.
Alok Singhal
1
Karena keadaan mallockegagalan untuk mendapatkan memori ditentukan oleh implementasi, implementasi dapat dengan mudah mendefinisikan bahwa alokasi size-0 selalu unsatisfiable ( ENOMEM), dan sekarang malloc(0)mengembalikan 0 (dengan errno==ENOMEM) secara konsisten. :-)
R .. GitHub STOP HELPING ICE
6
Bisakah Anda reallocmendapatkan pointer malloc(0)? Bisa Anda realloc((char*)NULL)?
Braden Best
3
@Braden Terbaik Ya untuk keduanya.
chux - Kembalikan Monica
11

malloc (0) adalah implementasi spesifik. Pustaka dapat mengembalikan NULL atau memiliki perilaku malloc biasa, tanpa alokasi memori. Apapun fungsinya, itu harus didokumentasikan di suatu tempat.

Biasanya, ini mengembalikan pointer yang valid dan unik tetapi TIDAK boleh dereferensi. Juga perhatikan bahwa itu BISA mengkonsumsi memori meskipun sebenarnya tidak mengalokasikan apa pun.

Dimungkinkan untuk mengalokasikan kembali pointer malloc (0) yang bukan null.

Memiliki malloc (0) verbatim tidak banyak gunanya. Ini sebagian besar digunakan ketika alokasi dinamis adalah nol byte dan Anda tidak peduli untuk memvalidasinya.

Coincoin
sumber
9
malloc()harus menyimpan "informasi rumah tangga" di suatu tempat (ukuran blok yang dialokasikan misalnya, dan data tambahan lainnya). Jadi, jika malloc(0)tidak dikembalikan NULL, itu akan menggunakan memori untuk menyimpan informasi itu, dan jika tidak free()d, akan menyebabkan kebocoran memori.
Alok Singhal
Implementasi Malloc melakukan pencatatan yang dapat menambahkan sejumlah data per pointer yang dikembalikan di atas ukuran yang diminta.
user7116
1
Memori yang dikonsumsi dan memori yang dialokasikan tidak berarti hal yang sama. Dalam kasus ini, sebagian besar implementasi akan mengembalikan pointer unik. Ini berarti bagian dari ruang alamat perlu dikorbankan untuk penunjuk itu. Bergantung pada pengalokasi, ini mungkin berarti akan mengalokasikan 1 byte atau lebih.
Coincoin
1
Pustaka dapat melakukan apa pun yang diinginkan - pustaka dapat mengembalikan penunjuk unik yang tidak malloc()akan ditampilkan oleh orang lain , atau dikembalikan NULL.
Alok Singhal
1
@jldupont: Setidaknya perpustakaan Microsoft C Run-Time mengembalikan penunjuk unik untuk malloc(0). Namun, dalam implementasi yang sama dari pustaka C standar, realloc(ptr, 0)membebaskan ptrdan mengembalikan NULL.
Medinoc
5

Ada jawaban di tempat lain di halaman ini yang dimulai dengan "malloc (0) akan mengembalikan alamat memori yang valid dan jangkauannya akan bergantung pada jenis penunjuk yang sedang dialokasikan memori". Pernyataan ini tidak benar (saya tidak memiliki reputasi yang cukup untuk mengomentari jawaban itu secara langsung, jadi tidak dapat meletakkan komentar ini langsung di bawah sana).

Melakukan malloc (0) tidak akan secara otomatis mengalokasikan memori dengan ukuran yang benar. Fungsi malloc tidak mengetahui apa yang Anda transmisikan hasilnya. Fungsi malloc hanya mengandalkan nomor ukuran yang Anda berikan sebagai argumennya. Anda perlu melakukan malloc (sizeof (int)) untuk mendapatkan penyimpanan yang cukup untuk menyimpan int, misalnya, bukan 0.

Krellan
sumber
4

malloc(0)tidak masuk akal bagi saya, kecuali kode tersebut mengandalkan perilaku khusus untuk implementasi. Jika kode dimaksudkan untuk menjadi portabel, maka itu harus memperhitungkan fakta bahwa pengembalian NULL dari malloc(0)bukanlah kegagalan. Jadi mengapa tidak menetapkan NULL sajaartist saja, karena itu adalah hasil sukses yang valid, dan lebih sedikit kode, dan tidak akan menyebabkan pemrogram pemeliharaan Anda meluangkan waktu untuk memahaminya?

malloc(SOME_CONSTANT_THAT_MIGHT_BE_ZERO)atau malloc(some_variable_which_might_be_zero)mungkin bisa memiliki kegunaannya, meskipun sekali lagi Anda harus lebih berhati-hati untuk tidak memperlakukan pengembalian NULL sebagai kegagalan jika nilainya 0, tetapi ukuran 0 seharusnya OK.

Steve Jessop
sumber
3

Ada banyak setengah jawaban benar di sekitar sini, jadi inilah fakta sebenarnya. Halaman manual untuk malloc()mengatakan:

Jika ukurannya 0, maka malloc () mengembalikan NULL, atau nilai pointer unik yang nantinya bisa berhasil diteruskan ke free ().

Artinya, sama sekali tidak ada jaminan bahwa hasil dari malloc(0)adalah unik atau tidak NULL. Satu-satunya jaminan disediakan oleh definisi free(), sekali lagi, inilah yang dikatakan halaman manual:

Jika ptr adalah NULL, tidak ada operasi yang dilakukan.

Jadi, apa pun yang malloc(0)dikembalikan, itu dapat diteruskan dengan aman free(). Tapi begitu juga NULLpenunjuk.

Akibatnya, menulis artist = malloc(0); tidak lebih baik daripada menulis artist = NULL;

cmaster - kembalikan monica
sumber
1
Sayang sekali penerapannya tidak diizinkan untuk mengembalikan pointer non-null, non-unik. Dengan cara itu, malloc(0)dapat menampilkan, katakanlah, 0x1, dan free()dapat memiliki pemeriksaan kasus khusus 0x1 seperti halnya untuk 0x0.
Todd Lehman
3
@Todd Lehman Penerapan dapat melakukan seperti yang Anda sarankan. Spesifikasi C tidak menentukan hasilnya harus " NULL, atau pointer unik". sebagai gantinya 'baik pointer nol atau pointer ke ruang yang dialokasikan ". Tidak ada persyaratan unik . OTOH, mengembalikan nilai khusus non-unik dapat mengganggu kode yang mengandalkan nilai unik. Mungkin pertanyaan kasus sudut untuk SO.
chux - Kembalikan Monica
manmungkin juga mendokumentasikan formulir yang ditentukan implementasi yang digunakan di * nix. Dalam hal ini tidak, tetapi masih bukan sumber kanonik untuk umum C.
Lundin
@Lin Benar. Tetapi halaman manual jauh lebih dapat diakses daripada standar C, dan halaman manual pada sistem GNU / Linux secara umum mendokumentasikan dengan cukup baik standar mana yang diikuti oleh implementasi. Bersamaan dengan informasi bagian mana yang mengikuti standar mana, haruskah berbeda. Saya merasa mereka berdua ingin tepat, dan mengiklankan setiap bit yang merupakan ekstensi GNU ...
cmaster - kembalikan monica
3

Mengapa Anda tidak boleh melakukan ini ...

Karena nilai kembali malloc bergantung pada implementasi, Anda mungkin mendapatkan pointer NULL atau alamat lain kembali. Hal ini pada akhirnya dapat membuat heap-buffer overflows jika kode penanganan error tidak memeriksa ukuran dan nilai yang dikembalikan, yang menyebabkan masalah stabilitas (crash) atau bahkan masalah keamanan yang lebih buruk.

Pertimbangkan contoh ini, di mana mengakses memori lebih lanjut melalui alamat yang dikembalikan akan merusak ukuran heap iff adalah nol dan implementasi mengembalikan nilai non NULL kembali.

size_t size;

/* Initialize size, possibly by user-controlled input */

int *list = (int *)malloc(size);
if (list == NULL) {
  /* Handle allocation error */
}
else {
  /* Continue processing list */
}

Lihat halaman Secure Coding ini dari CERT Coding Standards tempat saya mengambil contoh di atas untuk bacaan lebih lanjut.

auselen
sumber
Tautan telah dipindahkan: wiki.sei.cmu.edu/confluence/display/c/…
Cacahuete Frito
2

Memang, saya belum pernah melihat ini sebelumnya, ini adalah pertama kalinya saya melihat sintaks ini, bisa dibilang, kasus klasik fungsi berlebihan. Sehubungan dengan jawaban Reed, saya ingin menunjukkan bahwa ada hal serupa, yang tampak seperti fungsi yang kelebihan beban realloc:

  • foo bukan NULL dan ukurannya nol , realloc(foo, size);. Saat Anda meneruskan penunjuk non-NULL dan berukuran nol untuk realoc, realoc berperilaku seolah-olah Anda telah memanggil free (…)
  • foo adalah NULL dan ukurannya bukan nol dan lebih besar dari 1 , realloc(foo, size);. Saat Anda meneruskan pointer NULL dan ukurannya bukan nol, realloc berperilaku seolah-olah Anda telah memanggil malloc (…)

Semoga ini bisa membantu, Salam, Tom.

t0mm13b
sumber
1

Untuk benar-benar menjawab pertanyaan yang dibuat: tidak ada alasan untuk melakukan itu

Paolo
sumber
0

malloc (0) akan mengembalikan NULL atau pointer valid yang dapat diteruskan dengan benar ke free. Dan meskipun tampaknya memori yang ditunjukkannya tidak berguna atau tidak dapat ditulis atau dibaca, itu tidak selalu benar. :)

int *i = malloc(0);
*i = 100;
printf("%d", *i);

Kami mengharapkan kesalahan segmentasi di sini, tetapi yang mengejutkan, ini mencetak 100! Itu karena malloc sebenarnya meminta sebagian besar memori ketika kita memanggil malloc untuk pertama kalinya. Setiap panggilan ke malloc setelah itu, menggunakan memori dari potongan besar itu. Hanya setelah bagian besar itu selesai, ingatan baru diminta.

Penggunaan malloc (0): jika Anda berada dalam situasi di mana Anda ingin panggilan malloc berikutnya menjadi lebih cepat, memanggil malloc (0) harus melakukannya untuk Anda (kecuali untuk kasus edge).

Sagar Bhosale
sumber
1
Menulis ke *imungkin tidak macet dalam kasus Anda, tetapi itu perilaku yang tidak ditentukan. Waspadai setan hidung!
John Dvorak
1
Iya. Itu benar. Ini adalah implementasi spesifik. Saya telah memverifikasinya di MaxOS X dan beberapa distribusi Linux. Saya belum mencobanya di platform lain. Karena itu, konsep yang saya uraikan telah dijelaskan dalam buku "The C programming language" oleh Brain Kernighan dan Dennis Ritchie.
Sagar Bhosale
Saya tahu: sangat terlambat mengomentari pertanyaan ini. Namun terkadang ada kegunaannya malloc(0)yang tidak disebutkan. Pada implementasi yang mengembalikan nilai non-NULL, terutama dalam build DEBUG, kemungkinan akan mengalokasikan LEBIH BANYAK daripada yang Anda minta, dan memberi Anda penunjuk untuk melewati header internalnya. Ini memungkinkan Anda untuk merasakan penggunaan memori yang sebenarnya jika Anda mendapatkan ini sebelum dan sesudah serangkaian alokasi. misalnya: void* before = malloc(0); ... void* after = malloc(0); long long total = after - before;atau semacamnya.
Jesse Chisholm
Saya membaca "Bahasa pemograman C" oleh Brain Kernighan dan Dennis Ritchie dan saya tidak ingat apa yang dikatakannya malloc(0). Bisakah Anda mengatakan bab mana yang Anda rujuk juga? Memberikan kutipan yang tepat juga akan menyenangkan.
Андрей Беньковский
0

Di Windows:

  • void *p = malloc(0);akan mengalokasikan buffer panjang-nol pada heap lokal. Pointer yang dikembalikan adalah penunjuk heap yang valid.
  • mallocpada akhirnya memanggil HeapAllocmenggunakan heap runtime C default yang kemudian memanggil RtlAllocateHeap, dll.
  • free(p);digunakan HeapFreeuntuk membebaskan buffer dengan panjang 0 di heap. Tidak membebaskannya akan mengakibatkan kebocoran memori.
sam msft
sumber
0

Ini sebenarnya cukup berguna, dan (jelas IMHO), perilaku yang diizinkan untuk mengembalikan pointer NULL rusak. Penunjuk dinamis berguna tidak hanya untuk apa yang ditunjukkannya, tetapi juga fakta bahwa alamatnya unik. Mengembalikan NULL menghapus properti kedua itu. Semua program mallocs I yang disematkan (sebenarnya cukup sering) memiliki perilaku ini.

Scott Franco
sumber
-2

Berikut adalah analisis setelah menjalankan alat pemeriksaan memori valgrind.

==16740== Command: ./malloc0
==16740==
p1 = 0x5204040
==16740==
==16740== HEAP SUMMARY:
==16740==     in use at exit: 0 bytes in 0 blocks
==16740==   total heap usage: 2 allocs, 2 frees, 1,024 bytes allocated
==16740==
==16740== All heap blocks were freed -- no leaks are possible

dan inilah kode contoh saya:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main()
{
   //int i;
   char *p1;

   p1 = (char *)malloc(0);
   printf("p1 = %p\n", p1);

   free(p1);

   return 0;

}

Secara default 1024 byte dialokasikan. Jika saya meningkatkan ukuran malloc, byte yang dialokasikan akan meningkat 1025 dan seterusnya.

Shubhesh Swain
sumber
-3

Menurut jawaban Reed Copsey dan halaman manual malloc, saya menulis beberapa contoh untuk diuji. Dan saya menemukan malloc (0) akan selalu memberikan nilai yang unik. Lihat contoh saya:

char *ptr;
if( (ptr = (char *) malloc(0)) == NULL )
    puts("Got a null pointer");
else
    puts("Got a valid pointer");

Outputnya adalah "Got a valid pointer", yang artinya ptrtidak null.

Neal
sumber
-6

malloc(0)akan mengembalikan alamat memori yang valid dan jangkauannya akan bergantung pada jenis penunjuk yang dialokasikan memori. Anda juga dapat menetapkan nilai ke area memori tetapi ini harus dalam jangkauan dengan jenis penunjuk yang digunakan. Anda juga dapat mengosongkan memori yang dialokasikan. Saya akan menjelaskan ini dengan sebuah contoh:

int *p=NULL;
p=(int *)malloc(0);
free(p);

Kode di atas akan bekerja dengan baik di gcckompiler pada mesin Linux. Jika Anda memiliki kompiler 32 bit, maka Anda dapat memberikan nilai dalam kisaran integer, yaitu -2147483648 hingga 2147483647. Hal yang sama juga berlaku untuk karakter. Harap dicatat bahwa jika tipe pointer yang dideklarasikan berubah maka range nilai akan berubah terlepas dari malloctypecast, mis

unsigned char *p=NULL;
p =(char *)malloc(0);
free(p);

p akan mengambil nilai dari 0 sampai 255 dari char karena dideklarasikan sebagai unsigned int.

Suryakant Tiwari
sumber
5
Krellan benar dalam menunjukkan bahwa jawaban ini salah: malloc()tidak tahu apa-apa tentang pemeran (yang sebenarnya sepenuhnya berlebihan dalam C). Membedakan nilai kembalian malloc(0)akan memicu perilaku yang tidak ditentukan.
cmaster
-6

Hanya untuk memperbaiki kesan yang salah di sini:

artist = (char *) malloc(0);tidak akan pernah kembali NULL; itu tidak sama dengan artist = NULL;. Menulis sebuah program yang sederhana dan membandingkan artistdengan NULL. if (artist == NULL)salah dan if (artist)benar.

ALFRED OKORONKWO
sumber