[C] menù scelta

kokoko1
Salve ragazzi, nonostante il debugger del devc++ NON mi dia errore, non riesco a capire perchè il mio programmino non funzioni. Vi posto il codice:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE_MAX 21
struct merce {
       char tipo_merce[SIZE_MAX];
       int quantita;
       float prezzo;
       } mer;
       int get_menu_scelta(void);
       char nome1[SIZE_MAX];
       float p;
       char nome2[SIZE_MAX];
       int q;
       float prezzo1, prezzo2;
       int main()
       {
           int scelta;
           scelta=get_menu_scelta();
           switch(scelta){
                          case(1): 
                                   printf("nome articolo: ");
                                   fgets(mer.tipo_merce,SIZE_MAX,stdin);
                                   printf("quantita: ");
                                   scanf("%d", &mer.quantita);
                                   printf("prezzo: ");
                                   scanf("%f",&mer.prezzo);
                                   break;
                          case(2):
                                  printf("articolo: ");
                                  fgets(nome1,SIZE_MAX,stdin);
                                  printf("prezzo: ");
                                  scanf("%f",&p);
                                  break;
                          case(3):
                                  printf("articolo: ");
                                  fgets(nome2,SIZE_MAX,stdin);
                                  printf("quantita: ");
                                  scanf("%d",&q);
                                  break;
                         case(4):
                                 printf("prezzo1: ");
                                 scanf("%f", &prezzo1);
                                 printf("prezzo2: ");
                                 scanf("%f",&prezzo2);
                                 break;
                                 while(scelta);
           system ("PAUSE");
           return 0;
                                 }
                           }
            
            int get_menu_scelta( void )
{
  int selezione = 0;
  do
    {
    printf("\n" );
    printf("\n1 - inserisci articolo" );
    printf("\n2 - modifica prezzo");
    printf("\n3 - modifica quantita");
    printf("\n4 - stampa prezzo");
    printf("\n" );
    printf("\nEffettua una scelta: " );
    scanf("%d", &selezione );
    }
    while ( selezione < 1 || selezione > 4 );
  return selezione;
}


Se ad esempio scegliessi nel menù di inserire un articolo, dopo aver cliccato "1" e aver premuto INVIO, mi esce la schermata "nome articolo: quantita: " e dopo aver premuto nuovamente INVIO il programma si chiude automaticamente. Spero possiate aiutarmi a capire dove siano le parti di codice sbagliate. Vi ringrazio in anticipo.


[mod="Raptorista"]Sistemati tag codice[/mod]

Risposte
hamming_burst
Ciao,
ricontrolla i tag [code] e ne riparliamo :-)

hamming_burst
@grazie Rapstoria, così è molto meglio :-)

scusa come fa a compilarti senza warning questo codice?

con questo:

while(scelta);

dovrebbe darti qualche segnale, ma forse è qualcosa che DevC++ non fà, o è intellegente e lo ridefinisce correttamente lui.

Poi "SIZE_MAX" è una parola protetta, che non si può ridefinire. E' inclusa in "stdio.h" e te non pui ridefinirne una con lo stesso nome, cambiala in tipo "SIZE_STR_MAX".

Cerca di non fare come abitudine mettere varibili globali, come esercizi ok ma è cattiva programmazione, pure usare "system ("PAUSE"); " fa del tuo codice qualcosa di non portabile.
Ma va bhè avrai tempo per capire.

Tornando al codice:
lo hai scritto un po' "random" :-), ma sistemando e stando a quanto hai scritto te:

- metti una condizione di terminazione, tipo se inserisci il carattere "5" la usi come scelta di uscire.
- poi il "while(scelta);" messo così non serve a nulla, e nello switch non si possono mettere system() o return (consiglio aggiorna DevC++ perchè mi sembra strano non segnali).

Puoi sistemare così, tenendo in considerazione i punti precedenti:

int main() {

	while((scelta=get_menu_scelta())!=5){
		switch(scelta){



		}
	}

	return 0;
}


