• Non ci sono risultati.

FONDINF - Esercizi Linguaggio C

N/A
N/A
Protected

Academic year: 2021

Condividi "FONDINF - Esercizi Linguaggio C"

Copied!
59
0
0

Testo completo

(1)

FONDINF – ESERCIZI LINGUAGGIO C

Proglab1 calcolo del fattoriale di un numero Proglab2 prodotto dei numeri in un intervallo Proglab3 individuare max e min di n numeri Proglab4 test numero primo

Proglab5 disegnare un quadrato

Proglab6 disegnare il perimetro di un rettangolo Proglab7 indovinare un numero

Proglab8 calcolo n-mo numero di Fibonacci Proglab9 sommare gli elementi di due vettori Proglab10 inversione di un vettore su se stesso

Proglab11 individuare elementi comuni in due vettori Proglab12 prodotto somma diagonali matrice

Proglab13 inserimento di un vettore al centro di un altro Proglab14 vettore di numeri casuali non multipli di k Proglab15 stampare h-ma riga e k-ma colonna matrice Proglab16 elementi presenti nel vettore B ma non in A Proglab17 eliminare multipli di k in un vettore

Proglab18 verificare se una parola è palindroma Proglab19 terne il cui prodotto è minore della media

Proglab20 colonna con massimo numero di elementi dispari Proglab21 la più lunga sequenza crescente in un vettore Proglab22 verificare se il prodotto delle righe è crescente Proglab23 presenza di righe e colonne aventi la stessa somma Proglab24 calcolo cubo numero (puntatori)

Proglab25 stampa all’inverso di un vettore (puntatori) Proglab26 max tra due numeri (puntatori)

Proglab27 elemento centrale di un vettore (puntatori) Proglab28 max e min in un vettore (puntatori)

Proglab29 I/O di un vettore numerico Proglab30 I/O di una matrice numerica Proglab31 I/O di parole (una per riga) Proglab32 I/O di parole (su una sola riga) Proglab33 Copia di un file di testo

(2)

Proglab 1 – Calcolo del fattoriale di un numero

Leggere un numero naturale n e calcolare e stampare il suo fattoriale. n! = 1 * 2 * 3 * …… * (n-2) * (n-1) * n

Il programma accumula un passo alla volta il valore del fattoriale nella variabile fat. L’istruzione fat = fat * i; significa: moltiplica fat * i e il risultato assegnalo a fat. E’ importante l’istruzione fat = 1; per assegnare il valore iniziale a fat.

#include <stdio.h> main()

{

int n, fat, i; fat = 1;

printf("digita il numero di cui vuoi il fattoriale: "); scanf("%d", &n);

for (i = 1; i <= n; i++) fat = fat * i;

printf("il fattoriale di %d e' %d\n\n", n, fat); return(0);

}

TRACCIA DEL PROGRAMMA PER n = 4: n fat i ___________________________ 4 1 1 1 2 2 3 6 4 24 5

(3)

Proglab 2 – Prodotto dei numeri in un intervallo

Letti due numeri interi n1 e n2 (n1  n2), stampare il prodotto: n1* (n1 +1) * (n1 +2) * . . . * n2

Ad esempio, se n1 = 3 e n2 = 6 otteniamo: 3 * 4 * 5 * 6 = 360

Analogamente al fattoriale, la variabile p viene posta a 1 (altrimenti la prima volta che si esegue p = p * i; il valore di p risulterebbe indefinito) e poi, un passo alla volta, viene ad assumere il valore del prodotto cercato. #include <stdio.h>

main() {

int i, p, n1, n2;

printf("digita n1 e n2: "); scanf(" %d%d", &n1, &n2); p = 1; for (i = n1; i <= n2; i++) p = p * i; printf("il prodotto = %d\n", p); return(0); }

TRACCIA DEL PROGRAMMA PER n1=3, n2=6:

n1 n2 p i ___________________________________ 3 6 1 3 3 4 12 5 60 6 360 7

(4)

Proglab 3 – Individuare max e min di n numeri

Letti n numeri interi individuare e stampare il massimo e il minimo.

Ad esempio, se n = 5 e i numeri sono: 22, 56, -6, 89, -13, il massimo è 89 e il minimo -13.

Leggo il primo numero (22) e lo assegno sia a min che a max. Leggo il secondo (56) e mi chiedo se è < min (no) e se è maggiore di max (sì per cui cambio il valore di max (56)). Leggo il terzo numero (-6) e mi chiedo se è < min (sì per cui cambio il valore di min (-6)) e se è maggiore di max (no). Vado avanti così e alla fine max vale 89 e min -13.

#include <stdio.h> main()

{

int n, i, x, max, min;

printf("di quanti numeri vuoi calcolare max e min? "); scanf(" %d", &n);

printf("digita un numero: "); scanf(" %d", &max);

min = max;

for (i=1; i<n; i++) {

printf("digita un numero: "); scanf(" %d", &x); if (x < min) min = x; else if (x > max) max = x; }

printf("il max dei %d numeri e' %d, mentre il min e' %d\n\n", n, max, min);

return (0); }

(5)

Proglab 4 - Test numero primo

Un numero intero positivo si dice primo se è divisibile esattamente solo per se stesso e per l’unità: 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43,

47, 53, 59, 61, 67, ……

Scrivere un programma che legge n e controlla se è primo o no. Ad esempio, se n = 11 la risposta è sì, se n = 88 la risposta è no.

E’ semplice costruire un programma che effettui la verifica: basta calcolare il resto della divisione di n per tutti i numeri che vanno da 2 a n-1. Poiché l’operatore modulo (%) ci fornisce proprio il resto della divisione è sufficiente, all’interno di un for che va da 2 a n-1, controllare se n&i vale zero. Risulta utile utilizzare una variabile flag che può assumere i valori 0 o 1.

Nel programma che segue flag = 1 significa “numero primo”, flag = 0 “numero composto”. E’ necessario avvalorare inizialmente il flag a 1, nel caso il numero non sia primo (resto = zero) il flag viene messo a zero e quando si esce dal for testando il flag viene stampata la frase opportuna. #include <stdio.h>

