Perché usare i puntatori? [chiuso]


356

So che questa è una domanda davvero basilare, ma ho appena iniziato con una programmazione C ++ di base dopo aver codificato alcuni progetti con linguaggi di alto livello.

Fondamentalmente ho tre domande:

  1. Perché usare i puntatori sulle variabili normali?
  2. Quando e dove dovrei usare i puntatori?
  3. Come si usano i puntatori con le matrici?

5
Discusso prima a questa domanda Spero che ti aiuti!
Doug T.

4
Per un elenco di libri, consultare stackoverflow.com/questions/388242/… . Dopo Java, ho trovato molto utile il C ++ accelerato .
Jabba,

163
Usiamo i puntatori perché è più facile dare a qualcuno un indirizzo a casa tua che dare una copia della tua casa a tutti.
Rishi Dua,

14
@RishiDua Questa è la migliore spiegazione singola di un puntatore che abbia mai incontrato. Grazie per questo, ha aumentato la mia comprensione :)
Josh

2
I puntatori possono essere utilizzati anche quando si desidera restituire più di un valore / oggetto.
Gaurav,

Risposte:


172
  • Perché usare i puntatori sulle variabili normali?

La risposta breve è: No. ;-) I puntatori devono essere usati dove non puoi usare nient'altro. O è perché la mancanza di funzionalità appropriata, tipi di dati mancanti o per pura prestazione. Più sotto ...

  • Quando e dove dovrei usare i puntatori?

La risposta breve qui è: dove non puoi usare nient'altro. In C non hai alcun supporto per tipi di dati complessi come una stringa. Non è inoltre possibile passare una variabile "per riferimento" a una funzione. Ecco dove devi usare i puntatori. Inoltre puoi farli puntare praticamente su qualsiasi cosa, liste collegate, membri di strutture e così via. Ma non entriamo qui.

  • Come si usano i puntatori con le matrici?

Con poco sforzo e molta confusione. ;-) Se parliamo di tipi di dati semplici come int e char, c'è poca differenza tra un array e un puntatore. Queste dichiarazioni sono molto simili (ma non uguali - ad esempio, sizeofrestituiranno valori diversi):

char* a = "Hello";
char a[] = "Hello";

È possibile raggiungere qualsiasi elemento dell'array in questo modo

printf("Second char is: %c", a[1]);

Indice 1 poiché l'array inizia con l'elemento 0. :-)

Oppure potresti fare altrettanto

printf("Second char is: %c", *(a+1));

L'operatore puntatore (il *) è necessario poiché diciamo a printf che vogliamo stampare un carattere. Senza *, viene stampata la rappresentazione dei caratteri dell'indirizzo di memoria stesso. Ora invece stiamo usando il personaggio stesso. Se avessimo usato% s anziché% c, avremmo chiesto a printf di stampare il contenuto dell'indirizzo di memoria indicato da 'a' più uno (in questo esempio sopra), e non avremmo dovuto mettere il * di fronte:

printf("Second char is: %s", (a+1)); /* WRONG */

Ma questo non avrebbe appena stampato il secondo carattere, ma invece tutti i caratteri nei successivi indirizzi di memoria, fino a quando non è stato trovato un carattere nullo (\ 0). Ed è qui che le cose iniziano a diventare pericolose. Cosa succede se si tenta di stampare accidentalmente una variabile del tipo intero anziché un puntatore a caratteri con il formattatore% s?

char* a = "Hello";
int b = 120;
printf("Second char is: %s", b);

Ciò stamperebbe tutto ciò che si trova sull'indirizzo di memoria 120 e continuerebbe a stampare fino a quando non viene trovato un carattere null. Eseguire questa istruzione printf è errato e illegale, ma probabilmente funzionerebbe comunque, dato che in molti ambienti un puntatore è del tipo int. Immagina i problemi che potresti causare se dovessi usare sprintf () invece e assegnare in questo modo "array di caratteri" troppo lungo a un'altra variabile, che ha assegnato solo un certo spazio limitato allocato. Molto probabilmente finiresti per scrivere su qualcos'altro nella memoria e causerai l'arresto anomalo del tuo programma (se sei fortunato).

