PROBLEMA AIUTO C++ funzione con troppi parametri

Pubblicità

poltronaMAN

Nuovo Utente
Messaggi
3
Reazioni
0
Punteggio
19
buongiorno a tutti,
ho un problema che non riesco a risolvere (se esiste la soluzione). Faccio informatica alle superiori e come argomento siamo arrivati fino alle funzioni (no array, no puntatori, no variabili globali). Ogni volta che il mio prof di informatica fa una verifica, nel main vuole vedere SOLO dichiarazioni di variabili e SOLO funzioni.
Le verifiche che fa sono del tipo:
- richiedi un numero naturale N, richiedi due numeri a e b.
- genera N numeri (con la funzione rand) compresi nell'intervallo a e b. verificare:
- quanti sono quelli positivi e negativi
- quanti sono i multipli di 5 e 4 ma che siano quadrati perfetti
- calcola il cubo e il quadrato degli ultimi 2 numeri generati
eccetera eccetera

il mio prof vuole solo funzioni nel main e vuole che ogni valore ritorni nel main (tipo la variabile contenente il numero dei positivi eccetera). quindi dovrei creare una funzione dove vengono generati i numeri e per ogni numero generato devo fare le mille verifiche. il problema è che così facendo, la funzione si riempie con tantissimi parametri, facendo ritornare il valore delle variabili nel main tramite reference.

esempio:
C++:
#include <iostream>
#include <stdlib.h>
#include <ctime>

using namespace std;

void generazione_numeri(int N, int a, int b, int &positivi, int &negativi, int &multipli_4, int &multipli_5, int &quadrato, int &cubo);

int main()
{
    srand(time(NULL));
    int N, a, b, positivi = 0, negativi = 0, multipli_4, multipli_5, quadrato, cubo;
    generazione_numeri(N, a, b, positivi, negativi, multipli_4, multipli_5, quadrato, cubo);
}

//facciamo finta che abbia già richiesto in input N, a, b con una funzione. (a < b)

bool negativo_positivo(int numero)   //funzione per vedere se il numero è negativo o positivo
{
    if(numero > 0)
        return true;
}

void generazione_numeri(int N, int a, int b, int &positivi, int &negativi, int &multipli_4, int &multipli_5, int &quadrato, int &cubo)   //generazione numeri
{
    int counter = 1;
    int N_generato;
    do
    {
        N_generato = rand()%(b - a + 1) + a;
      
        if(negativo_positivo(N_generato))
            positivi++;
        else
            negativi++;

        //qui metterò le chiamate delle altre funzioni per fare le varie verifiche (ad esempio vedere quanti sono i multipli di 5 e di 4, eccetera)
        //ma, per far ritornare le variabili al main, devo passare i risultati al main tramite reference
        //facendo in questo modo i parametri sono tantissimi!!

        counter++;
    }
    while(counter <= N);
}

non esiste un metodo alternativo? non potendo mettere neanche un "ciclo do while" nel main, mi tocca metterlo nella funzione e passare i parametri nel main!! ma ci sono troppi parametri!!

grazie mille a chiunque riesca ad aiutarmi
 
Solitamente nel main si richiamano funzioni o al limite si crea un loop che mostri un menu (quando si utilizzano interfacce testuali). Comunque visto che è C++ dovresti importare cstdlib.

negativo_positivo puoi anche riscriverla così, magari un nome più appropriato:
C++:
bool is_positivo(int numero)   //funzione per vedere se il numero è negativo o positivo
{
    return numero > 0;
}

Comunque non è corretto il passaggio dei valori. Devi passarli per indirizzo e la funzione chiamata come argomenti deve avere dei puntatori. Puoi anche fare più funzioni e richiamarle da generazione_numeri, ottenendo qui i risultati. Ovviamente, se questa funzione deve restituire i risultati al main, non hai molte altre opzioni (se non fare ciò che stai facendo, o usare array o classi).
Quando arriverete alla OOP scriverete in maniera differente il codice (main compreso). Sempre che non vi abbia detto di spiegare il C++, quando invece lo utilizza come se fosse C (cosa che ahimè, non mi stupirebbe nemmeno, purtroppo).
 
