Oppure

Loading
23/05/17 8:34
Postato originariamente da AldoBaldo:

P.S. A me invece 'sta storia del tampone piace parecchio! E' ironicamente buffa, e un po' di leggerezza ci sta sempre bene. Essere dei buontamponi non implica necessariamente mancare di serietà. :heehee:


Aldo ... a te può stare bene ma nessuno, neanche i buontemponi, userà questa libreria con le funzioni che si chiamano libera_tampone ...

Poveri noi ...
23/05/17 15:20
lumo
Sul tampone ero ovviamente ironico.

Per quanto riguarda l'uso delle stringhe in C, la mia opinione personale è che dove serva manipolazione delle stringhe molto avanzata usare il C è un controsenso.
Nonostante questo ci sono molti software scritti in C che lavorano molto con il testo, ad esempio gli editor di testo (vim tanto per dirne uno). In quei casi ho visto che a parte qualche helper di solito si preferisce andare di malloc+funzioni standard, è quello che ci si aspetta normalmente.

Un approcio che considero interessante in C è quello di sdstring, github.com/antirez/… (ricordo che antirez è Salvatore Sanfilippo, autore di Redis dove si usa anche sds).
Il codice è molto facile da comprendere e la particolarità è che gli oggetti sdstring si possono passare in modo compatibile alle funzioni che vogliono un const char* con terminatore nullo.

Secondo me è molto più didattico implementare un clone di std::string semplice (magari senza tutto il lato C++ che serve per interagire con la STL, cioè iteratori e allocatore ridefinibile).
Come struttura si usa il classico puntatore + lunghezza + memoria allocata.
Di solito std::string è più complicato perché utilizza delle ottimizzazioni, una decina di anni fa era il copy-on-write, adesso mi pare che quasi tutte le librerie standard per C++ comuni utilizzino la small string optimization, ci sono molti video su youtube su questo argomento ben fatti.
Ultima modifica effettuata da lumo 23/05/17 15:22
aaa
23/05/17 17:35
AldoBaldo
Ragazzi carissimi, vi ringrazio veramente tanto per la pazienza che mi riservate e per gli spunti che mi proponete. Alcuni sono in grado di comprenderli e state ben certi che ne faccio tesoro, altri volano oggettivamente un po' troppo alto sopra la mia testa.

Rimane un fatto: non sto più usando "buffer", bensì "tampone". Ovviamente, se prima abbrevviavo con "buff", ora abbrevio con "tamp" (colpa tua, lumo). Vi avverto: sono a un passo dal cominciare a usare nomenclature in piemontese... ad esempio, sostituisci_frammento() potrebbe diventare cambeja_n_toc() :rotfl:
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.
23/05/17 18:03
Mikelius
Postato originariamente da AldoBaldo:

Ragazzi carissimi, vi ringrazio veramente tanto per la pazienza che mi riservate e per gli spunti che mi proponete. Alcuni sono in grado di comprenderli e state ben certi che ne faccio tesoro, altri volano oggettivamente un po' troppo alto sopra la mia testa.



Ho ripescato la mia vecchia funzione DoppioSpazio().
Funziona (almeno pare) non ho avuto tempo di ricontrollarla per bene, mi piacerebbe poi vedere la tua di implementazione AldoBaldo.
(p.s. ho pure incluso un piccolo main() per una prova al volo se volete)


/*
 * Data una stringa, crea una stringa con l'eliminazione dei doppi spazi.
 * Ritorna la dimensione della nuova stringa. Source e destination devono 
 * essere della stessa dimensione per il caso limite che source non avesse doppiSpazi
 *** MANCANO I CONTROLLI SULL'INPUT****
 */

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

/* Controlla un carattere con il successivo, se sono entrambi spazi, avanza il primo indice e ne copia solo 1
 * altrimenti copia normalmente il carattere. Se si trova un doppio spazio ripete il do while
 * (potrebbero esserci 3 spazii consecutivi ad esempio). Infine ritorna la dimensione nella nuova stringa pulita
 */