Oh, e se non lo assegni un valore stringa al char array / pointer quando lo dichiari, DEVI allocare una quantità sufficiente di memoria prima di assegnargli un valore. Usando malloc, calloc o simili. Questo poiché hai dichiarato un solo elemento nel tuo array / un singolo indirizzo di memoria a cui puntare. Quindi, ecco alcuni esempi:

char* x;
/* Allocate 6 bytes of memory for me and point x to the first of them. */
x = (char*) malloc(6);
x[0] = 'H';
x[1] = 'e';
x[2] = 'l';
x[3] = 'l';
x[4] = 'o';
x[5] = '\0';
printf("String \"%s\" at address: %d\n", x, x);
/* Delete the allocation (reservation) of the memory. */
/* The char pointer x is still pointing to this address in memory though! */
free(x);
/* Same as malloc but here the allocated space is filled with null characters!*/
x = (char *) calloc(6, sizeof(x));
x[0] = 'H';
x[1] = 'e';
x[2] = 'l';
x[3] = 'l';
x[4] = 'o';
x[5] = '\0';
printf("String \"%s\" at address: %d\n", x, x);
/* And delete the allocation again... */
free(x);
/* We can set the size at declaration time as well */
char xx[6];
xx[0] = 'H';
xx[1] = 'e';
xx[2] = 'l';
xx[3] = 'l';
xx[4] = 'o';
xx[5] = '\0';
printf("String \"%s\" at address: %d\n", xx, xx);

Si noti che è ancora possibile utilizzare la variabile x dopo aver eseguito un libero () della memoria allocata, ma non si sa cosa c'è dentro. Si noti inoltre che i due printf () potrebbero fornire indirizzi diversi, poiché non esiste alcuna garanzia che la seconda allocazione della memoria venga eseguita nello stesso spazio del primo.


8
Il tuo esempio con 120 in esso è sbagliato. Sta usando% c non% s quindi non ci sono bug; stampa semplicemente la lettera minuscola x. Inoltre, la tua successiva affermazione che un puntatore è di tipo int è sbagliata e un pessimo consiglio da dare a un programmatore C inesperto con puntatori.
R .. GitHub smette di aiutare ICE il

13
-1 Hai iniziato bene ma il primo esempio è sbagliato. No, non è lo stesso. Nel primo caso aè un puntatore e nel secondo caso aè un array. Ne ho già parlato? Non è lo stesso! Verifica tu stesso: confronta sizeof (a), prova ad assegnare un nuovo indirizzo a un array. Non funzionerà
sellibitze,

42
char* a = "Hello";e char a[] = "Hello";non sono uguali, sono piuttosto diversi. Uno dichiara un puntatore l'altro un array. Prova a sizeofe vedi la differenza.
Patrick Schlüter,

12
"Non è sbagliato o illegale eseguire questa dichiarazione printf". Questo è chiaramente sbagliato. Quell'istruzione printf ha un comportamento indefinito. In molte implementazioni causerà una violazione di accesso. I puntatori non sono in realtà di tipo int, sono in realtà puntatori (e nient'altro).
Mankarse,

19
-1, hai sbagliato così tanti fatti qui e dirò semplicemente che non meriti la quantità di voti o lo stato di risposta accettato.
asveikau,

50

Un motivo per utilizzare i puntatori è che una variabile o un oggetto possono essere modificati in una chiamata funzione.

In C ++ è meglio usare riferimenti che puntatori. Sebbene i riferimenti siano essenzialmente dei puntatori, C ++ nasconde in qualche modo il fatto e fa sembrare che si stia passando per valore. Ciò semplifica la modifica del modo in cui la funzione chiamante riceve il valore senza dover modificare la semantica del passaggio.

Considera i seguenti esempi:

Utilizzando riferimenti:

public void doSomething()
{
    int i = 10;
    doSomethingElse(i);  // passes i by references since doSomethingElse() receives it
                         // by reference, but the syntax makes it appear as if i is passed
                         // by value
}

public void doSomethingElse(int& i)  // receives i as a reference
{
    cout << i << endl;
}

Utilizzando i puntatori:

public void doSomething()
{
    int i = 10;
    doSomethingElse(&i);
}

public void doSomethingElse(int* i)
{
    cout << *i << endl;
}

16
Probabilmente è una buona idea menzionare che i riferimenti sono più sicuri, in quanto non è possibile passare un riferimento null.
SpoonMeiser,

