C++

Come usare i puntatori C++

Come usare i puntatori C++
La memoria di un computer è una lunga serie di celle. La dimensione di ogni cella è chiamata byte. Un byte è uno spazio occupato da un carattere inglese dell'alfabeto. Un oggetto nel senso ordinario è un insieme consecutivo di byte in memoria. Ogni cella ha un indirizzo, che è un numero intero, solitamente scritto in forma esadecimale. Ci sono tre modi per accedere a un oggetto in memoria. È possibile accedere a un oggetto utilizzando il cosiddetto puntatore as. È possibile accedervi utilizzando ciò che è noto come riferimento. È ancora possibile accedervi utilizzando un identificatore. Il focus di questo articolo è sull'uso di puntatori e riferimenti. In C++, c'è l'oggetto puntato e l'oggetto puntatore. L'oggetto appuntito ha l'oggetto di interesse. L'oggetto puntatore ha l'indirizzo dell'oggetto puntato.

Devi avere una conoscenza di base del C++, inclusi i suoi identificatori, funzioni e array; per capire questo articolo.

L'oggetto puntatore e l'oggetto puntato, ognuno ha il suo identificatore.

L'indirizzo dell'operatore, &

Questo è un operatore unario. Se seguito da un identificatore, restituisce l'indirizzo dell'oggetto dell'identificatore. Considera la seguente dichiarazione:

int ptdInt;

Di seguito il codice, la seguente espressione, restituirà l'indirizzo identificato da ptdInt:

&ptdInt

Non è necessario conoscere l'indirizzo esatto (numero) durante il codice.

L'operatore indiretto, *

Questo è un operatore unario nel contesto dei puntatori. Di solito viene digitato davanti a un identificatore. Se usato in una dichiarazione dell'identificatore, allora l'identificatore è l'oggetto puntatore che contiene solo l'indirizzo dell'oggetto puntato. Se usato davanti all'identificatore dell'oggetto puntatore, per restituire qualcosa, allora la cosa restituita è il valore dell'oggetto puntato.

Creazione di un puntatore

Dai un'occhiata al seguente segmento di codice:

float ptdFloat;
float *ptrFloat;
ptrFoat = &ptdFloat;

Il segmento inizia con la dichiarazione dell'oggetto puntato, ptdFloat. ptdFloat è un identificatore, che identifica solo un oggetto float. Avrebbe potuto essere assegnato un oggetto (valore) reale, ma in questo caso non gli è stato assegnato nulla. Successivamente nel segmento, c'è la dichiarazione dell'oggetto puntatore. L'operatore di rinvio davanti a questo identificatore significa che deve contenere l'indirizzo di un oggetto appuntito. Il tipo di oggetto, float all'inizio dell'istruzione, significa che l'oggetto puntato è un float. L'oggetto puntatore è sempre dello stesso tipo dell'oggetto puntato. ptrFoat è un identificatore, che identifica solo un oggetto puntatore.

Nell'ultima istruzione del codice, l'indirizzo dell'oggetto puntato è assegnato all'oggetto puntatore. Notare l'uso dell'indirizzo dell'operatore, &.

L'ultima istruzione (riga) sopra mostra che dopo aver dichiarato l'oggetto puntatore senza inizializzazione, non è necessario l'operatore indiretto, quando è necessario inizializzarlo. In effetti, è un errore di sintassi usare l'operatore indiretto nella terza (ultima) riga.

L'oggetto puntatore può essere dichiarato e inizializzato dall'oggetto puntato in un'unica istruzione, come segue:

float ptdFloat;
float *ptrFoat = &ptdFloat;

La prima riga del segmento di codice precedente e questa sono le stesse. La seconda e la terza riga del segmento di codice precedente sono state combinate in un'unica istruzione qui.

Nota nel codice sopra che quando si dichiara e si inizializza l'oggetto puntatore, deve essere usato l'operatore di indiretto. Tuttavia, non viene utilizzato se l'inizializzazione deve essere eseguita in seguito. L'oggetto puntatore viene inizializzato con l'indirizzo dell'oggetto puntato.

