Newsgroup: it.comp.lang.c
Titolo: Problema compilatore

Ho un problema con questo programma:
#include <conio.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct lista2
{
    char *chiam;
	char *data;
	char *ora;
	char *durata;
	float valor;
    struct lista2 *next;
	struct lista2 *last;
};
struct lista
{
    int interno;
    float costo;
    struct lista *nextp;
    struct lista2 *nexts;
};
int insert1(struct lista **start,int t_int,char *t_chiam,char
*t_data,char *t_ora,char *t_durata)
{
    struct lista *app,*app2,*old;
    struct lista2 *app3,*app4,*old2;
    app=(struct lista *)malloc(sizeof(struct lista));
    app->interno=t_int;
    app3=(struct lista2*)malloc(sizeof(struct lista2));
    app3->chiam=strdup(t_chiam);
    app3->data=strdup(t_data);
    app3->ora=strdup(t_ora);
    app3->durata=strdup(t_durata);
    if (!(*start))//Non ci sono elementi nella lista principale
    {
       (*start)=app;
       app->nextp=NULL;
       app->nexts=app3;
       //printf("%d ",t_int);
       return 0;
    }
    app2=(*start);
    old=NULL;
    while (app2)
    {
    	if (app2->interno<t_int)
    	{
    		old=app2;
    		app2=app2->nextp;
    	}
    	else if (app2->interno>t_int)
    	{
    		if (old)
    		{
    		    //Old esiste quindi app è in mezzo
    		    old->nextp=app;
                app->nextp=app2;
                app->nexts=app3;
                //printf("%d ",t_int);
                return 0;
            }
            //Old non esiste app è il più piccolo
    		app->nextp=app2;
    		(*start)=app;
    		app->nexts=app3;
    		//printf("%d ",t_int);
    		return 0;
    	}
    	else if (app2->interno==t_int)
    	{
    		free(app);
    		//printf("%d ",t_int);
    		app4=app2->nexts;
    		while (app4)
    		{
    		    old2=app4;
    		    app4=app4->next;
            }
            old2->next=app3;
            return 0;
    	}
    }
    //E' il ppiù grande
    app->nexts=app3;
    old->nextp=app;
    app->nextp=NULL;
    app->nexts=app3;
    return 0;
}
int main()
{
    struct lista *start=NULL,*last=NULL,*blob;
    struct lista2 *blob2;
    FILE *f,*f1;
    int t_interno;
    char t_chiam[20],t_data[20],t_ora[20],t_durata[20];
    f=fopen("bella.txt","r");
    while(!(feof(f)))
    {
    	fscanf(f,"%d %s %s %s
%s\n",&t_interno,t_chiam,t_data,t_ora,t_durata);
    	insert1(&start,t_interno,t_chiam,t_data,t_ora,t_durata);
    }
    blob=start;
    while (blob)
    {
    	printf("%d \n",blob->interno);
    	//printf("\0");
    	blob2=blob->nexts;
    	while (blob2)
    	{
    	    printf(" %s  \n",blob2->chiam);
    	    blob2=blob2->next;
        }
    	blob=blob->nextp;
    }
    getchar();
}
Un esempio del file da leggere è questo:
2701 +5555555 01/04/2006 04:32.28 00:02:34
2527 +4356566 01/04/2006 04:32.28 00:02:34
2203 +2322424 01/04/2006 04:32.28 00:02:34
2701 +6666666 01/04/2006 04:32.28 00:02:34
Il problema è che con il compilatore code::blocks funziona benissimo, al
contrario con visual c++ mi da errore alla lettura del secondo elemento
della lista, come se andasse a leggere una porzione di memoria
sbagliata. Come mai?E' il mio visual c++ che non funziona o anche a voi
succede lo stesso. La cosa mi preoccupa perchè l'esame si svolge su
macchine con insallato visual c++ e non vorrei che mi capitasse lo
stesso inconveniente.
Grazie mille a tutti quelli che mi sapranno dare delle risposte.
-- 
Posted via Mailgate.ORG Server - 
http://www.Mailgate.ORG

    {
<...> 
Lo ammetto, ci ho provato a trovare gli errori, ma mi si sono
incrociati gli occhi.  Devi attribuire un nome significativo alle tue
variabili: app1, app2, app3, app4, old, old2 non dicono nulla e
rendono ardua la lettura e la comprensione del codice.
Credo che l'errore più grave che tu faccia sia progettuale, ovvero di
ricostruire la logica di gestione della lista per due volte,
duplicando le possibilità di errore.
Tu puoi costruire benissimo un nodo generico:
/* nodo */
typedef struct node_tag {
        void *data;
        struct node_tag *next;
} node_t, *pnode_t;
/* costruttore nodo */
pnode_t node_new(const void *data) {
        pnode_t i = malloc(sizeof *i);
        if (i) {
           i->data=data;
           i->next=NULL;   
        }
        return i;
}
/* distruttore nodo */
void node_free(const pnode_t self) {
     if (self) free(self);
}
Una lista di liste non è altro che una lista il cui nodo contiene un
campo puntatore data che a sua volta è l'istanza di una lista.
Puoi costruire liste a n livelli così.
In ogni caso, dubito moltissimo che sia il tuo compilatore ad avere
problemi ;-)

 consuetudine tra i C-isti non è mai buona cosa.
(Mi approprio del thread :P)
Se la funzione non è banale preferisco avere due punti di uscita
(successo ed errore) per poter consolidare il cleanup (Linux kernel
style, per intenderci).
Questo permette di evitare di duplicare i passi di cleanup:
        if (!step1()) {
                cleanup1();
                err = -EFOO;
        }
        ...
        if (!step2()) {
                cleanup1();
                cleanup2();
                err = -EBAR;
        }
        ...
        return err;
diventa:
        if (!step1()) {
                err = -EFOO;
                goto clean1;
        }
        ...
        if (!step2()) {
                err = -EBAR;
                goto clean2;
        }
        ...
        return 0;
        /* Error path */
clean2:
        cleanup2();
clean1:
        cleanup1();
        return err;
Si così evita di duplicare parte dell'error path e si evita che i vari
pezzi sparsi possano perdere consistenza con il resto del codice (e.g.
un blocco viene aggiornato e l'altro viene dimenticato).
Un'altro caso in cui preferisco return multipli è la validazione degli
argomenti di una funzione:
int foo(char *a, int b) {
        if (!a)
                return -ESTUPID;
        if (b < 0)
                return -ELOOSER;
        ....
}
In questo caso i return sono tutti concentrati all'inzio della funzione
e (IMHO) non pregiudicano la leggibilità del codice.
Luca
-- 
Home: 
http://kronoz.cjb.net
"Ci sono le balle, le megaballe e le statistiche".
 Mark Twain

style, per intenderci).
Io invece preferisco sempre avere un unico punto d'uscita perché
prediligo la leggibilità/debuggabilità/manutenibilità del codice
rispetto alla compattezza.
Nel caso dei cleanup() io farei qualcosa di questo tipo:
int func() {
    int retval=0;
    int do_cleanup1=0;
    int do_cleanup2=0;
    if (!step1()) { 
       do_cleanup1=1;
       retval=1;
    }
 
    if (!step2()) {
       do_cleanup1=1;
       do_cleanup2=1;
       retval=2;  
    }
    if (do_cleanup1) cleanup1();
    if (do_cleanup2) cleanup2();
 
    return retval;
}

 Grazie mille a tutti quelli che mi sapranno dare delle risposte.
Potrei scriverti un esempio di codice "pulito", leggibile, sicuro e
funzionante, ma... non riuscendo a comprendere cosa deve fare il tuo
programma non posso.
Tommaso


programma non posso.
Anch'io sono curioso di conoscere le specifiche, ma solo per poter
dare il mio contributo, s'intende.

 NON funzioni.
[...]
Non è così.
OT {
    Se ti riferisci alla teoria delle funzioni calcolabili (Turing, Rice
ecc.) allora non puoi
    decidere nemmeno che un programma non funziona.
    Il teorema di Rice tradotto in "soldoni" recita:
    "Non è possibile caratterizzare insiemi di programmi partendo da
proprietà delle
    funzioni calcolate, a meno che essa sia banale (cioè che produce
l'insieme vuoto
    o l'insieme di tutte le funzioni)."
    Quindi ad esempio non puoi decidere se un programma (prendiamo il C come
    formalismo), calcola o NO una certa funzione.
    Non puoi nemmeno decidere se due generici programmi sono equivalenti
    o se vanno in loop su alcuni argomenti.
}
Quindi non puoi decidere ad esempio se una certo programma
scritto in C per calcolare il fattoriale NON funziona!
--
Giorgio Silvestri
DSP/Embedded/Real Time OS   Software Engineer

Non è così.
Rileggi il thread per capire cosa voglio dire ;-)

 }