26
Sì, questo è probabilmente il più grande vantaggio dell'utilizzo dei riferimenti. Grazie per segnalarlo. Nessun gioco di
parole

2
È sicuramente possibile passare riferimento null. Non è facile come passare il puntatore null.
n.

1
concordo con @ n0rd. Se pensi di non poter passare un riferimento null, ti sbagli. È più facile passare un riferimento pendente che un riferimento null, ma alla fine è possibile fare entrambi abbastanza facilmente. I riferimenti non sono proiettili d'argento che proteggono un ingegnere dallo spararsi al piede. Guardalo dal vivo .
WhozCraig,

2
@ n0rd: fare ciò è un comportamento esplicitamente indefinito.
Daniel Kamil Kozar,

42
  1. I puntatori consentono di fare riferimento allo stesso spazio in memoria da più posizioni. Ciò significa che è possibile aggiornare la memoria in una posizione e la modifica può essere vista da un'altra posizione nel programma. Risparmierai anche spazio potendo condividere componenti nelle tue strutture dati.
  2. È necessario utilizzare i puntatori in qualsiasi punto in cui è necessario ottenere e passare l'indirizzo in un punto specifico della memoria. È inoltre possibile utilizzare i puntatori per navigare negli array:
  3. Un array è un blocco di memoria contigua che è stato allocato con un tipo specifico. Il nome dell'array contiene il valore del punto iniziale dell'array. Quando aggiungi 1, questo ti porta al secondo posto. Ciò consente di scrivere loop che incrementano un puntatore che scorre verso il basso l'array senza disporre di un contatore esplicito da utilizzare per accedere all'array.

Ecco un esempio in C:

char hello[] = "hello";

char *p = hello;

while (*p)
{
    *p += 1; // increase the character by one

    p += 1; // move to the next spot
}

printf(hello);

stampe

ifmmp

perché prende il valore per ogni carattere e lo incrementa di uno.


because it takes the value for each character and increments it by one. È nella rappresentazione ASCII o come?
Eduardo S.

28

I puntatori sono un modo per ottenere un riferimento indiretto a un'altra variabile. Invece di contenere il valore di una variabile, ti dicono il suo indirizzo . Ciò è particolarmente utile quando si ha a che fare con le matrici, poiché utilizzando un puntatore al primo elemento di una matrice (il suo indirizzo) è possibile trovare rapidamente l'elemento successivo incrementando il puntatore (nella posizione dell'indirizzo successivo).

La migliore spiegazione di puntatori e aritmetica dei puntatori che ho letto è in The C Programming Language di K&R . Un buon libro per iniziare a imparare il C ++ è C ++ Primer .


1
grazie! infine, una spiegazione pratica dei vantaggi dell'utilizzo dello stack! un puntatore da posizionare in un array migliora anche le prestazioni accedendo ai valori @ e rispetto al puntatore?

Questa è probabilmente la migliore spiegazione che ho letto. la gente ha un modo di "complicare troppo" le cose :)
Detilium

23

Vorrei provare a rispondere anche a questo.

I puntatori sono simili ai riferimenti. In altre parole, non sono copie, ma piuttosto un modo per fare riferimento al valore originale.

Prima di ogni altra cosa, un posto in cui dovrete usare molto i puntatori è quando avete a che fare con hardware incorporato . Forse è necessario attivare / disattivare lo stato di un pin IO digitale. Forse stai elaborando un interrupt e devi archiviare un valore in una posizione specifica. Ottieni l'immagine. Tuttavia, se non hai a che fare direttamente con l'hardware e ti stai solo chiedendo quali tipi utilizzare, continua a leggere.

Perché usare i puntatori invece delle normali variabili? La risposta diventa più chiara quando hai a che fare con tipi complessi, come classi, strutture e array. Se dovessi usare una variabile normale, potresti finire per fare una copia (i compilatori sono abbastanza intelligenti da impedirlo in alcune situazioni e anche C ++ 11 aiuta, ma per ora staremo lontani da quella discussione).

Ora cosa succede se si desidera modificare il valore originale? Puoi usare qualcosa del genere:

MyType a; //let's ignore what MyType actually is right now.
a = modify(a); 

Funzionerà bene e se non sai esattamente perché stai usando i puntatori, non dovresti usarli. Fai attenzione al motivo "sono probabilmente più veloci". Esegui i tuoi test e se sono effettivamente più veloci, quindi utilizzali.

