Post by OsvaldPost by OsvaldPost by Soviet_MarioPost by Osvald[cut]
Post by enoquickPost by OsvaldPost by enoquickPuntatori e memoria dinamica (heap) non sono la stessa cosa
1) quando è più utile usare i puntatori
2) quando è più utile usare la memoria dinamica
Se ho ben capito, con i puntatori si ha *anche* la possibilità di
http://www.cplusplus.com/doc/tutorial/dynamic/
potrebbe essere un caso in cui conviene utilizzare i puntatori e la
memoria dinamica; infatti, nell'esempio, la dimensione dell' array
viene stabilita in fase di runtime (mediante input dell'utente) e si
ha quindi la possibilità di avere un array a dimensione variabile e
dipendente dall'input dell'utente.
Infatti; per usare la memoria dinamica è obbligatorio l' uso dei
puntatori ma l'uso dei puntatori non implica necessariamente l'uso
della memoria dinamica
OK...puoi, fare qualche esempio *semplice* (*se possibile*) di
convenienza dell'uso dei puntatori senza l'impiego della memoria
dinamica?
prova a pensare di avere una funzione che fa una divisione tra interi e
restituisce SIA il quoziente SIA il resto.
Come faresti ?
ah ... aggiungo di farlo senza creare una struct ad hoc che
incapsuli il doppio dato. Funzione che usi soltanto i tipi
nativi
Credo di essere riuscito a farlo ma senza l'uso dei puntatori :-((
senze ACCORGERTI di usare puntatori intendi dire : le
reference SONO puntatori, semplicemente con alcune
peculiarità, tipo l'accesso con semantica "plain" di alias
di nomi di variabili, e la costanza di indirizzo (che il
puntatore non ha necessariamente, essendo riciclabile).
Ma per il resto le reference SONO indirizzi quanto lo sono i
puntatori classici.
Post by OsvaldPost by Osvald==============================================
#include<iostream>
using namespace std;
void divisione (int a, int b, int& risdiv,int& resto)
{
risdiv = a/b;
resto = a%b;
}
int main ()
{
int risdiv=0;
int resto=0;
divisione(9,2,risdiv,resto);
cout<< "Risultato_div="<< risdiv<< endl;
cout<< "Resto="<< resto<< endl;
return 0;
}
okay, nell'esercizio dopo invece c'è ... un po' da mettersi
le mani nei capelli. Vediamolo
Post by OsvaldPost by Osvald==========================================================
..con l'uso dei puntatori ho ottenuto degli errori ...appena possibile
riprovo, *adesso cerco di dormire, se ci riesco*...:-(((....
cmq, trovo molto interessante l'esrcizio che hai proposto.
bene, infatti è "cannato", ma è cannando che si capisce
qualcosa anche, basta capire cosa c'è di sbagliato
Post by OsvaldHo provato con i puntatori, ma, durante l'esecuzione del programma,
"Prova.exe ha smesso di funzionare. Si e' verificato un problema che
impedisce il finzionamento corretto del programma.Chiudere il
programma."
Lanciando il debug mi compare il seguente messaggio (Finestra Call
#0 004013A8 main() (C:\Users\programmi\Desktop\Prova\main.cpp:28)
===========================================
#include<iostream>
using namespace std;
void divisione (int a, int b, int* p1,int *p2 )
{
int risdiv;
int resto;
queste dichiarazioni sono già molto sospette del fatto di
non avere capito che gli oggetti BERSAGLIO la funzione
doveva riceverli dall'esterno, tramite i parametri puntatore.
Invece ricrei due oggetti, che sono temporanei, nello
stackframe della funzione, e che quindi SVANIRANNO al return.
Non c'è nessuna ragione di dichiarare due temporanei per una
funzione simile (non in generale).
Ma l'orrore tra poco ...
Post by Osvaldp1=&risdiv;
p2=&resto;
questa è una delle cose peggiori da leggere : stai ricavando
l'indirizzo a due oggetti temporanei (morituri te salutant),
e ti appresti a passarli fuori della funzione ... se non
che, non li passi nemmeno fuori.
Cmq, sin qui l'errore è avere preso l'indirizzo di due
variabili evanescenti, indirizzo che diventerebbe una mina
vagante se uscisse dalla funzione e qualcuno ci scrivesse
sopra, perché gli oggetti puntati sono svaniti.
Non è finita
Post by Osvaldrisdiv = a/b;
resto = a%b;
qui esegui un calcolo inutile. Assegnare le variabili locali
automatiche svanisce appena fuori della funzione.
* gli oggetti puntati originariamente dai due argomenti (che
si supponevano essere stati inizializzati dal CHIAMANTE) non
sono mai stati scritti.
Infatti per scrivere nell'oggetto non devi usare
p1 = etc etc;
ma
*p1 = etc etc;
devi DEREFERENZIARE il puntatore, ossia indirizzare
l'oggetto puntato.
scrivendo p1=qualcosa ottieni solo di perdere l'indirizzo
che era stato passato dal chiamante (in teoria), e senza
aver toccato l'oggetto bersaglio.
inoltre l'effetto rimane LOCALE alla funzione chiamata,
infatti essa riceve come argomento UNA COPIA per valore
dell'indirizzo. Se anche tu localmente la alteri
(scollegandoti dal chiamante), globalmente l'indirizzo di
memoria non viene alterato di certo. Semplicemente la
funzione non vede più il suo oggetto originale, ma per come
l'hai scritto vede in modo diverso un oggetto locale
automatico, già in scope.
Post by Osvald}
int main ()
{
int* p1=NULL ;
int* p2=NULL ;
divisione(9,2,p1,p2);
ecco, la filosofia è totalmente diversa.
int p1, p2; // allochi DUE OGGETTI REALI, non puntatori al vuoto
divisione(9, 2, & p1, & p2);
// invochi passando gli indirizzi di tali oggetti
// in modo che la funzione possa vedere cose create
// dal chiamante
Post by Osvaldcout<< "Risultato_div="<< *p1<< endl;
l'errore scatta qui : stai passando NULL a cout.
Infatti la modifica ai puntatori fatta dentro divisione
rimane locale, i puntatori vengono passati byval, a meno di
non usare l'indirizzo dei puntatori, e nella funzione
passare **arg (è un uso che per il momento non ti serve di
sicuro).
Post by Osvaldcout<< "Resto="<< *p2<< endl;
anche qui passi NULL
Quindi di norma la funzione chiamata non alloca niente, ma
riceve gli indirizzi di oggetti bersaglio, e li usa
dereferenziandoli per registrare colà i suoi risultati.
Se invece la funzione chiamata deve ALLOCARE lei memoria e
ritornare un oggetto, allora lì devi usare per forza la
memoria dinamica heap, il cui life-cycle è a gestione manuale.
Non ritornare mai indirizzi di variabili AUTOMATICHE fuori
dalla funzione che le ha dichiarate, perché perdono validità
al return e detti oggetti sono sovrascritti o cmq invalidati.
In questo caso è più semplice restituire l'indirizzo nel
valore di ritorno, diversamente devi usare una reference a
un argomento puntatore, o un argomento puntatore a puntatore
e dereferenziarlo.
double * CreaResultQuadrato (double Val)
{
try {
double * ResultPtr = new double;
// la variabile creata, anonima, ha vita "manuale"
} catch (...) // se fallisce allocazione
{
return (double *) 0;
};
* ResultPtr = Val * Val;
// dereferenzia -> accede al double dinamico
return ResultPtr; // ritorna l'indirizzo
}
void main (void)
{
double * SquarePtr = CreaResultQuadrato (2.0);
if (SquarePtr != (double *) 0)
cout << (* SquarePtr);
else
count << "epic fail !";
return;
}
potresti provare a restituire l'oggetto via argomenti e non
via valore di ritorno ...
ciao
CCCP
Post by Osvaldreturn 0;
}
===========================================
La linea 28 segnalata dalla finestra "Call stack", corrisponde
cout<< "Risultato_div="<< *p1<< endl;
.....dove sbaglio e a cosa e' dovuto la segnalazione di errore che
ottengo?
Ciao e grazie milleeee!
--
1) Resistere, resistere, resistere.
2) Se tutti pagano le tasse, le tasse le pagano tutti
Soviet_Mario - (aka Gatto_Vizzato)