[C] Esercizio su diverse tipologie di dati.

StellaMartensitica
Salve,
potreste aiutarmi a risolvere questo esercizio? Non dovrebbe essere troppo lungo ma mi risulta difficile.

Scrivere un programma che calcoli un'espressione:

schermata tipica:

inserire espressione: 1+2.5*3
risultato: 10.5

Gli operandi dell'espressione sono numeri floating point. Gli operatori ammessi devono essere +,-,*,/.
Per semplicità l'espressione viene calcolata da sinistra a destra (nessun operatore deve avere precedenza sugli altri).

dovrei utilizzare il ciclo do-while e la funzione getchar() (dato che il capitolo del libro da cui l'ho preso di quello parla) ma non riesco a mettere insieme le cose.

Risposte
Super Squirrel
Il problema è legato all'input e al getchar(), oppure all'implementazione dell'algoritmo risolutivo?
Ipotizzando di essere già in possesso di una stringa contenente un'espressione valida (per esempio quella da te postata), non hai alcuna idea su come approcciare il problema?

StellaMartensitica
[ot]Ho un grosso problema con l'esame di informatica di base (l'unico esame di informatica) del mio corso.[/ot]

Il mio problema è che in tutto il pomeriggio l'unica cosa che sono riuscito a fare di questo esercizio è questo programma che se immetto o comunque un numero qualsiasi del tipo 123.4567 mi restitusce il numero.
Anzi. Non capisco perché ma ad esempio se metto 478.546 mi restituisce 478.54600006 (cioè mi aggiunge quale 1/1000000).
Potresti darmi un consiglio su come farlo semplicemente? Inoltre non servirebbero i vettori per fare questo esercizio perché il libro li introduce solo nel capitolo successivo.

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


int main(void)
{
char ch=0;
float totale=0;
float cumulativo=0;
int v[10];
int i=0;
int n;//indice


printf("Inserisci una espressione:\t");

ch=getchar();


while(ch!='+'&&ch!='-'&&ch!='*'&&ch!='/'&&ch!='.'&&ch!='\n')
{
v[i]=ch-48;
i++;
ch=getchar();
};
i--;
n=i;
do{
    cumulativo=cumulativo+v[i]*pow(10,n-i);
    i--;

}while(i>=0);
i++;
if(ch=='.')
{
    ch=getchar();
 while(ch!='+'&&ch!='-'&&ch!='*'&&ch!='/'&&ch!='\n')
{
v[i]=ch-48;
i++;
ch=getchar();
};
i--;
do{
    cumulativo=cumulativo+v[i]*pow(10,-1-1*i);
    i--;
}while(i>=0);
i++;//i=0
}
 printf("Cumulativo %f", cumulativo);

exit(0);
}

Super Squirrel
"SirDanielFortesque":
Potresti darmi un consiglio su come farlo semplicemente? Inoltre non servirebbero i vettori per fare questo esercizio perché il libro li introduce solo nel capitolo successivo.

Ragionando un po' ho constatato che il tutto può essere fatto senza scomodare gli array e la libreria math. Per esempio potresti partire dalla seguente impostazione:
    char c;
    char operatore = '+';
    double operando = 0;
    double risultato = 0;
    do
    {
        c = getchar();
        if(c >= '0' && c <= '9')
        {
            ...
        }
        else
        {
            if(operatore == '+')
            {
                risultato += operando;
            }
            else if(operatore == '-')
            {
                risultato -= operando;
            }
            ...
        }
    }
    while(c != '\n');

Per il momento lascia stare il carattere '.' e inizia ad implementare il tutto ipotizzando che l'espressione ammetta solo valori interi.
Spero che questo input ti possa essere utile, se hai dubbi chiedi pure!

Albesa81
"Super Squirrel":
[quote="SirDanielFortesque"]Potresti darmi un consiglio su come farlo semplicemente? Inoltre non servirebbero i vettori per fare questo esercizio perché il libro li introduce solo nel capitolo successivo.