guarda dove ho messo le parentesi graffe e usa la condizione che vuoi per l'uscita io ho usato 5, ma usa quello che vuoi basta che lo scrivi nella funzione.

mi sembra sia a posto così, prova :-)

kokoko1
"ham_burst":
@grazie Rapstoria, così è molto meglio :-)

scusa come fa a compilarti senza warning questo codice?

con questo:

while(scelta);

dovrebbe darti qualche segnale, ma forse è qualcosa che DevC++ non fà, o è intellegente e lo ridefinisce correttamente lui.

Poi "SIZE_MAX" è una parola protetta, che non si può ridefinire. E' inclusa in "stdio.h" e te non pui ridefinirne una con lo stesso nome, cambiala in tipo "SIZE_STR_MAX".

Cerca di non fare come abitudine mettere varibili globali, come esercizi ok ma è cattiva programmazione, pure usare "system ("PAUSE"); " fa del tuo codice qualcosa di non portabile.
Ma va bhè avrai tempo per capire.

Tornando al codice:
lo hai scritto un po' "random" :-), ma sistemando e stando a quanto hai scritto te:

- metti una condizione di terminazione, tipo se inserisci il carattere "5" la usi come scelta di uscire.
- poi il "while(scelta);" messo così non serve a nulla, e nello switch non si possono mettere system() o return (consiglio aggiorna DevC++ perchè mi sembra strano non segnali).

Puoi sistemare così, tenendo in considerazione i punti precedenti:

int main() {

	while((scelta=get_menu_scelta())!=5){
		switch(scelta){



		}
	}

	return 0;
}


guarda dove ho messo le parentesi graffe e usa la condizione che vuoi per l'uscita io ho usato 5, ma usa quello che vuoi basta che lo scrivi nella funzione.

mi sembra sia a posto così, prova :-)

Andando in ordine, il dev mi risulta aggiornato all'ultima versione, più precisamente la 4.9.9.2 e non so dirti il perchè non mi dia alcun tipo di errore..
Ho apportato tutte le modifiche al codice che mi hai fatto notare, ma nonostante questo il problema persiste, ma diciamo, si è modificato. Mi spiego meglio.
Come in precedenza, quando pongo una scelta, ad esempio "1" e premo INVIO, mi compare la scritta "nome articolo: quantita: " nello stesso momento, quando invece dovrebbe essere una "successione", cioè dovrebbe comparire prima la scritta "nome articolo:" e dopo aver scritto l'articolo e aver premuto INVIO dovrebbe comparire la scritta "quantita:". Non so se sono stato chiaro. Comunque mentre prima a questo punto se premevo INVIO usciva direttamente dal programma, ora compare il menu principale come se fosse ripetuto all'infinito :?
A cosa potrebbe essere dovuto?
Riporto il codice con le correzioni. Ho lasciato come condizione d'uscita il 5 per semplicità.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE_STR_MAX 21
struct merce {
       char tipo_merce[SIZE_STR_MAX];
       int quantita;
       float prezzo;
       } mer;
       int get_menu_scelta(void);
       char nome1[SIZE_STR_MAX];
       float p;
       char nome2[SIZE_STR_MAX];
       int q;
       float prezzo1, prezzo2;
       int main()
       {
           int scelta;
           while((scelta=get_menu_scelta())!=5){
           switch(scelta){
                          case(1): 
                                   printf("nome articolo: ");
                                   fgets(mer.tipo_merce,SIZE_STR_MAX,stdin);
                                   printf("quantita: ");
                                   scanf("%d", &mer.quantita);
                                   printf("prezzo: ");
                                   scanf("%f",&mer.prezzo);
                                   break;
                          case(2):
                                  printf("articolo: ");
                                  fgets(nome1,SIZE_STR_MAX,stdin);
                                  printf("prezzo: ");
                                  scanf("%f",&p);
                                  break;
                          case(3):
                                  printf("articolo: ");
                                  fgets(nome2,SIZE_STR_MAX,stdin);
                                  printf("quantita: ");
                                  scanf("%d",&q);
                                  break;
                         case(4):
                                 printf("prezzo1: ");
                                 scanf("%f", &prezzo1);
                                 printf("prezzo2: ");
                                 scanf("%f",&prezzo2);
                                 break;
                                 }
                         }              
           return 0;
           }
            
            int get_menu_scelta( void )
{
  int selezione = 0;
  do
    {
    printf("\n" );
    printf("\n1 - inserisci articolo" );
    printf("\n2 - modifica prezzo");
    printf("\n3 - modifica quantita");
    printf("\n4 - stampa prezzo");
    printf("\n5 - Esci");
    printf("\n" );
    printf("\nEffettua una scelta: " );
    scanf("%d", &selezione );
    }
    while ( selezione < 1 || selezione > 5 );
  return selezione;
}

