Newsgroup: it.comp.lang.c++
Titolo: Scambio di due variabili con puntatore

Sto provando ad assegnarmi qualche esercizio sui puntatori, ad es. il
seguente programma, esegue lo scambio tra due variabili mediante l'uso
di un puntatore:
 
======================================
 
// Scambio di due variabili di tipo intero
 
#include <iostream>
using namespace std;
int main()
{
 
int x=10,y=20;
 
int* p_x=NULL;
 
p_x=new  int;
 
*p_x=x;
 
x=y;
y=*p_x;
 
delete p_x;
 
cout<<"x="<<x<<endl<<"y="<<y;
 
return 0;
 
}
 
===============================
 
Con i puntatori, se ho ben capito, è possibile, un uso dinamico della
memoria; e' possibile cioe',  allocare e deallocare spazi di memoria
(memoria heap);
 
 se nel predetto programma NON avessi usato il puntatore, ma una
semplice variabile di appoggio(utilizzo memoria stack) di tipo intero
(per eseguire lo scambio delle varabili intere x e y), il programma
sarebbe stato meno ottimizzato dal punto di vista dell'impiego di
memoria?
 
 
Ciao e grazie milleeeeee!
 

 
 
Avrebbe usato memoria automatica invece di dinamica.
 
Su quale tipo di memoria si meglio usare e quale soluzione sia più leggera
per il processore nei vari casi lo lascio pensare a te (ma non cercare di
farti un'idea generale, solitamente dipende dal caso specifico).
 
Ciao!


Fra stack e heap i costi di accesso sono uguali
La differenza sta che new (o malloc in C) ha un costo ben superiore all' 
allocazione di una variabile nello stack e per simmetria anche delete (o 
free in C)
 
 
 
 
 
 

 free in C)
 
Quindi, nel caso in esame, sarebbe stato meglio NON utilizzare il
puntatore?....stavo cercando di capire quando potesse essere piu'
conveniente l'uso dei puntatori...ma forse sto cercando di andare
troppo oltre quelle che sono le conoscenze al momento acquisite...cmq
chiedo SCUSA al ng se a volte faccio domande banali e vi ringrazio per
i vostri preziosi suggerimenti.
 
Ciao e grazie mille!!
 
 
 
 
 
 


 
 
-- 
1) Resistere, resistere, resistere.
2) Se tutti pagano le tasse, le tasse le pagano tutti
Soviet_Mario - (aka Gatto_Vizzato)
 


 
 


 i vostri preziosi suggerimenti.
 
Si dice spesso che "non esistono domande stupide, solo le risposte possono
esserlo".
Per questo alla fine la risposta l'avrai sempre, ma a volte ci si altera quando
la domanda è relativa ad una cosa che chi domanda dovrebbe sapere ;)
 
Ciao!

 [...]
 
 
Ciao  Manlio


Puntatori e memoria dinamica (heap) non sono la stessa cosa
Quindi le domande dovrebbero essere due:
1) quando è più utile usare i puntatori
2) quando è più utile usare la memoria dinamica
 
 
 
 

 Ciao  Manlio



Se ho ben capito, con i puntatori si ha *anche* la possibilità di
utilizzare la memoria dinamica....l' esempio al link:
 
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.
 
Ciao e grazie mille!

 free in C)
 
Questa affermazione è condivisibile ma anche qui andrei cauto.
Prima di tutto la gestione di uno stack è più semplice solo perché 
l'hardware, il linguaggio macchina, il processore, la MMU  mettono
a disposizione mezzi per gestire lo stack molto efficientemente ma
la cosa dipende ancora dal caso particolare.
 
Viceversa non è tanto vero che gestire una heap è meno efficiente
che gestire uno  stack, solo chla heap  porta facilmente a memory 
leak e in genere le contromisure sono costose o inefficienti.


Infatti; per usare la memoria dinamica è obbligatorio l' uso dei 
puntatori  ma l'uso dei puntatori non implica necessariamente l'uso 
della memoria dinamica
 
 
 
 

 ...
 
Perciò io dico: "... *generalmente* sono comparabili."
 

 della memoria dinamica
 
OK...puoi, fare qualche esempio *semplice* (*se possibile*) di
convenienza dell'uso dei puntatori senza l'impiego della memoria
dinamica?
 
Ciao e grazie milleeeeeee!
 

 Ciao e grazie milleeeeeee!


 Come faresti ?
 