Tuttavia, supponiamo che tu stia risolvendo un problema in cui è necessario allocare memoria. Quando si alloca memoria, è necessario deallocare. L'allocazione della memoria potrebbe non riuscire. È qui che i puntatori diventano utili: ti consentono di verificare l'esistenza dell'oggetto che hai assegnato e ti consentono di accedere all'oggetto per cui è stata allocata la memoria de-referenziando il puntatore.

MyType *p = NULL; //empty pointer
if(p)
{
    //we never reach here, because the pointer points to nothing
}
//now, let's allocate some memory
p = new MyType[50000];
if(p) //if the memory was allocated, this test will pass
{
    //we can do something with our allocated array
    for(size_t i=0; i!=50000; i++)
    {
        MyType &v = *(p+i); //get a reference to the ith object
        //do something with it
        //...
    }
    delete[] p; //we're done. de-allocate the memory
}

Questa è la chiave per cui dovresti usare i puntatori - i riferimenti presuppongono che l'elemento a cui stai facendo riferimento esista già . Un puntatore no.

L'altro motivo per cui dovresti usare i puntatori (o almeno finirai per gestirli) è perché sono un tipo di dati che esisteva prima dei riferimenti. Pertanto, se finisci per usare le librerie per fare le cose che sai che sono migliori, scoprirai che molte di queste librerie usano puntatori ovunque, semplicemente per quanto tempo sono in giro (molto di questi sono stati scritti prima del C ++).

Se non hai utilizzato alcuna libreria, puoi progettare il tuo codice in modo tale da evitare i puntatori, ma dato che i puntatori sono uno dei tipi di base della lingua, più velocemente ti senti a tuo agio nell'usarli, più portatile le tue abilità in C ++ sarebbero.

Da un punto di vista della manutenibilità, dovrei anche menzionare che quando si utilizzano i puntatori, è necessario verificare la loro validità e gestire il caso quando non sono validi, oppure, supporre che siano validi e accettare il fatto che il tuo il programma si arresterà in modo anomalo o peggio QUANDO tale presupposto viene interrotto. Detto in altro modo, la tua scelta con i puntatori è quella di introdurre la complessità del codice o più sforzi di manutenzione quando qualcosa si rompe e stai cercando di rintracciare un bug che appartiene a un'intera classe di errori che i puntatori introducono, come il danneggiamento della memoria.

Quindi, se controlli tutto il tuo codice, stai lontano dai puntatori e invece usa i riferimenti, mantenendoli costanti quando puoi. Questo ti costringerà a pensare ai tempi di vita dei tuoi oggetti e finirà per mantenere il tuo codice più facile da capire.

Basta ricordare questa differenza: un riferimento è essenzialmente un puntatore valido. Un puntatore non è sempre valido.

Quindi sto dicendo che è impossibile creare un riferimento non valido? No. È del tutto possibile, perché C ++ ti consente di fare quasi tutto. È solo più difficile da fare involontariamente e rimarrai stupito da quanti bug non sono intenzionali :)


È possibile scrivere simpatiche classi wrapper per IO mappati in memoria con i quali è essenzialmente possibile evitare l'uso di puntatori.
einpoklum,

13

Ecco una visione leggermente diversa, ma perspicace del perché molte funzioni di C hanno senso: http://steve.yegge.googlepages.com/tour-de-babel#C

Fondamentalmente, l'architettura CPU standard è un'architettura Von Neumann ed è straordinariamente utile essere in grado di fare riferimento alla posizione di un elemento di dati in memoria, e fare aritmetica con esso, su una macchina del genere. Se conosci qualche variante del linguaggio assembly, vedrai rapidamente quanto sia cruciale a basso livello.

Il C ++ rende i puntatori un po 'confusi, poiché a volte li gestisce per te e nasconde il loro effetto sotto forma di "riferimenti". Se usi la C diritta, la necessità di puntatori è molto più ovvia: non c'è altro modo di fare una chiamata per riferimento, è il modo migliore per memorizzare una stringa, è il modo migliore per scorrere attraverso un array, ecc.


12

