DOMANDA Ambito delle variabili, concetto di "scope", passaggio dei parametri per valore, right-value e left-value di una variabile

Stato
Discussione chiusa ad ulteriori risposte.

MPG

Utente Attivo
544
4
Visto le mie difficoltà qualcuno puo' riassumermi alcuni concetti su questi argomenti:
"Ambito delle variabili, concetto di "scope", passaggio dei parametri per valore, right-value e left-value di una variabile"
Il mio libro non è molto ben fatto e la spiegazione è troppo veloce per me..
Grazie a tutti.
 
Ultima modifica:

_Achille

Utente Èlite
3,067
725
CPU
Intel i5-6600K @4.6 GHz
Dissipatore
Cryorig H5
Scheda Madre
ASRock Z170 Extreme 6
HDD
WesternDigital 1TB & Crucial MX200 250GB
RAM
Corsair Ven 16GB DDR4 2133MHz
GPU
Sapphire RX 580 Nitro+
Monitor
Dell S2418H
PSU
RM550X
Case
NZXT S340
Periferiche
Anne Pro 2, Razer Abyssus
OS
Windows 10 Pro
Sono cose che basta googlare.
Scope -> ambito di visibilità.
Passaggio per valore -> normale passaggio che viene effettuato a meno di reference, rvalue-reference o puntatori.
Left-value -> tutto ciò che può stare a sinistra (es. variabili non const, funzioni che ritornano un riferimento).
Right-value -> tutto ciò che sta solo a destra (es. costanti tipo numeri, stringhe, funzioni che ritornano un valore)
 

MPG

Utente Attivo
544
4
Si ma volevo una maggiore chiarezza con esempi non solo delle definizioni per capire meglio....
 

BAT

