Domanda

AKA - Cos'è questa ossessione con i puntatori?

Avendo solo realmente utilizzato moderno, linguaggi object oriented come ActionScript, Java e C#, non ho ben capito l'importanza di puntatori e cosa utilizzare per loro.Quello che mi manca su qui?

È stato utile?

Soluzione

È tutto solo un riferimento indiretto:La capacità di non fare i conti con i dati, ma dire "io ti mostra alcuni dati, di là".Hai lo stesso concetto in Java e C#, ma solo in formato di riferimento.

Le differenze principali sono che i riferimenti siano effettivamente immutabile indicazioni - che puntano sempre a qualcosa.Questo è utile, e facile da capire, ma è meno flessibile rispetto al C puntatore modello.C i puntatori sono indicazioni che si possono tranquillamente riscrivere.Si sa che la stringa che stai cercando è accanto alla stringa a cui punta?Beh, basta modificare leggermente il cartello.

Questo coppie bene con C "vicino all'osso, basso livello di conoscenza è necessario un" approccio".Noi sapere che un char* foo consiste in un set di caratteri a partire dalla posizione indicata dal pippo cartello.Se sappiamo anche che la stringa è lunga almeno 10 caratteri, possiamo cambiare il cartello (foo + 5) di punto in poi la stessa stringa, ma iniziare a metà della lunghezza.

Questa flessibilità è utile quando si sa cosa si sta facendo, e la morte se non (dove il "sapere" più che "sapere una lingua", è "conoscere l'esatto stato del programma").Sbagli, e il cartello si dirige fuori dal bordo di una scogliera.I riferimenti non permettono di violino, così è molto più sicuro che si può seguire senza rischio (soprattutto quando accoppiato con regole come "Un oggetto a cui fa riferimento non potrà mai scomparire", come nella maggior parte dei Garbage collection lingue).

Altri suggerimenti

Ti stai perdendo un sacco!!!La comprensione di come il computer funziona su livelli inferiori è molto utile in diverse situazioni.C e assembler farà per voi.

Fondamentalmente un puntatore consente di scrivere roba da qualsiasi punto della memoria del computer.In più primitivo hardware/OS o in sistemi embedded questo in realtà potrebbe fare qualcosa di utile.Dire girare il blinkenlichts e fuori di nuovo.

Naturalmente questo non funziona su sistemi moderni.Il sistema operativo è il Signore e Padrone di memoria principale.Se si tenta di accedere a una posizione di memoria errato, il processo di pagare per la sua arroganza, con la sua vita.

In C, i puntatori sono il modo per passare i riferimenti ai dati.Quando si chiama una funzione, non si desidera copiare un milione di bit di una pila.Invece dici solo dove risiedono i dati nella memoria principale.In altre parole, dare un puntatore per i dati.

In qualche misura questo è quello che succede anche con Java.Si passa riferimenti a oggetti, non gli oggetti stessi.Ricordate, infine, che ogni oggetto è un insieme di bit del computer la memoria principale.

I puntatori sono per modificare direttamente il contenuto della memoria.

Spetta a voi se si pensa che questo è una buona cosa da fare, ma è la base di come nulla viene fatto in C o in assembler.

Linguaggi di alto livello nascondere i puntatori dietro le quinte:per esempio, un riferimento in Java è implementato come un puntatore in quasi qualsiasi JVM che si incontrano, che è il motivo per cui si chiama NullPointerException, piuttosto che l'eccezione NullReferenceException.Ma non lasciare che il programmatore di accedere direttamente all'indirizzo di memoria in punta, e non può essere modificato da un valore diverso da l'indirizzo di un oggetto di tipo corretto.Quindi non offrono la stessa potenza (e la responsabilità) che i puntatori in basso a livello di linguaggi di programmazione.

