Uni.LaboratorioC History

Hide minor edits - Show changes to markup

November 08, 2007, at 10:42 PM by Ido -
Changed lines 12-13 from:

Troverete inoltre le risposte - eventualmente commentate dai migliori maghi - alle domande che i suddetti hanno pompato sulle rispettive pagine personali del corso. Leggi le risposte

to:

Troverete inoltre le risposte - eventualmente commentate dai migliori maghi - alle domande che i suddetti hanno pompato sulle rispettive pagine personali del corso.
Leggi le risposte

November 08, 2007, at 10:42 PM by Ido -
Changed line 4 from:

"Non tutte le librerie si possono invocare"
to:

"Non tutte le librerie si possono invocare"
November 08, 2007, at 10:41 PM by Ido -
Changed lines 2-3 from:
 :: Laboratorio C ::
to:
 :: Ambulatorio di C ::

"Non tutte le librerie si possono invocare"

...anche detto Laboratorio di programmazione, conducono Valentina Ciriani e Fabio Scotti.

Changed lines 9-15 from:


Troverete inoltre le risposte - eventualmente commentate dai migliori maghi - alle domande che i suddetti hanno pompato sulle rispettive pagine personali del corso.
Leggi le risposte


to:

Troverete inoltre le risposte - eventualmente commentate dai migliori maghi - alle domande che i suddetti hanno pompato sulle rispettive pagine personali del corso. Leggi le risposte


October 05, 2007, at 03:04 PM by MINCULPOP -
Added lines 2-3:
 :: Laboratorio C ::
October 04, 2007, at 01:46 PM by MINCULPOP -
Changed line 12 from:
to:
June 06, 2007, at 08:56 PM by Dario -
Added line 5:
June 05, 2007, at 01:02 AM by Ido -
Changed lines 6-7 from:

Troverete inoltre le risposte - eventualmente commentate dai migliori maghi - alle domande che i suddetti hanno pompato sulle rispettive pagine personali del corso. Leggi le risposte\\\

to:

Troverete inoltre le risposte - eventualmente commentate dai migliori maghi - alle domande che i suddetti hanno pompato sulle rispettive pagine personali del corso.
Leggi le risposte\\\

June 05, 2007, at 12:42 AM by Ido -
Added line 6:

Troverete inoltre le risposte - eventualmente commentate dai migliori maghi - alle domande che i suddetti hanno pompato sulle rispettive pagine personali del corso. Leggi le risposte\\\

June 04, 2007, at 11:16 PM by Ido -
Deleted line 4:
Added lines 7-8:

June 04, 2007, at 11:11 PM by Ido -
Changed lines 2-327 from:

Qui ci sono le soluzioni agli esercizi dell'ultima lezione, con tanto di commento.

Esercizio 1

Data la traccia sotto riportata completare il codice in modo di aumentare di 1 tutti gli interi pari e diminuire di 1 tutti quelli dispari nell'array vettore[] di dimensione dim. Riportare come risultato il numero che comparira' a monitor. Per esempio un vettore che contiene gli elementi {4,56,3,78,23} dopo essere stato aggiornato deve contenere gli elementi {5,57,2,79,22}. laboratorio 23-24?

 Aumenta interi pari
 #include <stdio.h>

 float CalcolaRisultato(int vettore[], int dim);

 int main() {

    int vettore[] = {4,56,3,78,23}  ;
    int dim = 5;
    int conto;
    float risultato;

    //Se il tuo programma funziona correttamente, dovresti ottenere: 2573

    for (conto = 0; conto < dim; conto ++) {
        if ((vettore[conto] % 2) == 0) vettore[conto] ++;
        else vettore[conto] --;
    }

    risultato = CalcolaRisultato(vettore, dim);
    printf("\nrisultato da copiare ed incollare = %d \n\n" , (int) risultato );
    getchar();
    exit(0);
 }  // main

 float CalcolaRisultato(int vettore[], int dim)
 {
   int i;
   float divisore, dividendo=0;
   for(i=0;i < dim; i++)
   {
      dividendo += i * vettore[i];
   }
   divisore = (dim +1)*dim/2; 
   return 100*dividendo/divisore; 
 }

Note sull'esercizio

Innanzitutto, l'esercizio ti dava un vettore di 462 elementi, mentre qui il vettore ne ha solamente 5.

