Delucidazioni funzioni c++

Michelejdk1997
Buongiorno ragazzi, ho alcuni dubbi sull'uso delle funzioni in c++
1)qual è la differenza tra sostituzione per valore e sostituzione per riferimento?
2)perchè gli array non possono essere passati per riferimento?
3)perchè negli array bidimensionali bisogna specificare solo la grandezza della seconda dimensione?
4)perchè si usano i prototipi di funzioni?ho capito che bisogna dichiarare i prototipi per evitare un side effect, ciò che non mi è chiaro è il motivo per il quale senza i prototipisi avrebbe un funzionamento non corretto del nostro programma.
scusate per il disturbo.

Risposte
Luc@s
Pensala a livello di business deal
Il prototipo e' un contratto.
Senza contratto come puoi dire cosa e' valido e cosa no?

Michelejdk1997
si più o meno mi è chiaro
dobbiamo anticipare al compilatore quali funzioni andremo ad usare, giusto?

Luc@s
Nei file .h di solito.

Michelejdk1997
per quanto riguarda la prima domanda un mio compagno di corse ha dato la seguente risposta:
quando "lavori" per valore "lavori" su una copia, mentre se "lavori" per riferimento alla fine della funzione il valore cambia.
E' corretta come risposta?(anche se un po' semplicistica)

Luc@s
A livello base si.
Il riferimento non copia e' abbastanza vero

Michelejdk1997
"Luc@s":
A livello base si.
Il riferimento non copia e' abbastanza vero

okok grazie mille

Giux1
"michele1239":

1)qual è la differenza tra sostituzione per valore e sostituzione per riferimento?


Sarebbe più corretto dire passaggio per valore e passaggio per riferimento, in ogni caso
Quando passi un dato per valore ad una funzione(di solito è l'approccio standard del C++) in realtà
stai operando con una copia del dato stesso nel contesto di una funzione, quindi tutto cio che farai con il parametro
non avrà ripercussioni sul dato originale

Se invece passi un riferimento con l'aggiunta dell'operatore $&$ oppure (se usi lo stile C)
e passi dei puntatori espliciti con l'operatore * stai passando proprio l'indirizzo dell'area di memoria in cui è stata allocata la variabile, di conseguenza se agisci sulla variabile stai modificando (per aliasing) il dato originale

Esempio di passaggio per valore
in questo caso lo cambio avviene localmente nella funzione
quindi x ed y nel main rimangono tali
int swap(int a, int b){
   int temp = a;
   a = b;
   b = temp;
}

int main(void)
{
   int x = 3, y = 4;
   swap(x, y); // sto passando una copia di x ed y
   return 0;
}



In questo caso il compilatore si aspetta dei puntatori
quindi la funzione opera direttamente con le variabili x ed y del main
che risultano scambiate correttamente
int swap(int *a, int *b){
   int temp = *a;
   *a = *b;
   *b = temp;
}

int main(void)
{
   int x = 3, y = 4;
   swap(&x, &y); // sto passando un riferimento di x ed y
   return 0;
}


"michele1239":

2)perchè gli array non possono essere passati per riferimento?


Il discordo degli array è un po complicato per via di alcune sottigliezze che il C++ ha ereditato dal C
Come saprai il nome di un array in C ed anche in C++ corrisponde all'indirizzo della prima cella dell'array stesso
(questo perchè in memoria gli array vengono memorizzati in locazioni contigue, e quindi si puo far uso dell'aritmetica dei puntatori in modo naturale e semplice) tuttavia
Quando passi un array ad una funzione gli stai passando una copia dell'indirizzo della prima cella. Quindi qui bisogna fare attenzione: gli array vengono passati implicitamente per riferimento(inteso come copia del puntatore alla prima cella dell'array).

"michele1239":

3)perchè negli array bidimensionali bisogna specificare solo la grandezza della seconda dimensione?


Per come ti dicevo sopra gli array come le matrici(che sono sempre array, però multidimensionali) vengono
memorizzati in memoria in celle contigue( praticamente la matrice è come se venisse allocata una riga dopo l'altra a partire dalla riga $0$, e proseguendo fino alla riga $n-1$)
Ebbene, ora il compilatore necessita per allocare correttamente la memoria di almeno $n-1$ dimensioni del tuo array
e nel caso delle matrici gli serve il numero delle colonne(per poter determinare quanto è grande una riga)
Questo perchè dietro le quinte l'aritmetica dei puntatori fa uso solo della dimensione delle righe, cioè del numero di colonne
che corrisponde alla seconda dimensione dell'array

"michele1239":

4)perchè si usano i prototipi di funzioni?ho capito che bisogna dichiarare i prototipi per evitare un side effect, ciò che non mi è chiaro è il motivo per il quale senza i prototipi si avrebbe un funzionamento non corretto del nostro programma.
scusate per il disturbo


Il discorso dei prototipi è storico nel C quindi nel C++ . Sono stati introdotti principalmente per
ridurre gli errori nel passaggio degli argomenti e per gestire i programmi di grandi dimensioni ma anche per motivi di efficienza nella compilazione.

