İlk başta daha sonra olduğundan daha korkunç görünen her şeyde olduğu gibi, ilk korkuyu aşmanın en iyi yolu kendinizi bilinmeyenin rahatsızlığına kaptırmaktır ! Ne de olsa bazen en çok öğrendiğimiz şeydir.
Maalesef sınırlamalar var. Hâlâ bir işlevi kullanmayı öğrenirken, örneğin bir öğretmen rolünü üstlenmemelisiniz. Görünüşe göre nasıl kullanılacağını bilmeyenlerin realloc
(yani şu anda kabul edilen cevap! ) Başkalarına yanlış bir şekilde nasıl kullanacaklarını söyleyen cevaplarını sık sık okurum, bu yaygın bir tuzak olmasına rağmen, bazen hata işlemeyi ihmal ettikleri kisvesi altında. bahsetmesi gereken. İşte nasıl kullanılacağını açıklayan bir cevap değil realloc
doğru . Hata kontrolü yapmak için cevabın dönüş değerini farklı bir değişkene kaydettiğine dikkat edin .
Bir işlevi her çağırdığınızda ve bir diziyi her kullandığınızda, bir işaretçi kullanırsınız. Dönüşümler örtük olarak gerçekleşiyor, bu da daha da korkutucu olmalı, çünkü genellikle en çok soruna neden olan, görmediğimiz şeylerdir. Örneğin bellek sızıntıları ...
Dizi operatörleri işaretçi operatörleridir. array[x]
gerçekten bir kısayol *(array + x)
olup, şu şekilde ayrılabilir: *
ve (array + x)
. Büyük ihtimalle *
kafanızı karıştıran şey budur. Biz ayrıca varsayarak problemden eklenmesini ortadan kaldırabilir x
olmak 0
, böylece array[0]
olur *array
ekleyerek çünkü 0
değerini değiştirmeyecektir ...
... ve böylece bunun *array
eşdeğer olduğunu görebiliriz array[0]
. Birini kullanmak istediğiniz yerde kullanabilirsiniz ve bunun tersi de geçerlidir. Dizi operatörleri işaretçi operatörleridir.
malloc
, realloc
Ve arkadaşlar yok icat Eğer baştan beri kullanıyorum bir işaretçi kavramını; bunu yalnızca , boyutta şiddetli, dinamik değişiklikler istediğinizde en uygun olan, farklı bir depolama süresi biçimi olan başka bir özelliği uygulamak için kullanırlar .
Şu anda kabul edilen cevap bu utanç verici , aynı zamanda bir ters geliyor StackOverflow'daki diğer bazı çok sağlam temellere dayanan tavsiye ve aynı zamanda, tam da bu USECASE parlar az bilinen bir özelliği tanıtmak için bir fırsat kaçırır: Esnek dizi üyeler! Bu aslında oldukça bozuk bir cevap ... :(
Dizinizi tanımladığınızda, üst sınır olmadan yapının sonundastruct
dizinizi bildirin. Örneğin:
struct int_list {
size_t size;
int value[];
};
Bu, dizinizi kendinizle int
aynı ayırmada birleştirmenize olanak tanır count
ve bunların bu şekilde bağlanması çok kullanışlı olabilir !
sizeof (struct int_list)
value
0 boyutuna sahipmiş gibi davranacak , bu yüzden size yapının boyutunu boş bir liste ile söyleyecektir . realloc
Listenizin boyutunu belirtmek için geçilen boyutu yine de eklemeniz gerekir .
Başka bir kullanışlı ipucu da realloc(NULL, x)
bunun eşdeğer olduğunu hatırlamaktır malloc(x)
ve bunu kodumuzu basitleştirmek için kullanabiliriz. Örneğin:
int push_back(struct int_list **fubar, int value) {
size_t x = *fubar ? fubar[0]->size : 0
, y = x + 1;
if ((x & y) == 0) {
void *temp = realloc(*fubar, sizeof **fubar
+ (x + y) * sizeof fubar[0]->value[0]);
if (!temp) { return 1; }
*fubar = temp; // or, if you like, `fubar[0] = temp;`
}
fubar[0]->value[x] = value;
fubar[0]->size = y;
return 0;
}
struct int_list *array = NULL;
struct int_list **
İlk argüman olarak kullanmayı seçmemin nedeni hemen açık görünmeyebilir, ancak ikinci argümanı düşünürseniz value
, içeriden yapılan herhangi bir değişiklik, push_back
çağırdığımız fonksiyon tarafından görünmez, değil mi? Aynısı ilk argüman için de geçerli ve bizim array
sadece burada değil, aynı zamanda muhtemelen onu aktardığımız diğer fonksiyonlarda da değiştirebilmeliyiz ...
array
hiçbir şeye işaret etmeye başlar; bu boş bir listedir. İlklendirmek, ona eklemekle aynı şeydir. Örneğin:
struct int_list *array = NULL;
if (!push_back(&array, 42)) {
// success!
}
Not: İşinizfree(array);
bittiğinde bunu unutmayın!