Oppure

Loading
19/05/17 20:25
AldoBaldo
Non so se a qualcuno possa tornare utile questa roba, però ho messo insieme un po' di funzioni di (in)utilità per stringhe dinamiche in C. In caso valga la pena (ditemelo voi) posso aggiungerlo alla sezione "esempi" o "utilità" o chissà quale dell'elenco dei programmi di Pierotofy.

Se intendete leggere sedetevi, perché il codice è un po' lunghetto...

utilita_stringhe_dinamiche.h:

#ifndef UTILITA_STRINGHE_DINAMICHE_H_INCLUDED
#define UTILITA_STRINGHE_DINAMICHE_H_INCLUDED

/*==============================================================================
duplica_stringa()

Riceve il puntatore ad una stringa C, ne effettua una copia in un'area di
memoria dinamica appositamente allocata, restituisce il puntatore alla memoria
allocata (NULL se l'allocazione fallisce).
Spetta al chiamante liberare con libera_buffer() la memoria allocata.
==============================================================================*/

char *duplica_stringa( const char *str );


/*==============================================================================
dimensiona_stringa()

Alloca la quantita' di memoria indicata da dim (dim NON include il carattere
terminatore) e copia la stringa str nello spazio di memoria allocato. Se dim e'
minore della lunghezza corrente della stringa, la stringa viene troncata. Se dim
e' maggiore della lunghezza corrente della stringa, lo spazio eccedente viene
impostato su una serie di zeri. Restituisce il puntatore alla memoria allocata
(NULL se l'allocazione fallisce).
Spetta al chiamante liberare con libera_buffer() la memoria allocata.
==============================================================================*/

char *dimensiona_stringa( const char *str, size_t dim );


/*==============================================================================
inserisci_stringa()

Inserisce la stringa agg nella posizione pos della stringa s. Se pos eccede la
lunghezza della stringa, l'aggiunta viene effettuata in coda alla stringa
stessa. Colloca la stringa risultante in un'area di memoria dinamica
appositamente allocata e restituisce il puntatore alla memoria allocata (NULL se
l'allocazione fallisce).
Spetta al chiamante liberare con libera_buffer() la memoria allocata.
==============================================================================*/

char *inserisci_stringa( const char *str, const char *agg, size_t pos );


/*==============================================================================
inserisci_intero()

Converte in stringa il valore indicato da n, quindi lo inserisce nella posizione
pos della stringa s. Se pos eccede la lunghezza della stringa, l'aggiunta viene
effettuata in coda alla stringa stessa. Colloca la stringa risultante in un'area
di memoria dinamica appositamente allocata e restituisce il puntatore alla
memoria allocata (NULL se l'allocazione fallisce).
Spetta al chiamante liberare con libera_buffer() la memoria allocata.
==============================================================================*/

char *inserisci_intero( const char *str, int n, size_t pos );


/*==============================================================================
sostituisci_caratteri()

Sostituisce nella stringa str tutte le occorrenze dei caratteri indicati nella
stringa orig con i caratteri indicati nelle stesse posizioni nella stringa sost.
Ad esempio, sostituisci_caratteri( "Provetta", "Pt", "Bd" ) da' come esito la
stringa "Brovedda". Colloca la stringa risultante in un'area di memoria dinamica
appositamente allocata e restituisce il puntatore alla memoria allocata (NULL se
l'allocazione fallisce). Spetta al chiamante liberare con libera_buffer() la
memoria allocata.
==============================================================================*/

char *sostituisci_caratteri(
    const char *str, const char *orig, const char *sost );


/*==============================================================================
sostituisci_frammento()

Sostituisce un frammento di l caratteri della stringa s con la stringa sost, a
partire dalla posizione pos (sost puo' anche essere piu' lungo o piu' corto di l
caratteri). Colloca la stringa risultante in un'area di memoria dinamica
appositamente allocata e restituisce il puntatore alla memoria allocata (NULL se
l'allocazione fallisce).
Spetta al chiamante liberare con libera_buffer() la memoria allocata.
==============================================================================*/

