PDA

Visualizza la versione completa : [C++] Problema lettura con overload operatore >> e stringhe dinamiche


nostradamus1915
16-01-2013, 13:48
Ho una classe con 2 variabili char *, quando vado a inizializzarle tramite l'operatore >> mi stampa una stringa che non corrisponde a quella che inserisco. Tuttavia, quando stampo C.nome all'interno della funzione stessa, la stringa è corretta, è nel main che viene cambiata. Questo succede solo con le var char *, l'int per esempio non viene cambiato.

cliente.h

class cliente{
private:
char * nome;
char * cognome;
int eta;
int test[3];

//overload << e >>
friend ostream& operator<<(ostream &,const cliente &);
friend istream& operator>>(istream &,cliente &);

public:
//funzioni varie

cliente.cpp

istream& operator>>(istream& in,cliente& C){
buffer app;
char * capp;

cout << "Inserisci nome:\n";
in >> app;
alloca(capp,app);
C.nome=capp;
cout << capp << endl;
cout << C.nome << endl;
cout << "Inserisci cognome:\n";
in >> app;
alloca(capp,app);
C.cognome=capp;
cout << "Inserisci eta:\n";
in >> C.eta;
return in;
}

allocstr.h //contiene la funzione d'allocazione

void alloca(char *&s,buffer bf){
s = new char[strlen(bf)];
s=bf;
}

Qualcuno sa dove mettere le mani?

MItaly
16-01-2013, 13:52
Com'è definito buffer? In ogni caso, usare dei char * gestiti direttamente dalla classe in genere è una pessima idea, dovresti usare std::string piuttosto.

nostradamus1915
16-01-2013, 13:53
Purtroppo la traccia impone chiaramente che le stringhe devono essere allocate dinamicamente.
Il buffer è così dichiarato:

typedef char buffer[256];

Edit: Credo di aver capito qual'è il problema ma non so come risolverlo.
Alla fine dell'overloading faccio "return in;", quindi passo tutto ciò che inserisco tramite in >>
Il problema sta nel fatto che faccio in >> variabile_appoggio; e poi C.nome=variabile_appoggio;
Inoltre non posso fare direttamente in >> C.nome; in quanto il programma crasherebbe...
idee?

MItaly
16-01-2013, 15:03
Originariamente inviato da nostradamus1915
Purtroppo la traccia impone chiaramente che le stringhe devono essere allocate dinamicamente.
std::string internamente usa stringhe allocate dinamicamente; il problema del tuo approccio è che gestendo manualmente la memoria nella classe ti ritrovi a ripetere un sacco di codice di gestione delle stringhe inutilmente, rendendo più complicato il codice della classe e violando il SRP. Comunque, se la traccia impone che sia così...


Edit: Credo di aver capito qual'è il problema ma non so come risolverlo.
Alla fine dell'overloading faccio "return in;", quindi passo tutto ciò che inserisco tramite in >>
Il problema sta nel fatto che faccio in >> variabile_appoggio; e poi C.nome=variabile_appoggio;
Inoltre non posso fare direttamente in >> C.nome; in quanto il programma crasherebbe...
idee?
Non ho ben capito perché tutto questo sia un problema... piuttosto, l'errore sta in alloca:


void alloca(char *&s,buffer bf){
s = new char[strlen(bf)];
s=bf;
}
s è un reference ad un char * (idea bizzarra, tra l'altro :confused: ), per cui:
- prima allochi della memoria per la nuova stringa (tra l'altro, devi allocare strlen(bf)+1 caratteri, dato che devi tener conto anche del carattere di fine stringa) e assegni la memoria così allocata a s;
- poi sovrascrivi il puntatore s, facendolo puntare a bf (che di fatto non è altro che un puntatore alla memoria fornita da app, visto che i parametri di tipo array in C++ di fatto vengono passati come puntatori); per questo, al termine della funzione sia C.nome che C.cognome puntano a della memoria che non esiste più (dato che app è locale a operator>>).

Una versione corretta di alloca sarebbe:


void alloca(char *&s,buffer bf){
s = new char[strlen(bf)+1];
strcpy(s, bf);
}

o più banalmente potresti usare strdup (nota che però con quest'ultima per liberare la memoria devi usare free).

Ma, di nuovo, il modo corretto è usare std::string:


class cliente{
private:
std::string nome;
std::string cognome;
int eta;
int test[3];
// ...



istream& operator>>(istream& in,cliente& C){
cout << "Inserisci nome:\n";
in >> C.nome;
cout << C.nome << endl;
cout << "Inserisci cognome:\n";
in >> C.cognome;
cout << "Inserisci eta:\n";
in >> C.eta;
return in;
}

nostradamus1915
16-01-2013, 15:59
Chiarissimo grazie! :)

MItaly
16-01-2013, 17:33
:ciauz:

Loading