Un'introduzione ai puntatori per i programmatori

Un'introduzione ai puntatori per i programmatori / Programmazione

Che tu te ne renda conto o no, la maggior parte dei programmi che hai usato usano in qualche modo dei puntatori. Forse hai vissuto un NullPointerException ad un certo punto. Come programmatore, il codice che scrivi più probabilmente utilizzerà i puntatori, anche se non li hai implementati tu stesso.

Oggi ti mostrerò come funzionano i puntatori, quindi potresti voler controllare come funzionano gli array e le liste Come funzionano le matrici e gli array in Python Come funzionano gli array e gli elenchi in Python Gli array e gli elenchi sono alcune delle strutture dati più utili nella programmazione - - anche se poche persone li usano al massimo delle loro potenzialità. Ulteriori informazioni per un programma di programmazione. Questo articolo sarà più basato sulla teoria del solito, ma attenetevi ad esso, i puntatori sono molto complessi!

Codice di compilazione

Prima di scavare nei puntatori, devi capire come il codice viene creato ed eseguito, forse lo sai già. Questa sezione avrà dichiarazioni abbastanza generali - cose che si applicano al maggioranza di lingue, ma non necessariamente tutte.

Riportiamo le cose all'inizio. Ogni computer utilizza binario What Is Binary? [La tecnologia ha spiegato] Cos'è il binario? [Tecnologia spiegata] Dato che il binario è così assolutamente fondamentale per l'esistenza dei computer, sembra strano che non abbiamo mai affrontato l'argomento prima - così oggi avevo pensato di dare una breve panoramica di ciò che è binario ... Per saperne di più, una serie di uni e zero che costituiscono la tecnologia moderna così come la conosciamo. È estremamente difficile codificare qualsiasi cosa in binario (i file sarebbero molto confusi), in quanto queste sono le istruzioni non elaborate necessarie per il tuo Unità centrale di elaborazione o CPU per funzionare Cos'è una CPU e cosa fa? Cos'è una CPU e cosa fa? Gli acronimi informatici sono confusi. Che cos'è una CPU comunque? E ho bisogno di un processore quad o dual-core? Che ne dici di AMD o Intel? Siamo qui per aiutare a spiegare la differenza! Leggi di più . Questo è noto come Codice macchina.

Il passo successivo dal codice macchina è montaggio. Questo è un formato leggibile in qualche modo umano. Anche se è ancora complesso da programmare, è possibile. Assembly è costituito da una serie di semplici comandi per eseguire attività ed è noto come a basso livello linguaggio di programmazione. È possibile scrivere programmi complessi, ma è difficile esprimere concetti astratti e richiede molta considerazione.

Molti videogiochi e applicazioni ad alte prestazioni hanno una parte della logica scritta in assembly, poiché è possibile riscontrare alcuni aumenti della velocità reale se si sa cosa si sta facendo. Tuttavia, per la stragrande maggioranza dei progetti di programmazione, non è necessario conoscere alcun assemblaggio.

Quindi se il codice macchina è troppo difficile da scrivere e l'assemblaggio è troppo difficile da programmare, con cosa scrivi il codice? Ecco dove alto livello le lingue entrano. Le lingue di alto livello rendono i programmi facili da scrivere. È possibile programmare in qualcosa che assomiglia alla tua lingua madre ed è facile esprimere algoritmi complessi. Potresti aver sentito parlare di molti linguaggi di alto livello (e sicuramente avrai usato un programma scritto in essi):

  • DI BASE
  • C++
  • blesità

Queste lingue sono molto vecchie ora e molte sono state sviluppate nei primi anni '50! Quasi ogni linguaggio di programmazione moderno è un linguaggio di alto livello, inclusi PHP e Python. Ci sono più lingue inventate ogni giorno (anche se ora ce ne sono abbastanza), ma come funziona esattamente il tuo codice se i computer richiedono un codice macchina??

Ecco dove arriva la compilazione. Un compilatore è un programma che converte il codice di alto livello in un modulo che può essere eseguito. Questo potrebbe essere un altro linguaggio di alto livello, ma di solito è assemblaggio. Alcuni linguaggi (come Python o Java) convertono il tuo codice in uno stadio intermedio chiamato bytecode. Questo richiederà una compilazione in un secondo momento, che di solito viene fatto su richiesta, come quando il programma viene eseguito. Questo è noto come appena in tempo compilazione, ed è abbastanza popolare.

Gestione della memoria

