Malloc'un (0) anlamı nedir?


Yanıtlar:


121

Spesifikasyonlara göre malloc (0) , "boş bir gösterici veya free () 'ye başarıyla geçirilebilen benzersiz bir gösterici" döndürecektir.

Bu temelde hiçbir şey ayırmanıza izin vermez, ancak yine de "artist" değişkenini endişelenmeden free () çağrısına aktarır. Pratik amaçlar için, yapmakla hemen hemen aynı şey:

artist = NULL;

51
Kişisel olarak, free () 'nin girdi olarak NULL üzerinde iyi çalışması garantili olduğundan (spesifikasyon gereği) NULL ayarının daha iyi bir çapraz platform stratejisi olduğunu düşünüyorum.
Reed Copsey

2
C. Ross'un bahsettiği gibi, bazı platformlar teknik olarak buraya bir işaretçi döndürebilir (bu, "ücretsiz olarak geçirilebilen benzersiz bir göstericidir"), ancak bunu bir karakter * olarak ele alıyorsanız, bu size bir geçersiz, sonlandırılmamış karakter. Çapraz platform durumlarında buna güvenmek tehlikeli olabilir.
Reed Copsey

9
Gerçekten gözlük iyi -.- olarak "güvenli realloc geçirilen" demek isterdim
hanshenrik

1
@NSAddict "sizeof'un 0 döndüreceği boş yapı", lütfen bir örnek sağlayın, bir dil uzantısı gibi geliyor.
chux

1
@hanshenrik Yapamayacağınızı kim söylüyor? realloc()tarafından döndürülen herhangi bir geçerli işaretçiyi geçmenize izin verir malloc(). Yeterli olmalı.
glglgl

51

C standardı (C17 7.22.3 / 1) diyor ki:

İstenen alanın boyutu sıfır ise, davranış uygulama tanımlanır: ya bir boş gösterici döndürülür ya da davranış, boyut sıfırdan farklı bir değermiş gibi olur, ancak döndürülen işaretçi bir nesneye erişmek için kullanılmamalıdır.

Yani, malloc(0)dönebilir NULLveya referans alınamayacak geçerli bir işaretçi olabilir . Her iki durumda da, onu aramak tamamen geçerlidir free().

Örneğin bir döngüde çağrıldığı ve sıfır olabileceği malloc(0)durumlar dışında, pek bir faydası olduğunu sanmıyorum .malloc(n)n

Bağlantıdaki koda baktığımda yazarın iki yanılgısı olduğuna inanıyorum:

  • malloc(0)her zaman geçerli bir işaretçi döndürür ve
  • free(0) kötüdür.

Bu yüzden, bunun artistve diğer değişkenlerin her zaman içlerinde bazı "geçerli" değerlere sahip olduğundan emin oldu. Yorum kadar diyor: // these must always point at malloc'd data.


10
Uygulamaya bağlı olması onu az ya da çok işe yaramaz hale getirir - bu C standardının daha berbat parçalarından biridir ve standart komitelerinin pek çoğu (örneğin PJ Plauger) bu konuda inledi.

10
Katılıyorum. Eğer malloc(0)geçerli bir işaretçi döndürdü sonra malloc()dönen NULLher zaman "başarısızlık" anlamına gelir ve 0daha tutarlı olan artık özel bir durum değildir.
Alok Singhal

1
mallocBelleği elde etmedeki başarısızlık durumları uygulama tanımlı olduğundan, bir uygulama basitçe boyut-0 tahsislerinin her zaman tatmin edici olmadığını ( ENOMEM) ve şimdi malloc(0)0 (ile errno==ENOMEM) döndürmenin tutarlı olduğunu tanımlayabilir . :-)
R .. GitHub BUZA YARDIM ETMEYİ DURDUR

6
Geri reallocdönen bir işaretçi yapabilir misin malloc(0)? Yapabilir misin realloc((char*)NULL)?
Braden Best

3
@Braden Best Evet ikisine de.
chux

11

malloc (0) davranışı uygulamaya özeldir. Kitaplık, bellek ayrılmadan NULL döndürebilir veya normal malloc davranışına sahip olabilir. Ne yaparsa yapsın, bir yerde belgelenmelidir.

Genellikle, geçerli ve benzersiz olan, ancak başvurulmaması gereken bir işaretçi döndürür. Ayrıca, aslında herhangi bir şey ayırmamış olsa bile belleği tüketebileceğini unutmayın.

Boş olmayan bir malloc (0) işaretçisini yeniden tahsis etmek mümkündür.