Un uso di puntatori (non menzionerò cose già trattate nei post di altre persone) è quello di accedere alla memoria che non hai allocato. Questo non è molto utile per la programmazione su PC, ma viene utilizzato nella programmazione integrata per accedere ai dispositivi hardware mappati in memoria.

Ai vecchi tempi di DOS, si era in grado di accedere direttamente alla memoria video della scheda video dichiarando un puntatore a:

unsigned char *pVideoMemory = (unsigned char *)0xA0000000;

Molti dispositivi embedded usano ancora questa tecnica.


Non è un motivo per usare un puntatore - una struttura simile a una campata - che detiene anche la lunghezza - è molto più appropriato. In questi giorni lo è gsl::spane presto lo sarà std::span.
einpoklum,

10

In gran parte, i puntatori sono matrici (in C / C ++): sono indirizzi in memoria e, se lo si desidera, è possibile accedervi come una matrice (in casi "normali").

Poiché sono l'indirizzo di un articolo, sono piccoli: occupano solo lo spazio di un indirizzo. Dato che sono piccoli, inviarli a una funzione è economico. E poi permettono a quella funzione di operare sull'oggetto reale piuttosto che su una copia.

Se si desidera eseguire un'allocazione dinamica dello spazio di archiviazione (ad esempio per un elenco collegato), è necessario utilizzare i puntatori, poiché sono l'unico modo per acquisire memoria dall'heap.


8
Penso che sia fuorviante affermare che i puntatori sono array. In realtà, i nomi di array sono puntatori const al primo elemento dell'array. Solo perché puoi accedere a un punto arbitrario come se fosse un array non significa che lo è ... potresti avere una violazione di accesso :)
rmeador

2
I puntatori non sono array. Leggere il capitolo 6 del comp.lang.c FAQ .
Keith Thompson,

I puntatori non sono in realtà matrici. Inoltre, non c'è molto uso neanche negli array grezzi, certamente non dopo C ++ 11 e std::array.
einpoklum,

@einpoklum - i puntatori sono abbastanza vicini agli array per essere equivalenti nelle operazioni di riferimento e iterare attraverso gli array :) .... inoltre - C ++ 11 era a 3 anni dal rilascio quando questa risposta è stata scritta nel 2008
warren

@warren: i puntatori non sono array né vicini ad array, ma semplicemente si decompongono in array. È pedagogicamente inappropriato dire alle persone che sono simili. Inoltre, puoi certamente avere riferimenti ad array, che non sono dello stesso tipo di puntatori e mantengono le informazioni sulla dimensione; vedi qui
einpoklum,

9

I puntatori sono importanti in molte strutture di dati la cui progettazione richiede la possibilità di collegare o concatenare un "nodo" a un altro in modo efficiente. Non "scegliere" un puntatore sopra per dire un normale tipo di dati come float, hanno semplicemente scopi diversi.

I puntatori sono utili laddove siano richieste prestazioni elevate e / o footprint di memoria compatto.

L'indirizzo del primo elemento nell'array può essere assegnato a un puntatore. Ciò consente quindi di accedere direttamente ai byte allocati sottostanti. L'intero punto di un array è di evitare la necessità di farlo.


9

Un modo per utilizzare i puntatori sulle variabili è eliminare la memoria duplicata richiesta. Ad esempio, se si dispone di un oggetto complesso di grandi dimensioni, è possibile utilizzare un puntatore per puntare a quella variabile per ogni riferimento effettuato. Con una variabile, è necessario duplicare la memoria per ogni copia.


Questo è un motivo per usare riferimenti (o al massimo - wrapper di riferimento), non puntatori.
einpoklum,

6

In C ++, se si desidera utilizzare il polimorfismo dei sottotipi , è necessario utilizzare i puntatori. Vedi questo messaggio: polimorfismo C ++ senza puntatori .

Davvero, quando ci pensi, questo ha senso. Quando usi il polimorfismo dei sottotipi, in ultima analisi, non sai in anticipo quale implementazione del metodo della classe o della sottoclasse verrà invocata perché non sai quale sia la classe effettiva.

L'idea di avere una variabile che contiene un oggetto di una classe sconosciuta non è compatibile con la modalità predefinita (non puntatore) di C ++ di archiviare oggetti nello stack, dove la quantità di spazio allocata corrisponde direttamente alla classe. Nota: se una classe ha 5 campi di istanza rispetto a 3, sarà necessario allocare più spazio.


