Qual è la differenza tra variabili e puntatori?


10

Mentre leggevo un articolo che delineava le differenze in OO e nella programmazione funzionale, mi sono imbattuto in indicatori di funzione. È passato un po 'di tempo da quando ho completato la mia laurea in Informatica (2003) e quindi ho cercato gli indicatori per rinfrescare la mia memoria.

I puntatori sono variabili che contengono un riferimento a un indirizzo di memoria. Possono essere considerati come punti ai dati contenuti in quell'indirizzo di memoria se tali dati esistono. Oppure, come nel caso dell'articolo, potrebbero indicare il punto di ingresso a una sezione di codice e possono essere utilizzati per chiamare quel codice.

Perché questo è diverso da una variabile? Le variabili sono nomi simbolici per gli indirizzi di memoria e i compilatori sostituiranno il nome con l'indirizzo effettivo. Ciò significa che le variabili contengono riferimenti a posizioni di memoria e possono essere considerate come punti ai dati a quell'indirizzo se tali dati esistono.

Se la differenza è nel comportamento (forse un puntatore non può essere riassegnato in fase di esecuzione o può essere assegnato solo un nome di variabile simbolico, non qualsiasi altro valore) non significa che si tratta solo di una variabile di un tipo particolare, il tipo di puntatore? Allo stesso modo una variabile dichiarata di tipo intero è limitata dalla compilazione in cui può essere utilizzata.

Cosa mi sto perdendo qui?


4
Niente, un puntatore è effettivamente un tipo la cui interpretazione semantica è che il contenuto della variabile è un indirizzo. Nota ovviamente che ci sono due indirizzi, c'è l'indirizzo del puntatore (cioè dove è memorizzata la variabile) e l'indirizzo a cui fa riferimento il puntatore (i dati effettivi all'indirizzo della variabile). Un puntatore è un tipo di riferimento .
Luke Mathieson,

Risposte:


8

La tua domanda è interessante in diversi modi, in quanto richiede attente distinzioni per diversi problemi. Ma la tua visione mi sembra sostanzialmente corretta. Non ho letto il tuo riferimento prima di scrivere la maggior parte di questa risposta per evitare di distorcere la mia risposta.

Innanzitutto, la tua affermazione Variables are symbolic names for memory addressesè quasi corretta, ma confonde il concetto e la sua normale implementazione. Una variabile è in realtà solo un contenitore che può contenere un valore che può essere modificato. Di solito, questo contenitore è implementato su un computer come un blocco di spazio di memoria, caratterizzato da un indirizzo e una dimensione poiché le variabili possono contenere oggetti che richiedono rappresentazioni con più o meno informazioni.

Ma considererò principalmente un punto di vista più astratto della semantica delle lingue, indipendentemente dalle tecniche di implementazione.

Quindi le variabili sono solo contenitori da un punto di vista astratto. Un tale contenitore non deve avere un nome. Tuttavia, le lingue spesso hanno variabili che sono nominate associando ad esso un identificatore, in modo che gli usi della variabile possano essere espressi dall'identificatore. Una variabile può effettivamente avere diversi identificatori attraverso vari meccanismi di aliasing. Una variabile può anche essere una sottoparte di una variabile più grande: un esempio è una cella di una variabile di matrice, che può essere denominata specificando la variabile di matrice e l'indice della cella, ma potrebbe anche essere associata agli identificatori tramite l'aliasing.

Sto deliberatamente usando la parola contenitore che è in qualche modo neutra, per evitare di invocare altre parole che possono essere caricate semanticamente tecnicamente. In realtà è vicino al concetto di riferimento descritto in Wikipedia , che è spesso confuso con un indirizzo di memoria. Il puntatore di parole stesso è spesso inteso come un indirizzo di memoria, ma non penso che sia significativo quando si considerano la maggior parte delle lingue di alto livello e probabilmente inappropriato nel documento di discussione a cui si fa riferimento (sebbene gli indirizzi possano essere utilizzati), poiché è inappropriato riferendosi ad un'implementazione specifica. Tuttavia, è appropriato per un linguaggio come C, che dovrebbe essere molto più vicino ai concetti di implementazione e all'architettura della macchina.