Bir malloc (0) kelimesine sahip olmak pek işe yaramaz. Çoğunlukla dinamik ayırma sıfır bayt olduğunda ve onu doğrulamak istemediğinizde kullanılır.


9
malloc()bir yerde "temizlik bilgisi" tutmalıdır (örneğin, tahsis edilen bloğun bu boyutu ve diğer yardımcı veriler). Dolayısıyla, malloc(0)geri dönmezse NULL, bu bilgiyi depolamak için belleği kullanacak ve değilse free(), bir bellek sızıntısı oluşturacaktır.
Alok Singhal

Malloc uygulamaları, istenen boyutun üzerine döndürülen işaretçi başına belirli miktarda veri ekleyebilen kayıt tutma gerçekleştirir.
user7116

1
Tüketilen bellek ve ayrılan bellek aynı anlama gelmez. Bu durumda, çoğu uygulama benzersiz bir işaretçi döndürecektir. Bu, söz konusu işaretçi için adres alanının bir kısmının feda edilmesi gerektiği anlamına gelir. Ayırıcıya bağlı olarak, bu aslında 1 bayt veya daha fazlasını ayıracağı anlamına gelebilir.
Coincoin

1
Kütüphane istediği her şeyi yapabilir - başka hiç kimsenin geri dönmeyeceği benzersiz bir işaretçi malloc()döndürebilir veya geri dönmeyecektir NULL.
Alok Singhal

1
@jldupont: En azından Microsoft C Run-Time kitaplığı için benzersiz bir işaretçi döndürür malloc(0). Bununla birlikte, standart C kitaplığının aynı uygulamasında, realloc(ptr, 0)boşa çıkar ptrve NULL döndürür.
Medinoc

5

Bu sayfanın başka bir yerinde "malloc (0) geçerli bir bellek adresi döndürecek ve aralığı bellek ayrılan göstericinin türüne bağlı olacak" şeklinde başlayan bir yanıt var. Bu ifade yanlıştır (bu yanıta doğrudan yorum yapacak kadar itibarım yok, bu yüzden bu yorumu doğrudan oraya koyamam).

Malloc (0) Doing olacak değil otomatik olarak doğru boyutta bellek ayrılamadı. Malloc işlevi sonucunu neye çevirdiğinizden habersizdir. Malloc işlevi, tamamen argüman olarak verdiğiniz boyut numarasına dayanır. Örneğin 0 değil, bir int tutmak için yeterli depolama alanı elde etmek için malloc (sizeof (int)) yapmanız gerekir.


4

malloc(0)Kod, uygulamaya özgü davranışa dayanmadığı sürece bana mantıklı gelmiyor. Kodun taşınabilir olması amaçlanıyorsa, bu durumda NULL dönüşünün malloc(0)bir başarısızlık olmadığı gerçeğini hesaba katmalıdır . Öyleyse neden artistyine de NULL atamıyorsunuz, çünkü bu geçerli ve başarılı bir sonuçtur ve daha az koddur ve bakım programcılarınızın bunu çözmek için zaman harcamasına neden olmaz?

malloc(SOME_CONSTANT_THAT_MIGHT_BE_ZERO)veya malloc(some_variable_which_might_be_zero)belki de bunların kullanımları olabilir, ancak yine de, değer 0 ise, ancak 0 boyutunun uygun olduğu varsayılırsa, NULL dönüşünü başarısız olarak değerlendirmemeye özen göstermelisiniz.


3

Burada pek çok yarı doğru cevap var, işte zor gerçekler. Man-sayfası malloc()diyor ki:

Boyut 0 ise malloc (), NULL veya daha sonra free () öğesine başarıyla geçirilebilecek benzersiz bir işaretçi değeri döndürür.

Bu, sonucunun malloc(0)benzersiz veya NULL olmadığına dair kesinlikle hiçbir garanti olmadığı anlamına gelir . Tek garanti tanımı free(), yine man sayfasının söylediği şudur:

Ptr NULL ise, hiçbir işlem gerçekleştirilmez.

Böylece, malloc(0)geri dönüşü ne olursa olsun , güvenle aktarılabilir free(). Ama bir NULLişaretçi de olabilir .

Sonuç olarak, yazmak artist = malloc(0); hiçbir şekilde yazmaktan daha iyi değildir artist = NULL;


1
Uygulamanın boş olmayan, benzersiz olmayan bir işaretçi döndürmesine izin verilmemesi çok kötü. Bu şekilde, malloc(0)örneğin 0x1 döndürebilir ve free()0x0 için olduğu gibi özel durum denetimi 0x1 olabilir.
Todd Lehman