Non mi piace particolarmente :|
In un caso reale si aumenterebbe l'indentazione di tutto il codice e
(IMHO eh) il codice "troppo indentato" è un'indicazione visiva di una
funzione scritta male.
Luca
-- 
Home: 
http://kronoz.cjb.net
The trouble with computers is that they do what you tell them, 
not what you want.
D. Cohen

 NON funzioni.
Leggendo le tue testuali parole sembrava proprio che
ti volessi riferire alla teoria della calcolabilità...
Devi ammettere che è comprensibile interpretare in questo modo.
E poi ho detto nel mio OT
"Se ti riferisci ... "
Se non ti riferisci a questo
semplicemente il mio commento non sia applica. :-)


ti volessi riferire alla teoria della calcolabilità...
Mi riferivo al fatto che, nella pratica, dire che un programma
"funzioni" significa sostanzialmente *presumerne*il funzionamento.  Se
un programma viene compilato con un compilatore e non dà problemi e
compilato con un altro non fa ciò che deve fare, allora il programma
NON funziona.  Purtroppo molti programmatori, partono dal principio
che il loro programma invece funziona eccome, ma è il secondo
compilatore ad avere problemi ;)

funzione scritta male.
A mio avviso, la vera funzione scritta male è quella troppo complessa
e che quindi richiede punti d'uscita sparsi, altrimenti non ci si
raccapezza più ;-)

 Grazie mille a tutti quelli che mi sapranno dare delle risposte.