[Edit:questa è una risposta alla domanda 'che cos'è questa ossessione con i puntatori?'.Tutti ho rispetto è assembler/C-stile puntatori con Java riferimenti.La domanda del titolo è cambiato:avevo impostato per rispondere alla nuova domanda avrei detto riferimenti in altre lingue oltre a Java]

Questo è come chiedere, “che cosa è questa ossessione con le istruzioni della CPU?Devo rinunciare a qualcosa, non aspersione x86 MOV istruzioni in tutto il luogo?”

Basta bisogno puntatori quando la programmazione a basso livello.Nella maggior parte superiore a livello di linguaggio di programmazione implementazioni, i puntatori sono utilizzati solo come ampiamente come in C, ma nascosto all'utente da parte del compilatore.

Quindi...Non ti preoccupare.Stai usando puntatori già, e senza i pericoli di farlo in modo non corretto, troppo.:)

Vedo puntatori come un cambio manuale a un'auto.Se si impara a guidare con una macchina che ha una trasmissione automatica, che non rendono un cattivo driver.E si può ancora fare la maggior parte del tutto che i driver che imparato su una trasmissione manuale può fare.Ci sarà solo un buco nella vostra conoscenza di guida.Se dovessi guidare un manuale che si sarebbe probabilmente in difficoltà.Certo, è facile capire il concetto di base di esso, ma una volta che devi fare una partenza in salita, sei fregato.Ma, c'è ancora un posto per trasmissioni manuali.Per esempio, i piloti devono essere in grado di passare a prendere la macchina per rispondere in modo ottimale alle attuali condizioni di gara.Avendo una trasmissione manuale è molto importante per il loro successo.

Questo è molto simile alla programmazione destra ora.C'è bisogno di C/C++ sviluppo di alcuni software.Alcuni esempi sono high-end 3D giochi, basso livello di software embedded, le cose in cui la velocità è una parte critica del software di scopo, e un basso livello di linguaggio che permette un maggiore accesso ai dati che devono essere trattati, è la chiave che le prestazioni.Tuttavia, per la maggior parte dei programmatori non è questo il caso, e non conoscendo i puntatori non è invalidante.Tuttavia, credo che tutti possano beneficiare di apprendimento su C e puntatori, e alla trasmissione manuale troppo.

Dal momento che si dispone di programmazione nei linguaggi object oriented, mettiamola in questo modo.

Si ottiene l'Oggetto A creare un'istanza di Oggetto B, e si passa come parametro di un metodo per Oggetto C.L'Oggetto C modifica alcuni valori nell'Oggetto B.Quando si sono di nuovo Oggetto di Un codice, è possibile vedere il valore modificato in Oggetto B.Perché è così?

Perché è passato un riferimento dell'Oggetto B Oggetto C, non ha fatto un'altra copia dell'Oggetto B.Così Un Oggetto e l'Oggetto C sia tenere i riferimenti allo stesso Oggetto B in memoria.Cambia da un luogo e di essere visto in un altro.Questo è chiamato Da Riferimento.

Ora, se si utilizzano tipi primitivi, invece, come int o float, e farli passare come parametri del metodo, le modifiche in Oggetto C non può essere visto da Un Oggetto, perché Un Oggetto semplicemente passato un copia invece di un riferimento della propria copia della variabile.Questo è chiamato per Valore.

Probabilmente già lo sapeva.

Tornando al linguaggio C, la Funzione passa alla Funzione B alcune variabili.Questi i parametri della funzione sono nativo di copie, per Valore.In ordine per la Funzione B per modificare la copia appartenendo a Una Funzione, la Funzione deve passare un puntatore per la variabile, in modo che diventa un passaggio per Riferimento.

"Ehi, qui è l'indirizzo di memoria per la mia variabile di tipo integer.Inserire il nuovo valore che la posizione di un indirizzo e mi prenderà più tardi."

Nota il concetto è simile, ma non al 100% di analogo.I puntatori possono fare molto di più che solo di passaggio "da riferimento".Puntatori permettono di funzioni per la manipolazione arbitraria locazioni di memoria per qualsiasi valore richiesto.I puntatori sono anche usati come nuovi indirizzi di codice di esecuzione dinamicamente eseguire la logica, non solo a dati variabili.I puntatori possono anche scegliere altri puntatori (doppio puntatore).Che è potente, ma anche molto facile introdurre difficile da rilevare i bug e vulnerabilità di sicurezza.