3
@Todd Lehman Bir uygulama önerdiğiniz gibi yapabilir. C belirtimi, sonucun " NULLveya benzersiz bir işaretçi" olması gerektiğini belirtmez . bunun yerine 'bir boş gösterici veya tahsis edilen alana bir işaretçi ". Benzersiz bir gereksinim yoktur . OTOH, benzersiz olmayan bir özel değer döndürmek, benzersiz değerlere dayanan kodu bozabilir. SO için bir köşe durumu sorusu olabilir.
chux - Reinstate Monica

man* nix'te kullanılan uygulama tanımlı formu da belgeleyebilir. Bu durumda olmaz, ancak yine de genel C için kanonik bir kaynak değildir.
Lundin

@Lundin True. Ancak kılavuz sayfaları C standardından çok daha erişilebilirdir ve GNU / Linux sistemlerindeki kılavuz sayfaları genellikle uygulamanın hangi standart (lar) ı izlediğini oldukça iyi belgelemektedir. Hangi parçaların hangi standarda uygun olduğu bilgisinin yanı sıra, farklı olmaları gerekir.
İkisinin

3

Neden bunu yapmamalısın ...

Malloc'un dönüş değeri uygulamaya bağlı olduğundan, bir NULL gösterici veya başka bir adres geri alabilirsiniz. Bu, hata işleme kodu hem boyutu hem de döndürülen değeri kontrol etmezse, kararlılık sorunlarına (çökmelere) veya daha da kötü güvenlik sorunlarına yol açarsa, yığın arabellek taşmaları oluşturabilir.

Döndürülen adres aracılığıyla belleğe daha fazla erişmenin, yığın boyutunun sıfır olduğu ve uygulamanın NULL olmayan bir değeri geri döndürdüğü durumlarda, bu örneği düşünün.

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 */
}

Daha fazla okumak için yukarıdaki örneği aldığım CERT Kodlama Standartları'ndaki bu Güvenli Kodlama sayfasına bakın .



2

Kuşkusuz, bunu daha önce hiç görmedim, bu sözdizimini ilk kez görüyorum, diyebiliriz ki, klasik bir aşırı işlev durumu. Reed'in cevabıyla bağlantılı olarak, aşırı yüklenmiş bir işlev gibi görünen benzer bir şey olduğunu belirtmek isterim realloc:

  • foo NULL değildir ve boyut sıfırdır realloc(foo, size);. NULL olmayan bir işaretçiyi ve yeniden tahsis etmek için sıfır boyutunu ilettiğinizde, realloc, ücretsiz (…) çağırmışsınız gibi davranır.
  • foo NULL'dur ve boyut sıfır değildir ve 1'den büyüktür realloc(foo, size);. NULL işaretçisi ilettiğinizde ve boyut sıfır değilse, realloc, malloc (…) çağırmışsınız gibi davranır.

Umarım bu yardımcı olur, Saygılarımızla, Tom.


1

Yapılan soruyu gerçekten cevaplamak için: bunu yapmak için bir neden yok


0

malloc (0), NULL veya doğru bir şekilde serbest bırakılabilen geçerli bir işaretçi döndürecektir. Ve işaret ettiği bellek işe yaramaz gibi görünse de ya da yazılamaz ya da okunamaz gibi görünse de, bu her zaman doğru değildir. :)

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

Burada bir segmentasyon hatası bekliyoruz, ancak şaşırtıcı bir şekilde bu 100 yazdırıyor! Çünkü malloc, ilk defa malloc dediğimizde büyük bir bellek parçası istiyor. Bundan sonra malloc'a yapılan her çağrı, o büyük parçadaki hafızayı kullanır. Ancak bu büyük parça bittikten sonra yeni hafıza istenir.

Malloc (0) kullanımı: sonraki malloc çağrılarının daha hızlı olmasını istediğiniz bir durumdaysanız, malloc (0) araması sizin için yapmalıdır (uç durumlar hariç).


1
'E yazmak *isizin durumunuzda çökmeyebilir, ancak yine de tanımlanmamış bir davranıştır. Nazal iblislere dikkat edin!
John Dvorak

1
Evet. Bu doğru. Uygulamaya özeldir. Bunu MaxOS X ve bazı Linux dağıtımlarında doğruladım. Diğer platformlarda denemedim. Bunu söyledikten sonra, anlattığım kavram Brain Kernighan ve Dennis Ritchie tarafından yazılan "C programlama dili" kitabında anlatılmıştır.
Sagar Bhosale