Nel seguente segmento di codice, l'operatore indiretto viene utilizzato per restituire il contenuto dell'oggetto puntato.

int ptdInt = 5;
int *ptrInt = &ptdInt;
cout << *ptrInt << '\n';

L'uscita è 5.

Nell'ultima istruzione qui, l'operatore indiretto è stato utilizzato per restituire il valore puntato dall'identificatore del puntatore. Quindi, quando usato in una dichiarazione, l'identificatore per l'operatore indiretto conterrebbe l'indirizzo dell'oggetto puntato. Quando utilizzato in un'espressione di ritorno, in combinazione con l'identificatore del puntatore, l'operatore di riferimento indiretto restituisce il valore dell'oggetto puntato.

Assegnare zero a un puntatore

L'oggetto puntatore dovrebbe sempre avere il tipo dell'oggetto puntato. Quando si dichiara l'oggetto puntatore, deve essere utilizzato il tipo di dati dell'oggetto puntato. Tuttavia, il valore dello zero decimale può essere assegnato al puntatore come nel seguente segmento di codice:

int ptdInt = 5;
int *ptrInt;
ptrInt = 0;
o nel segmento,
int ptdInt = 5;
int *ptrInt = 0;

In entrambi i casi, il puntatore (identificatore) è chiamato puntatore nullo; nel senso, non punta da nessuna parte. Cioè, non ha l'indirizzo di nessun oggetto appuntito. Qui, 0 è zero decimale e non zero esadecimale. Lo zero esadecimale punterebbe al primo indirizzo della memoria del computer.

Non cercare di ottenere il valore puntato da un puntatore nullo. Se ci provi, il programma potrebbe essere compilato, ma potrebbe non essere eseguito.

Nome dell'array come puntatore costante

Considera il seguente array:

int arr[] = 000, 100, 200, 300, 400;

Il nome dell'array, arr è in realtà l'identificatore che ha l'indirizzo del primo elemento dell'array. La seguente espressione restituisce il primo valore nell'array:

*arr

Con l'array, l'operatore di incremento, ++ si comporta in modo diverso. Invece di aggiungere 1, sostituisce l'indirizzo del puntatore, con l'indirizzo dell'elemento successivo nell'array. Tuttavia, il nome dell'array è un puntatore costante; il che significa che il suo contenuto (indirizzo) non può essere modificato o incrementato. Quindi, per incrementare, l'indirizzo iniziale dell'array deve essere assegnato a un puntatore non costante come segue:

int *ptr = arr;

Ora, ptr può essere incrementato per puntare all'elemento successivo dell'array. ptr è stato dichiarato qui come oggetto puntatore. Senza * qui, non sarebbe un puntatore; sarebbe un identificatore per contenere un oggetto int e non per contenere un indirizzo di memoria.

Il seguente segmento di codice infine punta al quarto elemento:

++ptr;
++ptr;
++ptr;

Il codice seguente restituisce il quarto valore dell'array:

int arr[] = 000, 100, 200, 300, 400;
int *ptr = arr;
++ptr;
++ptr;
++ptr;
cout << *ptr << '\n';

L'uscita è 300.

Nome della funzione come identificatore

Il nome di una funzione è l'identificatore della funzione. Considera la seguente definizione di funzione:

int fn()

cout << "seen" << '\n';
ritorno 4;

fn è l'identificatore della funzione. L'espressione,

&fn

restituisce l'indirizzo della funzione in memoria. fn è come l'oggetto appuntito. La seguente dichiarazione dichiara un puntatore a una funzione:

int (*funzione)();

L'identificatore per l'oggetto puntato e l'identificatore per l'oggetto puntatore è diverso. func è un puntatore a una funzione. fn è l'identificatore di una funzione. E così, si può fare in modo che func punti a fn come segue:

funzione = &fn;

Il valore (contenuto) di func è l'indirizzo di fn. I due identificatori avrebbero potuto essere collegati con un'istruzione di inizializzazione come segue:

int (*func)() = &fn;

Nota le differenze e le somiglianze nella gestione dei puntatori a funzione e dei puntatori scalari. func è un puntatore a una funzione; è l'oggetto appuntito; è dichiarato diversamente da un puntatore scalare.

La funzione può essere chiamata con,

fn()
o
funzione()

Non può essere chiamato con *func().

Quando la funzione ha parametri, le seconde parentesi hanno i tipi dei parametri e non è necessario avere gli identificatori per i parametri. Il seguente programma lo illustra:

#includere
usando lo spazio dei nomi std;
float fn(float fl, int in)

ritorno fl;

intero principale()

float (*func)(float, int) = &fn;
valore float = func(2.5, 6);
cout << val << '\n';
restituisce 0;

L'uscita è 2.5.

Riferimento C++

Fare riferimento in C++ è solo un modo per produrre un sinonimo (un altro nome) per un identificatore. Usa l'operatore &, ma non nello stesso modo in cui & viene usato per i puntatori. Considera il seguente segmento di codice:

int mioInt = 8;
int &yourInt = mioInt;
cout << myInt << '\n';
cout << yourInt << '\n';

L'uscita è:

8
8

La prima istruzione inizializza l'identificatore, myInt; io.e. myInt è dichiarato e fatto mantenere il valore, 8. La seconda istruzione crea un nuovo identificatore, yourInt un sinonimo di myInt. Per ottenere ciò, l'operatore & viene inserito tra il tipo di dati e il nuovo identificatore nella dichiarazione. Le istruzioni cout mostrano che i due identificatori sono sinonimi. Per restituire il valore in questo caso, non è necessario precederlo con * . Basta usare l'identificatore.

myInt e yourInt qui, non sono due oggetti diversi. Sono due identificatori diversi che fanno riferimento (identificano) la stessa posizione in memoria avente il valore 8. Se il valore di myInt viene modificato, anche il valore di yourInt cambierà automaticamente. Se il valore di yourInt viene modificato, anche il valore di myInt cambierà automaticamente.

Le referenze sono dello stesso tipo.

Riferimento a una funzione

Proprio come puoi avere un riferimento a uno scalare, puoi anche avere un riferimento a una funzione. Tuttavia, codificare un riferimento a una funzione è diverso dalla codificare un riferimento a uno scalare. Il seguente programma lo illustra:

#includere
usando lo spazio dei nomi std;
float fn(float fl, int in)

ritorno fl;

intero principale()

float (&func)(float, int) = fn;
valore float = func(2.5, 6);
cout << val << '\n';
restituisce 0;

L'uscita è 2.5.

Nota la prima istruzione nella funzione principale, che rende func un sinonimo di fn. Entrambi fanno riferimento alla stessa funzione. Notare l'uso singolo e la posizione di &. Quindi & è l'operatore di riferimento qui e non l'operatore dell'indirizzo. Per chiamare la funzione, usa uno dei due nomi.

Un identificatore di riferimento non è lo stesso di un identificatore di puntatore.

Funzione che restituisce un puntatore

Nel seguente programma, la funzione restituisce un puntatore, che è l'indirizzo dell'oggetto puntato:

#includere
usando lo spazio dei nomi std;
float *fn(float fl, int in)

float *fll = &fl;
ritorno pieno;

intero principale()

float *val = fn(2.5, 6);
cout << *val << '\n';
restituisce 0;

L'uscita è 2.5

La prima istruzione nella funzione, fn() è lì solo per creare un oggetto puntatore. Nota l'uso singolo e la posizione di * nella firma della funzione. Nota anche come il puntatore (indirizzo), è stato ricevuto nella funzione main() da un altro oggetto puntatore.

Funzione che restituisce un riferimento

Nel seguente programma, la funzione restituisce un riferimento:

#includere
usando lo spazio dei nomi std;
float &fn(float fl, int in)

float &frr = fl;
ritorno frr;

intero principale()

float &val = fn(2.5, 6);
cout << val << '\n';
restituisce 0;

