cerca
Laboratorio C - Lezione 23-24
modifica cronologia stampa login logout

Wiki

UniCrema


Materie per semestre

Materie per anno

Materie per laurea


Help

Laboratorio C - Lezione 23-24

 :: Laboratorio C - Lezione 23-24 ::

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.

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;
    int flag = 0;
    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 ++;
    }

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

    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(fscanf(costituzione,"%c", &c") == 1)
  {
   if (c == 'r') flag = 1;
   else if (c == 'a' && flag == 1) {
	flag = 0;
	numero_ra++;
   }
   else if (c=='i' || c == 'I') {
        numero_i++;
	flag = 0;
   }
   else flag = 0;
  }

DA MODIFICARE

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;

Torna al Laboratorio di C | Programmazione