Ora che sai come funzionano i linguaggi di programmazione, diamo un'occhiata alla gestione della memoria nei linguaggi di alto livello. Per questi esempi, userò pseudo codice - codice scritto non in una lingua specifica, ma usato per mostrare concetti piuttosto che sintassi esatta. Oggi, questo per lo più somiglia al C ++ in quanto è il miglior linguaggio di alto livello (secondo me).

Per questa sezione, ti aiuterà se hai una comprensione di come funziona la RAM Una guida rapida e sporca alla RAM: Che cosa è necessario sapere Una guida rapida e sporca alla RAM: Che cosa è necessario sapere La RAM è un componente cruciale di ogni computer , ma può essere fonte di confusione capire se non sei un guru della tecnologia. In questo post, lo analizziamo in termini facili da comprendere. Leggi di più .

La maggior parte delle lingue ha variabili: contenitori che memorizzano alcuni dati. Devi definire esplicitamente il tipo di dati. Alcuni linguaggi digitati dinamicamente come Python o PHP gestiscono questo per te, ma devono ancora farlo.

Di 'che hai una variabile:

int myNumber;

Questo codice dichiara una variabile chiamata il mio numero, e gli dà un tipo di dati di numero intero. Una volta compilato, il computer interpreta questo comando come:

“Trova un po 'di memoria vuota e prenota uno spazio abbastanza grande per memorizzare un numero intero”

Una volta eseguito questo comando, quel bit di memoria non può essere utilizzato da un altro programma. Non contiene ancora alcun dato, ma è riservato alla variabile myNumber.

Adesso assegna un valore alla tua variabile:

myNumber = 10;

Per completare questa operazione, il tuo computer accede alla sua posizione di memoria riservata e modifica qualsiasi valore ivi memorizzato, a questo nuovo valore.

Ora, va tutto bene, ma in che modo le posizioni di memoria non vengono riservate? Se i programmi riservano tutta la memoria che gli piace, la RAM si riempirebbe immediatamente - ciò renderebbe un molto sistema lento.

Per evitare questo potenziale problema, molte lingue implementano a netturbino, usato per distruggere le variabili (e quindi rilasciare le posizioni di memoria riservata) che sono sparite fuori dal campo di applicazione.

Forse ti starai chiedendo quale sia la portata e perché è così importante. Scope definisce i limiti e la durata delle variabili o qualsiasi memoria utilizzata da un programma. Una variabile è “fuori dal campo di applicazione” quando non è più possibile accedere a nessun codice (in quel momento il garbage collector interviene). Ecco un esempio:

function maths () int firstNumber = 1;  int secondNumber = 2; stampa (firstNumber + secondNumber); // non funzionerà

Questo esempio non verrà compilato. La variabile firstNumber è dentro il matematica funzione, quindi è l'ambito. Non è possibile accedervi dall'esterno della funzione in cui è stato dichiarato. Questo è un concetto di programmazione importante, e capire è fondamentale lavorare con i puntatori.

Questo modo di gestire la memoria è chiamato il pila. È il modo in cui funziona la grande maggioranza dei programmi. Non devi capire i puntatori per usarlo ed è abbastanza ben strutturato. Lo svantaggio della pila è la velocità. Poiché il computer deve assegnare memoria, tenere traccia delle variabili ed eseguire la garbage collection, c'è un piccolo sovraccarico. Questo va bene per i programmi più piccoli, ma per le attività ad alte prestazioni o per le applicazioni pesanti?

Inserisci: puntatori.

puntatori

Sulla superficie, i puntatori sembrano semplici. Fanno riferimento (indicare) una posizione in memoria. Questo potrebbe non sembrare diverso da “regolare” variabili in pila, ma credimi, c'è un'enorme differenza. I puntatori sono memorizzati sul mucchio. Questo è l'opposto dello stack: è meno organizzato, ma è molto più veloce.

Diamo un'occhiata a come vengono assegnate le variabili nello stack:

int numberOne = 1; int numberTwo = numberOne;

Questa è una sintassi semplice; La variabile numero due contiene il numero uno. Il suo valore viene copiato durante l'assegnazione da numero uno variabile.

Se volevi ottenere il indirizzo di memoria di una variabile, invece del suo valore, devi usare il segno e commerciale (&). Questo è chiamato il indirizzo di operatore, ed è una parte essenziale del tuo toolkit puntatore.

int numberOne = 1; int numberTwo = & numberOne;