Ciao poltronaMAN,

quello che il tuo professore vuole insegnarvi è di mantenere il flusso logico il più semplice possibile. Questo vuol dire che appena il software diventa un minimo complicato, dovresti sempre avere un'idea di cosa il programma faccia (esteso poi al concetto che una funzione dovrebbe essere il più piccola ed atomica possibile). In questo modo quando leggi cosa fa una funzione (che sia main o altro), sai già che logicamente è corretta, oppure no. Avere una funzione che si chiama "fai la magia qui" con dentro una complessità ciclica, o comunque con più di una ventina di righe, non permette di vedere la logica che conduce gli argomenti al risultato: se quindi la dividi in più sotto-funzioni, allora la logica sarà subito comprensibile, e lo sarà anche quella delle funzioni subordinate.
 
Sempre che non vi abbia detto di spiegare il C++, quando invece lo utilizza come se fosse C (cosa che ahimè, non mi stupirebbe nemmeno, purtroppo).
Quel NULL al posto di un nullptr fa sperare male...
quindi non ci sono metodi alternativi?
L'unico metodo alternativo, come detto da DispatchCode è creare varie funzioni che facciano certi check, come vedere se multiplo ecc, ma in una altra maniera...
C++:
void is_multiplo4(int value, unsigned& container)
{
    if(value % 4 == 0)
        ++container;
}
Eliminando codice nella funzione generatrice.

Comunque a mio vedere gestire così il codice è assurdo. Le operazioni di input dovrebbero essere affidate al main, e non ad una funzione.
 
Lo sbaglio del tuo esempio, come ti e' stato fatto notare, e' quello di creare una sola funzione, che a quel punto non serve a nulla, tanto vale fare tutto nel main().
Lo scopo e' di imparare come strutturare le funzioni. Una funzione deve fare molto poco, deve risolvere solo un piccolo problema. Per esempio , come hai fatto tu, vedere se un numero e' positivo o negativo. Dei passare alla funzione solo i parameteri che le servono. Deve ritornare solo i valori che interessano. In questa maniera si scrive un programma "modulare" che puo' venire facilmente modificato. Lo stesso vale anche nel corpo delle funzioni: cercare sempre di "rompere" blocchi di codice in sezioni che possono essere riscritte come funzioni.
Tra i motivi delle funzione, il principale e' quello di non riscrivere lo stesso codice se cambia SOLO il valore delle variabili: scrivi la funzione e passa le variabili come parametro. Ma il secondo, altrettanto importante, e' di scrivere programmi modulari, che sono piu' facili da capire, da testare, da modificare.

Cio' non toglie che a volte il numero di parametri da passare sia lo stesso grande. in quel caso nella programmazione che lo permette si scrivono "classi", i cui parametri possono essere modificati via proprieta' delle classi stesse. In C, vuole dire che un gruppo di variabili puo' essere collettivamente raggruppato in un gruppo logico, usando il concetto struct (che viene poi espanso nel C++ proprio con le classi, ma qui si diverge). A quel punto passi alle funzioni solo il puntatroe della struct.
 
...
Comunque a mio vedere gestire così il codice è assurdo. Le operazioni di input dovrebbero essere affidate al main, e non ad una funzione.
no, non e' assurdo.
Prendi per esempio il codice
C:
int i;
printf("Entra il valore di 'i': ");
scanf("%d", &i);
che e' corretto in quanto ha solo dichiarazioni e chiamate a funzioni. Tale codice va bene se per esempio non si fa nessun controllo sul valore di ingresso, per esempio deve essere compreso in in intervallo ben definito. Se il numero non e' corretto, devi avvertire l'utente e richiedere un altro numero, quindi hai bisogno di un loop. A quel punto si aggiunge piu' e piu' codice, e a quel punto ha senso scrivere una funzione che fa solo la lettura dei dati, e ne controlla la validita'.
C:
int i;
i = ChiediIlNumero("Entra il valore di 'i': ");
 