Nota che se stai usando '&' per passare argomenti per riferimento, dietro le quinte è ancora coinvolto il riferimento indiretto (cioè i puntatori). '&' È solo uno zucchero sintattico che (1) ti risparmia il problema di usare la sintassi del puntatore e (2) consente al compilatore di essere più rigoroso (come proibire i puntatori null).


No, non è necessario utilizzare i puntatori: è possibile utilizzare i riferimenti. E quando scrivi "i puntatori sono coinvolti dietro le quinte" - non ha senso. gotole istruzioni vengono utilizzate anche dietro le quinte - nelle istruzioni della macchina target. Non pretendiamo ancora di usarli.
einpoklum,

@ einpoklum-reinstateMonica Se hai una serie di oggetti su cui vuoi agire, assegnando ogni elemento a sua volta a una variabile temporanea e chiamando un metodo polimorfico su quella variabile, allora sì AVETE BISOGNO di un puntatore perché non è possibile ricollegare un riferimento.
Sildoreth,

Se si dispone di un riferimento di classe base a una classe derivata e si chiama un metodo virtuale su quel riferimento, verrà chiamato l'override della classe derivata. Ho sbagliato?
einpoklum,

@ einpoklum-reinstateMonica È corretto. Ma non puoi cambiare l'oggetto a cui fa riferimento. Quindi, se esegui il ciclo su un elenco / set / array di tali oggetti, una variabile di riferimento non funzionerà.
Sildoreth,

5

Perché copiare oggetti di grandi dimensioni in tutti i luoghi fa perdere tempo e memoria.


4
E in che modo i puntatori aiutano a farlo? Penso che una persona proveniente da Java o .Net non conosca la differenza tra lo stack e l'heap, quindi questa risposta è abbastanza inutile ..
Mats Fredriksson,

Puoi passare per riferimento. Ciò impedirà la copia.
Martin York,

1
@MatsFredriksson - Invece di passare (copiare) una grande struttura di dati e copiare nuovamente il risultato, basta puntare a dove si trova nella RAM e quindi modificarlo direttamente.
John U,

Quindi non copiare oggetti di grandi dimensioni. Nessuno ha detto che hai bisogno di suggerimenti per questo.
einpoklum,

5

Ecco la mia risposta, e non prometto di essere un esperto, ma ho trovato che i puntatori sono fantastici in una delle mie librerie che sto cercando di scrivere. In questa libreria (è un'API grafica con OpenGL :-)) è possibile creare un triangolo con oggetti vertici passati al loro interno. Il metodo di disegno prende questi oggetti a triangolo e beh ... li disegna in base agli oggetti di vertice che ho creato. Va bene.

Ma cosa succede se cambio una coordinata di vertice? Spostalo o qualcosa del genere con moveX () nella classe del vertice? Bene, ora devo aggiornare il triangolo, aggiungendo altri metodi e le prestazioni vengono sprecate perché devo aggiornare il triangolo ogni volta che si sposta un vertice. Non è ancora un grosso problema, ma non è eccezionale.

Ora, se avessi una maglia con tonnellate di vertici e tonnellate di triangoli, e la maglia ruotasse, si muovesse e così via. Dovrò aggiornare tutti i triangoli che usano questi vertici, e probabilmente tutti i triangoli della scena perché non saprei quali usano i vertici. È estremamente intensivo, e se ho diverse maglie in cima a un paesaggio, oh dio! Sono nei guai, perché sto aggiornando ogni triangolo quasi ogni fotogramma perché questi vertici cambiano continuamente!

Con i puntatori, non è necessario aggiornare i triangoli.

Se avessi tre oggetti * di vertice per classe di triangolo, non solo sto risparmiando spazio perché un triangolo di zillion non ha tre oggetti di vertice che sono grandi se stessi, ma anche questi puntatori indicheranno sempre i vertici a cui sono destinati, non importa quanto spesso cambiano i vertici. Poiché i puntatori puntano ancora allo stesso vertice, i triangoli non cambiano e il processo di aggiornamento è più facile da gestire. Se ti confondessi, non ne dubiterei, non pretendo di essere un esperto, sto solo gettando i miei due centesimi nella discussione.


4

La necessità di puntatori in linguaggio C è descritta qui

L'idea di base è che molte limitazioni del linguaggio (come l'uso di matrici, stringhe e la modifica di più variabili nelle funzioni) potrebbero essere rimosse manipolando le posizioni di memoria dei dati. Per superare questi limiti, in C. sono stati introdotti degli indicatori

