PDA

View Full Version : violazione di accesso


Unrue
13-07-2005, 10:28
Salve ragazzi, sto implementando il codice di huffman in c++. Ho dichiarato il file header in questo modo:

class Huffman {
public:
Huffman() {}
Huffman(unsigned char data, int freq, Huffman*sin, Huffman*des): codice(data), frequenza(freq), left(sin), right(des){}
~Huffman() {}

unsigned char codice;

int frequenza;

Huffman*left;

Huffman*right;

Huffman**crea_albero (FILE*in);

Huffman*ricerca (Huffman**lista, Huffman*salta, int*posizione);

Huffman*crea_albero_binario(Huffman**lista);

void crea_codice_Huffman(Huffman*node, unsigned char*codice, unsigned char numerobit);

void scrivi_bit(unsigned char*ptr, int posizionebit, char numerobit);

void scrivi();


};


Quando richiamo la funzione crea_albero mi da' una violazione di accesso.
Huffman**Huffman::crea_albero(FILE*in){
Huffman*PHuff[256];

int v=0;

while(!feof(in)){

v= fgetc(in);

if(PHuff[v]==NULL)

{PHuff[v]=new Huffman(v, 1, NULL, NULL);}
else
{PHuff[v]->frequenza++;} //qui mi da' l'errore
}
fclose(in);
return PHuff;
}

In pratica, quando leggo un simbolo in cui ho già creato l'albero, tento di acedere al campo frequenza dell'oggetto puntato dal puntatore nell'array, ma mi da' questo tipo di errore. Chi mi puo' aiutare? Thanks.

ilsensine
13-07-2005, 10:33
if(PHuff[v]==NULL)

PHuff[] non è inizializzato a NULL da nessuna parte

return PHuff;

PHuff vive sullo stack e perde il suo scopo all'uscita della funzione. Devi allocarlo dinamicamente se vuoi che sopravviva dopo il return.

cionci
13-07-2005, 10:36
Per favore...mettici qualche spazio...altrimenti non ci si capisce niente...

cionci
13-07-2005, 10:37
Tipo così:

Huffman(unsigned char data, int freq, Huffman*sin, Huffman*des): codice(data), frequenza(freq), left(sin), right(des) { }

ilsensine
13-07-2005, 10:38
Per favore...mettici qualche spazio...altrimenti non ci si capisce niente...
Gli spazi c'erano, è il [code] che manca (come al solito) :p

cionci
13-07-2005, 10:40
Nono...guada bene... Clicka su Modifica e lo vedi... Mancherà l'indentazione, ma gli spazi fra nome e tipo mancano...

cionci
13-07-2005, 10:41
Inoltre perchè le variabili membro non sono private ?

ilsensine
13-07-2005, 10:44
Nono...guada bene... Clicka su Modifica e lo vedi... Mancherà l'indentazione, ma gli spazi fra nome e tipo mancano...
Non avevo fatto in tempo a leggere il tuo secondo post, non sapevo a quali spazi ti riferivi :)

Unrue
13-07-2005, 10:50
E' vero, :doh:

Va bene questa dichiarazione allora? PHuff deve essere un puntatore ad un'array di puntatori di tipo Huffman:

PHuff=(Huffman*)malloc(sizeof(Huffman));

ilsensine
13-07-2005, 10:52
E' vero, :doh:

Va bene questa dichiarazione allora? PHuff deve essere un puntatore ad un'array di puntatori di tipo Huffman:

PHuff=(Huffman*)malloc(sizeof(Huffman));
Così non allochi un array di puntatori...

Unrue
13-07-2005, 10:54
Come si fa? non ricordo :cry:

ilsensine
13-07-2005, 10:58
Huffman **PHuff = new Huffman *[256];
for(unsigned pos=0; pos<256; ++pos) {
PHuff[pos] = new Huffman(pos, 0, NULL, NULL);
}

Anche altre soluzioni vanno bene (ad es. allocare direttamente un array di 256 oggetti).

Unrue
13-07-2005, 11:02
Huffman **PHuff = new Huffman *[256];
for(unsigned pos=0; pos<256; ++pos) {
PHuff[pos] = new Huffman(pos, 0, NULL, NULL);
}

Anche altre soluzioni vanno bene (ad es. allocare direttamente un array di 256 oggetti).

Grazie :) . Ho inserito il codice che mi hai suggerito, ma l'errore rimane. :(

ilsensine
13-07-2005, 11:03
Puoi postare il codice attuale su cui stai lavorando?

Unrue
13-07-2005, 11:05
Puoi postare il codice attuale su cui stai lavorando?


E' quello nel primo messaggio, ti posso dare il main se vuoi:

void main()
{ Huffman prova;
FILE*in;

in= fopen("D:logo.txt","r");

if (in!=NULL){
prova.crea_albero(in);
cout<<"Albero creato!";
}
else{ cout<<"File vuoto, impossibile comprimere";}

}



e questa è la dichiarazione della funzione nel file.cpp

Huffman**Huffman::crea_albero(FILE*in){

Huffman**PHuff = new Huffman *[256];
for(unsigned pos=0; pos<256; ++pos) {
PHuff[pos] = new Huffman(pos, 0, NULL, NULL);
}

int v=0;



while(!feof(in)){

v= fgetc(in);

if(PHuff[v]==NULL)

{PHuff[v]=new Huffman(v,1,NULL,NULL);}
else
{PHuff[v]->frequenza++;}
}
fclose(in);

return PHuff;

ilsensine
13-07-2005, 11:14
mmm feof ritorna true solo dopo che la fgetc ritorna -1.
Prova così:

while((v=fgetc(in))>=0)
PHuff[v]->frequenza++;

Unrue
13-07-2005, 11:25
mmm feof ritorna true solo dopo che la fgetc ritorna -1.
Prova così:

while((v=fgetc(in))>=0)
PHuff[v]->frequenza++;


Ho scritto cosi':

while(!feof(in)){
v= fgetc(in);

if(PHuff[v]==NULL)

{PHuff[v]=new Huffman(v,1,NULL,NULL);}
else
{while((v=fgetc(in))>0){PHuff[v]->frequenza++;}}
}

Funziona! Se un un grande! pero' non ho capito come mai feof ritorna true dopo che fgetc da' -1. Se feof da' false, fgetc non viene eseguita. Illuminami, e grazie ancora. Se avro' altri problemi spero che potro' contare su di te . Ciaooo ;)

Unrue
13-07-2005, 11:33
Poi non ci vorrebbe un if? In quel modo altrimenti non esce piu' da quel ciclo

ilsensine
13-07-2005, 11:39
Ho scritto cosi':

while(!feof(in)){
v= fgetc(in);

if(PHuff[v]==NULL)

Continua ad essere errato. Qui da me feof ritorna true solo dopo la prima volta che fgetc ritorna -1. Il risultato è un accesso a PHuff[-1] se il file è vuoto. Utilizza la
while((v=fgetc(in))>=0){PHuff[v]->frequenza++;}
direttamente eliminando il resto inutile di codice (nb occhio che il confronto è ">=0" non ">0").

ilsensine
13-07-2005, 11:45
pero' non ho capito come mai feof ritorna true dopo che fgetc da' -1.
Dalla documentazione in mio possesso, feof non fa altro che testare l'indicatore EOF dello stream. Evidentemente la fgetc imposta tale indicatore, ma solo quando si accorge che il file è finito (e contestualmente ritorna -1).
Ho letto adesso; non amo molto le funzioni sui FILE *.

Unrue
13-07-2005, 11:46
Continua ad essere errato. Qui da me feof ritorna true solo dopo la prima volta che fgetc ritorna -1. Il risultato è un accesso a PHuff[-1] se il file è vuoto. Utilizza la
while((v=fgetc(in))>=0){PHuff[v]->frequenza++;}
direttamente eliminando il resto inutile di codice (nb occhio che il confronto è ">=0" non ">0").


:confused: A me funziona pero', guarda:


while(!feof(in)){
v= fgetc(in);
if(PHuff[v]==NULL)
{PHuff[v]=new Huffman(v,1,NULL,NULL);}
else
{if(v>=0){PHuff[v]->frequenza++;}}
}
fclose(in);


Tu dici che dovrei scrivere cosi?

while((v=fgetc(in))>=0){PHuff[v]->frequenza++;}

e basta? Quindi il controllo sullla fine del file mi viene direttamente da v quando vale -1. Pero' devo metterci anche il codice che mi fa puntare il puntatore nella posizione v ad un'oggetto di tipo Huffman,quello non posso toglierlo. Incremento la frequenza solo se ho giò incontrato quel simbolo

Unrue
13-07-2005, 11:52
Dalla documentazione in mio possesso, feof non fa altro che testare l'indicatore EOF dello stream. Evidentemente la fgetc imposta tale indicatore, ma solo quando si accorge che il file è finito (e contestualmente ritorna -1).
Ho letto adesso; non amo molto le funzioni sui FILE *.

Alla fine ho scritto cosi:

while(v= fgetc(in)>=0){
if(PHuff[v]==NULL)
{PHuff[v]=new Huffman(v,1,NULL,NULL);}
else
{PHuff[v]->frequenza++;}
}
fclose(in);
cout<<"3";
return PHuff;

e funziona lo stesso, non so se in quell'altro modo andasse veramente, magari mi creava l'albero ma era tutto sbagliato

ilsensine
13-07-2005, 12:03
:confused: A me funziona pero', guarda:
Prova con un file di lunghezza 0 ;)

Alla fine ho scritto cosi:

while(v= fgetc(in)>=0){
if(PHuff[v]==NULL)
{PHuff[v]=new Huffman(v,1,NULL,NULL);}
else
{PHuff[v]->frequenza++;}
}

Il controllo sulla nullità di PHuff[v] è superfluo in quanto tutti gli oggetti sono stati preallocati (quindi PHuff[v] è sicuramente !=NULL).

Unrue
13-07-2005, 12:11
Prova con un file di lunghezza 0 ;)