main() {

int i, n, flag;

printf("digita un numero intero maggiore di 1: "); scanf(" %d", &n); flag = 1; for (i = 2; i < n; i++) { if (n % i == 0) flag = 0; } if (flag == 1)

printf("il numero %d e' primo\n\n", n); else

printf("il numero %d non e' primo\n\n",n); return(0);

(6)

Il programma è certamente corretto ma noi siamo interessati a programmi che siano anche efficienti, cioè diano i risultati con la massima rapidità. Nel nostro caso, osserviamo che nel caso che n sia, ad esempio, 25 il programma calcola i resti delle seguenti divisioni: 25/2, 25/3, 25/4, 25/5 (resto zero e quindi il flag viene azzerato), 25/6, 25/7, ……., 25/24.

E’ chiaro che effettuare le divisioni 25/6, 25/7, ……., 25/24 è uno spreco di tempo, per cui, nel momento in cui il resto vale zero (numero non primo), conviene uscire dal for utilizzando l’istruzione break:

for (i = 2; i < n; i++) { if (n % i == 0) { flag = 0; break; } }

Facciamo ora questa osservazione: se il numero n è composto, tutti i suoi divisori sono <= n/2.

Ad esempio, se n = 34 = 2 * 17 il primo divisore 2 < 34/2 e il secondo 17 = 34/2.

In generale, se un numero n è composto, non può esserci un divisore avente un valore > n/2 in quanto moltiplicato per un altro divisore (valore minimo 2) verrebbe fuori un numero maggiore di n.

Ad esempio, se n = 57, possiamo subito dire, senza fattorizzarlo, che, se è composto, nessun divisore è maggiore di 28, perché un ipotetico divisore maggiore di 28, ad es. 29, andrebbe moltiplicato per un altro divisore che come minimo varrebbe 2 e si avrebbe pertanto 58 (in realtà 57 = 3 * 19).

(7)

La conclusione è che basta controllare i resti fino a n/2 per cui il for diventa: for (i = 2; i <= n/2; i++) { if (n % i == 0) { flag = 0; break; } }

Possiamo però andare oltre osservando che:

Se un numero è composto, esiste un divisore <= sqrt(n). Ad esempio, se n = 49 = 7 * 7, il divisore 7 = sqrt(49). Se n = 33 = 3 * 11, il divisore 3 < sqrt(33) = 5.74….

In generale, se n è composto, può essere fattorizzato in due fattori:

n = a *b (ad esempio, 143 = 11 * 13 e 11 < sqrt (143) = 11.95) Se sia a che b fossero maggiori di sqrt (n), poiché

n = sqrt(n) * sqrt(n), a * b sarebbe > n.

Pertanto almeno uno dei fattori deve essere <= sqrt (n) e per verificare se n è primo basta controllare i resti fino a sqrt (n).

Questo ragionamento va bene per qualsiasi numero composto. Ad esempio: 210 = 2 * 3 * 5 * 7 può anche essere scritto: 210 = 15 * 14 e in questo caso abbiamo che il divisore 14 < sqrt(210) = 14.49.

In conclusione, il nostro for diventa (bisogna aggiungere la direttiva #include <math.h>): for (i = 2; i <= sqrt(n); i++) { if (n % i == 0) { flag = 0; break; } }

(8)

Proglab 5 – Disegnare un quadrato

Viene letta la lunghezza n del lato e viene stampato il relativo quadrato utilizzando il carattere asterisco (*).

#include <stdio.h> main()

{

int i, j, n;

printf ("digita il lato del quadrato: "); scanf ("%d", &n); printf ("\n\n\n"); for (i = 1; i <= n; i++) { for (j = 1; j <= n; j++) { printf ("*"); } printf ("\n"); } printf ("\n\n\n"); return (0); }

Ad esempio, se n = 3, bisogna stampare tre righe ciascuna costituita da tre asterischi. Dopo ogni riga bisogna anche effettuare uno \n.

Occorrono pertanto due for annidati (nested), cioè uno dentro l’altro aventi indici diversi. Il primo for (indice i) è detto esterno, il secondo (indice j) interno. Vediamo la traccia del programma:

n i j printf 3 1 1 * 2 * 3 * 4 \n 2 1 * 2 * 3 * 4 \n 3 1 * 2 * 3 * 4 \n 4

(9)

Proglab 6 – Disegnare il perimetro di un rettangolo

Leggere i numeri a e b e disegnare il perimetro di un rettangolo di base a e altezza b utilizzando l’asterisco. Ad esempio, se a=10 e b=5, si ha: a **********

* * * * * * **********

Due for servono per stampare il lato superiore e quello inferiore. Per stampare i due lati laterali occorre per b-2 volte stampare un “*” seguito da a-2 spazi e un “*\n” finale.

#include <stdio.h> main()

{

int a, b, i, j;

printf ("\ndigita la lunghezza della base: "); scanf("%d",&a);

printf ("\ndigita la lunghezza dell'altezza: "); scanf("%d",&b);

printf ("\n\n");

for (i=1; i<=a; i++) printf ("*"); printf ("\n");

for (i=1; i<=b-2; i++) { printf ("*");

for (j=1; j<=a-2; j++) printf (" "); printf ("*\n");

}

for (i=1; i<=a; i++) printf ("*");

printf ("\n\n"); return 0; }

(10)

Un vostro collega (Michele Citro) ha risolto il problema ragionando diversamente: Proglab 5 disegna un quadrato di asterischi “pieno”. Se abbiamo un rettangolo, queste istruzioni disegnano un rettangolo “pieno”: for (i = 1; i <= b; i++) {

for (j = 1; j <= a; j++) printf ("*"); printf ("\n");

}

Invece, l’asterisco va stampato solo lungo il perimetro del rettangolo. Osserviamo che quando i=1 ci troviamo sul lato superiore, quando i=b sul lato inferiore, quando j=1 sul lato sinistro, quando j=a sul lato destro. Ne segue che, solo quando i e j assumono tali valori, occorre stampare un asterisco, negli altri casi uno spazio. Ci torna allora utile l’operatore OR (||) già incontrato in Prog 8:

#include <stdio.h> main()

{

int a, b, i, j;

printf ("\ndigita la lunghezza della base: "); scanf("%d",&a);

printf ("\ndigita la lunghezza dell'altezza: "); scanf("%d",&b);

printf ("\n\n");

for (i=1; i<=b; i++) { for(j=1; j<=a; j++) {

if (i==1 || i==b || j==1 || j==a) printf("*"); else printf(" "); } printf("\n"); } printf ("\n\n"); return 0; }

(11)

Proglab 7 – Indovinare un numero

Il programma genera un numero casuale compreso tra 0 e 100 e chiede di indovinarlo. In caso di risposta sbagliata, il programma suggerisce di fornire un valore maggiore o minore. Al termine segnala il numero di tentativi fatti.

Questo è un problema in cui risulta appropriata l’istruzione while in quanto non è noto a priori il numero di tentativi per individuare il numero. Analogamente a quanto accade nel programma che controlla la validità dei dati input (Prog 18) occorre leggere il primo numero n fuori del while (altrimenti while (n != numero) sarebbe scorretta). Volendo evitare due istruzioni scanf("%d",&n) bisogna, come in Prog 18, utilizzare il do. #include <stdio.h>

#include <time.h> main()

{

int numero, n, cont; srand (time(NULL)); numero = rand() % 101;

printf ("\ndigita un numero: "); scanf("%d",&n);

cont = 1;

while (n != numero) { if (n < numero)

printf ("\ndigita un numero piu' grande\n"); else

printf ("\ndigita un numero piu' piccolo\n"); cont++;

printf ("\ndigita un numero: "); scanf("%d",&n);

}

printf ("\nhai indovinato ! il numero era proprio %d", numero); printf ("\nci sei riuscito in %d tentativi", cont);

printf ("\n\n\n"); return 0; }

(12)

Proglab 8 – Calcolare n-mo numero di Fibonacci

I numeri di Fibonacci sono definiti ricorsivamente come segue: F0 = 0 F1 = 1 Fn = Fn-1 + Fn-2

Dalla definizione pertanto abbiamo la sequenza: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, …….

0 1 2 3 4 5 6 7 8 9 10

In generale, in una definizione ricorsiva, gli oggetti vengono definiti in termini degli oggetti stessi. Nel nostro caso, l’n-mo numero di Fibonacci è definito come la somma dei due numeri precedenti. La definizione è corretta in quanto la ricorsione si ferma ad F0 = 0 e F1 = 1.

Ad esempio, F4 = F3 + F2 = (F2 + F1) + (F1 + F0) =

((F1 + F0) + F1) + (F1 + F0) = 1 + 0 + 1 + 1 + 0 = 3

In Proglab 1 abbiamo definito iterativamente il fattoriale di un numero naturale e abbiamo scritto una funzione iterativa che lo calcola. Possiamo anche definire ricorsivamente il fattoriale di un numero:

1! = 1 n! = n (n – 1)!

Ad esempio, il fattoriale di 3, in base alla definizione, vale:

3! = 3 x 2! quindi per avere 3! devo calcolare 2! 2! = 2 x 1! quindi per avere 2! devo calcolare 1!

1! = 1 per cui: 2! = 2 x 1 = 2 e infine: 3! = 3 x 2! = 3 x 2 = 6

(13)

Una funzione è detta ricorsiva se viene chiamata all’interno della funzione stessa. Partendo dalla definizione, è immediato scrivere una funzione ricorsiva che calcola il fattoriale o l’n-mo numero di Fibonacci. Le funzioni ricorsive verranno studiate l’anno prossimo nel corso di Algoritmi e Strutture Dati, ora vogliamo sviluppare una funzione iterativa che calcoli l’n-mo numero di Fibonacci.

Riflettendo sul problema, ci accorgiamo che è possibile con un semplice for partire da twoback=0 e oneback=1, sommarle, aggiornare i valori di queste variabili, sommarle ancora finchè si ottiene il numero cercato.

#include <stdio.h> int fib(int n);

main() {

int n, fibon;

printf ("digita il valore di n: "); scanf ("%d", &n);

fibon = fib (n);

printf ("\nil numero di Fibonacci di indice %d vale: %d\n",n, fibon);

return 0; }

int fib(int n) {

int i, twoback, oneback, current;

if (n==0) return 0; else if (n==1) return 1; else { twoback=0; oneback=1;

for (i= 2 ;i <= n; i++) {

current = twoback + oneback;

twoback = oneback; oneback = current; } return current; } }

(14)

Proglab 9 – Sommare gli elementi di due vettori

Vengono letti i vettori A e B di lunghezza n e viene avvalorato il vettore C i cui elementi sono: il primo elemento è la somma del primo di A e l’ultimo di B, il secondo elemento è la somma del secondo di A e il penultimo di B, e così via fino a sommare l’ultimo di A e il primo di B. Ad esempio, se A=[3, 2, 8, 5] e B=[15, 2, 9, 1], abbiamo C=[4,11,10,20] Occorre individuare un’espressione da utilizzare come indice degli elementi di B tale che: 1) quando i vale zero l’espressione vale n-1. 2) al crescere di i, l’espressione decresce.

