ESEMPI PRATICI E BASILARI DI C



Le basi


Un programma in C si presenta generalmente sotto questo schema:


Codice:
#include <stdio.h>


int main() {


istruzione;


// commento di una sola riga


/* commento
a più righe */
}

Il primo elemento che notiamo è l'include di "stdio.h", che altro non è che un "file header" presente nella directory include del nostro compilatore, ci permette di usare funzioni base di input/output come ad esempio printf().


La main è la funzione principale del programma, con la fine della funzione main abbiamo anche la fine dell'esecuzione del programma.


Come possiamo vedere la funzione main è preceduta dalla scritta "int", questo significa che la funzione restituirà un valore intero (numerico), di fatti ogni funzione restituisce un valore.


I commenti sono degli elementi che in realtà vengono scartati dal compilatore prima di essere compilati e dunque servono soltanto come punti di riferimento per noi e per chi legge il nostro codice, si possono scrivere in due forme, preceduti da //, per cui tutto ciò che viene dopo // ed è situato sulla stessa riga viene interpretato come commento, oppure c'è la forma /* commento */ che racchiude commenti che possono dividersi su più righe e tutto ciò che si trova tra /* e */ viene considerato commento.


Il codice da eseguire si trova tra le parentesi graffe che segnano l'inizio e la fine della funzione main e per dividere un'istruzione da un'altra si utilizza il punto e virgola ";".


Il primo programma


Codice:
#include <stdio.h>


int main() {
	printf("Hello World! \n");
	getchar();
}

Questo è il classico primo programma di ogni linguaggio di programmazione, il caro vecchio hello world! Rispetto alla lezioncina precedente non c'è quasi nulla di nuovo, apparte l'utilizzo della funzione printf() dichiarata nell'header file stdio.h e l'utilizzo della funzione getchar() la quale si occupa di attendere la pressione di un qualsiasi carattere. Utilizziamo la funzione getchar per evitare che il prompt dei comandi si chiuda senza farci vedere il risultato del nostro lavoro, ovvero la scritta Hello World! stampata sul nostro monitor.


Possiamo vedere l'utilizzo di "\n" che è una sequenza di escape e serve ad andare a capo.


Le variabili


Codice:
#include <stdio.h>


// Le variabili e il printaggio


int main() {
int a = 3;
char b = 'b';
float c = 2.6;
char string[5] = "ciao";
printf("A vale %d\n", a);
printf("B vale %c\n", b);
printf("C vale %f\n", c);
printf("String vale %s\n", string);
getchar();
}

Questo esempio è già leggermente più complesso degli altri precedentemente proposti, dichiara semplicemente quattro variabili differenti e le stampa a schermo.


Possiamo vedere una variabile di tipo int (intero), una di tipo char (carattere), una di tipo float (numerica a virgola mobile) e una di tipo string che in realtà non è altro che un array di caratteri.


Questi sono i vari tipi di variabili in C:


char per i caratteri ASCII
double per numeri a virgola mobile con precisione doppia
float per numeri a virgola mobile con precisione singola
int per i numeri interi
long int per numeri interi grandi
short int per numeri interi piccoli
unsigned int per i numeri interi positivi


La dichiarazione delle variabili deve avvenire prima di ogni altra istruzione presente nel main, di fatti nel C la dichiarazione delle variabili successivamente viene generalmente considerata erronea dal compilatore, mentre in C++ non abbiamo questo tipo di problemi.


Per fare riferimento a delle variabili in C non scriviamo direttamente il loro nome, bensì degli indicatori chiamati stringhe di formato e sono:


%c per le variabili di tipo char
%d o %i per le variabili intere decimali
%f per le variabili di tipo float
%l o %ld per le variabili di tipo long
%lf per le variabili di tipo double
%o per le variabili intere ottali
%p per trovare l'indirizzo di una variabile
%s per le variabili di tipo stringa
%x per le variabili intere esadecimali


Le costanti


Codice:
#include <stdio.h>
#define PI  3.14


int main() {
const float PI = 3.14;
}

Esistono due modi di dichiarare le costanti, tramite #define o tramite la keyword const. Il secondo modo è quello più corretto ed è molto simile alla dichiarazione delle variabili.


Le funzioni


Codice:
#include <stdio.h>


// Le funzioni


int square(int a);
int add(int b, int c);
int sott(int d, int e);
int molt(int f, int g);
int div(int h, int i);


int main() {
int a = 2;
int b = 3;
int c = 4;
int d = 5;
int e = 6;
int f = 7;
int g = 8;
int h = 10;
int i = 10;


printf("Il quadrato di %d e' %d\n", a, square(a));
printf("La somma di %d e %d e' %d\n", b, c, add(b,c));
printf("La sottrazione di %d e %d e' %d\n", d, e, sott(d,e));
printf("La moltiplicazione di %d e %d e' %d\n", f, g, molt(f,g));
printf("La divisione di %d e %d e' %d\n", h, i, div(h,i));
getchar();
}


