Domanda

Ho cercato di scrivere una stringa di sostituire la funzione in C, che lavora su un char *, che è stato allocato con malloc().È un po ' diverso di trovare e sostituire le stringhe, piuttosto che i caratteri della stringa di partenza.

È banale fare se la ricerca e sostituzione di stringhe hanno la stessa lunghezza (o la stringa da sostituire è inferiore alla stringa di ricerca), dato che non ho abbastanza spazio allocato.Se si tenta di utilizzare realloc(), Ricevo un errore che mi dice che sto facendo un doppio libero - che non vedo come sto, dato che io sono solo utilizzo realloc().

Forse un po ' di codice:

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);
    }
}

Il programma funziona, fino a quando cerco di realloc() in un caso in cui la stringa sostituita sarà più la stringa iniziale.(Ancora lavori del genere, solo che sputa fuori errori così come il risultato).

Se aiuta, il codice di chiamata, assomiglia a questo:

#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");
    }
}
È stato utile?

Soluzione

Come regola generale, si dovrebbe mai gratis o realloc su un utente, a condizione che il buffer.Non so dove l'utente allocato lo spazio (in modulo, in un'altra DLL) quindi non è possibile utilizzare una qualsiasi delle funzioni di allocazione in un buffer utente.

A condizione che ora non può fare qualsiasi riallocazione all'interno di una funzione, si dovrebbe cambiare il suo comportamento un po', come quando si fa una sola sostituzione, in modo che l'utente sarà in grado di calcolare la risultante stringa di lunghezza massima e di fornire un buffer abbastanza a lungo per questa sostituzione si verifica.

Poi si potrebbe creare un'altra funzione per fare le sostituzioni multiple, ma si deve allocare tutto lo spazio per la stringa risultante e copia l'utente stringa di input.Quindi è necessario fornire un modo per eliminare la stringa è allocato.

Risultato:

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

Altri suggerimenti

Prima di tutto, scusate il ritardo per la festa.Questo è il mio primo stackoverflow risposta.:)

Come è stato sottolineato, quando realloc() viene chiamato, è potenzialmente in grado di modificare il puntatore alla memoria riallocati.Quando questo accade, l'argomento "stringa" non è più valido.Anche se si riassegnare, il cambiamento va al di fuori del campo di applicazione una volta che la funzione termina.

Per rispondere all'OP, realloc() restituisce un puntatore alla nuova riallocare la memoria.Il valore di ritorno deve essere memorizzato da qualche parte.Generalmente, in questo modo:

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);
}

Come TyBoer punti fuori, voi non potete modificare il valore del puntatore passato come input per questa funzione.È possibile assegnare quello che si vuole, ma il cambiamento sarà andare fuori del campo di applicazione al fine della funzione.Nel seguente blocco, "input" può o non può essere un puntatore non valido una volta che la funzione completa:

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 cerca di aggirare questo restituendo il nuovo puntatore come l'output della funzione.Se lo fai, è onere del chiamante per non utilizzare il puntatore del mouse ha usato per l'input.Se si confronta il valore di ritorno, poi ci sono due puntatori nello stesso punto, e solo bisogno di chiamare gratis() su uno di essi.Se non corrispondono, l'input puntatore punta ora a memoria che possono o non possono essere di proprietà del processo.La dereferenziazione potrebbe causare un errore di segmentazione.

Si potrebbe utilizzare un doppio puntatore per l'ingresso, come questo:

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

Se il chiamante è un duplicato di input puntatore da qualche parte, che duplicato potrebbe essere ancora valido oggi.

Penso che la soluzione più pulita qui è quello di evitare l'uso di realloc() quando si cerca di modificare la funzione chiamante ingresso.Solo malloc() un nuovo buffer, di ritorno che, e di consentire al chiamante di decidere se o non libera il vecchio testo.Questo ha il vantaggio di lasciare che il chiamante mantenere la stringa originale!

Un solo colpo nel buio, perché io non l'ho provato ancora, ma quando si realloc restituisce il puntatore tanto come malloc.Perché realloc possibile spostare il puntatore, se necessario, è più probabile che operano su un puntatore non valido se non fai il seguente:

input = realloc(input, strlen(input) + delta);

Qualcun altro ha chiesto scusa per essere in ritardo per la festa - due mesi e mezzo fa.Oh bene, spendere un sacco di tempo a fare il software di archeologia.

Mi interessa che nessuno ha commentato in modo esplicito sulla perdita di memoria nel disegno originale, o off-by-one di errore.E stava osservando la perdita di memoria che mi dice esattamente il motivo per cui si stanno ottenendo il doppio libero di errore (perché, per essere precisi, si sta liberando la memoria stessa più volte - e si sta facendo così dopo calpestava i già liberato la memoria).

Prima di condurre l'analisi, vado d'accordo con quelli che dicono che l'interfaccia è inferiore a stellare;tuttavia, se affrontato con la perdita di memoria/calpestando i problemi e documentato l' 'deve essere allocata memoria' obbligo, potrebbe essere "OK".

