next up previous contents index
Next: Ordinare un array Up: Array, enumerati, stringhe Previous: Definizione di un array   Indice   Indice analitico

Vettori e funzioni

Nel capitolo dedicato alle funzioni abbiamo analizzato tre possibili metodi per il passaggio degli argomenti: per valore, per indirizzo, per riferimento. Il primo di essi inizializza la variabile locale alla funzione chiamata, con il valore della variabile della funzione chiamante; si tratta in definitiva di una copia. Un array potrebbe anche essere molto grande, in termini di memoria occupata, e farne una copia ogni volta che una funzione viene chiamata potrebbe essere un'operazione del tutto inefficiente. Per questo motivo, il C++ consente per il passaggio di array un solo metodo: per indirizzo. La sintassi è molto semplice, in quanto rispecchia quella del passaggio per valore delle variabili; vediamo subito un semplice esempio:

// ex6_2_1.cpp
#include <iostream.h>

// stampa gli elementi da 0 a n-1 di un vettore intero
void stampaVettore (int a[], int n) {
  for (int i = 0; i < n; i++)
    cout << "a[" << i << "]: " << a[i] << "\n";
}

void main() {
  const int N = 7;
  int a[N];
  for (int i = 0; i < N; i++)
    a[i] = i - N/2;
  stampaVettore (a, N);
}

output:
a[0]: -3
a[1]: -2
a[2]: -1
a[3]: 0
a[4]: 1
a[5]: 2
a[6]: 3

Come si vede, nell'argomento della funzione non è necessario inserire il numero degli elementi. Un'altra osservazione importante è la seguente: quando passiamo un vettore ad una funzione, non sappiamo il numero degli elementi di tale vettore, per cui dobbiamo passare sempre anche tale numero.

Vediamo un esempio che inserisca in vettore la successione di Fibonacci e la stampi; essa è la seguente:

\begin{displaymath}
1,1,2,3,5,8,13,21,\ldots
\end{displaymath}

per cui il termine $n$-esimo è dato dalla seguente

\begin{displaymath}
a_{n} = a_{n-1} + a_{n-2}
\end{displaymath}

cioè è la somma dei due termini che lo precedono; si pone $a_0 = a_1 = 1$.

// ex6_2_2.cpp
#include <iostream.h>

// inserisce in un vettore la successione di Fibonacci
void creaFibonacci (int v[], int n) {
  v[0] = v[1] = 1;  // per ipotesi
  for (int i = 2; i < n; i++)
    v[i] = v[i-1] + v[i-2];
}

// stampa un vettore dal termine inf al sup
void stampa (int v[], int inf, int sup) {
  for (int i = inf; i <= sup; i++)
    cout << "v[" << i << "]: " << v[i] << "\n";
}

void main() {
  const int MAX = 40;
  int fibonacci[MAX + 1];
  creaFibonacci (fibonacci, MAX + 1);
  int inf, sup;
  cout << "stampare i termini"
    "\nda: "; cin >> inf;
  cout << "a: "; cin >> sup;
  if (!(inf > sup || sup > MAX || inf < 0))
    stampa (fibonacci, inf, sup);
}

esempio di output:
stampare i termini
da: 3
a: 7
v[3]: 3
v[4]: 5
v[5]: 8
v[6]: 13
v[7]: 21

La procedura di passare ad una funzione due indici (inferiore e superiore, ad esempio) insieme ad un array è molto comune, e verrà ripresa in diversi futuri programmi di esempio.

Presentiamo ora un programma che ``mischia'' un mazzo di 52 carte da poker e le stampa (tale esempio è basato su ex3_6_2.cpp):


// ex6_2_3.cpp
// mischia un mazzo di carte da poker
// basato su ex3_6_2.cpp
#include <iostream.h>
#include <time.h>
#include <stdlib.h>

const int N_CARTE = 52;

// non passiamo il numero di elementi del vettore
// in quanto esso e' noto a priori (N_CARTE)
void mischiaCarte (int mazzo[]) {
  // inizializza il generatore dei numeri casuali
  srand( time(0) );
  for (int i = 0; i < N_CARTE; i++) {
    bool ok;
    do {
      // sceglie un numero da 1 a N_CARTE (52)
      int carta = rand() % N_CARTE + 1;
      ok = true;
      for (int j = 0; j < i; j++)
        if (mazzo[j] == carta) {  for (int i = 0; i < N_CARTE; i++) {
    bool ok;
    do {
      // sceglie un numero da 1 a N_CARTE (52)
      int carta = rand() % N_CARTE + 1;
      ok = true;
      for (int j = 0; j < i; j++)
        if (mazzo[j] == carta) {
          ok = false;
          break;
        }
      mazzo[i] = carta;
    } while (!ok);
  }

          ok = false;
          break;
        }
      mazzo[i] = carta;
    } while (!ok);
  }
}

void stampaCarte (int mazzo[]) {
  for (int i = 0; i < N_CARTE; i++) {
    int carta = (mazzo[i] % 13) + 1;
    int seme = (mazzo[i] - 1) / 13;
    // seme:   0=cuori 1=quadri    2=fiore      3=picche
    // carta:  1=asso  11=fante(J) 12=regina(Q) 13=re(K)
    switch (carta) {
    case 1:
      cout << "A  di "; break;
    case 10:
      cout << "10 di "; break;
    case 11:
      cout << "J  di "; break;
    case 12:
      cout << "Q  di "; break;
    case 13:
      cout << "K  di "; break;
    default:
      cout << carta << "  di ";
    }
    switch (seme) {
    case 0:
      cout << "C\t"; break;
    case 1:
      cout << "Q\t"; break;
    case 2:
      cout << "F\t"; break;
    case 3:
      cout << "P\t";  break;
    }
    if (i % 5 == 4)
      cout << "\n";
    else
      cout << "\t";
  }
}