int square(int a) {
return a*a;
}


int add(int b, int c) {
return b+c;
}


int sott(int d, int e) {
return d-e;
}


int molt(int f, int g) {
return f*g;
}


int div(int h, int i) {
return h/i;
}

Le funzioni sono delle procedure che restituiscono però un valore di un tipo determinato, per utilizzare una funzione prima dobbiamo dichiararne la presenza in questo modo prima della funzione main:


Codice:
tipo_variabile_restituita nome_funzione(variabile1, variabile2.. variabile666);

Poi specificare la funzione dopo la main tramite la forma:


Codice:
tipo_variabile_restituita nome_funzione(variabile1, variabile2.. variabile666) {
codice_da_eseguire;
}

In questo caso sono state create delle funzioni apposite per le operazioni tra enti numerici, per cui ritornano appunto valori interi. Il programma non fa altro che sfruttare le funzioni per permettere le operazioni tra più variabili dichiarate in precedenza.


Le procedure


Codice:
#include <stdio.h>


// Le procedure


void numero(int a);


int main() {
int a = 5;
numero(a);
getchar();
}


void numero(int a) {
printf("Il numero a vale %d\n", a);
return;
}

Le procedure non sono altro che dei blocchi di codice che vengono richiamati ed eseguiti, vengono sfruttati generalmente per evitare ripetizione di codice pressocché uguale o con piccole modifiche.


Sono praticamente identiche alle funzioni apparte per il fatto che sia nella dichiarazione che nella specificazione del codice il tipo di variabile da restituire è void (ovvero VUOTO), dunque nullo.


Si richiamano semplicemente scrivendone il nome e passando i parametri necessari (in questo caso A) nella parentesi.


L'input da tastiera


Codice:
#include <stdio.h>


// Input da tastiera -> scanf()


int moltiplicazione(int a, int b);


int main() {
int a, b;
printf("Scrivi il numero da moltiplicare: ");
scanf("%d", &a);
printf("\nScrivi il numero per il quale lo vuoi moltiplicare: ");
scanf("%d", &b);
printf("\nIl risultato della moltiplicazione tra %d e %d e': %d\n", a, b, moltiplicazione(a,b));
}


int moltiplicazione(int a, int b) {
return a*b;
}

Questo programma moltiplica tra loro due numeri immessi dall'utente che lo esegue, per gestire l'input da tastiera viene usata la funzione scanf(), la metodologia di utilizzo è simile a quella della funzione printf(), la cosa che cambia è che oltre a riferirci a una variabile tramite la stringa di formato dobbiamo scrivere "&" prima del nome della variabile, per ora è meglio non spiegare perché, lo si vedrà successivamente.


Il Ciclo if-else


Codice:
#include <stdio.h>


// Ciclo if-else


int main() {
int a;
printf("Scrivi un numero: ");
scanf("%d", &a);
if (a>0) {
printf("Il numero inserito e' maggiore di zero\n");
} else if (a<0) {
printf("Il numero inserito e' minore di zero\n");
} else {
printf("Il numero inserito e' zero\n");
}
}

Questo codice non fa altro che controllare se un numero è positivo, negativo o uguale a zero.


Il ciclo if-else segue la forma:


Codice:
if (condizione) {
codice;
} else if (altra_condizione) {
altro_codice;
}

Operatori di confronto


Codice:
#include <stdio.h>


// Operatori di confronto


int main() {
int a, b;


printf("Digita un numero: ");
scanf("%d", &a);
printf("Digitane un altro: ");
scanf("%d", &b);
printf("Confronto i due numeri..\n");
if (a>b) {
printf("%d e' maggiore di %d\n", a, b);
} else {
printf("%d non e' maggiore di %d\n", a, b);
}
if (a<b) {
printf("%d e' minore di %d\n", a, b);
} else {
printf("%d non e' minore di %d\n", a, b);
}
if (a>=b) {
printf("%d e' maggiore o uguale di %d\n", a, b);
} else {
printf("%d non e' maggiore o uguale di %d\n", a, b);
}
if (a<=b) {
printf("%d e' minore o uguale di %d\n", a, b);
} else {
printf("%d non e' minore o uguale di %d\n", a, b);
}
if (a!=b) {
printf("%d e' diverso da %d\n", a, b);
} else {
printf("%d e' uguale a %d\n", a, b);
}
if (a==b) {
printf("%d e' uguale a %d\n", a, b);
} else {
printf("%d e' diverso da %d\n", a, b);
}
getchar();
}

Questo programmino confronta due variabili tramite tutti gli operatori di confronto disponibili.


Attenzione, se si vuole vedere se una variabile è uguale a un'altra variabile o a un altro valore non bisognerà scrivere (a=0) ma (a==0).


Infatti tramite la scrittura == si confrontano due variabili mentre con la scrittura = si assegna un valore a una variabile.


> significa maggiore
< significa minore
>= significa maggiore o uguale
<= significa minore o uguale
== significa uguale
!= significa diverso


Gli operatori logici


Codice:
#include <stdio.h>


// Operatori logici AND e OR


int main() {
int a;


printf("Digita un numero: ");
scanf("%d", &a);


if (a>0 && a<666) {
printf("Il numero digitato e' compreso tra 0 e 666\n");
} else if (a > 666 || a < 0) {
printf("Il numero digitato e' minore di 0 o maggiore di 666\n");
}


}

Questo programmino non fa altro che controllare se il numero immesso dall'utente che lo esegue è compreso tra 0 e 666 o è esterno.


AND & OR sono degli operatori logici che vengono utilizzati per verificare delle condizioni sotto diversi aspetti.


In C gli operatori logici sono:


AND che si scrive &&
OR che si scrive ||
XOR (exclusive OR) che si scrive ^
NOT (negazione) che si scrive !


Questa è una guida sugli operatori logici che scrissi tempo fa:


Gli operatori logici vengono utilizzati per l'algebra booleana - che si chiama così perché fu inventata da George Boole -, questo ramo della matematica lavora unicamente su due numeri: 0, 1: questi numeri - detti anche simboli binari poiché sono gli unici due numeri che compongono questo tipo di linguaggio - sono fondamentali per il linguaggio binario e di conseguenza anche per il computer, il quale lavora in binario.. terminata questa piccola introduzione possiamo iniziare con la descrizione degli operatori logici utilizzati nella crittografia - e proprio per questo anche in matematica -.


NOT: questo operatore inverte il valore di un simbolo binario. Es. 0 diventa 1, 1 diventa 0.
Se noi abbiamo in binario la parola 'pippo' ossia '0111000001101001011100000111000001101111' essa diventerà '1000111110010110100011111000111110010000' che equivarrebbe in ASCII a '�–���'. emozionante no? lol


AND: questo operatore viene utilizzato per restituire uno dei due simboli binari come risultato di un paragone di altri due simboli binari. facciamo un esempio: 1 AND 1 - risultato 1. 0 AND 1 - risultato 0. 0 AND 0 - risultato 0. in poche parole se entrambi gli operatori messi a paragone sono 1 ottenuto sarà 1 - in booleano equivalente al termine 'vero' -, altrimenti si otterrà 0 - in booleano equivalente al termine 'falso' -.


NAND: - da Not AND - come dice anche il nome è l'opposto di AND, ossia se vi sono due numeri messi a paragone entrambi uguali a 0 restituisce 1, altrimenti restituisce 0.


OR: questo operatore logico restituisce sempre il valore 1, apparte nel caso in cui entrambi i numeri messi a paragone siano pari a 0. Es. 0 OR 0 restituisce 0, negli altri casi sempre 1. anche questo ha un opposto - proprio come il Not AND - che si chiama NOR - Not OR -.


e infine, ma forse il più importante per la crittografia, poiché invertibile


XOR: - eXclusive OR - questo è uguale all'OR solamente che restituisce 0 anche nel caso vengano paragonati due simboli positivi (1) uguali. Es. 0 XOR 0 = 0 - 0 XOR 1 = 1 - 1 XOR 0 = 1 - 1 XOR 1 = 0.


la sua importanza in crittografia è costituita dalla possibilità di ottenere conoscendo un termine e il risultato il secondo termine. inoltre lo XOR è alla base della creazione di un qualsiasi semplicissimo crittatore. nel linguaggio di programmazione 'C' basta utilizzare il segno '^' per mettere in paragone tramite XOR due variabili.


La struttura switch-case


Codice:
#include <stdio.h>


// Switch-Case


int main() {
int a;


printf("Inserisci un numero: ");
scanf("%d", &a);


switch(a) {


case 1:
printf("Hai digitato 1\n");
break;


case 2:
printf("Hai digitato 2\n");
break;


case 3:
printf("Hai digitato 3\n");
break;


default:
printf("Il numero digitato non e' compreso tra 1 e 3\n");
break;
}
}

Il programma in questione si occupa di controllare se il numero immesso dall'utente che lo esegue è 1, 2, 3 o è differente da questi.