hamming_burst
guarda vista l'ora vado un po' a naso :-)

per la stampa consecutiva "nome articolo: quantita: " posso ipotizzare che sia il compilatore che ti abbia riordinato il codice, o essendo che c'è fgets(), ed essendo che c'è una questione sotto di apertura e chiusura di stdout, penso che la stampa a video sia "più veloce" di fgets()...solo ipotesi.

poi qua rivedendo il codice il while nella funzione get_menu_scelta() è inutile, essendo che c'è pure nel main. Devi scegliere come disegnare il tuo codice, o crei una funzione o usi il while in modo migliore.
per il "count-to-infinite" mi sembra sia colpa del break; per via di scoping.

una soluzione prova a mettere continue; al posto di break; e togliere e rimodellare i cicli while.


PS: dove hai letto che bisogna mettere in una funzione che non ha parametri il costrutto "void"? essendo che molti non lo fanno...e che è molto corretto.

kokoko1
"ham_burst":
guarda vista l'ora vado un po' a naso :-)

per la stampa consecutiva "nome articolo: quantita: " posso ipotizzare che sia il compilatore che ti abbia riordinato il codice, o essendo che c'è fgets(), ed essendo che c'è una questione sotto di apertura e chiusura di stdout, penso che la stampa a video sia "più veloce" di fgets()...solo ipotesi.

poi qua rivedendo il codice il while nella funzione get_menu_scelta() è inutile, essendo che c'è pure nel main. Devi scegliere come disegnare il tuo codice, o crei una funzione o usi il while in modo migliore.
per il "count-to-infinite" mi sembra sia colpa del break; per via di scoping.

una soluzione prova a mettere continue; al posto di break; e togliere e rimodellare i cicli while.


PS: dove hai letto che bisogna mettere in una funzione che non ha parametri il costrutto "void"? essendo che molti non lo fanno...e che è molto corretto.

Allora, per quanto riguarda il "count-to-infinite" ho risolto togliendo il ciclo while in scelta=get_menu_scelta() come mi hai fatto notare tu.
Per quanto riguarda il problema di stampa "nome articolo: quantita: ", confermo che sia un problema di "velocità". Infatti ho provato a sostituire fgets() con uno scanf e non mi ha dato nessun problema! Sapresti come risolvere il problema con fgets()?
PS: se non sbaglio credo di averlo letto su una guida di programmazione su internet XD

apatriarca
DEV-C++ E' UNO DEI PEGGIORI IDE GRATUITI DISPONIBILI ATTUALMENTE SU WINDOWS E LA VERSIONE DEL COMPILATORE CHE CONTIENE E MOLTO DATATA E POCO STANDARD!!! L'ultima versione disponibile è una beta e credo abbia ormai più di 10 anni. Fatti quindi un favore e inizia ad usare un programma migliore (anche se potresti avere problemi con il codice di certi prof).

Venendo al quesito del void. In C,
int funzione();

e
int funzione(void);