Potrei scriverti un esempio di codice "pulito", leggibile, sicuro e
funzionante, ma... non riuscendo a comprendere cosa deve fare il tuo
programma non posso.
Tommaso
Scusate ma ero un po' di fretta è non ho scritto le direttive del
programma.
Il programma consisteva in questo, si aveva un file di input che si
riferiva alle telefonate fatte dai vari uffici
di una ipotetica azienda con i relativi interni.
In questo file vi sono n righe suddise in cinque campi:
1°-interno da cui partono le chiamate
2°-numero chiamato
3°-data della telefonate
4°-ora della telefonata 
5°-durata della telefonata
Un ipotetico file è questo:
2701 +5555555 01/04/2006 04:32.28 00:03:34
2527 +4356566 01/04/2006 04:32.28 00:02:34
2203 +2322424 01/04/2006 04:32.28 00:02:34
2701 +6666666 01/04/2006 04:32.28 00:02:34
Il testo diceva di creare un lista principale degli interni con i nodi
così strutturati:
struct lista
{
    int interno;
    float costo;
    struct lista *nextp;
    struct lista2 *nexts;
};
Il primo campo si riferisce all'interno,il secondo il prezzo di tutte le
telefonate fatte dall'interno(non implementato),
il terzo è un puntatore al nodo successivo,cioè al succesivo interno, il
quarto è un puntatore all'elemento
di testa della lista2, cioè alla lista delle telefonate fatte
dall'interno.
I nodi della lista delle telefonate sono così formate:
struct lista2
{
    char *chiam;
	char *data;
	char *ora;
	char *durata;
	float valor;
    struct lista2 *next;
};
I campi si riferiscono ai vari dettagli della telefonata con in più il
campo valor che indica il costo della chiamata, è un
puntatore al succesivo nodo,cioè alla succesiva telefonata fatta
dall'interno.
Il programma doveva creare una lista principale di interni ordinati in
maniera crescente secondo
il campo interno, ognuno di questi nodi doveva poi avere un puntatore
che puntava alla lista delle telefonate fatte
dallo stesso.
Questo è il file che mi dain output il mio programma:
2203 
 +2322424 01/04/2006 04:32.28 00:02:34 0.309000