ah ... aggiungo di farlo senza creare una struct ad hoc che 
incapsuli il doppio dato. Funzione che usi soltanto i tipi 
nativi



 
E' ancora possibile per una data classe ridefinire i metodi statici new 
e delete
Ma il new placement è stato tolto dallo standard ?
 
 


 
 
Questo non l'ho mai detto
 


void f(const T&)
 
 
Il primo parametro è un reference ma in pratica è un puntatore
 
 
Oppure
 
 
void f(T* x)
 
 
Oppure
 
int a;int b;
int* x = expr ? &a : &b
 
......
 
uso di x
 
 
 
Ma,sinceramente, non mi è mai capitato in pratica di usare direttamente 
un puntatore ad una variabile sullo stack (l' ultimo caso)
Se qualcuno ha qualche altra idea è ben accetto
 
 
 
 
 

 Se qualcuno ha qualche altra idea è ben accetto
 
beh, tutte le volte che una funzione deve ritornare più di 
un unico risultato, è inevitabile passare reference e/o 
puntatori (secondo i gusti, i secondi sono più espliciti 
imho). E i parametri passati alla funzione, possono e spesso 
sono anche variabili automatiche (o a propria volta 
parametri ricevuti, ammettendo una certa catena di chiamate).
 
 
P.S. no, non sapevo che new "placement" fosse stato 
estromesso, perché non conosco lo standard.
Devo dire che lo trovato molto comodo e garantista, e 
veramente non ne comprendo la ragione.
Era uno dei modi di avere garanzie minime certe di memoria 
(preallocazione statica), da gestire però in modo dinamico 
nel senso di riciclabile per oggetti diversi. Non so come 
mai sia stato tolto. Forse qualche nuova funzionalità 
permette le stesse cose in modo più agile ? O forse la 
memoria non è ormai più considerata una risorsa men che 
sicura, vista l'abbondanza ? Boh



Credo di essere riuscito a farlo ma senza l'uso dei puntatori :-((
 
==============================================
 
#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;
}
 
==========================================================
 
 
..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.
 
Ciao e grazie MILLEEEEEEEE!
 

 vista l'abbondanza ? Boh
 
La mia era una domanda, non so se il new "placement" è stato tolto
Dovrei mettermi a cercare per saperlo
 


Ho provato con i puntatori, ma, durante l'esecuzione del programma,
compare la finestra windows:
 
"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
stack):
 
#0 004013A8 main() (C:\Users\programmi\Desktop\Prova\main.cpp:28)
 
Il programma e' il seguente:
 
===========================================
 
 
#include <iostream>
using namespace std;
 
void divisione (int a, int b, int* p1,int *p2 )
{
 
  int risdiv;
  int resto;
 
  p1=&risdiv;
 
  p2=&resto;
 
  risdiv = a/b;
 
  resto = a%b;
 
  }
 
int main ()
{
  int* p1=NULL ;
  int* p2=NULL ;
 
 divisione(9,2,p1,p2);
 
 cout << "Risultato_div=" << *p1 << endl;
 cout << "Resto=" << *p2 << endl;
 
 return 0;
}
 
===========================================
 
La linea 28 segnalata dalla finestra "Call stack", corrisponde
all'istruzione:
 
 cout << "Risultato_div=" << *p1 << endl;
 
....dove sbaglio e a cosa e' dovuto la segnalazione di errore che
ottengo?
 
Ciao e grazie milleeee!

 int* p_x=NULL;
 
Usa nullptr per i puntatori, non NULL.
http://www.stroustrup.com/C++11FAQ.html#nullptr
 
 
 

 Ciao e grazie milleeee!
 
 



Credo che l'errore sia dovuto al fatto che, nella funzione void
divisione:
 
p1=&risdiv;
 
p2=&resto;
 
 
sono due puntatori che fanno riferimento ad *indirizzi di variabili
locali*:
 
..il seguente programma sembra essere corretto:
 
========================================================
 
#include <iostream>
using namespace std;
 
void divisione (int a, int b, int* p1_risdiv,int *p2_resto )
{
 
  *p1_risdiv= a/b;
 
  *p2_resto= a%b;
 
  p1_risdiv= NULL;
 
  p2_resto= NULL;
 
  }
 
int main ()
{
 
   int risdiv=0;
   int resto=0;
 
   int* p1=NULL;
   int* p2=NULL;
 
   p1=&risdiv;
   p2=&resto;
 
 divisione(9,2,p1,p2);
 
 cout << "Risultato_div=" << *p1 << endl;
 cout << "Resto=" << *p2 << endl;
 
 return 0;
}
 
