Doing arasındaki fark nedir:
ptr = (char **) malloc (MAXELEMS * sizeof(char *));
veya:
ptr = (char **) calloc (MAXELEMS, sizeof(char*));
Malloc üzerinde calloc kullanmak ne zaman iyi bir fikirdir?
ptr = calloc(MAXELEMS, sizeof(*ptr));
Doing arasındaki fark nedir:
ptr = (char **) malloc (MAXELEMS * sizeof(char *));
veya:
ptr = (char **) calloc (MAXELEMS, sizeof(char*));
Malloc üzerinde calloc kullanmak ne zaman iyi bir fikirdir?
ptr = calloc(MAXELEMS, sizeof(*ptr));
Yanıtlar:
calloc()
sıfır sıfırlanmış bir tampon verirken malloc()
belleği başlatılmaz.
Büyük ayırmalar için, calloc
genel işletim sistemleri altındaki uygulamaların çoğu işletim sisteminden bilinen sıfırlanmış sayfalar alır (örneğin POSIX mmap(MAP_ANONYMOUS)
veya Windows aracılığıyla VirtualAlloc
), böylece bunları kullanıcı alanına yazmanıza gerek kalmaz. Bu normalden malloc
işletim sisteminden daha fazla sayfa alır; calloc
sadece işletim sisteminin garantisinden yararlanır.
Bu, calloc
belleğin yine de "temiz" ve tembel olarak tahsis edilebileceği ve yazma sırasında kopyalamanın sistem genelinde paylaşılan bir fiziksel sıfır sayfasına eşleştirilebileceği anlamına gelir . (Sanal belleğe sahip bir sistem olduğunu varsayarsak.)
Bazı derleyiciler malloc + memset'i (0) sizin için calloc olarak optimize edebilir, ancak belleğin olarak okunmasını istiyorsanız calloc'u açıkça kullanmalısınız 0
.
Belleği yazmadan önce okumayacaksanız malloc
, işletim sisteminden yeni sayfalar almak yerine (muhtemelen) size dahili boş listesinden kirli bellek verebilmesi için kullanın. (Veya küçük bir tahsis için serbest listede bir bellek bloğunu sıfırlamak yerine).
Katıştırılmış uygulamaları, işletim sistemi yoksa kendisini sıfır belleğe calloc
bırakabilir calloc
veya işlemler arasında bilgi sızıntılarını durdurmak için sayfaları sıfırlayan süslü bir çok kullanıcılı işletim sistemi değildir.
Gömülü Linux'ta, mmap(MAP_UNINITIALIZED|MAP_ANONYMOUS)
çok kullanıcılı bir sistemde güvensiz olduğu için yalnızca bazı gömülü çekirdekler için etkinleştirilen malloc olabilir .
calloc
işletim sistemi hızlandırmak için bazı hileler yapabildiğinden, mutlaka daha pahalı değildir. FreeBSD'nin boş bir CPU zamanı aldığında, sadece etrafta dolaşan ve ayrılmış bellek bloklarını sıfırlayan basit bir işlemi çalıştırmak için kullandığını ve blokları bir bayrakla işaretlediğini biliyorum. Yani bunu yaptığınızda calloc
, önce bu gibi önceden sıfırlanmış bloklardan birini bulmaya çalışır ve sadece size verir - ve büyük olasılıkla bir tane bulur.
Daha az bilinen bir fark, Linux gibi iyimser bellek tahsisine sahip işletim sistemlerinde, döndürülen işaretçinin malloc
program gerçekten dokunana kadar gerçek bellek tarafından desteklenmemesidir.
calloc
gerçekten belleğe dokunuyor (üzerine sıfırlar yazıyor) ve böylece işletim sisteminin tahsisi gerçek RAM (veya takas) ile desteklediğinden emin olacaksınız. Bu yüzden malloc'dan daha yavaştır (sadece sıfırlamakla kalmaz, işletim sistemi de diğer işlemleri değiştirerek uygun bir bellek alanı bulmalıdır)
Malloc'un davranışı hakkında daha fazla tartışma için bu SO sorusuna bakınız.
calloc
sıfır yazmanıza gerek yok. Tahsis edilen blok çoğunlukla işletim sistemi tarafından sağlanan yeni sıfır sayfadan oluşuyorsa, bu sayfalara dokunulmaz. Bu, elbette, calloc
genel bir kütüphane işlevi yerine işletim sistemine ayarlanmalıdır malloc
. Ya da bir uygulayıcı, calloc
sıfırlamadan önce her bir kelimeyi sıfıra karşı kıyaslayabilir. Bu hiçbir zaman kazandırmaz, ancak yeni sayfaların kirlenmesini önler.
dlmalloc
benzeri uygulamalar , yeni anonim sayfalar (veya eşdeğeri) kullanılarak memset
yığının elde edilip edilmediğini atlar mmap
. Genellikle bu tür tahsis 256k ya da daha büyük büyük parçalar için kullanılır. Kendi başıma sıfır yazmadan önce sıfıra karşı karşılaştırma yapan herhangi bir uygulama bilmiyorum.
omalloc
ayrıca atlar memset
; calloc
uygulama tarafından kullanılmayan sayfalara (sayfa önbelleği) dokunmak gerekmez. Yine de, son derece ilkel calloc
uygulamalar farklıdır.
Sıklıkla gözden kaçan bir avantaj, calloc
(uygun uygulamaların) sizi tamsayı taşması güvenlik açıklarına karşı korumaya yardımcı olmasıdır. Karşılaştırmak:
size_t count = get_int32(file);
struct foo *bar = malloc(count * sizeof *bar);
vs.
size_t count = get_int32(file);
struct foo *bar = calloc(count, sizeof *bar);
Birincisi, küçük bir ayırmaya ve daha sonra count
daha büyük bir arabellek taşmasına neden olabilir.SIZE_MAX/sizeof *bar
. İkincisi, bu durumda büyük bir nesne oluşturulamadığı için otomatik olarak başarısız olur.
Tabii ki, taşma olasılığını görmezden gelen uygun olmayan uygulamalar için uyanık olmanız gerekebilir ... Bu, hedeflediğiniz platformlar için bir endişe ise, taşma için yine de manuel bir test yapmanız gerekecektir.
char
bir değil bir içerisine sonucu geri atama bir taşma daha ziyade bir uygulama tanımlı dönüşüm char
nesne.
size_t
64-bit ise sorun değil" ise, bu güvenlik hatalarına yol açacak kusursuz bir düşünce biçimidir. size_t
boyutlarını temsil eder ve 32 bit numarası ve bir keyfi ürünü düşünmek için hiçbir neden yok soyut bir türüdür size_t
(not: sizeof *bar
prensipte 64-bit C uygulanmasına ilişkin 2'den büyük ^ 32 olabilir!) içinde uyuyor size_t
.
Belgeler, calloc'u belleği sıfırla başlatan malloc gibi görünür; bu birincil fark değil! Calloc fikri bellek tahsisi için yazma üzerine kopyalama semantiğini kullanmaktır. Calloc ile bellek ayırdığınızda, hepsi sıfıra başlatılan aynı fiziksel sayfaya eşlenir. Ayrılan belleğin sayfalarından herhangi biri fiziksel bir sayfaya yazıldığında ayrılır. Bu genellikle BÜYÜK karma tabloları yapmak için kullanılır, örneğin karma boş bölümleri fazladan bellek (sayfalar) tarafından desteklenmediğinden; bunlar mutlu bir şekilde sıfırdan başlatılmış tek bir sayfaya işaret ederler, bunlar süreçler arasında bile paylaşılabilir.
Sanal adrese herhangi bir yazma bir sayfaya eşlenir, bu sayfa sıfır sayfaysa, başka bir fiziksel sayfa tahsis edilir, sıfır sayfa buraya kopyalanır ve kontrol akışı istemci işlemine döndürülür. Bu bellek eşleme dosyaları aynı şekilde çalışır, sanal bellek, vb çalışır .. çağrı kullanır.
İşte konu hakkında bir optimizasyon hikayesi: http://blogs.fau.de/hager/2007/05/08/benchmarking-fun-with-calloc-and-zero-pages/
Ayrılan bellek bloğunun boyutu arasında fark yoktur. calloc
bellek bloğunu tamamen sıfır bitlik fiziksel bir desenle doldurur. Pratikte, tahsis edilen bellek bloğunda bulunan nesnelerin calloc
değişmez değerle başlatılır gibi başlangıç değerine sahip olduğu 0
, yani tamsayıların 0
kayan noktalı değişkenlerin - değerinin 0.0
, işaretçilerin - uygun boş-işaretçi değerine sahip olması gerektiği varsayılır. , ve bunun gibi.
Bilgiçliksel bakış açısından, calloc
(ve aynı zamanda memset(..., 0, ...)
) sadece tip nesnelerini (sıfırlarla) doğru şekilde başlatması garanti edilir unsigned char
. Diğer her şeyin doğru şekilde başlatıldığı garanti edilmez ve tanımlanmamış davranışa neden olan tuzak gösterimi içerebilir . Başka bir deyişle, unsigned char
yukarıda belirtilen tüm sıfır-bitli patterm dışında herhangi bir tür geçersiz bir değeri, tuzak temsilini temsil edebilir.
Daha sonra, Teknik Düzeltme-C99 standardından birinde, davranış tüm tamsayı türleri için tanımlanmıştır (bu anlamlıdır). Yani resmi olarak, mevcut C dilinde yalnızca calloc
(ve memset(..., 0, ...)
) ile tamsayı türlerini başlatabilirsiniz . Genel durumda başka bir şey başlatmak için kullanılması, C dili açısından tanımlanmamış davranışa yol açar.
Pratikte, calloc
hepimizin bildiği gibi çalışır :), ancak (yukarıdakileri göz önünde bulundurarak) kullanmak isteyip istemediğiniz size bağlıdır. Şahsen bundan tamamen kaçınmayı tercih ediyorummalloc
onun yerine ve kendi başlatmamı .
Son olarak, bir diğer önemli ayrıntı, calloc
son blok boyutunu dahili olarak hesaplamak için eleman boyutunu eleman sayısıyla çarparak yapılmasıdır. Bunu yaparken, calloc
olası aritmetik taşmaya dikkat etmelisiniz. İstenen blok boyutu doğru bir şekilde hesaplanamazsa, ayırma başarısız olur (boş gösterici). Bu arada, malloc
sürümünüz taşma izlemeye çalışmaz. Taşma durumunda bir miktar "öngörülemeyen" bellek ayıracaktır.
memset(p, v, n * sizeof type);
bir sorun n * sizeof type
yaratıyor çünkü taşma olabilir. Sanırım for(i=0;i<n;i++) p[i]=v;
sağlam kod için bir döngü kullanmam gerekecek .
n
bir eleman boyutuna sahip olduğu elemanları bulunmaktadır sizeof type
, o zaman n*sizeof type
taşması nedeniyle herhangi bir nesnenin en büyük boyutu daha az olmalıdır olabilir SIZE_MAX
.
SIZE_MAX
, ancak burada diziler yok. İşaretçiden döndürülen işaretçi calloc()
, aşılmamış bellek miktarını aşıyor olabilir SIZE_MAX
. Birçok uygulamalar için 2 args ürünü sınırladık calloc()
için SIZE_MAX
henüz C talent sınırlama getirmez.
Bir makaleden calloc ile eğlenceli Benchmarking () ve sıfır sayfalarda üzerine Georg Hager Blogu
Calloc () kullanarak bellek ayırırken, istenen bellek miktarı hemen ayrılmaz. Bunun yerine, bellek bloğuna ait tüm sayfalar, bazı MMU sihirleriyle tüm sıfırları içeren tek bir sayfaya bağlanır (aşağıdaki bağlantılar). Bu tür sayfalar yalnızca okunursa (karşılaştırmanın orijinal sürümündeki b, c ve d dizileri için geçerliyse) veriler, elbette önbelleğe uyan tek sıfır sayfasından sağlanır. Belleğe bağlı döngü çekirdekleri için çok fazla. Bir sayfa yazılırsa (nasıl olursa olsun) bir hata oluşursa, “gerçek” sayfa eşlenir ve sıfır sayfa belleğe kopyalanır. Buna yazma üzerine kopyalama, iyi bilinen bir optimizasyon yaklaşımı denir (hatta C ++ derslerimde birçok kez öğrettim). Daha sonra,
calloc
genellikle malloc+memset
0
Özellikle aşağıdaki malloc+memset
gibi bir şey yaparken açıkça kullanmak genellikle biraz daha iyidir :
ptr=malloc(sizeof(Item));
memset(ptr, 0, sizeof(Item));
Bu daha iyidir çünkü sizeof(Item)
derleyici tarafından derleme zamanında bilinir ve derleyici çoğu durumda sıfır bellek için mümkün olan en iyi talimatlarla değiştirir. Öte yandan memset
, gerçekleşiyorsa calloc
, tahsisin parametre boyutu calloc
kodda derlenmez ve memset
genellikle genellikle çağrılır, uzun sınıra kadar bayt-bayt dolgusu yapmak için kod içerecek şekilde doldurulur. sizeof(long)
parçalar halinde bellek ve son olarak kalan boşluğu bayt-byte doldurur. Ayırıcı, bazılarını çağıracak kadar akıllı olsa bile aligned_memset
, hala genel bir döngü olacaktır.
Dikkate değer bir istisna, çok büyük bir bellek yığınının (bazı power_of_two kilobayt) malloc / calloc işlemini gerçekleştirmenizdir, bu durumda tahsis doğrudan çekirdekten yapılabilir. İşletim sistemi çekirdekleri genellikle güvenlik nedeniyle verdikleri tüm belleği sıfırlayacağından, yeterince akıllı calloc ek sıfırlama ile geri döndürebilir. Yine - sadece küçük olduğunu bildiğiniz bir şeyi ayırıyorsanız, malloc + memset performans açısından daha iyi olabilirsiniz.
calloc()
yavaş yapan ikinci bir nokta daha vardır malloc()
: boyut için çarpma. malloc () genellikle bir derleme zaman sabitine sahip olacakken, calloc()
genel bir çarpma ( size_t
64 bit ise çok pahalı 64 bit * 64 bit = 64 bit işlem) kullanmak gerekir.
struct foo { char a,b,c; };
. calloc
her zaman tüm bölgeyi temizleyecekseniz malloc
+ ' dan her zaman daha iyidir . boyut * öğelerinde de int taşması için dikkatli ama etkili bir denetime sahiptir. memset
malloc
calloc
Fark 1:
malloc()
genellikle bellek bloğunu tahsis eder ve bellek segmentidir.
calloc()
bellek bloğunu ayırır ve tüm bellek bloğunu 0 olarak başlatır.
Fark 2:
Eğer düşünürsek malloc()
sözdizimi, sadece 1 argüman alacak. Aşağıdaki örneği inceleyin:
data_type ptr = (cast_type *)malloc( sizeof(data_type)*no_of_blocks );
Örn: int türü için 10 blok bellek ayırmak istiyorsanız,
int *ptr = (int *) malloc(sizeof(int) * 10 );
Eğer düşünürsek calloc()
sözdizimi, bu 2 argüman alacak. Aşağıdaki örneği inceleyin:
data_type ptr = (cast_type *)calloc(no_of_blocks, (sizeof(data_type)));
Örn: int türü için 10 blok bellek ayırmak ve bunların tümünü SIFIRLA başlatmak istiyorsanız,
int *ptr = (int *) calloc(10, (sizeof(int)));
Benzerlik:
Her ikisi de malloc()
ve calloc()
döküm türü değilse varsayılan olarak geçersiz * döndürür.!
İki fark vardır.
Birincisi, argümanların sayısıdır. iki bağımsız değişkene ihtiyaç malloc()
duyarken, tek bir bağımsız değişken alır (bayt cinsinden bellek gerekir) calloc()
.
İkinci olarak, malloc()
ayrılan bellek, süre başlatılmaz calloc()
SIFIR başlatır ayrılan belleği.
calloc()
bir bellek alanı tahsis ederse, uzunluk parametrelerinin ürünü olacaktır. calloc
belleği SIFIR ile doldurur ve ilk bayta bir işaretçi döndürür. Yeterli yer bulamazsa bir NULL
işaretçi döndürür .Sözdizimi: ptr_var=(cast_type *)calloc(no_of_blocks , size_of_each_block);
ieptr_var=(type *)calloc(n,s);
malloc()
REQUSTED SIZE belleğinin tek bir bloğunu ayırır ve ilk bayta bir işaretçi döndürür. Gerekli bellek miktarını bulamazsa, boş gösterici döndürür.Kullanımı: sırasında işlevi, bayt sayısı tahsis etmektir bir bağımsız değişken almak fonksiyon elemanlarının sayısı olmak, bir, iki bağımsız değişken ve diğer bayt sayısı bu elemanların her biri için tahsis etmek için olmak. Ayrıca, ayrılmış alanı sıfırlar, ilk sırada sıfırlar .ptr_var=(cast_type *)malloc(Size_in_bytes);
malloc()
calloc()
calloc()
malloc()
calloc()
Deklare edilmediği fonksiyon <stdlib.h>
başlığının üzerinde birkaç avantajı sunmaktadır malloc()
fonksiyonu.
malloc()
ve calloc()
C standart kitaplığından dinamik bellek ayırmaya izin veren işlevlerdir, yani her ikisi de çalışma zamanı sırasında bellek ayırmaya izin verir.
Prototipleri aşağıdaki gibidir:
void *malloc( size_t n);
void *calloc( size_t n, size_t t)
Bu ikisi arasında temel olarak iki fark vardır:
Davranış: malloc()
bir bellek bloğunu başlatmadan ayırır ve bu bloktaki içeriği okumak çöp değerlerine neden olur. calloc()
Öte yandan, bir bellek bloğu tahsis eder ve sıfırlara başlatır ve bu bloğun içeriğini okumak sıfırlarla sonuçlanır.
Sözdizimi: malloc()
1 bağımsız değişken alır (ayrılacak boyut) ve calloc()
iki bağımsız değişken alır (ayrılacak blok sayısı ve her bloğun boyutu).
Her ikisinden de dönüş değeri, başarılıysa, ayrılan bellek bloğunun bir göstergesidir. Aksi takdirde, bellek ayırma hatasını belirten NULL döndürülür.
Misal:
int *arr;
// allocate memory for 10 integers with garbage values
arr = (int *)malloc(10 * sizeof(int));
// allocate memory for 10 integers and sets all of them to 0
arr = (int *)calloc(10, sizeof(int));
Aynı işlevi olarak calloc()
kullanılarak elde edilebilir malloc()
ve memset()
:
// allocate memory for 10 integers with garbage values
arr= (int *)malloc(10 * sizeof(int));
// set all of them to 0
memset(arr, 0, 10 * sizeof(int));
Not malloc()
tercihen üzerinde kullanıldığında calloc()
daha hızlı beri. Değerlerin sıfırdan başlatılması isteniyorsa calloc()
bunun yerine kullanın.
Henüz belirtilmeyen bir fark: boyut sınırı
void *malloc(size_t size)
en fazla kadarını ayırabilir SIZE_MAX
.
void *calloc(size_t nmemb, size_t size);
hakkında tahsis edebilir SIZE_MAX*SIZE_MAX
.
Bu yetenek, doğrusal adreslemeli birçok platformda sıklıkla kullanılmaz. Bu tür sistemler, sınırlama calloc()
ile nmemb * size <= SIZE_MAX
.
512 baytlık bir tür düşünün disk_sector
ve kod çok sayıda sektör kullanmak istiyor . Burada kod yalnızca SIZE_MAX/sizeof disk_sector
sektörlere kadar kullanılabilir .
size_t count = SIZE_MAX/sizeof disk_sector;
disk_sector *p = malloc(count * sizeof *p);
Daha da büyük bir ayırmaya izin veren aşağıdakileri göz önünde bulundurun.
size_t count = something_in_the_range(SIZE_MAX/sizeof disk_sector + 1, SIZE_MAX)
disk_sector *p = calloc(count, sizeof *p);
Şimdi böyle bir sistem böyle büyük bir tahsis sağlayabiliyorsa başka bir konudur. Bugün çoğu olmayacak. Yine de, SIZE_MAX
65535 iken uzun yıllar oldu. Moore yasası göz önüne alındığında , bunun yaklaşık 2030'luk SIZE_MAX == 4294967295
100 GB'lık bazı bellek modelleri ve bellek havuzları ile gerçekleşeceğinden şüpheleniliyor .
size_t
32 bitten daha büyük olmasını sağlar. Tek soru, calloc
ürünü aşan değerlerle kullanmanın , SIZE_MAX
bir işaretçiyi daha küçük bir ayırmaya döndürmek yerine sıfır elde etmeye güvenip güvenemeyeceğidir.
calloc()
aşan tahsislere izin veriyor SIZE_MAX
. Geçmişte 16 bit ile oldu size_t
ve bellek ucuzlamaya devam ettikçe, yaygın olmasa bile ilerlemesinin hiçbir nedeni göremiyorum .
SIZE_MAX
. Kesinlikle böyle bir tahsisin başarılı olabileceği herhangi bir koşul olmasını gerektirmez; Bu tür tahsisleri gerçekleştiremeyen uygulamaların geri dönmesi gerektiğini belirtmenin özel bir yararı olmadığından emin değilim NULL
(özellikle bazı uygulamaların malloc
henüz taahhüt edilmemiş ve kod gerçekten kullanmaya çalıştığında boşluğa dönüş işaretlerinin olması yaygın olduğu göz önüne alındığında) o).
size_t
için uint64_t
?
Blok sayısı:
malloc () istenen belleğin tek bloğunu atar,
calloc () istenen belleğin birden çok bloğunu atar
Başlatma:
malloc () - ayrılan belleği temizlemez ve başlatmaz.
calloc () - ayrılan belleği sıfıra başlatır.
Hız:
malloc () hızlıdır.
calloc (), malloc () 'dan daha yavaştır.
Bağımsız Değişkenler ve Sözdizimi:
malloc () 1 bağımsız değişken alır:
bayt
calloc () 2 bağımsız değişken alır:
uzunluk
void *malloc(size_t bytes);
void *calloc(size_t length, size_t bytes);
Bellek Ayırma Şekli:
malloc işlevi, kullanılabilir yığından istenen 'boyutta' bellek atar.
Calloc işlevi, 'num * boyutuna eşit olan boyutta bir bellek atar.
İsminin Anlamı:
malloc ismi "bellek ayırma" anlamına gelir.
Calloc ismi "bitişik ayırma" anlamına gelir.
malloc
ailenin sonucunu