Neden realloc ile çift serbest hatası alıyorum ()?

oy
11

Bir çalışır C, içinde yerini işlevi bir dize yazmak için denedim char *kullanarak tahsis edildiği, malloc(). O bulmak ve başlangıç dizesinde dizeleri yerine karakterleri yerini alacak o biraz farklı.

Arama ve değiştirme dizeleri aynı uzunlukta (veya değiştirin dizi arama dizesi daha kısadır) ise yeterince alanın belirtildiği, çünkü yapmak Önemsiz. Ben kullanmayı denerseniz realloc()sadece kullanıyorum çünkü ben ne kadar görmüyorum ki - ben bir çift serbest yapıyorum bana söyler bir hata alıyorum realloc().

Belki biraz kod yardımcı olacaktır:

void strrep(char *input, char *search, char *replace) {
    int searchLen = strlen(search);
    int replaceLen = strlen(replace);
    int delta = replaceLen - searchLen;
    char *find = input;

    while (find = strstr(find, search)) {

        if (delta > 0) {
            realloc(input, strlen(input) + delta);
            find = strstr(input, search);            
        }

        memmove(find + replaceLen, find + searchLen, strlen(input) - (find - input));
        memmove(find, replace, replaceLen);
    }
}

Ben deneyin kadar program çalışır realloc()yerini dize ilk dize daha uzun olacak bir durumda. (Hala tür işleri sadece sonuç olarak da bu hatalara tükürüyor).

Eğer yardımı olacaksa, arama kodu gibi görünür:

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

void strrep(char *input, char *search, char *replace);

int main(void) {
    char *input = malloc(81);

    while ((fgets(input, 81, stdin)) != NULL) {
        strrep(input, Noel, Christmas);
    }
}
Oluştur 04/08/2008 saat 12:06
kaynak kullanıcı
Diğer dillerde...                            


8 cevaplar

oy
12

Öncelikle, üzgünüm geciktim partiye değilim. Bu benim ilk stackoverflow cevaptır. :)

işaret edildiği gibi realloc () çağrıldığında, potansiyel hafızaya işaretçi tahsis edilen değiştirebilir. Bu olduğunda, argüman "dize" geçersiz hale gelir. Bunu yeniden atamak bile işlevi bittikten sonra, değişim kapsamı dışına gider.

OP cevap vermek için, realloc () yeni yeniden tahsis bellek için bir işaretçiyi geri döndürmektedir. Dönüş değeri bir yere depolanması gerekir. Genellikle, bu yapardın:

data *foo = malloc(SIZE * sizeof(data));
data *bar = realloc(foo, NEWSIZE * sizeof(data));

/* Test bar for safety before blowing away foo */
if (bar != NULL)
{
   foo = bar;
   bar = NULL;
}
else
{
   fprintf(stderr, "Crap. Memory error.\n");
   free(foo);
   exit(-1);
}

TyBoer işaret ettiği gibi, siz ibrenin değeri bu işleve girdi olarak geçirilen değiştiremezsiniz. Ne istersen atayabilirsiniz, ama değişim işlevi sonunda kapsamı dışındadır gidecek. işlev tamamladığında, aşağıdaki blokta "giriş" veya geçersiz bir işaretçi olabilir veya olmayabilir:

void foobar(char *input, int newlength)
{
   /* Here, I ignore my own advice to save space. Check your return values! */
   input = realloc(input, newlength * sizeof(char));
}

Mark fonksiyonunun çıktısı olarak yeni işaretçi döndürerek bu geçici bir çözüm çalışır. Bunu yaparsanız, külfeti daha asla o girişi için kullanılan işaretçi kullanmak arayan üzerindedir. o dönüş değeri eşleşirse, o zaman aynı noktaya iki işaretçiler ve sadece bunlardan biri üzerinde () serbest çağırmanız gerekir. Eşleşmezlerse, giriş işaretçi şimdi veya süreç ait olabilir veya olmayabilir belleğe işaret ediyor. çözümleyecek bir segment hataya neden olabilir.

Böyle girişi, bir çift işaretçi kullanabilirsiniz:

void foobar(char **input, int newlength)
{
   *input = realloc(*input, newlength * sizeof(char));
}

Arayan bir yere girdi pointer bir kopyasını varsa, artık geçersiz olabilir hala yinelenen söyledi.

Burada en temiz çözüm realloc kullanarak kaçınmaktır düşünüyorum () fonksiyonu arayanın girişini değiştirmeye çalışırken. Sadece Malloc () Yeni bir tampon, o dönmek ve arayan eski metni serbest olup olmadığına karar verelim. Bu Arayan orijinal dize tutmak icar yararı vardır!

Cevap 08/08/2008 saat 22:37
kaynak kullanıcı

oy
11