2527 
 +4356566 01/04/2006 04:32.28 00:02:34 0.309000
2701 
 +5555555 01/04/2006 04:32.28 00:03:34 0.429000
 +6666666 01/04/2006 04:32.28 00:02:34 0.309000
Adesso che ho spipegato grossomodo il programma cercherò di commentare
al meglio il listato seguente:
int insert1(struct lista **start,int t_int,char *t_chiam,char
*t_data,char *t_ora,char *t_durata)
{
//Qui dichiaro tutte le varie variabili che mi serviranno nel seguito
del programma
    struct lista *app,*app2,*old;
    struct lista2 *app3,*app4,*old2;
    char ora1[3],min1[3],sec1[3];
    int ora,min,sec,sec_tot;
//Qui calcolo la durata delle telefonate, molto macchinosamente ma non
sapevo che altro fare
    ora1[0]=t_durata[0];
    ora1[1]=t_durata[1];
    ora1[2]='\0';
    min1[0]=t_durata[3];
    min1[1]=t_durata[4];
    min1[2]='\0';
    sec1[0]=t_durata[6];
    sec1[1]=t_durata[7];
    sec1[2]='\0';
    ora=atoi(ora1);
    min=atoi(min1);
    sec=atoi(sec1);
    sec_tot=ora*3600+min*60+sec;
//Qui alloco memoria per i due nodi,quello degli interni, e quello della
telefonate che succesivamente provvederò
//a inserire correttamente nelle lista, riempo anche tutti i vari campi
dei nodi
    app=(struct lista *)malloc(sizeof(struct lista));
    app->interno=t_int;
    app3=(struct lista2*)malloc(sizeof(struct lista2));
    app3->chiam=strdup(t_chiam);
    app3->data=strdup(t_data);
    app3->ora=strdup(t_ora);
    app3->durata=strdup(t_durata);
    app3->valor=sec_tot*0.002+0.001;
//Il puntatore start punta all'elemento di testa della lista
principale,esso nel main è inizializzato a NULL
//quindi se esso vale ancora NULL vuol dire che non è stato ancora
immesso alcun nodo
    if (!(*start))
    {
//Dato che la lista è vuota il primo elemento della lista diventerà
allora app precedemente allocato
       (*start)=app;
//Dato che la lista è vuota nextp il puntatore all'interno succesivo
dovrà per forza essere NULL
       app->nextp=NULL;
//A maggior ragione non ci sono ancora telefonate fatte dal suddeto
interno quindi il primo elemento della lista
//delle telefonate dovrà per forza essere app3,quindi faccio puntare il
puntatore alla testa
       app->nexts=app3;
       //printf("%d ",t_int);
       return 0;
    }
//Faccio puntare app2 al puntatore di testa della lista principale in
modo da poter scandire l'intera lista dall'inizio
//per l'inserimento ordinato
    app2=(*start);
    old=NULL;
//Questo ciclo scandisce dall'inzio alla fine la lista,si interrompe
quando app2 è NULL cioè quando si è arrivata
//alla fine della lista
    while (app2)
    {
//Questo if confronta l'interno del nuovo nodo con l'interno puntato da
app2,fino a che linterno del nuovo nodo
//sarà maggiore di quello di app2 si va avanti con la scansione,facendo
puntare app2 al nodo succesivo, e tenendo conto
//del nodo precedente ad app2 con old
    	if (app2->interno<t_int)//if1
    	{
    		old=app2;
    		app2=app2->nextp;
    	}
//Quando finalmente linterno del nuovo nodo è minore di quello puntato
da app2 si fanno quueste operazioni
    	else if (app2->interno>t_int)
    	{
//Questo if controlla se old esiste cioè controlla che il nuovo nodo non
sia il più piccolo di tutti,
//infatti in questo caso nel primo if t_int sarebbe stato subito più
piccolo di app2->interno, stando così le cose
//non sarebbe entrato nel corpo dell'if1 dove definiva old=app2 e old
sarebbe ancora uguale a NULL
//stando così il nuovo nodo sarà intermedio quindi si fa puntare il
campo nextp del nodo old,cioè il nodo
//con il campo int più piccolo di t_int a app,il campo nextp di app ad
app2,il campo nextp di app app->nextp aad app2
//dato che t_int è più piccolo di app2->interno così si ha l'insermento
ordinato
    		if (old)
    		{
    		   old->nextp=app;
                   app->nextp=app2;
                   app->nexts=app3;
                   return 0;
            }
//Se old non esiste come spiegato prima t_int è il più piccolo quindi
app diventerà il nuovo elemento di testa
//il nextp punterà ad app2 e app->nexts punterà a app3
    		app->nextp=app2;
    		(*start)=app;
    		app->nexts=app3;
    		return 0;
    	}
//in tutti i precedenti casi si trattava di interni diversi,si inseriva
cioè il numero di un interno
//nuovo,che cioè non era ancora presente nella lista degli interni,esso
era o più piccolo o più grande
//questo if tratta il caso dove app2->interno è uguale all'interno del
nuovo nodo, in questo caso
//vuole dire l'interno del nuovo nodo è già presente nella lista cioe'
si è già trovata un'occorenza dello stesso
//nel file.
//In questo caso non bisogna creare un nuovo nodo della lista
principale(lista) ma bisogna solo aggiungere
//una nuova chiamata alla lista secondaria delle chiamate(lista2), in
coda alla stessa.
    	else if (app2->interno==t_int)
    	{
//Libero la memoria precedentemente allocata dato che non mi serve
perchè è gia presente un nodo con questo
//interno
    		free(app);
//Faccio puntare il puntatore alla lista2 al primo elemento della lista
delle chiamate del nodo già  presente
//cioè app2->nexts, in questo modo scandirò tutta la lista delle
chiamate per inserire la nuoava chiamata in coda
                app4=app2->nexts;
//Finchè app4 esiste cioè finchè app4->next è NULL quindi siamo arrivati
alla fine della lista,tenendo sempre
//conto dell'elemento precedente ad app4
    		while (app4)
    		{
    		    old2=app4;
    		    app4=app4->next;
            }
//Faccio puntare il vecchio ultimo elemento della lista al nuovo
elemento precedentemente allocato
            old2->next=app3;
            return 0;
    	}
    }
//Se si esce dal file vuol dire che il nuovo interno è più grande di
tutti i nodi della lista principale dato che non
//è mai entrato in questo if: if (app2->interno>t_int),quindi faccio
puntare app->nexts(il puntatore alla testa della lista
//delle chiamate ad app3 dato che non ci sono altri nodi con lo stesso
interno,old->nextp cioè l'elemento precedente
//a quello inserito ad app, e il puntatore app->nextp, cioè il puntatore
all'elemento successivo della lista degli intrni a
//NULL essendo esso l'elemento ultimo della suddetta
    app->nexts=app3;
    old->nextp=app;
    app->nextp=NULL;
    return 0;
}
int main()
{
    //Qui dichiaro e inizializzo a NULL il puntatore alla testa della
lista principale,blob e blob2
//che mi serviranno com appoggio nella scrittura del file
    struct lista *start=NULL,*blob;
    struct lista2 *blob2;
    FILE *f,*f1;
    int t_interno;
    char t_chiam[20],t_data[20],t_ora[20],t_durata[20];
//Apro i due file
    f=fopen("bella.txt","r");
    f1=fopen("finish.txt","w");
//Leggo tutto il file fino alla fine
    while(!(feof(f)))
    {
//Leggo i vari campi della chiamata
    	fscanf(f,"%d %s %s %s
%s\n",&t_interno,t_chiam,t_data,t_ora,t_durata);
//Inserisco il nuovo nodo
    	insert1(&start,t_interno,t_chiam,t_data,t_ora,t_durata);
    }
//Inizializzo a blob a start per stampare tutti gli elementi della lista
principale
    blob=start;
    while (blob)
    {
    	fprintf(f1,"%d \n",blob->interno);
//Idem come prima ma per la lista2 delle telefonate
    	blob2=blob->nexts;
    	while (blob2)
    	{
    	    fprintf(f1," %s %s %s %s
%f\n",blob2->chiam,blob2->data,blob2->ora,blob2->durata,blob2->valor);
    	    blob2=blob2->next;
        }
    	blob=blob->nextp;
    	fprintf(f1,"%\n\n");
    }
    printf("OPERAZIONE EFFETTUATA CON SUCCESSO,premere un tasto per
continuare");
    getchar();
//Fine
}
Spero che così sia più chiaro,scusate per la scarsezza di informazioni e
commenti ma sono abituato a non scrivere
niente dato che per fare i programmi abbiamo solo un'ora e mezza, e non
faccio in tempo a scrivere i commenti.
La mia domanda era capisco che due compilatori diversi possano dare
diversi errori in fase di compilazione, ma quando
si compila e si produce il codice eseguibile i due non dovrebbero essere
uguali,come fa uno a non darmi errori di lettura
di memoria e l'altro si.
Grazie per la pazienza e scusate se vi ho fatto perdere tempo a leggere
del codice illeggibile.
  Vincenz


 di memoria e l'altro si.
Io lo farei piu' lineare, togliendo diverse variabili temp. dal codice e 
gestendo un minimo di controllo di errori.
Come passatempo domenicale :-) ho provato a farne uno simile al tuo, 
lasciando le strutture come richieste, sulla base di quanto sopra hai 
detto (spero di aver capito). E' circa nove anni che non programmo in C 
full-time (oggi uso altri linguaggi), quindi *riguardalo* se va bene ed 
eventualmente prendilo come possibile soluzione.
Inoltre scusa la "notazione (quasi) ungherese" che uso per i nomi delle 
variabili, ero/sono abituato cosi' :-) (tra l'altro mi piacerebbe aprire 
un thread su questo argomento).
NB: ci sono dei "goto err" e possono non piacere a tutti (nella forma 
che ho usato e' di solito ben accetto).
Ciao
/Sorry/ per i commenti :-)
Provato solo con gcc su linux.
// ............................................. //
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define TRUE 1
#define FALSE 0
typedef struct lista2
{	char	*chiam;
	char	*data;
	char	*ora;
	char	*durata;
	float	valor;		/* da implementare */
	struct lista2 *next;
} CHIAMATA, *PCHIAMATA;
typedef struct lista
{	int 		interno;
	float 		costo;   /* da implementare */
	struct lista   *nextp;
	struct lista2  *nexts;
} LISTA, *PLISTA;
int inserisci(PLISTA *ppRootLista, int nInterno, char *pTelChiam, char 
*pData, char *pOra, char *pDurata)
{	PLISTA 	pLista = NULL,
		pListaLast = NULL;
	PCHIAMATA pNewChiamata = NULL;
	if(!ppRootLista)
		return (FALSE);
	if(!(pNewChiamata = malloc(sizeof(*pNewChiamata))))
		goto err;
	memset(pNewChiamata, 0, sizeof(*pNewChiamata));
 
	if(!(pNewChiamata->chiam = strdup(pTelChiam)))
		goto err;
	if(!(pNewChiamata->data = strdup(pData)))
		goto err;
	if(!(pNewChiamata->ora = strdup(pOra)))
		goto err;
	if(!(pNewChiamata->durata = strdup(pDurata)))
		goto err;
	for(	pListaLast = NULL, pLista = *ppRootLista;
		pLista && pLista->interno < nInterno;
		pListaLast = pLista, pLista=pLista->nextp
	);
	if(!(pLista && pLista->interno == nInterno))
	{	PLISTA pL = malloc(sizeof(*pL));
		if(!pL)
			goto err;
		memset(pL, 0, sizeof(*pL));
		pL->interno = nInterno;
		if(!*ppRootLista || !pListaLast)
			*ppRootLista = pL;
		pL->nextp = pLista;
		if(pListaLast)
			pListaLast->nextp = pL;
		pLista = pL;
	}
	if(pLista->nexts)
	{	PCHIAMATA pC = NULL;
		for(pC = pLista->nexts; pC && pC->next; pC = pC->next)
			;
		pC->next = pNewChiamata;
	}
	else	pLista->nexts = pNewChiamata;
	return (TRUE);
err:
	if(pNewChiamata)
	{	if(pNewChiamata->chiam)
			free(pNewChiamata->chiam);
		if(pNewChiamata->data)
			free(pNewChiamata->data);
		if(pNewChiamata->ora)
			free(pNewChiamata->ora);
		if(pNewChiamata->durata)
			free(pNewChiamata->durata);
	}
	return (FALSE);
}
void freeAll(PLISTA *ppRootLista)
{	PLISTA pL, pLista;
	PCHIAMATA pC, pChiamata;
	if(ppRootLista)
	{	for(pLista = *ppRootLista; (pL = pLista); )
		{	for(pChiamata = pLista->nexts; (pC = pChiamata);)
			{	pChiamata = pC->next;
				free(pC);
			}
			pLista = pLista->nextp;
			free(pL);
		}
		ppRootLista = NULL;
	}
}
int main()
{	PLISTA pL, pRootLista = NULL;
	PCHIAMATA pC;
	FILE    *fp;
	int     nInterno;
	char    szTelChiam[20], szData[20], szOra[20], szDurata[20];
	char    szLine[255];
	if((fp = fopen("bella.txt", "r")))
         {	while(!(feof(fp)))
                 {	if(!fgets(szLine, sizeof(szLine)-1, fp))
                                 break;
			if(5 != sscanf(szLine, "%d %19s %19s %19s %19s", &nInterno, 
szTelChiam, szData, szOra, szDurata))
				continue;  /* migliorare/implementare il controllo dati in input? */
			inserisci(&pRootLista, nInterno, szTelChiam, szData, szOra, szDurata);
		}
		fclose(fp);
         }
         for(pL = pRootLista; pL; pL = pL->nextp)
         {	printf("%d\n", pL->interno);
		for(pC = pL->nexts; pC; pC = pC->next)
			printf("\t%s %s %s %s\n", pC->chiam, pC->data, pC->ora, pC->durata);
         }
	freeAll(&pRootLista);
	return (0);
}
-- 
Cybertoldo
Per rispondermi via email, sostituisci moc.liamg con 
gmail.com

 }
...e, come giustamente ha scritto Andrea, se dovesse mancare la funz. 
strdup(), dopo le #include <...> e' possibile mettere qualcosa del tipo:
#define HAS_STRDUP 1 /* impostare a 0 o 1 */
#if !HAS_STRDUP
char *__MY_strdup(const char *s)
{	char *p = malloc(strlen(s) + 1);
	if (p)
		strcpy(p, s);
	return p;
}
#define strdup  __MY_strdup
#endif


 #define HAS_STRDUP 1 /* impostare a 0 o 1 */
No no, basta un #ifndef strdup
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

 
...l'ho fatta cosi' in modo che sia 'anche' possibile provare in fase di 
test (o anche utilizzare al posto di quella "ufficiale") la "nostra" 
strdup(), semplicemente ponendo a 0 o 1 il valore. Non mi sembra 
disturbi + di tanto il codice... :-)
PS: Quando (in antichita', dirai tu... :) ) c'erano problemi di 
compatibilita' con i vari compilatori - su altrettanto vari sistemi op. 
- questa era una delle tecniche 'normalmente' utilizzate. Anche perche' 
succedeva frequentemente di trovare funzioni standard (o quasi) buggate 
o diverse come comportamento.


 char *__MY_strdup(const char *s)
[...]
Per dovere di cronaca gli identificatori che
iniziano con due underscore __ oppure con un
underscore _ seguiti da una lettera maiuscola sono
sempre riservati.
Il loro uso provoca "comportamento indefinito".
Per sicurezza sarebbe meglio usare sempre nomi
che NON iniziano con "_".


strdup()
Bah... quella funzione ha un comportamento banale, non è che ci sia
molto da testare...

                                        free(pC->durata);
free(NULL) è esplicitamente consentito dallo standard.
Luca
-- 
Home: 
http://kronoz.cjb.net
#include <stdio.h> 
int main(void) {printf("\t\t\b\b\b\b\b\b");
printf("\t\t\b\b\b\b\b\b");return 0;}