Il cuore dell'esercizio sta nella sequenza

    for (conto = 0; conto < dim; conto ++) {
        if ((vettore[conto] % 2) == 0) vettore[conto] ++;
        else vettore[conto] --;
    }

che vuol dire esattamente questo:

  for (conto = 0; conto < dim; conto ++)

esamina il vettore dal primo all'ultimo elemento, ricordando che dim = numero elementi del vettore.

   if ((vettore[conto] % 2) == 0) vettore[conto] ++;
   else vettore[conto] --;

If ((vettore[conto] % 2) == 0) controlla se l'elemento conto-esimo del vettore è pari, cioè se il resto della divisione intera per due è 0.

In caso positivo, esegue la riga vettore[conto] ++, come da specifica; in caso contrario invece viene diminuito con vettore[conto] --, sempre come da specifica.

La funzione CalcolaRisultato è stata data dal professore, serve per generare il valore che va incollato etc. etc.

Esercizio 2

Esegui le seguenti attivita':

  • salva il testo sotto riportato nel file telefonate.txt ;
  • scrivi il programma Contatelefonate.c che accede al file telefonate.txt e calcola il numero di telefonate effettuate a un cellulare e il numero di quelle effettuate verso un numero fisso;
  • calcola come risultato il maggiore tra questi due numeri.

Per stabilire se il telefono e' un cellulare o un fisso si consiglia di utilizzare la funzione strcmp(s1,s2) che restituisce 0 se le due stringhe sono uguali, un numero negativo se s1 e' minore di s2 in ordine lessicografico e un numero positivo altrimenti. Nota bene: il file telefonate.txt e' composto da stringa tabulatore numeroconvirgola tabulatore stringa tabulatore stringa FINERIGA

Note preliminari

Il file telefonate.txt fornito dal professore NON è nel formato che lui indica, cioè stringa tab numeroconvirgola tab stringa tab string FINERIGA, perché non ci sono TAB ma SPAZI fra una riga e l'altra!

Inoltre, il risultato che dà lui, cioè 45, è SBAGLIATO: le chiamate a cellulare sono 44, e sono maggiori delle 23 chiamate a fisso...

Telefonate

 #include <stdio.h>
 #include <string.h>

 int main() {
    FILE * telefonate;
    int chiamate_fisso = 0;
    int chiamate_cell = 0;
    int valore;


    char numero[30];
    char ora[30];
    char tipo[30];
    char durata[30];

    telefonate = fopen("telefonate.txt", "r");

    if (telefonate == NULL) {
       printf("Errore nell'apertura del file telefonate.txt\n");
       getchar();
       return 1;
    }

    while (!feof(telefonate)) {
          fscanf(telefonate,"s s\n", numero, ora, tipo, durata);
          printf("%s\n", tipo);
          valore = strcmp(tipo, "cellul");
          if (valore == 0) chiamate_cell ++;
          else chiamate_fisso++;
    }

    if (chiamate_fisso > chiamate_cell) printf("%d\n", chiamate_fisso);
    else printf("%d\n", chiamate_cell);

    getchar();
    return 0;
 }

Note postliminari

L'unica stringa che ci interessa è la 3a, cioè quella che contiene scritto cellul oppure milano, firenze o quel diavolo che è.

La funzione strcmp(stringa1,stringa2) fa parte della libreria standard del C, e la si ottiene con la riga

 #include <string.h>

in cima.

strcmp(stringa1, stringa2) funziona così:

  • se le stringhe sono uguali, restituisce uno 0;
  • se la prima stringa è MINORE della seconda, lessicograficamente parlando, resituisce -1, o comunque un valore minore di 0
  • se invece la seconda stringa è MAGGIORE della seconda, restituisce un valore maggiore di 0, di solito + 1.

Che cosa vuol dire lessicograficamente parlando? Bene o male, è una specie di conto alfabetico, provate un po' per vedere che cosa voglia significare.

Ai nostri fini, serve solo verificare che la terza stringa sia uguale a cellul, e in quel caso aumentare il contatore di numero di chiamate a cell.

Tutto ciò lo si ottiene con

 valore = strcmp(tipo, "cellul");
 if (valore == 0) chiamate_cell ++;
 else chiamate_fisso++;

dove int valore l'ho dichiarata appositamente allo scopo.

Esercizio 3

