C Domanda specifica per ambito variabile
-
07-07-2019 - |
Domanda
Ecco uno scenario particolare di cui non sono stato chiaro (in termini di ambito) da molto tempo.
considera il codice
#include <stdio.h>
typedef struct _t_t{
int x;
int y;
} t_t;
typedef struct _s_t{
int a;
int b;
t_t t;
}s_t;
void test(s_t & s){
t_t x = {502, 100};
s.t = x;
}
int main(){
s_t s;
test(s);
printf("value is %d, %d\n", s.t.x, s.t.y);
return 0;
}
l'output è
value is 502, 100
Quello che mi confonde un po 'è il seguente. La dichiarazione
t_t x
è dichiarato nell'ambito del test funzionale. Quindi, da quello che ho letto sulla programmazione in C, dovrebbe essere spazzatura fuori da questo ambito. Eppure restituisce un risultato corretto. È perché il " = " sulla linea s.t = x; copia i valori di x in s.t?
Modifica ---
dopo alcuni esperimenti
#include <stdio.h>
typedef struct _t_t{
int x;
int y;
} t_t;
typedef struct _s_t{
int a;
int b;
t_t t;
}s_t;
void test(s_t & s){
t_t x = {502, 100};
t_t * pt = &(s.t);
pt = &x;
}
int main(){
s_t s;
test(s);
printf("value is %d, %d\n", s.t.x, s.t.y);
return 0;
}
produce effettivamente
value is 134513915, 7446516
come previsto.
Soluzione
È perché il " = " sulla riga s.t = x; copia i valori di x in s.t?
Sì.
A proposito, questo è C ++. Hai superato il " s " da locale a principale come riferimento alla funzione, che la modifica. Poiché è un riferimento e non una copia, influisce sul "chiamante".
del chiamanteAltri suggerimenti
t_t x = {502, 100}; s.t = x;
Nel tuo primo test , stai istruendo il compilatore a copiare il valore di x
in st
- funziona come previsto. La variabile locale x
non rientra nell'ambito di applicazione, ma non viene mai referenziata al di fuori della funzione: i dati inizialmente contenuti vengono copiati nel membro t
di main ()
. Sarebbe effettivamente lo stesso se invece scrivessi: s
della variabile locale
t_t x = {502, 100};
s.t.x = x.x;
s.t.y = x.y;
Nel secondo test , si assegna un puntatore a un altro puntatore, entrambi dichiarati come variabili locali. Questo non fa nulla di utile - il valore in s.t
rimane non inizializzato. Ho annotato il codice per aiutarti a seguirlo:
t_t x = {502, 100}; // local variable x initialized with 502, 100
t_t * pt = &(s.t); // local variable pt initialized with ADDRESS OF s.t
pt = &x; // local variable pt re-assigned to hold address of local variable x
// local variables go out of scope, output parameter s remains unmodified
Leggi questo: Copia predefinita- costruttori e operatori di incarichi
Non fornendo un operatore di assegnazione, struct _s_t eseguirà una copia superficiale di tutti i suoi membri quando viene assegnato. Poiché stai memorizzando tutto in _t_t in base al valore, tutti i dati vengono copiati in base al valore.
Il problema che stai descrivendo è quando _t_t contiene un puntatore ai dati.
nel caso:
typedef struct _s_t{
int a;
int b;
t_t* t;
}s_t;
void test(s_t & s){
t_t x = {502, 100};
s.t = &x;
}
Ciò causerebbe un problema, poiché t_t verrebbe distrutto alla fine di test () a quel punto quel puntatore non sarebbe valido.
ETA: perché hai aggiunto altro alla domanda ...
void test(s_t & s){
t_t x = {502, 100};
t_t * pt = &(s.t);
pt = &x;
}
Qui hai creato un problema diverso. Quello che è successo lì è che hai creato un puntatore all'indirizzo di s.t, che va bene. Tuttavia, hai quindi riassegnato quel puntatore in modo che punti a x (questo compito, non ha fatto nulla per s.t, stai solo cambiando ciò a cui punta il puntatore pt) Il motivo per cui l'output è "come previsto" è perché stai solo leggendo lo stato non inizializzato della struttura.
Hai ragione, la linea
s.t = x;
copierà i valori.
Un'assegnazione copia il valore da una variabile a un'altra variabile. Quindi, sebbene la x locale originale sia sparita, ne hai una copia in s.
Sarebbe abbastanza diverso quando hai appena assegnato un puntatore a x:
typedef struct _s_t{
int a;
int b;
t_t* t;
}s_t;
void test(s_t & s){
t_t x = {502, 100};
s.t = &x;
}
Quindi avresti un problema: hai solo l'indirizzo di x ma x non c'è più. Quindi hai effettivamente un riferimento a una posizione di memoria non valida. Il comportamento di questo programma sarebbe allora indefinito.