Se definisci una funzione prima del main il programma dovrebbe andar bene lo stesso( e questo dipende dalla versione del tuo compilatore), in ogni caso è buona prassi dichiarare le funzioni mediante i prototipi perchè questo aiuta il compilatore
ad effettuare il debug alla ricerca di eventuali incongruenze nel passaggio dei parametri, e soprattutto quando più funzioni si chiamano tra loro. Il fatto che va in errore probabilmente è dovuto alle nuove restrizioni dei compilatori per le nuove versioni del C++... Infine il prototipo viene impiegato anche per gestire per l'overloading(sovraccarico) delle funzioni (cioè quando hai delle funzioni con lo stesso nome, ma con parametri differenti) le cosiddette "signature"

P.S. Nessun disturbo se vuoi altri chiarimenti, scrivi pure :-D

Michelejdk1997
"Giux":
[quote="michele1239"]
1)qual è la differenza tra sostituzione per valore e sostituzione per riferimento?


Sarebbe più corretto dire passaggio per valore e passaggio per riferimento, in ogni caso
Quando passi un dato per valore ad una funzione(di solito è l'approccio standard del C++) in realtà
stai operando con una copia del dato stesso nel contesto di una funzione, quindi tutto cio che farai con il parametro
non avrà ripercussioni sul dato originale

Se invece passi un riferimento con l'aggiunta dell'operatore $&$ oppure (se usi lo stile C)
e passi dei puntatori espliciti con l'operatore * stai passando proprio l'indirizzo dell'area di memoria in cui è stata allocata la variabile, di conseguenza se agisci sulla variabile stai modificando (per aliasing) il dato originale

Esempio di passaggio per valore
in questo caso lo cambio avviene localmente nella funzione
quindi x ed y nel main rimangono tali
int swap(int a, int b){
   int temp = a;
   a = b;
   b = temp;
}

int main(void)
{
   int x = 3, y = 4;
   swap(x, y); // sto passando una copia di x ed y
   return 0;
}



In questo caso il compilatore si aspetta dei puntatori
quindi la funzione opera direttamente con le variabili x ed y del main
che risultano scambiate correttamente
int swap(int *a, int *b){
   int temp = *a;
   *a = *b;
   *b = temp;
}

int main(void)
{
   int x = 3, y = 4;
   swap(&x, &y); // sto passando un riferimento di x ed y
   return 0;
}


"michele1239":

2)perchè gli array non possono essere passati per riferimento?


Il discordo degli array è un po complicato per via di alcune sottigliezze che il C++ ha ereditato dal C
Come saprai il nome di un array in C ed anche in C++ corrisponde all'indirizzo della prima cella dell'array stesso
(questo perchè in memoria gli array vengono memorizzati in locazioni contigue, e quindi si puo far uso dell'aritmetica dei puntatori in modo naturale e semplice) tuttavia
Quando passi un array ad una funzione gli stai passando una copia dell'indirizzo della prima cella. Quindi qui bisogna fare attenzione: gli array vengono passati implicitamente per riferimento(inteso come copia del puntatore alla prima cella dell'array).

"michele1239":

3)perchè negli array bidimensionali bisogna specificare solo la grandezza della seconda dimensione?


Per come ti dicevo sopra gli array come le matrici(che sono sempre array, però multidimensionali) vengono
memorizzati in memoria in celle contigue( praticamente la matrice è come se venisse allocata una riga dopo l'altra a partire dalla riga $0$, e proseguendo fino alla riga $n-1$)
Ebbene, ora il compilatore necessita per allocare correttamente la memoria di almeno $n-1$ dimensioni del tuo array
e nel caso delle matrici gli serve il numero delle colonne(per poter determinare quanto è grande una riga)
Questo perchè dietro le quinte l'aritmetica dei puntatori fa uso solo della dimensione delle righe, cioè del numero di colonne
che corrisponde alla seconda dimensione dell'array

"michele1239":

4)perchè si usano i prototipi di funzioni?ho capito che bisogna dichiarare i prototipi per evitare un side effect, ciò che non mi è chiaro è il motivo per il quale senza i prototipi si avrebbe un funzionamento non corretto del nostro programma.
scusate per il disturbo


Il discorso dei prototipi è storico nel C quindi nel C++ . Sono stati introdotti principalmente per
ridurre gli errori nel passaggio degli argomenti e per gestire i programmi di grandi dimensioni ma anche per motivi di efficienza nella compilazione.

Se definisci una funzione prima del main il programma dovrebbe andar bene lo stesso( e questo dipende dalla versione del tuo compilatore), in ogni caso è buona prassi dichiarare le funzioni mediante i prototipi perchè questo aiuta il compilatore
ad effettuare il debug alla ricerca di eventuali incongruenze nel passaggio dei parametri, e soprattutto quando più funzioni si chiamano tra loro. Il fatto che va in errore probabilmente è dovuto alle nuove restrizioni dei compilatori per le nuove versioni del C++... Infine il prototipo viene impiegato anche per gestire per l'overloading(sovraccarico) delle funzioni (cioè quando hai delle funzioni con lo stesso nome, ma con parametri differenti) le cosiddette "signature"

P.S. Nessun disturbo se vuoi altri chiarimenti, scrivi pure :-D[/quote]

grazie mille, sei stato molto chiaro!

axpgn
Scusami, ma mi spieghi perché per ringraziare hai citato tutto il (lungo) post (per giunta) precedente?

Rispondi
Per rispondere a questa discussione devi prima effettuare il login.