Vettori, indirizzi e puntatori Finora abbiamo usato gli indirizzi nel chiamare  la funzione scanf()  le altre funzioni per riferimento Tuttavia la vera.

Slides:



Advertisements
Presentazioni simili
Puntatori Linguaggio C.
Advertisements

Introduzione al linguaggio C++
Corso di Fondamenti di Programmazione canale E-O
LINGUAGGIO DI PROGRAMMAZIONE C
INFORMATICA Algoritmi fondamentali
Puntatori in C e C++.
Array multidimensionali
PUNTATORI Introduzione
Differenze tra C e C++ Commenti: Adesso puoi inserire dei commenti tra // e la fine della linea. Usare le librerie C: In C++ puoi anche chiamare una funzione.
Introduzione al linguaggio C
Introduzione al linguaggio C Dr. Francesco Fabozzi Corso di Informatica.
Fondamenti di Informatica Prof. Cantone
Anno accademico Array e puntatori in C.
Algoritmi in C++ (1) da completare
Indirizzi delle variabili A ogni variabile sono associati tre concetti fondamentali: il valore memorizzato; il tipo dati di appartenenza; lindirizzo. Il.
FUNZIONI DI BIBLIOTECA
Fondamenti di Informatica II Ingegneria Informatica / Automatica (A-I) Meccanica Prof. M.T. PAZIENZA a.a – 3° ciclo.
Caratteri e stringhe di caratteri
Argomenti dalla linea dei comandi Gli argomenti possono essere passati a qualsiasi funzione di un programma, compresa la main(), direttamente dalla linea.
Ambito delle variabili
FILE DATI 16 lunedi 26 luglio giovedi ore 9 Come sappiamo, un file dati è un gruppo di informazioni tra loro correlate, memorizzate in un dispositivo di.
Funzioni definite dall’utente
PROGRAMMI DI RICERCA E ORDINAMENTO
Fondamenti di Informatica II Ingegneria Informatica (A-I) Prof. M.T. PAZIENZA a.a – 3° ciclo.
Corso di Fondamenti di programmazione a.a.2009/2010
Prof.ssa Chiara Petrioli -- Fondamenti di programmazione, a.a. 2009/2010 Corso di Fondamenti di programmazione a.a. 2009/2010 Prof.ssa Chiara Petrioli.
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Corso di Programmazione 1 a.a.2006/2007 Prof.ssa Chiara Petrioli Corso di Laurea.
DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE Puntatori Marco D. Santambrogio – Ver. aggiornata al 21 Marzo 2013.
Process synchronization
memoria gestita staticamente:
Struct, enum, Puntatori e Array dinamici
Esercizi FUNZIONI Passaggio di parametri per valore, variabili e tipi locali e globali, prototipo.
Esercizi Puntatori, struct con campi puntatore, puntatori a struct, rapporto tra array e puntatori. FUNZIONI Passaggio di parametri per indirizzo, passaggio.
Le funzioni.
Algoritmi e Programmazione Avanzata
FUNZIONI... Una funzione permette di dare un nome a una espressione rendendola parametrica float f(){ return * sin(0.75); } float f1(int x) { return.
2000 Prentice Hall, Inc. All rights reserved. Capitolo 10 (Deitel) Strutture, unioni ed enumerazioni Sommario Introduzione Definire le strutture.
Prof.ssa Chiara Petrioli -- Fondamenti di programmazione, a.a. 2009/2010 Corso di Fondamenti di programmazione a.a. 2009/2010 Prof.ssa Chiara Petrioli.
Puntatori e gestione dinamica della memoria
Unità Didattica 3 Linguaggio C
G. Amodeo, C. Gaibisso Programmazione di Calcolatori Lezione XVIII Le matrici Programmazione di Calcolatori: le matrici 1.
Passaggio di parametri per indirizzo
C. Gaibisso Programmazione di Calcolatori Lezione XIV I vettori Programmazione di Calcolatori: i vettori 1.
Programmazione di Calcolatori
1Piero Scotto - C14. Finalità del corso Programma Materiale Requisiti Spendibilità 2Piero Scotto - C14.
2000 Prentice Hall, Inc. All rights reserved. Attivazione di funzioni La chiamata/attivazione di funzione viene indicata citando il nome della funzione.
Complessità di un algoritmo
1 Fabio Scotti ( ) Laboratorio di programmazione per la sicurezza Valentina Ciriani ( ) Laboratorio di programmazione Lezione 11 e 12 -
Definizione di un algoritmo
GLI ARRAY MONODIMENSIONALI. Utilizzando le nostre attuali conoscenze, proviamo a risolvere il seguente problema: Calcolare la media dei voti conseguiti.
Ripetizione La vera potenza dei programmi per computer risiede nella capacità di ripetere lo stesso calcolo o sequenza di istruzioni più volte, ogni volta.
Il linguaggio C Puntatori e dintorni.
Prof.ssa Chiara Petrioli -- corso di programmazione 1, a.a. 2006/2007 Corso di Programmazione 1 a.a.2006/2007 Prof.ssa Chiara Petrioli Corso di Laurea.
Vettori (a una dimensione)
Parte 3 Lo stato: variabili, espressioni ed assegnazioni
DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE Puntatori Marco D. Santambrogio – Ver. aggiornata al 11 Ottobre 2014.
Fondamenti di Informatica 2 Ingegneria Informatica Docente: Giovanni Macchia a.a
1 Il linguaggio C Puntatori e dintorni. 2 Puntatori : idea di base In C è possibile conoscere e denotare l’indirizzo della cella di memoria in cui è memorizzata.
Allievi Elettrici - AA Le funzioni ricorsive in C
© Piero Demichelis Tipi strutturati I tipi considerati finora hanno la caratteristica comune di non essere strutturati: ogni elemento è una singola entità.
DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE Puntatori Marco D. Santambrogio – Ver. aggiornata al 11 Marzo 2014.
DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE Array e “stringhe” Marco D. Santambrogio – Ver. aggiornata al 8 Aprile 2015.
ALLOCAZIONE STATICA: LIMITI Per quanto sappiamo finora, in C le variabili sono sempre dichiarate staticamente –la loro esistenza deve essere prevista e.
Linguaggio C: Le basi Stefano Cagnoni e Monica Mordonini
Esercizi.
DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE Array e “stringhe” Marco D. Santambrogio – Ver. aggiornata al 14 Marzo 204.
DIPARTIMENTO DI ELETTRONICA E INFORMAZIONE Array e “stringhe” Marco D. Santambrogio – Ver. aggiornata al 28 Ottobre 2014.
“ Pseudocodice ” Un programma per computer lavorerà su in insieme di “ variabili ” contenenti i dati del problema, soluzioni intermedie, soluzioni finali.
30/10/01Array 1  Un array e’ una struttura dati che contiene piu’ valori del medesimo tipo.  La lunghezza di un array e’ stabilita quando l’array viene.
Linguaggio C: Funzioni e Puntatori Laboratorio di Programmazione Gruppo 1.
Transcript della presentazione:

Vettori, indirizzi e puntatori Finora abbiamo usato gli indirizzi nel chiamare  la funzione scanf()  le altre funzioni per riferimento Tuttavia la vera potenza dei puntatori è nelle operazioni con vettori, stringhe e altre strutture dati, poiché esiste una relazione diretta e stretta tra vettori, indirizzi e puntatori. Mostriamo intanto che: Puntatori come nomi di vettori. Riprendiamo in considerazione il precedente vettore voti, costituito da 5 interi. Osserviamo che l’uso di un subscritto nasconde l’uso che il computer fa degli indirizzi. Di fatto, il computer usa il subscritto per calcolare l’indirizzo dell’elemento desiderato basandosi su:  l’indirizzo di partenza del vettore  la quantità di memoria usata per ciascun elemento. il riferimento agli elementi di un vettore può avvenire tramite i puntatori

Quindi la chiamata, ad es., del 4° elemento, voti[3], fa eseguire al computer il seguente calcolo: &voti[3] = &voti[0] + (3 * 2) come è illustrato dalla figura seguente: Perciò, se creiamo un puntatore che memorizzi l’indirizzo del 1° elemento del vettore voti, possiamo accedere agli elementi del vettore simulando la modalià seguita dal computer.

A tale fine potremmo: memorizzare l’indirizzo dell’elemento voti[0] nel puntatore punt_v, con l’istruzione di assegnazione punt_v = &voti[0]; usare l’operatore di indirezione * e l’indirizzo memorizzato nel puntatore per accedere a ciascun elemento del vettore. In tal modo l’espressione *punt_v (“ la variabile puntata da punt_v ”) è un riferimento a voti[0], come mostra la figura seguente:

Notazione con puntatore e offset. Una caratteristica unica dei puntatori è che nelle espressioni che li usano si possono inserire gli offset. Ad es., nell’espressione *(punt_v + 1) 1 è un offset, che rende l’espressione un riferimento alla variabile che segue di 1 posizione la variabile puntata da punt_v, ossia voti[1]. Analogamente, l’espressione *(punt_v + 3) è un riferimento alla variabile che segue di 3 posizioni la variabile puntata da punt_v, ossia voti[3], come illustra la seguente tabella

Usando la corrispondenza tra puntatori e subscritti, abbiamo adesso due possibilità diverse per accedere agli elementi del vettore voti : 1. con un programma che usi i subscritti, quale: #include void main(void) { int i; int voti[] = {98, 87, 92, 79, 85}; for (i = 0; i <= 4; ++i) printf("\nL’elemento %d è %d", i, voti[i]); }

#include void main(void) { int *punt_v; int i; int voti[] = {98, 87, 92, 79, 85}; punt_v = &voti[0]; for (i = 0; i <= 4; ++i) printf("\nL’elemento %d è %d", i, *(punt_v + i)); } Essi producono, ovviamente, la stessa uscita: 2. con un programma che usi i puntatori, quale:

Il metodo usato nel programma precedente per accedere ai singoli elementi del vettore simula quello con cui un computer fa riferimento agli elementi del vettore. Ogni subscritto usato dal programmatore viene convertito automaticamente in un’equivalente espressione con puntatori. Nel nostro caso, dato che la dichiarazione di punt_v comprende l’informazione che le variabili puntate sono interi, ogni offset aggiunto all’indirizzo in punt_v viene automaticamente scalato secondo la dimensione di un intero. Così, ad es., *(punt_v + 3) è un riferimento all’indirizzo di voti[0] più un offset di 6 byte (3 * 2), come illustrato in una figura precedente.

Osservazioni 1. Le parentesi nell’espressione *(punt_v + 3) sono necessarie per un riferimento corretto all’elemento desiderato. Infatti la loro omissione darebbe luogo all’espressione *punt_v + 3 che aggiunge 3 alla “variabile puntata da punt_v ”, che è voti[0]. 2. L’espressione *(punt_v + 3) non cambia l’indirizzo memorizzato in punt_v. Una volta che il computer abbia usato l’offset per localizzare la variabile corretta a partire dall’indirizzo di partenza in punt_v, l’offset è eliminato e l’indirizzo in punt_v rimane inalterato.

Costanti puntatore. Sebbene il puntatore punt_v usato nel programma precedente sia stato creato per memorizzare l’indirizzo di partenza del vettore voti, ciò non era in realtà necessario. Infatti, quando si dichiara un vettore, il compilatore crea automaticamente per esso una costante puntatore interna, nella quale memorizza l’indirizzo di partenza del vettore. Una costante puntatore è identica a una variabile puntatore creata dal programmatore sotto molti aspetti (ma, come vedremo, non tutti). Per ogni vettore creato, il suo nome diventa quello della costante puntatore che il compilatore ha creato per esso, e nella quale viene memorizzato l’indirizzo di partenza della prima locazione riservata per il vettore.

Così, le dichiarazioni del vettore voti nei due programmi precedenti hanno effettivamente:  riservato memoria sufficiente per 5 interi  creato una costante puntatore interna di nome voti, nella quale hanno memorizzato l’indirizo di voti[0]. Perciò, il programma precedente si può anche semplificare sopprimendo le due istruzioni scritte in chiaro: #include void main(void) { int *punt_v; int i; int voti[] = {98, 87, 92, 79, 85}; punt_v = &voti[0]; for (i = 0; i <= 4; ++i) printf("\nL’elemento %d è %d", i, *(voti + i)); }

In esso, avendo usato voti come puntatore, abbiamo eliminato le istruzioni int *punt_v; (che dichiarava il puntatore punt_v ) e punt_v = &voti[0]; (che lo inizializzava). Sotto molti aspetti, Perciò non sarebbe valida un’espressione del tipo voti = &voti[2] Infatti un nome di vettore ha lo scopo di localizzare correttamente l’inizio del vettore, e tale scopo verebbe meno se fosse consentito alterare l’indirizzo memorizzato nel nome del vettore. un nome di vettore è una costante puntatore, e l’indrizzo memorizzato in essa non può essere cambiato da un’istruzione di assegnazione. un nome di vettore e un puntatore si possono usare in modo intercambiabile. Tuttavia, un vero puntatore è una variabile, e l’indirizzo memorizzato in esso può essere cambiato mentre

Inoltre, non sarebbe valida un’espressione contenente l’indirizzo di un nome di vettore, quale &voti Ciò perché il puntatore creato dal compilatore è interno a esso e non memorizzato in memoria, come le variabili puntatore. Un interessante complemento al fatto che il riferimento agli elementi di un vettore può avvenire tramite i puntatori è che anche Ad es., se punt_num è una variabile puntatore, l’espressione *(punt_num + i) può essere sostituita da punt_num[i] anche se punt_num non è creato come vettore. Come prima, quando il compilatore incontra la notazione con subscritto la sostituisce internamente con quella a puntatore. un riferimento puntatore si può sempre sostituire con un riferimento subscritto

Aritmetica dei puntatori Le variabili puntatore, come tutte le altre, contengono valori, che nel caso specifico sono indirizzi. Perciò, sommando e sottraendo numeri ai puntatori possiamo ottenere indirizzi differenti. Inoltre, gli indirizzi nei puntatori possono essere confrontati usando qualsiasi operatore relazionale ( ==, <=,...) valido per confrontare le altre variabili. Nell’eseguire i calcoli con i puntatori si deve porre attenzione a produrre indirizzi che puntino a qualcosa di significativo, mentre nel confrontare i puntatori si devono effettuare confronti che abbiano senso.

Consideriamo le due dichiarazioni: int num[100]; int *punt_n; per assegnare a punt_n l’indirizzo di num[0] si può usare, oltre alla ovvia istruzione di assegnazione: punt_n = &num[0]; anche la meno ovvia istruzione: punt_n = num; Esse producono lo stesso risultato perché num è una costante puntatore che contiene l’indirizzo della prima componente del vettore, ossia l’indirizzo di num[0]. La figura seguente illustra l’allocazione di memoria risultante dalle precedenti istruzioni di dichiarazione e assegnazione, nell’ipotesi che la locazione d’inizio del vettore num sia l’indirizzo 18934

Una volta che punt_n contenga un indirizzo valido, gli si possono aggiungere e sottrarre valori per produrre nuovi indirizzi. Quando si aggiungono o sottraggono numeri ai puntatori, il computer li aggiusta automaticamente per garantire che il risultato punti ancora a un valore del tipo corretto.

Ad es., l’istruzione: punt_n = punt_n + 4; forza il computer a scalare il 4 del numero corretto per garantire che l’indirizzo risultante sia quello di un intero. Dato che ogni intero richiede 2 byte di memoria, il computer moltiplica il 4 per 2 e quindi aggiunge 8 all’indirizzo in punt_n, ottenendo l’indirizzo 18942, che è quello corretto di num[4]. Gli indirizzi possono essere incrementati o decrementati usando anche gli operatori di incremento prefissi e postfissi: l’aggiunta di 1 a un puntatore lo fa puntare all’elemento successivo, la sottrazione di 1 lo fa puntare al precedente. Sono quindi valide le seguenti combinazioni: *punt_num++ /* usa il puntatore e poi lo incrementa */ *++punt_num /* incrementa il puntatore e poi lo usa */ *punt_num-- /* usa il puntatore e poi lo decremente */ *--punt_num /* decrementa il puntatore e poi lo usa */

Di esse la più usata è *punt_num++, che consente di accedere a ogni elemento di un vettore via via che si procede in esso dal suo indirizzo di partenza a quello dell’ultimo elemento. Un esempio del suo utilizzo è fornito nel programma seguente, che calcola la somma degli elementi di un vettore. #include void main(void) { int numeri[5] = {16, 54, 7, 43, -5}; int i, somma = 0, *punt_num; punt_num = numeri; /*memorizza l’indirizzo di numeri[0] in punt_num*/ for (i = 0; i <= 4; ++i) somma = somma + *punt_num++; printf(“La somma degli elementi del vettore è %d",somma); }

I puntatori possono anche essere confrontati, il che risulta utile quando si usano puntatori che puntano a elementi del medesimo vettore. Ad es., per accedere ai vari elementi del vettore, anziché usare un contatore in un ciclo for si può confrontare l’indirizzo in un puntatore con gli indirizzi iniziale e finale del vettore stesso. L’espressione punt_num <= &numeri[4] è vera (diversa da zero) finché l’indrizzo in punt_num è minore o uguale all’indirizzo di numeri[4]. Dato che numeri è una costante puntatore che contiene l’indirizzo di numeri[0], il termine &numeri[4] può essere sostituito dal termine equivalente numeri + 4. Usando una di queste due forme, il programma precedente si può riscrivere come il seguente, che continua ad aggiungere gli elementi del vettore finché l’indirizzo in punt_num è minore o uguale all’indrizzo dell’ultimo elemento del vettore.

#include void main(void) { int numeri[5] = {16, 54, 7, 43, -5}; int totale = 0, *punt_num; punt_num = numeri; /* memorizza l'indirizzo di numeri[0] in punt_num */ while (punt_num <= numeri + 4) somma += *punt_num++; printf(“La somma degli elementi del vettore è: %d",somma); }