void main() {
  int mazzo[N_CARTE];
  // mettiamo a zero tutti gli elementi di mazzo[]
  for (int i = 0; i < N_CARTE; i++)
    mazzo[i] = 0;
  mischiaCarte (mazzo);
  stampaCarte (mazzo);
}

esempio di output:
 A di Q Q di P 7 di P 2 di P K di F
 2 di Q K di P 8 di F 10 di C J di Q
 K di Q 9 di C 7 di C 2 di F J di C
 6 di F 7 di Q A di C 8 di P 5 di Q
 5 di P A di F 5 di C 5 di F 3 di Q
 Q di C Q di Q 9 di P 3 di C 4 di C
 Q di F 4 di F K di C 10 di F 2 di C
 7 di F 6 di P 10 di P J di F 4 di P
 9 di Q 9 di F J di P 8 di C 3 di F
 6 di C 6 di Q A di P 4 di Q 3 di P
 8 di Q 10 di Q      

La funzione che mischia le carte non è del tutto ovvia, ad una prima impressione; le operazioni che compiamo sono le seguenti: estraiamo un numero a caso e controlliamo che esso non sia già stato assegnato alle altre carte del mazzo: in questa maniera possiamo ottenere un elenco di 52 numeri tutti diversi l'uno dall'altro. Per effettuare questo controllo, non dobbiamo far altro che scorrere il nostro vettore dalla prima posizione fino a quella della carta da estrarre; abbiamo utilizzato dunque due indici (i e j) i quali scorrono il vettore il primo una ed una sola volta, il secondo 51 volte (la prima carta estratta è sicuramente buona ...). Come sempre, questo procedimento non è il più efficiente che si possa costruire, ma funziona ed è adatto ai nostri scopi; inoltre per soli 52 numeri interi da estrarre, con l'attuale sviluppo tecnologico , qualunque personal computer impiega tempi brevissimi a completare le operazioni (per intenderci, ho provato il programma su di una macchina con un processore Intel Pentium II e mediamente il programma è stato eseguito in 8 millisecondi; ho provato poi a fargli estrarre 52000 numeri ,un numero che per certi scopi non è poi molto grande, e siamo già sui 10 minuti di attesa).

Anche le funzioni aventi vettori come argomenti possono essere sovrapposte; per esempio sovrapponiamo la funzione sin della libreria math.h facendole calcolare il seno di ciascun elemento di un vettore:


// ex6_2_4.cpp
#include <iostream.h>
#include <math.h>

const double PI = 3.14159265358979323846264338327;
const int N_ELEM = 9;

void sin (double v[], int n) {
  for (int i = 0; i < n; i++)
    v[i] = sin(v[i]);
}

void stampa (double v[], int n) {
  for (int i = 0; i < n; i++)
    cout << v[i] << "\n";
}

void main() {
  double v[N_ELEM];
  for (int i = 0; i < N_ELEM; i++)
    v[i] = PI/4 * i;
  sin (v, N_ELEM);
  stampa (v, N_ELEM);
}

output:
0
0.707107
1
0.707107
1.22461e-16
-0.707107
-1
-0.707107
-2.44921e-16

Il vettore in questo esempio è stato costruito con i multipli di PI/4, il quale è una buona approssimazione di $\frac{\pi}{4}$; tale approssimazione non è però in certi casi sufficiente, infatti risulta essere: $\sin(0) \neq \sin(\pi) \neq \sin(2\pi)$, che è matematicamente non vero.

ex-2
si scriva un programma che calcoli e stampi i primi $n$ termini della successione di Padovan, con $n$ immesso dall'utente; la successione di Padovan (cugina molto meno famosa della successione di Fibonacci) è data da:

\begin{displaymath}
a_n = a_{n-2} + a_{n-3}
\end{displaymath}

e si pone $a_0 = a_1 = a_2 = 1$; in questa maniera si ha:

\begin{displaymath}
1,1,1,2,2,3,4,5,7,9,12,\ldots
\end{displaymath}

ex-3
si scriva un programma che sovrapponga la funzione sqrt e permetta di calcolare la radice quadrata di ciascun elemento di un array;
ex-4
si scriva una funzione che accetti un vettore ed il numero dei suoi elementi, e ritorni la media degli elementi di esso;
ex-5
si scriva una funzione che accetti un vettore, il numero dei suoi elementi e una variabile bool: se essa è vera allora assegni agli elementi del vettore tutti numeri dispari, altrimenti pari;
ex-6
si scriva una funzione che torni il minimo comune multiplo (o il massimo comun divisore) degli elementi di un array dato (attenzione: esercizio non banale);
ex-7
si scriva una funzione che inserisca in un vettore le coordinate (unidimensionali) di un punto materiale che si muove di moto uniformemente accelerato; siano dati: accelerazione, velocità iniziale, posizione iniziale, durata del tempo di osservazione e intervallo di misurazione.


next up previous contents index
Next: Ordinare un array Up: Array, enumerati, stringhe Previous: Definizione di un array   Indice   Indice analitico
Claudio Cicconetti
2000-09-06