Scrivi un programma che:

  1. conta quanti caratteri ci sono nel file COSTITUZ.TXT (63 KB) ;
  2. conta quante volte compare la lettera minuscola 'r' seguita dalla minuscola 'a' ;
  3. calcola come FLOAT la frequenza di occorrenza della lettera 'i' (e' indifferente se maiuscola o minuscola);
  4. restituisce come soluzione (con due decimali dopo la virgola) il FLOAT contenete il prodotto delle due quantita' appena calcolate nei punti 2.e 3.

Soluzione: risultato da copiare ed incollare = 45.23

costituzione.c

 #include <stdio.h>

 int main() {
    FILE * costituzione;
    int numero_ra = 0;
    int numero_i = 0;
    int numero_caratteri = 0;
    float frequenza_i;
    float risultato;
    char c;

    costituzione = fopen("costituzione.txt", "r");

    if (costituzione == NULL) {
       printf("Errore nell'apertura del file costituzione.txt");
       getchar();
       return 1;
    }

    while (!feof(costituzione)) {

          fscanf(costituzione, "%c", &c);
          numero_caratteri ++;
          if (c == 'r') {
                fscanf(costituzione, "%c", &c);
                numero_caratteri ++;
                if (c == 'a') numero_ra ++;
          }
          else if (c == 'i' || c == 'I') numero_i ++;
    }

    frequenza_i = (float) numero_i / numero_caratteri;

    printf("Numero di ra = %d\n", numero_ra);
    printf("Numero di i = %d\n", numero_i);
    printf("Numero di caratteri = %d\n", numero_caratteri);
    printf("Frequenza di i = %f\n", frequenza_i);
    printf("risultato = %2.2f", numero_ra * frequenza_i);

    fclose(costituzione);

    getchar();
    return 0;
 }

Note sull'esercizio

I punti dubbi sono:

  • I caratteri come lo spazio o la punteggiatura vanno contati come numero_caratteri, oppure no? E le lettere accentate, vanno trasformate in lettere non accentate o che diavolo?

Ad ogni modo, il cuore dell'esercizio sta nelle righe

 while (!feof(costituzione)) {
   fscanf(costituzione, "%c", &c);
   numero_caratteri ++;
   if (c == 'r') {
     fscanf(costituzione, "%c", &c);
     numero_caratteri ++;
     if (c == 'a') numero_ra ++;
   }
   else if (c == 'i' || c == 'I') numero_i ++;
 }

Ogni volta che faccio una fscanf sul file, aumento il numero di caratteri, ed il motivo mi sembra ovvio.

Se il carattere trovato è una r, devo poi controllare che ci sia una a, ecco perché dopo il primo

 if (c == 'r')

c'è un'altra fscanf.

Sia che trovo una lettera che non è r, sia che trovo una r non seguita da una a, il programma cade automaticamente nell'

 else if (c == 'i' || c == 'I') numero_i ++;

Ciò accade perché uso sempre il char c per immagazzinare il prossimo carattere da leggere.

Esercizio 4

Utilizzando codoce sotto riportato come traccia si scriva un programma che contiene una funzione ricorsiva int magia(int n) che si basa sulla funzione ricorsiva magia(n):

  1. magia(0) vale 1;
  2. se n>0, allora magia(n) vale (magia(n-1)+100) se n e' pari e (2*magia(n-1)) se n e' dispari;

Il risultato e' quello restituito a monitor dal codice.

magia.c

 #include <stdio.h>

 int magia(int n);

 int main() //NON MODIFICARE IL MAIN
 {
   printf("la soluzione e' --> %d", magia(13));
   getchar();
   return(0);
 }

 int magia(int n) {
 // 1.  magia(0) vale 1;
 // 2. se n>0, allora magia(n) vale (magia(n-1)+100) se n e' pari e (2*magia(n-1)) se n e' dispari;
   if (n == 0) return 1;
   else if (n > 0) {
        if ((n % 2) == 0) return magia(n - 1) + 100;
        else return 2*magia(n-1);
   }
 }

Note sull'esercizio

Le funzioni ricorsive si scrivono esattamente come le leggete: se ci fate caso, ho copiato pari pari la specifica data dal problema e l'ho tradotta in C.

Infatti, la riga che dice:
magia(0) vale 1;

si traduce letteralmente in

 if (n == 0) return 1;

mentre la riga che dice:
se n>0, allora magia(n) vale (magia(n-1)+100) se n e' pari e (2*magia(n-1)) se n e' dispari;

diventa

   else if (n > 0) {
        if ((n % 2) == 0) return magia(n - 1) + 100;
        else return 2*magia(n-1);
   }

Esercizio 5

Si utilizzi il codice sotto riportato per risolvere l'esercizio. Data il vettore di caratteri (stringa) v[] inizializzato nel codice dell'esercizio:

  • si critti carattere per carattere la stringa v[] mediante il metodo di Cesare con chiave 1 memorizzando il risultato nella stringa srt[];
  • La stringa srt[] deve possedere il proprio terminatore;
  • il risultato finale e' il numero che compare a monitor (viene prodotto automaticamente dalla funzione CalcolaRisulato che ha gia' impostato il passaggio della stringa srt).

