mercoledì 1 dicembre 2010

Testo esercitazione 3

Come anticipato a lezione pubblico il testo dell'esercitazione 3 che non abbiamo svolto per i noti motivi legati alla legge Gelmini.
I primi tre esercizi sono estremamente semplici (dovete semplicemente scrivere le funzioni richieste e verificarne il funzionamento corretto con un programma di esempio).
Il quarto e quinto esercizio servono a capire la differenza fra passaggio per valore e passaggio per riferimento (secondo la sintassi introdotta dal C++). E' importante capire la differenza non solo dal punto di vista sintattico del linguaggio ma in termini di approccio totalmente diverso.
L'esercizio 6 serve ad acquisire dimistichezza con l'overloading di funzioni e i template di funzione.
Gli esercizi 7, 8 e 9 invece prevedono la scrittura di funzioni che ricevono array come parametri. Nell'esercizio 8 per l'ordinamento del vettore potete utilizzare qualsiasi algoritmo conoscete o avete gia' a disposizione.

Provate a svolgere l'esercitazione e se avete dubbi o suggerimenti scriveteli sul blog in modo da rendere partecipi i vostri colleghi. Ricordate che i vostri dubbi probabilmente sono anche dubbi di altri colleghi quindi non esitate a renderli pubblici. Io cerchero' di chiarirli per quanto possibile o sul blog stesso o riprendendo gli argomenti a lezione.

Buon lavoro.

