Yanıtlar:
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;
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 NULL
veya 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 vefree(0)
kötüdür.Bu yüzden, bunun artist
ve 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
.
malloc(0)
geçerli bir işaretçi döndürdü sonra malloc()
dönen NULL
her zaman "başarısızlık" anlamına gelir ve 0
daha tutarlı olan artık özel bir durum değildir.
malloc
Belleğ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 . :-)
realloc
dönen bir işaretçi yapabilir misin malloc(0)
? Yapabilir misin realloc((char*)NULL)
?
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.
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.
malloc()
döndürebilir veya geri dönmeyecektir NULL
.
malloc(0)
. Bununla birlikte, standart C kitaplığının aynı uygulamasında, realloc(ptr, 0)
boşa çıkar ptr
ve NULL döndürür.
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.
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 artist
yine 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.
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 NULL
işaretçi de olabilir .
Sonuç olarak, yazmak artist = malloc(0);
hiçbir şekilde yazmaktan daha iyi değildir artist = NULL;
malloc(0)
örneğin 0x1 döndürebilir ve free()
0x0 için olduğu gibi özel durum denetimi 0x1 olabilir.
NULL
veya 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.
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.
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 .
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
:
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.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.
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ç).
*i
sizin durumunuzda çökmeyebilir, ancak yine de tanımlanmamış bir davranıştır. Nazal iblislere dikkat edin!
malloc(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.
malloc(0)
. Lütfen hangi bölümden bahsettiğinizi söyler misiniz? Kesin bir alıntı yapmak da güzel olurdu.
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.malloc
sonuçta HeapAlloc
varsayılan C çalışma zamanı yığınını kullanarak çağırır ve bu da çağrılar RtlAllocateHeap
vb.free(p);
HeapFree
Yığın üzerindeki 0 uzunluklu arabelleği boşaltmak için kullanır . Serbest bırakmamak bellek sızıntısına neden olur.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.
Emin değilim, bulduğum bazı rastgele malloc kaynak kodlarına göre , 0 girişi NULL dönüş değeriyle sonuçlanıyor. Bu nedenle, sanatçı işaretçisini NULL olarak ayarlamanın çılgın bir yolu.
http://www.raspberryginger.com/jbailey/minix/html/lib_2ansi_2malloc_8c-source.html
İş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.
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ı ptr
boş değildir.
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 malloc
yazı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.
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.
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 artist
ile NULL
. if (artist == NULL)
yanlış ve if (artist)
doğrudur.