L’espressione appropriata è: n – i – 1. #include <stdio.h> main() { int i, j, n, A[100], B[100], C[100]; printf("\nnumero di elementi di A e B: "); scanf(" %d", &n);

printf("\ndigita gli elementi di A: "); for (i=0; i<n; i++) {

scanf(" %d", &A[i]); }

printf("\ndigita gli elementi di B: "); for (i=0; i<n; i++) {

scanf(" %d", &B[i]); }

for (i=0; i<n; i++) {

C[i] = A[i] + B[n-i-1]; }

for (i=0; i<n; i++) {

printf (" \n%d", C[i]); }

printf ("\n\n"); return(0); }

(15)

Proglab 10 – Inversione di un vettore su se stesso

Viene letto il vettore int A di lunghezza n e i suoi elementi vengono invertiti, cioè il primo elemento assume il valore dell’ultimo, il secondo il valore del penultimo, e così via. Non utilizzare vettori ausiliari.

Ad esempio, se A = [32, 8 , 76, 21] si trasforma in A = [21, 76, 8, 32] -Per scambiare i valori due variabili a e b, occorre una variabile x di appoggio e la sequenza di istruzioni è: x = a; a = b; b = x;

-L’ultimo scambio avviene quando i raggiunge il valore n/2 – 1. Nel nostro esempio n=4 e l’ultimo scambio coinvolge A[1] e A[2]. Tenere presente che, in caso di n dispari, è presente un elemento centrale che non viene scambiato. Ad es.: [32, 8 , 76, 21, 14]  [14, 21, 76, 8, 32]. #include <stdio.h> main() { inti, j, n, x, A[100]; printf("\nnumero di elementi di A: "); scanf(" %d", &n);

printf("\ndigita gli elementi di A: "); for (i=0; i<n; i++) {

scanf(" %d", &A[i]); }

for (i=0; i<n/2; i++) { x = A[i];

A[i] = A[n-i-1]; A[n-i-1] = x; }

for (i=0; i<n; i++) {

printf("%d ", A[i]); }

printf("\n\n"); return(0); }

(16)

Proglab 11 – Individuare elementi comuni in due vettori

Il programma legge due vettori int A e B di lunghezza n e m e stampa gli elementi presenti in entrambi i vettori.

Ad esempio, se A = [4, -8, 33, 98, -2] e B = [ -21, 44, 4, -2] vengono stampati 4 e -2.

Riflettendo sul problema, si arriva al seguente algoritmo: una volta letti i due vettori, per ogni elemento di A bisogna effettuare la sua ricerca in tutto B e se lo si trova lo si stampa. Occorrono due for annidati con indici diversi. Il for esterno realizza la frase “per ogni elemento di A”, il for interno il resto dell’algoritmo.

#include <stdio.h> main()

{

int i, j, n, m, flag, A[100], B[100]; printf("numero di elementi di A: "); scanf("%d", &n);

printf("digita gli elementi di A: "); for (i=0; i<n; i++)

scanf("%d", &A[i]);

printf("numero di elementi di B: "); scanf("%d", &m);

printf("digita gli elementi di B: "); for (i=0; i<m; i++)

scanf("%d", &B[i]);

printf("elementi comuni ad A e B: "); for (i=0; i<n; i++) {

for (j=0; j < m; j++) if (A[i] == B[j]) { printf("%d ", A[i]); break; } } printf("\n"); return(0); }

(17)

Proglab 12 – Prodotto somma diagonali matrice

La funzione main legge l’ordine n della matrice quadrata int A e chiama una funzione che legge i suoi elementi. Quindi main calcola e stampa il prodotto della somma delle due diagonali della matrice.

Ad esempio, se n=3 e la matrice A è: 3 5 1

4 2 3 5 1 7

la diagonale principale ha somma 12 e la secondaria 8 pertanto il loro prodotto vale 96.

#include <stdio.h>

void leggimatrice(int A[][100], int n); main()

{

int A[100][100], n, i, s1, s2; printf("ordine della matrice: "); scanf("%d", &n);

leggimatrice(A, n); s1 = 0;

s2 = 0;

for (i=0; i<n; i++) { s1 = s1 + A[i][i]; s2 = s2 + A[i][n-i-1]; }

printf("\nprodotto somma diagonali = %d\n", s1*s2); return(0);

}

void leggimatrice(int A[][100], int n) {

inti, j;

for (i=0; i<n; i++) {

printf("elementi della riga di indice %d: ", i); for (j=0; j<n; j++)

scanf("%d", &A[i][j]); }

return; }

(18)

Proglab 13 – Inserire vettore al centro di un altro

La funzione main chiama due volte una funzione per leggere prima il vettore float A lungo n e poi il vettore float B lungo m. Poi main chiama una funzione che inserisce il vettore B al centro di A. Infine main stampa il vettore A così modificato.

Ad esempio, se n=4 e m=3 e A=(2.5, 6.7, 1.4, 7.1) e B=(3.8, 1.9, 9.2), il vettore A diventa: A = (2.5, 6.7, 3.8, 1.9, 9.2, 1.4, 7.1)

Per inserire B al centro di A bisogna innanzitutto spostare la seconda metà di A (partendo dall’ultimo elemento) di m posti a destra (primo for). Poi si può inserire B nello spazio liberato (secondo for).

#include <stdio.h> intleggiarray(float x[]);

void inserisci(float x[], float y[], int n, int m); void stamparray(float x[], int n);

main() { float A[100], B[100]; int n, m; n = leggiarray(A); m = leggiarray(B); inserisci(A, B, n, m); stamparray(A, n+m); return(0); }

(19)

void inserisci(float x[], float y[], int n, int m) {

inti;

for (i=n-1; i>=n/2; i--) x[i+m] = x[i]; for (i=n/2; i<n/2+m; i++)

x[i] = y[i - n/2]; return; } int leggiarray(float x[]) { int n, i;

printf ("\ndimensione array \? "); scanf(" %d", &n);

for (i=0; i<n; i++)

scanf(" %f", &x[i]); return(n);

}

void stamparray(float x[], int n) {

int i;

for (i=0; i<n; i++)

printf(" %f ", x[i]); printf("\n\n");

return; }

(20)

Proglab 14 – Vettore di numeri casuali non multipli di k

main legge i numeri interi n, k, a e b e chiama una funzione che costruisce un vettore di n numeri casuali x tali che non sono multipli di k e inoltre a  x  b. Quindi main chiama una funzione che stampa il vettore.

Ad esempio, se n=4, k=2, a=50, b=200, il vettore potrebbe essere: A=[53, 121, 187, 73]

#include <stdio.h> #include <time.h>

int costruisciarray(int X[]); void stamparray(int X[], int n); main() { int A[100], n; n = costruisciarray(A); stamparray(A, n); return(0); } int costruisciarray(int X[]) { int a, b, i, n, k;

printf (“\ndigita i valori di a e b: “); scanf (“%d%d”, &a, &b);

printf("digita i valori di n e k: "); scanf("%d %d", &n, &k);

srand(time(NULL)); for (i=0; i<n; i++) {

X[i] = rand()%(b – a +1) + a; if (X[i] % k == 0) i--; } return(n); }

(21)

Proglab 15 – Stampare h-ma riga e k-ma colonna

main legge una matrice intera n x m. Poi legge gli indici h e k e stampa la riga di indice h e la colonna di indice k.

Ad esempio, se la matrice è: 3 7 2 9

1 8 7 6 8 3 4 8

e gli indici sono h=1 e k=2 viene stampata la riga: 1 8 7 4 e la colonna: 2 7 4

#include <stdio.h> main()