25 commenti:

  1. Salve prof. avendo fatto java non so bene quale funzione utilizzare per creare 10 numeri casuali interi compresi fra 1 e 100 (esercizio 8).. ho utlizzato srand(time(0)); va bene lo stesso?
    Per l'esercizio n°9 non so bene come funziona rand(), e quindi cm utilizzarlo!!
    Cordiali saluti,
    Eliseo Simonelli.

    RispondiElimina
  2. In realta' srand(time(0)) serve a inizializzare il generatore di numeri casuali e la devi chiamare una sola volta a inizio programma.
    rand() invece restituisce un numero casuale fra 0 e 32767, esattamente come il metodo nextInt(32767) della classe Random di Java.
    Per generare un numero fra 1 e 100 puoi usare rand()%100+1

    RispondiElimina
  3. Questo commento è stato eliminato dall'autore.

    RispondiElimina
  4. Il vostro collega Gabriele, che poi ha eliminato il suo post, aveva scritto essenzialmente la stessa cosa che ho scritto io.
    Vi invito per il futuro a rispondere liberamente alle domande dei colleghi (e non cancellare i post anche dopo che intervengo io). Questo spazio sara' realmente utile quando si innescheranno dinamiche di domande e risposte anche fra di voi e non soltanto fra voi e me.

    RispondiElimina
  5. Ops.. ho cancellato il post perchè praticamente diceva le stesse cose scritte da lei ma con un minuto di ritardo. Mi sembrava ridondante, mi scusi per la cancellazione.

    RispondiElimina
  6. Professore ho un problema riguardo il sesto esercizio quando bisogna creare una funzione template per minimo. Il compilatore dà errore dicendo:
    "C:\Dev-Cpp\Progetti\main.cpp call of overloaded `min(int&, int&)' is ambiguous "

    qui il codice:
    http://nopaste.info/2e1d0c1e7d.html

    RispondiElimina
  7. Aggiorno la situazione...ho risolto grazie al suggerimento di Luca scoprendo infatti che min è una funzione già esistente nel linguaggio C++.
    http://www.cplusplus.com/reference/algorithm/min/

    Basta quindi cambiare il nome della funzione.

    RispondiElimina
  8. Ho avuto dei problemi sull'utilizzo in generale del valore di default.
    Facendo uso di dichiarazione e definzione di funzioni non so in quale delle due è più corretto metterlo, . Il professore mi pare abbia detto che è indifferente. Solo nel momento in cui vado a utilizzare la funzione per testare il valore di default (indifferentemente se uso o no i file separati per le funzioni) se questo si trova nella dichiarazione riesco a compilare, mentre nn ci riesco se lo metto nella definizione della funzione.
    Potrei avere dei chiarimenti in proposito?
    Giuseppe Di Fatta

    RispondiElimina
  9. @Jaywazz89
    Da quanto ho capito l'indicazione del(dei) parametro(i) di default va messo "alla fine" della lista dei parametri formali, e vanno indicati nel prototipo; se li imposto solo nella definizione della funzione mi da errore; se imposto un default in entrambi, lo stesso mi da errore, perlomeno con g++ 4.4.3 su Linux.

    RispondiElimina
  10. Approfitto dei post di O.Scicolone per un chiarimento e un suggerimento. Il codice di O.Scicolone non funzionava perche' usava il simbolo min che e' gia' usato nella libreria standard. Tuttavia gli spazi dei nomi sono stati introdotti proprio per limitare questi problemi rendendo visibili di una libreria solo i simboli che decidiamo noi.
    O.Scicolone evidentemente nel suo programma aveva usato:
    using namespace std;
    importando cosi' TUTTI i simboli di std, fra cui min e tanti altri che non usa.
    Se avesse scritto:
    using std::cout;
    using std::endl;
    il programma non avrebbe avuto problemi in quando il simbolo min non sarebbe stato importato ed sarebbe stato disponibile per essere utilizzato dal programmatore.

    RispondiElimina
  11. Bene, vedo con piacere che il blog si comincia ad animare. Rispondo a Jaywazz89 e RollerBitch (evitate commenti sul nickname del/della collega, ognuno si sceglie il nickname che vuole...)
    Gli argomenti di default, che come precisato da RollerBitch devono essere alla fine della lista dei parametri, normalmente devono essere specificati nel prototipo. Gli argomenti di default possono essere messi direttamente nella definizione della funzione solo nel caso in cui questa si trova prima del main e quindi non ha prototipo. Per intenderci e' corretto il seguente programma:

    void fun(int x = 0) {
    cout << x;
    }

    int main() {
    fun(5); // stampa 5
    fun(); // stampa 0
    }

    cosi' come e' corretto anche questo:

    void fun(int x = 0);

    int main() {
    fun(5); // stampa 5
    fun(); // stampa 0
    }

    void fun(int x = 0) {
    cout << x;
    }

    Sarebbe sbagliato in ogni caso mettere valori di default (anche se identici) sia nel prototipo che nella funzione.

    RispondiElimina
  12. Ho specificato gli argomenti di default così:
    http://nopaste.info/89470d74c2.html (quindi solo nel prototipo).
    Ora, mi sorgono alcuni dubbi e vorrei sapere se:
    a) un template conviene scriverlo come le altre funzioni (prototipo_template -> main() -> template_completo)?
    b) come faccio a dare i valori di default (a tempo di esecuzione) dal momento che con lo spazio o con invio non ne vuole sapere? Ho provato con "\n" ma oltre alla funzione double le altre due mi danno valori di default improponibili.

    RispondiElimina
  13. ehm chiedo scusa, ma è il nick del profilo Google :)

    Comunque è proprio con i codici come il secondo da lei postato, professore, che ricevo l'errore in compilazione


    "12: error: default argument given for parameter 1 of ‘void fun(int)’
    ire.cpp:4: error: after previous specification in ‘void fun(int)’

    Questa è precisamente la risposta che ottengo dal codice da lei postato (con l'include e il return del main); credo di essere io a non capire bene: il codice in questione non dichiara lo stesso argomento di default sia nel prototipo che nella definizione di fun()?

    RispondiElimina
  14. @Gabriele:
    in realta' nel codice che hai linkato i parametri di default li hai specificati sia nel prototipo che nell'implementazione del template e, con mia sorpresa, ho notato che col mio compilatore (g++ 4.2.1, MacOS X 10.6.5) compila regolarmente anche se in pratica usa quelli del prototipo ignorando quelli dell'implementazione del template. Una cosa del genere con funzioni normali non avrebbe neanche compilato.
    a) le funzioni template si usano per piccoli compiti e di solito conviene implementarle direttamente prima del main senza usare prototipi. Del resto le funzioni template hanno regole un po' diverse, ad esempio non puoi usare il template in un file e mettere l'implementazione della funzione template in un altro file come si fa normalmente per tutte le altre funzioni.
    b) non ho capito che vuoi dire... se intendevi nell'input da tastiera, cioe' scrivi cin >> x >> y; ne inserisci uno solo e ti aspetti che al secondo venga assegnato un valore di default allora la risposta e' che non si puo' fare.

    RispondiElimina
  15. @RollerBitch:
    hai ragione, nel copia e incolla mi e' scappato un =0 di troppo... il codice pubblicato non compila perche' mette i valori di default sia nel prototipo che nell'implementazione. Il codice corretto e' il seguente:

    void fun(int x = 0);

    int main() {
    fun(5); // stampa 5
    fun(); // stampa 0
    }

    void fun(int x) {
    cout << x;
    }

    RispondiElimina
  16. Lei ha ragionissima. Le ho postato un link sbagliato, perchè mentre scrivevo il messaggio ho modificato il programma specificando i parametri di default solo nel prototipo del template e non nella sua implementazione.

    Si, era quello che intendevo io. Però, cosa strana, se per esempio immetto "\n" come valore di uno dei due double mi restituisce 0.0 come minimo, ma in int e float (uso i float per impiegare il template) mi escono numeri inconsistenti. Onestamente non ne ho capito il motivo.

    RispondiElimina
  17. Prof. ho un'altra domanda a proposito del codice di gabriele: è normale che su Linux la funzione system() non venga riconosciuta? (non è inclusa tra le funzioni predefinite di g++ suppongo)
    In tal caso, quale file d'intestazione devo includere per ottenerla?

    grazie

    RispondiElimina
  18. @Gabriele, ho provato a fare quello che dici utilizzando il tuo codice.
    Se inserisci un numero minore di zero come primo double ti dà quel numero come minimo, ma se il primo numero è maggiore di 0 allora ti dà 0 come minimo, questo xkè(a parte il fatto che è sbagliato dare \n come input su un double, perchè è di tipo carattere, di fatto ti riempie tutto lo stream di input che segue) evidentemente il carattere \n è tale che considerandolo come double il primo valore che finisce sullo stream di input è uno zero, che quindi viene assegnato alla tua seconda variabile double. Motivo per cui quando inseriamo dei valori con il cin dobbiamo stare molto attenti sul valore che andiamo ad inserire.

    RispondiElimina
  19. @RollerBitch:
    http://bytes.com/topic/c/answers/223320-system-pause-linux

    "The only use I've seen for this in Windows programs is to work around the horrible broken terminal emulator that comes with Windows. You won't have that problem on Linux: the emulator is not going to close when your program terminates, so this is pointless."

    Da quel che ne ho capito è sistema dipendente e nel caso di linux è inutile perchè la shell non si chiude al termine del programma.

    @Jaywazz89:
    Grazie mille. Ricontrollando il codice a mente serena e dopo il tuo commento, mi è tutto molto più chiaro :P

    RispondiElimina
  20. Ok gabriele grazie, credevo system(pause) facesse qualcosa di più particolare; in questo caso, è superflua.

    RispondiElimina
  21. Vedo che vi siete gia' chiariti abbastanza correttamente fra di voi, dico comunque la mia per completezza.
    @Gabriele, @Jaywazz89: non basatevi mai su come l'operatore >> interpreta dati che non sono del tipo aspettato in quanto il comportamento e' piuttosto aleatorio.
    @Gabriele, @RollerBitch: la funzione int system(char[]) e' definita in cstdlib (la trovate gia' inclusa perche' iostream include a sua volta cstdlib) e semplicemente esegue il comando che riceve come parametro. Il comando puo' essere qualsiasi cosa che potete dare da riga di comando. Ad esempio in Linux system("ls"); vi stampa l'elenco della directory corrente, in Windows system("dir"); farebbe la stessa cosa. system("PAUSE"); sotto Linux non funziona perche' non c'e' il comando PAUSE.

    RispondiElimina
  22. Grazie prof. della precisazione ma in quel caso non dovrei ottenere un errore a run-time di comando non trovato? invece ottengo un "funzione system non dichiarata".
    Però se come dice lei oltre a iostream includo anche cstdlib funziona.
    é come se iostream non includesse cstdlib

    PS: Ho controllato in iostream in /usr/include/c++/ecc.. e include solo istream, ostream e bits/c++config.h. In cstdlib non è definita direttamente system ma dovrei seguire tutta la catena degli include per verificare. Forse su Linux il comportamento è diverso?

    grazie

    RispondiElimina
  23. @RollerBitch:
    esatto nel caso in cui usi system("pause") ad esempio su MacOS X, e hai messo le include corrette, il programma compila e a run-time di da un errore, non fatale, e il messaggio "comando non trovato".
    Per quanto riguarda le include corrette la documentazione della libreria standard dice che system e' definita in cstdlib ed e' quindi quello l'include da inserire nel codice. Il fatto che in alcuni sistemi iostream includa cstdlib non e' garantito e dipende dalla versione della libreria.

    RispondiElimina
  24. Ah perfetto, grazie del chiarimento.

    RispondiElimina