Genel bir kural olarak, gereken asla bir kullanıcı sağlanan tampon ücretsiz veya realloc yapmak. Eğer bir kullanıcı tampon üzerindeki ayırma işlevlerinin herhangi kullanamaması için kullanıcı (başka DLL, senin modülünde) yer tahsis nerede bilmiyorum.

artık işlevi içinde herhangi yeniden tahsisini yapamaz kaydıyla, yalnızca bir yedek yapıyor gibi, biraz onun davranışını değiştirmek gerekir, bu nedenle kullanıcı Sonuç dizesi, maksimum uzunluğu hesaplamak mümkün ve bunun için yeterince uzun bir tampon sağlayacaktır yedek oluşmaya.

Sonra birden değiştirmeler yapmak için başka bir işlev oluşturabilir, ancak ortaya çıkan dize bütün alanı ayırmak ve kullanıcı girişi dizesi kopyalamak gerekecektir. O zaman ayrılan dizesini silmek için bir yol sağlamalıdır.

Sonuçlanan:

void  strrep(char *input, char *search, char *replace);
char* strrepm(char *input, char *search, char *replace);
void  strrepmfree(char *input);
Cevap 04/08/2008 saat 12:19
kaynak kullanıcı

oy
6

İki buçuk ay önce - Başkası partiye geç kaldığım için özür diledi. Neyse, ben yazılım arkeolojiyi yapıyor zaman oldukça fazla harcamak.

Bence kimse özgün tasarım bellek sızıntısı veya kapalı-birer hata açıkça yorumladı ettiğini ilgileniyorum. Ve bu tam olarak neden çift serbest hatası (- ve zaten serbest bellek ezip sonra bunu yaparken, çünkü hassas olmak, aynı bellek birden çok kez azat edilir) alıyorsanız söyler bellek sızıntısı gözlemleyerek edildi.

analizlerinin yapılması önce, arayüz az yıldız söyleyenler katılıyorum edeceğiz; Eğer bellek sızıntısı / ezip konularda ele ve 'tahsis edilmelidir hafıza' şartını belgelenmiş ancak, tamamdır 'olabilir.