L'uscita è 2.5.

La prima istruzione nella funzione, fn() è lì solo per creare un riferimento. Nota l'uso singolo e la posizione di & nella firma della funzione. Nota anche come il riferimento è stato ricevuto nella funzione main() da un altro riferimento.

Passaggio di un puntatore a una funzione

Nel seguente programma, un puntatore, che è in realtà l'indirizzo di un oggetto a puntamento float, viene inviato come argomento alla funzione:

#includere
usando lo spazio dei nomi std;
float fn(float *fl, int in)

ritorno *fl;

intero principale()

flottante v = 2.5;
valore float = fn(&v, 6);
cout << val << '\n';
restituisce 0;

L'uscita è 2.5

Nota l'uso e la posizione di * per il parametro float nella firma della funzione. Non appena inizia la valutazione della funzione fn(), viene fatta la seguente dichiarazione:

float *fl = &v;

Sia fl che &v puntano allo stesso oggetto appuntito che contiene 2.5. *fl nell'istruzione return non è una dichiarazione; significa, il valore dell'oggetto puntato a cui punta l'oggetto puntatore.

Passaggio di un riferimento a una funzione

Nel seguente programma viene inviato un riferimento come argomento alla funzione:

#includere
usando lo spazio dei nomi std;
float fn(float &fl, int in)

ritorno fl;

intero principale()

flottante v = 2.5;
valore float = fn(v, 6);
cout << val << '\n';
restituisce 0;

L'uscita è 2.5

Nota l'uso e la posizione di & per il parametro float nella firma della funzione. Non appena inizia la valutazione della funzione fn(), viene fatta la seguente dichiarazione:

float &fl = v;

Passare un array a una funzione

Il seguente programma mostra come passare un array a una funzione:

#includere
usando lo spazio dei nomi std;
int fn(int arra[])

restituire arra[2];

intero principale()

int arr[] = 000, 100, 200, 300, 400;
int val = fn(arr);
cout << val << '\n';
restituisce 0;

L'uscita è 200.

In questo programma, è l'array che viene passato. Nota che il parametro della firma della funzione ha una dichiarazione di array vuota. L'argomento nella chiamata alla funzione è solo il nome di un array creato.

Una funzione C++ può restituire un array??

Una funzione in C++ può restituire il valore di un array, ma non può restituire l'array. La compilazione del seguente programma genera un messaggio di errore:

#includere
usando lo spazio dei nomi std;
int fn(int arra[])

ritorno arra;

intero principale()

int arr[] = 000, 100, 200, 300, 400;
int val = fn(arr);
restituisce 0;

Puntatore di un puntatore

Un puntatore può puntare a un altro puntatore. Cioè, un oggetto puntatore può avere l'indirizzo di un altro oggetto puntatore. Devono comunque essere tutti dello stesso tipo. Il seguente segmento di codice illustra questo:

int ptdInt = 5;
int *ptrInt = &ptdInt;
int **ptrptrInt = &ptrInt;
cout << **ptrptrInt << '\n';

L'uscita è 5.

Nella dichiarazione di puntatore a puntatore, viene utilizzato double * double. Per restituire il valore dell'oggetto puntato finale, viene ancora utilizzato il doppio *.

Matrice di puntatori

Il seguente programma mostra come codificare un array di puntatori:

#includere
usando lo spazio dei nomi std;
intero principale()

int num0=000, num1=100, num2=200, num3=300, num4=400;
int *no0=&num0, *no1=&num1, *no2=&num2, *no3=&num3, *no4=&num4;
int *arr[] = no0, no1, no2, no3, no4;
cout << *arr[4] << '\n';
restituisce 0;

L'uscita è:

400

Nota l'uso e la posizione di * nella dichiarazione dell'array. Nota l'uso di * quando si restituisce un valore nell'array. Con puntatori di puntatori, sono coinvolti due *. Nel caso di array di puntatori, un * è già stato preso in considerazione, perché l'identificatore dell'array è un puntatore.