{

int A[100][100], i, j, n, m, h, k;

printf("numero di righe e di colonne: "); scanf("%d %d", &n, &m);

printf("digita gli elementi della matrice: "); for (i=0; i<n; i++) {

for (j=0; j<m; j++) {

scanf("%d", &A[i][j]); }

}

printf("digita indice di riga e indice di colonna: "); scanf("%d %d", &h, &k);

printf("riga %d: ", h); for (j=0; j<m; j++)

printf("%d ", A[h][j]); printf("\ncolonna %d: ", k); for (i=0; i<n; i++)

printf("%d ", A[i][k]); return(0);

(22)

Proglab 16–Elementi presenti nel vettore B ma non in A

Il programma legge due vettori interi A e B (lunghi n ed m) e stampa gli elementi presenti in B ma non in A.

Ad esempio, se A=[5, 7, 2] e B=[2, 9, 5, 8] stampiamo 9 e 8.

Per ogni elemento del vettore B occorre vedere se esso è presente in A, per cui occorre il for esterno for (i=0; i<m; i++).

Il for interno for (j=0; j<n; j++) deve confrontare l’i-mo elemento di B con tutti gli elementi di A in quanto solo quando anche l’n-mo confronto dà esito negativo si può concludere che l’i-mo di B non è presente in A. Un modo per gestire il problema è uscire con un break dal for interno quando B[i] == A[j]. In tal caso il valore di j sarà al massimo n-1. Se invece j vale n significa che tutti i confronti hanno dato esito negativo per cui debbo stampare B[i].

#include <stdio.h> main() { int i, j, n, m, A[100], B[100]; printf("numero di elementi di A: "); scanf("%d", &n);

printf("digita gli elementi di A: "); for (i=0; i<n; i++)

scanf("%d", &A[i]);

printf("numero di elementi di B: "); scanf("%d", &m);

printf("digita gli elementi di B: "); for (i=0; i<m; i++)

(23)

printf("elementi presenti in B ma non in A: "); for (i=0; i<m; i++) {

for (j=0; j<n; j++) if (B[i] == A[j]) break; if (j==n) printf("%d ", B[i]); } printf("\n"); return(0); }

Un altro modo, più semplice, di risolvere il problema è utilizzare un variabile flag con questo significato: flag 1 significa che B[i] non è presente in A, flag 0 che lo è. Prima di entrare nel for interno metto a 1 il flag e se un confronto dà esito positivo lo metto a 0. Quando esco dal for interno se il flag vale ancora 1 stampo B[i].

printf("elementi presenti in B ma non in A: "); for (i=0; i<m; i++) {

flag = 1; for (j=0; j<n; j++) if (B[i] == A[j]) flag = 0; if (flag == 1) printf("%d ", B[i]); }

(24)

Proglab 17 – Eliminare i multipli di k in un vettore

La funzione main chiama una funzione che legge n numeri interi, main legge poi un numero intero k e chiama una funzione che elimina dal vettore, compattandolo, gli eventuali multipli di k, infine main chiama una funzione che stampa il vettore modificato.

Ad esempio, se n=5, k=3 e A=[23, 33, 14, 72, 26], il vettore diventa: A=[23, 14, 26]

Nel caso in cui A[i] è multiplo di k devo eliminare A[i] dal vettore, per cui la sua lunghezza diminuisce di 1. Ora devo spostare tutti gli elementi che seguono A[i] di un posto a sinistra. L’istruzione i-- è importante. Riferendoci all’esempio, quando i=1, A[i] vale 33, viene effettuato il compattamento e 14 va al posto di 33. Poi i diventa 0, la i++ me lo riporta a 1 e viene correttamente controllato se 14 è anche lui multiplo di 3. In assenza di i-- il controllo non verrebbe effettuato.

#include <stdio.h> int leggi_array(int A[]);

int elimina_multipli(int A[], int n, int k); void stampa_array(int A[], int n);

main() { int n, A[100], k; n = leggi_array(A); printf("digita k: "); scanf("%d", &k); n = elimina_multipli(A, n, k); stampa_array(A, n); return(0); }

(25)

int leggi_array(int A[]) { int i, n; printf("numero di elementi: "); scanf("%d", &n); printf("digita %d elementi: ", n); for (i=0; i<n; i++)

scanf("%d", &A[i]); return(n);

}

void stampa_array(int A[], int n) {

int i;

for(i=0; i<n; i++)

printf("%d ", A[i]); printf("\n");

return; }

int elimina_multipli(int A[], int n, int k) {

int i, j;

for (i=0; i < n; i++) {

if (A[i] % k == 0) { n = n-1; for (j=i; j<n; j++) { A[j] = A[j+1]; } i--; } } return(n); }

(26)

Proglab 18 –Verificare se una parola è palindroma

Il programma chiede di digitare una parola e individua se essa è palindroma, cioè leggibile da sinistra a destra o viceversa (osso, oro, aveva, ingegni, ossesso, onorarono, etc.)

Algoritmo. Verificare se il primo carattere coincide con l’ultimo, poi se il secondo coincide con il penultimo, e così via.

Domanda 1: quando deve arrestarsi la verifica ?

Domanda 2: S[i] va confrontato con S[j]. Quanto deve valere j ? Domanda 3: quale test effettuare per rispondere SI’-NO ?

Risposta 1: non appena un confronto fra lettere corrispondenti fallisce, la verifica si arresta perché la parola non è palindroma.

Vediamo quando fermarsi se invece la parola è palindroma. Consideriamo le due parole palindrome “osso” (n=4 indici da 0 a 3) e “onorarono” (n=9 indici da 0 a 8).

Nel caso di “osso” l’ultimo confronto (‘s’ con ‘s’) si ha quando i=1 (i < 4/2 = 2),

nel caso di “onorarono” l’ultimo confronto (‘r’ con ‘r’) si ha quando i=3 (i <  9/2  = 4).

Perciò, in generale, il valore massimo che può assumere i è  n/2  - 1. Risposta 2. Il primo confronto avviene tra S[0] e S[n-1], il secondo tra S[1] e S[n-2], e così via per cui occorre un’espressione che, al crescere di i, decresce. Tale espressione è (n - i -1).

Risposta 3. La struttura di iterazione più indicata è il for. Se un confronto fallisce esco dal for con un break, altrimenti vado avanti con i confronti. Quando esco dal for, se i=n/2 significa che tutti i confronti hanno dato esito positivo e sono uscito dal for perché i ha raggiunto il valore n/2, se invece i<n/2 significa che un confronto ha dato esito negativo e sono uscito dal for per effetto del break.

(27)

#include <stdio.h> #include <string.h> main() { char S[50]; int i, n;

printf("digita una parola: "); scanf("%s", S);

n = strlen(S);

for (i=0; i<n/2; i++) { if (S[i] != S[n-i-1])

break; }

if (i == n/2)

printf("la parola \"%s\" e' palindroma.\n", S); else

printf("la parola \"%s\" non e' palindroma.\n", S); return(0);

}

Poichè esco dal for se S[i] != S[n-i-1] significa che se S[i] == S[n-i-1] devo restare nel for, per cui posso scrivere equivalentemente:

for (i=0; i<n/2 && S[i] == S[n-i-1]; i++) { ;

(28)

Alla Domanda 3 si può anche rispondere utilizzando una variabile flag inizialmente avvalorata con 1 e azzerata se un confronto fallisce.

main() {

char S[50]; int i, n, flag = 1;

printf("digita una parola: "); scanf("%s", S);

n = strlen(S);

for (i=0; i<n/2; i++) { if (S[i] != S[n-i-1])

flag = 0; }

if (flag == 1)

printf("la parola \"%s\" e' palindroma.\n", S); else

printf("la parola \"%s\" non e' palindroma.\n", S); return(0);

(29)

Proglab 19 – Terne il cui prodotto < media vettore

La funzione main chiama una funzione che genera un vettore casuale di n interi compresi fra -10 e 10 e lo stampa. Poi main stampa, se presenti, le terne di numeri il cui prodotto è minore della media di tutti gli elementi del vettore.

Ad esempio, se il vettore generato è: x = [9, 10, 1, -7, 6, -2]

la media vale 9 +10 + 1 – 7 + 6 – 2 = 17 = 3.4 5 5

ed esistono le terne (10, 1, -7) e (1, -7, 6) il cui prodotto degli elementi è minore della media (-70 e -42).

Usualmente, noi stampiamo tutti gli elementi di un array. La funzione stamparray è invece fatta in modo da stampare p elementi a partire dall’elemento di indice k. Osserviamo che, nella chiamata di una funzione, i parametri attuali possono essere delle costanti. Ciò accade in stamparray(v, i, 3) e nella funzione hanoi vista a lezione. Ovviamente, la soluzione più semplice è usare direttamente la printf per stampare la terna di numeri.

#include <stdio.h> #include <time.h> int generarray(int x[]);

float mediarray(int x[], int n);

void stamparray(int x[], int k, int p); main() { int i, n, v[300]; float m; n = generarray(v); stamparray(v, 0, n); m = mediarray(v, n); printf ("\nmedia = %f\n\n", m);

(30)

for (i=0; i<=n-3; i++) { if (v[i]*v[i+1]*v[i+2] < m) stamparray(v, i, 3); } return(0); } int generarray(int x[]) { int n, i; printf("numero di elementi: "); scanf("%d", &n); srand(time(NULL)); for (i=0; i<n; i++) {

x[i] = rand()%10 + 1; }

return(n); }

float mediarray(int x[], int n) {

int i;

float m = 0.0;

for (i=0; i<n; i++) { m = m + x[i]; }

m = m/n; return(m); }

void stamparray(int x[], int k, int p) {

int i;

for (i=k; i<k+p; i++)

printf("%d ", x[i]); printf("\n");

return; }

(31)

Proglab 20 – Colonna con max numero elementi dispari

La funzione main legge le dimensioni della matrice int A e chiama una funzione che avvalora i suoi elementi. Quindi main individua la colonna di A avente il massimo numero di elementi dispari (se ce ne sono più di una, se ne prende una) e stampa l’indice di tale colonna e i suoi elementi.

IMPORTANTE: organizzare il programma in funzioni, non utilizzare array ausiliari, non introdurre variabili globali.

Ad esempio, se la matrice A è: 3 7 2 9

1 5 7 6 8 3 4 8

la prima colonna ha due elementi dispari, la seconda colonna ha tre elementi dispari, la terza e la quarta uno. Viene stampato quindi l’indice della seconda colonna (1) e i suoi elementi (7 5 3).

Analogamente a quanto accade in tutti i problemi di massimo e minimo, occorre introdurre due variabili: cmax e jmax per contenere il numero massimo di dispari e l’indice della relativa colonna. Prima di entrare nel for che esamina in sequenza le colonne della matrice, occorre inizializzare cmax con il numero di dispari nella prima colonna e jmax con il suo indice (0). In linguaggio pseudo-C abbiamo:

cmax = n. dispari nella prima colonna jmax = 0

for (j=1; j<m; j++) {

c = n. dispari nella j-ma colonna if (c > cmax) {

jmax = j; cmax = c; }

(32)

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

void leggimatrice(int A[100][100], int n, int m); int contadispari(int A[100][100], int n, int j); main()

{

int A[100][100], n, m, j, jmax, c, cmax; printf("numero di righe e di colonne: "); scanf("%d %d", &n, &m);

leggimatrice(A, n, m); jmax = 0; cmax = contadispari(A, n, 0); for (j=1; j<m; j++) { c = contadispari(A, n, j); if (c > cmax) { jmax = j; cmax = c; } }

printf("\nla colonna con il maggior numero di elementi dispari \ne' quella di indice %d: ", jmax);

printf("\n\n"); for (j=0; j<n; j++) printf("%d ", A[j][jmax]); printf("\n\n"); return(0); }

(33)

void leggimatrice(int A[][100], int n, int m) {

int i, j;

for (i=0; i<n; i++) {

printf("elementi della riga di indice %d: ", i); for (j=0; j<m; j++)

scanf("%d", &A[i][j]); }

return; }

int contadispari(int A[100][100], int n, int j) {

int i, c = 0;

for (i=0; i<n; i++)

if (A[i][j] % 2 == 1) c++; return(c);

(34)

Proglab 21 – La più lunga sequenza crescente

La funzione main chiama una funzione che avvalora un vettore A int di lunghezza n, poi main individua e stampa la più lunga sequenza di elementi crescenti contigui.

IMPORTANTE: non utilizzare vettori ausiliari.

Ad esempio, se A = [44, 12, 15, 8, 36, 36, 75, 24, 42, 88, 71]

vi sono tre sequenze crescenti: 12, 15 8, 36, 36, 75 24, 42, 88 e viene stampata la sequenza 8, 36, 36, 75

Analogamente a quanto accade in Proglab 19, occorre introdurre due variabili: lungmax per contenere la massima lunghezza e imax per contenere l’indice del primo elemento della sequenza di massima lunghezza. Prima di entrare nel for che individua tale sequenza, azzeriamo lungmax e imax.

if (A[i] <= A[i+1]) viene incrementato il contatore k e if (k>lungmax) vengono modificati i valori di lungmax e imax. Altrimenti viene azzerato k e con j = i+1 viene avvalorato j con l’indice dell’elemento da cui potrebbe iniziare la sequenza di lunghezza massima.

(35)

#include <stdio.h> int leggivettore(int A[]); main()

{

int A[50], i, j, k, n, lungmax, imax; n = leggivettore(A);

k = 0; j = 0;

lungmax = 0; imax = 0;

for (i=0; i<n-1; i++) { if (A[i] <= A[i+1]) { k++; if (k>lungmax) { imax = j; lungmax = k; } } else { j = i+1; k = 0; } }

for (i=imax; i<=imax+lungmax; i++) printf("%d ", A[i]);

printf("\n\n"); return(0); }

int leggivettore (int x[]) {

int n, i;

printf ("\ndimensionevettore \? "); scanf(" %d", &n);

for (i=0; i<n; i++)

scanf(" %d", &x[i]); return(n);

(36)

Proglab 22 – Verificare se il prodotto righe è crescente

La funzione main chiama una funzione che costruisce una matrice n x m di numeri casuali tali che -30  A[i][j]  30. Poi main chiama una funzione che verifica se il prodotto di ogni riga è  a quello della riga successiva. Infine main stampa “sì” o “no” a seconda del risultato.

Ad esempio, se la matrice A è: 3 1 2 4

1 4 2 6 3 3 8 1 2 7 9 1

il prodotto degli elementi della prima riga vale 24 il prodotto della seconda riga vale 48

la terza riga vale 72 la quarta riga vale 126 per cui la risposta è sì

Se, invece, ad esempio, la terza riga è: 2 4 1 4

(37)

Si esce dal for esterno in due casi:

1) perché tutte le n-1 verifiche hanno avuto successo, si è giunti al termine dell’iterazione e quindi il valore di i all’uscita dal for è n-1 (nel for, i viene prima incrementato e poi viene controllata la condizione: l’ultima iterazione è stata fatta con i=n-2 poi i viene incrementato, passa a n-1 e la condizione non è più verificata)

2) perché p1 > p2 cioè il prodotto di una riga ha un valore maggiore di quello della riga successiva. In questo caso i ha un valore diverso da n-1.

Pertanto, controllando il valore di i sappiamo se la matrice ha le caratteristiche volute oppure no.

Non è obbligatorio utilizzare l’operatore AND nell’intestazione del for. Siamo nella stessa situazione di Proglab 17 (verifica parola palindroma), il for può essere sostituito da queste istruzioni:

for (i=0; i<n-1; i++) { if (p1 > p2)

break; #include <stdio.h> #include <time.h> #define MAX 100

void generamatrice(int A[MAX][MAX], int n, int m); int verifica(int A[MAX][MAX], int n, int m);

void stampamatrice(int A[MAX][MAX], int n, int m); main()

{

int n, m, A[MAX][MAX];

printf("numero di righe e di colonne della matrice: "); scanf("%d %d", &n, &m);

generamatrice(A, n, m); stampamatrice(A, n, m); if (verifica(A, n, m) == 1) printf("si'\n"); else printf("no\n"); return(0); }

(38)

void generamatrice(int A[MAX][MAX], int n, int m) {

int i, j;

srand(time(NULL)); for (i=0; i<n; i++)

for (j=0; j<m; j++)

A[i][j] = rand() % 61 - 30; return;

}

int verifica(int A[MAX][MAX], int n, int m) {

int p1, p2, i, j; p1 = 1;

p2 = 1;

for (i=0; i<n-1 && p1<=p2; i++) { p1 = 1; p2 = 1; for (j=0; j<m; j++) { p1 = p1*A[i][j]; p2 = p2*A[i+1][j]; } } if (i == n-1) return(1); else return(0); }

void stampamatrice(int A[MAX][MAX], int n, int m) {

int i, j;

for (i=0; i<n; i++) { for (j=0; j<m; j++)

printf("%4d ", A[i][j]); printf("\n");

}

(39)

Proglab 23 – Verificare se in una matrice vi sono

righe e colonne aventi la stessa somma

Leggere n e m e generare una matrice n x m di numeri casuali compresi tra 0 e 5. Verificare se esiste una riga della matrice in cui la somma degli elementi sia uguale alla somma degli elementi di una colonna. In caso positivo stampare i relativi indici di riga e colonna e il valore della somma, in caso negativo segnalare la cosa. In caso positivo per più righe e/o colonne stampare gli indici della prima coppia riga-colonna incontrata e stop.

IMPORTANTE: Organizzare il programma in funzioni (una per generare la matrice, una per stamparla, una per fare la verifica). Non utilizzare array ausiliari, non introdurre variabili globali.

Esempio. Sia n = 2 e m = 4 e supponiamo che la matrice sia: 1 4 2 2

0 3 0 1

Nessuna riga ha somma uguale a qualche colonna. Esempio. Sia n = 3 e m = 5 e la matrice sia:

0 3 1 2 1 4 3 0 1 3 0 2 0 4 2

La riga di indice 2 ha la stessa somma della colonna di indice 1 (8).

(40)

#include <stdio.h> #include <time.h> #define MAX 5

void generamatrice(int A[100][100], int n, int m); void printmatrice(int A[100][100], int n, int m); void verificamatrice(int A[100][100], int n, int m); main(void) {

int n, m, A[100][100];

printf("numero di righe e di colonne: "); scanf("%d %d", &n, &m);

generamatrice(A, n, m); printmatrice(A, n, m); verificamatrice(A, n, m); return 0;

}

void generamatrice(int A[100][100], int n, int m) { int i, j;

srand(time(NULL)); for (i=0; i<n; i++) for (j=0; j<m; j++)

A[i][j] = rand() % MAX; return;

}

void printmatrice(int A[100][100], int n, int m) { int i, j;

printf("\n\n");

for (i=0; i<n; i++) { for (j=0; j<m; j++) printf("%2d ", A[i][j]); printf("\n"); } printf("\n\n"); return; }

(41)

ALGORITMO:

Scorrere righe matrice

Calcolare somma i-ma riga Scorrere colonne matrice

Calcolare somma j-ma colonna

Se somma riga = somma colonna return void verificamatrice(int A[100][100], int n, int m) {

int i, j, k, somriga, somcol, flag = 0; for (i=0; i<n && flag == 0; i++) { somriga = 0;

for (j=0; j<m; j++)

somriga = somriga + A[i][j]; for (j=0; j<m && flag == 0; j++) { somcol = 0;

for (k=0; k<n; k++)

somcol = somcol + A[k][j]; if (somcol == somriga) {

flag = 1;

printf("la riga di indice %d ha somma uguale alla colonna di indice %d (%d)\n", i, j, somcol); }

} }

if (flag == 0)

printf("non sono presenti righe e colonne con la stessa somma");

printf("\n\n"); return; }

Nel momento in cui la ricerca ha successo, il flag viene messo a 1, si stampano i valori degli indici e della somma e si esce dal secondo e poi dal primo for. L’operatore && può essere sostituito (Proglab 17) da questo if: if (flag != 0) break;

Nel terzo for possiamo utilizzare l’indice j usato anche nel secondo in quanto i due for non sono “nested”. Per il quarto for dobbiamo invece usare un indice diverso (k) poiché questo for è annidato nel terzo.

(42)

Proglab 24 – Cubo di un numero (puntatori)

main legge un intero e chiama una funzione che ne calcola il cubo e restituisce il suo valore a main. main stampa tale valore.

Doppia versione: passaggio per valore e per riferimento.

#include <stdio.h> #include <stdlib.h> int calcolacubo (int n);

main() {

int numero, numeroalcubo; printf ("digita un numero: "); scanf ("%d", &numero);

numeroalcubo = calcolacubo (numero);

printf ("\nil suo cubo vale: %d", numeroalcubo); return 0;

}

int calcolacubo (int n) {

return n * n * n; }

#include <stdio.h> #include <stdlib.h> int calcolacubo (int *n);

main() {

int numero, numeroalcubo; printf ("digita un numero: "); scanf ("%d", &numero);

numeroalcubo = calcolacubo (&numero);

printf ("\nil suo cubo vale: %d", numeroalcubo); return 0;

}

int calcolacubo (int *n) {

return *n * *n * *n; }

calcolacubo riceve l’indirizzo di numero e tramite l’operatore * accede al valore contenuto in quell’indirizzo. Notare il differente significato dell’ *: moltiplicazione e, a sinistra di un puntatore, accesso al valore puntato.

(43)

Proglab 25 – Inverso di un vettore (puntatori)

main, servendosi del puntatore ptr, legge un vettore int di n elementi e poi lo stampa in ordine inverso.

Ad esempio, se il vettore è X = (3, 6, 8, 2, 7) viene stampata la sequenza: 7 2 8 6 3. #include <stdio.h> #include <stdlib.h> main() { int x[10], n, *ptr; printf("\n\ndimensione vettore ? "); scanf(" %d", &n); printf("\n\ndigita %d numeri: ", n); for (ptr = x; ptr < x+n; ptr++) scanf("%d", ptr);

printf("\n\nvettore in ordine inverso: "); for (ptr = x+n-1; ptr >= x; ptr--)

printf(" %d", *ptr); printf ("\n\n");

return(0); }

Il programma è analogo a Prog 62: ptr assume inizialmente il valore x (indirizzo del primo elemento del vettore x), viene letto il primo elemento, poi ptr viene incrementato di 1, ma in effetti essendo ptr un puntatore a interi, ptr aumenta di 4, cosicchè assume come valore l’indirizzo del primo dei quattro byte riservati per contenere x[1], e così via.

Ad esempio, supponendo che lo spazio riservato per il vettore vada dal byte 720 al byte 759, si esce dal for quando, letto il decimo elemento e inserito nei byte 756-759, ptr viene incrementato, assume il valore 760 e la condizione non è più verificata:

ptr = 760 non è minore di x + n = 720 + 10*4 = 760.

Nel secondo for, ptr vale inizialmente x+n-1 = 720 + 10*4 – 4 = 756, cioè proprio l’indirizzo di x[9], ultimo elemento del vettore.

(44)

Proglab 26 – Max tra due numeri (puntatori)

main legge due numeri e chiama una funzione passando i loro indirizzi. La funzione individua quale dei due ha il massimo valore e restituisce a main il relativo puntatore. main stampa il valore del massimo.

#include <stdio.h> #include <stdlib.h> int *max (int *a, int *b);

main() {

int *ptr, a, b;

printf("\n\ndigita i due numeri: "); scanf("%d%d", &a, &b);

ptr = max (&a, &b);

printf("\nil max dei due numeri vale %d\n\n", *ptr); return(0);

}

int *max (int *a, int *b) { if (*a > *b) return a; else return b; }

Anche senza sapere cosa calcola la funzione max, il suo prototipo ci fornisce queste informazioni:

la funzione riceve in input due puntatori a interi e restituisce, associato al nome della funzione, un puntatore a interi.

Guardando ora la funzione max, vediamo che essa, ricevendo gli indirizzi delle variabili a e b, tramite l’operatore * accede ai loro valori e, se il primo numero è maggiore del secondo, restituisce a main l’indirizzo della prima variabile, altrimenti l’indirizzo della seconda.

main inserisce tale indirizzo in ptr e poi, tramite l’operatore * stampa il valore del numero.

(45)

Proglab 27 – Elemento centrale vettore (puntatori)

main legge un vettore di n numeri e chiama una funzione passando n e il vettore. La funzione restituisce a main il puntatore all’elemento centrale del vettore. main stampa il valore di tale elemento.

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

int *centrale (int x[], int n); main() { int x[50], n, i, *ptr; printf("\n\ndimensione vettore ? "); scanf(" %d", &n); printf("\n\ndigita %d numeri: ",n); for (i=0; i < n; i++)

scanf("%d", &x[i]); ptr = centrale (x, n);

printf("\nl'elemento centrale del vettore vale: %d\n\n", *ptr); return(0);

}

int *centrale (int x[], int n) {

return &x[n/2]; }

Analogamente a Proglab 26, la funzione restituisce a main l’indirizzo dell’elemento centrale del vettore, main lo inserisce in ptr e poi, utilizzando l’operatore *, stampa il valore di tale elemento.

(46)

Proglab 28 – Max e min in un vettore (puntatori)

main legge un vettore di n numeri e chiama una funzione passando il vettore e gli indirizzi delle variabili max e min. La funzione avvalora le variabili max e min e restituisce il controllo a main. main stampa i valori di max e min.

#include <stdio.h> #include <stdlib.h> void maxmin (int x[], int n, int *max, int *min); main()

{

int x[50], n, i, max, min;

printf("\n\ndi quanti numeri vuoi calcolare max e min? "); scanf(" %d", &n);

printf("\n\ndigita %d numeri: ",n); for (i=0; i < n; i++)

scanf("%d", &x[i]); maxmin (x, n, &max, &min);

printf("\nil max dei %d numeri digitati e' %d, mentre il min e' %d\n\n", n, max, min);

return(0); }

void maxmin (int x[], int n, int *max, int *min) {

int i;

*max = *min = x[0]; for (i=1; i<n; i++) if (x[i] < *min) *min = x[i]; else if (x[i] > *max) *max = x[i]; }

Una funzione può restituire, associato al suo nome, zero valori (funzione void) o, al massimo, un solo valore. maxmin deve individuare due valori per cui deve ricevere gli indirizzi di max e min e, tramite l’operatore *, modificare opportunamente i valori delle due variabili.

(47)

Esercizi sulle funzioni di input/output

Le funzioni di input/output sono ovviamente essenziali per la scrittura di programmi. Finora ci siamo serviti soprattutto delle funzioni scanf, printf, getchar, putchar. Quando abbiamo introdotto i file, abbiamo esemplificato le corrispondenti funzioni fscanf, fprintf, fgetc, fputc.

Vi sono molte altre funzioni la qual cosa non deve stupire: per manipolare una matrice presente in memoria le istruzioni che abbiamo studiato sono necessarie e sufficienti, ma gli elementi della matrice potranno essere stati introdotti da input diversi e in forma diversa (caratteri, stringhe, numeri forniti uno alla volta o su righe diverse e con separatori di vario tipo (spazi o caratteri speciali). Anche i risultati del programma potranno avere una grande varietà di possibili formati e tutto ciò rende opportuno esaminare con più attenzione le caratteristiche basilari delle funzioni di input/output. In C lo standard input (stdin) è la tastiera e lo standard output (stdout) lo schermo: questi stream non vanno dichiarati, non vanno aperti né chiusi. Invece, abbiamo prima visto che per gestire un file occorre definire un file

pointer (fp) ed effettuare l’apertura del file e la sua successiva chiusura.

Esiste anche un terzo stream standard (standard error, stderr) che può essere utilizzato per mandare su schermo i messaggi di errore (stderr, a differenza di stdout, non può essere reindirizzato dallo schermo a un file). Trasferire dati da/in un disco è un’operazione lenta rispetto alla velocità con la quale opera la CPU, per cui sarebbe irrazionale accedere a un disco ogniqualvolta bisogna leggere o scrivere un byte. Il buffering è la tecnica per cui i dati scritti su uno stream vengono mantenuti in un’area di memoria (buffer). Quando il buffer è pieno (o si chiude il file) il buffer viene svuotato (flush) trasferendo il suo contenuto sul disco. Il simmetrico avviene per la lettura dei dati. Questi trasferimenti “in blocco” rendono più efficienti le operazioni I/O e vengono gestiti automaticamente. Vi sono però rare situazioni in cui risulta utile la funzione fflush (fpt) che svuota il buffer associato al file pointer fpt.

(48)

Le funzioni di input/output rientrano in tre classi: 1) I/O formattato

2) I/O di caratteri 3) I/O di righe

Di seguito esaminiamo le funzioni più utilizzate delle tre classi nel contesto di programmi esempio che si limitano ad effettuare lettura e scrittura su file.

1) Input/output formattato

Le funzioni appartenenti a questa classe si servono di una stringa di controllo per gestire correttamente la lettura e la scrittura dei dati. Le ben note scanf e printf, al pari di fscanf e fprintf, sono le sole a poter convertire i dati input dalla forma testuale a quella numerica e fare il viceversa per i dati output. Le prime due funzioni lavorano su stdin e stdout mentre le altre due sullo stream individuato dal file pointer.

Proglab 29 – I/O di un vettore numerico

Prima di eseguire il programma, occorre creare il file di testo contenente i numeri. Accedere al “Blocco note” e digitare i numeri su una o più righe. Ad esempio:

567 23 89

231 4 678 45 890

Salvare con, ad esempio, il nome “inputvet”.

Eseguire il programma fornendo il nome del file input: inputvet.txt e il nome del file output: outputvet.txt (ad esempio).

Terminata l’esecuzione, in outputvet troviamo: 567 23 89 231 4 678 45 890

(49)

#include <stdio.h> #include <stdlib.h> #define MAXVET 50 FILE *aprifile(char *);

int readvet(FILE *fpin, int vet[]); void printvet (int vet[], int n);

void writevet(FILE *fp, int vet[], int n); main()

{

int vet[MAXVET], n; FILE *fpin, *fpout; fpin = aprifile("r"); n = readvet(fpin, vet); printvet (vet, n); fclose(fpin); fpout = aprifile("w"); writevet(fpout, vet, n); fclose(fpout); return EXIT_SUCCESS; }

FILE *aprifile(char* tipo) {

char nomefile[MAXVET]; FILE *fptr;

printf("\n\ndigitare nome file: "); scanf("%s", nomefile);

if((fptr = fopen(nomefile, tipo)) == NULL) {

printf("errore apertura file %s\n", nomefile); exit(EXIT_FAILURE);

}

return fptr; }

int readvet(FILE *fpin, int vet[]) {

int n=0;

while (! feof(fpin)) {

fscanf (fpin,"%d", &vet[n]); n++;

}

return(n); }

(50)

void printvet (int vet[], int n) { int i, j; for (i = 0; i < n; i++) { printf ("%5d", vet[i]); printf ("\n"); } return; }

void writevet(FILE *fp, int vet[], int n) { int i; for (i = 0; i < n; i++) { fprintf (fp, "%6d", vet[i]); } }

Proglab 30 - I/O di una matrice numerica

Con il “Blocco note” creiamo, ad esempio, il file input inputmat: 3 4

56 23 11 77 5 78 4 672 764 3 13 45

Eseguiamo il programma (la funzione aprifile è sempre la stessa) fornendo il nome del file input: inputmat.txt e il nome del file output: outputmat.txt. Terminata l’esecuzione, in outputmat troviamo:

56 23 11 77 5 78 4 672 764 3 13 45 #include <stdio.h> #include <stdlib.h> #define MAXRIGHE 50 #define MAXCOL 50 FILE *aprifile(char *);

void readmatrix(FILE *fpin, int mat[][MAXCOL], int *n, int *m); void printmatrix (int mat[][MAXCOL], int n, int m);

(51)

main() {

int mat[MAXRIGHE][MAXCOL], n, m;

FILE *fpin, *fpout; fpin = aprifile("r");

readmatrix(fpin, mat, &n, &m);

printmatrix (mat, n, m); fclose(fpin); fpout = aprifile("w"); writematrix(fpout, mat, n, m); fclose(fpout); return EXIT_SUCCESS; }

void readmatrix(FILE *fpin, int mat[][MAXCOL], int *n, int *m) {

int i, j;

fscanf (fpin, "%d%d", n, m); for (i = 0; i < *n; i++) {

for (j = 0; j < *m; j++)

fscanf (fpin, "%d", &mat[i][j]); }

return; }

Perchè n e m (main) siano avvalorati, bisogna passare i loro indirizzi. Nella prima fscanf compaiono n e m senza & in quanto sono indirizzi. Nei for ci sono *n e *m in quanto il test va fatto con i numeri prima letti e non con i loro indirizzi.

void printmatrix (int mat[][MAXCOL], int n, int m) { int i, j; for (i = 0; i < n; i++) { for (j = 0; j < m; j++) printf ("%4d", mat[i][j]); printf ("\n"); } return; }

void writematrix(FILE *fp, int mat[][MAXCOL], int n, int m) { int i, j; for (i = 0; i < n; i++) { for (j = 0; j < m; j++) fprintf (fp, "%4d", mat[i][j]); fprintf (fp, "\n"); }

(52)

Proglab 31 – I/O di parole (una per riga)

Con il “Blocco note” creiamo, ad esempio, il file input inputparolerighe: tavolo

carciofo latte

frigorifero

Eseguiamo il programma fornendo il nome del file input: inputparolerighe.txt e il nome del file output: outputparolerighe.txt. Terminata l’esecuzione, in outputparolerighe troviamo:

tavolo carciofo latte frigorifero #include <stdio.h> #include <stdlib.h> #define MAXRIGHE 50 #define MAXCOL 50 FILE *aprifile(char *);

int readmatrix(FILE *fpin, char mat[][MAXCOL]); void printmatrix (char mat[][MAXCOL], int n);

void writematrix(FILE *fp, char mat[][MAXCOL], int n); main()

{

FILE *fpin, *fpout;

char mat[MAXRIGHE][MAXCOL]; int n; fpin = aprifile("r"); n = readmatrix(fpin, mat); printmatrix (mat, n); fclose(fpin); fpout = aprifile("w"); writematrix(fpout, mat, n); fclose(fpout); return EXIT_SUCCESS; }

(53)

int readmatrix(FILE *fpin, char mat[][MAXCOL]) {

int n=0;

while ( ! feof(fpin)) {

fscanf (fpin,"%s", mat[n]); n++;

}

return(n); }

void printmatrix(char mat[][MAXCOL], int n) {

int i;

printf ("\n\n"); for (i=0; i<n; i++)

printf("%s\n", &mat[i][0]); printf ("\n\n");

return; }

La printf("%s\n", &mat[i][0]) è equivalente a printf("%s\n", mat[i]).

void writematrix(FILE *fp, char mat[][MAXCOL], int n) {

int i;

for(i = 0; i < n; i++)

fprintf(fp, "%s\n", mat[i]); }

(54)

Prog lab 32 – I/O di parole (su una sola riga)

Con il “Blocco note” creiamo, ad esempio, il file input inputparoleriga: strada melone giorno valle

Eseguiamo il programma fornendo il nome del file input: inputparoleriga.txt e il nome del file output: outputparoleriga.txt.

Terminata l’esecuzione, in outputparoleriga troviamo: strada melone giorno valle

#include <stdio.h> #include <stdlib.h> #define MAXRIGHE 50 #define MAXCOL 50 FILE *aprifile(char *);

int readmatrix(FILE *fpin, char mat[][MAXCOL]); void printmatrix (char mat[][MAXCOL], int n);

void writematrix(FILE *fp, char mat[][MAXCOL], int n); main()

{

FILE *fpin, *fpout;

char mat[MAXRIGHE][MAXCOL]; int n; fpin = aprifile("r"); n = readmatrix(fpin, mat); printmatrix (mat, n); fclose(fpin); fpout = aprifile("w"); writematrix(fpout, mat, n); fclose(fpout); return EXIT_SUCCESS; }

(55)

int readmatrix(FILE *fpin, char mat[][MAXCOL]) { int k=0, j=0, n=0; char s[50]; fscanf (fpin,"%[^\n]", s); while (s[k] != '\0') { j = 0; while (s[k] != ' ' && s[k] != '\0') { mat[n][j] = s[k]; j++; k++; } mat[n][j] = '\0'; while (s[k] == ' ') k++; if (j > 0) n++; } return(n); }

Il primo while serve a scorrere la stringa fino alla fine. Il secondo while inserisce una parola nella n-ma riga della matrice e si esce quando si incontra uno spazio o ‘\0’. Il k-mo carattere della frase viene inserito nella riga n-ma alla posizione j. Quando si esce dal while, dopo l’ultimo carattere della parola viene inserito ‘\0’ in modo da poter stampare la parola con il formato %s. Il terzo while serve a saltare gli spazi.

void printmatrix(char mat[][MAXCOL], int n) {

int i;

printf ("\n\n"); for (i=0; i<n; i++)

printf("%s\n", &mat[i][0]); printf ("\n\n");

return; }

void writematrix(FILE *fp, char mat[][MAXCOL], int n) {

int i;

for(i = 0; i < n; i++)

fprintf(fp, "%s ", mat[i]); }

(56)

2) Input/output di caratteri

Queste funzioni leggono e scrivono singoli caratteri. Abbiamo incontrato la getchar che legge da stdin e la fgetc che legge da fp.

Simmetricamente, putchar scrive su stdout e fputc scrive sullo stream relativo al suo file pointer.

Proglab 33 – Copia di un file di testo

Con il “Blocco note” creiamo, ad esempio, il file input inputcopyfile: strada melone giorno valle

lontano vicino sole

scuola gioco tanto meglio

Eseguiamo il programma fornendo il nome del file input: inputcopyfile.txt e il nome del file output: outputcopyfile.txt.

Terminata l’esecuzione, in outputcopyfile troviamo: strada melone giorno valle

lontano vicino sole

(57)

#include <stdio.h> #include <stdlib.h> FILE *aprifile(char *);

void copyfile(FILE *fp, FILE *fpout); main()

{

FILE *fpin, *fpout; fpin = aprifile("r"); fpout = aprifile("w"); copyfile(fpin, fpout); fclose(fpin); fclose(fpout); return EXIT_SUCCESS; }

void copyfile(FILE *fpin, FILE *fpout) { char car; car = fgetc(fpin); while (! feof(fpin)){ fputc(car, fpout); car = fgetc(fpin); } }

(58)

3) Input/output di righe