La struttura switch-case è una specie di else-if che però risulta più ordinato nel caso di confronti "massicci" di variabili.


La sua forma tipica è:


Codice:
switch(variabile) {


case valore_della_variabile:
codice;
break; // interrompe il ciclo


case valore2_della_variabile:
codice2;
break;


case default: // nel caso la variabile non assuma nessun valore sopracitato
codice_default;
break;
}

Ciclo for


Codice:
#include <stdio.h>


// Ciclo for


int main() {
int i;


for (i=1; i<=10; i++) {
printf("i e' uguale a %d\n", i);
}
getchar();
}

Il ciclo for viene utilizzato per ripetere un determinato codice ciclicamente per un determinato numero di volte.


Si presenta nella forma:


Codice:
for (variabile iniziale; condizione; step) {
codice;
}

Nel nostro esempio vediamo un codice che stampa il valore di i per 10 volte, in quanto viene eseguito da quando i è pari a 1 finché non diventa maggiore di 10.


L'istruzione while


Codice:
#include <stdio.h>


// Ciclo while


int main() {
int i=666;


while (i<=700) {
printf("i vale %d\n", i);
i++;
}
getchar();
}

L'istruzione while ha un effetto praticamente uguale a quello del ciclo for, in questo esempio stampa tutti i numero da 666 a 700.


La forma base è:


Codice:
while (condizione) {
codice;
step;
}

Istruzione do-while


Codice:
#include <stdio.h>


// Ciclo do-while


int main() {
int i=0;


do {
printf("i vale %d\n", i);
i++;
} while (i<=10);
getchar();
}

Il ciclo do-while è praticamente identico al while, con la differenza che il codice viene eseguito almeno 1 volta, nonostante la condizione non venga soddisfatta, si presenta sotto la forma:


Codice:
do {
codice;
step;
} while (condizione);

Istruzione GOTO


Codice:
#include <stdio.h>


// Istruzione goto


int main() {
int i=0;


etichetta:
printf("i vale %d\n", i);
i++;


if (i<=10) {
goto etichetta;
}
getchar();
}

Questo programmino alquanto inutile non fa altro che verificare una condizione ed andare all'etichetta tramite l'istruzione goto.


L'istruzione goto non è altro che il JMP (JuMP) dell'assembly e appunto "salta" da una parte all'altra del codice, indicata da un'etichetta.


Le etichette si indicano con


Codice:
nome_etichetta:

e comprendono tutto il codice che segue.


Break e Continue


Codice:
#include <stdio.h>


// break e continue


int main() {
int i=1;


for (;;) {
printf("i vale %d\n", i);
i++;


if (i>10) {
break;
} else {
continue;
}
}
getchar();
}

In questo codice c'è una forma particolare di un ciclo for che permette la ripetizione infinita del codice al suo interno, ovvero senza specificare alcun parametro per il ciclo (;.


Per interrompere un ciclo si usa l'istruzione break altrimenti per continuarlo continue.


Nell'esempio viene stampato il valore di i 10 volte, finché il valore di i supera appunto il numero 10 e il ciclo subisce l'effetto dell'istruzione break.


Array monodimensionali


Codice:
#include <stdio.h>


// Gli array monodimensionali


int main() {
 const int j=5;
 int prodscal=0;
 int i;
 int arr1[j];
 int arr2[j];   
 char yn;
 
  for (i=0; i<j; i++) {
      printf("Digita il valore n. %d del primo vettore: ", i+1);
      scanf("%d", &arr1[i]);
      }
      
  for (i=0; i<j; i++) {
      printf("Digita il valore n. %d del secondo vettore: ", i+1);
      scanf("%d", &arr2[i]);
  }
  
  for (i=0; i<j; i++) {
      prodscal += (arr1[i]*arr2[i]);  
      printf("Il prodotto scalare dei due vettori e' %d\n", prodscal);
      prodscal=0;
  }
  getchar();
  printf("Press any key to close the program. . .");
  getchar();
}

Questo codice è un esempio abbastanza complesso dove si può vedere l'utilizzo degli array per calcolare il prodotto scalare di due vettori.


Un array non è altro che un insieme di variabili dello stesso tipo che si distinguono tramite un indice, si dichiara così:


Codice:
tipo_variabili nome_array[numero_variabili]

Se vogliamo scrivere una stringa in C dovremo utilizzare un array di char, se volessimo più specificamente memorizzare in un array di char la parola ciao dovremmo scrivere:


Codice:
char stringa[5] = "ciao";

Perché 5 e non 4? Perché le stringhe in C non sono altro che dei vettori di caratteri che terminano con il byte \0 che determina la fine del vettore, quindi ci dev'essere un posto in più proprio per \0.


Guida in costante aggiornamento e progresso