In realtà, se si osservano variabili o valori a livello di implementazione, potrebbero esserci diversi sistemi complessi di indiretta, di "puntatori a livello di macchina", ma che sono (e dovrebbero essere) invisibili all'utente, in modo che il punto di vista astratto Lo sviluppo può essere valido. Per la maggior parte dei linguaggi di programmazione, l'utente non dovrebbe preoccuparsi, o addirittura conoscere, l'implementazione, poiché l'implementazione può variare molto per un determinato linguaggio. Questo potrebbe non essere vero per alcuni linguaggi, come C, intenzionalmente vicini all'architettura della macchina, come sostituto avanzato di linguaggi di assemblaggio che sono in relazione quasi diretta con la codifica binaria esplicita, ma di livello troppo basso per un uso conveniente nella maggior parte situazioni.

Ciò che l'utente di una lingua dovrebbe sapere, e talvolta dovrebbe essere anche inferiore a quello, sono quali sono i valori e le operazioni associate, dove possono essere contenuti, come possono essere associati ai nomi, come funziona il sistema di denominazione, come può essere nuovo tipi di valori da definire, ecc.

612

L'associazione di un valore immutabile a un identificatore viene generalmente chiamata costante. I Litterali sono costanti in questo senso.

I "contenitori di valori" possono anche essere considerati come valori e la loro associazione con un identificatore è una variabile nel solito senso "ingenuo" che si sta utilizzando. Quindi potresti dire che una variabile è una "costante contenitore".

Ora potresti chiederti quale sia la differenza tra l'associazione di un identificatore a un valore (dichiarazione costante) o l'assegnazione di un valore a una variabile, ovvero la memorizzazione del valore nel contenitore definito come costante del contenitore. In sostanza, la dichiarazione può essere vista come un'operazione che definisce una notazione, che associa un identificatore che è un'entità sintattica a un valore che è un'entità semantica. L'assegnazione è un'operazione puramente semantica che modifica uno stato, ovvero modifica il valore di un contenitore. In un certo senso, la dichiarazione è un meta concetto senza alcun effetto semantico, oltre a fornire un meccanismo di denominazione (cioè sintattico) per le entità semantiche.

In realtà, le assegnazioni sono operazioni semantiche che si verificano in modo dinamico durante l'esecuzione del programma, mentre le dichiarazioni hanno una natura più sintattica e di solito devono essere interpretate nel testo del programma, indipendentemente dall'esecuzione. Questo è il motivo per cui l'ambito statico (ovvero l'ambito testuale) è di solito il modo naturale di comprendere il significato degli identificatori.

Dopotutto, posso dire che un valore di puntatore è solo un altro nome per un contenitore e una variabile di puntatore è una variabile di contenitore, cioè un contenitore (costante) che può contenere un altro contenitore (con possibili limitazioni sul gioco contenitore imposto da alcuni tipo di sistema).

Per quanto riguarda il codice, dichiari [pointers] might indicate the entry point to a section of code and can be used to call that code. In realtà questo non è del tutto vero. Una sezione di codice è spesso insignificante da sola (dal punto di vista di alto livello o di implementazione). Da un punto di vista di alto livello, il codice di solito contiene identificatori e devi interpretarli nel contesto statico in cui sono stati dichiarati. Ma in realtà esiste una possibile duplicazione dello stesso contesto statico, dovuta essenzialmente alla ricorsione che è un fenomeno dinamico (runtime) e il codice può essere eseguito solo in un'istanza dinamica appropriata del contesto statico. Questo è un po 'complesso, ma la conseguenza è che il concetto corretto è quello di una chiusura che associa un pezzo di codice e un ambiente in cui gli identificatori devono essere interpretati. La chiusura è il giusto concetto semantico, cioè è un valore semantico correttamente definibile. Quindi puoi avere costanti di chiusura, variabili di chiusura,