Array di stringhe a lunghezza variabile

Un letterale stringa è una costante che restituisce un puntatore. Un array di stringhe di lunghezza variabile è un array di puntatori. Ogni valore nell'array è un puntatore. I puntatori sono indirizzi a posizioni di memoria e sono della stessa dimensione. Le stringhe di diversa lunghezza sono altrove in memoria, non nell'array. Il seguente programma ne illustra l'utilizzo:

#includere
usando lo spazio dei nomi std;
intero principale()

const char *arr[] = "donna", "ragazzo", "ragazza", "adulto";
cout << arr[2] << '\n';
restituisce 0;

L'output è "ragazza".

La dichiarazione dell'array inizia con la parola riservata, “const” per costante; seguito da "char" per il carattere, quindi l'asterisco, * per indicare che ogni elemento è un puntatore. Per restituire una stringa dall'array, non viene utilizzato *, a causa della natura implicita del puntatore di ogni stringa. Se viene utilizzato *, verrà restituito il primo elemento della stringa.

Puntatore a una funzione che restituisce un puntatore

Il seguente programma illustra come viene codificato un puntatore a una funzione che restituisce un puntatore:

#includere
usando lo spazio dei nomi std;
int *fn()

numero int = 4;
int *inter = #
ritorno tra;

intero principale()

int *(*func)() = &fn;
int val = *func();
cout << val << '\n';
restituisce 0;

L'uscita è 4.

La dichiarazione di un puntatore a una funzione che restituisce un puntatore è simile alla dichiarazione di un puntatore a una funzione ordinaria ma preceduta da un asterisco. La prima istruzione nella funzione main() lo illustra. Per chiamare la funzione utilizzando il puntatore, precederlo con *.

Conclusione

Per creare un puntatore a uno scalare, fai qualcosa del tipo,

galleggiante appuntito;
float *puntatore = &pointed;

* ha due significati: in una dichiarazione indica un puntatore; per restituire qualcosa, è per il valore dell'oggetto puntato.

Il nome dell'array è un puntatore costante al primo elemento dell'array.

Per creare un puntatore a una funzione, puoi fare,

int (*func)() = &fn;

dove fn() è una funzione definita altrove e func è il puntatore.

& ha due significati: in una dichiarazione, indica un riferimento (sinonimo) allo stesso oggetto come un altro identificatore; quando si restituisce qualcosa, significa l'indirizzo-di.

Per creare un riferimento a una funzione, puoi fare,

float (&refFunc)(float, int) = fn;

dove fn() è una funzione definita altrove e refFunc è il riferimento.

Quando una funzione restituisce un puntatore, il valore restituito deve essere ricevuto da un puntatore. Quando una funzione restituisce un riferimento, il valore restituito deve essere ricevuto da un riferimento.

Quando si passa un puntatore a una funzione, il parametro è una dichiarazione, mentre l'argomento è l'indirizzo di un oggetto puntato. Quando si passa un riferimento a una funzione, il parametro è una dichiarazione, mentre l'argomento è il riferimento.

Quando si passa un array a una funzione, il parametro è una dichiarazione mentre l'argomento è il nome dell'array senza []. La funzione C++ non restituisce un array.

Un puntatore a puntatore ha bisogno di due * invece di uno, dove appropriato.

cris

Come modificare le impostazioni del mouse e del touchpad utilizzando Xinput in Linux
La maggior parte delle distribuzioni Linux viene fornita con la libreria "libinput" per impostazione predefinita per gestire gli eventi di input su un...
Rimappa i pulsanti del mouse in modo diverso per software diversi con X-Mouse Button Control
Forse hai bisogno di uno strumento che possa cambiare il controllo del tuo mouse con ogni applicazione che utilizzi. In questo caso, puoi provare un'a...
Recensione del mouse wireless Microsoft Sculpt Touch
Ho letto di recente del Microsoft Scolpisci il tocco mouse wireless e ho deciso di acquistarlo. Dopo averlo usato per un po', ho deciso di condividere...