Linguaggio C: Puntatori e Dichiarazioni complesse

Clara

Puntatori: definizione

Il puntatore è una variabile il cui contenuto è l’indirizzo di un oggetto (variabile, funzione); l’operatore & permette di ottenere l’indirizzo di un oggetto, mentre l’operatore unario * di indirezione permette a un puntatore di accedere al valore contenuto nella locazione di memoria, il cui indirizzo si trova nel puntatore stesso (locazione di memoria “puntata” dal puntatore).

Definizione, in C, di variabili puntatore:

                                         tipo  *identificatore;

Esempi:

  • int a,*p;    // dichiarazione di una variabile di tipo intero (a) e di un puntatore ad interi (p) (         può contenere indirizzi di variabili intere).

  • char *q;    // q è dichiarata come puntatore a caratteri (può contenere indirizzi di variabili di tipo carattere).

  • float *n;    // n è dichiarata come puntatore a float (può contenere indirizzi di // variabili di tipo float).

  • # include <stdio.h>

     main()

       { int a,b, *x,*y;  // a e b variabili intere; x e y puntatori ad interi.

          scanf (“%d”,&a);    // &a: indirizzo della variabile a.

          scanf (“%d),&b);   // &b: indirizzo della variabile b.

          x = &a;    // x conterrà l’indirizzo della variabile a.

          y = &b;   // y conterrà l’indirizzo della variabile b.

          printf (“%d”,*x);   // è equivalente a printf (“%d”,a): la variabile puntatore x

                                    // contiene l’indirizzo della variabile a, quindi *x indica il contenuto. 

                                   // della locazione di memoria il cui indirizzo si trova in x.

         printf (“%d”,*y);    // è equivalente a printf (“%d”,b): vale quanto detto per x.

        }

  • int a,*q;      // a variabile intera; q puntatore ad interi.

        &a = 10;     // è errata perché non si può modificare l’indirizzo di una variabile.

       *q = 10;     // è corretta, perché viene assegnato un valore nella locazione di memoria puntata da q, ma i risultati sono imprevedibili perché la ella di memoria indirizzata da q potrebbe essere qualsiasi.

  • const int *i;     // puntatore a un valore costante di tipo int; il  puntatore può essere  modificato perché punti a un altro valore, ma il valore a cui punta, adesso, non può essere modificato.

  • int *const i;    // puntatore costante a un valore di tipo int; il valore puntato può essere modificato il puntatore no.

Array e puntatori

C’è una stretta relazione tra array e puntatori; infatti in C il nome dell’array coincide con l’indirizzo del primo elemento dell’array stesso cioè, fatte le dichiarazioni:

     int vett[10],*p;

si ha 

    vett ≡ &vett[0]

pertanto è lecito scrivere:

    p = vett;         // è equivalente a  p = &vett[0];

e si ha che:

    *p ≡ vett[0]

   *(p+i) ≡ vett[i]

    p[i] ≡ *(vett+i)

da notare che *(p+i) è diverso da *p+i  (in questo caso viene sommato i al contenuto della cella puntata da p, infatti l’operatore di indirezione ha precedenza più alta dell’addizione).

Nella manipolazione di puntatori e nomi di array bisogna tener presente che mentre i puntatori sono delle variabili i nomi di array sono delle costanti, perciò, se p è un puntatore e vett il nome di un array, mentre è lecito scrivere:

    p = vett;  o p++;

è errato scrivere:

   vett = p; o vett++;

perché si sta cercando di modificare l’indirizzo di una variabile.

L’uso dei puntatori permette di scrivere programmi molto concisi, qualche volta però a scapito della comprensione; il seguente segmento di programma permette, ad esempio, di inizializzare a 0 gli elementi di un array:

.................

int dati[10],*p;

for (p = dati; p < &dati[10]; *p++ = 0);

.................

(p=dati): p punta inizialmente al primo elemento dell’ array;

(p < &dati[10]): il ciclo ha termine quando p = &dati[10];

(*p++ = 0): a ogni passaggio, nell’elemento puntato da p (*p) viene messo  il valore 0, quindi p viene incrementato (incremento postfisso), per puntare all’elemento successivo.

Le funzioni per la manipolazione di stringhe (array di char) fanno largo uso dei puntatori; le più utilizzate di queste funzioni sono:

  • strcpy(stringa1, stringa2):  copia stringa2 in stringa1.

  • strcmp(stringa1,stringa2):  confronta stringa1 con stringa2; restituisce 0 se  stringa1 = stringa2; un valore  < 0 se stringa1 < stringa2; un valore > 0 se stringa1 > stringa2.

  • strcat(stringa1,stringa2):  concatena stringa2 a stringa1.

  • strlen(stringa): restituisce il numero di caratteri di stringa (‘\0’ è escluso dal conteggio).

  • atoi(stringa), atol(stringa), atof(stringa): convertono una stringa rispettivamente in un int, un long, un double.