Solitamente nel main si richiamano funzioni o al limite si crea un loop che mostri un menu (quando si utilizzano interfacce testuali). Comunque visto che è C++ dovresti importare cstdlib.

negativo_positivo puoi anche riscriverla così, magari un nome più appropriato:
C++:
bool is_positivo(int numero)   //funzione per vedere se il numero è negativo o positivo
{
    return numero > 0;
}

Comunque non è corretto il passaggio dei valori. Devi passarli per indirizzo e la funzione chiamata come argomenti deve avere dei puntatori. Puoi anche fare più funzioni e richiamarle da generazione_numeri, ottenendo qui i risultati. Ovviamente, se questa funzione deve restituire i risultati al main, non hai molte altre opzioni (se non fare ciò che stai facendo, o usare array o classi).
Quando arriverete alla OOP scriverete in maniera differente il codice (main compreso). Sempre che non vi abbia detto di spiegare il C++, quando invece lo utilizza come se fosse C (cosa che ahimè, non mi stupirebbe nemmeno, purtroppo).
no, non e' assurdo.
Prendi per esempio il codice
C:
int i;
printf("Entra il valore di 'i': ");
scanf("%d", &i);
che e' corretto in quanto ha solo dichiarazioni e chiamate a funzioni. Tale codice va bene se per esempio non si fa nessun controllo sul valore di ingresso, per esempio deve essere compreso in in intervallo ben definito. Se il numero non e' corretto, devi avvertire l'utente e richiedere un altro numero, quindi hai bisogno di un loop. A quel punto si aggiunge piu' e piu' codice, e a quel punto ha senso scrivere una funzione che fa solo la lettura dei dati, e ne controlla la validita'.
C:
int i;
i = ChiediIlNumero("Entra il valore di 'i': ");
Eh è vero. Anche utilizzare cout e cin sono chiamate a funzioni (operator<<(ostream&, const tipo&)) ma non so bene cosa intenda il suo professore con "chiamate a funzioni".
Io ad esempio mi immagino un codice così
C++:
int main()
{
    int var1, var2, var3;
    Input(&var1, &var2, &var3);
    Scrivi(Somma(var1, var2, var3);
    return 0;
}

E così va anche bene, ma se dovessi fare input o output da file?
Dovrei aggiungere come parametro un reference ad un oggetto ostream/istream... insomma roba evitabilissima. Anche per un fatto di prestazioni.
 
E così va anche bene, ma se dovessi fare input o output da file?
Dovrei aggiungere come parametro un reference ad un oggetto ostream/istream... insomma roba evitabilissima. Anche per un fatto di prestazioni.
No, devi passare solo il nome del file, magari con la convenzione che se e' una stringa nulla allora leggi da terminale.
Anzi, avere una funzione per leggere i dati e' essenziale se in futuro cambi il posto dove i dati sono inseriti, per esempio in un database. Devi solo cambiare una funzione (Input() nel tuo caso) e il resto del programma rimane inalterato.

Per il fatto "prestazioni" entriamo in un altro campo completamente :) Quando si scrive un programma le prestazioni vanno lasciate per ultime. Il concetto di "premature optimization" e' di solito considerato un no-no dai programmatori.
 
No, devi passare solo il nome del file, magari con la convenzione che se e' una stringa nulla allora leggi da terminale.
Anzi, avere una funzione per leggere i dati e' essenziale se in futuro cambi il posto dove i dati sono inseriti, per esempio in un database. Devi solo cambiare una funzione (Input() nel tuo caso) e il resto del programma rimane inalterato.

Per il fatto "prestazioni" entriamo in un altro campo completamente :) Quando si scrive un programma le prestazioni vanno lasciate per ultime. Il concetto di "premature optimization" e' di solito considerato un no-no dai programmatori.
Fai però conto che voglio utilizzare anche cin e cout e in più voglio mettere dei flag al file, non posso passare la stringa quindi.

Beh insomma secondo me è meglio evitare di rendere una funzione qualsiasi istruzione, è molto ridondante.

Per le prestazioni più che altro dipende se il compilatore la definisce inline o meno.
 