Ora il numero due variabile punti in una posizione di memoria, piuttosto che ottenere il numero uno copiato al proprio, nuova posizione di memoria. Se si dovesse emettere questa variabile, non sarebbe il numero uno (anche se questo è memorizzato nella posizione di memoria). Emetterebbe la sua posizione di memoria (probabilmente qualcosa come 2167, anche se varia a seconda del sistema e della RAM disponibile). Per accedere al valore memorizzato in un puntatore, invece della posizione di memoria, è necessario dereference il puntatore. Questo accede direttamente al valore, che sarebbe il numero uno in questo caso. Ecco come si dereferenzia un puntatore:

int numberTwo = * numberOne;

Il operatore di dereferenziazione è un asterisco (*).

Questo può essere un concetto difficile da capire, quindi torniamo sopra:

  • Il indirizzo di operatore (&) memorizza l'indirizzo di memoria.
  • Il operatore di dereferenziazione (*) accede al valore.

La sintassi cambia leggermente quando si dichiarano i puntatori:

int * myPointer;

Il tipo di dati di int qui si riferisce al tipo di dati il ​​puntatore punti a, e non il tipo del puntatore stesso.

Ora che sai quali sono i puntatori, puoi fare alcuni trucchetti davvero accurati con loro! Quando viene utilizzata la memoria, viene avviato il sistema operativo sequenzialmente. Puoi pensare alla RAM come a un piccione. Molti buchi per memorizzare qualcosa, solo uno può essere utilizzato contemporaneamente. La differenza qui è che questi fori dei piccioni sono tutti numerati. Quando si assegna memoria, il sistema operativo inizia dal numero più basso e funziona. Non salterà mai tra numeri casuali.

Quando si lavora con i puntatori, se si è assegnato un array, è possibile navigare facilmente al prossimo elemento semplicemente aumentando il puntatore.

Ecco dove diventa interessante. Quando si passano valori a una funzione (utilizzando le variabili memorizzate nello stack), questi valori vengono copiati nella funzione. Se queste sono grandi variabili, il programma ora le sta memorizzando due volte. Al termine della tua funzione, potresti aver bisogno di un modo per restituire questi valori. Le funzioni generalmente possono restituire solo una cosa, quindi se si desidera restituire due, tre o quattro elementi?

Se si passa un puntatore alla propria funzione, viene copiato solo l'indirizzo di memoria (che è minuscolo). Questo risparmia molto alla tua CPU! Forse il tuo puntatore punta a un enorme array di immagini - non solo la tua funzione può lavorare sugli stessi identici dati memorizzati nella stessa identica posizione di memoria, ma una volta eseguita, non è necessario restituire nulla. pulito!

Devi essere molto attento però. I puntatori possono ancora uscire dal campo di applicazione e essere raccolti dal garbage collector. I valori memorizzati nella memoria, tuttavia, non vengono raccolti. Questo è chiamato una perdita di memoria. Non è più possibile accedere ai dati (poiché i puntatori sono stati distrutti), ma sta ancora utilizzando la memoria. Questo è un motivo comune per molti programmi di arresto anomalo e può non riuscire in modo spettacolare se vi è una grande quantità di dati. La maggior parte delle volte, il tuo sistema operativo ucciderà il tuo programma se hai una grossa perdita (usando più RAM di quella del sistema), ma non è desiderabile.

I puntatori di debug possono essere un incubo, specialmente se stai lavorando con grandi quantità di dati o lavorando in loop. I loro svantaggi e difficoltà di comprensione valgono davvero i compromessi che ottieni in termini di prestazioni. Sebbene ricordi, potrebbero non essere sempre richiesti.

Questo è tutto per oggi. Spero che tu abbia imparato qualcosa di utile su un argomento complesso. Certo, non abbiamo coperto tutto ciò che c'è da sapere - è un argomento molto complesso. Se sei interessato a saperne di più, ti consiglio vivamente C ++ in 24 ore.

Se questo fosse un po 'complesso, dai un'occhiata alla nostra guida ai linguaggi di programmazione più facili 6 I linguaggi di programmazione più semplici da imparare per principianti 6 Linguaggi di programmazione più semplici da imparare per principianti Imparare a programmare è trovare la lingua giusta tanto quanto lo è processo di edificazione. Ecco i primi sei linguaggi di programmazione più facili per i principianti. Leggi di più .

Hai saputo come funzionano i puntatori oggi? Hai qualche consiglio o consiglio da condividere con altri programmatori? Salta nei commenti e condividi i tuoi pensieri qui sotto!

Scopri di più su: Programmazione.