cesare.c

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

 float CalcolaRisultato(char stringa[]);

 int main()
 {

 char v[]="SIATTACCADOMANIALLALBA" ; 
 char str[1000]=""; // stringa nella quale va inserito il risultato finale

 float risultato;
 int i;

 // ----- inzio dell'esercizo -------
 for (i = 0; i < strlen(v); i ++) {
     str[i] = v[i] + 1;
 } 
 str[strlen(v)] = 0;
 printf("%s\n", str);

  // ----- fine dell'esercizo -------



 // NON TOCCARE TUTTE LE RIGHE QUI SOTTO
 risultato = CalcolaRisultato(str);
 printf("\nrisultato da copiare ed incollare = %d \n\n" , (int) risultato );
 getchar();
 exit(0);
 }  // main

 float CalcolaRisultato(char stringa[])
 {
   int i;
   float divisore, dividendo=0;
   int dim = strlen(stringa);
   for(i=0;i < dim; i++)
   {
      dividendo += i * (int)stringa[i];
   }
   divisore = (dim +1)*dim/2; 
   return 100*dividendo/divisore; 
 }

Note sull'esercizio

Mi sembra semplice: ogni lettera va incrementata di 1, cioè la a diventa b etc.

Inoltre, questa modifica non va salvata nella stringa originale, bensì in str[]. Ciò vuol dire che occorre mettere il \0 alla fine della stringa, perché la teoria ci insegna che le stringhe in C sono NULL-terminated, cioè finiscono con uno 0 (non il carattere, ma proprio il valore 0).

Ecco perché ho messo

 str[strlen(v)] = 0;

La strlen(v) mi restituisce la lunghezza della stringa v. Da notare che se la stringa ha 4 caratteri, la strlen mi restituisce il numero 4 => occorre ricordarsi che la prima posizione delle stringhe è 0.

Quindi, il ciclo for è stato scritto cos':

 for (i = 0; i < strlen(v); i ++) {

mentre il 5° carattere deve essere il famoso 0 di cui sopra:

 str[strlen(v)] = 0;
to:

In questa sezione potrete trovare le soluzioni commentate degli esercizi del buon Scotti e della sensuale Ciriani, divise e confezionate per lezione.


\\

June 04, 2007, at 11:03 PM by Ido -
June 04, 2007, at 11:02 PM by Ido -
Changed lines 5-6 from:

Data la traccia sotto riportata completare il codice in modo di aumentare di 1 tutti gli interi pari e diminuire di 1 tutti quelli dispari nell'array vettore[] di dimensione dim. Riportare come risultato il numero che comparira' a monitor. Per esempio un vettore che contiene gli elementi {4,56,3,78,23} dopo essere stato aggiornato deve contenere gli elementi {5,57,2,79,22}.

to:

Data la traccia sotto riportata completare il codice in modo di aumentare di 1 tutti gli interi pari e diminuire di 1 tutti quelli dispari nell'array vettore[] di dimensione dim. Riportare come risultato il numero che comparira' a monitor. Per esempio un vettore che contiene gli elementi {4,56,3,78,23} dopo essere stato aggiornato deve contenere gli elementi {5,57,2,79,22}. laboratorio 23-24?

June 04, 2007, at 09:36 PM by Dario -
Added lines 327-328:
June 04, 2007, at 05:16 PM by 159.149.102.5 -
Changed lines 149-151 from:
 #include <string.h>
 #include <ctype.h>
to:
Changed line 176 from:
          else if (c == 'i') numero_i ++;
to:
          else if (c == 'i' || c == 'I') numero_i ++;
Changed line 179 from:
    frequenza_i = (numero_i * 100) / numero_caratteri;
to:
    frequenza_i = (float) numero_i / numero_caratteri;
Changed lines 185-187 from:

// printf("risultato = %2.2f", numero_ra * frequenza_i); NO

    printf("risultato = %2.2f", numero_ra / frequenza_i);
to:
    printf("risultato = %2.2f", numero_ra * frequenza_i);
Changed lines 191-192 from:

}