char *sostituisci_frammento(
    const char *str, const char *sost, size_t pos, size_t l );


/*==============================================================================
sostituisci_frammenti()

Cerca nella stringa str le ricorrenze della stringa ptrn e le sostituisce con la
stringa sost. Colloca la stringa risultante in un'area di memoria dinamica
appositamente allocata e restituisce il puntatore alla memoria allocata (NULL se
l'allocazione fallisce).
Spetta al chiamante liberare con libera_buffer() la memoria allocata.
==============================================================================*/

char *sostituisci_frammenti(
    const char *str, const char *ptrn, const char *sost );


/*==============================================================================
sostituisci_segnaposto()

Cerca nella stringa str le ricorrenze della stringa ptrn e le sostituisce,
nell'ordine, con le stringhe contenute nell'array di stringhe puntato da sost.
L'array deve contenere la quantita' di stringhe specificata dal parametro qSost.
Se ci sono discrepanze tra la quantita' delle ricorrenze di ptrn in str e il
valore di qSost, prevale la quantita' minore.
Colloca la stringa risultante in un'area di memoria dinamica appositamente
allocata e restituisce il puntatore alla memoria allocata (NULL se l'allocazione
fallisce).
Spetta al chiamante liberare con libera_buffer() la memoria allocata.
==============================================================================*/

char *sostituisci_segnaposto(
    const char *str, const char *ptrn, const char **sost, size_t qSost );


/*==============================================================================
libera_buffer()

Riceve il puntatore ad un puntatore ad una stringa C collocata in un'area di
memoria allocata dinamicamente, libera con free() quella memoria e annulla il
puntatore.
==============================================================================*/

void libera_buffer( char **buffer );


#endif // UTILITA_STRINGHE_DINAMICHE_H_INCLUDED


utilita_stringhe_dinamiche.c:

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

#include "utilita_stringhe_dinamiche.h"



/*==============================================================================
Riceve il puntatore ad una stringa C, ne effettua una copia in un'area di
memoria dinamica appositamente allocata, restituisce il puntatore alla memoria
allocata (NULL se l'allocazione fallisce).
Spetta al chiamante liberare con libera_buffer() la memoria allocata.
==============================================================================*/

char *duplica_stringa( const char *str ) {
    char *tmp = NULL;

	if( str ) { // verifica che il parametro s sia una stringa valida
        size_t l = strlen(str)+1; // +1 per includere il terminatore
        if( (tmp=malloc(l)) ) memcpy( tmp, str, l );
    }

    return tmp;
}



/*==============================================================================
Alloca la quantita' di memoria indicata da dim (dim NON include il carattere
terminatore) e copia la stringa str nello spazio di memoria allocato. Se dim e'
minore della lunghezza corrente della stringa, la stringa viene troncata. Se dim
e' maggiore della lunghezza corrente della stringa, lo spazio eccedente viene
impostato su una serie di zeri. Restituisce il puntatore alla memoria allocata
(NULL se l'allocazione fallisce).
Spetta al chiamante liberare con libera_buffer() la memoria allocata.
==============================================================================*/

char *dimensiona_stringa( const char *str, size_t dim ) {
    char *tmp = NULL;

	if( str ) { // verifica che il parametro s sia una stringa valida
        tmp = calloc( dim+1, sizeof(*tmp) );

        if( tmp ) { // allocazione riuscita, copiamo
            size_t l = strlen( str );
            strncpy( tmp, str, l<dim?l:dim );
        }
    }

    return tmp;
}



/*==============================================================================
Inserisce la stringa agg nella posizione pos della stringa s. Se pos eccede la
lunghezza della stringa, l'aggiunta viene effettuata in coda alla stringa
stessa. Colloca la stringa risultante in un'area di memoria dinamica
appositamente allocata e restituisce il puntatore alla memoria allocata (NULL se
l'allocazione fallisce).
Spetta al chiamante liberare con libera_buffer() la memoria allocata.
==============================================================================*/