Inoltre, si vede anche che usando i puntatori, è possibile eseguire il codice più velocemente e risparmiare memoria nei casi in cui si stanno passando tipi di dati di grandi dimensioni (come una struttura con molti campi) a una funzione. Fare una copia di tali tipi di dati prima del passaggio richiederebbe tempo e consumerebbe memoria. Questo è un altro motivo per cui i programmatori preferiscono i puntatori per i tipi di big data.

PS: fare riferimento al collegamento fornito per una spiegazione dettagliata con un codice di esempio.


La domanda riguarda C ++, questa risposta riguarda C.
einpoklum,

no, la domanda è taggata c AND c ++. Forse il tag c è irrilevante, ma è qui dall'inizio.
Jean-François Fabre

3

In java e C # tutti i riferimenti agli oggetti sono puntatori, la cosa con c ++ è che hai più controllo su dove puntano i puntatori. Ricorda Con grande potenza derivano grandi responsabilità.


1

Per quanto riguarda la seconda domanda, in genere non è necessario utilizzare i puntatori durante la programmazione, tuttavia esiste un'eccezione a ciò e cioè quando si crea un'API pubblica.

Il problema con i costrutti C ++ che le persone generalmente usano per sostituire i puntatori dipendono molto dal set di strumenti che usi, il che va bene quando hai tutto il controllo di cui hai bisogno sul codice sorgente, tuttavia se compili una libreria statica con Visual Studio 2008 per esempio e provando ad usarlo in Visual Studio 2010, si otterranno molti errori di collegamento perché il nuovo progetto è collegato a una versione più recente di STL che non è compatibile con le versioni precedenti. Le cose diventano ancora più cattive se compili una DLL e dai una libreria di importazione che le persone usano in un set di strumenti diverso perché in quel caso il tuo programma si arresterà prima o poi senza motivo apparente.

Quindi, allo scopo di spostare grandi set di dati da una libreria all'altra, potresti prendere in considerazione la possibilità di dare un puntatore a un array alla funzione che dovrebbe copiare i dati se non vuoi forzare gli altri a usare gli stessi strumenti che usi . La parte buona di questo è che non deve nemmeno essere un array in stile C, puoi usare uno std :: vector e dare il puntatore dando l'indirizzo del primo elemento e vettore [0] per esempio, e usa lo std :: vector per gestire l'array internamente.

Un altro buon motivo per utilizzare nuovamente i puntatori in C ++ riguarda le librerie, considerare di avere una DLL che non può essere caricata quando il programma è in esecuzione, quindi se si utilizza una libreria di importazione la dipendenza non è soddisfatta e il programma si arresta in modo anomalo. Questo è il caso, ad esempio, quando si fornisce un'API pubblica in una DLL insieme all'applicazione e si desidera accedervi da altre applicazioni. In questo caso per utilizzare l'API è necessario caricare la dll dalla sua posizione (di solito si trova in una chiave di registro) e quindi è necessario utilizzare un puntatore a funzione per poter chiamare le funzioni all'interno della DLL. A volte le persone che creano l'API sono abbastanza gentili da darti un file .h che contiene funzioni di supporto per automatizzare questo processo e darti tutti i puntatori di funzione di cui hai bisogno,


1
  • In alcuni casi, i puntatori a funzione sono necessari per utilizzare le funzioni che si trovano in una libreria condivisa (.DLL o .so). Ciò include l'esecuzione di cose in diverse lingue, dove spesso viene fornita un'interfaccia DLL.
  • Fare compilatori
  • Realizzare calcolatori scientifici, in cui si dispone di una matrice o un vettore o una mappa di stringhe di puntatori a funzioni?
  • Prova di modificare direttamente la memoria video - creando il tuo pacchetto grafico
  • Creare un'API!
  • Strutture di dati: puntatori di collegamento nodo per alberi speciali che si stanno creando

Ci sono molte ragioni per i puntatori. Avere la manipolazione del nome C in particolare è importante nelle DLL se si desidera mantenere la compatibilità tra le lingue.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.