to:
 }
Deleted lines 193-194:

Esce sbagliato. Devo verificare, ma ci sono buoni indizi che il risultato da lui fornito, cioè 45.23, sia veramente sbagliato.

Changed lines 195-200 from:
  1. I caratteri come lo spazio o la punteggiatura vanno contati come numero_caratteri, oppure no? E le lettere accentate, vanno trasformate in lettere non accentate o che diavolo?
  2. Il numero di occorrenze di ra non può essere così basso, perché se la frequenza di i nel testo è sul 9%, vuol dire che al massimo posso trovare 5 ra in tutto il testo! Ma basta contare il numero di volte che la parola democRAzia compare nel testo, ed è chiaro che non può essere così.

Soluzione: non è il prodotto, ma la DIVISIONE!

Chiaro esempio di approssimazione.

to:
  • I caratteri come lo spazio o la punteggiatura vanno contati come numero_caratteri, oppure no? E le lettere accentate, vanno trasformate in lettere non accentate o che diavolo?
Changed line 206 from:
   else if (c == 'i') numero_i ++;
to:
   else if (c == 'i' || c == 'I') numero_i ++;
Changed line 213 from:
 else if (c == 'i') numero_i ++;
to:
 else if (c == 'i' || c == 'I') numero_i ++;
June 04, 2007, at 05:00 PM by Dario -
June 04, 2007, at 05:00 PM by Dario -
Added lines 271-335:

Esercizio 5

Si utilizzi il codice sotto riportato per risolvere l'esercizio. Data il vettore di caratteri (stringa) v[] inizializzato nel codice dell'esercizio:

  • si critti carattere per carattere la stringa v[] mediante il metodo di Cesare con chiave 1 memorizzando il risultato nella stringa srt[];
  • La stringa srt[] deve possedere il proprio terminatore;
  • il risultato finale e' il numero che compare a monitor (viene prodotto automaticamente dalla funzione CalcolaRisulato che ha gia' impostato il passaggio della stringa srt).

cesare.c

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

 float CalcolaRisultato(char stringa[]);

 int main()
 {

 char v[]="SIATTACCADOMANIALLALBA" ; 
 char str[1000]=""; // stringa nella quale va inserito il risultato finale

 float risultato;
 int i;

 // ----- inzio dell'esercizo -------
 for (i = 0; i < strlen(v); i ++) {
     str[i] = v[i] + 1;
 } 
 str[strlen(v)] = 0;
 printf("%s\n", str);

  // ----- fine dell'esercizo -------



 // NON TOCCARE TUTTE LE RIGHE QUI SOTTO
 risultato = CalcolaRisultato(str);
 printf("\nrisultato da copiare ed incollare = %d \n\n" , (int) risultato );
 getchar();
 exit(0);
 }  // main

 float CalcolaRisultato(char stringa[])
 {
   int i;
   float divisore, dividendo=0;
   int dim = strlen(stringa);
   for(i=0;i < dim; i++)
   {
      dividendo += i * (int)stringa[i];
   }
   divisore = (dim +1)*dim/2; 
   return 100*dividendo/divisore; 
 }

Note sull'esercizio

Mi sembra semplice: ogni lettera va incrementata di 1, cioè la a diventa b etc.

Inoltre, questa modifica non va salvata nella stringa originale, bensì in str[]. Ciò vuol dire che occorre mettere il \0 alla fine della stringa, perché la teoria ci insegna che le stringhe in C sono NULL-terminated, cioè finiscono con uno 0 (non il carattere, ma proprio il valore 0).

Ecco perché ho messo

 str[strlen(v)] = 0;

La strlen(v) mi restituisce la lunghezza della stringa v. Da notare che se la stringa ha 4 caratteri, la strlen mi restituisce il numero 4 => occorre ricordarsi che la prima posizione delle stringhe è 0.