Queste funzioni leggono e scrivono righe. Abbiamo visto la gets che legge da stdin finchè non incontra il carattere new-line (a differenza della scanf che si ferma al primo spazio).

La fgets legge da qualsiasi stream e pone un limite al numero di caratteri che andrà a salvare, ad esempio: fgets (string, 50, fp)

legge una riga da fp, la lettura si interrompe quando incontra il carattere new-line oppure siano stati letti 49 caratteri.

Sia la gets che la fgets inseriscono “\0” alla fine della stringa e restituiscono il puntatore nullo in caso di errore.

Per l’output abbiamo la puts che scrive in stdout e aggiunge new-line alla fine, mentre la fputs scrive in fp e non aggiunge il carattere new-line.

Proglab 34 – I/O di frasi (una per riga)

#include <stdio.h> #include <stdlib.h> #define MAXRIGHE 50 #define MAXCOL 50 FILE *aprifile(char *);

int readmatrix(FILE *fpin, char mat[][MAXCOL]); void printmatrix (char mat[][MAXCOL], int n);

void writematrix(FILE *fp, char mat[][MAXCOL], int n); main()

{

FILE *fpin, *fpout;

char mat[MAXRIGHE][MAXCOL]; int n; fpin = aprifile("r"); n = readmatrix(fpin, mat); printmatrix (mat, n); fclose(fpin); fpout = aprifile("w"); writematrix(fpout, mat, n); fclose(fpout); return EXIT_SUCCESS; }