===================================================
 
Cosa ne pensate?...esiste soluzione migliore?
 
 
Ciao e grazie mille!
 
 


Utilizzando nullptr ottengo l'errore:
 
"C:\Users\cesare\Desktop\programmi\main.cpp|24|warning: identifier
'nullptr' is a keyword in C++11 [-Wc++0x-compat]|"
 
...probabilmente il copmilatore che utilizzo (Code Blocks::con
compilatore: gnu gcc) NON e' aggiornato alla vers. C++11?
 
Ciao e grazie mille!
 
 
 
 
 
 
 
 
 
 
 

 Ciao e grazie mille!



Credo il tuo compilatore ti suggerisca di abilitare C++11 tramite 
l'opzione -Wc++0x-compat
 


No, scusa, non avevo letto bene. Quel -Wc++0x-compat � per 
abilitare/disabilitare il warning. Per abilitare C++11 passa -std=c++0x 
al compilatore.
 
 

 al compilatore.
 
Nella scheda compiler flags del compilatore trovo, tra le varie
opzioni:
 
-std=c++0x
 
-std=c++11
 
...ho notato che, se scelgo la prima che hai suggerito o la seconda
non ottengo errori anche se non conosco la diffferenza trale le due
opzioni.
 
 
Ciao e grazie mille!
 
 
 
 
 
 
 
 
 
 
 
 

 "ottimizzare" ancora.
 
 
.....pero', se ho ben capito, in base a quanto suggerisci, alla fine
siamo ritornati, *in linea di massima*, al primo programma che avevo
scritto, cio' senza l'uso *esplicito* dei puntatori*.
 
Ciao e grazie  mille!
 

 opzioni.
 
Nessuna differenza.
 
 

 Come faresti ?
 
 
@Osvald: questo ï¿œ uno dei modi per risolvere l'esercizio proposto.
Come vedi la funzione divisione restituisce alla funzione
chiamante il tipo void ma in pratica con l'uso dei puntatori essa 
riesce a restituire due risultati. Questo ï¿œ impossibile con 
l'istruzione return che puï¿œ restituire solo 1 valore. I puntatori 
devono essere studiati e "digeriti" e per fare
questo occorre pazienza, impegno e tempo.
 
#include <iostream>
 
using std::cout;
using std::cin;
using std::endl;
 
void divisione(int, int, int*, int*);
 
int main()
{
     int numeratore = 0;
     int denominatore = 0;
     int quoziente = 0;
     int resto = 0;
 
     cout << "Inerisci il numeratore della frazione: ";
     cin >> numeratore;
 
     cout << "Inerisci il denominatore della frazione: ";
     cin >> denominatore;
 
     divisione(numeratore, denominatore, &quoziente, &resto);
 
     cout << "\nil risultato della divisione e\' " << quoziente
          << "\ncon il resto di " << resto << endl;
 
     return 0;
}
 
void divisione(int num, int denom, int *risultato, int *resto)
{
     *risultato = num / denom;
     *resto = num % denom;
}

 [...]
 
 
Ciao  Manlio

 Ciao  Manlio
 
 


 Ciao  Manlio
 
 


 }
 
OK...ti ringrazio..ho provato a risolvere l'esercizio con l'uso delle
variabili globali:
 
================================================
 
#include <iostream>
 using namespace std;
 
   int risdiv=0; //variabile globale
   int resto=0;  //variabile globale
 
void divisione (int a, int b)
 {
 
  risdiv = a/b;
 
  resto = a%b;
 
  }
 
int main ()
 {
 
 divisione(9,2);
 
 cout << "Risultato_div=" << risdiv << endl;
 cout << "Resto=" << resto << endl;
 
 return 0;
 
}
 
==============================================
 
Sembra funzionare correttamente, pero', probabilmente, l'uso delle
variabili globali, e' da evitare (quando possibile) perche' possono
essere modificate da qualsiasi funzione presente nel programma con il
risultato che, forse, risulta piu' difficile individuare un errore
logico nel caso di un cattivo funzionamento del programma: giusto?
 
Inoltre , non saprei se a livello di impiego di memoria, con l'uso
delle variabili globali il programma e' meno ottimizzato rispetto ad
altre soluzioni.
 
Appena possibile provero' a risolvere l'esercizio anche usando le
strutture.
 
Ciao e grazie mille!!!
 
 
 
 
 
 

 Ciao e grazie mille!!!
 