Moderatore
Staff Forum
Utente Èlite
22,907
11,558
CPU
1-Neurone
Dissipatore
Ventaglio
RAM
Scarsa
Net
Segnali di fumo
OS
Windows 10000 BUG
Variabile = un contenitore di dati identificato da un tipo un nome. Esempio:
int a;
dichiara una variabile chiamata "a" il cui tipo è un intero, quindi contiene solo valori interi.
l'assegnazione
a = 10;
scrive (in binario naturalmente) nella cella di memoria di a il valore 10;
adesso scriviamo l'espressione
a = a + 5;
si distinguono 2 parti a seconda della posizione dell'=
  1. left-value (valore a sinistra) a: è la parte a sinistra dell'assegnazione; rappresenta il nome simbolico della variabile e ti dice "esiste in memoria una cella di memoria che simbolicamente identifichiamo con l'etichetta a (sotto-sotto tale etichetta è un indirizzo di memoria)
  2. right-value (valore a destra) a + 5; : è la parte a destra dell'assegnazione e contienre VALORI; la "a" a destra è 10, ossia è il CONTENUTO della cella di memoria la cui etichetta è "a".
  3. l'effetto dell'istruzione a = a + 5; è copiare in un registro della CPU il valore 10 (la a sulla destra dell'uguale), copiare in un altro registro il valore 5, eseguire la somma (eventualmente) in un altro registro ottenendo il valore 15. Infine copia il valore 15 come nuovo valore contenuto nella cella di memoria relativa alla variabile a (quella a sinistra).
In breve, il left-value è l'etichetta di un indirizzo, il right-value è il contenuto nella cella di memoria di quell'indirizzo.

Lo SCOPE (raggio/campo d'azione o visibilità) di una variabile è la porzione di codice (in questo caso C++) all'interno di cui essa è utilizzabile;
lo scope di una variabile inizia dalla sua dichiarazione, finisce nel blocco di codice in cui è dichiarata
C++:
int main() {
    int a=10;
    for(int i=0; i<a; i++){
        cout << " a = " << a << endl; // OK
        cout << " i = " << i << endl;
    }
    cout << " a = " << a << endl; // OK
    cout << " i = " << i << endl; // ERRORE, NON COMPILA: i visibile solo nel for
    return 0;
}

Le funzioni sono definite da un nome, un tipo di ritorno (eventualmente void), una lista di parametri ciascuno con un tipo;
tutto cià si chiama "firma" della funzione. Poi ovviamente segue il corpo della funzione ossia le istruzioni.
I parametri della firma si chiamano PARAMETRI FORMALI: significa che, quando si chiama la funzione su certi valori la funzione li identifica formalmente con i nomi di variabile definita nel suo codice. Esempio:
C++:
#include <iostream>
using namespace std;

int sommaInt(int a, int b) // FIRMA
{ // inizio corpo
    return a+b; // corpo:
} // fine corpo

int main() {
    int x, y;
    cout << "Inserisci x --> ";
    cin >> x;
    cout << "Inserisci y --> ";
    cin >> y;
    int somma = sommaInt(x,y);
    cout << x << " + " << y << " = " << somma << endl; // OK
    return 0;
}
In questo semplice programma definisco 2 variabili intere chiamate x ed y;
il programma le legge e le memorizza in celle di memoria etichettate simbolicamente x ed y;
l'istruzione
int somma = sommaInt(x,y);
  1. definisce una variabile intera somma e le riserva una cella di memoria
  2. chiama la funzione sommaInt sui VALORI di x ed y: i valori si chiamano PARAMETRI ATTUALI perché sono quelli che in questo momento verranno manipolati dalla funzione. La funzione INTERNAMENTE fa una corrispondenza tra i parametri che le vengono passati: esegue una COPIA di x e lo indica con a (parametro formale) all'interno del proprio codice, poi fa una COPIA di y e lo indica con b;. Quindi internamente alla funzione si calcola a+b cioè x+y, il risultato è ritornato come intero e copiato nella cella di memoria di somma.
Adesso immagina di modificare il main, usando a e b al posto di x ed y.
C++:
int main() {
    int a, b; // sono differenti da quelli di sommaInt
    cout << "Inserisci a --> ";
    cin >> a;
    cout << "Inserisci b --> ";
    cin >> b;
    int somma = sommaInt(a,b);
    cout << a << " + " << b << " = " << somma << endl; // OK
    return 0;
}
Non cambia nulla: a e b nel main quando sono passati alla funzione vengono ricopiati in 2 nuove celle di memoria che SIMBOLICAMENTE noi umani indichiamo ancora con a e b, ma il programma in realtà usa indirizzi binari differenti (non lettere) per cui non farà mai confusione.
 
Ultima modifica:
  • Mi piace
Reazioni: Lux90

MPG

Utente Attivo
544
4
Caspita ma sei un professore? Complimenti per la spiegazione!!
Ho solo un dubbio sulla definizione "passaggio dei parametri per valore".
 

BAT

Moderatore
Staff Forum
Utente Èlite
22,907
11,558
CPU
1-Neurone
Dissipatore
Ventaglio
RAM
Scarsa
Net
Segnali di fumo
OS
Windows 10000 BUG
te l'ho appena spiegato: passaggio per valore significa semplicemente che quando passi i parametri ad una funzione gli passi dei valori di cui la funzione fa una copia (per non modificare i valori originali che gli hai passato).
Il C++ supporta poi il passaggio per riferimento (passa l'indirizzo di una variabile) che può alterare il contenuto della variabile originale.
 

MPG

Utente Attivo
544
4
Scusami ma questo che avevo fatto pochi giorni fa è sbagliato scritto cosi':
/*scrivere una funzione che, presi tre
parametri double B,b,h, stampa a video
l'area del trapezio*/


Codice:
#include <iostream>
#include <ctime>
#include<cstdlib>
#include <chrono>


using namespace std;
using namespace chrono;


double B;
double b;
double h;
double area;

void areatrapezio ()

{
cout<< "inserisci base maggiore  ";
cin>>B;
cout<< "inserisci base minore  ";
cin>>b;
cout<< "inserisci altezza  ";
cin>>h;
area=((B+b)*h)/2;
cout<<"l'area del trapezio e': " <<area<<endl;
}



int main()
{

    areatrapezio();

}
Post unito automaticamente:

Sarebbe meglio cosi' ?

Codice:
include <iostream>

using namespace std;



double areatrapezio (double b, double B, double h)
{
    return ((B+b)*h)/2;
}


    int main() {
   {

    double B,b,h;
    cout << "Inserisci b --> ";
    cin >> b;
    cout << "\nInserisci B --> ";
    cin >> B;
    cout << "Inserisci h --> ";
    cin >> h;
    double area = areatrapezio (b,B,h);
    cout << area<< endl;

    return 0;
}
    }
 
Ultima modifica:

_Achille

Utente Èlite
3,067
725
CPU
Intel i5-6600K @4.6 GHz
Dissipatore
Cryorig H5
Scheda Madre
ASRock Z170 Extreme 6
HDD
WesternDigital 1TB & Crucial MX200 250GB
RAM
Corsair Ven 16GB DDR4 2133MHz
GPU
Sapphire RX 580 Nitro+
Monitor
Dell S2418H
PSU
RM550X
Case
NZXT S340
Periferiche
Anne Pro 2, Razer Abyssus
OS
Windows 10 Pro
Scusami ma questo che avevo fatto pochi giorni fa è sbagliato scritto cosi':
/*scrivere una funzione che, presi tre
parametri double B,b,h, stampa a video
l'area del trapezio*/


Codice:
#include <iostream>
#include <ctime>
#include<cstdlib>
#include <chrono>


using namespace std;
using namespace chrono;


double B;
double b;
double h;
double area;

void areatrapezio ()

{
cout<< "inserisci base maggiore  ";
cin>>B;
cout<< "inserisci base minore  ";
cin>>b;
cout<< "inserisci altezza  ";
cin>>h;
area=((B+b)*h)/2;
cout<<"l'area del trapezio e': " <<area<<endl;
}



int main()
{

    areatrapezio();

}
Post unito automaticamente:

Sarebbe meglio cosi' ?

Codice:
include <iostream>

using namespace std;



double areatrapezio (double b, double B, double h)
{
    return ((B+b)*h)/2;
}


    int main() {
   {

    double B,b,h;
    cout << "Inserisci b --> ";
    cin >> b;
    cout << "\nInserisci B --> ";
    cin >> B;
    cout << "Inserisci h --> ";
    cin >> h;
    double area = areatrapezio (b,B,h);
    cout << area<< endl;

    return 0;
}
    }
Andrebbe fatto così a meno di saper usare i reference.
 

MPG

Utente Attivo
544
4
Non so cosa siano i reference..
comunque va bene il secondo postato giusto?
Post unito automaticamente:

 
Ultima modifica:

DispatchCode

Moderatore
Staff Forum
Utente Èlite
2,222
1,853
CPU
Intel I9-10900KF 3.75GHz 10x 125W
Dissipatore
Gigabyte Aorus Waterforce X360 ARGB
Scheda Madre
Asus 1200 TUF Z590-Plus Gaming ATX DDR4
HDD
1TB NVMe PCI 3.0 x4, 1TB 7200rpm 64MB SATA3
RAM
DDR4 32GB 3600MHz CL18 ARGB
GPU
Nvidia RTX 3080 10GB DDR6
Audio
Integrata 7.1 HD audio
Monitor
LG 34GN850
PSU
Gigabyte P850PM
Case
Phanteks Enthoo Evolv X ARGB
Periferiche
MSI Vigor GK30, mouse Logitech
Net
FTTH Aruba, 1Gb (effettivi: ~950Mb / ~480Mb)
OS
Windows 10 64bit / OpenSUSE Tumbleweed
Non so cosa siano i reference..
comunque va bene il secondo postato giusto?
Post unito automaticamente:

I reference li vedrete tra poco.

Si, va bene. Ma devi capirne la logica, poiché in un caso un po' differente devi giungere comunque ad una soluzione.
 

pabloski

Utente Èlite
2,868
916
Non so cosa siano i reference..

Se vuoi capire cosa sono i reference, che poi è l'opposto del passaggio per valore, cosa faresti se io t'imponessi di scrivere la funzione areatrapezio così?

C++:
void areatrapezio (double b, double B, double h)

Considera che a questo punto non hai modo di ritornare il valore dell'area tramite return. L'unica possibilità, senza usare variabili globali, è questa

C++:
void areatrapezio (double b, double B, double h, double &a)

{

    a = ((B+b)*h)/2;

}

Notato quello strano simbolo vicino al nome della variabile a? Quello indica un passaggio per riferimento ( reference, l'opposto del passaggio per valore ) e passa alla funzione non un numero ma l'indirizzo della variabile

C++:
double area;
areatrapezio (b,B,h,area);

Con questo giochino la funzione areatrapezio può andare a scrivere nella variabile area che è definita nel main. Cioè accede ad una variabile fuori dal suo scope.

Ovvero quando assegna il risultato alla variabile a, sta scrivendo in realtà in area. La variabile a funziona come un alias della variabile area.
 
U

Utente 16812

Ospite
Visto le mie difficoltà qualcuno puo' riassumermi alcuni concetti su questi argomenti:
"Ambito delle variabili, concetto di "scope", passaggio dei parametri per valore, right-value e left-value di una variabile"
Il mio libro non è molto ben fatto e la spiegazione è troppo veloce per me..
Grazie a tutti.

Farò riferimento al Pascal ma il concetto è generale ;)
Puoi pensare ad un programma come ad una gerarchia di procedure: al livello più alto ci sono quelle da affinare, al livello più basso quelle completamente affinate :sisi:
Ok … quindi la struttura di un programma consiste in una serie di sottoprogrammi (eventualmente annidati) :sisi:
Ora, di solito gli oggetti che vengono dichiarati all'interno del sottoprogramma hanno significato solo nell'ambito del sottoprogramma stesso.
Negli altri casi le dichiarazioni vengono effettuate nella parte dichiarativa del programma stesso.
Dunque nell'ambito di un sottoprogramma possono esistere due tipi di oggetti: quelli LOCALI e quelli GLOBALI (qualcuno li definisce anche NON LOCALI).
Gli oggetti locali possono essere costanti, variabili, ecc., definiti nella parte dichiarativa del sottoprogramma.
Gli oggetti globali vengono definiti nell'ambiente della procedura.
In particolare gli oggetti globali vengono definiti nel MAIN del programma mentre gli oggetti non locali sono definiti nei sottoprogrammi di livello superiore.
Tieni conto che questa distinzione che ho voluto puntualizzare non viene più usata, per cui si parla indifferentemente di oggetti globali o non locali.
Riassumendo, ciascun identificatore ha un suo SCOPE, ossia un CAMPO DI VALIDITA' in cui, per quanto possa essere ristretto, è riconosciuto e usato.
Possiamo dire che lo "scope" è quella subroutine in cui l'oggetto è stato dichiarato, nel caso però di subroutine annidate la faccenda si complica :asd:
Quello che dobbiamo fare in questo caso è definire delle regole precise per determinare lo scope di oggetti locali, non locali e globali del programma :sisi:
Spero di aver contribuito a chiarire meglio i termini della questione posta :look:
A presto ;)
Post unito automaticamente:

Caspita ma sei un professore? Complimenti per la spiegazione!!
Ho solo un dubbio sulla definizione "passaggio dei parametri per valore".

Come sai, uno dei motivi per cui le subroutine sono largamente utilizzate è quello di evitare di riscrivere intere parti di programma :sisi:
Ora, soprattutto nel caso di algoritmi complessi, non è raro trovare parti di programma in più punti assolutamente uguali nella logica, che operano su dati di valore diverso.
Ovviamente questo implica alcuni inconvenienti: errori di copiatura in primo luogo, operazioni di testing su tutte le "occorrenze" delle istruzioni in secondo luogo.
Per risolvere il problema ci viene in aiuto una "nuova" struttura: i parametri :asd:
I parametri sono oggetti che possiedono un identificatore, un tipo e un valore che verrà definito successivamente.
In modo del tutto intuitivo, possiamo dire che si scrivono le istruzioni della subroutine facendole "lavorare" su oggetti "fittizi": i cosiddetti PARAMETRI FORMALI.
Al momento della chiamata della subroutine si forniscono le indicazioni per effettuare le "corrispondenze" tra gli oggetti reali, cioè i PARAMETRI ATTUALI, e i parametri formali (che sono fittizi, come abbiamo detto).
In base a queste corrispondenze, la CPU attua la cosiddetta TRASMISSIONE DEI PARAMETRI, ossia sostituisce i parametri formali con quelli attuali :asd:
Si tratta di un passaggio completamente automatico e trasparente per il programmatore.
L'utilizzo dei parametri comporta evidenti vantaggi nella programmazione ma occorre innanzitutto individuare questi parametri, gli oggetti locali, non locali e globali, poi occorre anche dichiarare sia i parametri formali che quelli attuali e infine dare le indicazioni sulle corrispondenze per la sostituzione.
Sicuramente la sostituzione dei parametri costituisce, se vogliamo, il problema più impegnativo: dobbiamo trovare un modo più o meno semplice per dare alla CPU tutte le informazioni necessarie per la corretta attuazione della sostituzione dei parametri.
Possiamo considerare la sostituzione per nome (o per "valore") come quella di "default" per quanto riguarda il passaggio dei parametri.
Al momento della chiamata della subroutine la CPU riserva una zona di memoria per i parametri formali, poi questi parametri formali vengono inizializzati coi valori dei parametri attuali.
Da questo momento in poi i parametri attuali non vengono più considerati, la CPU lavora solo sui parametri formali, ossia sull'area di memoria ad essi riservata.
Ovviamente al rientro dalla subroutine l'area di memoria dedicata viene rilasciata.
In sintesi, il passaggio dei parametri per nome garantisce che il valore del parametro attuale non venga in alcun modo modificato dalla subroutine, in quanto la CPU lo utilizza soltanto per inizializzare l'area di memoria.
Ecco ... questo sistema è valido se il parametro è un argomento e non un risultato poiché in quest'ultimo caso andrebbe perso.
Se il parametro è un risultato della subroutine dovremo ricorrere alla trasmissione dei parametri per "referenza" :sisi:
A presto ;)

P.S. Faccio sempre riferimento al Pascal ma il concetto è generale :)
 
Ultima modifica da un moderatore:
Stato
Discussione chiusa ad ulteriori risposte.

Entra

oppure Accedi utilizzando
Discord Ufficiale Entra ora!

Discussioni Simili