Una funzione è una chiusura, di solito con alcuni parametri per definire o inizializzare alcune delle sue entità (costanti e variabili).

Salto molte variazioni sull'uso di questi meccanismi.

Le chiusure possono essere utilizzate per definire strutture OO in linguaggi imperativi o funzionali. In realtà, i primi lavori sullo stile OO (probabilmente prima del nome) sono stati fatti in questo modo.

Il documento a cui fai riferimento, che ho sfogliato rapidamente, sembra essere interessante, scritto da una persona competente, ma probabilmente non è una lettura facile se non hai un'esperienza significativa con una varietà di lingue e i loro modelli computazionali sottostanti.

Ma ricorda: molte cose sono negli occhi di chi guarda, purché conservi una visione coerente. I punti di vista possono differire.

Questo risponde alla tua domanda?

PS: questa è una risposta lunga. Se ritieni che una parte di esso sia inadeguata, ti preghiamo di essere esplicito su quale sia. Grazie.


Ho dovuto leggerlo alcune volte, ma penso che risponda alla mia domanda, sì. Sebbene le mie definizioni siano troppo incentrate sull'implementazione, l'idea che un puntatore sia un tipo particolare di variabile sembra essere accurata, ovvero "un valore di puntatore è solo un altro nome per un contenitore e una variabile di puntatore è una variabile di contenitore" Dove non ottenere la distinzione che si fa è tra un puntatore contenente l'indirizzo di un blocco di codice ed essere un contenitore che contiene un contenitore che contiene una chiusura. La distinzione tra quella di un contesto statico e quella di un programma è in esecuzione?
NectarSoft,

1
@NectarSoft La distinzione è solo tra blocco di codice e chiusura. Quello che sto dicendo è che, di per sé, isolato da qualsiasi contesto, un blocco di codice di solito non significa nulla. Se ti dico che " se i math rath sono più grandi dei borogoves, allora i toves si contorcono ", la frase non significa nulla perché ti manca il contesto in cui sono definiti tutti questi concetti. Questo contesto statico è generalmente il testo che racchiude il frammento di codice. Il problema è che questo stesso contesto statico può avere diverse istanze di runtime e il frammento di codice deve fare riferimento solo a una di esse.
babou,

1
@NectarSoft (continua) Quindi il valore di chiusura è l'associazione del frammento di codice e un'istanza dinamica di contesto statico che dà significato a questo frammento. Un'associazione dello stesso frammento di codice con un'istanza dinamica diversa dello stesso contesto statico fornisce una chiusura diversa. In genere, il codice può utilizzare una variabile appartenente al contesto, ma sarà una variabile diversa per ogni istanza dinamica del contesto, sebbene il suo nome (definito staticamente) rimanga lo stesso. Ciò chiarisce il problema o devo creare un esempio nella risposta (il formato dei commenti è vincolato)?
babou,

Chiarisce la questione, grazie, mentre sollevo altre domande sulle quali passerò del tempo a riflettere. Ad esempio, se è necessario un puntatore distinto per ogni chiusura, sembra che il puntatore diventi parte del contesto dinamico e quindi appartenga alla chiusura! Mi chiedo anche i limiti di chiusura e la gerarchia di chiusura, poiché ognuno di questi contesti associati a un blocco di codice statico e referenziati da un puntatore sarà necessariamente una variabile in una sua chiusura. Tutto questo è fuori tema, quindi farò un po 'di lettura e forse farò un'altra domanda quando
rimarrò

@NectarSoft In realtà. quando si crea una chiusura, si tenta di limitare il contesto associato al codice a ciò che è necessario per dare un significato adeguato a quel codice (fino ad alcuni vincoli pratici per evitare la micro-gestione delle informazioni). Questo può essere deciso staticamente.
babou,

2

La differenza è per definizione e applicazione, un puntatore è una variabile specializzata per contenere un indirizzo di memoria di un'altra variabile; in termini di OO un puntatore potrebbe forse essere considerato ereditare il suo comportamento da una classe generale chiamata variabile.

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.