Oppure

Loading
24/05/17 14:41
lumo
Io prima per l'esempio di Buffer Overflow, mi riferivo al fatto di passare dei parametri "giusti" facendo ora delle prove mi accorgo che non è bene fidarsi del main() .

Sono stato un po' brusco con "insicuro e inutile", comunque è proprio quello di cui parlo. Riscrivere la funzione non serve a molto se poi ha la stessa interfaccia insicura.

Consiglio due alternative
// ritorna la stringa senza spazi doppi, il chiamante deve occuparsi di liberare la memoria allocata dinamicamente
char* eliminaDoppiSpazi(const char* s);


oppure
// ritorna la lunghezza della stringa modificata per convenienza
int eliminaDoppiSpazi(char* s);

Siccome la stringa dopo l'elaborazione non può essere più lunga di quella originale, si può usare la stessa memoria (che sicuramente è sufficiente), modificando però la stringa originale.
È un caso particolare permesso da questo algoritmo, se la lunghezza potesse aumentare non si potrebbe fare.
È anche lo stesso metodo che uso io con std::unique in C++

Una interfaccia un po' più sicura per la tua potrebbe essere questa in altri casi
// ritorna la lunghezza di dest
int eliminaDoppiSpazi(const char* s1, char* dest, size_t maxDestLength);

Così si rifà un po' a strcat -> strncat, ma in questo caso non ha molto senso.
aaa
24/05/17 21:19
AldoBaldo
Ah, be'... se come dice Lumo si intende fare una modifica sul posto, la mia versione è facilissimamente adattabile.

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

/*==============================================================================
Elimina "sul posto" i caratteri spaziatori consecutivamente multipli, facendo
inoltre in modo che la stringa modificata non contenga mai un carattere
spaziatore nella sua prima ne' nella sua ultima posizione.
Restituisce la dimensione della stringa modificata.
In caso d'errore, restituisce il valore massimo rappresentabile per mezzo del
tipo size_t.
==============================================================================*/