Quali sono i problemi?Beh, si passa un buffer di realloc(), e realloc() ti restituisce un nuovo puntatore all'area usa - e si ignora che il valore di ritorno.Di conseguenza, realloc (), probabilmente ha liberato la memoria originale, e poi si passa il puntatore stesso di nuovo, e si lamenta che si sta liberando la memoria stessa due volte, perché si passa il valore originale di nuovo.Questo non solo perdite di memoria, ma significa che si continua ad usare l'originale spazio -- e John Downey shot in the dark punti che sono utilizzati da realloc(), ma non sottolineare quanto seriamente si sta facendo così.C'è anche un fuori-da-un errore perché non allocare spazio sufficiente per il NUL '\0' che termina la stringa.

La perdita di memoria si verifica perché non forniscono un meccanismo per raccontare il chiamante sull'ultimo valore della stringa.Perché hai tenuto calpestava la stringa originale più lo spazio dopo di esso, sembra che il codice ha funzionato, ma se il codice chiamante liberato lo spazio, troppo sarebbe un doppio errore di connessione, o si potrebbe ottenere un core dump o equivalente, perché la memoria di informazioni di controllo è completamente criptato.

Il codice, inoltre, non proteggere contro indefinito progresso, a prendere in considerazione la sostituzione 'Noel' con 'Joyeux Noel'.Ogni volta, è possibile aggiungere 7 caratteri, ma devi trovare un altro Noel nel testo sostituito, ed espanderlo, e così via e così via.La mia correzione (sotto) non affrontare questo problema, la soluzione più semplice è probabilmente per verificare se la stringa di ricerca viene visualizzata la stringa da sostituire;un'alternativa è quella di saltare la stringa di sostituzione e di continuare la ricerca, dopo di esso.Il secondo ha qualche non banale la codifica dei problemi da affrontare.

Quindi, la mia proposta di revisione della tua chiamata funzione è:

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);
}

Questo codice non rileva errori di allocazione di memoria - e, probabilmente, si blocca (ma se non, perdite di memoria) se realloc() ha esito negativo.Vedi Steve Maguire 'di Scrittura Solida rubrica di Codice per una discussione approfondita di problemi di gestione della memoria.

Nota, provare a modificare il codice per sbarazzarsi di html, codici di escape.

Beh, anche se è stato un po da quando ho utilizzato il C/C++, realloc, che cresce solo riutilizza il puntatore di memoria valore, se c'è spazio in memoria dopo il blocco originale.

Per esempio, considerare questo:

(xxxxxxxxxx..........)

Se il puntatore punti per la prima x, e .significa free locazione di memoria e crescere la dimensione della memoria a cui punta la variabile da 5 byte, sarà un successo.Questo è ovviamente un esempio semplificato come blocchi arrotondati fino a una certa dimensione per l'allineamento, ma comunque.

Tuttavia, se si tenta di crescere di un ulteriore 10 byte, e c'è solo 5 disponibili, è necessario spostare il blocco in memoria e aggiorna il puntatore del mouse.

Tuttavia, nel tuo esempio si passa alla funzione un puntatore a carattere, non un puntatore a variabile, e così, mentre il strrep funzione internamente potrebbe essere in grado di regolare la variabile in uso, è una variabile locale per il strrep funzione e il codice chiamante verrà lasciato con l'originale puntatore del valore della variabile.

Questo valore del puntatore, tuttavia, è stato liberato.

Nel tuo caso, l'input è il colpevole.

Tuttavia, vorrei fare un'altra proposta.Nel tuo caso sembra che l' ingresso variabile è infatti di ingresso, e se lo è, non deve essere modificata, a tutti.

Vorrei quindi provare a trovare un altro modo per fare quello che si vuole fare, senza cambiare ingresso, come effetti collaterali come questo può essere difficile da rintracciare.

Questo sembra funzionare;

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

Sospiro, c'è comunque di postare il codice senza succhiare?

realloc è strano, complicato e dovrebbe essere utilizzato solo quando ha a che fare con un sacco di memoria un sacco di volte al secondo.cioè- dove in realtà rende il codice più veloce.

Ho visto il codice di cui

realloc(bytes, smallerSize);

è stato utilizzato e lavorato per ridimensionare il buffer, rendendo più piccoli.Ha lavorato circa un milione di volte, poi per qualche motivo realloc deciso che, anche se si stavano accorciando il buffer, si darebbe una bella copia.Così si crash in un posto a caso 1/2 secondo dopo la brutta roba successo.

Utilizzare sempre il valore di ritorno di realloc.

Rapidi accenni.

Invece di:
void strrep(char *input, char *search, char *replace)
provare:
void strrep(char *&input, char *search, char *replace)

e che nel corpo:
input = realloc(input, strlen(input) + delta);

Generalmente leggere sul passaggio di argomenti della funzione come valori di riferimento e realloc() descrizione :).

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top