[C] Copia input su output tagliando gli spazi (principiante)

di il
9 risposte

[C] Copia input su output tagliando gli spazi (principiante)

Dovevo fare questo esercizio:
Scrivete un programma che copi il suo input sul suo output, sostituendo una stringa di uno o più spazi con uno spazio singolo.

Io ho scritto questo:
  /* Copia l'input sull'output sostituendo stringhe di 2 o piú spazi con un singolo spazio; vers. 2 */

#include <stdio.h>

void main() {

        int c, sp;
        sp = 0;

        putchar(10);

        while((c = getchar()) != EOF) {
                if(c == ' ' && sp == 0) {
                        ++sp;
                        putchar(c); }
                else if(c == ' ' && sp > 0)
                        ++sp;
                else {
                        sp = 0;
                        putchar(c); }
                }

        printf("\n\n");
}  
Che dite, il codice é accettabile? O c'erano sistemi migliori per farlo?

9 Risposte

  • Re: [C] Copia input su output tagliando gli spazi (principiante)

    Main deve restituire un int, per il resto, se ti funziona, va bene
  • Re: [C] Copia input su output tagliando gli spazi (principiante)

    Perché main deve restituire un int? Se uso void main() non va bene?
  • Re: [C] Copia input su output tagliando gli spazi (principiante)

    No, non va bene, è sbagliato e un buon compilatore dovrebbe segnalartelo.
    Puoi invece omettere il return(0) (risultato con successo) che viene aggiungo di default.
  • Re: [C] Copia input su output tagliando gli spazi (principiante)

    Il main() deve obbligatoriamente restituire al sistema un valore intero segnato con i comuni sistemi mainstream per PC. Qualsiasi altra forma è sbagliata e non standard.

    Il codice proposto peraltro è carente dal punto di vista logico. La duplicazione dei casi per la gestione delle iterazioni di spazi è ridondante e inutile.
    
                    if(' ' == c) 
                    {
                        if (0 == sp)
                        {
                            putchar(c); 
                        }
                        ++sp;
                    }
                    else
                    {
                        ...
                    }
    
    Sicuramente si deve rifiutare categoricamente fin dai primi passi ogni attitudine del tipo "se funziona, va bene". Codesta è la negazione della stessa essenza del software engineering e della buona programmazione!
  • Re: [C] Copia input su output tagliando gli spazi (principiante)

    M.A.W. 1968 ha scritto:


    ...

    Sicuramente si deve rifiutare categoricamente fin dai primi passi ogni attitudine del tipo "se funziona, va bene". Codesta è la negazione della stessa essenza del software engineering e della buona programmazione!
    concordo con te che se un codice funziona non è detto che sia corretto, e comunque ben scritto, tuttavia io mi riferivo alla domanda posta: "Che dite, il codice é accettabile? O c'erano sistemi migliori per farlo?", dato che ci sono una infinità di modi per implementare lo stesso algoritmo e ciascuno sarà portato a supporre che la propria via sia la migliore. Un codice "ermetico" per esempio è efficiente ma non certo ben leggibile. A questo mi riferivo, lo hai pensato? lo hai provato? funziona? allora va bene! Io lo scriverei meglio? penso di sì, ma non è il punto.
    Scrivere invece void main è un errore, e questo per me va segnalato.
    Questo logicamente è il mio pensiero.
  • Re: [C] Copia input su output tagliando gli spazi (principiante)

    Grazie mille, le vostre risposte sono state molto istruttive
  • Re: [C] Copia input su output tagliando gli spazi (principiante)

    M.A.W. 1968 ha scritto:


    .
    Il codice proposto peraltro è carente dal punto di vista logico. La duplicazione dei casi per la gestione delle iterazioni di spazi è ridondante e inutile.
    Ho fatto un altro semplice esercizio (simile al precedente) in cui ho cercato di seguire il tuo consiglio migliorando la parte logica:
      /* Esercizio 1.12 Scrivete un programma che stampi il suo input con
       una parola per linea.                                            */
    
    #include <stdio.h>
    
    #define IN 1
    #define OUT 0
    
    int main() {
            int c, parola;
            parola = OUT;
    
            while((c=getchar()) != EOF) {
                    if(c!=' ' && c!='\n' && c!='\t') {
                            parola=IN;
                            putchar(c); }
                    else {
                            if(parola==IN)  {
                                    putchar(10);
                                    parola=OUT; }
                            }
            }
            return 0;
    }  
    Che ne pensi?
  • Re: [C] Copia input su output tagliando gli spazi (principiante)

    lucifugo ha scritto:


    Ho fatto un altro semplice esercizio (simile al precedente) in cui ho cercato di seguire il tuo consiglio migliorando la parte logica:
      /* Esercizio 1.12 Scrivete un programma che stampi il suo input con
       una parola per linea.                                            */
    
    #include <stdio.h>
    
    #define IN 1
    #define OUT 0
    
    int main() {
            int c, parola;
            parola = OUT;
    
            while((c=getchar()) != EOF) {
                    if(c!=' ' && c!='\n' && c!='\t') {
                            parola=IN;
                            putchar(c); }
                    else {
                            if(parola==IN)  {
                                    putchar(10);
                                    parola=OUT; }
                            }
            }
            return 0;
    }  
    Che ne pensi?
    L'esercizio è decisamente semplice e la soluzione è didatticamente accettabile.
    Certo sarebbe meglio utilizzare una enum per le due costanti IN e OUT che rappresentano i due stati della basilare FSM che implementa l'intera logica del programma.

    Inoltre è tassativamente proibito usare costanti numeriche manifeste come in putchar(10): il simbolo '\n' è sempre da preferisi perché portabile anche su sistemi non-ASCII, e più in generale per non creare alcun problema di refactoring e decodifica in casi realistici di applicazione.

    Allo stesso modo, è sempre bene anteporre le costanti (tutto ciò che non può essere un lvalue valido) all'operatore di comparazione, in modo da scaricare sul compilatore come errore sintattico quello che è uno degli errori semantici più comuni.
    
        if (IN == parola) 
        {
            ...
        }
    


    Riguardo al codice della prima if(), la logica di valutazione in short circuit del C la rende comunque accettabile prestazionalmente. In generale, tuttavia, è sempre meglio evitare di affastellare troppe condizioni logiche nel medesimo statement, per questioni di leggibilità e mantenibilità del codice: in casi di questo genere, ad esempio, è sempre un'ottima idea usare la funzione strchr() controllando se il carattere in input appartiene alla stringa dei separatori, come in
    
        strchr(" \n\r\t", c)
    
    Una collezione organica di queste raccomandazioni è contenuta nei testi avanzati indicati nella seconda parte di questa nota bibliografica, convalidata da oltre due decenni di didattica del linguaggio C ai massimi livelli applicativi.

    sebaldar ha scritto:


    ...ci sono una infinità di modi per implementare lo stesso algoritmo e ciascuno sarà portato a supporre che la propria via sia la migliore.
    L'informatica applicativa è anche un'arte (soprattutto nel senso sennettiano di "attività artigianale"), ma è soprattutto una scienza e una disciplina ingegneristica. Esistono delle metriche ben precise (function points, McCabe, complessità ciclomatica, profiling a runtime e dozzine di altre tecniche miste) che consentono di valutare in modo oggettivo e impersonale se un codice è "migliore" o "peggiore" di altri in un senso tecnico estremamente ben definito, confrontando varie implementazioni sensate sulla base di una specifica applicativa il più possibile precisa e aderente alla realtà.

    Il software engineering si occupa appunto di studiare e creare programmi oggettivamente "migliori" secondo parametri ben definiti, lasciando a margine i personalismi e misurando invece i costi, i tempi, la complessità, la manutenibilità: stimando poi a parte tutto ciò che risulta purtroppo non quantificabile, come la "leggibilità" o la "comprensibilità" che dipendono strettamente dal programmatore e dalla sua esperienza, e si rivelano unicamente tramite misure indirette (un codice poco comprensibile e mal documentato causerà costi di manutenzione ovviamente maggiori e avrà maggior probabilità di causare ulteriori bug, con aggravio dei costi...).

    In ogni caso, esiste un complesso e completo quadro oggettivo e intersoggettivo di riferimento al quale implicitamente ci si riconduce quando un professionista con la mia esperienza spende un giudizio di merito sulla qualità complessiva di un codice, sia pure un banale esercizio. Non stiamo vagamente cercando di confrontare Kandinski con Giotto.
  • Re: [C] Copia input su output tagliando gli spazi (principiante)

    M.A.W. 1968 ha scritto:



    L'esercizio è decisamente semplice e la soluzione è didatticamente accettabile.
    Certo sarebbe meglio utilizzare una enum per le due costanti IN e OUT che rappresentano i due stati della basilare FSM che implementa l'intera logica del programma.

    Inoltre è tassativamente proibito usare costanti numeriche manifeste come in putchar(10): il simbolo '\n' è sempre da preferisi perché portabile anche su sistemi non-ASCII, e più in generale per non creare alcun problema di refactoring e decodifica in casi realistici di applicazione.

    Allo stesso modo, è sempre bene anteporre le costanti (tutto ciò che non può essere un lvalue valido) all'operatore di comparazione, in modo da scaricare sul compilatore come errore sintattico quello che è uno degli errori semantici più comuni.
    
        if (IN == parola) 
        {
            ...
        }
    


    Riguardo al codice della prima if(), la logica di valutazione in short circuit del C la rende comunque accettabile prestazionalmente. In generale, tuttavia, è sempre meglio evitare di affastellare troppe condizioni logiche nel medesimo statement, per questioni di leggibilità e mantenibilità del codice: in casi di questo genere, ad esempio, è sempre un'ottima idea usare la funzione strchr() controllando se il carattere in input appartiene alla stringa dei separatori, come in
    
        strchr(" \n\r\t", c)
    
    Una collezione organica di queste raccomandazioni è contenuta nei testi avanzati indicati nella seconda parte di questa nota bibliografica, convalidata da oltre due decenni di didattica del linguaggio C ai massimi livelli applicativi.
    Ancora mille grazie per la tua risposta dettagliata e piena di spunti, che adesso vado ad approfondire.
Devi accedere o registrarti per scrivere nel forum
9 risposte