Esercizio 1.19 KR

di il
7 risposte

Esercizio 1.19 KR

[EDIT] Devo aver ricopiato male il codice o aver usato una copia "intermedia" perchè usando il codice che ho postato sono le stringhe dispari a mandare in crash il programma, mentre con le pari mi scrive una stringa in più... cerco di vedere cosa ho combinato... ma intanto prego potete comunque accomodarvi Avevo dimenticato le parentesi al primo if del ciclo. Ora è come vi dicevo: funzione per stringhe dispari, crasha per stringhe pari!

Salve, quest'esercizio mi chiede di creare una funzione reverse(s) che inverte una stringa e di usarla per creare un programma che inverte le linee di testo date in input.

Nella mia funzione reverse ho usato due parametri anzichè uno (solo per comodità):

void reverse(char s[], int i)
{
    int j, temp;

    j = 0;
    while (i != j) {
        temp = s[j];
        s[j] = s[i];
        s[i] = temp;
        --i;
        ++j;
    }
}
In pratica gli indici i e j fanno da riferimento agli estermi della stringa (il vettore s) e gli elementi a cui puntano si scambiano, al ciclo successivo si prendono gli elementi più "interni" e così via fino a quando gli indici si incrociano. Mi sembra qui non ci siano problemi.

Per il programma, ho implementato tutto nella funzione void ma, come ormai mi capita con gli esercizi che mi sembrano più che banali, presenta un bug che non so spiegare.

Brevemente, il processo di creazione ha seguito questi passi:
- creo un ciclo che legge i caratteri e si ferma quando incontra il carattere EOF;
- un contatore all'interno del ciclo si usa come indice per il vettore, in modo da inserirci i caratteri man mano;
- sempre all'interno del ciclo la condizione più ovvia che fa partire la chiamata alla funzione reverse è quando si presenta il carattere newline (a patto che non sia l'unico carattere presente nella stringa), l'altra condizione è che si raggiunga il limite di lunghezza del vettore;
- non c'è bisogno di inserire un carattere che mi indichi la fine della stringa, la posizione di fine si ricava dal contatore usato come indice del vettore (in ogni caso è possibile comunque inserire un carattere che segna la fine della stringa).

L'implementazione è questa:

#include <stdio.h>
#define MAXLINEA 1000

void reverse(char s[], int i);

int main(void)
{
    char linea[MAXLINEA];
    int ch, i;

    i = 0;
    while ((ch=getchar()) != EOF) {
        if (ch != '\n') {
            linea[i] = ch;
            ++i;
        }
        if (i==(MAXLINEA) || (ch=='\n' && i>0)) {
            reverse(linea, i-1);
            for (ch=0; ch<i; ++ch)
                putchar(linea[ch]);
            putchar('\n');
            i = 0;
        }
    }
    return 0;
}

void reverse(char s[], int i)
{
    int j, temp;

    j = 0;
    while (i != j) {
        temp = s[j];
        s[j] = s[i];
        s[i] = temp;
        --i;
        ++j;
    }
}
Volendo percorrere i passaggi con un esempio, diciamo che io digiti abcd

1. Ora in ch c'è 'a', il contatore i è uguale a zero, il primo elemento del vettore sarà 'a'. Il contatore i viene incrementato. Il secondo if viene ignorato.

2. Ora in ch c'è 'b', il contatore i è uguale a uno, il secondo elemento del vettore sarà 'b'. Il contatore i viene incrementato. Il secondo if viene ignorato.

3. Ora in ch c'è 'c', il contatore i è uguale a due, il terzo elemento del vettore sarà 'c'. Il contatore i viene incrementato. Il secondo if viene ignorato.

4. Ora in ch c'è 'd', il contatore i è uguale a tre, il quarto elemento del vettore sarà 'd'. Il contatore i viene incrementato. Il secondo if viene ignorato.

5. Ora in ch c'è '\n', il contatore i è uguale a quattro. Il contatore i NON viene incrementato. Si accede al secondo if e si chiama la funzione reverse, indicando come secondo argomento i-1, ossia 3, che corrisponde al quarto elemento del vettore. Si stampano gli i caratteri con un ciclo for, dove un contatore (ho usato ch stesso) che va da zero a i-1 viene usato come indice del vettore. i viene portato nuovamente a zero e il ciclo ricomincia con una nuova linea

--------------------------------------

Mi sembrava fatta... e invece il programma fa il suo dovere quando gli elementi sono di numero dispari, ma quando sono pari si blocca!

