Consiglio impostazione algoritmo

di il
18 risposte

Consiglio impostazione algoritmo

Salve! Ho fatto l'esercizio 1.23 del K&R e l'algoritmo che ho fatto mi sembra funzioni bene, ma visto che mi sembra il primo esercizio ad essere appena un po' più articolato rispetto agli altri, volevo un parere riguardo l'impostazione dell'algoritmo e lo stile per ricevere un feedback ed evitare di assumere uno stile spiacevole e disordinato. Infatti al primo tentativo mi era uscito un po' un pastrocchio che in un secondo momento ho organizzato meglio, usando diverse funzioni (come suggeritomi da +m+ in un altra discussione).

Il testo dell'esercizio è questo:
"Write a program to remove all comments from a C program. Don't forget to handle quoted strings and character constants properly. C comments don't nest."

Questo il mio algoritmo:

#include <stdio.h>

int stampa_ch1(void);
int canc_comm_1(void);
int canc_comm_2(void);

int ch1, ch2;

int main(void)
{

    while ((ch1=getchar()) != EOF) { /* Salvo il primo carattere e controllo che non sia uguale a EOF */
        if (ch1 != '/')              /* Se non può iniziare un commento stampo ch1 e vado all'iterazione successiva. */
            putchar(ch1);
        else {                                       /* Altrimenti, se il secondo carattere non fa iniziare un commento,*/
            ch2 = getchar();                         /* chiamo stampa_ch1 */
            if ( (ch2 != '/') && (ch2 != '*') )
                stampa_ch1();
            else if (ch2 == '*') /* Altrimenti controllo che tipo di commento è e chiamo larelativa funzione */
                canc_comm_1();
            else if (ch2 == '/')
                canc_comm_2();
        }
    }

    return 0;
}

/* Controlla se il secondo carattere dà inizio ad un commento. In caso negativo stampa il primo, */
/* salva il secondo nel primo e restituisce il controllo all'iterazione successiva*/
int stampa_ch1(void)
{
    putchar(ch1);
    ch1 = ch2;

    return 0;
}

/* Ignora tutti i caratteri all'interno del commento vecchio stile */
int canc_comm_1(void)
{
    ch1 = getchar();
    ch2 = getchar();
    while ( (ch1 != '*') || (ch2 != '/') ) { /* controlla quando i due caratteri indicano la fine di un commento */
        ch1 = ch2;
        ch2 = getchar();
    }

    return 0;
}

/* Ignora tutti i caratteri all'interno del commento  nuovo stile */
int canc_comm_2(void)
{
    while ( (ch1=getchar()) != '\n' )
        ;
    putchar(ch1);

    return 0;
}

PS: se legge un moderatore, vorrei sapere se ritenete possa essere appropriato postare tutti gli esercizi che faccio in un unica discussione, anzichè creare una discussione solo quando incontro un problema e per ogni esercizio. In questo modo, io potrei riceve feedback sul modo in cui imposto i miei algoritmi da chiunque voglia dare un consiglio, mentre creerei una discussione più ordinata che immagino possa essere utile a chiunque abbia la curiosità di leggere gli esercizi e i commenti degli utenti.