È  possibile anche definire un puntatore ad una struttura (struct o union), esempio:

typedef  struct 

{  char nome[20];

    int eta;

} DATI;

DATI a, *p;   // a è una variabile del tipo DATI e p un puntatore a una variabile di tipo DATI

per accedere ad un campo di una struttura attraverso un suo puntatore, piuttosto che attraverso il nome di una variabile, basta sostituire all’ operatore . l’operatore ->, cosicché

            a.nome  ≡ p->nome

Un uso più complesso dei puntatori si ha nei seguenti casi:

  1. int (*p)[10];  // p è un puntatore ad un array di 10 interi

  2. int *p[10];   // p è un array di 10 puntatori ad interi

  3. char **p;   // p è un puntatore ad un puntatore a char

  4. int (*p) (int);  // p è un puntatore ad una funzione che restituisce un intero e che ha // come parametro di input un intero

Lezioni di programmazione online e a casa
Alfredo (15)10100
Nicolò 1ª lezione gratis (5)10100

Dichiarazioni complesse

Si può “modificare”  un identificatore  con questi modificatori 

* puntatore (a sinistra dell'identificatore)

( ) funzione (a destra dell'identificatore)

[ ] array (a destra dell'identificatore)  

Le ( ) [ ]  hanno la stessa precedenza con associazione da sinistra a destra e hanno la precedenza su *

Interpretazione dei dichiaratori complessi

1) si parte dall' identificatore

2) guardare se a destra ci sono ( ) o [ ] e quindi a sinistra *

3) se a destra c'è una ")"  tornare indietro e applicare 1) e 2)   a ogni cosa entro parentesi

4) applicare lo specificatore di tipo

Esempio 1:

           3bis

char *(*(*Var) ()  )[10];

    5     2   1   3         4

1 – Var:  identificatore; è seguito da una “)”, guardare se a destra e a sinistra sono presenti ( ) [ ] o *

2 – *: è   un puntatore  (*Var)

3 – (): a  una funzione (3) che restituisce un puntatore (3bis)  (  *  (*Var) () )

4 – [10] : a un array di 10 elementi,  che sono 

5 – char *: puntatori a char.

Nota al punto 3: la coppia () (funzione senza  parametri) ha precedenza rispetto all' *

Esempio 2:

int *var[5];  //array di 5 puntatori a int; [ ] ha la precedenza su * che è applicato al tipo degli elementi dell’array.

Esempio 3:

int (*var)[5];  //puntatore ad un array di 5  interi; la precedenza è cambiata dalle parentesi.

Esempio 4:

long *var (long, long);  //funzione che ha  2 param di tipo long e restituisce un puntatore a long; ( ) ha la precedenza su * che è applicato al valore restituito dalla funzione.

Esempio 5:

long (*var) (long, long); //puntatore a funzione che ha  2 param di tipo long e restituisce un long; la precedenza è cambiata dalle parentesi.

Esempio 6:

struct Rec 

int a;

char b;

} (*Var[5])( struct Rec, struct Rec);

Var è un array di 5 puntatori  a funzioni che restituiscono una struttura Rec e con 2 parametri di tipo Rec.

Per interpretare una dichiarazione complessa si può usare il metodo "clockwise spiral rule". 

Ci sono 3 semplici regole da seguire:

  1. Partendo dall’identificatore, muoversi secondo una spirale in senso orario; quando si incontra uno dei seguenti simboli sostituirlo con la corrispondente dichiarazione:

    1. [X ] o []    Array X di dimensioni …   oppure  Array  di dimensioni …

    2. (type1, type2, …) funzione con parametri in ingresso type1, type2, … che restituisce ….  

    3. * puntatore/i  a …

  2. Continuare, muovendosi sempre secondo una spirale in senso orario, fino a quando non sono stati esaminati tutti gli elementi.

  3. Esaminare, prima, tutti gli elementi racchiusi nelle parentesi  tonde (...)

Ti è piaciuto? Condividilo
Clara
Clara
(2)
Lezioni private - Programmazione, SQL e Informatica
Usa il nostro Strumento di Ricerca Intelligente
© 2007 - 2024 Letuelezioni.it è un membro della famiglia GoStudent Mappa del sito: Insegnanti privati