(59)

int readmatrix(FILE *fpin, char mat[][MAXCOL]) {

int n=0;

while((fgets(mat[n], MAXCOL, fpin)) != NULL){ n++;

}

return n; }

void printmatrix(char mat[][MAXCOL], int n) {

int i;

printf ("\n\n"); for (i=0; i<n; i++)

printf("%s\n", &mat[i][0]); printf ("\n\n");

return; }

void writematrix(FILE *fp, char mat[][MAXCOL], int n) {

int i;

for(i = 0; i < n; i++)

fprintf(fp, "%s\n", mat[i]); }

Riferimenti

Documenti correlati

{ reader.close(); } // questa istruzione viene eseguita // comunque prima di passare. // l’eccezione al

Ripetendo k volte il test, ogni volta con una scelta casuale indipendente del valore della base a, la probabilità che un numero composto (soddisfacente le ipotesi del Teorema)

Fissiamo una lettera dell’alfabeto (sarà la chiave di cifratura del nostro sistema crittografico) e calcoliamo il suo valore numerico a con 0a20 (tale valore numerico è

L’ispettore Numerik sta affrontando un caso complicato e misterioso: è alla ricerca di un abilissimo ladro che, da alcune settimane, compie numerosi furti in città.. Gli unici

Se vogliamo diminuire ancora tale probabilit` a possiamo ripetere il test di Miller-Rabin con altre basi... Cercare di rompere questo sistema e di decifrare e leggere

Scrivere un metodo che, dato un array bidimensionale di interi a, restituisce true se la somma degli elementi a ij , la cui somma degli indici i e j `e pari, `e uguale alla somma

Scrivere un metodo che, dato un array bidimensionale di interi a, restituisce true se il prodotto degli elementi a ij , la cui somma degli indici i e j `e pari, `e maggiore del

Alcuni esercizi sull’esecuzione di codice Java con array