18 Risposte

  • Re: Consiglio impostazione algoritmo

    Ma hai provato il tuo programma? Funziona? Hai avuto problemi particolari?

    P.S. Non sono un moderatore ma sicuramente postare tutti i tuoi esercizi in una sola discussione non ha senso. E penso che creare un thread per ogni problema sia proprio indicato. Con tutti i dettagli necessari, ad esempio, qui ne mancano tanti e la questione risulta generica ....
  • Re: Consiglio impostazione algoritmo

    Mi pare serva una sistemata generale.
    inizia a scrivere in pseudocodice come affronteresti il problema.
  • Re: Consiglio impostazione algoritmo

    Caspita. Mi sono completamente dimenticato che delle stringhe e i caratteri che possono contenere i simboli / /* //. Vabbè penso serva solo qualche aggiunta. (Inoltre ho visto che c'è un errore nel codice (o meglio ho inviato una versione non corretta). Il codice definitivo prevedeva di salvare il primo carattere in ch1 con la getchar prima del ciclo, la condizione del while non conteneva la getchar, che era inserita all'interno del ciclo. Dopo inserisco la correzione).

    +m+ ha scritto:


    mi pare serva una sistemata generale.
    inizia a scrivere in pseudocodice come affronteresti il problema.
    Per pseudocodice intendi un "codice in linguaggio generico" oppure di buttar giù a parole le idee per creare l'algoritmo? Te lo chiedo perchè quando si parla di pseudocodice vedo idee differenti (ad esempio per il prof del liceo i diagrammi di flusso li considerava come pseudocodice, anche se non sono sinonimi).

    Inizio con una descrizione generica che mi sembra più semplice.

    Innanzitutto avevo una scelta sull'acquisizione e il controllo del testo: leggere il flusso di caratteri così come veniva inserito ed operare carattere per carattere, oppure salvare ogni riga di input in un vettore di tipo char. Ho scelto la prima.
    Poi mi sono chiesto come si riconosce un commento. Per i commenti in stile /* ... */ ci sono due caratteri che indicano dove inizia e due caratteri che indicano dove finisce, per le linee commentate i due caratteri // ne indicano l'inizio, mentre il carattere di newline ne indica la fine.
    Il programma avrebbe dovuto stampare un carattere per volta fin quando non si fosse presentata la condizione di inizio di un commento, per poi ignorare i caratteri fin quando non si fosse presentata la condizione di fine commento. Per la condizione avrei potuto opzionalmente creare una variabile che mi indicasse lo stato (fuori dal commento/dentro il commento), cosa che non ho fatto.
    Quindi abbiamo un ciclo che legge i caratteri volta per volta fin quando non viene inserito il carattere EOF.
    All'interno del ciclo posso essere sicuro di poter stampare il carattere di quell'iterazione se il carattere è diverso da '/', perchè in quel caso sono sicuro che non sta iniziando un commento, a quel punto posso leggere il prossimo carattere.
    Quando si presenta il carattere '/' potrei essere di fronte alla condizione di inizio commento oppure no, ciò dipende dal secondo carattere, per cui, se il secondo carattere non corrisponde nè a '*' (commento vecchio stile) nè a '/' (linea di commento), vuol dire che era un "falso allarme", posso allora stampare il primo carattere e salvare il secondo carattere per utilizzarlo al ciclo successivo.
    Se invece il secondo carattere indica l'inizio di un commento, controllo se è '*' oppure '/'.
    Nel primo caso opero con due variabili che indicano due caratteri consecutivi, in questo modo posso controllare quando ricevo l'indicazione di fine commento: fin quando la condizione non è verificata, prese due variabili che contengono i primi due caratteri consecutivi, sposto il secondo nella prima variabile e nella seconda variabile metto il prossimo carattere; una volta raggiunta la condizione di fine commento salvo il primo carattere dopo il commento per utilizzarlo al ciclo successivo.
    Nel secondo caso mi basta leggere ed ignorare i caratteri fin quando non incontro quello di newline.

    Ora, per quanto riguarda la parte mancante, basterà creare una condizione tipo testo_si/testo_no, ossia una sorta di valore booleano che mi dice quando mi trovo all'interno di una stringa oppure di un carattere, nel qual caso devo solo stampare carattere per carattere senza poter attivare le altre condizioni.

    oregon ha scritto:


    Ma hai provato il tuo programma? Funziona? Hai avuto problemi particolari?
    L'ho provato con un paio di codici e a parte il fatto di essermi dimenticato della questione stringhe sembra funzionare. In effetti in origine avevo tentato un altro approccio che mi stava incasinando (fondamentalmente consideravo troppe variabili insieme senza procedere "a pezzettini" con il ragionamento) e presentava. Quando poi mi sono reso conto che stavo procedendo più per prova ed errore correggendo bug e aver perso di vista l'impostazione globale ho fatto ordine e, tutto sommato, mi piace abbastanza (almeno per il fatto che alla fine sono riuscito a "pianificare" anzichè andare a tentativi, poi per il codice in se ho bisogno del parere degli esperti, visto che ho solo da imparare).

    Ah dimenticavo. Il codice giusto (senza la questione stringhe) è questo
    
    #include <stdio.h>
    
    int stampa_primo(void);
    int stampa_secondo(void);
    int canc_comm_1(void);
    int canc_comm_2(void);
    
    int ch1, ch2;
    
    int main(void)
    {
        ch1 = getchar();
        while (ch1 != EOF) {             /* Controllo che il caratterenon sia uguale a EOF */
            if (ch1 != '/')              /* Se non può iniziare un commento stampo ch1 e prendo il seguente carattere */
                stampa_primo();          /* per l'iterazione successiva */
            else {                                       /* Altrimenti, se il secondo carattere non fa iniziare un commento,*/
                ch2 = getchar();                         /* stampo il carattere e prendo il secondo per l'iterazione seguente */
                if ( (ch2 != '/') && (ch2 != '*') )
                    stampa_secondo();
                else if (ch2 == '*')     /* Altrimenti controllo che tipo di commento è e chiamo la relativa funzione */
                    canc_comm_1();
                else if (ch2 == '/')
                    canc_comm_2();
            }
        }
    
        return 0;
    }
    
    /* Stampa il primo caratteree salva il prossimo nella variabile ch1 */
    int stampa_primo(void)
    {
        putchar(ch1);
        ch1 = getchar();
    
        return 0;
    }
    
    /* Controlla se il secondo carattere dà inizio ad un commento. In caso negativo stampa il primo, */
    /* salva il secondo nel primo e restituisce il controllo all'iterazione successiva*/
    int stampa_secondo(void)
    {
        putchar(ch1);
        ch1 = ch2;
    
        return 0;
    }
    
    /* Ignora tutti i caratteri all'interno del commento vecchio stile */
    int canc_comm_1(void)
    {
        ch1 = getchar();
        ch2 = getchar();
        while ( (ch1 != '*') || (ch2 != '/') ) { /* controlla quando i due caratteri indicano la fine di un commento */
            ch1 = ch2;
            ch2 = getchar();
        }
        ch1 = getchar();
    
        return 0;
    }
    
    /* Ignora tutti i caratteri all'interno del commento  nuovo stile */
    int canc_comm_2(void)
    {
        while ( (ch1=getchar()) != '\n' )
            ;
    
        return 0;
    }
    
  • Re: Consiglio impostazione algoritmo

    Ora è completo
    
    #include <stdio.h>
    
    int stampa_stringa(void);
    int stampa_carattere(void);
    int stampa_primo(void);
    int stampa_secondo(void);
    int canc_comm_1(void);
    int canc_comm_2(void);
    
    int ch1, ch2;
    
    int main(void)
    {
        ch1 = getchar();
        while (ch1 != EOF) {             /* Controllo che il carattere non sia uguale a EOF */
            if (ch1 == '\"')
                stampa_stringa();
            else if (ch1 == '\'')
                stampa_carattere();
            else if (ch1 != '/')              /* Se non può iniziare un commento stampo ch1 e prendo il seguente carattere */
                stampa_primo();          /* per l'iterazione successiva */
            else {                                       /* Altrimenti, se il secondo carattere non fa iniziare un commento,*/
                ch2 = getchar();                         /* stampo il carattere e prendo il secondo per l'iterazione seguente */
                if ( (ch2 != '/') && (ch2 != '*') )
                    stampa_secondo();
                else if (ch2 == '*')     /* Altrimenti controllo che tipo di commento è e chiamo la relativa funzione */
                    canc_comm_1();
                else if (ch2 == '/')
                    canc_comm_2();
            }
        }
    
        return 0;
    }
    
    /* Stampa tutti i caratteri che trova fin quando non incontra il carattere " */
    int stampa_stringa(void)
    {
        putchar(ch1);
        ch1 = getchar();
        while (ch1 != '\"') {
            putchar(ch1);
            ch1 = getchar();
        }
        putchar(ch1);
        ch1 = getchar();
    
        return 0;
    }
    
    /* Stampa tutti i caratteri che trova fin quando non incontra il carattere " */
    int stampa_carattere(void)
    {
        putchar(ch1);
        ch1 = getchar();
        while (ch1 != '\'') {
            putchar(ch1);
            ch1 = getchar();
        }
        putchar(ch1);
        ch1 = getchar();
    
        return 0;
    }
    
    /* Stampa il primo caratteree salva il prossimo nella variabile ch1 */
    int stampa_primo(void)
    {
        putchar(ch1);
        ch1 = getchar();
    
        return 0;
    }
    
    /* Controlla se il secondo carattere dà inizio ad un commento. In caso negativo stampa il primo, */
    /* salva il secondo nel primo e restituisce il controllo all'iterazione successiva*/
    int stampa_secondo(void)
    {
        putchar(ch1);
        ch1 = ch2;
    
        return 0;
    }
    
    /* Ignora tutti i caratteri all'interno del commento vecchio stile */
    int canc_comm_1(void)
    {
        ch1 = getchar();
        ch2 = getchar();
        while ( (ch1 != '*') || (ch2 != '/') ) { /* controlla quando i due caratteri indicano la fine di un commento */
            ch1 = ch2;
            ch2 = getchar();
        }
        ch1 = getchar();
    
        return 0;
    }
    
    /* Ignora tutti i caratteri all'interno del commento  nuovo stile */
    int canc_comm_2(void)
    {
        while ( (ch1=getchar()) != '\n' )
            ;
    
        return 0;
    }
    
    Alla fine ho usato altri due if per gestire stringhe e caratteri accompagnati da altrettante funzioni per la stampa.
  • Re: Consiglio impostazione algoritmo

    Quello che hai descritto a parole, non e' altro che un automa a stati finiti.

    L'implementazione che hai fatto e', ovviamente, molto pasticciata.

    Una soluzione molto, ma molto, piu' semplice era proprio quella di tenete uno STATO e leggere un carattere alla volta.

    Ti do una prima implementazione (minimale) su cui puoi ragionare e estendere per le tue necessita'.
    Considerero' SOLO i commenti su singola linea.

    elenco di stati: TEXT, START_COMMENT, LINE_COMMENT

    0) stato = TEXT
    1) leggo ch
    2) se stato == TEXT: se ch == '/', stato = START_COMMENT, goto 1), altrimenti write ch, goto 1)
    3) se stato == START_COMMENT: se ch == "/", stato = LINE_COMMENT; goto 1), altrimenti write "/"; write ch; stato = TEXT; goto 1)
    4) se stato == LINE_COMMENT: se ch == '\n'; write ch; stato = TEXT; goto 1) altrimenti goto 1)

    A questo punto, aggiungendo stati, puo' gestire: commenti a blocchi, le stringhe, ...
    Attento che, ufficialmente, dentro un commento /* ... */ ci possono essere altri /*, ma il PRIMO */ che trovi, chiude il commento!
  • Re: Consiglio impostazione algoritmo

    migliorabile ha scritto:


    Quello che hai descritto a parole, non e' altro che un automa a stati finiti.

    L'implementazione che hai fatto e', ovviamente, molto pasticciata.

    Una soluzione molto, ma molto, piu' semplice era proprio quella di tenete uno STATO e leggere un carattere alla volta.

    Ti do una prima implementazione (minimale) su cui puoi ragionare e estendere per le tue necessita'.
    Considerero' SOLO i commenti su singola linea.

    elenco di stati: TEXT, START_COMMENT, LINE_COMMENT

    0) stato = TEXT
    1) leggo ch
    2) se stato == TEXT: se ch == '/', stato = START_COMMENT, goto 1), altrimenti write ch, goto 1)
    3) se stato == START_COMMENT: se ch == "/", stato = LINE_COMMENT; goto 1), altrimenti write "/"; write ch; stato = TEXT; goto 1)
    4) se stato == LINE_COMMENT: se ch == '\n'; write ch; stato = TEXT; goto 1) altrimenti goto 1)

    A questo punto, aggiungendo stati, puo' gestire: commenti a blocchi, le stringhe, ...
    Attento che, ufficialmente, dentro un commento /* ... */ ci possono essere altri /*, ma il PRIMO */ che trovi, chiude il commento!

    NB: nota che usando lo strumento corretto per fare un certo lavoro, anche la realizzazione del lavoro diventa decisamente piu'
    semplice.
    Scusa ma mi sembra esattamente quello che ho fatto io, durante l'implementazione era proprio quello il modello che avevo in mente, però anzichè esplicitare lo stato con delle variabili booleane ed usare solo gli if, ho usato anche gli else.

    lo stato TEXT è lo stato di base, se ci sono i doppi apici c'è lo stato stringa (e chiama la funzione apposita), se invece c'è un apice singolo c'è lo stato carattere (con relativa funzione), se c'è uno slash c'è uno stato di "probabile commento" che può dare origine ad uno stato di commento con linea, o ad uno stato di commento semplice oppure ad una condizione di base.

    In pratica mi sembrava equivalente usare gli stati booleani per verificare le varie condizioni oppure utilizzare gli else, solo che gli else mi sembravano più chiari. Dici che risulta più leggibile se associo un valore ad ogni stato e me la gioco solo con i booleani? (intanto vado a scrivere la versione "a stati").
  • Re: Consiglio impostazione algoritmo

    Ho fatto l'algoritmo "a stati", ma c'è un errore ed è più di un ora che non riesco a trovarlo. Inserendo il suo stesso codice, in alcune punti non ignora i commenti, in altri lo fa.
    Comunque bug a parte mi sembra molto più complicato così, ma forse avevi in mente un'altra impostazione?
    Ecco il codice
    
    #include <stdio.h>
    #define SI 1
    #define NO 0
    
    int stampa_stringa(void);
    int stampa_carattere(void);
    int stampa_primo(void);
    int stampa_secondo(void);
    int canc_comm_1(void);
    int canc_comm_2(void);
    
    int ch1, ch2;
    
    int main(void)
    {
        int stato_base, stato_stringa, stato_carattere, stato_alarm, stato_com1, stato_com2;
    
        ch1 = getchar();
        while (ch1 != EOF) {
            stato_base = SI;
            stato_stringa = stato_carattere = stato_alarm = stato_com1 = stato_com2 = NO;
            if (ch1 == '\"') {
                stato_stringa = SI;
                stato_base = NO;
                stampa_stringa();
            }
            if ( (stato_base == SI) && (ch1 == '\'') ) {
                stato_base = NO;
                stato_carattere = SI;
                stampa_carattere();
            }
            if ( (stato_base == SI) && (ch1 == '/') ) {
                stato_alarm = SI;
                stato_base = NO;
                ch2 = getchar();
            }
            if ( (stato_alarm == SI) && (ch2 != '/') && (ch2 != '*') ) {
                stato_alarm = NO;
                stampa_secondo();
            }
            if ( (stato_alarm == SI) && (ch2 == '*') ) {
                stato_alarm = NO;
                canc_comm_1();
            }
            if ( (stato_alarm == SI) && (ch2 == '/') ) {
                stato_alarm = NO;
                canc_comm_2();
            }
            if (stato_base == SI)
                stampa_primo();
        }
    
        return 0;
    }
    
    /* Stampa tutti i caratteri che trova fin quando non incontra il carattere " */
    int stampa_stringa(void)
    {
        putchar(ch1);
        ch1 = getchar();
        while (ch1 != '\"') {
            putchar(ch1);
            ch1 = getchar();
        }
        putchar(ch1);
        ch1 = getchar();
    
        return 0;
    }
    
    /* Stampa tutti i caratteri che trova fin quando non incontra il carattere " */
    int stampa_carattere(void)
    {
        putchar(ch1);
        ch1 = getchar();
        while (ch1 != '\'') {
            putchar(ch1);
            ch1 = getchar();
        }
        putchar(ch1);
        ch1 = getchar();
    
        return 0;
    }
    
    /* Stampa il primo caratteree salva il prossimo nella variabile ch1 */
    int stampa_primo(void)
    {
        putchar(ch1);
        ch1 = getchar();
    
        return 0;
    }
    
    /* Controlla se il secondo carattere dà inizio ad un commento. In caso negativo stampa il primo, */
    /* salva il secondo nel primo e restituisce il controllo all'iterazione successiva*/
    int stampa_secondo(void)
    {
        putchar(ch1);
        ch1 = ch2;
    
        return 0;
    }
    
    /* Ignora tutti i caratteri all'interno del commento vecchio stile */
    int canc_comm_1(void)
    {
        ch1 = getchar();
        ch2 = getchar();
        while ( (ch1 != '*') || (ch2 != '/') ) { /* controlla quando i due caratteri indicano la fine di un commento */
            ch1 = ch2;
            ch2 = getchar();
        }
        ch1 = getchar();
    
        return 0;
    }
    
    /* Ignora tutti i caratteri all'interno del commento  nuovo stile */
    int canc_comm_2(void)
    {
        while ( (ch1=getchar()) != '\n' )
            ;
    
        return 0;
    }
    
  • Re: Consiglio impostazione algoritmo

    Vediamo, io ho usato 2 variabili locali, una getchar. Ed e' tutto quello che serve

    Tu stai usando:

    2 variabilo globali
    6 variabili locali
    13 getchar

    E in diversi posti NON prendi in considerazione l'EOF.

    Io non l'ho preso in considerazione NON perche' non va preso in considerazione, ma perche' ti ho solo dato una traccia su come procedere.

    Direi che puoi semplificarlo di molto.
    Inoltre, questo e' un caso in cui i goto non sono il diavolo (ma brobabilmente basta il continue)


    Ecco a cosa serve studiare la macchina di Turing
  • Re: Consiglio impostazione algoritmo

    Sai perchè? Anzichè rifare l'algoritmo stavo traducendo quello che avevo postato. Il fatto è che ero stanco e non ho prestato attenzione al tuo commento e mi sono limitato a convertire il mio in una versione a stati (che comunque sarebbe stato meglio fare senza tutte quelle variabili).

    Ad ogni modo, la tua impostazione è precisa ed identica a quella che avevo ideato inizialmente (se ho capito bene), ma che poi ho abbandonato perchè non volevo usare l'istruzione continue (e mi sembra che un'impostazione del genere non sia fattibile senza quel'istruzione) e perchè mi sembrava meno caotico e più leggibile fare una procedura ad hoc per ogni opzione.

    L'algoritmo eccolo qui
    
    #include <stdio.h>
    #define BASE 0
    #define STRINGA 1
    #define CARATTERE 2
    #define ALARM 3
    #define COMM1 4
    #define COMM2 5
    #define FINE_COMMENTO 6
    
    int main(void)
    {
        int stato, ch1;
    
        stato = BASE;
        while ((ch1=getchar()) != EOF) {
            if (stato == BASE) {
                if (ch1 == '/') {
                    stato = ALARM;
                    continue;
                }
                else if (ch1 == '\"') {
                    putchar(ch1);
                    stato = STRINGA;
                    continue;
                }
                else if (ch1 == '\'') {
                    putchar(ch1);
                    stato = CARATTERE;
                    continue;
                }
                else {
                    putchar(ch1);
                    continue;
                }
            }
            if (stato == ALARM) {
                if (ch1 == '*') {
                    stato = COMM1;
                    continue;
                }
                else if (ch1 == '/') {
                    stato = COMM2;
                    continue;
                }
                else {
                    putchar(ch1);
                    stato = BASE;
                    continue;
                }
            }
            if (stato == COMM1) {
                if (ch1 == '*') {
                    stato = FINE_COMMENTO;
                    continue;
                }
                else
                    continue;
            }
            if (stato == FINE_COMMENTO) {
                if (ch1 == '/') {
                    stato = BASE;
                    continue;
                }
                else
                    continue;
            }
            if (stato == COMM2) {
                if (ch1 == '\n') {
                    putchar(ch1);
                    stato = BASE;
                    continue;
                }
                else
                    continue;
            }
            if (stato == STRINGA) {
                if (ch1 == '\"') {
                    putchar(ch1);
                    stato = BASE;
                    continue;
                }
                else {
                    putchar(ch1);
                    continue;
                }
            }
            if (stato == CARATTERE) {
                if (ch1 == '\'') {
                    putchar(ch1);
                    stato = BASE;
                    continue;
                }
                else {
                    putchar(ch1);
                    continue;
                }
            }
        }
    
        return 0;
    }
    
    Domanda: se volessi spezzettare il codice in più funzioni mi sembra che l'istruzione continue non funzioni se la metto all'interno della procedura giusto?

    Tornando invece all'altro codice ossia questo qui
    
    #include <stdio.h>
    
    int stampa_stringa(void);
    int stampa_carattere(void);
    int stampa_primo(void);
    int stampa_secondo(void);
    int canc_comm_1(void);
    int canc_comm_2(void);
    
    int ch1, ch2;
    
    int main(void)
    {
        ch1 = getchar();
        while (ch1 != EOF) {             
            if (ch1 == '\"')
                stampa_stringa();
            else if (ch1 == '\'')
                stampa_carattere();
            else if (ch1 != '/')              
                stampa_primo();          
            else {                                       
                ch2 = getchar();                         
                if ( (ch2 != '/') && (ch2 != '*') )
                    stampa_secondo();
                else if (ch2 == '*')     
                    canc_comm_1();
                else if (ch2 == '/')
                    canc_comm_2();
            }
        }
    
        return 0;
    }
    
    /* Stampa tutti i caratteri che trova fin quando non incontra il carattere " */
    int stampa_stringa(void)
    {
        putchar(ch1);
        ch1 = getchar();
        while (ch1 != '\"') {
            putchar(ch1);
            ch1 = getchar();
        }
        putchar(ch1);
        ch1 = getchar();
    
        return 0;
    }
    
    /* Stampa tutti i caratteri che trova fin quando non incontra il carattere " */
    int stampa_carattere(void)
    {
        putchar(ch1);
        ch1 = getchar();
        while (ch1 != '\'') {
            putchar(ch1);
            ch1 = getchar();
        }
        putchar(ch1);
        ch1 = getchar();
    
        return 0;
    }
    
    /* Stampa il primo caratteree salva il prossimo nella variabile ch1 */
    int stampa_primo(void)
    {
        putchar(ch1);
        ch1 = getchar();
    
        return 0;
    }
    
    /* Controlla se il secondo carattere dà inizio ad un commento. In caso negativo stampa il primo, */
    /* salva il secondo nel primo e restituisce il controllo all'iterazione successiva*/
    int stampa_secondo(void)
    {
        putchar(ch1);
        ch1 = ch2;
    
        return 0;
    }
    
    /* Ignora tutti i caratteri all'interno del commento vecchio stile */
    int canc_comm_1(void)
    {
        ch1 = getchar();
        ch2 = getchar();
        while ( (ch1 != '*') || (ch2 != '/') ) { /* controlla quando i due caratteri indicano la fine di un commento */
            ch1 = ch2;
            ch2 = getchar();
        }
        ch1 = getchar();
    
        return 0;
    }
    
    /* Ignora tutti i caratteri all'interno del commento  nuovo stile */
    int canc_comm_2(void)
    {
        while ( (ch1=getchar()) != '\n' )
            ;
    
        return 0;
    }
    
    perchè è peggio dell'altro? credevo fosse meglio creare delle funzioni ad hoc in questa maniera anzichè creare un intero corpo come per quello a stati. si tratta di un algoritmo diciamo "standard" che si implementa in un certo modo oppure si tratta di valutazioni "ad occhio" (tralasciamo la complessità computazionale alla quale al momento non do molto peso)?

    PS: se non mi sbaglio l'EOF non lo considero solo nelle stringhe, nei caratteri e nei commenti, ma l'ho fatto volutamente! non so se magari l'ho dimenticato da qualche altra parte.
  • Re: Consiglio impostazione algoritmo

    Siamo proprio lontani.

    primo approccio: le tue funzioni fanno dei getchar. Ma, in generale, è meglio avere una funzione che lavora su stringhe (che gli passi come parametro), piuttosto che con IO.
    avrai qualcosa del tipo
    apri il file e leggilo in un buffer.
    alloca un secondo buffer di dimensioni uguali al primo
    chiama la funzione che prende il primo buffer e lo trasforma nel secondo
    stampa il contenuto del secondo

    comunque stai facendo sforzi apprezzabili
  • Re: Consiglio impostazione algoritmo

    +m+ ha scritto:


    siamo proprio lontani.

    primo approccio: le tue funzioni fanno dei getchar. Ma, in generale, è meglio avere una funzione che lavora su stringhe (che gli passi come parametro), piuttosto che con IO.
    avrai qualcosa del tipo
    apri il file e leggilo in un buffer.
    alloca un secondo buffer di dimensioni uguali al primo
    chiama la funzione che prende il primo buffer e lo trasforma nel secondo
    stampa il contenuto del secondo

    comunque stai facendo sforzi apprezzabili
    per aprire e leggere file con il C ancora non ci sono arrivato (son cose che al massimo potrei fare con python che conosco un po' meglio, ma ora devo imparare il C).

    quando parli di usare le stringhe, ti riferisci a salvare ogni riga in un vettore? come ho scritto questa era una delle due scelte che mi ero proposto, ho optato per leggere il flusso di caratteri semplicemente perchè mi è venuto più immediato. Alla prossima occasione cambio approccio, sempre se ho inteso bene.

    PS: non ho ancora capito bene questo: in C le stringhe sono semplicemente vettori di caratteri?
  • Re: Consiglio impostazione algoritmo

    La continue si puo' usare solo nei cicli.

    L'approccio a funzioni non va molto bene perche' richiede la duplicazione di codice.

    Ad esempio, l'EOF va sempre considerato, perche' nessuno ti assicura che il testo da analizzare sia ben formato. Se inizio una stringa o un carattere, ma non la chiudo, o un commento a blocchi, o un commento su linea come ultima riga del testo, SENZA un NL finale (e questo e' assolutamente valido), il tuo programma fa il botto.

    Se voglio che tu supporti anche le sequenze di escape ('\n' ad esempio), il tuo approccio ti incasina ulteriormente.

    In C, la stringa e' solo un vettore di caratteri con il carattere 0 (zero) come terminatore.

    In questo caso, l'approccio a stringhe e' inadeguato: va benissimo l'approccio un carattere alla volta.
  • Re: Consiglio impostazione algoritmo

    +m+ ha scritto:


    comunque stai facendo sforzi apprezzabili
    E' già qualcosa ma è anche un problema! Quando faccio un esercizio ho due possibilità: o lo faccio come mi viene e vado avanti con lo studio, oppure posto sul forum per ricevere feedback ed approfondire ed imparare di più. Per quanto la seconda possibilità io l'abbracci con piacere (forse più della prima) e sono consapevole che non è tempo perso, mi fa stare comunque fermo sullo studio, quindi a volte devo necessariamente impormi di andare avanti senza fissarmi ad approfondire ogni algoritmo che ho di fronte.
  • Re: Consiglio impostazione algoritmo

    migliorabile ha scritto:


    La continue si puo' usare solo nei cicli.
    Si, questo lo so, intendevo: se chiamo una funzione all'interno di un ciclo e questa contiene l'istruzione continue non va bene; se però anzichè inserirla nella funzione, io faccio restituire alla funzione l'istruzione continue è come se l'avessi inserita nel ciclo? oppure non posso dare l'istruzione continue in pasto ad una return (e credo che non si può)? Vabbè che ora provo ma mi era venuto in mente e l'ho scritto.
    Ad esempio, l'EOF va sempre considerato, perche' nessuno ti assicura che il testo da analizzare sia ben formato. Se inizio una stringa o un carattere, ma non la chiudo, o un commento a blocchi, o un commento su linea come ultima riga del testo, SENZA un NL finale (e questo e' assolutamente valido), il tuo programma fa il botto.

    Se voglio che tu supporti anche le sequenze di escape ('\n' ad esempio), il tuo approccio ti incasina ulteriormente.

    In C, la stringa e' solo un vettore di caratteri con il carattere 0 (zero) come terminatore.

    In questo caso, l'approccio a stringhe e' inadeguato: va benissimo l'approccio un carattere alla volta.
    [/quote]

    Si ovvio, avevo fatto tutte quelle assunzioni che hai elencato per semplicità... non è che non c'avessi pensato, è che le avevo volontariamente ignorate
Devi accedere o registrarti per scrivere nel forum
18 risposte