Se non avete visto puntatori prima, si sta sicuramente perdendo questo mini gem:

void strcpy(char *dest, char *src)
{    
        while(*dest++ = *src++);
}

Storicamente, ciò che ha reso programmazione è stata la realizzazione che posizioni di memoria può contenere istruzioni per il computer, non solo i dati.

Puntatori nasceva dalla consapevolezza che i percorsi di memoria potrebbe anche tenere il discorso di altre posizioni di memoria, dandoci così un riferimento indiretto.Senza puntatori (a basso livello) più complesse strutture di dati sarebbe impossibile.No linked-list, binari, alberi o hash-tabelle.Nessun passaggio per riferimento, solo per valore.Dal momento che i puntatori possono scegliere di codice, senza di loro ci sarebbe anche non funzioni virtuali o funzione look-up table.

Io uso i puntatori e riferimenti fortemente nel mio lavoro, giorno per giorno...in codice gestito (C#, Java) e non gestiti (C++, C).Ho imparato come trattare con i puntatori e ciò che essi sono dal maestro stesso...[Binky!!][1] Nient'altro da dire ;)

La differenza tra un puntatore e di riferimento è questo.Un puntatore è un indirizzo di un blocco di memoria.Può essere riscritto o, in altre parole, riassegnati a qualche altro blocco di memoria.Un riferimento è semplicemente cambiando il nome di un oggetto.Può essere assegnato solo una volta!Una volta assegnato a un oggetto, non può essere assegnato a un altro.Un riferimento, non un indirizzo, è un altro nome per la variabile.Check out C++ FAQ per ulteriori informazioni su questo.

Link1

LInk2

Attualmente sto alla cintola la progettazione di un elevato livello di enterprise software che blocchi di dati (memorizzati in un database SQL, in questo caso) fa riferimento a 1 o più altri soggetti.Se un blocco di dati rimane quando non sono più entità di riferimento, stiamo sprecando di archiviazione.Se uno dei punti di riferimento in modo che i dati che non è presente, questo è un grande problema di troppo.

C'è una forte analogia tra i nostri problemi, e quelli di gestione della memoria in una lingua che utilizza i puntatori.È estremamente utile per essere in grado di parlare con i miei colleghi in termini di analogia.Non cancellare senza riferimenti dati è una "perdita di memoria".Un riferimento che non va da nessuna parte è un "dangling pointer".Possiamo scegliere esplicito "libera", o siamo in grado di realizzare la "garbage collection" con "reference counting".

Così qui, di comprensione, di basso livello, la gestione della memoria è di aiuto nella progettazione di applicazioni ad alto livello.

In Java si utilizza puntatori per tutto il tempo.La maggior parte delle variabili sono dei puntatori a oggetti - che è il motivo per cui:

StringBuffer x = new StringBuffer("Hello");
StringBuffer y = x;
x.append(" boys");
System.out.println(y);

...stampa "Ciao ragazzi" e non "Ciao".

L'unica differenza C è che è comune per aggiungere e sottrarre da puntatori, e se si ottiene la logica sbagliata, si può finire a fare scherzi con i dati non si dovrebbe toccare.

Le stringhe sono fondamentali per la C (e altre lingue).Quando la programmazione in C, si deve gestire la vostra memoria.Non basta dire "ok, ho bisogno di un sacco di stringhe";è necessario pensare a una struttura dati.Quanta memoria avete bisogno?Quando si assegna?Quando sei libero?Diciamo che si desidera 10 stringhe, ciascuna con non più di 80 caratteri.

Va bene, ogni stringa è un array di caratteri (81 caratteri - non si deve dimenticare il null o te ne pentirai!) e poi ogni stringa è di per sé in un array.Il risultato finale sarà un array multidimensionale qualcosa di simile

char dict[10][81];

Si noti, per inciso, che dict non è una "stringa" o "matrice", o un "char".Si tratta di un puntatore.Quando si tenta di stampare una di quelle corde, stai passando l'indirizzo di un singolo carattere;C, si presuppone che se si inizia a caratteri di stampa si finirà per colpire un valore null.E si presume che se siete all'inizio di una stringa, e un salto in avanti 81 byte, si arriva all'inizio della stringa successiva.E, infatti prendendo il puntatore e l'aggiunta di 81 byte è l' unico modo possibile per saltare alla corda successiva.

Così, perché sono puntatori importante?Perché non si può fare nulla senza di loro.Si può anche fare qualcosa di semplice come la stampa fuori un sacco di stringhe;si certamente non si può fare qualcosa di interessante come implementare liste collegate, o hash, o code o alberi, o di un file di sistema, o qualche codice di gestione di memoria, o un kernel o...qualsiasi cosa.È NECESSARIO capire perché C solo le mani un blocco di memoria e ti lascia fare il resto, e fare tutto ciò con un blocco di materie prime di memoria richiede puntatori.

Anche molte persone suggeriscono che la capacità di capire i puntatori è altamente correlato con l'abilità di programmazione.Joel ha fatto di questo argomento, tra gli altri.Per esempio

Ora, devo ammettere che la programmazione con i puntatori non è necessario che il 90% del codice scritto oggi, infatti, è addirittura pericoloso nel codice di produzione.OK.Va bene.E la programmazione funzionale è proprio molto usato in pratica.Concordato.

Ma è ancora importante per alcuni dei più emozionanti, i lavori di programmazione.Senza puntatori, per esempio, non si può mai essere in grado di lavorare sul kernel Linux.Non si può capire una riga di codice in Linux, o, di fatto, qualsiasi sistema operativo, senza realmente capire i puntatori.

Da qui.Ottimo articolo.

Per essere onesti, la maggior parte sviluppatori esperti avrà una risata (si spera amichevole) se non sai puntatori.In un mio precedente Lavoro abbiamo avuto due nuovi assunti lo scorso anno (appena laureato) che non conoscevo puntatori, e che da solo è stato l'argomento di conversazione con loro per circa una settimana.Nessuno poteva credere a quanto qualcuno potrebbe laurearsi senza conoscere i puntatori...

Riferimenti in C++ sono fondamentalmente diverse da riferimenti in Java o .NET lingue;.NET lingue sono tipi speciali chiamati "byrefs" che si comportano molto come il C++ "riferimenti".

A C++ o di riferimento .NET byref (io uso il termine ultimo, per distinguere da .NET riferimenti) è un tipo speciale, che non sia in possesso di una variabile, ma piuttosto contiene informazioni sufficienti per identificare una variabile (o qualcosa che può comportarsi come uno, come un array di slot) tenute altrove.Byrefs, sono generalmente utilizzati come parametri di funzione e gli argomenti, e sono destinati ad essere effimera.Il codice che passa un byref a una funzione garantisce che la variabile che viene identificato, quindi, esiste, almeno fino a che la funzione restituisce, e funzioni che in genere la garanzia di non tenere qualsiasi copia di un byref dopo il loro ritorno (si noti che in C++ quest'ultima limitazione non viene applicata).Così, byrefs non può sopravvivere più a lungo le variabili identificate in tal modo.

In Java e .NET lingue, un riferimento è un tipo che identifica un oggetto heap;ogni heap oggetto è associata una classe, e il codice in oggetto heap di classe possono accedere ai dati memorizzati in oggetto.Mucchio di oggetti, può concedere, al di fuori del codice limitata o accesso completo ai dati in esso memorizzati, e/o per consentire all'esterno il codice per chiamare alcuni metodi all'interno della loro classe.Con un punto di riferimento per la chiamata di un metodo di classe farà riferimento, per essere reso disponibile a tale metodo, che può quindi utilizzarlo per accedere ai dati (anche dati privati) all'interno dell'oggetto heap.

Ciò che rende riferimenti speciali in Java e .NET languages è che essi mantengono, come un assoluto invariante, che ogni non-null riferimento continuerà a identificare lo stesso heap oggetto fintanto che esistono riferimenti.Una volta nessun riferimento a un oggetto heap esiste in tutto l'universo, l'oggetto heap semplicemente cesserà di esistere, ma non c'è nessun modo che un oggetto heap può cessare di esistere, mentre ogni riferimento ad esso esiste, né vi è alcun modo per un "normale" riferimento a un oggetto heap spontaneamente diventare qualcosa di diverso da un riferimento a tale oggetto.Sia in Java .NETTE hanno di speciale "debole" di riferimento, ma anche sostengono l'invariante.Se non debole il riferimento a un oggetto esiste in tutto l'universo, quindi qualsiasi esistente riferimenti deboli saranno annullati;una volta che si verifica, non ci sarà alcun riferimento all'oggetto e si può, pertanto, essere invalidato.

Puntatori, come C++ riferimenti e Java/.NET riferimenti, identificare oggetti, ma a differenza dei tipi di cui sopra di riferimenti possono sopravvivere più a lungo gli oggetti identificati.Se l'oggetto identificato da un puntatore cessa di esistere, ma il puntatore non, qualsiasi tentativo di utilizzare il puntatore del mouse si traducono in un Comportamento Indefinito.Se un puntatore non è noto per essere null o per identificare un oggetto che attualmente esiste, non c'è standard definiti dall'modo di fare nulla puntatore altro che sovrascrivere con qualcos'altro.E ' perfettamente legittimo che un puntatore a continuare ad esistere dopo che l'oggetto identificato, quindi, ha cessato di farlo, a condizione che non si utilizza il puntatore del mouse, ma è necessario che qualcosa al di fuori del puntatore indicare se o non è sicuro da usare perché non c'è modo di chiedere il puntatore stesso.

La differenza fondamentale tra puntatori e riferimenti (di qualsiasi tipo) è che i riferimenti possono essere sempre chiesto se sono validi (sarà essere sia valido o identificabili come null), e se osservate per essere valido rimarranno così fino a che esiste.I puntatori non può essere chiesto se sono validi, e il sistema non fa nulla per garantire che i puntatori non essere valide, né consentire puntatori che diventano non validi per essere riconosciuto come tale.

Per molto tempo non ho capito puntatori, ma ho capito array di indirizzamento.Allora io di solito mettere insieme un po 'di area per il deposito di oggetti in un array, e quindi utilizzare un indice di array come il "puntatore" concetto.

SomeObject store[100];
int a_ptr = 20;
SomeObject A = store[a_ptr];

Un problema con questo approccio è che dopo che ho modificato la 'A', devo riassegnare al 'store' array in modo che le modifiche vengano permanente:

store[a_ptr] = A;

Dietro le quinte, il linguaggio di programmazione è stato fare più copia di operazioni.La maggior parte del tempo questo non influisce sulle prestazioni.È fatto principalmente il codice error-prone e ripetitivo.

Dopo che ho imparato a capire i puntatori, mi sono trasferito dalla attuazione della matrice di indirizzamento approccio.L'analogia è ancora abbastanza valido.Basti pensare che il 'negozio' array è gestito dal linguaggio di programmazione in fase di esecuzione.

SomeObject A;
SomeObject* a_ptr = &A;
// Any changes to a_ptr's contents hereafter will affect
// the one-true-object that it addresses. No need to reassign.

Oggi, io uso solo i puntatori quando io non posso legittimamente la copia di un oggetto.Ci sono una serie di ragioni per cui questo potrebbe essere il caso:

  1. Per evitare un costoso oggetto di copia operazione per il bene di prestazioni.
  2. Qualche altro fattore da non permettere un oggetto operazione di copia.
  3. Si desidera che la chiamata di una funzione per avere effetti collaterali su un oggetto (non passare l'oggetto, passare il puntatore tali informazioni).
  4. In alcune lingue - se si desidera restituire più di un valore da un funzione (anche se in genere evitate).

I puntatori sono più pragmatici modo di rappresentare un riferimento indiretto a basso livello di linguaggi di programmazione.

I puntatori sono importanti!Che "punto" a un indirizzo di memoria, e molte strutture interne sono rappresentate come puntatori, vale a dire, Un array di stringhe è in realtà un elenco di puntatori a puntatori!I puntatori possono anche essere utilizzati per aggiornare le variabili passate funzioni.

Hai bisogno di loro, se si desidera generare "oggetti" in fase di runtime, senza pre allocare memoria sullo stack

Parametro di efficienza - il passaggio di un puntatore (Int - 4 byte) invece di copiare un intero (arbitarily grande) oggetto.

Classi Java sono passati attraverso di riferimento (in fondo è un puntatore) anche btw, solo che in java che è nascosto dal programmatore.

Programmazione in linguaggi come il C e il C++ è molto più vicino al "metallo".Puntatori a tenere una posizione di memoria in cui le variabili, dati, funzioni etc.live.È possibile passare un puntatore invece di passare dal valore (copia delle variabili e dei dati).

Ci sono due cose che sono difficili con i puntatori:

  1. Puntatori a puntatori, indirizzi, etc.può ottenere molto criptico.Essa conduce a errori, ed è di difficile lettura.
  2. Memoria puntatori punto è spesso assegnato dal mucchio, il che significa che sono responsabili per il rilascio di tale memoria.Più si ottiene, più è difficile mantenere il passo con questo requisito, e si finisce con perdite di memoria che sono difficili da rintracciare.

Si potrebbe paragonare il comportamento del puntatore a come Java gli oggetti vengono passati in giro, con l'eccezione che in Java non è necessario preoccuparsi di liberare la memoria come questo viene gestito dalla procedura di garbage collection.In questo modo si ottiene le cose buone su di puntatori, ma non hanno a che fare con i negativi.È ancora possibile ottenere perdite di memoria in Java, naturalmente, se non de-fare riferimento a oggetti, ma che è una questione diversa.

Anche solo qualcosa di nota, è possibile utilizzare i puntatori in C# (rispetto alla normale riferimenti), segnando un blocco di codice unsafe.Quindi è possibile eseguire in giro per cambiare direttamente gli indirizzi di memoria e fare aritmetica dei puntatori e tutta quella roba di divertimento.È grande per molto veloce per la manipolazione di immagini (l'unico posto dove io personalmente ho utilizzato).

Per quanto ne so, Java, ActionScript non supportano il codice unsafe e puntatori.

Io sono sempre in difficoltà con la messa a fuoco su tali cose come puntatori o riferimenti in linguaggi di alto livello.E ' davvero utile pensare ad un livello di astrazione più elevato, in termini di comportamento degli oggetti (o anche solo funzioni) invece di pensare in termini di "fammi vedere, se mi invii l'indirizzo di questa cosa c'è, allora che cosa sarà di me tornare con un puntatore a qualcosa d'altro"

Considerare anche una semplice funzione di scambio.Se si dispone di

void swap(int & a, int & b)

o

procedura di Swap(var a, b :integer)

poi interpretare questi per dire che i valori possono essere modificati.Il fatto che è in corso di attuazione, passando gli indirizzi delle variabili è solo una distrazione dalla fine.

Stesso con gli oggetti --- non credo di identificatori di oggetto come puntatori o riferimenti alle "cose".Invece, pensare a loro come, anche, gli OGGETTI, a cui è possibile inviare messaggi.Anche nel primitivo linguaggi come il C++, si può andare molto di più molto di più da pensare (e scrivere) al più alto livello possibile.

Scrivere più di 2 righe di c o c++ e lo scoprirai.

Sono i "puntatori" per la posizione di memoria di una variabile.È come passare una variabile da un pò di riferimento.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top