View Full Version : [C] mai vista una cosa del genere
caustico
29-01-2008, 18:21
ciao a tutti, vi espongo brevemente qual'è il problema. . .sto facendo un programmino leggermente complesso (quantomeno piu del solito helloworld.c) ma mi capita una cosa incredibile. . .quando compilo ed eseguo il codice in universita' il programma gira perfettamente, quando invece compilo ed eseguo il medesimo codice a casa (sia sulla virtual machine che su una macchina dedicata) questo mi da una segmentation fault che a detta di gdb viene generata nel momento in cui faccio una fopen su un file. . .voi mi direte "be lo hai programmato male" e vi darei ragione visto che non sono proprio un fenomeno, ma com'è possibile che in uni funziona e a casa addirittura va in segmentation fault?. . .compilato con -Wall -pedantic non mi restituisce neanche un warning. . .ora se il programma non dovessi inviarlo al mio professore non ci sarebbero problemi, lo faccio andare in uni e chi si è visto si è visto. . .ma visto che il prof nelle migliori delle ipotesi lo compilera' sul suo portatile. . .puo' dipendere dalla versione di gcc? in uni usiamo fedora5 mi pare mentre a casa ho una suse virtuale e una mepis sul portatile. . .
bla bla bla... sarebbe bastato incollare il sorgente correttamente formattato tra i tag CODE :read:
caustico
29-01-2008, 19:01
bla bla bla... sarebbe bastato incollare il sorgente correttamente formattato tra i tag CODE :read:
ma sono 420 righe di codice. . .
beh incolla solo la parte che secondo te dovrebbe contenere l'errore...
AnonimoVeneziano
29-01-2008, 19:06
Beh, fatto sta che senza codice noi non possiamo farci niente :stordita:
"Ti chiedi il come mai, ti chiedi il quasi quasi, dov'è la risposta? La risposta non la devi cercare fuori. La risposta è dentro di te ... epperò è sbagliata!" :D
caustico
29-01-2008, 19:18
grazie a tutti ho risolto
cdimauro
29-01-2008, 19:22
Mi sembra il classico caso di memoria inizializzata (generalmente tutta azzerata) in una piattaforma e NON inizializzata (quindi con valori casuali) nell'altro.
caustico
29-01-2008, 19:24
Mi sembra il classico caso di memoria inizializzata (generalmente tutta azzerata) in una piattaforma e NON inizializzata (quindi con valori casuali) nell'altro.
e come potrei risolvere? cioè non alloco una struttura, non ancora perlomeno per cui cosa dovrei andare a inizializzare?
caustico
29-01-2008, 19:45
ho capito il problema. . .inizializzo una char descrizione[10000000] (lo avevo detto che non sono buono a programmare :D ) cosa che probabilmente non piace ne alla virtual ne al mio portatile. . .ma a questo punto vi faccio una domanda, come faccio ad allocare dinamicamente una stringa di caratteri? cioè come faccio a caricare un carattere alla volta senza sapere quanti caratteri devo caricare in una stringa?
wingman87
29-01-2008, 19:59
Devi usare malloc e realloc, ma forse puoi tenere il codice che hai e usare una memset per inizializzare il tutto (non ho letto il codice ma mi sembra di aver capito che sia questo il problema) -> LINK (http://www.cplusplus.com/reference/clibrary/cstring/memset.html)
sottovento
29-01-2008, 20:09
ho capito il problema. . .inizializzo una char descrizione[10000000] (lo avevo detto che non sono buono a programmare :D ) cosa che probabilmente non piace ne alla virtual ne al mio portatile. . .ma a questo punto vi faccio una domanda, come faccio ad allocare dinamicamente una stringa di caratteri? cioè come faccio a caricare un carattere alla volta senza sapere quanti caratteri devo caricare in una stringa?
Ciao, scusa l'intromissione.
In pausa pranzo stavo controllando il tuo codice, ed avrei un paio di suggerimenti da dare:
void aggiungi_feed(){
char ind[100], tmp[10], str[100], cmd[]="wget -O tmp ";
printf("\nInserisci l'indirizzo URL del feed da aggiungere ai preferiti\n");
scanf("%s", ind);
strcpy(str,ind);
strcat(cmd,str);
system(cmd);
Vai a fare la strcat a cmd. Non avrai spazio a sufficienza in questa stringa, molto probabilmente avrai un errore random (nel senso che ogni tanto funziona ed ogni tanto vai in crash).
Sempre nella stessa funzione:
fp = fopen("tmp", "r");
fgets(tmp, 6, fp);
if(strcmp(tmp,"<?xml")==0){
fp=fopen("rss","a");
fprintf(fp,"\n");
fprintf(fp,ind);
fclose(fp);
printf("\nFeed aggiunto ai preferiti\n");
}
else{
system("clear");
printf("\n\n\tL'indirizzo URL inserito non si riferisce a un feed, digita nuovamente 3 per riprovare\n");
}
Controlla sempre che il file sia stato aperto correttamente. Nel caso il file tmp non venga trovato, o sia lockato da qualche altro programma, etc., la successiva fgets() andra' in crash. Lo stesso quando apri rss, subito dopo.
Supponi ora che le aperture dei file vadano bene. Siccome usi la variabile fp per entrambi i file, quando eseguirai la seconda fopen() ti perderai il file precedente, senza aver nemmeno la possibilita' di chiuderlo.
Pertanto, siccome il numero di file che puoi aprire e' limitato, ad un certo punto il tuo programma non potra' piu' aprire file, e siccome non hai fatto il controllo sull'esito dell'apertura, andra' in crash.
Attenzione che questo tipo di crash e' di quelli che definisci "stranissimi": sono effettivamente difficili da trovare semplicemente analizzando l'output (del tipo "perche' funzionava correttamente fino a 10 min. fa ed ora va in crash?")
void memorizza(char *in){
char tmp[5], titolo[500], descrizione[10000000], link[500], data[55], enclosure[500],type[500];
char fine;
Beh, questa l'hai trovata tu:in generale non e' bello creare una variabile locale da 10 milioni di caratteri. Potresti avere qualche problema.
Per risolverlo, prima di tutto valuta se e' davvero necessario avere una variabile cosi' grande (sai, l'hai chiamata descrizione....).
In secondo luogo, puoi valutare se allocare dinamicamente o metterla globale/statica.
Anche in questa funzione apri un file senza controllare, ma ne abbiamo gia' parlato.
ATTENZIONE - attento al "gioco" che fai chiamando leggi_file() che richiama apri_file() che a sua volta richiama leggi_file(). Non e' sano. Controlla se puoi risolvere in altro modo (sicuramente lo puoi fare).
caustico
29-01-2008, 22:05
innanzi tutto grazie sottovento passo subito a qualche delucidazione,allora: non faccio ulteriori controlli che il file sia stato aperto correttamente o meno all'interno della apri_file perchè questi vengono fatti dalla void controlla_input che passa alla apri_file solo nel caso in cui l'apertura avviene con successo; per quanto riguarda il gioco che faccio chiamando leggi_file() che richiama apri_file() che a sua volta richiama leggi_file() pur convenendo con te che non sia il massimo è l'unica soluzione pseudoplausibile che mi è venuta in mente per permettere al programma di non uscire dall'esecuzione qualora non venga passato un argomento durante l'esecuzione o nel caso in cui il file specificato non esista. . .per quanto riguarda il resto hai ragionissima su tutta la linea, la var descrizione contiene quello che c'è all'interno dei campi <description></description> di un rss, di conseguenza non ha una lunghezza fissa, e pur essendo discretamente grande non è infinito. . .quindi di sicuro se lo sapessi fare char descrizione sarebbe una var dinamica. . .
sottovento
30-01-2008, 00:36
innanzi tutto grazie sottovento passo subito a qualche delucidazione,allora: non faccio ulteriori controlli che il file sia stato aperto correttamente o meno all'interno della apri_file perchè questi vengono fatti dalla void controlla_input che passa alla apri_file solo nel caso in cui l'apertura avviene con successo; per quanto riguarda il gioco che faccio chiamando leggi_file() che richiama apri_file() che a sua volta richiama leggi_file() pur convenendo con te che non sia il massimo è l'unica soluzione pseudoplausibile che mi è venuta in mente per permettere al programma di non uscire dall'esecuzione qualora non venga passato un argomento durante l'esecuzione o nel caso in cui il file specificato non esista. . .per quanto riguarda il resto hai ragionissima su tutta la linea, la var descrizione contiene quello che c'è all'interno dei campi <description></description> di un rss, di conseguenza non ha una lunghezza fissa, e pur essendo discretamente grande non è infinito. . .quindi di sicuro se lo sapessi fare char descrizione sarebbe una var dinamica. . .
Ciao,
per quanto riguarda leggi_file() e apri_file() direi che cambiare non e' difficilissimo. Tutto sommato, visto che apri_file() e' chiamata in due punti soltanto (uno di questi e' appunto leggi_file()) potresti semplicemente scrivere:
void apri_file(char *i)
{
char s[20]="wget -O file ";
char op[500], str[500];
fp=fopen(i,"r");
while (fp == NULL)
{
printf("Il File non esiste!!!\n");
leggi_file(i);
fp=fopen(i,"r");
}
Ovviamente in leggi_file() toglierai la chiamata ad apri_file().
Non spaventarti se leggi_file contiene solo un paio di righe di codice: e' segno che stai andando nella direzione giusta.
Inoltre otterrai anche il vantaggio che le funzioni, cambiate in questo modo, fanno esattamente quello che il loro nome suggerisce, e non qualcosa di piu'.
Per questo stesso motivo, mi permetterei di suggerirti di togliere la chiamata ad apri_file da controlla_input().
Fai fare a controlla_input() solo il controllo e fagli ritornare un risultato. Usa poi questo esito per chiamare o meno la apri_file().
Altro suggerimento: spesso trovare gli errori run time e' piuttosto difficile. Invece che fare una printf ("Il file non esiste\n") (che potrebbe non esser vero, magari il problema e' un altro), scrivi
perror ("non posso aprire il file");
La perror() fara' seguire alla tua scritta il motivo della mancata apertura: magari non hai i permessi, o il file e' lockato,...
Per quanto riguarda la tua descrizione, puoi fare come ti e' stato suggerito prima: dichiarare quel campo come puntatore a char (del tipo char *descrizione) e scrivere:
void memorizza(char *in)
{
char tmp[5], titolo[500], *descrizione, link[500], data[55], enclosure[500],type[500];
descrizione = (char *)malloc (10000000);
if (descrizione == NULL)
{
printf ("Impossibile allocare memoria per la descrizione!!\n"); // Non usare perror qui!
// Esegui ora qualche altra operazione. Non puoi seguire il normale flusso di esecuzione.
}
...
qui usi la memoria
...
free (descrizione); // Restituisci la memoria al sistema
Ricorda di fare la free() in qualunque caso: se decidi di uscire prima da questa funzione e descrizione e' allocata, deallocala.
ciao a tutti, vi espongo brevemente qual'è il problema. . .sto facendo un programmino leggermente complesso (quantomeno piu del solito helloworld.c) ma mi capita una cosa incredibile. . .quando compilo ed eseguo il codice in universita' il programma gira perfettamente, quando invece compilo ed eseguo il medesimo codice a casa (sia sulla virtual machine che su una macchina dedicata) questo mi da una segmentation fault che a detta di gdb viene generata nel momento in cui faccio una fopen su un file. . .voi mi direte "be lo hai programmato male" e vi darei ragione visto che non sono proprio un fenomeno, ma com'è possibile che in uni funziona e a casa addirittura va in segmentation fault?. . .compilato con -Wall -pedantic non mi restituisce neanche un warning. . .ora se il programma non dovessi inviarlo al mio professore non ci sarebbero problemi, lo faccio andare in uni e chi si è visto si è visto. . .ma visto che il prof nelle migliori delle ipotesi lo compilera' sul suo portatile. . .puo' dipendere dalla versione di gcc? in uni usiamo fedora5 mi pare mentre a casa ho una suse virtuale e una mepis sul portatile. . .
La causa più comune sono variabili non inizializzate. Un compilatore magari le inizializza a caso, l'altro per niente ed ecco che scappa il Segmentation Fault. Infatti,in genere,è buona norma compilare ed eseguire il proprio sorgente con diversi compilatori e verificare che il comportamento sia lo stesso.
vBulletin® v3.6.4, Copyright ©2000-2025, Jelsoft Enterprises Ltd.