Perché incrementare i puntatori?

23

Recentemente ho iniziato ad imparare il C ++, e poiché la maggior parte delle persone (in base a ciò che ho letto) è alle prese con i puntatori.

Non nel senso tradizionale, capisco cosa sono, e perché sono usati, e come possono essere utili, tuttavia non riesco a capire come i puntatori incrementali sarebbero utili, chiunque può fornire una spiegazione di come incrementare un il puntatore è un concetto utile e un C ++ idiomatico?

Questa domanda è arrivata dopo aver iniziato a leggere il libro A Tour of C ++ di Bjarne Stroustrup, mi è stato consigliato questo libro, perché ho abbastanza familiarità con Java, e i ragazzi di Reddit mi hanno detto che sarebbe stato un buon libro di "passaggio".

    
posta INdek 01.08.2014 - 03:22
fonte

3 risposte

44

Quando hai un array, puoi impostare un puntatore per puntare a un elemento dell'array:

int a[10];
int *p = &a[0];

Qui p punta al primo elemento di a , che è a[0] . Ora puoi incrementare il puntatore per puntare all'elemento successivo:

p++;

Ora p punta al secondo elemento, a[1] . Puoi accedere all'elemento qui utilizzando *p . Questo è diverso da Java, dove dovresti usare una variabile indice intera per accedere agli elementi di un array.

L'incremento di un puntatore in C ++ in cui quel puntatore non punta a un elemento di un array è comportamento indefinito .

    
risposta data 01.08.2014 - 03:34
fonte
37

I puntatori incrementali sono C ++ idiomatico, perché la semantica del puntatore riflette un aspetto fondamentale della filosofia di progettazione alla base della libreria standard C ++ (basata su STL )

Il concetto importante qui è che l'STL è progettato attorno a contenitori, algoritmi e iteratori. I puntatori sono semplicemente iteratori .

Ovviamente, la possibilità di incrementare (o aggiungere / sottrarre da) i puntatori torna a C. Un sacco di algoritmi di manipolazione della C-string può essere scritto semplicemente usando l'aritmetica del puntatore. Considera il seguente codice:

char string1[4] = "abc";
char string2[4];
char* src = string1;
char* dest = string2;
while ((*dest++ = *src++));

Questo codice utilizza l'aritmetica del puntatore per copiare una C-string con terminazione null. Il ciclo termina automaticamente quando incontra il null.

Con C ++, la semantica dei puntatori è generalizzata al concetto di iteratori . La maggior parte dei contenitori C ++ standard fornisce iteratori, a cui è possibile accedere tramite le funzioni membro begin e end . Gli iteratori si comportano come dei puntatori, in quanto possono essere incrementati, dereferenziati e talvolta decrementati o avanzati.

Per ripetere su std::string , dovremmo dire:

std::string s = "abcdef";
std::string::iterator it = s.begin();
for (; it != s.end(); ++it) std::cout << *it;

Aumentiamo l'iteratore proprio come avremmo incrementato un puntatore a una semplice stringa C. La ragione per cui questo concetto è potente è che puoi utilizzare i modelli per scrivere funzioni che funzioneranno per qualsiasi tipo di iteratore che soddisfi i requisiti di concetto necessari. E questo è il potere dell'STL:

std::string s1 = "abcdef";
std::vector<char> buf;
std::copy(s1.begin(), s1.end(), std::back_inserter(buf));

Questo codice copia una stringa in un vettore. La funzione copy è un modello che funziona con qualsiasi iteratore che supporta l'incremento (che include semplici puntatori). Potremmo usare la stessa funzione copy su una semplice stringa C:

   const char* s1 = "abcdef";
   std::vector<char> buf;
   std::copy(s1, s1 + std::strlen(s1), std::back_inserter(buf));

Potremmo usare copy su un std::map o un std::set o qualsiasi contenitore personalizzato che supporti gli iteratori.

Nota che i puntatori sono un tipo specifico di iteratore: iteratore di accesso casuale , il che significa che supportano l'incremento, il decremento e l'avanzamento con l'operatore + e - . Altri tipi di iteratore supportano solo un sottoinsieme di semantica del puntatore: un iteratore bidirezionale supporta almeno l'incremento e il decremento; un forward iterator supporta almeno un incremento. (Tutti i tipi di iteratore supportano il dereferenziamento.) La funzione copy richiede un iteratore che almeno supporti l'incremento.

Puoi leggere i diversi concetti di iteratore qui .

Quindi, i puntatori incrementali sono un modo idiatico di C ++ per scorrere su un C-array, o accedere a elementi / offset in un array C.

    
risposta data 01.08.2014 - 05:37
fonte
16

L'aritmetica del puntatore è in C ++ perché era in C. L'aritmetica del puntatore si trova in C perché è un normale idioma in assemblatore .

Ci sono molti sistemi in cui il "registro di incremento" è più veloce di "carica il valore costante 1 e aggiungi alla registrazione". Inoltre, alcuni sistemi consentono di "caricare DWORD in A dall'indirizzo specificato nel registro B, quindi aggiungere sizeof (DWORD) a B" in una singola istruzione. In questi giorni potresti aspettarti un compilatore ottimizzante per risolverlo, ma questa non era un'opzione nel 1973.

Questo è fondamentalmente lo stesso motivo per cui gli array C non sono controllati dai limiti e le stringhe C non hanno una dimensione incorporata in esse: il linguaggio è stato sviluppato su un sistema in cui ogni byte e ogni istruzione sono contati.

    
risposta data 01.08.2014 - 13:14
fonte

Leggi altre domande sui tag