Ragionando un po' ho constatato che il tutto può essere fatto senza scomodare gli array e la libreria math. Per esempio potresti partire dalla seguente impostazione:
    char c;
    char operatore = '+';
    double operando = 0;
    double risultato = 0;
    do
    {
        c = getchar();
        if(c >= '0' && c <= '9')
        {
            ...
        }
        else
        {
            if(operatore == '+')
            {
                risultato += operando;
            }
            else if(operatore == '-')
            {
                risultato -= operando;
            }
            ...
        }
    }
    while(c != '\n');

Per il momento lascia stare il carattere '.' e inizia ad implementare il tutto ipotizzando che l'espressione ammetta solo valori interi.
Spero che questo input ti possa essere utile, se hai dubbi chiedi pure![/quote]
L'esercizio non è banale come sembra, se si vogliono fare le cose per bene bisogna implementare quantomeno un automa a pila.

StellaMartensitica
Mi hai sbloccato finalmente. sopratutto questo risultato+=operando.

Adesso ho il programma che funzia:

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


int main(void)
{

    float a;
    char ch=0;
    float cumulativo=0;


printf("Inserisci un' espressione:\n\n\t");

scanf("%f", &a);
cumulativo=a;



while(ch!='\n'){
ch=getchar();
    if(ch=='\n')
    {
        break;
    } else{
scanf("%f", &a);


switch (ch)
{
    case '+': cumulativo=cumulativo+a;
    break;
    case '-': cumulativo=cumulativo-a;
    break;
    case '*': cumulativo=cumulativo*a;
    break;
    case '/': cumulativo=cumulativo/a;
    break;
    default: ;
    break;
}

    }
}

printf("Totale:\t%f",cumulativo);

    exit(0);
}


Avevo bisogno di un suggerimento che mi sbloccasse.

Ho solo un dubbio. Resta questo piccolo problema. Ossia se inserisco per esempio

$1+2.5*3$

mi restituisce $10.50000001$
oppure $10.49999999$

Una volta ogni 3 circa. Posso trascurare questo fatto o è qualcosa che sbaglio?

StellaMartensitica
"Albesa81":
automa a pila.


No non lo abbiamo fatto al corso. Cosa intendi?

StellaMartensitica
Comunque funzia io mi ritengo soddisfatto. L'unica cosa che non riesco a capire è perché introduce un errore sul risultato... Cioè quel 0.000000001 che aggiunge o toglie che però è brutto a vedersi.

Super Squirrel
@SirDanielFortesque

Interessante, non avevo pensato a quest'utilizzo della scanf()! :D
Giusto per rendere il codice più pulito, farei qualcosa del genere:
#include <stdio.h>

int main()
{
    double risultato = 0;
    double operando;
    char operatore = '+';
    printf("ESPRESSIONE: ");
    do
    {
        scanf("%lf", &operando);
        if(operatore == '+')
        {
            risultato += operando;
        }
        else if(operatore == '-')
        {
            risultato -= operando;
        }
        else if(operatore == '*')
        {
            risultato *= operando;
        }
        else
        {
            risultato /= operando;
        }
    }
    while((operatore = getchar()) != '\n');
    printf("RISULTATO: %lf", risultato);
    return 0;
}

Per quanto riguarda gli "errori sul risultato" prova ad utilizzare i double.

@Albesa81
Mi dispiace, ma non so a cosa ti riferisci... il mio bagaglio di conoscenze teoriche sull'informatica è abbastanza limitato!

StellaMartensitica
@Super squirrel...

si direi che il mio è più uno "spaghetti programming", se confrontato col tuo.

E' che tendo a far casino, dimenticare i ";" , le parentesi, e chi più ne ha più ne metta. E quindi poi non lo compila...

E poi non sapevo si potesse mettere un assegnazione dentro una condizione così.


...
while ((operatore = getchar()) != '\n');
...



Questo devo tenerlo a mente.

Con il tipo double adesso non lo fa più l'errore 0.0000000...

Grazie dei consigli. Ciao!

Albesa81
Che cosa ti restituiscono stream tipo questi?

\( 23489 +@ 5 \)
\( 11 +- 123785134.26 \)

