PDA

View Full Version : [C++]lettura da istream e crash dell'applicazione


anyanka
22-10-2008, 18:00
Salve a tutti, avrei bisogno di una mano:
sto sviluppando una piccola applicazione in C++ che legga (per ora) file xml, come parser uso expat.
Per passare i dati al parser apro il file con un istream, conto i caratteri, quindi lo resetto e eseguo una get che mette tutto in un array di caratteri di dim. uguale al numero ricavato precedentemente e a partire da un puntatore (char * buffer) che poi passo al parser xml.
Ora la questione è: con i file piccoli (ho provato fino a 300 caratteri circa) funziona...
con i file grandi (circa 103000 caratteri ma anche già con 14000 dà problemi) va tutto in crash, generando anche un report di errori di windows sia facendo il run da eclipse, sia facendo partire direttamente l'eseguibile.

Dov'è il problema? è troppo grande il buffer? :help: :help: :help:



#include <cstdio>
#include <iostream>
#include <fstream>
#include "C:/MinGW/Include/Expat 2.0.1/source/lib/expat.h"

using namespace std;

/* ************* LETTURA FILE XML ATTRAVERSO UN PARSER OTTENUTO CON LA LIBRERIA EXPAT **********/


const int MAX_NOME_FILE = 100 ;


/* prima di tutto devo definire gli ElementHandler */

void start_tag(void *userData, const XML_Char *name, const XML_Char **atts);

void end_tag(void *userData, const XML_Char *name);

void data_handler (void *userData, const XML_Char *s, int len);

XML_Parser parser = XML_ParserCreate("UTF-8");
/* PROCEDURA:
* 1)leggo il file aprendolo con uno stream
* 2)conto il num di caratteri che contiene
* 3)creo il parser
* 4)parso tutto il file passando il numero di caratteri ottenuti dalla conta
*/

int main(){
string nomeFile ; //nome del file richiesto da input
char file[MAX_NOME_FILE] ;
char * fp;
ifstream inputFile ; // stream di input
int num_caratteri = -1; //numero di caratteri contenuti nel file

XML_SetElementHandler(parser, start_tag, end_tag);
XML_SetCharacterDataHandler(parser, data_handler);
cout << "**********Programma per la lettura di un file XML********** " << endl;
cout << "Inserire il percorso del file da leggere " << endl;
cin >> nomeFile ;
/* apertura del file */
fp = strcpy(file, nomeFile.c_str());
inputFile.open(fp);
assert(inputFile);
/* conteggio caratteri */
while(!inputFile.eof()){
inputFile.get() ;
num_caratteri++ ;
}
cout << "Il file contiene " << num_caratteri << " caratteri" << endl;
/* resetto i flag dello stream per poter ricominciare la lettura */
inputFile.clear();
inputFile.seekg(0, ios::beg);

/* procedura di parse */
cout << " *******************" << endl;

int ris; // risultato del parser
char * buffer;

inputFile.get(buffer, num_caratteri, EOF); // <----si blocca qui
system("PAUSE");
ris = XML_Parse(parser, buffer, num_caratteri-1, 0);
system("PAUSE");
if(ris == 0){
XML_Error errore = XML_GetErrorCode(parser);
int riga = XML_GetCurrentLineNumber(parser);
int colonna = XML_GetCurrentColumnNumber(parser);
cout << XML_ErrorString(errore) << "\nriga num: " << riga <<"\ncolonna num: " << colonna << endl;
}
else {
cout << "parse eseguito." << endl;
}
inputFile.close();
XML_ParserFree(parser);
system("PAUSE");
return 0;
}

void start_tag(void *userData,
const XML_Char *name,
const XML_Char **atts) {
/* gestore dello start tag */
cout << "trovato start tag: " << name << endl;
int num_att = XML_GetSpecifiedAttributeCount(parser) ;
cout << "attributi: " << num_att/2 << endl;
if(num_att != 0){
for(int i=0; i<num_att; i++) {
cout << "attributo : " << atts[i] << " = " ;
i++ ;
cout << atts[i] << endl;
}
}
}

void end_tag(void *userData,
const XML_Char *name){
/* gestore dell'end tag */
cout << "\nchiusura tag " << name << endl;
}