Il controllo sulla nullità di PHuff[v] è superfluo in quanto tutti gli oggetti sono stati preallocati (quindi PHuff[v] è sicuramente !=NULL).


No aspetta, questa cosa non mi torna. Io ho un'array di puntatori tutti inizializzati a NULL e siamo d'accordo. Se ho trovato un simbolo v nuovo nel file che sto leggendo devo inizializzare tale puntatore nella posizione v facendolo puntare ad un oggetto di tipo Huffman (v,1,NULL,NULL). Tale controllo devo mettercelo, ma allora lo creo se la frequenza di quel nodo è 0. In pratica:

while(v=fgetc(in)>=0){
if(PHuff[v]->frequenza=0)
{PHuff[v]=new Huffman(v,1,NULL,NULL);}
else
{PHuff[v]->frequenza++;}
}
fclose(in);

va bene cosi'?il programma gira :) )

ilsensine
13-07-2005, 12:13
No aspetta, questa cosa non mi torna. Io ho un'array di puntatori tutti inizializzati a NULL e siamo d'accordo.
Non siamo d'accordo. Se hai usato il codice di inizializzazione che ho postato, gli oggetti sono tutti preallocati con frequenza 0, che mi sembra la soluzione più logica.
Se non vuoi questo comportamento devi cambiare la

for(unsigned pos=0; pos<256; ++pos) {
PHuff[pos] = new Huffman(pos, 0, NULL, NULL);
}

in

for(unsigned pos=0; pos<256; ++pos) {
PHuff[pos] = NULL;
}

Unrue
13-07-2005, 12:18
Non siamo d'accordo. Se hai usato il codice di inizializzazione che ho postato, gli oggetti sono tutti preallocati con frequenza 0, che mi sembra la soluzione più logica.
Se non vuoi questo comportamento devi cambiare la

for(unsigned pos=0; pos<256; ++pos) {
PHuff[pos] = new Huffman(pos, 0, NULL, NULL);
}

in

for(unsigned pos=0; pos<256; ++pos) {
PHuff[pos] = NULL;
}


Hai ragione, ho sbagliato. i puntatori sono tutti preallocati, ma hanno frequenza 0. Man mano che leggo un simbolo v, faccio un controllo sulla frequenza del puntatore alla posizione v, se è un simbolo nuovo, la frequenza che leggo è 0 , quindi la incremento. Se è diversa da zero, vuol dire che quel simbolo l'ho già trovato nel file che sto leggendo, quindi la incremento di uno. Ok cosi'? :)

Unrue
13-07-2005, 15:32
Non siamo d'accordo. Se hai usato il codice di inizializzazione che ho postato, gli oggetti sono tutti preallocati con frequenza 0, che mi sembra la soluzione più logica.
Se non vuoi questo comportamento devi cambiare la

for(unsigned pos=0; pos<256; ++pos) {
PHuff[pos] = new Huffman(pos, 0, NULL, NULL);
}

in

for(unsigned pos=0; pos<256; ++pos) {
PHuff[pos] = NULL;
}



Ciao,scusa se ti ridisturbo, il programma gira,ma accade una ocsa stranissima.Ho preso un fileprova.txt in cui ci ho scritto :
file di prova,vediamo se funziona


Ebbene, per vedere se funzionava il tutto ho messo delle stampe a video dopo la funzione fgetc e con grande sorpresa ho notato che mi da sempre 1! Cioè v, vale sempre 1, infatti il programma giustamente scrive 34 volte, (il numero delle battiture nel file di esempio), nella posizione 1 dell'array di puntatori. Come mai?

Unrue
13-07-2005, 15:56
Ho risolto rispolveranto la funzione feof ma facendo un controllo dopo sul vaolre restituito da v;

while(!feof(in)){
v=fgetc(in);
if(v>=0){
cout<<"\n"<<"questa è la v: "<<v;
PHuff[v]->frequenza++;
}
}

Adesso funziona ! :)