Quindi, il ciclo for è stato scritto cos':

 for (i = 0; i < strlen(v); i ++) {

mentre il 5° carattere deve essere il famoso 0 di cui sopra:

 str[strlen(v)] = 0;
June 04, 2007, at 04:55 PM by Dario -
Changed lines 225-270 from:

Esercizio 4

to:

Esercizio 4

Utilizzando codoce sotto riportato come traccia si scriva un programma che contiene una funzione ricorsiva int magia(int n) che si basa sulla funzione ricorsiva magia(n):

  1. magia(0) vale 1;
  2. se n>0, allora magia(n) vale (magia(n-1)+100) se n e' pari e (2*magia(n-1)) se n e' dispari;

Il risultato e' quello restituito a monitor dal codice.

magia.c

 #include <stdio.h>

 int magia(int n);

 int main() //NON MODIFICARE IL MAIN
 {
   printf("la soluzione e' --> %d", magia(13));
   getchar();
   return(0);
 }

 int magia(int n) {
 // 1.  magia(0) vale 1;
 // 2. se n>0, allora magia(n) vale (magia(n-1)+100) se n e' pari e (2*magia(n-1)) se n e' dispari;
   if (n == 0) return 1;
   else if (n > 0) {
        if ((n % 2) == 0) return magia(n - 1) + 100;
        else return 2*magia(n-1);
   }
 }

Note sull'esercizio

Le funzioni ricorsive si scrivono esattamente come le leggete: se ci fate caso, ho copiato pari pari la specifica data dal problema e l'ho tradotta in C.

Infatti, la riga che dice:
magia(0) vale 1;

si traduce letteralmente in

 if (n == 0) return 1;

mentre la riga che dice:
se n>0, allora magia(n) vale (magia(n-1)+100) se n e' pari e (2*magia(n-1)) se n e' dispari;

diventa

   else if (n > 0) {
        if ((n % 2) == 0) return magia(n - 1) + 100;
        else return 2*magia(n-1);
   }
June 04, 2007, at 04:27 PM by Dario -
Changed lines 187-188 from:
    printf("risultato = %2.2f", numero_ra * frequenza_i);
to:

// printf("risultato = %2.2f", numero_ra * frequenza_i); NO

    printf("risultato = %2.2f", numero_ra / frequenza_i);
Added line 203:

Soluzione: non è il prodotto, ma la DIVISIONE!\\\

June 04, 2007, at 04:20 PM by Dario -
Changed line 44 from:

NOTE SULL'ESERCIZIO

to:

Note sull'esercizio

Changed line 123 from:

strcmp(stringa1, stringa2) funziona così:\\\

to:

strcmp(stringa1, stringa2) funziona così:

Changed lines 136-223 from:

dove int valore l'ho dichiarata appositamente allo scopo.

to:

dove int valore l'ho dichiarata appositamente allo scopo.

Esercizio 3

Scrivi un programma che:

  1. conta quanti caratteri ci sono nel file COSTITUZ.TXT (63 KB) ;
  2. conta quante volte compare la lettera minuscola 'r' seguita dalla minuscola 'a' ;
  3. calcola come FLOAT la frequenza di occorrenza della lettera 'i' (e' indifferente se maiuscola o minuscola);
  4. restituisce come soluzione (con due decimali dopo la virgola) il FLOAT contenete il prodotto delle due quantita' appena calcolate nei punti 2.e 3.

Soluzione: risultato da copiare ed incollare = 45.23

costituzione.c

 #include <stdio.h>
 #include <string.h>
 #include <ctype.h>

 int main() {
    FILE * costituzione;
    int numero_ra = 0;
    int numero_i = 0;
    int numero_caratteri = 0;
    float frequenza_i;
    float risultato;
    char c;

    costituzione = fopen("costituzione.txt", "r");

    if (costituzione == NULL) {
       printf("Errore nell'apertura del file costituzione.txt");
       getchar();
       return 1;
    }

    while (!feof(costituzione)) {

          fscanf(costituzione, "%c", &c);
          numero_caratteri ++;
          if (c == 'r') {
                fscanf(costituzione, "%c", &c);
                numero_caratteri ++;
                if (c == 'a') numero_ra ++;
          }
          else if (c == 'i') numero_i ++;
    }

    frequenza_i = (numero_i * 100) / numero_caratteri;

    printf("Numero di ra = %d\n", numero_ra);
    printf("Numero di i = %d\n", numero_i);
    printf("Numero di caratteri = %d\n", numero_caratteri);
    printf("Frequenza di i = %f\n", frequenza_i);
    printf("risultato = %2.2f", numero_ra * frequenza_i);

    fclose(costituzione);

    getchar();
    return 0;

}

Note sull'esercizio

Esce sbagliato. Devo verificare, ma ci sono buoni indizi che il risultato da lui fornito, cioè 45.23, sia veramente sbagliato.

I punti dubbi sono:

  1. I caratteri come lo spazio o la punteggiatura vanno contati come numero_caratteri, oppure no? E le lettere accentate, vanno trasformate in lettere non accentate o che diavolo?
  2. Il numero di occorrenze di ra non può essere così basso, perché se la frequenza di i nel testo è sul 9%, vuol dire che al massimo posso trovare 5 ra in tutto il testo! Ma basta contare il numero di volte che la parola democRAzia compare nel testo, ed è chiaro che non può essere così.

Chiaro esempio di approssimazione.

Ad ogni modo, il cuore dell'esercizio sta nelle righe

 while (!feof(costituzione)) {
   fscanf(costituzione, "%c", &c);
   numero_caratteri ++;
   if (c == 'r') {
     fscanf(costituzione, "%c", &c);
     numero_caratteri ++;
     if (c == 'a') numero_ra ++;
   }
   else if (c == 'i') numero_i ++;
 }

Ogni volta che faccio una fscanf sul file, aumento il numero di caratteri, ed il motivo mi sembra ovvio.

Se il carattere trovato è una r, devo poi controllare che ci sia una a, ecco perché dopo il primo

 if (c == 'r')

c'è un'altra fscanf.

Sia che trovo una lettera che non è r, sia che trovo una r non seguita da una a, il programma cade automaticamente nell'

 else if (c == 'i') numero_i ++;

Ciò accade perché uso sempre il char c per immagazzinare il prossimo carattere da leggere.

Esercizio 4

June 04, 2007, at 04:10 PM by Dario -
Changed lines 61-64 from:

In caso positivo, esegue la riga vettore[conto] ++, come da specifica; in caso contrario invece viene diminuito con vettore[conto] --, sempre come da specifica.

to:

In caso positivo, esegue la riga vettore[conto] ++, come da specifica; in caso contrario invece viene diminuito con vettore[conto] --, sempre come da specifica.

La funzione CalcolaRisultato è stata data dal professore, serve per generare il valore che va incollato etc. etc.

Esercizio 2

Esegui le seguenti attivita':

  • salva il testo sotto riportato nel file telefonate.txt ;
  • scrivi il programma Contatelefonate.c che accede al file telefonate.txt e calcola il numero di telefonate effettuate a un cellulare e il numero di quelle effettuate verso un numero fisso;
  • calcola come risultato il maggiore tra questi due numeri.

Per stabilire se il telefono e' un cellulare o un fisso si consiglia di utilizzare la funzione strcmp(s1,s2) che restituisce 0 se le due stringhe sono uguali, un numero negativo se s1 e' minore di s2 in ordine lessicografico e un numero positivo altrimenti. Nota bene: il file telefonate.txt e' composto da stringa tabulatore numeroconvirgola tabulatore stringa tabulatore stringa FINERIGA

Note preliminari

Il file telefonate.txt fornito dal professore NON è nel formato che lui indica, cioè stringa tab numeroconvirgola tab stringa tab string FINERIGA, perché non ci sono TAB ma SPAZI fra una riga e l'altra!

Inoltre, il risultato che dà lui, cioè 45, è SBAGLIATO: le chiamate a cellulare sono 44, e sono maggiori delle 23 chiamate a fisso...

Telefonate

 #include <stdio.h>
 #include <string.h>

 int main() {
    FILE * telefonate;
    int chiamate_fisso = 0;
    int chiamate_cell = 0;
    int valore;


    char numero[30];
    char ora[30];
    char tipo[30];
    char durata[30];

    telefonate = fopen("telefonate.txt", "r");

    if (telefonate == NULL) {
       printf("Errore nell'apertura del file telefonate.txt\n");
       getchar();
       return 1;
    }

    while (!feof(telefonate)) {
          fscanf(telefonate,"s s\n", numero, ora, tipo, durata);
          printf("%s\n", tipo);
          valore = strcmp(tipo, "cellul");
          if (valore == 0) chiamate_cell ++;
          else chiamate_fisso++;
    }

    if (chiamate_fisso > chiamate_cell) printf("%d\n", chiamate_fisso);
    else printf("%d\n", chiamate_cell);

    getchar();
    return 0;
 }

Note postliminari

L'unica stringa che ci interessa è la 3a, cioè quella che contiene scritto cellul oppure milano, firenze o quel diavolo che è.

La funzione strcmp(stringa1,stringa2) fa parte della libreria standard del C, e la si ottiene con la riga

 #include <string.h>

in cima.

strcmp(stringa1, stringa2) funziona così:

* se le stringhe sono uguali, restituisce uno 0;

  • se la prima stringa è MINORE della seconda, lessicograficamente parlando, resituisce -1, o comunque un valore minore di 0
  • se invece la seconda stringa è MAGGIORE della seconda, restituisce un valore maggiore di 0, di solito + 1.

Che cosa vuol dire lessicograficamente parlando? Bene o male, è una specie di conto alfabetico, provate un po' per vedere che cosa voglia significare.

Ai nostri fini, serve solo verificare che la terza stringa sia uguale a cellul, e in quel caso aumentare il contatore di numero di chiamate a cell.

Tutto ciò lo si ottiene con

 valore = strcmp(tipo, "cellul");
 if (valore == 0) chiamate_cell ++;
 else chiamate_fisso++;

dove int valore l'ho dichiarata appositamente allo scopo.

June 04, 2007, at 04:01 PM by Dario -
Added lines 1-64:

(:title Laboratorio C:) Qui ci sono le soluzioni agli esercizi dell'ultima lezione, con tanto di commento.

Esercizio 1

Data la traccia sotto riportata completare il codice in modo di aumentare di 1 tutti gli interi pari e diminuire di 1 tutti quelli dispari nell'array vettore[] di dimensione dim. Riportare come risultato il numero che comparira' a monitor. Per esempio un vettore che contiene gli elementi {4,56,3,78,23} dopo essere stato aggiornato deve contenere gli elementi {5,57,2,79,22}.

 Aumenta interi pari
 #include <stdio.h>

 float CalcolaRisultato(int vettore[], int dim);

 int main() {

    int vettore[] = {4,56,3,78,23}  ;
    int dim = 5;
    int conto;
    float risultato;

    //Se il tuo programma funziona correttamente, dovresti ottenere: 2573

    for (conto = 0; conto < dim; conto ++) {
        if ((vettore[conto] % 2) == 0) vettore[conto] ++;
        else vettore[conto] --;
    }

    risultato = CalcolaRisultato(vettore, dim);
    printf("\nrisultato da copiare ed incollare = %d \n\n" , (int) risultato );
    getchar();
    exit(0);
 }  // main

 float CalcolaRisultato(int vettore[], int dim)
 {
   int i;
   float divisore, dividendo=0;
   for(i=0;i < dim; i++)
   {
      dividendo += i * vettore[i];
   }
   divisore = (dim +1)*dim/2; 
   return 100*dividendo/divisore; 
 }

NOTE SULL'ESERCIZIO

Innanzitutto, l'esercizio ti dava un vettore di 462 elementi, mentre qui il vettore ne ha solamente 5.

Il cuore dell'esercizio sta nella sequenza

    for (conto = 0; conto < dim; conto ++) {
        if ((vettore[conto] % 2) == 0) vettore[conto] ++;
        else vettore[conto] --;
    }

che vuol dire esattamente questo:

  for (conto = 0; conto < dim; conto ++)

esamina il vettore dal primo all'ultimo elemento, ricordando che dim = numero elementi del vettore.

   if ((vettore[conto] % 2) == 0) vettore[conto] ++;
   else vettore[conto] --;

If ((vettore[conto] % 2) == 0) controlla se l'elemento conto-esimo del vettore è pari, cioè se il resto della divisione intera per due è 0.

In caso positivo, esegue la riga vettore[conto] ++, come da specifica; in caso contrario invece viene diminuito con vettore[conto] --, sempre come da specifica.