size_t doppioSpazio(const char *source, char *destination )
{
    int controllo = 0; // Controlla se si trova un doppioSpazio
    size_t i = 0 ;  //Primo indice
    size_t k = 0 ; // Secondo Indice 
    size_t dimFrase = strlen(source);

    char *appoggio = (char*)malloc( (dimFrase+1)* sizeof( char ) );
    strncpy( appoggio, source, dimFrase+1 );

    do{
        controllo = 0;
        for( k=0, i = 0; i < dimFrase; k++, i++ ){
            if( appoggio[i] == ' ' && appoggio[i+1] == ' ' ){
               i++;
               controllo = 1;
            }
            appoggio[k] =appoggio[i];
        }
        appoggio[k] = '
Postato originariamente da AldoBaldo:

Ragazzi carissimi, vi ringrazio veramente tanto per la pazienza che mi riservate e per gli spunti che mi proponete. Alcuni sono in grado di comprenderli e state ben certi che ne faccio tesoro, altri volano oggettivamente un po' troppo alto sopra la mia testa.



Ho ripescato la mia vecchia funzione DoppioSpazio().
Funziona (almeno pare) non ho avuto tempo di ricontrollarla per bene, mi piacerebbe poi vedere la tua di implementazione AldoBaldo.
(p.s. ho pure incluso un piccolo main() per una prova al volo se volete)


/*
 * Data una stringa, crea una stringa con l'eliminazione dei doppi spazi.
 * Ritorna la dimensione della nuova stringa. Source e destination devono 
 * essere della stessa dimensione per il caso limite che source non avesse doppiSpazi
 *** MANCANO I CONTROLLI SULL'INPUT****
 */

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

/* Controlla un carattere con il successivo, se sono entrambi spazi, avanza il primo indice e ne copia solo 1
 * altrimenti copia normalmente il carattere. Se si trova un doppio spazio ripete il do while
 * (potrebbero esserci 3 spazii consecutivi ad esempio). Infine ritorna la dimensione nella nuova stringa pulita
 */
size_t doppioSpazio(const char *source, char *destination )
{
    int controllo = 0; // Controlla se si trova un doppioSpazio
    size_t i = 0 ;  //Primo indice
    size_t k = 0 ; // Secondo Indice 
    size_t dimFrase = strlen(source);

    char *appoggio = (char*)malloc( (dimFrase+1)* sizeof( char ) );
    strncpy( appoggio, source, dimFrase+1 );

    do{
        controllo = 0;
        for( k=0, i = 0; i < dimFrase; k++, i++ ){
            if( appoggio[i] == ' ' && appoggio[i+1] == ' ' ){
               i++;
               controllo = 1;
            }
            appoggio[k] =appoggio[i];
        }
        appoggio[k] = '{parsed_message}';
    } while( controllo==1);
    strcpy( destination, appoggio );
    free(appoggio);
    return strlen(destination);
}
int main( void )
{
    char    src[50] = "Ciao    Mondo    Bello    ";
    char   dest[50] = "";
    size_t    dimN  = 0;
    printf( "\n**** STRINGHE INIZIALI ****\n\n" );
    printf( "Stringa Iniziale =[%s]\n", src );
    printf( "Stringa Finale   =[%s]\n", dest );

    dimN = doppioSpazio( src, dest);
    printf( "\n\n\n\n**** STRINGHE FINALI ****\n\n" );
    printf( "Stringa Iniziale =[%s]\n", src );
    printf( "Stringa Finale   =[%s]\n", dest );

    return 0;
}

'; } while( controllo==1); strcpy( destination, appoggio ); free(appoggio); return strlen(destination); } int main( void ) { char src[50] = "Ciao Mondo Bello "; char dest[50] = ""; size_t dimN = 0; printf( "\n**** STRINGHE INIZIALI ****\n\n" ); printf( "Stringa Iniziale =[%s]\n", src ); printf( "Stringa Finale =[%s]\n", dest ); dimN = doppioSpazio( src, dest); printf( "\n\n\n\n**** STRINGHE FINALI ****\n\n" ); printf( "Stringa Iniziale =[%s]\n", src ); printf( "Stringa Finale =[%s]\n", dest ); return 0; }

Ultima modifica effettuata da Mikelius 23/05/17 18:06
aaa
23/05/17 18:23
lumo
Facilissimo un buffer overflow con quella funzione, sta nel mucchio "insicure e inutili" a mio avviso.

Questo è come si potrebbe fare in C++ (da standard 2011 in poi)
#include <iostream>
#include <string>
#include <algorithm>

void rimuoviDoppie(std::string& s)
{
    auto last = std::unique(s.begin(), s.end(), [](char c1, char c2) {
                return c1 == c2 && c1 == ' ';
    });

    s.erase(last, s.end());
}

int main()
{
    std::string s = "Parola  con doppi  spazi";
    rimuoviDoppie(s);
    std::cout << s << std::endl;
    return 0;
}


Tengo aperto il topic per la discussione ma vi prego almeno di rimanere in tema (stringhe), lasciamo i tamponi altrove.
Ultima modifica effettuata da lumo 23/05/17 18:23
aaa
23/05/17 18:52
Mikelius
Postato originariamente da lumo:

Facilissimo un buffer overflow con quella funzione, sta nel mucchio "insicure e inutili" a mio avviso.

Questo è come si potrebbe fare in C++ (da standard 2011 in poi)



L'avevo scritta 10 anni fa più o meno...
Non voglio essere presuntuoso, ma per capire,
Un esempio pratico di un possibile buffer overflow?

P.s. conosco a malapena il C, il tuo codice in C++ lo capisco a malapena XD
Fermo restando l'utilità o meno (almeno un utilità didattica potrebbe averla) mi piacerebbe vedere un implementazione in C in modo da orientare le mie prossime (e vecchie) funzioni nella giusta direzione.
(Ad esempio, se avessi chiesto come parametri di input solo source, e allocato dentro la funzione destination, ritornando il puntatore a destination e demandando il compito di deallocare la stringa al chiamante, sarebbe stata più sicura?)
Ultima modifica effettuata da Mikelius 23/05/17 19:59
aaa
23/05/17 20:56
AldoBaldo
Io avrei fatto così:

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

/*==============================================================================
Elimina 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. Il puntatore alla stringa originale
puo' coincidere con quello alla stringa modificata. Qualora i due puntatori non
coincidano, lo spazio di memoria puntato da modf deve avere dimensioni
prudenzialmente almeno uguali a quello puntato da orig.
Restituisce la dimensione della nuova stringa così modificata. In caso d'errore,
restituisce il valore massimo rappresentabile per mezzo del tipo size_t.
==============================================================================*/

size_t EliminaSpaziatureMultiple( const char *orig, char *modf ) {
    if( orig && modf ) {
        const char *po = orig; // puntatore per scorrere la stringa originale
        char *pm = modf;       // 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 = 'Io avrei fatto così:


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

/*==============================================================================
Elimina 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. Il puntatore alla stringa originale
puo' coincidere con quello alla stringa modificata. Qualora i due puntatori non
coincidano, lo spazio di memoria puntato da modf deve avere dimensioni
prudenzialmente almeno uguali a quello puntato da orig.
Restituisce la dimensione della nuova stringa così modificata. In caso d'errore,
restituisce il valore massimo rappresentabile per mezzo del tipo size_t.
==============================================================================*/

size_t EliminaSpaziatureMultiple( const char *orig, char *modf ) {
    if( orig && modf ) {
        const char *po = orig; // puntatore per scorrere la stringa originale
        char *pm = modf;       // 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 src[50] = "Ciao    Mondo    Bello    ";
    char dest[50] = "";
    size_t dimN = 0;

    printf( "\n**** STRINGHE INIZIALI ****\n\n" );
    printf( "Stringa Iniziale =[%s]\n", src );
    printf( "Stringa Finale   =[%s]\n", dest );

    dimN = EliminaSpaziatureMultiple( src, dest );

    printf( "\n\n\n\n**** STRINGHE FINALI ****\n\n" );
    printf( "Stringa Iniziale =[%s]\n", src );
    printf( "Stringa Finale   =[%s]\n", dest );
    printf( "Lunghezza della stringa finale: %u\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) = 'Io avrei fatto così:

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

/*==============================================================================
Elimina 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. Il puntatore alla stringa originale
puo' coincidere con quello alla stringa modificata. Qualora i due puntatori non
coincidano, lo spazio di memoria puntato da modf deve avere dimensioni
prudenzialmente almeno uguali a quello puntato da orig.
Restituisce la dimensione della nuova stringa così modificata. In caso d'errore,
restituisce il valore massimo rappresentabile per mezzo del tipo size_t.
==============================================================================*/

size_t EliminaSpaziatureMultiple( const char *orig, char *modf ) {
    if( orig && modf ) {
        const char *po = orig; // puntatore per scorrere la stringa originale
        char *pm = modf;       // 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 src[50] = "Ciao    Mondo    Bello    ";
    char dest[50] = "";
    size_t dimN = 0;

    printf( "\n**** STRINGHE INIZIALI ****\n\n" );
    printf( "Stringa Iniziale =[%s]\n", src );
    printf( "Stringa Finale   =[%s]\n", dest );

    dimN = EliminaSpaziatureMultiple( src, dest );

    printf( "\n\n\n\n**** STRINGHE FINALI ****\n\n" );
    printf( "Stringa Iniziale =[%s]\n", src );
    printf( "Stringa Finale   =[%s]\n", dest );
    printf( "Lunghezza della stringa finale: %u\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 src[50] = "Ciao Mondo Bello "; char dest[50] = ""; size_t dimN = 0; printf( "\n**** STRINGHE INIZIALI ****\n\n" ); printf( "Stringa Iniziale =[%s]\n", src ); printf( "Stringa Finale =[%s]\n", dest ); dimN = EliminaSpaziatureMultiple( src, dest ); printf( "\n\n\n\n**** STRINGHE FINALI ****\n\n" ); printf( "Stringa Iniziale =[%s]\n", src ); printf( "Stringa Finale =[%s]\n", dest ); printf( "Lunghezza della stringa finale: %u\n", dimN ); return 0; }
Ultima modifica effettuata da AldoBaldo 23/05/17 21:29
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.
23/05/17 22:10
Mikelius
Postato originariamente da AldoBaldo:

Io avrei fatto così:

{...}



Mi piace. Comunque, come nel mio bisogna stare attenti alla memoria allocata per *modf, se nel main() si passa un Array di 2 char, ad esempio, si genera un errore.
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() .
aaa