Perché due riferimenti allo stesso vettore restituiscono indirizzi di memoria diversi per ciascun elemento del vettore?


9

Sto imparando R e attualmente sto leggendo questo libro . Per essere sicuro di aver compreso il concetto, ho eseguito il seguente test che si è rivelato abbastanza confuso per me e apprezzerei se tu potessi chiarirlo. Ecco il test, che ho eseguito direttamente nella shell R dal terminale (non usando RStudio o Emacs ESS).

> library(lobstr)
>
> x <- c(1500,2400,8800)
> y <- x
> ### So the following two lines must return the same memory address
> obj_addr(x)
[1] "0xb23bc50"
> obj_addr(y)
[1] "0xb23bc50"
> ### So as I expected, indeed both x and y point to the same memory 
> ### location: 0xb23bc50
>
>
>
> ### Now let's check that each element can be referenced by the same
> ### memory address either by using x or y
> x[1]
[1] 1500
> y[1]
[1] 1500
> obj_addr(x[1])
[1] "0xc194858"
> obj_addr(y[1])
[1] "0xc17db88"
> ### And here is exactly what I don't understand: x and y point 
> ### to the same memory address, so the same must be true for 
> ### x[1] and y[1]. So how come I obtain two different memory
> ### addresses for the same element of the same vector?
>
>
>
> x[2]
[1] 2400
> y[2]
[1] 2400
> obj_addr(x[2])
[1] "0xc15eca0"
> obj_addr(y[2])
[1] "0xc145d30"
> ### Same problem!
>
>
>
> x[3]
[1] 8800
> y[3]
[1] 8800
> obj_addr(x[3])
[1] "0xc10e9b0"
> obj_addr(y[3])
[1] "0xc0f78e8"
> ### Again the same problem: different memory addresses

Potresti dirmi dove è il mio errore e cosa ho frainteso in questo problema?


1
Non conosco R ma in altre lingue hai valore e tipi di riferimento. Se intero è di tipo valore come in C ++ o C #, qualsiasi assegnazione creerà un nuovo numero intero. Quindi ogni numero intero avrà il proprio indirizzo.
Ostello

1
In effetti, anche eseguirlo obj_addr(x[1])due volte dovrebbe darti risultati diversi, poiché ogni nuovo numero intero avrà il suo indirizzo.
Bas

@Bas Ho testato ciò che hai menzionato, ovvero eseguendo in successione obj_addr (x [1]), e in effetti facendo ciò, R restituisce ogni volta un risultato diverso (indirizzo di memoria diverso). Ma non capisco perché, perché a me sembra che non assegni nulla, quindi non creo un nuovo oggetto (per il quale ovviamente ci sarà un nuovo indirizzo poiché gli oggetti sono immutabili in R). Per me obj_addr (x [1]) significa che sto solo leggendo un oggetto già esistente.
user17911

Risposte:


5

Qualsiasi oggetto R è un C (puntatore-chiamato SEXP- a) "multi-oggetto" ( struct). Ciò include le informazioni (che R deve operare, ad esempio il lengthnumero di riferimenti - per sapere quando copiare un oggetto - e altro) sull'oggetto R e, inoltre, i dati effettivi dell'oggetto R a cui abbiamo accesso.

lobstr::obj_addr, presumibilmente, restituisce l'indirizzo di memoria a cui SEXPpunta un . Quella parte della memoria contiene sia le informazioni che i dati dell'oggetto R. Dall'interno dell'ambiente R non è possibile / non è necessario accedere alla memoria (puntatore alla) dei dati effettivi in ​​ciascun oggetto R.

Come Adam osserva nella sua risposta, la funzione [ copia l'ennesimo elemento dei dati contenuti nell'oggetto C in un nuovo oggetto C e restituisce il SEXPpuntatore a R. Ogni volta che [viene chiamato, viene creato un nuovo oggetto C e restituito a R.

Non possiamo accedere all'indirizzo di memoria di ciascun elemento dei dati effettivi del nostro oggetto tramite R. Ma giocando un po ', possiamo tracciare i rispettivi indirizzi usando l'api C:

Una funzione per ottenere gli indirizzi:

ff = inline::cfunction(sig = c(x = "integer"), body = '
             Rprintf("SEXP @ %p\\n", x);

             Rprintf("first element of SEXP actual data @ %p\\n", INTEGER(x));

             for(int i = 0; i < LENGTH(x); i++) 
                 Rprintf("<%d> @ %p\\n", INTEGER(x)[i], INTEGER(x) + i);

             return(R_NilValue);
     ')

E applicando ai nostri dati:

x = c(1500L, 2400L, 8800L)  #converted to "integer" for convenience
y = x

lobstr::obj_addr(x)
#[1] "0x1d1c0598"
lobstr::obj_addr(y)
#[1] "0x1d1c0598"

ff(x)
#SEXP @ 0x1d1c0598
#first element of SEXP actual data @ 0x1d1c05c8
#<1500> @ 0x1d1c05c8
#<2400> @ 0x1d1c05cc
#<8800> @ 0x1d1c05d0
#NULL
ff(y)
#SEXP @ 0x1d1c0598
#first element of SEXP actual data @ 0x1d1c05c8
#<1500> @ 0x1d1c05c8
#<2400> @ 0x1d1c05cc
#<8800> @ 0x1d1c05d0
#NULL

La successiva differenza di memoria tra gli elementi di dati del nostro oggetto è uguale alla dimensione del inttipo:

diff(c(strtoi("0x1d1c05c8", 16), 
       strtoi("0x1d1c05cc", 16), 
       strtoi("0x1d1c05d0", 16)))
#[1] 4 4

Utilizzando la [funzione:

ff(x[1])
#SEXP @ 0x22998358
#first element of SEXP actual data @ 0x22998388
#<1500> @ 0x22998388
#NULL
ff(x[1])
#SEXP @ 0x22998438
#first element of SEXP actual data @ 0x22998468
#<1500> @ 0x22998468
#NULL

Questa potrebbe essere una risposta più che necessaria ed è semplicistica sui tecnicismi reali, ma, si spera, offre un quadro più "chiaro" più chiaro.


Eccezionale! Ti ringrazio davvero molto per una spiegazione così dettagliata e chiara per persone come me che sono completamente principianti in R. Inoltre, il tuo esempio è molto impressionante nel mostrare la flessibilità di R e le sue possibili potenti interazioni con altri linguaggi di programmazione. Mille grazie per il tuo tempo e il tuo aiuto.
user17911

3

Questo è un modo per vederlo. Sono sicuro che esiste una visione più tecnica. Ricorda che in R, quasi tutto è una funzione. Questo include la funzione di estratto, [. Ecco un'affermazione equivalente a x[1]:

> `[`(x, 1)
[1] 1500

Quindi quello che stai facendo è eseguire una funzione che restituisce un valore (check out ?Extract). Quel valore è un numero intero. Quando si esegue obj_addr(x[1]), si sta valutando la funzione x[1]e quindi si dà la obj_addr()di quel ritorno funzione, non l'indirizzo del primo elemento della matrice che si vincolato ad entrambi xe y.


Grazie mille per il vostro aiuto e la vostra attenzione al mio problema. In effetti questo è ciò che non sapevo, cioè recuperare un valore con "Estrai" crea effettivamente un nuovo oggetto. Come ho già detto, sono davvero un principiante in R! Grazie mille per il tuo tempo e la tua descrizione.
user17911
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.