...
Per le prestazioni più che altro dipende se il compilatore la definisce inline o meno.
Le ottimizzazioni vanno fatte alla fine. Per questo e' utile "spezzare" il vodice in piu' funzioni: si fa girare il codice, e si guarda quanto tempo spende in ogni funzione. Quindi si comincia a ottimizzare a partire dalle funzioni piu' "costose". Ossia, inutile ottimizzare una funzione che prende solo il 1% del tempo totale. Ma come ho detto, il discorso ottimizzazione e' molto complesso, merita una discusssione a parte e non ha nulla a che vedere con questa discussione.
 
penso che voi siate programmatori di professione giusto? quando fate un programma quante funzioni usate?

quoto @_Achille : (ultimamente il forum mi sta dando problemi con la quotatura)
nel main, quando si fa la chiamata delle funzioni, non si mette l'operatore & prima delle variabili, perché già messo nei parametri formali.
noi richiediamo l'input dell'utente in questo modo:

C++:
#include <iostream>

using namespace std;

void input_utente(int &numero);

int main()
{
    int n1;
    void input_utente(n1);
}

void input_utente(int &numero)   //inserimento ad esempio di un numero naturale
{
    float r;
    do
    {
        cout << "Inserisci un numero ";
        cin >> r;
        numero = r;
    }
    while(numero != r || numero <= 0);
}

Perché hai detto: Quel NULL al posto di un nullptr fa sperare male... ???
 
Ultima modifica:
Quante funzioni usiamo? Quante bastano :hihi:

Come scritto sopra: funzioni piccole a piacere, che svolgono una logica atomica a piacere. Se solo pensi al flusso logico "fai A, quindi calcola B con A, C con A e B e ritorna D", probabilmente c'è spazio per almeno 4 funzioni. E 4 righe "logiche" che le uniscono tutte.
 
penso che voi siate programmatori di professione giusto? quando fate un programma quante funzioni usate?

quoto @_Achille : (ultimamente il forum mi sta dando problemi con la quotatura)
nel main, quando si fa la chiamata delle funzioni, non si mette l'operatore & prima delle variabili, perché già messo nei parametri formali.
noi richiediamo l'input dell'utente in questo modo:

C++:
#include <iostream>

using namespace std;

void input_utente(int &numero);

int main()
{
    int n1;
    void input_utente(n1);
}

void input_utente(int &numero)   //inserimento ad esempio di un numero naturale
{
    float r;
    do
    {
        cout << "Inserisci un numero ";
        cin >> r;
        numero = r;
    }
    while(numero != r || numero <= 0);
}

Perché hai detto: Quel NULL al posto di un nullptr fa sperare male... ???
In tal caso ho usato i puntatori solo per mostrare che le operazioni venivano eseguite sulle locazioni di var1, var2, var3 e non in una loro copia.

In C++ si usa nullptr non (void*)0

Io non sono un programmatore di professione visto che molto probabilmente ho praticamente la tua stessa età :asd:. Comunque poche, si risolve tutto con metodi e lamda.
 
Ultima modifica:
Io cerco sempre di spezzare il codice in più funzioni possibili, i benefici sono innumerevoli. Scrivere codice modulare ti permette di riciclare lo stesso codice invece di ripeterlo facendo taglia e cuci, che per un programmatore è una pratica da eliminare ed evitare come la peste. Quello è quello che si insegna a scuola, ma i vantaggi possono riempire un libro. Scrivere funzioni generiche è il primo passo per scrivere librerie, ossia raccolte di funzioni che chiami di continuo. Proprio ieri il mio manager mi ha chiesto una modifica in un programma che non scrissi io, per aggiungere qualcosa che ero sicuro avevamo già fatto, infatti il codice era già pronto, mi è bastato includere una nostra libreria nel progetto, chiamarne una funzione, e il gioco era fatto. Lo ho provato senza doverlo controllare perché la libreria era già provata e riprovata. Due minuti dopo ero nell'ufficio del manager dicendo che il lavoro era finito, dammi altro da fare :] impiegai più tempo a scrivere la documentazione.
 
Pubblicità
Pubblicità
Indietro
Top