hanno effettivamente significati diversi, ma questa differenza non c'è nel C++ e scommetto che la maggior parte dei programmatori C non la conosce. Il primo è infatti il prototipo di una funzione che ha un numero qualsiasi di parametri, mentre il secondo non ne può avere nessuno. La differenza ha comunque solo senso a livello di prototipo della funzione e spesso viene usato il primo per indicare il secondo. In effetti nel C++ hanno eliminato questa differenza che a mio parere è solo utile a rendere il codice meno leggibile.

Per quanto riguarda invece fgets, è generalmente buona norma non mischiare scanf e fgets perché hanno un comportamento un po' diverso e poco compatibile. Se proprio vuoi usare fgets in questo modo è buona norma eliminare gli eventuali spazi e caratteri di "a capo" ancora presenti nel buffer (scanf li lascia nel buffer). Credo sia a questo punto più semplice usare scanf però. Magari inserendo la lunghezza del buffer tra % e s. "%10s" legge per esempio una stringa di al massimo 10 caratteri come spiegato ad esempio alla pagina http://www.cplusplus.com/reference/clib ... dio/scanf/

hamming_burst
ma questa differenza non c'è nel C++ e scommetto che la maggior parte dei programmatori C non la conosce.

Ah non sapevo che nel C++ non ci fosse più, interessante.
E confermo che molti non sanno la differenza, a me è stata spiega dal docente di sistemi operativi in sede di esame mentre mostravo un progetto...si impara sempre qualcosa, in ogni occasione :-)
Ma però la forma con il "void" da come l'hanno spiegata a me, da alcune sicurezze (sicurezze statiche a mio dire) in più in fase di compilazione di codice per il kernel di un sistema operativo (scritto in C)....

kokoko1
"apatriarca":
DEV-C++ E' UNO DEI PEGGIORI IDE GRATUITI DISPONIBILI ATTUALMENTE SU WINDOWS E LA VERSIONE DEL COMPILATORE CHE CONTIENE E MOLTO DATATA E POCO STANDARD!!! L'ultima versione disponibile è una beta e credo abbia ormai più di 10 anni. Fatti quindi un favore e inizia ad usare un programma migliore (anche se potresti avere problemi con il codice di certi prof).

Venendo al quesito del void. In C,
int funzione();

e
int funzione(void);

hanno effettivamente significati diversi, ma questa differenza non c'è nel C++ e scommetto che la maggior parte dei programmatori C non la conosce. Il primo è infatti il prototipo di una funzione che ha un numero qualsiasi di parametri, mentre il secondo non ne può avere nessuno. La differenza ha comunque solo senso a livello di prototipo della funzione e spesso viene usato il primo per indicare il secondo. In effetti nel C++ hanno eliminato questa differenza che a mio parere è solo utile a rendere il codice meno leggibile.

Per quanto riguarda invece fgets, è generalmente buona norma non mischiare scanf e fgets perché hanno un comportamento un po' diverso e poco compatibile. Se proprio vuoi usare fgets in questo modo è buona norma eliminare gli eventuali spazi e caratteri di "a capo" ancora presenti nel buffer (scanf li lascia nel buffer). Credo sia a questo punto più semplice usare scanf però. Magari inserendo la lunghezza del buffer tra % e s. "%10s" legge per esempio una stringa di al massimo 10 caratteri come spiegato ad esempio alla pagina http://www.cplusplus.com/reference/clib ... dio/scanf/

Allora vedrò di cambiare ide se possibile.. :-)
Per quanto riguarda la spiegazione del "void" sei stato chiarissimo come sempre :wink:
Tornando al programma, ho provato come hai detto tu con lo scanf e inserendo "%21s", mi da problemi solo quando inserisco uno "spazio" , ritorna il "count-to.infinite" :?
Come potremmo risolvere?
Se non avessi bisogno di questi "spazi" avremmo già risolto il problema...
Ti ringrazio comunque per la disponibilità che mi stai dando, penso sia stressante per te sentirti fare in continuo domande...

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