char *inserisci_stringa( const char *str, const char *agg, size_t pos ) {
    char *tmp = NULL;

    if( str && agg ) {
        size_t lStr = strlen( str );
        size_t lAgg = strlen( agg );

        tmp = malloc( lStr+lAgg+1 );

        if( tmp ) { // allocazione riuscita, inseriamo
            if( pos > lStr ) pos = lStr;
            memcpy( tmp, str, pos );
            memcpy( tmp+pos, agg, lAgg );
            memcpy( tmp+pos+lAgg, str+pos, lStr-pos+1 );
        }
    } else if( str ) tmp = duplica_stringa( str );

    return tmp;
}



/*==============================================================================
Converte in stringa il valore indicato da n, quindi lo inserisce nella posizione
pos della stringa s. Se pos eccede la lunghezza della stringa, l'aggiunta viene
effettuata in coda alla stringa stessa. Colloca la stringa risultante in un'area
di memoria dinamica appositamente allocata e restituisce il puntatore alla
memoria allocata (NULL se l'allocazione fallisce).
Spetta al chiamante liberare con libera_buffer() la memoria allocata.
==============================================================================*/

char *inserisci_intero( const char *str, int n, size_t pos ) {
    char buff[32];
    sprintf( buff, "%d", n );
    return inserisci_stringa( str, buff, pos );
}



/*==============================================================================
Sostituisce nella stringa str tutte le occorrenze dei caratteri indicati nella
stringa orig con i caratteri indicati nelle stesse posizioni nella stringa sost.
Ad esempio, sostituisci_caratteri( "Provetta", "Pt", "Bd" ) da' come esito la
stringa "Brovedda". Colloca la stringa risultante in un'area di memoria dinamica
appositamente allocata e restituisce il puntatore alla memoria allocata (NULL se
l'allocazione fallisce). Spetta al chiamante liberare con libera_buffer() la
memoria allocata.
==============================================================================*/

char *sostituisci_caratteri(
    const char *str, const char *orig, const char *sost ) {
    char *tmp = NULL;

    if( str && orig && sost ) {
        size_t lStr  = strlen( str );
        size_t lOrig = strlen( orig );
        size_t lSost = strlen( sost );

        if( lStr && lOrig && lSost && lOrig==lSost ) {
            size_t i, j;

            tmp = duplica_stringa( str );

            if( tmp ) { // allocazione riuscita, sostituiamo
                for( i=0; i<lStr; ++i )
                    for( j=0; j<lOrig; ++j )
                        if( tmp[i] == orig[j] )
                            tmp[i] = sost[j];
            }
        }
    } else if( str ) tmp = duplica_stringa( str );

    return tmp;
}



/*==============================================================================
Sostituisce un frammento di l caratteri della stringa s con la stringa sost, a
partire dalla posizione pos (sost puo' anche essere piu' lungo o piu' corto di l
caratteri). Colloca la stringa risultante in un'area di memoria dinamica
appositamente allocata e restituisce il puntatore alla memoria allocata (NULL se
l'allocazione fallisce).
Spetta al chiamante liberare con libera_buffer() la memoria allocata.
==============================================================================*/

char *sostituisci_frammento(
    const char *str, const char *sost, size_t pos, size_t l ) {
    char *tmp = NULL;

    if( str && sost ) {
        size_t lStr = strlen( str );
        size_t lSost = strlen( sost );

        if( pos > lStr ) pos = lStr;
        if( pos+l > lStr ) l = lStr-pos;

        tmp = malloc( (lStr-l)+lSost+1 );

        if( tmp ) { // allocazione riuscita, sostituiamo
            memcpy( tmp, str, pos );
            memcpy( tmp+pos, sost, lSost );
            memcpy( tmp+pos+lSost, str+pos+l, lStr-pos-l+1 );
        }
    } else if( str ) tmp = duplica_stringa( str );

    return tmp;
}



/*==============================================================================
Cerca nella stringa str le ricorrenze della stringa ptrn e le sostituisce con la
stringa sost. Colloca la stringa risultante in un'area di memoria dinamica
appositamente allocata e restituisce il puntatore alla memoria allocata (NULL se
l'allocazione fallisce).
Spetta al chiamante liberare con libera_buffer() la memoria allocata.
==============================================================================*/

char *sostituisci_frammenti(
    const char *str, const char *ptrn, const char *sost ) {
    char *tmp = NULL; // per il buffer dell'esito

    if( str && ptrn && sost ) { // verifica la validita' dei parametri
        // quanto e' lungo il pattern da sostituire?
        size_t lPtrn = strlen( ptrn );

        if( lPtrn != 0 ) { // il pattern da sostituire non puo' essere vuoto
            // quante volte ptrn ricorre nella stringa?
            size_t qRic; // qRic = quantita' di ricorrenze (del pattern in str)
            const char *pPtrn = strstr( str, ptrn );
            for( qRic=0; pPtrn; ++qRic )
                pPtrn = strstr( ++pPtrn, ptrn );

            if( qRic>0 ) { // il pattern deve essere presente almeno una volta
                // rileva la lunghezza delle parti "in gioco"
                size_t lStr  = strlen( str ); // la lunghezza di str
                size_t lSost = strlen( sost ); // lunghezza delle sostituzioni

                // alloca il buffer per la stringa risultante dalle sostituzioni
                tmp = malloc( lStr - lPtrn*qRic + lSost*qRic + 1 );

                if( tmp ) { // allocazione riuscita, sostituiamo
                    const char *pOrig; // il punto di str dal quale copiare
                    char *pDest; // punta al punto di tmp nel quale copiare
                    size_t i;

                    for( pOrig=str, pDest=tmp, i=0; i<=qRic; ++i ) {
                        if( (pPtrn=strstr(pOrig,ptrn)) ) {
                            memcpy( pDest, pOrig, pPtrn-pOrig );
                            pDest += pPtrn-pOrig;
                            pOrig += pPtrn-pOrig + lPtrn;
                            memcpy( pDest, sost, lSost );
                            pDest += lSost;
                        } else memcpy( pDest, pOrig, lStr-(pOrig-str)+1 );
                    }
                }
            } else tmp = duplica_stringa( str );
        } else tmp = duplica_stringa( str );
    } else if( str ) tmp = duplica_stringa( str );

    return tmp;
}



/*==============================================================================
Cerca nella stringa str le ricorrenze della stringa ptrn e le sostituisce,
nell'ordine, con le stringhe contenute nell'array di stringhe puntato da sost.
L'array deve contenere la quantita' di stringhe specificata dal parametro qSost.
Se ci sono discrepanze tra la quantita' delle ricorrenze di ptrn in str e il
valore di qSost, prevale la quantita' minore.
Colloca la stringa risultante in un'area di memoria dinamica appositamente
allocata e restituisce il puntatore alla memoria allocata (NULL se l'allocazione
fallisce).
Spetta al chiamante liberare con libera_buffer() la memoria allocata.
==============================================================================*/

char *sostituisci_segnaposto(
    const char *str, const char *ptrn, const char **sost, size_t qSost ) {
    size_t *lSost = NULL;
    char *tmp = NULL;
    size_t i;

    // verifica la validita' dei parametri
    if( sost ) {
        for( i=0; i<qSost; ++i )
            if( !sost[i] )
                return duplica_stringa( str );
    } else return duplica_stringa( str );

    if( str && ptrn ) { // verifica la validita' dei parametri
        // quant'e' lungo il pattern da sostituire?
        size_t lPtrn = strlen( ptrn );

        if( lPtrn != 0 ) { // il pattern da sostituire non puo' essere vuoto
            // quante volte ptrn ricorre nella stringa?
            size_t qRic; // qRic = quantita' di ricorrenze (del pattern in str)
            const char *pPtrn = strstr( str, ptrn ); // la posizione del pattern
            for( qRic=0; pPtrn; ++qRic )
                pPtrn = strstr( ++pPtrn, ptrn );
            if( qRic > qSost ) qRic = qSost; else qSost = qRic;

            // alloca un buffer per la lunghezza delle stringhe sostitutive
            if( (lSost=calloc(qSost,sizeof(*lSost))) == NULL ) return tmp;

            if( qRic>0 ) { // il pattern deve essere presente almeno una volta
                size_t lStr  = strlen( str ); // la lunghezza di str
                size_t totLSost = 0; // la lunghezza totale delle sostituzioni

                // rileva la lunghezza d'ognuna delle parti sostitutive
                for( i=0; i<qSost; ++i ) {
                    lSost[i] = strlen( sost[i] );
                    totLSost += lSost[i]; // aggiunge alla somma totale
                }

                // alloca il buffer per la stringa risultante dalle sostituzioni
                tmp = malloc( lStr - lPtrn*qRic + totLSost + 1 );

                if( tmp ) { // allocazione riuscita, sostituiamo
                    const char *pOrig; // il punto di str dal quale copiare
                    char *pDest; // punta al punto di tmp nel quale copiare

                    for( pOrig=str, pDest=tmp, i=0; i<=qRic; ++i ) {
                        if( (pPtrn=strstr(pOrig,ptrn)) ) {
                            memcpy( pDest, pOrig, pPtrn-pOrig );
                            pDest += pPtrn-pOrig;
                            pOrig += pPtrn-pOrig + lPtrn;
                            memcpy( pDest, sost[i], lSost[i] );
                            pDest += lSost[i];
                        } else memcpy( pDest, pOrig, lStr-(pOrig-str)+1 );
                    }
                }
            } else tmp = duplica_stringa( str );
        } else tmp = duplica_stringa( str );
    } else if( str ) tmp = duplica_stringa( str );

    free( lSost );
    return tmp;
}



/*==============================================================================
Riceve il puntatore ad un puntatore ad una stringa C collocata in un'area di
memoria allocata dinamicamente, libera con free() quella memoria e annulla il
puntatore.
==============================================================================*/

void libera_buffer( char **buffer ) {
    if( buffer ) if( *buffer ) { free( *buffer ); *buffer = NULL; }
}




Lo scopo di tanto lavorio è sempre lo stesso: passare il tempo a far qualcosa di più attivo rispetto a guardare la TV.
ATTENZIONE! Sono un hobbista e l'affidabilità delle mie conoscenze informatiche è molto limitata. Non prendere come esempio il codice che scrivo, perché non ho alcuna formazione accademica e rischieresti di apprendere pratiche controproducenti.
19/05/17 21:57
lumo
Ciao Aldo, un po' di commenti

1) duplica_stringa() -> esiste quasi dappertutto strdup che fa esattamente questa cosa, inoltre dovresti a rigor di logica controllare che memcpy copi veramente tutto (visto che segui uno stile molto difensivo :rotfl: )

2) libera_buffer() -> questa secondo me è assolutamente da evitare, se leggi lo standard dovrebbe esserci scritto che free(NULL); può funzionare (quindi quegli if non servono). Il dover settare a NULL il puntatore rimasto non lo vedo come un motivo sufficiente a scrivere una funzione apposita, è una cosa che ci si aspetta in un programma C. Inoltri aggiungendo la doppia indirezione secondo me si fanno più errori e più confusione.

3) inserisci_stringa() -> la funzione è utile ma se fossi chi usa la libreria preferirei un errore se specificassi un indice sbagliato

4) inserisci_intero() -> proprio per il fatto che l'implementazione è solo un mashup di inserisci_stringa non sentirei il bisogno di questa funzione (che solleva la questione del: perché non inserisci_float? double? e così via)

5) sostituisci_* -> queste meritano una discussione un po' approfondita quindi rimando di qualche giorno, ti do un anticipo:
* una volta implementata sostituisci_frammenti(), tutte le altre potrebbero essere riscritte usando questa.
* le performance di sostituisci_caratteri() si possono migliorare notevolmente usando una lookup table (nel caso ci siano pochi caratteri, come dovrebbe essere in genere), oppure con un sort stabile
* il codice è molto contorto, quindi è più facile che ci siano errori (mortali nel caso si maneggi memoria) ed è poco efficiente perché scorre carattere per carattere. Usando funzioni come strchr, strstr, strpbrk e simili per la ricerca dovrebbe le performance dovrebbero migliorare. Migliorerebbero ancora di più con algoritmi di ricerca tipo Knuth-Morris-Pratt, Boyer-Moore e così via. Per farla breve, non mi fiderei ad usare quelle funzioni per motivi di sicurezza e performance. Un modo veloce per migliorare dovrebbe essere quello di utilizzare inserisci_stringa (che te lo sei scritto a fare se poi fai tutto a mano? :P)
Ultima modifica effettuata da lumo 19/05/17 21:59
aaa
19/05/17 23:24
Mikelius
Ciao, anche io volevo fare qualcosa di simile ... ma per ora il tempo lo sto impiegando altrove.

Comunque, prima di tutto una curiosita':
// Perchè hai usato 2 if invece che 1 if() con dentro un &&?

void libera_buffer( char **buffer ) {   
    if( buffer ) 
        if( *buffer ) {
            free( *buffer ); 
            *buffer = NULL; 
       }
} 


Secondo, se potrebbero interessarti le funzioni che volevo inserire (non so se esistono nelle librerie standard):

- string_Maiusc(char *str) // Rende tutti i Caratteri MAIUSCOLI
- string_minusc(char *str) // Rende tutti i Caratteri minuscoli
- string_Title(char *str) // Applica la maiuscola alle prime lettere di ogni parola, il resto minuscole
- delDoubleSpace(char *str) // Cancella i doppi spazi in delle stringhe
- countWord(char *str) // Conta le parole all'interno della stringa
- hideString(char *str) // Genera una stringa con '*' al posto delle lettere: [Ciao mondo -> **** ***** ]

ed forse altre che ora non ricordo










aaa
20/05/17 20:20
AldoBaldo
Mikelius, ho usato i due if annidati anziché l'unico if con la condizione && perché se un puntatore è NULL il contenuto della memoria puntata non è significativo (e potrebbe creare situazioni imprevedibili). Dunque, PRIMA verifico che il puntatore non sia NULL, solo DOPO essermi assicurato che sia un puntatore valido ne controllo il contenuto. Poi che sia un ragionamento pertinente oppure no non saprei dire -- a me sembra che abbia senso.
ATTENZIONE! Sono un hobbista e l'affidabilità delle mie conoscenze informatiche è molto limitata. Non prendere come esempio il codice che scrivo, perché non ho alcuna formazione accademica e rischieresti di apprendere pratiche controproducenti.
20/05/17 20:35
AldoBaldo
Lumo, alcuni dei tuoi commenti mi ispirano delle perplessità e dei dubbi.

1) a. strdup() è standard? non l'ho trovato nella documentazione sul C che son solito usare.
b. Può davvero capitare che memcpy() "salti" qualcosa? Per me è una novità.
c. Lo stile difensivo fa sì che i miei programmi non crashino mai!!!
(evviva l'umiltà :D) è ben vero che son tutti programmi semplici.

2) Mi piace risparmiare una riga di codice perché ho uno schermo con risoluzione limitata e amo avere più codice possibile sott'occhio. Per questo ho predisposto libera_buff(): una riga e via. In altre circostanze uso free() e subito dopo annullo il puntatore sulla stessa riga, per lo stesso scopo. Se ho capito bene la documentazione, free(NULL) semplicemente dovrebbe ritornare senza fare nulla. Forse intendevi suggerire che si può semplicemente liberare comunque la memoria e impostare comunque a zero il puntatore (tanto se è già NULL non succede nulla)?

3) Ci avevo pensato, poi ho optato per questa soluzione perché passando (ad esempio) 0xFFFFFFFF si può usare inserisci_stringa() come se fosse un concatena_stringa(). Pensi che sarebbe dunque il caso di farne due funzioni separate?

4) In effetti inizialmente avevo implementato anche inserisci_double()...

5) Aspetto l'approfondimento.
ATTENZIONE! Sono un hobbista e l'affidabilità delle mie conoscenze informatiche è molto limitata. Non prendere come esempio il codice che scrivo, perché non ho alcuna formazione accademica e rischieresti di apprendere pratiche controproducenti.
20/05/17 21:27
lumo
Postato originariamente da AldoBaldo:

Lumo, alcuni dei tuoi commenti mi ispirano delle perplessità e dei dubbi.

1) a. strdup() è standard? non l'ho trovato nella documentazione sul C che son solito usare.
b. Può davvero capitare che memcpy() "salti" qualcosa? Per me è una novità.
c. Lo stile difensivo fa sì che i miei programmi non crashino mai!!!
(evviva l'umiltà :D) è ben vero che son tutti programmi semplici.

In effetti no, ero io che mi fumavo qualcosa, comunque controllare ma non segnalare nessun errore è forse peggio di crashare terribilmente.
Riguardo strdup invece, non è standard, per due motivi: uno che è facile dal implementare, l'altro che se serve un allocatore specializzato (insomma usare qualcosa di diverso da malloc) allora una implementazione standard diventerebbe inutile

2) Mi piace risparmiare una riga di codice perché ho uno schermo con risoluzione limitata e amo avere più codice possibile sott'occhio. Per questo ho predisposto libera_buff(): una riga e via. In altre circostanze uso free() e subito dopo annullo il puntatore sulla stessa riga, per lo stesso scopo. Se ho capito bene la documentazione, free(NULL) semplicemente dovrebbe ritornare senza fare nulla. Forse intendevi suggerire che si può semplicemente liberare comunque la memoria e impostare comunque a zero il puntatore (tanto se è già NULL non succede nulla)?


Sì, e che gli if non servono a nulla. Anzi, il secondo non serve a nulla, ma il primo serve perché hai messo il doppio puntatore, ecco perché sono ferocemente contrario alla tua funzione :P (comunque compra uno schermo più grande :rotfl: )

3) Ci avevo pensato, poi ho optato per questa soluzione perché passando (ad esempio) 0xFFFFFFFF si può usare inserisci_stringa() come se fosse un concatena_stringa(). Pensi che sarebbe dunque il caso di farne due funzioni separate?


Si, immaginati uno che vede un inserimento a 0xFFFFFFFF, penserebbe subito che hai commesso uno sbaglio.

4) In effetti inizialmente avevo implementato anche inserisci_double()...


Via quella funzione :yup:

5) Aspetto l'approfondimento.

Giugno si avvicina pericolosamente quindi non so, magari se ho tempo la via più veloce è riscrivere una delle funzioni che mi piace di meno così vedi la differenza tra il tuo modo e il mio.

Rimane il fatto che il C è un linguaggio terribile per la manipolazione delle stringhe, dover usare strlen() ogni volta per saperne la lunghezza necessita lo scorrimento di tutti i caratteri. Di solito le librerie per le stringhe hanno una struttura che incapsula puntatore e lunghezza, oppure altre varianti (tipo sdstring che ti avevo mostrato). Pascal memorizzava la lunghezza della stringa all'inizio della stringa.

Dunque, PRIMA verifico che il puntatore non sia NULL, solo DOPO essermi assicurato che sia un puntatore valido ne controllo il contenuto. Poi che sia un ragionamento pertinente oppure no non saprei dire -- a me sembra che abbia senso.

Ha senso (problema comunque introdotto inutilmente dal doppio puntatore) ma puoi usare un if solo, perché gli operatori booleani in C sono sempre short-circuit:
if (buffer != NULL && *buffer != NULL) {
   ...
}

in questo caso se la prima condizione fallisce, è ovvio che anche avendo altre condizioni vere nel resto dell'and l'if sarà falso. Quando si ha il short-circuiting alla prima condizione falsa l'if fallisce e tutte quelle dopo non vengono eseguite, quindi sei al sicuro da indirizzamenti invalidi.

L'or si comporta allo stesso modo ma è duale (alla prima condizione vera l'if è vero).

OT: ma perché non usi tampone invece di buffer, che schifo sto inglese
Ultima modifica effettuata da lumo 20/05/17 21:30
aaa
20/05/17 23:29
Mikelius
Postato originariamente da AldoBaldo:

Mikelius, ho usato i due if annidati anziché l'unico if con la condizione && perché se un puntatore è NULL il contenuto della memoria puntata non è significativo (e potrebbe creare situazioni imprevedibili). Dunque, PRIMA verifico che il puntatore non sia NULL, solo DOPO essermi assicurato che sia un puntatore valido ne controllo il contenuto. Poi che sia un ragionamento pertinente oppure no non saprei dire -- a me sembra che abbia senso.


Al di là della utilità o meno dei 2 controlli (forse è meglio farne uno in più, che uno in meno), volevo dire quello che ha scritto lumo, ovvero la storia del short-circuit.
Pensavo la conoscessi ...
(Comunque, ti ringrazio. Mi hai involontariamente suggerito di aggiungerlo al mio articolo sulle espressioni booleane XD)
Invece, le altre funzioni t'ispirano?
aaa
21/05/17 13:49
AldoBaldo
Short-circuit...
Ovviamente mi sono appena documentato (per questo scrivo qui: oltre che per divertirmi, anche per scoprire cose che non so). In effetti il concetto è semplice e molto razionale, ma non ne sapevo proprio nulla! Ovviamente approfondirò ulteriormente, perché mi sa che può semplificare parecchie situazioni. Una cosa, però, devo chiedere: si tratta di una caratteristica "ufficiale", quindi sempre affidabile, o di una ottimizzazione che dipende dall'implementazione e che quindi può essere a volte disponibile e a volte no?

Le altre funzioni...
Cambiare tra maiuscole e minuscole è una cosa non proprio elementare, perché comporta di rimestare con i charset per tenere debito conto degli accenti e di altri segni diacritici. In genere uso le funzioni di sistema di Win32 CharUpperBuff() e CharLowerBuff(). Sono pressoché certo che ogni sistema operativo comune metta a disposizione qualcosa di simile. Certamente potrei scrivere un paio di funzioni di "smistamento" che chiamino a loro volta la funzione di sistema (per concentrare in un unico punto le chiamate al sistema, in caso di cambiamento di piattaforma) ma non so quanto possa essere utile.
Lo stesso discorso si applica alle funzioni che richiedono l'individuazione delle parole, indispensabile per modificare le iniziali e per contare le parole stesse.
La funzione per "mascherare" i caratteri... mah... davvero potrebbe servire? Magari per giocare all'impiccato?
La funzione per cancellare le doppie mi piace! La implementerò in modo che si possa specificare quale carattere (o serie di caratteri) prendere in considerazione. Ovviamente, se si ritiene, spaziatori inclusi. Grazie del suiggerimento.
ATTENZIONE! Sono un hobbista e l'affidabilità delle mie conoscenze informatiche è molto limitata. Non prendere come esempio il codice che scrivo, perché non ho alcuna formazione accademica e rischieresti di apprendere pratiche controproducenti.