Biliyorum: bu soruya çok geç yorum. Ancak bazenmalloc(0) bunun bahsedilmeyen bir kullanımı vardır . NULL olmayan bir değer döndürdüğü uygulamalarda, özellikle de bir DEBUG yapısında, muhtemelen sizin istediğinizden DAHA FAZLASINI ayırır ve size dahili başlığını geçmeniz için işaretçi verir. Bu, bir dizi ayırmadan önce ve sonra bunu alırsanız, gerçek bellek kullanımı hakkında bir fikir edinmenizi sağlar . örneğin: void* before = malloc(0); ... void* after = malloc(0); long long total = after - before;veya benzeri.
Jesse Chisholm

Brain Kernighan ve Dennis Ritchie'nin yazdığı "C programlama dili" ni okudum ve hakkında hiçbir şey söylediğini hatırlamıyorum malloc(0). Lütfen hangi bölümden bahsettiğinizi söyler misiniz? Kesin bir alıntı yapmak da güzel olurdu.
Андрей Беньковский

0

Windows'ta:

  • void *p = malloc(0);yerel yığın üzerinde sıfır uzunluklu bir arabellek ayıracaktır. Döndürülen işaretçi geçerli bir yığın göstericidir.
  • mallocsonuçta HeapAllocvarsayılan C çalışma zamanı yığınını kullanarak çağırır ve bu da çağrılar RtlAllocateHeapvb.
  • free(p);HeapFreeYığın üzerindeki 0 uzunluklu arabelleği boşaltmak için kullanır . Serbest bırakmamak bellek sızıntısına neden olur.

0

Aslında oldukça kullanışlıdır ve (tabii ki IMHO), bir NULL gösterici döndürmek için izin verilen davranış bozuktur. Dinamik bir işaretçi yalnızca işaret ettiği şey için değil, aynı zamanda adresinin benzersiz olduğu gerçeği için de yararlıdır. NULL döndürmek, bu ikinci özelliği kaldırır. Gömülü malloc programlarının tümü (aslında oldukça sık) bu davranışa sahiptir.



-2

İşte valgrind bellek kontrol aracı ile çalıştırdıktan sonraki analiz.

==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

ve işte örnek kodum:

#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;

}

Varsayılan olarak 1024 bayt ayrılmıştır. Malloc'un boyutunu artırırsam, ayrılan baytlar 1025 kadar artacaktır.


-3

Göre Reed Copsey cevap ve malloc'un adam sayfasında, ben testine bazı örnekler yazdı. Ve malloc (0) 'un ona her zaman benzersiz bir değer vereceğini öğrendim. Örneğime bakın:

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

Çıktı "Geçerli bir göstericiye sahip" olacaktır, bunun anlamı ptrboş değildir.


-6

malloc(0)geçerli bir bellek adresi döndürecektir ve aralığı bellek ayrılan göstericinin türüne bağlı olacaktır. Ayrıca bellek alanına değerler atayabilirsiniz, ancak bu, kullanılan işaretçi tipine göre olmalıdır. Ayrılan belleği de boşaltabilirsiniz. Bunu bir örnekle açıklayacağım:

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

Yukarıdaki kod gcc, Linux makinesindeki bir derleyicide düzgün çalışacaktır . 32 bitlik bir derleyiciniz varsa tamsayı aralığında değerler sağlayabilirsiniz, yani -2147483648 ila 2147483647. Aynı şey karakterler için de geçerlidir. Belirtilen işaretçi türü değiştirilirse, değer aralığının mallocyazım türünden bağımsız olarak değişeceğini lütfen unutmayın.

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

p işaretsiz bir tamsayı olarak bildirildiğinden, 0 ile 255 karakter arasında bir değer alır.


5
Krellan bu cevabın yanlış olduğuna işaret etmekte haklı: malloc()oyuncu kadrosu hakkında hiçbir şey bilmiyor (aslında C'de tamamen gereksizdir). Dönüş değerinin referansının kaldırılması, malloc(0)tanımsız davranışı çağırır.
cmaster - reinstate monica

-6

Sadece burada yanlış bir izlenimi düzeltmek için:

artist = (char *) malloc(0);asla geri dönmeyecek NULL; ile aynı değil artist = NULL;. Basit bir program yazın ve karşılaştırmak artistile NULL. if (artist == NULL)yanlış ve if (artist)doğrudur.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.