size_t EliminaSpaziatureMultiple( char *str ) {
    if( str ) {
        char *po = str; // puntatore per scorrere la stringa originale
        char *pm = str; // puntatore per scorrere la stringa modificata
        size_t l = 0;   // per la lunghezza della stringa risultante
        int spazio = 0; // !=0 se si tratta di uno spazio; 0 altrimenti

        while( isspace(*po) ) ++po; // eliminiamo gli eventuali spazi iniziali

        while( *po ) { // finche' ci sono caratteri nella stringa originale
            spazio = isspace( *po ); // il carattere corrente e' uno spazio?

            ++l; // copia comunque, quindi la stringa modificata si "allunga"
            *pm++ = *po++; // spazio o no, copia il carattere corrente

            if( spazio ) // se il carattere appena copiato e' uno spazio...
                while( isspace(*po) ) // ...e fintanto che ci sono spazi...
                    ++po; // ... passa al carattere successivo
        }

        if( !spazio ) { // l'ultimo carattere copiato e' uno spazio?
            *pm = 'Ah, be'... se come dice Lumo si intende fare una modifica sul posto, la mia versione è facilissimamente adattabile.


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

/*==============================================================================
Elimina "sul posto" i caratteri spaziatori consecutivamente multipli, facendo
inoltre in modo che la stringa modificata non contenga mai un carattere
spaziatore nella sua prima ne' nella sua ultima posizione.
Restituisce la dimensione della stringa modificata.
In caso d'errore, restituisce il valore massimo rappresentabile per mezzo del
tipo size_t.
==============================================================================*/

size_t EliminaSpaziatureMultiple( char *str ) {
    if( str ) {
        char *po = str; // puntatore per scorrere la stringa originale
        char *pm = str; // puntatore per scorrere la stringa modificata
        size_t l = 0;   // per la lunghezza della stringa risultante
        int spazio = 0; // !=0 se si tratta di uno spazio; 0 altrimenti

        while( isspace(*po) ) ++po; // eliminiamo gli eventuali spazi iniziali

        while( *po ) { // finche' ci sono caratteri nella stringa originale
            spazio = isspace( *po ); // il carattere corrente e' uno spazio?

            ++l; // copia comunque, quindi la stringa modificata si "allunga"
            *pm++ = *po++; // spazio o no, copia il carattere corrente

            if( spazio ) // se il carattere appena copiato e' uno spazio...
                while( isspace(*po) ) // ...e fintanto che ci sono spazi...
                    ++po; // ... passa al carattere successivo
        }

        if( !spazio ) { // l'ultimo carattere copiato e' uno spazio?
            *pm = '{parsed_message}'; // se non lo e', "termina" la stringa modificata
        }
        else { // si', l'ultimo carattere e' uno spazio: eliminiamolo!
            --l; // la stringa viene accorciata di un carattere (lo spazio)
            *(pm-1) = '{parsed_message}'; // il terminatore viene posto un carattere prima
        }

        return l; // restituisce la lunghezza della stringa modificata
    } else return -1; // essendo size_t senza segno, questo significa
                      // restituire il valore massimo possibile per size_t
}

int main( void ) {
    char str[50] = "Ciao    Mondo    Bello    ";
    size_t dimN = 0;

    printf( "Stringa originale  = [%s]\n", str );
    printf( "Lunghezza della stringa originale: %u\n\n", strlen(str) );

    dimN = EliminaSpaziatureMultiple( str );

    printf( "Stringa Modificata = [%s]\n", str );
    printf( "Lunghezza della stringa modificata: %u\n\n", dimN );

    return 0;
}


L'unica differenza è che si impostano sia po sia pm sullo stesso valore iniziale, ovvero l'indirizzo dell'unico parametro str.

size_t EliminaSpaziatureMultiple( char *str ) {
    if( str ) {
        char *po = str; // puntatore per scorrere la stringa originale
        char *pm = str; // puntatore per scorrere la stringa modificata
        
    // il resto della funzione e' identico alla versione con due parametri
}


Ovviamente, anche il modo in cui si usa la funzione deve cambiare (vedi il main del primo listato).
'; // se non lo e', "termina" la stringa modificata } else { // si', l'ultimo carattere e' uno spazio: eliminiamolo! --l; // la stringa viene accorciata di un carattere (lo spazio) *(pm-1) = 'Ah, be'... se come dice Lumo si intende fare una modifica sul posto, la mia versione è facilissimamente adattabile.

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

/*==============================================================================
Elimina "sul posto" i caratteri spaziatori consecutivamente multipli, facendo
inoltre in modo che la stringa modificata non contenga mai un carattere
spaziatore nella sua prima ne' nella sua ultima posizione.
Restituisce la dimensione della stringa modificata.
In caso d'errore, restituisce il valore massimo rappresentabile per mezzo del
tipo size_t.
==============================================================================*/

size_t EliminaSpaziatureMultiple( char *str ) {
    if( str ) {
        char *po = str; // puntatore per scorrere la stringa originale
        char *pm = str; // puntatore per scorrere la stringa modificata
        size_t l = 0;   // per la lunghezza della stringa risultante
        int spazio = 0; // !=0 se si tratta di uno spazio; 0 altrimenti

        while( isspace(*po) ) ++po; // eliminiamo gli eventuali spazi iniziali

        while( *po ) { // finche' ci sono caratteri nella stringa originale
            spazio = isspace( *po ); // il carattere corrente e' uno spazio?

            ++l; // copia comunque, quindi la stringa modificata si "allunga"
            *pm++ = *po++; // spazio o no, copia il carattere corrente

            if( spazio ) // se il carattere appena copiato e' uno spazio...
                while( isspace(*po) ) // ...e fintanto che ci sono spazi...
                    ++po; // ... passa al carattere successivo
        }

        if( !spazio ) { // l'ultimo carattere copiato e' uno spazio?
            *pm = '{parsed_message}'; // se non lo e', "termina" la stringa modificata
        }
        else { // si', l'ultimo carattere e' uno spazio: eliminiamolo!
            --l; // la stringa viene accorciata di un carattere (lo spazio)
            *(pm-1) = '{parsed_message}'; // il terminatore viene posto un carattere prima
        }

        return l; // restituisce la lunghezza della stringa modificata
    } else return -1; // essendo size_t senza segno, questo significa
                      // restituire il valore massimo possibile per size_t
}

int main( void ) {
    char str[50] = "Ciao    Mondo    Bello    ";
    size_t dimN = 0;

    printf( "Stringa originale  = [%s]\n", str );
    printf( "Lunghezza della stringa originale: %u\n\n", strlen(str) );

    dimN = EliminaSpaziatureMultiple( str );

    printf( "Stringa Modificata = [%s]\n", str );
    printf( "Lunghezza della stringa modificata: %u\n\n", dimN );

    return 0;
}


L'unica differenza è che si impostano sia po sia pm sullo stesso valore iniziale, ovvero l'indirizzo dell'unico parametro str.

size_t EliminaSpaziatureMultiple( char *str ) {
    if( str ) {
        char *po = str; // puntatore per scorrere la stringa originale
        char *pm = str; // puntatore per scorrere la stringa modificata
        
    // il resto della funzione e' identico alla versione con due parametri
}


Ovviamente, anche il modo in cui si usa la funzione deve cambiare (vedi il main del primo listato).
'; // il terminatore viene posto un carattere prima } return l; // restituisce la lunghezza della stringa modificata } else return -1; // essendo size_t senza segno, questo significa // restituire il valore massimo possibile per size_t } int main( void ) { char str[50] = "Ciao Mondo Bello "; size_t dimN = 0; printf( "Stringa originale = [%s]\n", str ); printf( "Lunghezza della stringa originale: %u\n\n", strlen(str) ); dimN = EliminaSpaziatureMultiple( str ); printf( "Stringa Modificata = [%s]\n", str ); printf( "Lunghezza della stringa modificata: %u\n\n", dimN ); return 0; }


L'unica differenza è che si impostano sia po sia pm sullo stesso valore iniziale, ovvero l'indirizzo dell'unico parametro str.

size_t EliminaSpaziatureMultiple( char *str ) {
    if( str ) {
        char *po = str; // puntatore per scorrere la stringa originale
        char *pm = str; // puntatore per scorrere la stringa modificata
        
    // il resto della funzione e' identico alla versione con due parametri
}


Ovviamente, anche il modo in cui si usa la funzione deve cambiare (vedi il main del primo listato).
Ultima modifica effettuata da AldoBaldo 24/05/17 21:32
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.
24/05/17 21:39
AldoBaldo
Per dire, passando esplicitamente il carattere da considerare come spaziatore si potrebbe anche fare a meno di usare isspace(), che potrebbe fare confusione tra spazio, new line e tabulazione.

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

/*==============================================================================
Elimina "sul posto" i caratteri spaziatori consecutivamente multipli, facendo
inoltre in modo che la stringa modificata non contenga mai un carattere
spaziatore nella sua prima ne' nella sua ultima posizione.
Restituisce la dimensione della stringa modificata.
In caso d'errore, restituisce il valore massimo rappresentabile per mezzo del
tipo size_t.
==============================================================================*/

size_t EliminaSpaziatureMultiple( char *str, char spaziatore ) {
    if( str ) {
        char *po = str; // puntatore per scorrere la stringa originale
        char *pm = str; // puntatore per scorrere la stringa modificata
        size_t l = 0;   // per la lunghezza della stringa risultante
        int spazio = 0; // !=0 se si tratta di uno spazio; 0 altrimenti

        while( *po==spaziatore ) ++po; // elimina gli eventuali spazi iniziali

        while( *po ) { // finche' ci sono caratteri nella stringa originale
            spazio = *po==spaziatore; // il carattere corrente e' uno spazio?

            ++l; // copia comunque, quindi la stringa modificata si "allunga"
            *pm++ = *po++; // spazio o no, copia il carattere corrente

            if( spazio ) // se il carattere appena copiato e' uno spazio...
                while( *po==spaziatore ) // ...e fintanto che ci sono spazi...
                    ++po; // ... passa al carattere successivo
        }

        if( !spazio ) { // l'ultimo carattere copiato e' uno spazio?
            *pm = 'Per dire, passando esplicitamente il carattere da considerare come spaziatore si potrebbe anche fare a meno di usare isspace(), che potrebbe fare confusione tra spazio, new line e tabulazione.


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

/*==============================================================================
Elimina "sul posto" i caratteri spaziatori consecutivamente multipli, facendo
inoltre in modo che la stringa modificata non contenga mai un carattere
spaziatore nella sua prima ne' nella sua ultima posizione.
Restituisce la dimensione della stringa modificata.
In caso d'errore, restituisce il valore massimo rappresentabile per mezzo del
tipo size_t.
==============================================================================*/

size_t EliminaSpaziatureMultiple( char *str, char spaziatore ) {
    if( str ) {
        char *po = str; // puntatore per scorrere la stringa originale
        char *pm = str; // puntatore per scorrere la stringa modificata
        size_t l = 0;   // per la lunghezza della stringa risultante
        int spazio = 0; // !=0 se si tratta di uno spazio; 0 altrimenti

        while( *po==spaziatore ) ++po; // elimina gli eventuali spazi iniziali

        while( *po ) { // finche' ci sono caratteri nella stringa originale
            spazio = *po==spaziatore; // il carattere corrente e' uno spazio?

            ++l; // copia comunque, quindi la stringa modificata si "allunga"
            *pm++ = *po++; // spazio o no, copia il carattere corrente

            if( spazio ) // se il carattere appena copiato e' uno spazio...
                while( *po==spaziatore ) // ...e fintanto che ci sono spazi...
                    ++po; // ... passa al carattere successivo
        }

        if( !spazio ) { // l'ultimo carattere copiato e' uno spazio?
            *pm = '{parsed_message}'; // se non lo e', "termina" la stringa modificata
        }
        else { // si', l'ultimo carattere e' uno spazio: eliminiamolo!
            --l; // la stringa viene accorciata di un carattere (lo spazio)
            *(pm-1) = '{parsed_message}'; // il terminatore viene posto un carattere prima
        }

        return l; // restituisce la lunghezza della stringa modificata
    } else return -1; // essendo size_t senza segno, questo significa
                      // restituire il valore massimo possibile per size_t
}

int main( void ) {
    char str[50] = "  Ciao    Mondo    Bello    ";
    size_t dimN = 0;

    printf( "Stringa originale  = [%s]\n", str );
    printf( "Lunghezza della stringa originale: %u\n\n", strlen(str) );

    dimN = EliminaSpaziatureMultiple( str, ' ' );

    printf( "Stringa Modificata = [%s]\n", str );
    printf( "Lunghezza della stringa modificata: %u\n\n", dimN );

    return 0;
}
'; // se non lo e', "termina" la stringa modificata } else { // si', l'ultimo carattere e' uno spazio: eliminiamolo! --l; // la stringa viene accorciata di un carattere (lo spazio) *(pm-1) = 'Per dire, passando esplicitamente il carattere da considerare come spaziatore si potrebbe anche fare a meno di usare isspace(), che potrebbe fare confusione tra spazio, new line e tabulazione.

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

/*==============================================================================
Elimina "sul posto" i caratteri spaziatori consecutivamente multipli, facendo
inoltre in modo che la stringa modificata non contenga mai un carattere
spaziatore nella sua prima ne' nella sua ultima posizione.
Restituisce la dimensione della stringa modificata.
In caso d'errore, restituisce il valore massimo rappresentabile per mezzo del
tipo size_t.
==============================================================================*/

size_t EliminaSpaziatureMultiple( char *str, char spaziatore ) {
    if( str ) {
        char *po = str; // puntatore per scorrere la stringa originale
        char *pm = str; // puntatore per scorrere la stringa modificata
        size_t l = 0;   // per la lunghezza della stringa risultante
        int spazio = 0; // !=0 se si tratta di uno spazio; 0 altrimenti

        while( *po==spaziatore ) ++po; // elimina gli eventuali spazi iniziali

        while( *po ) { // finche' ci sono caratteri nella stringa originale
            spazio = *po==spaziatore; // il carattere corrente e' uno spazio?

            ++l; // copia comunque, quindi la stringa modificata si "allunga"
            *pm++ = *po++; // spazio o no, copia il carattere corrente

            if( spazio ) // se il carattere appena copiato e' uno spazio...
                while( *po==spaziatore ) // ...e fintanto che ci sono spazi...
                    ++po; // ... passa al carattere successivo
        }

        if( !spazio ) { // l'ultimo carattere copiato e' uno spazio?
            *pm = '{parsed_message}'; // se non lo e', "termina" la stringa modificata
        }
        else { // si', l'ultimo carattere e' uno spazio: eliminiamolo!
            --l; // la stringa viene accorciata di un carattere (lo spazio)
            *(pm-1) = '{parsed_message}'; // il terminatore viene posto un carattere prima
        }

        return l; // restituisce la lunghezza della stringa modificata
    } else return -1; // essendo size_t senza segno, questo significa
                      // restituire il valore massimo possibile per size_t
}

int main( void ) {
    char str[50] = "  Ciao    Mondo    Bello    ";
    size_t dimN = 0;

    printf( "Stringa originale  = [%s]\n", str );
    printf( "Lunghezza della stringa originale: %u\n\n", strlen(str) );

    dimN = EliminaSpaziatureMultiple( str, ' ' );

    printf( "Stringa Modificata = [%s]\n", str );
    printf( "Lunghezza della stringa modificata: %u\n\n", dimN );

    return 0;
}
'; // il terminatore viene posto un carattere prima } return l; // restituisce la lunghezza della stringa modificata } else return -1; // essendo size_t senza segno, questo significa // restituire il valore massimo possibile per size_t } int main( void ) { char str[50] = " Ciao Mondo Bello "; size_t dimN = 0; printf( "Stringa originale = [%s]\n", str ); printf( "Lunghezza della stringa originale: %u\n\n", strlen(str) ); dimN = EliminaSpaziatureMultiple( str, ' ' ); printf( "Stringa Modificata = [%s]\n", str ); printf( "Lunghezza della stringa modificata: %u\n\n", dimN ); return 0; }
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.