/* mi fa vedere tutto quello che c'è dopo uno start tag e fino alla fine del file */
void data_handler (void *userData, const XML_Char *s, int len){
//string stringa = string(s);
//cout << "lunghezza stringa temporanea : " << stringa.length() << " stringa: " << stringa << endl;

}



sì.. me ne ero dimenticata...

banryu79
22-10-2008, 18:02
Se posti il codice "incriminato" è più facile aiutarti.

anyanka
22-10-2008, 18:09
sì l'ho aggiunta adesso.. :stordita:

praticamente con i file grandi conta i caratteri e quando arriva all'istruzione

inputFile.get(buffer, num_caratteri-1, EOF)

va in crash :boh:

EDIT: ho fatto qualche altra prova: sopporta fino a circa 3600 caratteri.. dai 3612 in poi va in crash

cionci
23-10-2008, 00:19
C'è qualche motivo per cui vuoi leggere tutto il file con una sola lettura ?

anyanka
23-10-2008, 10:36
sì...perché (almeno per quello che ho capito fino ad ora) il parser poi troverebbe errori nel momento in cui il testo si divide tra un blocco e l'altro...non saprei proprio come dirgli "se il file non è finito aspetta e attaccaci l'altro blocco prima di segnalare errori"

tomminno
23-10-2008, 14:37
sì...perché (almeno per quello che ho capito fino ad ora) il parser poi troverebbe errori nel momento in cui il testo si divide tra un blocco e l'altro...non saprei proprio come dirgli "se il file non è finito aspetta e attaccaci l'altro blocco prima di segnalare errori"

L'ultimo parametro del metodo XML_Parse indica se stai passando l'ultimo blocco del file che può essere impostato a eof dello stream:

int XMLPARSEAPI XML_Parse(XML_Parser parser, const char *s, int len, int isFinal);


void Parse(const string & data, int isFinal)
{
if (!XML_Parse(parser, data.data(), data.length(), isFinal))
{
stringstream s;
s << XML_ErrorString(XML_GetErrorCode(parser)) << " At line " << XML_GetCurrentLineNumber(parser);
throw exception(s.str().c_str());
}
}

anyanka
23-10-2008, 15:13
vero! ma come lo gestisco?
da quello che si evince dagli errori è la get che dà problemi, prima ancora di arrivare all'istruzione "XML_Parse(....)" :confused:

cionci
23-10-2008, 15:21
Non ci butterei la mano sul fuoco, ma mi viene da pensare che la get ti dia errore perché stai leggendo oltre la porzione del file bufferizzata.
Leggi quindi riga per riga, senza calcolare la dimensione del file prima. Ogni riga la passi XML_Parse.

Edit: non avevo visto l'orrore: ma i buffer non si allocano più ? :D

char * buffer = new char[num_caratteri+1];

inputFile.get(buffer, num_caratteri, EOF); // <----si blocca qui

anyanka
23-10-2008, 15:30
OMG!! mi sembrava mancasse qualcosa :sbonk: :doh: :uh:
comunque va bene anche char * buffer = new char[num_caratteri] tanto l'eof non devo considerarlo...
evidentemente per pochi caratteri andava bene...per gli altri non allocava abbastanza spazio...

Grazie mille! :flower: :vicini:

cionci
23-10-2008, 15:34
Ma il carattere di fine stringa suppongo tu lo debba considerare ;)

anyanka
23-10-2008, 15:45
se metto un carattere in più il parser mi dà errore perché dopo una nuova linea - evidentemente - si aspetta un tag che non trova.. quindi per quello che mi serve va bene così :)
se poi mi darà altri errori saprò dove andare a mettere mani ...

cionci
23-10-2008, 15:59
Non vedo come la lunghezza del buffer possa andare ad influire sul parser. Tu devi passare la lunghezza precedente al parser non quella con il +1 ;) Il +1 serve solo per riservare spazio per il carattere di fine stringa.

anyanka
23-10-2008, 16:19
allora ricapitolando, il programma funziona se:

- inizializzo num_caratteri = 0;
- li conto
- creo il buffer con char * buffer = new char[num_caratteri+1]
- passo alla get num_caratteri
- decremento num_caratteri di 1
- passo il nuovo valore al parser

se cambio anche una sola di queste condizioni non funziona più...
salvo il fatto che posso usare la dichiarazione ... new char[num_Caratteri] e funziona lo stesso...

:boh: