• Non ci sono risultati.

Il linguaggio C Il linguaggio C Puntatori Puntatori

N/A
N/A
Protected

Academic year: 2021

Condividi "Il linguaggio C Il linguaggio C Puntatori Puntatori"

Copied!
56
0
0

Testo completo

(1)

Il linguaggio C Il linguaggio C

Puntatori Puntatori

Moreno Marzolla

Dipartimento di Informatica—Scienza e Ingegneria (DISI) Università di Bologna https://www.moreno.marzolla.name/

Libro cap. 7, 8.1, 8.2

(2)
(3)

Ringraziamenti

Questi lucidi si basano su materiale fornito dal prof.

Mirko Viroli, Università di Bologna

(4)

Come sono rappresentati gli array in C?

Consideriamo int a[] = {11, -7, 3, 22}

Supponiamo che un intero occupi 4 byte

Cioè sizeof(int) == 4

Supponiamo che il primo elemento di a[] sia

memorizzato a partire dall'indirizzo di memoria 100010

11 -7 3 22

1000 1004 1008 1012

a[0] a[1] a[2] a[3]

Indirizzo di memoria

(5)

In generale

Consideriamo un array a[N] di valori di tipo T

Supponiamo che sizeof(T)= k

Indichiamo con Mem(a[i]) l'indirizzo di memoria a partire dal quale è memorizzato il valore a[i]

Allora, per ogni 0 ≤ i < N si ha:

Mem(a[i]) = Mem(a[0]) + i ´ k

11 -7 3 22

a[0] a[1] a[2] a[3]

(6)

Array multidimensionali

In C le matrici sono memorizzate "per righe"

Cioè le righe della matrice sono memorizzate in posizioni contigue della memoria

int m[4][3]

m[0][0] m[1][0] m[2][0] m[3][0]

(7)

Array multidimensionali

Consideriamo

int v[3][2]={{11,12},{21,22},{31,32}}

Supponiamo che v[0][0] sia memorizzato a partire dall'indirizzo di memoria 100010

Supponiamo che sizeof(int) == 4

11 12 21 22

1000 1004 1008 1012

v[0][0]

31 32 1016 1020

v[1][0] v[2][0]

v[0][1] v[1][1] v[2][1]

... ...

(8)

In generale

Data una matrice m[R][C] di valori di tipo T

Supponiamo che sizeof(T)= k

Sia Mem(m[i][j]) l'indirizzo di memoria a partire dal quale è memorizzato il valore m[i][j]

Allora, per ogni 0 ≤ i < R, 0 ≤ j < C si ha:

Mem(m[i][j]) = Mem(m[0][0]) + (i ´ C + j) ´ k

(9)

Domanda

Supponiamo che sizeof(double) == 8

Dato un array double a[10]

Supponiamo che a[0] sia memorizzato a partire dall'indirizzo di memoria 2048

A partire da quale indirizzo di memoria si trova a[5]?

Dato un array double m[3][7]

Supponiamo che m[0][0] sia memorizzato a partire dall'indirizzo di memoria 4096

A partire da quale indirizzo di memoria si trova m[2][4] ?

(10)

Stringhe (sequenze di caratteri) in C

La notazione "prova di stringa" è convertita dal compilatore in un array di char che termina col

carattere speciale '\0', che ha codice ASCII 0

Quindi "prova di stringa" occupa 17 byte di memoria:

16 per i caratteri + 1 per il terminatore

È possibile calcolare la lunghezza di una stringa contando quanti caratteri ci sono prima del '\0'

(11)

Esempio stringhe

/* es-stringhe.c */

#include <stdio.h>

int main( void ) {

char s1[6] = "Prova"; /* Ok, il compilatore alloca 6 elementi */

char s2[] = "Prova"; /* Ok, il compilatore alloca 6 elementi */

char s3[] = {'P','r','o','v','a','\0'};

printf("Stampa diretta di s2 e s3 : %s, %s\n", s2, s3);

printf("Elementi di s2: %c %c %c %c %c %c\n",

s2[0], s2[1], s2[2], s2[3], s2[4], s2[5]);

printf("Codici ASCII di s3: %d %d %d %d %d %d\n", s3[0], s3[1], s3[2], s3[3], s3[4], s3[5]);

return 0;

}

Stampa diretta di s2 e s3 : Prova, Prova Elementi di s2: P r o v a

(12)

Linguaggio C - puntatori 12

Lunghezza di una stringa

/* lunghezza-stringa.c */

#include <stdio.h>

int lunghezza(char c[]) {

int i;

for (i=0; c[i]!=0; i++) ; /* Corpo vuoto */

return i;

}

int main(void)

{ char s1[] = "Prova";

char s2[] = {'P','r','o','v','a','\0'};

printf("Lunghezza di s1: %d\n", lunghezza(s1));

printf("Lunghezza di s2: %d\n", lunghezza(s2));

return 0;

}

Lunghezza di s1: 5 Lunghezza di s2: 5

(13)

Lunghezza di una stringa

/* es-strlen.c */

#include <stdio.h>

#include <string.h>

int main(void) {

char s[] = "Prova";

printf("Lunghezza di s: %d\n", (int)strlen(s));

return 0;

Esiste una funzione predefinita strlen(s) che restituisce la lunghezza di s

È necessario includere string.h

Restituisce un size_t, che va convertito in int per poter essere stampato con la stringa di formato %d

(14)

Puntatori: dichiarazione

Un puntatore è una variabile il cui valore è l'indirizzo di memoria in cui è presente un valore di un certo tipo

Dichiarazione:

int *x; dichiara una variabile x contenente l'indirizzo di memoria di un valore di tipo int

Il tipo di x è “puntatore a intero”

Attenzione:

int *x, *y;

dichiara due variabili x e y di tipo "puntatore a intero"

int *x, y;

dichiara una variabile x di tipo "puntatore a intero", e una variabile y di tipo "intero" (NON puntatore)

(15)

Operatore & (riferimento)

Operatore unario applicabile a variabili

restituisce l'indirizzo della cella di memoria a partire dalla quale è memorizzata quella variabile

Se v è una variabile di tipo T, &v ha tipo “puntatore a T”

/* punt.c */

#include <stdio.h>

int main(void) {

int i=5; double d=1.5; int a[5];

int *pi = &i; /* E' un puntatore alla variabile i */

double *pd = &d; /* E' un puntatore alla variabile d */

int *pa4 = &a[4]; /* E' un puntatore al quinto elemento di a[] */

printf("%p\n", (void*)pi);

return 0;

} 0x7ffc68e726d8

(16)

Esempio

/* punt.c */

#include <stdio.h>

int main(void)

{ int i=5; double d=1.5; int a[5];

int *pi = &i;

double *pd = &d;

int *pa4 = &a[4];

printf("%p\n", (void*)pi);

return 0;

}

5 1.5

??

??

??

??

??

i d

a[0]

a[1]

a[2]

a[3]

a[4]

pi 2048

2052 2076 pd

pa4

2048 2052

2060 2064 2068 2072 2076 2080 2084 2088 Indirizzi di mem.

Assumiamo che:

un int occupi 4 byte

un double occupi 8 byte

un puntatore occupi 4 byte

Domanda: quale è la dimensione massima della memoria utilizzabile?

Non necessariamente le variabili i, d, pi, pd, pa4 e a[] sono adiacenti in memoria; gli elementi di a[] sono invece garantiti essere adiacenti

2056

(17)

Operatore di deriferimento *

Detto anche operatore di indirezione

Dato un puntatore p, l'espressione *p restituisce il valore della variabile "puntata" da p

È possibile assegnare un valore all'espressione *p per modificare il valore della variabile puntata

int main(void) {

int v = 5;

int *p = &v; /* p punta alla variabile v */

int w = *p; /* w ha valore 5 */

*p = *p + 1; /* v diventa 6 */

return 0;

}

(18)

Operatore di deriferimento *

/* punt2.c */

#include <stdio.h>

int main(void) {

int i = 5, j = 10;

int *v = &i; /* v punta alla variabile i */

int *w; /* w ha contenuto indefinito */

w = &j; /* w punta alla variabile j */

*w = 4; /* j viene modificato in 4 */

*w = *v; /* j viene modificato in 5, come i */

w = v; /* w punta a dove punta v, ossia i */

*w = 7; /* ora i vale 7 */

printf("i=%d, j=%d, *w=%d, *v=%d\n", i, j, *w, *v);

return 0;

}

(19)

5 10 i

j

/* punt2.c */

#include <stdio.h>

int main(void) {

int i = 5, j = 10;

int *v = &i; /* v punta alla variabile i */

int *w; /* w ha contenuto indefinito */

w = &j; /* w punta alla variabile j */

*w = 4; /* j viene modificato in 4 */

*w = *v; /* j viene modificato in 5, come i */

w = v; /* w punta a dove punta v, ossia i */

*w = 7; /* ora i vale 7 */

printf("i=%d, j=%d, *w=%d, *v=%d\n", i, j, *w, *v);

return 0;

}

(20)

5 10 i

j v

/* punt2.c */

#include <stdio.h>

int main(void) {

int i = 5, j = 10;

int *v = &i; /* v punta alla variabile i */

int *w; /* w ha contenuto indefinito */

w = &j; /* w punta alla variabile j */

*w = 4; /* j viene modificato in 4 */

*w = *v; /* j viene modificato in 5, come i */

w = v; /* w punta a dove punta v, ossia i */

*w = 7; /* ora i vale 7 */

printf("i=%d, j=%d, *w=%d, *v=%d\n", i, j, *w, *v);

return 0;

}

(21)

5 10 i

j v

/* punt2.c */

#include <stdio.h>

int main(void) {

int i = 5, j = 10;

int *v = &i; /* v punta alla variabile i */

int *w; /* w ha contenuto indefinito */

w = &j; /* w punta alla variabile j */

*w = 4; /* j viene modificato in 4 */

*w = *v; /* j viene modificato in 5, come i */

w = v; /* w punta a dove punta v, ossia i */

*w = 7; /* ora i vale 7 */

printf("i=%d, j=%d, *w=%d, *v=%d\n", i, j, *w, *v);

return 0;

}

(22)

Linguaggio C - puntatori 22

5 10 i

j v w

/* punt2.c */

#include <stdio.h>

int main(void) {

int i = 5, j = 10;

int *v = &i; /* v punta alla variabile i */

int *w; /* w ha contenuto indefinito */

w = &j; /* w punta alla variabile j */

*w = 4; /* j viene modificato in 4 */

*w = *v; /* j viene modificato in 5, come i */

w = v; /* w punta a dove punta v, ossia i */

*w = 7; /* ora i vale 7 */

printf("i=%d, j=%d, *w=%d, *v=%d\n", i, j, *w, *v);

return 0;

}

(23)

5 4 i

j v

/* punt2.c */

#include <stdio.h>

int main(void) {

int i = 5, j = 10;

int *v = &i; /* v punta alla variabile i */

int *w; /* w ha contenuto indefinito */

w = &j; /* w punta alla variabile j */

*w = 4; /* j viene modificato in 4 */

*w = *v; /* j viene modificato in 5, come i */

w = v; /* w punta a dove punta v, ossia i */

*w = 7; /* ora i vale 7 */

printf("i=%d, j=%d, *w=%d, *v=%d\n", i, j, *w, *v);

return 0;

}

(24)

Linguaggio C - puntatori 24

5 5 i

j v w

/* punt2.c */

#include <stdio.h>

int main(void) {

int i = 5, j = 10;

int *v = &i; /* v punta alla variabile i */

int *w; /* w ha contenuto indefinito */

w = &j; /* w punta alla variabile j */

*w = 4; /* j viene modificato in 4 */

*w = *v; /* j viene modificato in 5, come i */

w = v; /* w punta a dove punta v, ossia i */

*w = 7; /* ora i vale 7 */

printf("i=%d, j=%d, *w=%d, *v=%d\n", i, j, *w, *v);

return 0;

}

(25)

5 5 i

j v

/* punt2.c */

#include <stdio.h>

int main(void) {

int i = 5, j = 10;

int *v = &i; /* v punta alla variabile i */

int *w; /* w ha contenuto indefinito */

w = &j; /* w punta alla variabile j */

*w = 4; /* j viene modificato in 4 */

*w = *v; /* j viene modificato in 5, come i */

w = v; /* w punta a dove punta v, ossia i */

*w = 7; /* ora i vale 7 */

printf("i=%d, j=%d, *w=%d, *v=%d\n", i, j, *w, *v);

return 0;

}

(26)

Linguaggio C - puntatori 26

7 5 i

j v w

/* punt2.c */

#include <stdio.h>

int main(void) {

int i = 5, j = 10;

int *v = &i; /* v punta alla variabile i */

int *w; /* w ha contenuto indefinito */

w = &j; /* w punta alla variabile j */

*w = 4; /* j viene modificato in 4 */

*w = *v; /* j viene modificato in 5, come i */

w = v; /* w punta a dove punta v, ossia i */

*w = 7; /* ora i vale 7 */

printf("i=%d, j=%d, *w=%d, *v=%d\n", i, j, *w, *v);

return 0;

}

(27)

Esempio con gli array

int main(void) {

int a[] = {11, 7};

int *w = &a[1]; /* w punta al secondo elemento dell'array */

int i = *w; /* i viene assegnato a 7 */

*w = 0; /* il secondo elem. dell'array viene posto a 0 */

return 0;

}

(28)

11 7 a[0]

a[1]

int main(void) {

int a[] = {11, 7};

int *w = &a[1]; /* w punta al secondo elemento dell'array */

int i = *w; /* i viene assegnato a 7 */

*w = 0; /* il secondo elem. dell'array viene posto a 0 */

return 0;

}

Esempio con gli array

(29)

11 7 a[0]

a[1]

w

int main(void) {

int a[] = {11, 7};

int *w = &a[1]; /* w punta al secondo elemento dell'array */

int i = *w; /* i viene assegnato a 7 */

*w = 0; /* il secondo elem. dell'array viene posto a 0 */

return 0;

}

Esempio con gli array

(30)

11 7 a[0]

a[1]

w i 7

int main(void) {

int a[] = {11, 7};

int *w = &a[1]; /* w punta al secondo elemento dell'array */

int i = *w; /* i viene assegnato a 7 */

*w = 0; /* il secondo elem. dell'array viene posto a 0 */

return 0;

}

Esempio con gli array

(31)

11 0 a[0]

a[1]

w i 7

int main(void) {

int a[] = {11, 7};

int *w = &a[1]; /* w punta al secondo elemento dell'array */

int i = *w; /* i viene assegnato a 7 */

*w = 0; /* il secondo elem. dell'array viene posto a 0 */

return 0;

}

Esempio con gli array

(32)

Puntatori: inizializzazione

L'header file stddef.h definisce il simbolo NULL che denota un indirizzo di memoria "non valido"

Può quindi essere usato come valore iniziale di un puntatore, se necessario

stddef.h viene incluso indirettamente anche da altri header (es., stdio.h), quindi potrebbe non essere necessario includerlo esplicitamente

(33)

/* null-ptr.c : esempio di uso di NULL */

#include <stdio.h>

#include <stddef.h>

int main( void ) {

int a = 10, *ptr_a = NULL;

ptr_a = &a;

if ( ptr_a == NULL ) {

printf("ptr_a non valido\n");

} else {

printf("ptr_a punta a %p che contiene il valore %d\n", (void*)ptr_a, *ptr_a);

}

return 0;

}

ptr_a punta a 0x7ffe4439c7d4 che contiene il valore 10

Esempio

Può essere omesso, perché in gcc viene già incluso indirettamente da stdio.h

(34)

Linguaggio C - puntatori 34

Input da tastiera

La funzione scanf, duale a printf, viene usata per ricevere input da tastiera e assegnarne il valore ad una variabile

bisogna passare a scanf il puntatore alla variabile dove si vuole venga memorizzato il risultato

#include <stdio.h>

int main(void) {

int x;

float f;

printf("Inserisci un intero: "); scanf("%d",&x);

printf("Inserisci un float: "); scanf("%f",&f);

printf("x=%d, f=%f, prodotto=%f\n", x, f, x*f);

return 0;

}

(35)

Input di stringhe

Le stringhe andranno depositate in un array di caratteri

scanf vuole l'indicazione %s o %Ns

come secondo argomento mettere l'array

#include <stdio.h>

int main(void) {

char str1[11], str2[11];

printf("Inserisci una stringa: ");

scanf("%s", str1); /* non usare &str1 se str1 è una stringa!!! */

printf("Inserisci una stringa di non più di 10 caratteri: ");

scanf("%10s", str2); /* nota: char str2[11] per includere il \0 finale */

printf("str1: %s\n", str1);

printf("str2: %s\n", str2);

return 0;

(36)

Array e puntatori

Un array di T si comporta come un puntatore

Se a è una variabile dichiarata come T a[N] (array di T)...

...l'espressione a (senza indici) ha tipo T* (puntatore a T) e ha come valore l'indirizzo di memoria di a[0]

Un puntatore può essere "indicizzato" come se fosse un array

Se v è dichiarata come T *v (puntatore a T) e valore un indirizzo di memoria M...

...allora l'espressione v+k (k intero) ha tipo "puntatore a T" e contiene l'indirizzo di memoria

M + k ´ sizeof(T)

...e l'espressione v[k] (k intero) ha tipo T e valore pari a quello memorizzato a partire dall'indirizzo M + k ´ sizeof(T)

(37)

Aritmetica dei puntatori

/* arit-punt.c */

#include <stdio.h>

int main(void)

{ int a[] = {15, 16, 17};

int *p, *q;

p = a; /* Ok, e' come scrivere p = &a[0] */

*p = -1; /* ora l'array a[] vale {-1, 16, 17} */

q = p + 1; /* q contiene l'indirizzo di a[1] */

q++; /* q contiene l'indirizzo di a[2] */

*q = -3; /* ora l'array a[] vale {-1, 16, -3} */

*(p+1) = 2; /* ora l'array a[] vale {-1, 2, -3} */

printf("%d %d %d\n", a[0], a[1], a[2]);

printf("%d\n", *(p+2));

return 0;

}

(38)

Attenzione

Se p è una variabile di tipo puntatore, allora in genere

*(p+1) ≠ *p + 1

Esempio: cosa stampa il programma seguente?

/* arit-punt2.c */

#include <stdio.h>

int main(void)

{ int a[] = {1, 21, -3};

int *p = a;

printf("%d\n", *(p+1));

printf("%d\n", *p + 1);

return 0;

}

(39)

Attenzione

Da quanto detto in precedenza dovrebbe essere chiaro perché non sia possibile controllare se due

array a[] e b[] contengono gli stessi valori scrivendo (a == b)

Il programma seguente stampa "falso": perché?

/* confronto.c */

#include <stdio.h>

int main(void)

{ int a[] = {1, 21, -3};

int b[] = {1, 21, -3};

printf("%s\n", (a == b ? "vero" : "falso"));

return 0;

}

(40)

Metodo corretto per confrontare il contenuto di due array

/* arrays_equal.c */

#include <stdio.h>

/* restituisce 1 se e solo se a[] e b[] hanno lo stesso contenuto */

int arrays_equal(int a[], int b[], int n) {

int i;

for (i=0; i<n; i++) { if (a[i] != b[i]) {

return 0;

}

}return 1;

}

int main(void)

{ int a[] = {1, 21, -3};

int b[] = {1, 21, -3};

printf("%s\n", (arrays_equal(a, b, 3) ? "vero" : "falso"));

return 0;

}

(41)

Attenzione

Se p è un puntatore a T:

L'espressione p++ incrementa p, che quindi conterrà l'indirizzo (p + sizeof(T))

L'espressione *p++ equivale a *(p++)

(p++) ritorna l'indirizzo corrente puntato da p, e poi lo incrementa

Quindi *p++ ritorna il valore puntato da p, e poi incrementa p

Mettere sempre le parentesi per evitare confusione

Esempio: cosa fa il

programma di lato? #include <stdio.h>

int main(void)

{ int a[] = {1, 21, -3};

int *p = &a[0];

printf("%d\n", *p++);

(42)

Array e funzioni

Le funzioni seguenti sono equivalenti e si invocano tutte allo stesso modo

int sum1(int a[], int n) {

int i, s=0;

for (i=0; i<n; i++) { s += a[i];

}

return s;

}

int sum2(int *a, int n) {

int i, s=0;

for (i=0; i<n; i++) { s += a[i];

}

return s;

}

int sum3(int *a, int n) {

int i, s=0;

for (i=0; i<n; i++) { s += *(a+i);

}

return s;

}

int sum4(int *a, int n) {

int *p, s=0;

for( p=a; p<a+n; p++) { s += *p;

}

return s;

}

(43)

int sum4(int *a, int n) {

int *p, s=0;

for( p=a; p<a+n; p++) { s += *p;

}

return s;

}

3 -1 12 5 4

Spiegazione di sum4()

Supponiamo

sizeof(int) == 4

a[] = {3, -1, 12, 5, 4}

a a+5

(44)

Puntatori a carattere

L'"equivalenza" tra array e puntatori consente di manipolare le stringhe (sequenze di caratteri) sia come array di char, sia come puntatori a

char

/* lunghezza2.c */

#include <stdio.h>

int lunghezza( char* s ) { int n;

for (n=0; *s; s++) { n++; } return n;

}

int main( void ) {

char *s1 = "Prova";

char s2[] = "Prova";

printf("%d %d\n",

lunghezza(s1), lunghezza(s2));

return 0;

}

'P' 'r' 'o' 'v' 'a' 0 'P' 'r' 'o' 'v' 'a' 0

s1 s2

Memoria

(45)

Attenzione

C'è una differenza

importante tra s1 e s2

Modificare il contenuto di s1 causa un

comportamento indefinito

Modificare il contenuto di s2 è ammesso

/* indefinito.c */

#include <stdio.h>

int main( void )

{ char *s1 = "Prova";

char s2[] = "Prova";

*s1 = 'p'; /* INDEFINITO */

s2[0] = 'p'; /* Ok */

printf(“%s %s\n”, s1, s2);

return 0;

}

'P' 'r' 'o' 'v' 'a' 0 'P' 'r' 'o' 'v' 'a' 0

s1 s2

Solo in questo caso, i caratteri del letterale

“Prova” vengono memorizzati in un'area di memoria

che si deve immaginare “a sola

lettura”

(46)

Passaggio per puntatore

Una applicazione

importante dei puntatori è per "modificare" il

parametro attuale

non si passa il “cosa” ma il “dove”

/* punt-parametro.c */

#include <stdio.h>

void incrementa(int *x) { *x = *x + 1;

}

int main( void ) { int a = 10;

incrementa(&a);

printf("a = %d\n", a);

return 0;

}

(47)

Passaggio per puntatore

/* punt-parametro.c */

#include <stdio.h>

void incrementa(int *x) { *x = *x + 1;

}

int main( void ) {

int a = 10;

incrementa(&a);

printf("a = %d\n", a);

return 0;

}

10

1024 a

(48)

Passaggio per puntatore

/* punt-parametro.c */

#include <stdio.h>

void incrementa(int *x) { *x = *x + 1;

}

int main( void ) {

int a = 10;

incrementa(&a);

printf("a = %d\n", a);

return 0;

}

10

1024 a

void incrementa(int *x) { *x = *x + 1;

}

x = 1024

(49)

Passaggio per puntatore

/* punt-parametro.c */

#include <stdio.h>

void incrementa(int *x) { *x = *x + 1;

}

int main( void ) {

int a = 10;

incrementa(&a);

printf("a = %d\n", a);

return 0;

}

11

1024 a

void incrementa(int *x) { *x = *x + 1;

}

x = 1024

(50)

Passaggio per puntatore

/* punt-parametro.c */

#include <stdio.h>

void incrementa(int *x) { *x = *x + 1;

}

int main( void ) {

int a = 10;

incrementa(&a);

printf("a = %d\n", a);

return 0;

}

11

1024 a

void incrementa(int *x) { *x = *x + 1;

}

x = 1024

(51)

Passaggio per puntatore

/* punt-parametro.c */

#include <stdio.h>

void incrementa(int *x) { *x = *x + 1;

}

int main( void ) {

int a = 10;

incrementa(&a);

printf("a = %d\n", a);

return 0;

}

11

1024 a

a = 11

Output

(52)

Passaggio per puntatore

/* punt-parametro.c */

#include <stdio.h>

void incrementa(int *x) { *x = *x + 1;

}

int main( void ) {

int a = 10;

incrementa(&a);

printf("a = %d\n", a);

return 0;

}

11

1024 a

a = 11

Output

(53)

La funzione malloc()

Definita in stdlib.h

Serve per allocare (riservare) una porzione di memoria da usare per memorizzare qualunque dato

Si passa come parametro la dimensione (in byte) richiesta

malloc()ritorna un puntatore void * che deve essere convertito (con un cast) al puntatore di tipo richiesto

La memoria va liberata quando non serve più con free()

Con malloc() è possibile creare array la cui dimensione non è nota a priori

Consente anche di realizzare funzioni che creano array e li

(54)

Linguaggio C - Gestione della memoria 54

/* reverse-fun.c : esempio di funzione che ritorna un array */

#include <stdio.h>

#include <stdlib.h>

/* Dato un array a[] di lunghezza n, restituisce un nuovo array di lunghezza n il cui contenuto e' il contenuto di a[]

"rovesciato" */

int *reverse(int a[], int n)

{ int *r = (int *)malloc(n*sizeof(int));

int i;

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

r[i]=a[n-1-i];

}

return r;

}

int main( void )

{ int in[] = {10, 20, 30, 40};

int *out = reverse(in, 4);

printf("%d %d %d %d\n", out[0], out[1], out[2], out[3]);

free(out);

return 0;

}

Esempio

Contiene la dichiarazione di malloc()

(55)

Attenzione

La memoria allocata con malloc() non viene liberata uscendo da una funzione

int *prova( void )

{ int *r = (int *)malloc(10*sizeof(int));

...return r; /* OK: la memoria puntata da r rimane allocata anche fuori dalla funzione */

}

(56)

Attenzione

La memoria occupata da un array locale viene invece liberata uscendo da una funzione

int *prova( void ) { int r[10];

...return r; /* NO: la mem. di r[] viene liberata al termine della funzione */

}

prova.c:7:12: warning: function returns address of local variable [-Wreturn-local-addr]

return r;

^

Riferimenti

Documenti correlati

Se invece di eseguire prove singole, eseguiamo delle serie di prove, da 36 o più lanci ciascuna, si avrà, nella maggior parte delle serie eseguite, in percentuale

quest’ultima discussione metafisica che probabilmente appassioner` a solo l’aspirante studioso della teoria dei Linguaggi di Programmazione, ` e bene ricordare che i pas- saggi

Appena il programma viene caricato in memoria per essere eseguito la memoria apparirebbe come mostrato dalla seguente figura:. A seguito dell'esecuzione del main(), l'area Heap

Si noti che la funzione free() , de-alloca l'area puntata dal puntatore, ma non annulla il puntatore, ossia esso non viene posto a NULL, ma viene lasciato al valore

Poiché la memoria heap è limitata,  questa può essere esaurita e quindi è 

Si applica a un puntatore e restituisce il valore contenuto nella cella puntata =&gt; serve per accedere alla variabile puntatap. • Operatori aritmetici (vedi vettori

The set of function parameters, plus return address, plus local variables is called Stack Frame of the function. The CPU internally has

The set of function parameters, plus return address, plus local variables is called Stack Frame of the function. The CPU internally has