Ciao!

 Visto che stai studiando prova tutto quello che ti viene in mente! :-)
 
:-))
 
Quello che trovo impegnativo, oltre al linguaggio di programmazione
con le sue regole, i suoi costrutti...ecc....e' riuscire ad
individuare con una certa *rapidita'* quale e' *l'algoritmo* (che
credo, almeno per semplici problemi di programmazione, prescinde dal
linguaggio usato) per la soluzione (magari, inizialmente, anche non
ottimale) di un determinato problema.
 
Chiaramente ci sono degli algoritmi di base da imaparare: la ricerca
del max in un vettore, l'ordinamento di un vettore, merge di due
vettori, conversione di base..ecc....
 
Poi,  chiaramente, per alcuni problemi di programmazione sono
richieste conoscenze di analisi matematica (es. calcolo approssimato
di un'equazione, di un integrale), ma, forse, in tal caso, avendo le
relative conoscenze, lo sviluppo dell'algoritmo risulta piu' semplice
rispetto ai predetti problemi.
 
Consigli a riguardo?
 
Ciao e grazie mille per la tempestivita' delle risposte!
 
 
 
 
 
 
 
 
 

 Ciao e grazie mille!!!



 
 


 non ho capito del tutto la domanda ...
 
Es. Se mi si chiede di scrivere un programma per il calcolo di
un'equazione di secondo grado non ci sono molte difficolta', basta
conoscere la relativa formula risolutiva e scrivere un algoritmo e'
abbastanza semplice; in tal caso, basta avere delle conoscenze di base
di matematica.....ma se mi si chiede di scrivere un programma che
ordina un vettore di n elementi, oppure un merge di due vettori, non
ci vogliono grandi basi di matematica ma bisogna avere un buon
allenamento (almeno se si cerca di scriverlo senza sbirciare prima la
soluzione) con lo scrivere gli algortimi.
 
Spero di essere stato piu' chiaro.
 
Ciao e grazie mille!
 
 

 
 
Non saprei.. Credo questa sia una delle cose che dipende dall'esperienza..
 
Ti dico come faccio io, ma ognuno ha il suo modo di pensare..
I problemi di matematica/fisica sono i più immediati, basta applicare le
regole che usi a mano o, se non è accettabile, cercare in letteratura.
I problemi di ordinamento/ricerca/etc su strutture dati sono così comuni che
saltano subito all'occhio.
Se non ho la più pallida idea di cosa applicare perché è una situazione nuova
io faccio così, ma non è detto che sia la strada migliore: prima vedo se è
simile ad un problema NP, e in quel caso (almeno che non sia uno di quelli che
uso spesso) cerco in letteratura gli algoritmi più comuni; altrimenti, vedo
se è risolvibile con un divide-et-impera (in quel caso applichi qualche tipo
di ricerca binaria, a seconda dei casi) o, se ogni step è riconducibile al
precedente, se è più sensato un algoritmo greedy o una ricerca di un cammino
sul grafo equivalente.
 
Comunque, ribadisco, *questo* è il difficile e l'interessante del mondo della
programmazione: il linguaggio è solo un mezzo.
 
Ciao!

 regole che usi a mano
 
[cut]
 
....esattamente, .intentevo proprio questo (vedi mia risposta a
Soviet_Mario), mentre problemi che non richiedono grandi conoscenze di
matematica, tipo il seguente::
 
http://www.dmi.unisa.it/people/nappi/www/lip/traccia1.pdf
  (e'
richiesto in C, sto provando a scriverlo in C++)
 
li trovo piu' impegnativi...cmq il prof. NON ha ancora spiegato il
tipo e difficolta' di programmi che chiedera' all'esame: spero NON
siano troppo complessi....non credo che con un corso di quattro mesi
si di venta un programmatore.
 
Ciao e grazie milleeeee
 
 
 
 
 
 
 
 
 

 [...]
 
Ciao  Manlio
 


Sì, il problema che hai postato richiede solo di pensarci un po', e vedrai
che verrai comunque giudicato sull'utilizzo del linguaggio, non sull'efficenza
del codice!
Sulla domanda iniziale e le risposte che ti ho dato, magari dovrai aspettare
di seguire corsi più in là (a ingegneria informatica, principalmente algoritmi
e strutture dati, ma molta roba mi ricordo la feci a elettronica digitale e
informatica 2 - fermo restando che il 90% di quello che uso oggi nel codice
l'ho imparato dai colleghi nei primi anni di lavoro, per cui non avere troppa
fretta!)
 
Ciao!