Linguaggi di Programmazione
(AA 2002/2003)
Corso di Laurea in Informatica
Gabriella Pasi
PROGRAMMAZIONE A OGGETTI
• Incapsulamanto dei dati
– i dettagli di definizione di oggetti sono nascosti, solo le
interfacce con l’esterno sono visibili
• Ereditarietà
– Gli oggetti sono definiti in una gerarchia ed ereditano
dall’immediato parente caratteristiche comuni, che
possono essere specializzate
• Astrazione
– Il meccanismo con cui si specificano le caratteristiche
peculiari di un oggetto
• Polimorfismo
– Possibilità di definire funzioni con lo stesso nome che
pure sono state specializzate per una particolare classe
JAVA
Java è un linguaggio di programmazione ad alto livello creato dalla
Sun Microsystems nel 1995
Java è un linguaggio orientato ad oggetti molto simile al C++,
rispetto al quale risulta più semplificato allo scopo di prevenire gli
errori di programmazione più comuni.
Il codice sorgente in Java (con estensione .java) è compilato in un
formato chiamato bytecode (estensione .class), che può essere
eseguito da un interprete Java. Il bytecode può essere eseguito su
differenti architetture di calcolo dato che esistono interpreti ed
ambienti di esecuzione Java (Virtual Machines o VMs) per la
maggior parte dei sistemi operativi.
JAVA
• Il compilatore Java traduce il programma sorgente
in una rappresentazione speciale detta bytecode
• Il bytecode Java non è un linguaggio macchina di
una CPU particolare, ma di una macchina virtuale
Java
• L’interprete traduce il bytecode nel linguaggio
macchina e lo esegue
• Un compilatore Java compiler non è legato ad una
particolare macchina
• Java è indipendente dall’architettura della
macchina
JAVA
codice sergente
Java
compilatore
Java
bytecode
Java
interprete
Java
compilatore
Bytecode
codice
macchina
JAVA: Tipi di dati primitivi.
Tipo Dimensione
Descrizione
byte
8 bit, complemento a due. Intero a 8 bit.
short 16 bit, complemento a due. Intero ridotto.
int
32 bit, complemento a due. Intero normale.
long
64 bit, complemento a due. Intero molto grande.
float
32 bit
Virgola mobile, singola precisione.
double 64 bit
Virgola mobile, doppia precisione.
char
16 bit, carattere Unicode. Carattere.
boolean Vero o Falso.
Valore booleano.
INTRODUZIONE AL LINGUAGGIO C
Linguaggio C
•
•
•
•
è basato sul paradigma imperativo
è di alto livello;
permette di vedere anche dettagli di basso livello del calcolato
è compilato;
Linguaggio Java
• è basato sul paradigma a oggetti;
• è di alto livello;
• non è in grado di vedere direttamente i dettagli di basso
livello del calcolatore;
• è interpretato;
• l'interprete (macchina virtuale) non e in grado di leggere
direttamente il programma, ma legge un file in formato
intermedio indipendente dall'architettura (bytecode) che si
ottiene tramite compilazione del file sorgente.
INTRODUZIONE AL LINGUAGGIO C
Poiché il C NON E’ un linguaggio orientato a oggetti, NON APPLICA
i seguenti concetti:
Classi
Oggetti
Istanzanziazione
Costruttori
Ereditarietà
Metodi
Overloading
public/private/protected
ALCUNI SITI UTILI SUL LINGUAGGIO C
TUTORIAL SU C
http://www.lysator.liu.se/c/bwk-tutor.html
http://www-math.unice.fr/laboratoire/help/C/ctutor/node1.html
JAVA - C
http://www.cs.cornell.edu/courses/cs414/2001SP/tutorials/cforjava.htm
Struttura di un programma:
differenza concettuale
Un programma JAVA è costituito da una collezione di classi.
Una classe, che contiene il metodo “main”, è la classe iniziale.
Una classe definisce in modo astratto una categoria di oggetti,
definendone sia la struttura sia le operazioni su di essi lecite.
Un programma C è costituito da una collezione di funzioni.
Non esiste il concetto di classe come categoria di oggetti.
Una funzione C è una collezione di “statement”, che includono
chiamate ad altre funzioni, e ha gli stessi costrutti standard quali gli
statement if, i cicli while e for, ecc. Questi ultimi sono espressi come
in Java.
ALCUNE DIFFERENZE TRA JAVA E C
“namespace” unico per funzioni e variabili globali
Ogni classe in Java definisce uno spazio di nomi (spacename):
questo permette di definire funzioni e variabili con lo stesso nome in
classi distinte. Quando si identifica una funzione o una variabile in
Java è necessario esprimere lo spacename.
In C, tutte le funzioni sono globali e occorre condividere uno spazio
di nomi unico (uno per programma). Anche le variabili globali fanno
parte dello spacename condiviso.
NB: in C esistono altri spazi di nomi: uno spazio di nomi unico è
condiviso da una struttura, da un’unione o da una enumerazione. Ogni
blocco ha uno spazio di nomi per le variabili locali
In C le funzioni devono avere nomi diversi, indipendentemente dai
loro argomenti
ALCUNE DIFFERENZE TRA JAVA E C
I programmi Java possono essere più semplici da sviluppare poichè:
 la gestione dinamica della memoria è prevalentemente automatica
 sono effettuati controlli di illegalità di operazioni (ad esempio
oltrepassare i limiti di un array).
I programmi C hanno tipicamente un’esecuzione più veloce, poichè:
 la gestione dinamica della memoria (che spesso non è richiesta) è
completamente controllata dal programmatore
 non ci sono controlli di illegalità di operazioni (maggiore
attenzione nella scrittura da parte dei programmatori),
maggiore responsabilità da parte del programmatore C
ESEMPIO DI PROGRAMMA C
#include <stdio.h>
void main(void)
{
printf(“Hello World. \n \t and you ! \n ”);
/* stampa di un messaggio */
return;
}
$Hello World.
and you !
$
ESEMPIO DI PROGRAMMA C
• #include <stdio.h>
= include il file di libreria stdio.h
– senza punto e virgola alla fine
– solo lettere minuscole – il C è case-sensitive
• void main(void){ … } è il solo codice eseguito
• printf(“ /* messaggio che si desidera stampare */ ”);
• \n = a capo
\t = tab
• Il simbolo \ prima di caratteri speciali in printf.
–
printf(“Have you heard of \”The Rock\” ? \n”);
COMMENTI
JAVA
/* commento su più
linee …….. */
// commento su linea singola
C
/* soltanto commento su più
linee …….. */
public class FooBar {
public static void main(String [] args) {
System.out.println("Hello world\n");
}
}
public class FooBar {
public static void main(String [] args) {
System.out.printfln("Hello world\n");
}
}
TIPI DI DATI SEMPLICI
• Tipo di dato # bytes(typical)
notaz.breve
• int
4
%d
• char
1
• float
4
• double
8
• long
4
%l
• short
2
• modificatori:
• signed / unsigned
• long double
• ex:
valori
da -2,147,483,648 a 2,147,483,647
da -128 a 127
%c
3.4E+/-38 (7 cifre)
%f
1.7E+/-308 (15 cifre)
%lf
da -2,147,483,648 a 2,147,483,647
da -32,768 a 32,767
- int, char, long, short
TIPI PRIMITIVI
Dimensioni: le dimensioni tipiche e l'intervallo di valori per i
tipi fondamentali di dati dipendono dall’architettura della
macchina utilizzata
Nel caso di un'architettura a 32 bit:
TIPI PRIMITIVI
C: TIPI PRIMITIVI
I modicatori di tipo che si
• char: carattere ASCII;
applicano ai tipi interi char e int
• int: intero;
sono
• float: virgola mobile;
• double: virgola mobile doppia • signed: con segno;
• unsigned: senza segno;
precisione;
• long: maggior estensione;
• void: nessun
• short:
estensione;
valore/qualunque
Come in Java,tipo.
le funzioni C functions
che nonminor
“producono”
un
valore restituiscono void. A differenza del Java, una funzione C senza
parametri ha void nella sua lista di parametri.
NOTA BENE: non esiste tipo boolean. Le condizioni espresse in
espressioni condizionali e iterative, e gli operandi di operatori logici
(!, && e ||), sono espressioni intere con una interpretazione
booleana:zero significa falso, non-zero significa vero. Gli operatori
relazionali (= =, !=, <=, >=, < e >) e gli operatori logici restituiscono
0 per falso e 1 per vero.
ESEMPIO 2 DI PROGRAMMA C
#include <stdio.h>
void main(void)
{
int nstudents = 0; /* inizializzazione, richiesta */
printf(“How many students does Cornell have ?:”);
scanf (“%d”, &nstudents); /* Read input */
printf(“Cornell has %d students.\n”, nstudents);
return ;
}
$How many students does Cornell have ?: 20000 (enter)
Cornell has 20000 students.
$
CONVERSIONE DI TIPI
Cast: permette di forzare un'espressione perchè sia di un tipo
specifico.
(tipo) espressione;
ATTENZIONE: il cast inibisce il controllo sui tipi da parte del
compilatore!
Es.: int i, j;
float x = 123.4e10;
i = x, il compilatore avverte che i due tipi sono
diversi;
#include <stdio.h>
void main(void)j = (int) x, nessun avvertimento!!
{
int i,j = 12;
/* i non è inizializzato, solo j */
float f1,f2 = 1.2;
i = (int) f2;
f1 = i;
/* i <- 1, 0.2 perso */
/* f1 <- 1.0 */
f1 = f2 + (int) j; /* f1 <- 1.2 + 12.0 */
f1 = f2 + j;
/* f1 <- 1.2 + 12.0 */
}
ISTRUZIONE printf
ISTRUZIONE printf
ISTRUZIONE printf
ISTRUZIONE printf
ISTRUZIONE printf
ISTRUZIONE printf
JAVA E C: ASPETTI SIMILI
• Operatori in C uguali a quelli in Java:
• Aritmetici
• int i = i+1; i++; i--; i *= 2;
• +, -, *, /, %,
• Relazionali e Logici
• <, >, <=, >=, ==, !=
• &&, ||, &, |, !
• Sintassi come in Java:
•
•
•
•
•
•
if ( ) { } else { }
while ( ) { }
do { } while ( );
for(i=1; i <= 100; i++) { }
switch ( ) {case 1: … }
continue; break;
ESEMPIO
#include <stdio.h>
#define DANGERLEVEL 5
/* C Preprocessor - sostituzione quando appare */
/* come final in Java final tipo nome
[valore] */
void main(void)
{
float level=1;
/* if-then-else come in Java */
if (level <= DANGERLEVEL){ /*sostituito da 5*/
printf(“livello basso!\n”);
}
else printf(“bene !\n”);
return;
}
NOTAZIONI CRIPTICHE
int x = 0,y = 2,z = 1025;
float a = 0.0,b = 3.14159,c = -37.234;
x = x + 1;
x++;
++x;
z = y++;
z = ++y;
/*
/*
/*
/*
/*
y = y - 1;
y--;
--y;
y = 3;
z = y--;
z = --y;
/* decrementa y */
/* decrementa y */
/* decrementa y */
a
a
a
a
a
/*
/*
/*
/*
/*
= a + 12;
+= 12;
*= 3.2;
-= b;
/= 10.0;
incrementa
incrementa
incrementa
z = 2, y =
z = 4, y =
x
x
x
3
4
*/
*/
*/
*/
*/
/* z = 3, y = 2 */
/* z = 1, y = 1 */
aggiunge 12 ad a */
aggiunge 12 ad a */
moltiplica a per 3.2 */
sottrae b ad a */
divide a per 10.0 */
ARRAY MONODIMENSIONALI
#include <stdio.h>
void main(void)
{
int number[12]; /* 12 celle, una cella per studente */
int index, sum = 0;
/* inizializzare sempre un array prima dell’uso */
for (index = 0; index < 12; index++) {
number[index] = index;
}
/* ora, number[index]=index; causerebbe un errore */
for (index = 0; index < 12; index = index + 1) {
sum += number[index];
/* somma gli elementi dell’array */
}
return;
}
JAVA: ARRAY
La dichiarazione di un array avviene in Java senza
l'indicazione esplicita del numero di elementi. La dichiarazione
avviene come se si trattasse di un tipo di dati normale, con la
differenza che si aggiungono una coppia di parentesi quadre a
sottolineare che si tratta di un array di elementi di quel tipo.
int[] arrayDiInteri;
Per fare in modo che l'array esista effettivamente, occorre che
questo sia inizializzato, fornendogli gli elementi. Si usa per questo
l'operatore new seguito dal tipo di dati con il numero di elementi
racchiuso tra parentesi quadre. Per esempio,
arrayDiInteri = new int[7];
ARRAY IN C
• Stringhe
char nome[6];
nome = {‘C’,’S’,’4’,’1’,’4’,’\0’};
/* ’\0’= end of string */
printf(“%s”, nome); /* stampa fino a ‘\0’ */
– Funzioni che permettono di operare su stringhe
• strcpy, strncpy, strcmp, strncmp, strcat,
strncat, strstr,strchr
• #include <strings.h> at program start
• Array multidimensionali
int points[3][4];
points [1][3] = 12; /* NON points[3,4] !*/
printf(“%d”, points[1][3]);
STRINGHE
main()
{
char name[5];
/* definisce una stringa di caratteri */
name[0] = 'D';
name[1] = ’o';
name[2] = 'v';
name[3] = 'e';
name[4] = 0;
/* end of text */
printf(”Il nome è %s\n",nome);
printf(”una lettera è %c\n",name[2]);
}
JAVA: stringhe
Le stringhe in Java sono oggetti, e in particolare se ne
distinguono due tipi: stringhe costanti e stringhe variabili. La
distinzione è utile perché questi due tipi di oggetti hanno bisogno
di una forma di rappresentazione diversa.
Dichiarazione:
String variabile;
La creazione dell'oggetto
utilizzando l'operatore new.
new String (stringa);
si
ottiene
STRINGHE
char name1[12],name2[12],mixed[25];
char title[20];
strcpy(name1,"Rosalinda");
strcpy(name2,"Zeke");
if(strcmp(name1,name2)>0) /* returns 1 if name1 > name2 */
strcpy(mixed,name1);
else strcpy(mixed,name2);
strcat(mixed,name2);
• Conversione di tipi
– attenzione con la conversione di tipi
• c = (char) some_int;
• Arrays
– Sempre inizializzare prima di usarli
– int number[12];
printf(“%d”, number[20]);
• produce un output indefinito, può terminare, può
persino non essere segnalato.
• Le stringhe sono terminate dalla sequenza by ’\0’
char name[6] = {‘C’,’S’,’4’,’1’,’4’,’\0’};
/* ’\0’= end of string */
printf(“%s”, name); /* stampa sino a ‘\0’ */
CLASSI E STRUTTURE
Il C non permette di creare classi (a questo scopo in Java si usa
il costrutto class). Il concetto di classe NON ESISTE in C.
Tuttavia in C si possono creare strutture per mezzo del
costrutto struct. Una struttura C non contiene funzioni(metodi).
Tutte le parti di una struct sono visibili ad ogni porzione di
codice che conosce la dichiarazione.
struct point {
int x;
int y;
};
struct point {
int x, y;
};
Con la definizione struct si crea un nuovo tipo dato (tipo di dato
creato dall’utente)
STRUTTURE
• Insieme di variabili
– cui si fa riferimento con un unico nome
– si mantengono unite informazioni correlate
– concetto logico di record
nuovo tipo dato
STRUTTURE
Dopo avere definito il tipo si possono dichiarare elementi
di questo tipo:
struct point pt;
struct ind indirizzo;
E’ possibile creare il tipo dato e dichiararne le variabili in
un unico passaggio
STRUTTURE
Inizializzazione di un elemento:
struct point pt = {300,33};
Accesso ai vari elementi di una struttura attraverso
l’operatore. (punto) - come in Java:
struct point location;
location.x = 10;
location.y = 13;
STRUTTURE
A differenza del Java, dove le variabili di una classe sono riferimenti a
oggetti, in C le variabili di tipo struttura sono gli oggetti stessi.
L’assegnamento di strutture causa la copiatura dei membri :
struct point a = { 1, 2 };
struct point b;
b = a;
/* copia a.x in b.x,
e a.y in b.y */
b.x = 10; /* non agisce su a.x */
STRUTTURE
#include <stdio.h>
struct birthday{
int month;
int day;
int year;
};
main() {
struct birthday mybday;
/* new non è necessario ! */
/* quindi, è soltanto simile a Java ! */
mybday.day=1; mybday.month=1; mybday.year=1977;
printf(“Sono nato il %d/%d/%d”, mybday.day,
mybday.month, mybday.year);
}
PUNTATORI
In Java tutte le variabili di tipi non primitivi sono riferimenti.
Il C non realizza il concetto di ‘riferimento’, ma ha invece i puntatori, che il
Java non ha. Un puntatore è l’indirizzo in memoria di un dato. Una
variabile può essere di tipo puntatore, in tal caso essa contiene l’indirizzo di
un dato in memoria.
/* assumiamo di essere all’interno di un blocco*/
int i, j; /* i e j sono variabili intere */
int *ip; /* ip è una variabile che può puntare
una variabile intera */
i = 10;
j = 20;
/* assegnamento di valori */
ip = &i;
*ip = 5;
ip = &j;
*ip += 7;
i += *ip;
/*
/*
/*
/*
/*
ip punta a i */
assegnamento indiretto di 5 a i */
ip punta a j */
j ora contiene 27 */
i ora contiene 32 */
PUNTATORI, esempio
int x = 5, y = 10;
float f = 12.5, g = 9.8;
char c = ‘c’, d = ‘d’;
5
4300
10
4304
12.5
4308
9. 8
4312
c
d
4316 4317
PUNTATORI
Puntatore = variable contenente l’indirizzo di un’altra variabile
float f;
float *f_addr;
f
/* variabile numerica */
/* variabile di tipo puntatore */
f_addr
any float
?
?
?
4300
4304
any address
f_addr = &f; /* & = operatore indirizzo */
f
f_addr
?
4300
4300
4304
PUNTATORI
*f_addr = 3.2;
f
/* assegnamento indiretto */
f_addr
3.2
4300
4300
4304
float g=*f_addr;
/* assegnamento indiretto: g vale 3.2*/
f = 1.3;
f
f_addr
1.3
4300
4300
4304
PUNTATORI - ESEMPIO
#include <stdio.h>
void main(void) {
int j;
int *ptr;
ptr=&j;
}
/* inizializza ptr prima di usarlo */
/* *ptr=4 non inizializza ptr! */
*ptr=4;
/* j <- 4 */
j=*ptr;
/* j <- ??? */
Dichiarazioni e definizioni
I programmi C sono costituiti di collezioni di due tipi di elementi:
• funzioni (hanno un comportamento) e
• entità - oggetti (hanno valori; le variabili sono delle entità).
Un compilatore C legge un file sorgente in modo sequenziale, cercando
i nomi di tipi, variabili e funzioni.
La dichiarazione di un tipo, oggetto e funzione comunica al compilatore
l’esistenza di un nome e di come esso potrà essere usato più avanti nel
file. Se il compilatore incontra un nome che non è stato già dichiarato,
vi è la generazione di un errore.
La definizione di una variabile può anche indicare il suo valore
iniziale; la definizione di una funzione specifica il suo comportamento.
FUNZIONI
In Java, l’uso di una funzione può apparire prima della sua
definizione. In C, tutte le funzioni utilizzate nel file sorgente devono
essere dichiarate prima dell’invocazione nel file, permettendo cosi’ al
compilatore un controllo della correttezza degli argomenti rispetto alla
definizione dei parametri formali della funzione.
Una dichiarazione di funzione (o prototipo) è simile alla definizione
della funzione, ma il suo corpo (il codice tra gli statement { e }) è
sostituito da un ;. Se il compilatore trova una invocazione di funzione
prima di una dichiarazione, cercherà di inferire una dichiarazione
dall’invocazione, e questo può produrre errori.
MODULARITÀ DEI PROGRAMMI
I programmi Java sono costruiti in modo modulare, anche per
favorire il riutilizzo del codice.
Il codice sorgente è diviso in molti file sorgente (.java), ed è usato
per generare dei file byte-code di tipo classe (.class).
In Java, esiste una relazione diretta tra il nome di una classe e il
file contenente il codice di quella classe. Questi file sono
combinati durante l’esecuzione (run-time) per produrre il
programma in esecuzione.
MODULARITÀ DEI PROGRAMMI
Anche un grosso programma C può essere diviso in molti file
sorgente (solitamente con estensione .c), la cui compilazione
produce distinti file di tipo oggetto che (solitamente) hanno lo
stesso nome con una diversa estensione (.o o .obj). Questi
costituiscono moduli di C che possono essere combinati per
ottenere un programma eseguibile. Un file oggetto contiene
le rappresentazioni con nome associato delle funzioni e delle
variabili globali definite nel suo file sorgente, e permette un
riferimento ad altre funzioni e dati globali per mezzo del loro
nome, anche se risiedono in moduli separati.
In C, non esiste alcuna relazione tra i nomi di funzioni
e variabili e i nomi dei moduli che li contengono.
MODULARITÀ DEI PROGRAMMI
Il programma eseguibile finale è prodotto per mezzo di un linker
(spesso definito all’interno del compilatore) che collega tutti i
moduli rilevanti (file oggetto). Il linker cerca di risolvere tutti i nomi
a cui si fa riferimento nei moduli in indirizzi di memoria richiesti dal
codice macchina generato. Il linking fallisce se alcuni nomi non
possono essere risolti, o se ci sono due rappresentazioni con lo
stesso nome.
FUNZIONI
• Gli argomenti possono essere passati a una
funzione
– per valore
– per riferimento
• I valori prodotti da una funzione possono
essere
– per valore
– per riferimento
FUNZIONI: ESEMPIO 1
#include <stdio.h>
int sum(int a, int b);
/* prototipo della funzione all’inizio del
file */
void main(void){
int total = sum(4,5); /* chiamata alla funzione */
printf(“La somma di 4 e 5 è %d”, total);
}
int sum(int a, int b){
return (a+b);
}
/* definizione della funzione
- argomenti passati per valore */
/* return per valore */
FUNZIONI: ESEMPIO 2
#include <stdio.h>
int sum(int *pa, int *pb);
/* prototipo della funzione all’inizio del
file */
void main(void){
int a=4, b=5;
int *ptr = &b;
int total = sum(&a,ptr); /* chiamata alla funzione */
printf(“La somma di 4 e 5 è %d”, total);
}
int sum(int *pa, int *pb){/* definizione della funzione
- argomenti passati per riferimento */
return (*pa+*pb);
/* return per valore */
}
FUNZIONI: ESEMPIO 3 (passaggio di array)
#include <stdio.h>
void init_array(int array[], int size) ;
void main(void) {
int list[5];
init_array(list, 5);
for (i = 0; i < 5; i++)
printf(“next:%d”, list[i]);
}
void init_array(int array[], int size)
{
/* gli array sono SEMPRE passati per riferimento */
int i;
for (i = 0; i < size; i++)
array[i] = 0;
}
FUNZIONI: ESEMPIO 4 (passaggio di array e
aritmentica dei puntatori)
int maxMin (double arr [ ], int size, double *max, double *min)
{
if ( arr == NULL || size<= 0)
return 0;
for (*max = *min = arr[0], p = arr +1; p < arr + size; p++)
{
if (*max < *p)
*max = *p;
funzione che calcola il min ed il max
if (*min > *p)
passando tutti i parametri per riferimento
*mim = *p,
tranne size
}
return 1
}
ALLOCAZIONE DINAMICA DELLA MEMORIA
L'allocazione dinamica permette di creare tipi di dati e strutture
di qualsiasi dimensione e lunghezza in modo dinamico.
Tra gli utilizzi più diffusi:
 definizione di array dinamici;
 strutture dinamiche di dati, ad es. “linked list”.
ALLOCAZIONE DINAMICA DELLA MEMORIA
• Allocazione e de-allocazione esplicita
#include <stdio.h>
void main(void) {
int *ptr;
/* alloca spazio per contenere un intero */
ptr = (int *)malloc(sizeof(int));
/* fa qualcosa con lo spazio definito */
*ptr=4;
free(ptr);
/* libera lo sapeio allocato */
}
STRUTTURA DELLA MEMORIA
PER UN PROGRAMMA
0
Header info
100
Code
400
Tutte le malloc()
Data - Heap
Memoria dinamica
Data - stack
Stack di
memoria locale
+ chiamate di
funzioni
560
1010
Tutte le var
1200
ALLOCAZIONE DINAMICA DELLA MEMORIA
Le funzioni malloc() e free() fanno parte di una libreria esterna
e vengono utlizzate per allocare e liberare memoria quando ce
n’è bisogno (allocazione dinamica).
La funzione malloc è predefinita come:
char *malloc(int numero_di_byte)
Questa funzione ritorna un puntatore a carattere che corrisponde al
punto di inizio in memoria della porzione riservata di dimensione
”numero_di_byte". Se la memoria richiesta non puo' essere allocata,
ritorna un puntatore nullo.
Se si vuole avere un puntatore ad un altro tipo di dato, si deve
utilizzare il “casting”:
puntatore = (tipo*) malloc(byte);
…………...
Libera la memoria precedentemente
free(puntatore);
allocata
ALLOCAZIONE DINAMICA DELLA MEMORIA
Solitamente viene utilizzata la funzione sizeof() per specificare il
numero di bytes da allocare:
int *ip;
ip = (int *) malloc(sizeof(int));
Nel seguente esempio viene allocata/deallocata memoria per 10
interi
int *pint;
pint = (int*) malloc(10 * sizeof(int));
free(p int);
ALLOCAZIONE DINAMICA DELLA MEMORIA
"sizeof" puo' essere usata per trovare la dimensione di un qualsiasi
tipo di dato, variabile o struttura; e' possibile farlo semplicemente
passando uno di questi come argomento alla funzione.
Cosi':
int i;
struct COORD {float x,y,z};
sizeof(int), sizeof(i),
sizeof(struct COORD)
Array dinamici
In molti casi il numero di elementi di un vettore/matrice
può essere determinato solo durante l’esecuzione di un
programma.
Es: Supponiamo di voler ricevere in input un vettore. Il
primo numero che viene dato è la dimensione di questo
vettore, mentre i numeri successivi sono gli elementi.
Usando i vettori statici avremmo bisogno di decidere a
priori un numero massimo di elementi e ciò porrebbe dei
grossi limiti all’applicabilità del nostro programma.
Usando la funzione malloc() possiamo decidere la
dimensione del vettore durante l’esecuzione dl programma
Array dinamici
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h> /*header file contenente la definizione
main()
{
int *p;
/* definiamo un putatatore ad intero */
int dim,i;
printf(“Inserire il numero di elementi del vettore:”);
scanf(“%d”,&dim);
p=(int *)malloc(dim*sizeof(int));
/* alloca dinamicamente una zona di memoria*/
if ( p==NULL){/*verifica se l’allocazione è andata a b
printf ("Errore: Memoria non disposnibile \n");
exit(1);
}
for(i=0;i<dim;i++){
printf(“Inserire il valore dell’elemento %d del
scanf(“%d”,&p[i]);
printf(“L’indirizzo di p[%d] e’:%x\n il suo valore e’*
}
free(p); //libera la memoria allocata
}
Strutture dati ricorsive: liste
Per consentire la definizione di strutture dati ricorsive, ogni linguaggio
deve fornire un modo per "riusare" il nome della struttura che si sta
definendo dentro la definizione stessa.
typedef struct item {
la parola chiave typedef consente
la denizione di nuovi nomi di tipi di
dati a partire da quelli esistenti
Nuovo nome associato al tipo struct item
int value;
struct item *next;
} listItem;
listItem *list;
così, si può fare riferimento alla struttura all'interno della sua stessa
definizione, perché il tipo struct item è già noto al
compilatore quando si entra nel blocco {...}
etichettato item
n1
n2
n3
Strutture dati ricorsive: liste semplici
Strutture dati ricorsive: liste doppie
Strutture dati ricorsive: alberi binari
typedef struct item {
int value;
struct item *left,
*right;
} node;
typedef node *tree;