Problema con funzione inserimento[c++]

Gianni911
Ragazzi ho un problema con la compilazione,credo sia la funzione inserimento perché é l'ultima che scritto,anche se l'ho controllata..
#include "g.h"
G::G(){testa=NULL;}

G::~G(){elem*q;
        for(q=testa;q!=NULL;q=q->pun){testa=testa->pun;
                                       delete q;
                                       delete[] q->codice;
                                       q=testa;}
}

                 
void G::inserisci(const char* mat,int esami){
     elem*q,*k;
          for(q=testa;(q!=NULL)&&(q->esami<esami);q=q->pun){k=q;}
             elem* r=new elem;
              r->codice=new char[strlen(mat)+1];
             strcpy(r->codice,mat);
             r->esami=esami;
   if(testa==NULL){
                             testa=r;
                             r->pun=NULL;
                            }
       else{
                      k->pun=r;
                      r->pun=q;}
          
     
}



                    
ostream& operator<<(ostream& os, const G& g){
   elem*p;
  os<<"Matr"<<'\t'<<"Esami"<<'\t'<<endl;
  for (p=g.testa;p!=0;p=p->pun)
      os<<p->codice<<'\t'<<p->esami<<endl;
 
 return os;
}



e file.h
#include<iostream>
using namespace std;

struct elem{
       char* codice;
       int esami;
       elem* pun;};

class G{
      private:
      elem* testa;
      public:
              G();
              G(const G&);
             ~G();
             void inserisci(const char*,int);
             friend ostream& operator<<(ostream&,const G&);
      };


grazie ciao.. :D

Risposte
apatriarca
Ma quali errori ti da il compilatore?

Gianni911
mi crasha..
Posto anche il main
#include "g.h"
int main(){
    
           G z;
           cout<<z<<endl;
           z.inserisci("vvgvg",7);
           cout<<z<<endl;
  
    
    
    system("pause");
    return 0;
    }


provo a spiegarmi meglio,quando compilo non crasha,nessun problema fino a quando premo enter per uscire dalla finestra dos ,crasha..

Gianni911
trovato niente?? :cry:

Rggb1
Il tuo distruttore cancella (delete) 'q', e DOPO cancella 'q->codice'.

Gianni911
scusami ma é già cosi...
Comunque anche provando ad invertire non ottengo nulla...
G::~G(){elem*q;
        for(q=testa;q!=NULL;q=q->pun){testa=testa->pun;
                                       delete q;
                                       delete[] q->codice;
                                       q=testa;}
}


comunque l'errore l'ho trovato adesso era si nel distruttore,ma nell'assegnazione di testa a q...
A questo punto ti chiedo,dov'è il problema di riassegnare q??
Per quanto riguarda il codice
delete q;
delete[] q->codice;

ho sempre visto fare cosi,ma non riesco a capire cosa fanno le due istruzioni??
Non sarebbe meglio il contrario?? :?

Rggb1
Non ho capito che avresti invertito... :-D

Comunque è quello che intendevo: se cancelli 'qualcosa' e poi cancelli 'qualcosa->altro', come può funzionare? Che oggetto sarebbe 'qualcosa->altro' se 'qualcosa' è cancellato?

Gianni911
mentre scivevi ho modifiato il post sopra
"Rggb":

Non ho capito che avresti invertito... :-D

Inndevo dire invertiro in questo modo
delete[]q->codice;
delete q;

"Rggb":

Comunque è quello che intendevo: se cancelli 'qualcosa' e poi cancelli 'qualcosa->altro', come può funzionare? Che oggetto sarebbe 'qualcosa->altro' se 'qualcosa' è cancellato?

Sono d'accordo con te ,ma la cancellazione di qualcosa non é
delete q ??
,cioé il puntatore alla struttura...

Rggb1
C'è anche un altro problema, la riassegnazione 'q=q->pun' a fine ciclo... quale sarebbe il codice del distruttore adesso? Funziona?

Gianni911
si ho aggiustato funziona tutto perfettamente,ma non riesco a rispondere da solo a alle due domande che ho fatto prima..

Gianni911
Sai dirmi perché era quello il problema?? :?

Rggb1
Allora, siccome ho un po' perso il filo e non ho ancora capito cosa hai modificato e come, torno al codice che hai postato la prima volta:
G::~G(){elem*q;
        for(q=testa;q!=NULL;q=q->pun){testa=testa->pun;
                                       delete q;
                                       delete[] q->codice;
                                       q=testa;}
}


