View Full Version : [C] menu + switch
negator136
30-10-2005, 10:24
ciao a tutti
sto facendo un programma in grado di calcolare le soluzioni di equazioni di secondo grado.
il programma l'ho fatto tranquillamente ma ora vorrei (su consiglio del prof...) complicarlo un po', giusto per sperimentare qualche nuova funzione che ho imparato.
in pratica voglio mettere il menu, che chiede quale dipo di equazionie risolvere, in una funzione esterna al main.
sto lavorando con tre file distinti: 1. il programma, 2. la mia libreria di funzioni, 3. il file con le intestazioni.
questo è il codice del programma:
#include <stdio.h>
#include <math.h>
#include "funzioni.c"
int main()
{
cleanScreen();
while(grade_menu==grade_menu){
menu();
switch (grade_menu){
case '1': /*Risoluzione equazione di primo grado*/
eq1grado();
break;
case '2': /*Risoluzione equazione di secondo grado*/
eq2gradoCompl();
break;
case '0': /*Uscita*/
printf("\n");
return 0;
}
}
return 0;
}
questa è la funzione del menu:
void menu(void)
{
printf("\n*** RISOLUTORE DI EQUAZIONI ***\n");
printf("\nSelezionare il tipo di equazione che si desidera risolvere:\n");
printf("\n\t1) Primo grado\n");
printf("\n\t2) Secondo grado\n");
printf("\n\t0) Esci\n\n");
grade_menu=getchar();
}
questa è parte del file delle intestazioni:
int grade_menu;
void menu(void);
a me il codice sembra corretto... eppure l'esecuzione da dei problemi... in particolare questa è una prova di esecuzione:
*** RISOLUTORE DI EQUAZIONI ***
Selezionare il tipo di equazione che si desidera risolvere:
1) Primo grado
2) Secondo grado
0) Esci
2
Si vuole risolvere l'equazione di secondo grado del tipo: AX^2 + BX + C = 0
Inserire A: 2
Inserire B: -4
Inserire C: 2
Le soluzioni sono coincidenti e valgono 1.00
*** RISOLUTORE DI EQUAZIONI ***
Selezionare il tipo di equazione che si desidera risolvere:
1) Primo grado
2) Secondo grado
0) Esci
*** RISOLUTORE DI EQUAZIONI ***
Selezionare il tipo di equazione che si desidera risolvere:
1) Primo grado
2) Secondo grado
0) Esci
1
Si vuole risolvere l'equazione di primo grado del tipo: AX + B = 0
Inserire A: 3
Inserire B: -6
La soluzione e'2.00
*** RISOLUTORE DI EQUAZIONI ***
Selezionare il tipo di equazione che si desidera risolvere:
1) Primo grado
2) Secondo grado
0) Esci
*** RISOLUTORE DI EQUAZIONI ***
Selezionare il tipo di equazione che si desidera risolvere:
1) Primo grado
2) Secondo grado
0) Esci
0
ale@debian:~/Programmi C/bo$
1. perchè ogni volta che finisce una risoluzione mi fa comparire DUE volte il menu anzichè UNA?!?
2. la condizione del "while" è un po' stupida... avete consigli a riguardo? magari anche sostituire il while con un'altra funzione elementare equivalente...
lo so, visto così sembra un lavoro in utile, visto che avrei potuto semplicemente lasciare come condizione del while un grade=getchar() e il menu all'interno della funzione, ma vorrei capire perchè non funziona...
grazie in anticipo a chi mi risponderà :)
DanieleC88
30-10-2005, 11:50
1. perchè ogni volta che finisce una risoluzione mi fa comparire DUE volte il menu anzichè UNA?!?
Credo sia dovuto al fatto che quel getchar() in menu(), la prima volta, ritorna con un valore che a te non serve, rimasto dall'ultima pressione di un tasto (ASCII: 10+13).
Metti un bel: "while (getchar() != 0);" prima di "grade_menu=getchar();" in menu().
2. la condizione del "while" è un po' stupida... avete consigli a riguardo? magari anche sostituire il while con un'altra funzione elementare equivalente...
:D
while (1) {
}
;)
leadergl
30-10-2005, 11:59
Il tuo problema sta qui:
void menu(void)
{
printf("\n*** RISOLUTORE DI EQUAZIONI ***\n");
printf("\nSelezionare il tipo di equazione che si desidera risolvere:\n");
printf("\n\t1) Primo grado\n");
printf("\n\t2) Secondo grado\n");
printf("\n\t0) Esci\n\n");
grade_menu=getchar();
}
o meglio qui:
grade_menu=getchar();
perchè quando tu vai ad inserire "1" ad esempio lui nel buffer dello "stdin" rimane "1\n" ovvero anche il tuo enter e quindi ti carica due volte la schermata perchè analizza anche gli altri caratteri...
puoi:
1) usare:
char c;
scanf("%s",&c); /*so che dovrebbe essere "%c" ma poi da lo stesso errore*/
/* che invece non si presenta mettendo "%s"*/
2) usare "fflush(stdin);" per svuotare il buffer di "stdin" (devi inserire la funzione prima di grade_menu=getchar();
3) usare: while (getchar()!='\n'); sempre prima del tuo getchar();
altro non so...è da poco che uso il C.
cmq usa la soluzione 1 ;)
negator136
30-10-2005, 15:51
grazie per le risposte :) grazie a voi sono riuscito a risolvere qualcosa...
anche se ho ancora molti problemi...
aggiorno il file principale:
#include <stdio.h>
#include <math.h>
#include "funzioni.c"
int main()
{
cleanScreen();
while(1){
menu3opzioni('t','s','A','B','C');
switch (grade_menu){
case '1': /*Risoluzione equazione di primo grado*/
eq1grado();
break;
case '2': /*Risoluzione equazione di secondo grado*/
eq2gradoCompl();
break;
case '0': /*Uscita*/
printf("\n");
return 0;
}
}
return 0;
}
ecco quello delle funzioni:
void menu3opzioni(char titolo, char sottotitolo, char opzioneA, char opzioneB, char opzioneC)
{
printf("\n%c", titolo);
printf("\n%c", sottotitolo);
printf("\n%c", opzioneA);
printf("\n%c", opzioneB);
printf("\n%c", opzioneC);
printf("\n\n");
do {
scanf("%s", &grade_menu);
check('3', grade_menu);
} while (grade_menu != grade_check);
}
void check(char numero_opzioni, char valore_immesso){
if ((valore_immesso >= 0) && (valore_immesso < numero_opzioni)) {
grade_check = valore_immesso;
}
else {
printf("Scelta non valida. Inserire un nuovo valore.\n");
grade_check = -1;
}
}
ed infine l'intestazione:
char grade_menu;
char grade_check;
void eq1grado(void);
void eq2grado(void);
float delta(float e,float f,float g);
void eq2gradoCompl(void);
void menu3opzioni(char titolo, char sottotitolo, char opzione1, char opzione2, char opzione0);
void check(char numero_opzioni, char valore_immesso);
come vedete ho creato una funzione menù generica, i cui parametri d'ingresso dovrebbero essere i testi del titolo e delle opzioni... il fatto è che mi viene solo con dei caratteri e non con delle stringhe... idee?
io pensavo di mettere al posto di "char" l'equivalente per le stringhe ma poi ho pensato che probabilmente non esiste...
il secondo problema, più grave, è il fatto che impostando grade_menu e grade_check come char, nella funzione che controlla se il valore appartiene all'intervallo non riesco a fare in modo che mi escluda i valori negativi... anche qui, avete idee?
grazie mille :)
leadergl
30-10-2005, 16:30
il problema sta qua:
void menu3opzioni(char titolo, char sottotitolo, char opzione1, char opzione2, char opzione0);
se sono dichiarate come "char" perche ti dovrebbe visualizzare delle stringhe!?
in C:
char carattere; /* dichiarazione carattere */
char stringa[10]; /* dichiarazione per stringhe (da 0 a 9) */
negator136
30-10-2005, 17:37
il problema sta qua:
void menu3opzioni(char titolo, char sottotitolo, char opzione1, char opzione2, char opzione0);
se sono dichiarate come "char" perche ti dovrebbe visualizzare delle stringhe!?
in C:
char carattere; /* dichiarazione carattere */
char stringa[10]; /* dichiarazione per stringhe (da 0 a 9) */
void menu3opzioni(char titolo[30], char sottotitolo[30], char opzione1[30], char opzione2[30], char opzione0[30]);
quindi così dovrei risolvere, giusto?
ero convinto di averci già provato... vabbè... avrò sbagliato qualcosa :) grazie
per l'altro problema? :(
negator136
31-10-2005, 09:29
HELP vi prego!! :muro:
intanto ho avuto un idea...
come posso fare in modo che il programma acquisisca un solo carattere e poi proceda da solo senza dover premere invio?
in questo modo risolverei due problemi:
- eviterei di dover controllare che i numeri immessi siano positivi, visto che non potrei più immettere "-" e "numero"...
- potrei controllare nella stessa funzione tutti i caratteri ascii... lettere e simboli compresi, dal momento che ho impostato le variabili in ingresso come char.
dai che ci siamo quasi :)
grazie :)
17Qwerty71
31-10-2005, 12:48
HELP vi prego!! :muro:
intanto ho avuto un idea...
come posso fare in modo che il programma acquisisca un solo carattere e poi proceda da solo senza dover premere invio?
in questo modo risolverei due problemi:
- eviterei di dover controllare che i numeri immessi siano positivi, visto che non potrei più immettere "-" e "numero"...
- potrei controllare nella stessa funzione tutti i caratteri ascii... lettere e simboli compresi, dal momento che ho impostato le variabili in ingresso come char.
dai che ci siamo quasi :)
grazie :)
Utilizzi la funzione getch e la putch.
Se vuoi far stampare solo i numeri da 0 a 1 fai in questo modo
for(i=0; c= getch() && i < 1; i++)
if(c >= '0' && c <= '1'){
putch(c);
numero = c - '0';
}
else
i--;
}
Così facendo l'utente è costretto ad immettere un solo carattere (i < 1), il quale deve essere compreso tra 0 e 1. Se così fosse il carattere viene stampato e immesso nella variabile intera "numero" (con c - '0' la converti praticamente).
Nel caso digitasse altri caratteri il contatore (i) va indietro di uno e il ciclo viene rieseguito. :)
negator136
31-10-2005, 16:18
(con c - '0' la converti praticamente)
ti ringrazio per la risposta. ora provo a metterla in pratica...
potresti spiegarmi meglio la frase che ho quotato?
non capisco perchè in qual modo dovrebbe convertirmi la variabile da char a int :muro:
thanks
17Qwerty71
31-10-2005, 16:58
ti ringrazio per la risposta. ora provo a metterla in pratica...
potresti spiegarmi meglio la frase che ho quotato?
non capisco perchè in qual modo dovrebbe convertirmi la variabile da char a int :muro:
thanks
No, vabbe tu poi potresti non convertirla (quindi assegnare numero = c), ma poi nel controllo successivo, quello per la scelta del menù in pratica, metti come condizione (numero == 'uno_dei_tre_possibili numeri')
Essendo un carattere (ricevuto da tastiera) con getch tu vai a memorizzare nella variabile c il codice ascii del corispettivo tasto premuto. In questo modo quando tu per esempio premi 1, la variabile c assumerà il valore del codice ascii del nuemero 0 incrementato di 1 (ovvero 49 se non erro).
Così facendo nell'esempio che ti avevo fatto la variabile intera numero verra a trovarsi non il codice ascii, ma il numero convertito.
Quindi al controllo che occorre fare successivamente invece di confrontare la variabile numero al corispettivo ascii, la confronti con l'ascii convertito. :)
Non so' se si capisce come ho scritto :stordita:
negator136
31-10-2005, 17:40
No, vabbe tu poi potresti non convertirla (quindi assegnare numero = c), ma poi nel controllo successivo, quello per la scelta del menù in pratica, metti come condizione (numero == 'uno_dei_tre_possibili numeri')
Essendo un carattere (ricevuto da tastiera) con getch tu vai a memorizzare nella variabile c il codice ascii del corispettivo tasto premuto. In questo modo quando tu per esempio premi 1, la variabile c assumerà il valore del codice ascii del nuemero 0 incrementato di 1 (ovvero 49 se non erro).
Così facendo nell'esempio che ti avevo fatto la variabile intera numero verra a trovarsi non il codice ascii, ma il numero convertito.
Quindi al controllo che occorre fare successivamente invece di confrontare la variabile numero al corispettivo ascii, la confronti con l'ascii convertito. :)
Non so' se si capisce come ho scritto :stordita:
ho capito quello che hai detto e ti ringrazio per la spèiegazione :)
purtroppo però sono troppo imbranato e non sono riuscito a mettere in pratica ciò che mi hai detto di fare...
resta il problema che se inserisco un numero negativo, o una coppia di caratteri, la funzione "check" non da il risultato sperato (frase di errore), bensì mi rimanda all'inizio della funzione menu... :muro:
queste sono le due funzioni allo stato attuale... come dovrei modificarle esattamente?
preferirei lasciare le funzioni divise, in modo da poter riutilizzare la "check" anche per menu più grandi...
void menu3opzioni(char titolo[60], char sottotitolo[60], char opzioneA[60], char opzioneB[60], char opzioneC[60]) {
printf("\n%s", titolo);
printf("\n%s", sottotitolo);
printf("\n%s", opzioneA);
printf("\n%s", opzioneB);
printf("\n%s", opzioneC);
printf("\n\n");
do {
scanf("%s", &grade_menu);
check('3', grade_menu);
} while (grade_menu != grade_check);
}
void check(char numero_opzioni, char valore_immesso) {
if ((valore_immesso >= 0) && (valore_immesso < numero_opzioni)) {
grade_check = valore_immesso;
}
else {
printf("Scelta non valida. Inserire un nuovo valore.\n");
grade_check = -1;
}
}
nel frattempo, vi pongo un altro quesito: come faccio a creare una funzione che mi stampi "Premere INVIO per proseguire" e che faccia proprio quello che dice? :D
io ho scritto questa ma, giustamente, prima dell'invio si aspetta l'immissione di un carattere...
void wait(void){
int invio;
printf("Premere INVIO per proseguire");
scanf("%d", &invio);
}
perdonate la mia ignoranza... ma sono proprio niubbo...
grazie mille di nuovo :)
17Qwerty71
31-10-2005, 18:23
nel frattempo, vi pongo un altro quesito: come faccio a creare una funzione che mi stampi "Premere INVIO per proseguire" e che faccia proprio quello che dice? :D
io ho scritto questa ma, giustamente, prima dell'invio si aspetta l'immissione di un carattere...
void wait(void){
int invio;
printf("Premere INVIO per proseguire");
scanf("%d", &invio);
}
perdonate la mia ignoranza... ma sono proprio niubbo...
grazie mille di nuovo :)
Praticamente fai la stessa cosa che hai fatto con getch per ricevere i numeri del menù
while(getch() != '\r') ;
In pratica questo ciclo continua ad eseguire il ciclo (e quindi a chiederti un carattere) fino a che tu non premi invio (che nell'ascii corrisponde al numero 13 o semplicemente '\r').
Forse ti chiederai, il carattere di andare a capo non era '\n'?
Si anche quello, ma quando si va a capo linea (e quidni si preme invio) la tastiera invia due caratteri, il '\r' che va all'inizio della riga e subito dopo il '\n' che va nella riga sotto. Fatto stà quindi che occorre controllare se viene ad esserci il carattere '\r' e non '\n'. :)
DanieleC88
01-11-2005, 09:05
[CODE]do {
scanf("%s", &grade_menu);
check('3', grade_menu);
} while (grade_menu != grade_check);
Non usare "%s" con tanta leggerezza. È il metodo più veloce, ma anche quello più sbagliato. In questo modo il tuo programma non aspetterà la sola pressione dii un tasto, leggerà un'intera stringa. Stringa che potrebbe anche essere molto grande e causare buffer overflow. Spiego meglio: una stringa viene salvata in memoria in un indirizzo ed è costituita da una serie di caratteri terminata dal carattere nullo (con valore ASCII zero). Potresti scrivere una stringa anche così:
char stringa[5] = {'h', 'e', 'l', 'l', 'o', 0};
Insomma, quando tu chiami scanf in quel modo, scanf riempirà un numero di caratteri corrispondente alla lunghezza della stringa immessa nella memoria che ha come inizio l'indirizzo della variabile grade_menu (che però conterrà solo un carattere quando la leggerai, perché la dimensione è char). In questo modo, se hai altre variabili con un indirizzo vicino, rischi di modificare anche quelle. Per il tuo programma potrebbe non essere una cosa molto importante, ma per cose più complesse sarebbe un rischio serio per la stabilità.
ciao ;)
17Qwerty71
01-11-2005, 14:01
Non usare "%s" con tanta leggerezza. È il metodo più veloce, ma anche quello più sbagliato. In questo modo il tuo programma non aspetterà la sola pressione dii un tasto, leggerà un'intera stringa. Stringa che potrebbe anche essere molto grande e causare buffer overflow. Spiego meglio: una stringa viene salvata in memoria in un indirizzo ed è costituita da una serie di caratteri terminata dal carattere nullo (con valore ASCII zero). Potresti scrivere una stringa anche così:
char stringa[5] = {'h', 'e', 'l', 'l', 'o', 0};
Insomma, quando tu chiami scanf in quel modo, scanf riempirà un numero di caratteri corrispondente alla lunghezza della stringa immessa nella memoria che ha come inizio l'indirizzo della variabile grade_menu (che però conterrà solo un carattere quando la leggerai, perché la dimensione è char). In questo modo, se hai altre variabili con un indirizzo vicino, rischi di modificare anche quelle. Per il tuo programma potrebbe non essere una cosa molto importante, ma per cose più complesse sarebbe un rischio serio per la stabilità.
ciao ;)
Una cosa da chiederti. Ma quindi se io dichiaro un'array di 10 char e l'utente ne immette più di tale numero i rimanenti quindi (quelli dopo la 11esima posizione) vengono scritti ugualmente in memoria? :confused:
Pensavo che non venivano presi in considerazione :stordita:
negator136
01-11-2005, 15:13
dal momento che, durante la compilazione, non mi riconosce il comando getch(), ho creato questa funzione...
void wait(void){
printf("Premere INVIO per proseguire");
while(getchar() != '\r');
}
perchè non va? posso premere invio o qualsiasi altro carattere quante volte voglio, ma non esce dal ciclo e non passa alla funzione successiva :muro:
funzione invece in questo modo:
void wait(void){
printf("Premere A e INVIO per proseguire");
while(getchar() != 'a');
}
ma non mi piace perchè non è quello che avevo in mente...
idee? :mc:
DanieleC88
01-11-2005, 16:36
Una cosa da chiederti. Ma quindi se io dichiaro un'array di 10 char e l'utente ne immette più di tale numero i rimanenti quindi (quelli dopo la 11esima posizione) vengono scritti ugualmente in memoria? :confused:
Pensavo che non venivano presi in considerazione :stordita:
Prova tu stesso. ;)
#include <string.h>
#include <stdio.h>
int main(int argc, char * argv[])
{
char prova = '-';
char provetta = '-';
strcpy(&prova, "01");
printf("prova: %c, provetta: %c\n", prova, provetta);
return 0;
}
Come vedi, i due caratteri vengono dichiarati uno di seguito all'altro e vengono inizializzati al carattere '-'. Quando strcpy prova a copiare la stringa "01" nell'indirizzo di "prova" (&prova), il secondo carattere finirà in "provetta".
negator136
01-11-2005, 20:38
dal momento che, durante la compilazione, non mi riconosce il comando getch(), ho creato questa funzione...
void wait(void){
printf("Premere INVIO per proseguire");
while(getchar() != '\r');
}
perchè non va? posso premere invio o qualsiasi altro carattere quante volte voglio, ma non esce dal ciclo e non passa alla funzione successiva :muro:
funzione invece in questo modo:
void wait(void){
printf("Premere A e INVIO per proseguire");
while(getchar() != 'a');
}
ma non mi piace perchè non è quello che avevo in mente...
idee? :mc:
nessuno sa come risolvere questo problema? :(
negator136
02-11-2005, 19:26
up :muro:
DanieleC88
03-11-2005, 14:34
nessuno sa come risolvere questo problema? :(
Semplice: non riceve mai quel carattere, perciò il ciclo non potrà mai terminare. Quando premi "invio", il carattere inviato è '\n', non '\r'. '\n', infatti, significa proprio "new line", indica che il cursore deve scendere di una linea, ed è il carattere generato dalla pressione di "invio". '\r', invece, è il "carriage return", che fa tornare il cursore all'inizio della riga.
Modifica così:
printf("Premere INVIO per continuare...");
while (getchar() != '\n');
ciao ;)
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.