(Nota che il primo non è un'espressione aritmetica, il secondo sì).

StellaMartensitica
Risultati assurdi.

il primo fa 46978.00000
il secondo fa -123785134.26

Perché? Ci devo pensare.

Super Squirrel
@Albesa81

Ovviamente si presuppone che lo stream rappresenti un'espressione "valida".

Il secondo stream ovviamente viene interpretato come 11+(−123785134.26), quindi non vedo quale sia il problema.

Albesa81
"Super Squirrel":
@Albesa81
Ovviamente si presuppone che lo stream rappresenti un'espressione "valida".

Assunzione quantomeno grossolana ma forse accettabile per un corso di informatica di base (spero non per un corso di laurea scientifico).
"Super Squirrel":
Il secondo stream ovviamente viene interpretato come 11+(−123785134.26), quindi non vedo quale sia il problema.

Allora ci dev'essere un problema sulla mia macchina, che in output dà \( -123785128.000000 \).

vict85
Ho l'impressione che tu stia studiando da un libro un po' antiquato. C'è una eccessiva attenzione all'inserimento dei valori rispetto al risolvere materialmente il problema. Insomma imparare ad usare l'IO può essere importante, ma imparare a pensare nel modo giusto lo è di più.

Personalmente trovo che avrebbe più senso provare a risolvere lo stesso problema ma supponendo che la equazione sia passata alla funzione che devi implementare come stringa:
float valuta_equazione( char const equazione[] );
In questo modo ti concentreresti maggiormente sul problema e non sull'uso di getchar e altre funzioni della libreria standard. Anche perché i computer hanno a disposizione una quantità di memoria abbastanza grande e ha più senso salvarti direttamente una intera riga (per esempio con fgets).

Inoltre ti conviene usare la libreria ctype.h.

StellaMartensitica
@AlbeSan81
"Albesa81":
$23489+@5$


Per quanto riguarda questo dovrei mettere un controllo di tutti i caratteri che stampa un messaggio di errore quanto viene inserito un carattere non valido (che non sia una cifra, un '.', un '/', un '*' un '-', un '+' o un '\n').

"Albesa81":
$11"+−"123785134.26$

Per quanto riguarda quest'altro bisogna dire che l'esercizio prevedeva che non ci fossero precedenze tra le operazioni, come avevo specificato (in quanto l'esercizio si trova in uno dei primi capitoli del libro). Pertanto non ci potevano stare parentesi in mezzo (ché appunto introdurrebbero una precedenza) e poi per le regole dell'aritmetica mettere un + e un - attaccati non ha molto senso su carta. Anche se gli elaboratori prendono +- come fosse un -. Pertanto anche in questo caso metterei un controllo che fa si che non appena vengono rilavati due operatori uno vicino all'altro mi stampa un messaggio di errore, vista la natura dell'esercizio.

[ot]
"Albesa81":
spero non per un corso di laurea scientifico


Ebbene si, mi hai beccato. E' per un corso di laurea in ingegneria meccanica. Ho trascurato la materia fin dall'inizio in favore delle altre materie e adesso me ne pento dato che ho come prospettiva il dovermi trascinare dietro questo esame ancora per un po'. Come minimo fino agli appelli estivi.[/ot]

@Vict85
"vict85":
In questo modo ti concentreresti maggiormente sul problema e non sull'uso di getchar e altre funzioni della libreria standard. Anche perché i computer hanno a disposizione una quantità di memoria abbastanza grande e ha più senso salvarti direttamente una intera riga (per esempio con fgets).Inoltre ti conviene usare la libreria ctype.h.


Per quanto scritto in questo messaggio penso a questo punto tu abbia capito che io sono ancora al livello 0 dell'informatica (il massimo utilizzo che facevo di un computer fino a ieri era il pacchetto office e i programmi di disegno CAD).

Il libro consigliato per il corso sarebbe "informatica arte e mestiere" di Mandrioli, Ceri, Sbattella, Cremonesi, Cugola. Ma per quanto in linea di massima possa anche risultare di piacevole lettura di fatto l'ho trovato poco adatto a seguire il corso "informatica di base" che si proponeva in soli 6 mesi di insegnarci a usare il C $&&$ Matlab. Quindi mi sono procurato un altro libro che avesse pure degli esercizi. Il risultato è stato che chi aveva già studiato un linguaggio di programmazione alle superiori si è trovato bene, e gli altri (tra cui anch'io) hanno fatto molta fatica.

Rispondi
Per rispondere a questa discussione devi prima effettuare il login.