Ci vedo due problemi:
1) ad ogni ciclo, alla fine c'è l'assegnazione q=q->pun, quindi lo assegni due volte; infatti il codice del ciclo for è equivalente a questo:
q=testa;
  while (q != NULL)
  {
    testa=testa->pun;
    delete q;
    delete[] q->codice;
    q=testa;
    q=q->pun;
  }


2) cancella q->codice dopo aver cancellato q, che potrebbe portare a risultati non previsti: dopo aver eseguito una delete, un oggetto non è qualcosa di referenzialmente valido.

Ed ora parliamo delle modifiche che hai fatto: puoi postare il codice? Cioé, hai tolto l'assegnazione doppia, hai spostato le righe, cos'altro? Non l'ho capito ancora... :?

Gianni911
questo é il codice
#include "g.h"

G::G(){testa=NULL;}
G::~G(){elem*q;
        for(q=testa;q!=NULL;q=q->pun){testa=testa->pun;
                                       delete q;
                                       delete[]q->codice;
                                      /*qui avevo inserito un q=testa; che mi dava problemi,ma non sono sicuro di aver capito il  motivo..*/
                                       }
}
              
void G::inserisci(const char* mat,int esami){
     elem*q,*k;
          for(q=testa;(q!=NULL)&&((q->esami)<esami);q=q->pun){k=q;}
                     elem* r=new elem;
                     r->codice=new char[strlen(mat)+1];
                     strcpy(r->codice,mat);
                     r->esami=esami;
                     
      if(testa==NULL){  testa=r;
                        r->pun=NULL;
                      }
                else{
                      k->pun=r;
                      r->pun=q;}
}

           
G::G(const char* nome){
           char codice[15];
           int esami;
           fstream ff;
           ff.open(nome,ios::in);
           if(!ff)
           {
                  cerr<<"File non trovato"<<endl;
                  exit(1);
           }
           while(ff>>codice){
                             ff>>esami;
                   inserisci(codice,esami);}
           
           
           }







bool G::verifica(const char* c,int n){
     elem*q;
     for(q=testa;q!=NULL;q=q->pun)if(strcmp(q->codice,c)==0){q->esami=n;return true;}
     
     return false;
     }


G::G(const G& g){
                 elem*q,*s,*k;
                 testa=NULL;
                 for(q=g.testa;q!=NULL;q=q->pun){
                                                 for(s=testa;s!=NULL;s=s->pun){k=s;}
                                                    elem*r=new elem;
                                                    r->codice=new char[strlen(q->codice)+1];
                                                    strcpy(r->codice,q->codice);
                                                    r->esami=q->esami;

                                                  if(testa==NULL){testa=r;
                                                                  r->pun=NULL;}
                                                  else{
                                                       k->pun=r;
                                                       r->pun=s;}  
                                                 }
                                                 }
                                                 

                   
ostream& operator<<(ostream& os, const G& g){
   elem*p;
  os<<"Matr"<<'\t'<<"Esami"<<'\t'<<endl;
  for (p=g.testa;p!=0;p=p->pun)
      os<<p->codice<<'\t'<<p->esami<<endl;
 
 return os;
}



Per il resto continuo a pensare ,che il queste due righe sia meglio scriverle cosi,credo che sia meglio deletare prima il qualcosa->altro e poi il qualcosa...
Potresti spiegarmelo??
delete[] q->codice;
delete q;


ps:comunque adesso funziona tutto..

Rggb1
L'errore originale era quasi sicuramente dovuto alla doppia assegnazione di 'q'; alla fine del ciclo c'era un 'q=testa', nel momento in cui questo era l'ultimo elemento esso era NULL, quindi 'q' valeva NULL, ma successivamente (ultima istruzione del ciclo) veniva assegnato 'q=q->pun', e q->pun non esistendo generava una violazione di accesso.

Adesso funziona? Beh, anche se non cancelli tutto, comunque il distruttore lo richiami solo prima di uscire dal programma, e quindi la memoria allocata viene comunque rilasciata al sistema.

"Gianni91":
Per il resto continuo a pensare ,che il queste due righe sia meglio scriverle cosi,credo che sia meglio deletare prima il qualcosa->altro e poi il qualcosa...

Giustamente.

Gianni911
Ok ,adesso ci sono, grazie per il tuo aiuto.. :smt023

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