Innanzitutto sarei contento se qualcuno trovasse l'errore. Ora provo a farlo di nuovo usando magari un altro procedimento (purtroppo mi sembra più facile rifarlo di nuovo anzichè trovare un errore). Infine se avete suggerimenti riguardo l'impostazione "concettuale" e lo stile, sono ben accetti (ad esempio, mi conviene spezzettare il programma in varie funzioni anche se il programma è così piccolo? e roba del genere)

Saluti a tutto il forum

7 Risposte

  • Re: Esercizio 1.19 KR

    Se avessi preso carta e penna secondo saresti riuscito da solo a correggere il problema.
    Per i dispari ti viene bene perchè i due indici tendono a coincidere per i pari no.
    Quindi ti basta aggiungere alla condizione del while che oltre ad essere i != j deve verificarsi anche che i sia maggiore di j.

    Però se continui a ragionare sulla logica dell'esercizio vedrai che quest'ultima condizione che ti ho suggerito basta per effettuare il "reverse" di una stringa pari o dispari che sia.
  • Re: Esercizio 1.19 KR

    No il problema è che ogni volta che c'è un bug guardo alla parte sbagliata! sono troppo convinto che in un pezzo non ci siano errori e quindi non lo guardo proprio.

    Non so se facendolo con carta e penna me ne sarei accorto, anzi direi proprio di no. In effetti stavo per usare il simbolo > , poi però pensando che si sarebbero incrociati non avevo pensato al fatto che potevano non coincidere! mi sono reso conto che ho preso il vizio di ragionare "per approssimazione" sorvolando sui dettagli (non so da quando visto che in passato facevo esattamente l'opposto!) e programmando escono fuori questi errori da vero imbecille.

    Comunque grazie, non sarei mai andato a guardare la funzione reverse!

    Per il resto, hai qualche altro consiglio?
  • Re: Esercizio 1.19 KR

    aaaaaghghh come godo quando funziona un programma
  • Re: Esercizio 1.19 KR

    E' un esercizio, quindi non vale la pena di appesantirlo con dettagli meno importanti.
    Ma, una volta che hai "consolidato" il tuo codice, passa a una versione "vera".
    Ossia:
    - cosa succede se passo una stringa vuota?
    - se i è zero o negativo?
    - cosa succede se passo una stringa troppo lunga ?

    Dopo la fase diciamo così "di esercizio" inizia a pensare come un "vero" programmatore.
    Ossia a "blindare" il tuo codice da tutte le possibili condizioni di input che generino errori (ti risparmio tutta la teoria che c'è qui dietro, la mia gatta si è stesa sulla pancia)
    Poi, praticamente sempre, non usare procedure (aka: funzioni void), bensì definisci comunque un valore di ritorno intero per segnalare eventuali errori, di input e/o computazione.

    Già che ci sei chiediti se c'è un cast implicito oppure no: perchè questo
    temp = s[j];
    è un assegnamento di un char ad un intero.
    Questo è bene? E' male? E' voluto?
    Può avere effetti collaterali?
  • Re: Esercizio 1.19 KR

    +m+ ha scritto:


    E' un esercizio, quindi non vale la pena di appesantirlo con dettagli meno importanti.
    Ma, una volta che hai "consolidato" il tuo codice, passa a una versione "vera".
    Ossia:
    - cosa succede se passo una stringa vuota?
    - se i è zero o negativo?
    - cosa succede se passo una stringa troppo lunga ?

    Dopo la fase diciamo così "di esercizio" inizia a pensare come un "vero" programmatore.
    Ossia a "blindare" il tuo codice da tutte le possibili condizioni di input che generino errori (ti risparmio tutta la teoria che c'è qui dietro, la mia gatta si è stesa sulla pancia)
    Qualcosina sui "casi limite" la so
    Poi, praticamente sempre, non usare procedure (aka: funzioni void), bensì definisci comunque un valore di ritorno intero per segnalare eventuali errori, di input e/o computazione.

    Già che ci sei chiediti se c'è un cast implicito oppure no: perchè questo
    temp = s[j];
    è un assegnamento di un char ad un intero.
    Questo è bene? E' male? E' voluto?
    Può avere effetti collaterali?
    Grazie per i consigli.

    Ma cosa intendi con il consiglio sulle funzioni void? Mettere una return alla fine accertarmi che l'esecuzione arriva alla fine della "procedura"? In modo da poter effettuare un test?
  • Re: Esercizio 1.19 KR

    Ritorni 1 se la funzione ha avuto successo,0 altrimenti
  • Re: Esercizio 1.19 KR

    Visto che ti poni queste domande,puoi usare Splint.
Devi accedere o registrarti per scrivere nel forum
7 risposte