Sorun ne? De, bir) (Realloc tampon ve realloc geçen () size kullanmalıdır alanına yeni işaretçi döndürür - ve bu dönüş değeri yok sayar. Sonuç olarak, realloc () muhtemelen orijinal bellek serbest bıraktı ve sonra tekrar bunu aynı işaretçi geçmesi ve tekrar kendisine özgün değeri geçtikleri için iki kez aynı bellek boşaltma ediyoruz yakınıyor. Bu bellek sızdırıyor, ancak orijinal alanını kullanmaya devam anlamına gelir sadece -) Eğer realloc (suiistimal ettiğini karanlık noktalarında ve John Downey'nin atış dışarı, ancak bunu yaparken nasıl ciddi vurgulamak etmez. Eğer dize sonlandırır NUL '\ 0' için yeterli alan tahsis yok çünkü bir kapalı-birer hata da var.

Eğer dizenin son değeri hakkında arayanı anlatmak için bir mekanizma sağlamaz, çünkü bellek sızıntısı oluşur. Kod çalıştı gibi görünüyor, ancak çağıran kod alanı serbest, artık çok çift serbest hatayı alacağı, ya da bir çekirdek dökümü veya çünkü eşdeğer alabilirsiniz, orijinal dize artı ondan sonra boşluk ezip tuttu Çünkü bellek kontrol bilgisi tamamen karıştırılmaktadır.

Kodunuz da belirsiz büyüme karşı koruma sağlamaz - 'Joyeux Noel' ile 'Noel' değiştirmeyi düşünün. Her seferinde, 7 karakter eklersiniz, ancak bunu ve benzeri yerini metinde başka Noel bulmak ve genişletmek ve istiyorum. (Aşağıda) Benim düzeltme bu sorunu gidermez - basit bir çözüm arama dizesi yerine dizede gösterilip gösterilmediğini kontrol etmek muhtemelen; Alternatif yerine dize üzerinde atlamak ve peşine aramaya devam etmektir. İkinci ele almak bazı önemsiz olmayan kodlama sorunları vardır.

Yani, denilen fonksiyonun önerdiğim revizyon geçerli:

char *strrep(char *input, char *search, char *replace) {
    int searchLen = strlen(search);
    int replaceLen = strlen(replace);
    int delta = replaceLen - searchLen;
    char *find = input;

    while ((find = strstr(find, search)) != 0) {
        if (delta > 0) {
            input = realloc(input, strlen(input) + delta + 1);
            find = strstr(input, search);            
        }

        memmove(find + replaceLen, find + searchLen, strlen(input) + 1 - (find - input));
        memmove(find, replace, replaceLen);
    }

    return(input);
}

Bu kod bellek ayırma hataları algılamaz - ve muhtemelen realloc () başarısız olursa çöküyor (eğer değilse, bellek sızdırıyor). bellek yönetim sorunları geniş bir tartışma için Steve Maguire 'Yazma Katı Kod' kitabı bakınız.

Cevap 21/10/2008 saat 03:41
kaynak kullanıcı

oy
6

Sadece karanlıkta bir atış Ben henüz denemedim çünkü ancak Realloc zaman malloc'dan gibi çok işaretçi döndürür. realloc işaretçisini hareket Çünkü aşağıdakileri yapmanız yoksa büyük olasılıkla geçersiz işaretçi üzerinde faaliyet gösteriyor gerekirse:

input = realloc(input, strlen(input) + delta);
Cevap 04/08/2008 saat 12:14
kaynak kullanıcı

oy
4

html kaçış kodları kurtulmak için kodunuzu düzenlemeye çalışıyor, unutmayın.

Eh, ben C / C ++ kullanılan bu yana epey zaman, orijinal bloktan sonra hafızada yer varsa sadece bellek işaretçi değerini yeniden kullanır büyür realloc olmuştur bile.

Örneğin, bu göz önünde bulundurun:

(Xxxxxxxxxx ..........)

İlk x İşaretçinizin noktaları ve varsa. boş bellek konumunu ifade eder ve bellek boyutu 5 bayt ederek değişkeni tarafından işaret büyür, bu başarılı olacak. blok yine hizalama için belirli bir boyuta yuvarlanır ancak gibidir Bu elbette basitleştirilmiş bir örneği verilmiştir.

Ancak, sonradan başka bir 10 bayt bunu büyümeye çalışın ve sadece 5 mevcut ise, bu bellekte bloğunu taşımak ve işaretçi güncellemeniz gerekir.

Ancak, sizin örnekte size değişken karakteri değil, bir işaretçi için fonksiyonu bir işaretçi geçiyoruz ve böylece strrep fonksiyonu dahili olarak kullanımda değişkeni ayarlamak mümkün olabilir iken, bu strrep işleve bir yerel değişkendir ve Sesli arama kodu orijinal işaretçi değişken değeri ile bırakılacaktır.

Bu işaretçi değeri, ancak serbest edilmiştir.

Senin durumunda, giriş suçlu.

Ancak, ben başka bir öneri yapacak. Gibi durumda görünüyor girişi hiç de değişken aslında girdi olduğunu ve eğer, bu değiştirilmemelidir.

Ben böylece değiştirmeden, sen ne yapmak istediğinizi yapmak için başka bir yol bulmaya çalışacağını söyledi girişi böyle yan etkiler izleyerek bulmak zor olabileceğinden,.

Cevap 04/08/2008 saat 12:17
kaynak kullanıcı

oy
3

realloc, garip karmaşıktır ve saniyede kez hafıza sürü bir sürü ile uğraşırken sadece kullanılmalıdır. aslında daha hızlı kod yapar - yani.

Ben kodu nerede gördük

realloc(bytes, smallerSize);

kullanılmış ve daha küçük hale tampon yeniden boyutlandırmak için çalışmıştır. yaklaşık bir milyon kez çalıştı, sonra nedense realloc için size tampon kısaltarak olsa bile, bu size güzel bir yeni bir kopyasını verecek karar verdi. kötü şeyler oldu sonra Yani rastgele bir yerde 1/2 bir saniye çökmesine.

Her zaman realloc dönüş değerini kullanın.

Cevap 16/05/2011 saat 23:57
kaynak kullanıcı

oy
3

Bu iş gibi görünüyor;

char *strrep(char *string, const char *search, const char *replace) {
    char *p = strstr(string, search);

    if (p) {
        int occurrence = p - string;
        int stringlength = strlen(string);
        int searchlength = strlen(search);
        int replacelength = strlen(replace);

        if (replacelength > searchlength) {
            string = (char *) realloc(string, strlen(string) 
                + replacelength - searchlength + 1);
        }

        if (replacelength != searchlength) {
            memmove(string + occurrence + replacelength, 
                        string + occurrence + searchlength, 
                        stringlength - occurrence - searchlength + 1);
        }

        strncpy(string + occurrence, replace, replacelength);
    }

    return string;
}

Siir, bu emme olmadan kodu sonrası için zaten var mı?

Cevap 04/08/2008 saat 12:39
kaynak kullanıcı

oy
0

Benim hızlı ipuçları.

Yerine:
void strrep(char *input, char *search, char *replace)
deneyin:
void strrep(char *&input, char *search, char *replace)

ve vücutta daha:
input = realloc(input, strlen(input) + delta);

Genel olarak değerler / referans ve realloc () tanımı :) gibi işlev bağımsız geçen okuyun.

Cevap 04/08/2008 saat 12:20
kaynak kullanıcı

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more