Libreria Grafi Parsing

di il
21 risposte

Libreria Grafi Parsing

Buonasera! Sto creando una libreria per la gestione dei grafi: il programma chiamante deve prevedere la possibilità di caricare il grafo a partire da un file (in cui è descritto secondo le regole di una specifica grammatica), inserire un nuovo grafo e memorizzarlo su un nuovo file, passare da una rappresentazione a liste di adiacenza a matrici di adiacenza e viceversa.
Premesso che il main è del tutto indefinito, in quanto la traccia è parecchio lunga e sto cercando prima di tutto di creare le funzioni una dopo l'altra e dopo mi occupo di come voglio siano organizzati i vari menu.
Inoltre siccome sto cercando di risolvere vari problemi, ci sono molti stampe a video inutili, che mi servono solo per capire passo dopo passo cosa sta facendo il programma.
Il problema che riscontro è la traduzione da matrici di adiacenza a liste, compila, esegue, ma la funzione da un risultato errato, e mi sfugge completamente dove sia l'errore!

Sia un file di esempio il seguente:
grafo1.txt
(6) 1->(+1.0) 1|2; 2->(+2.0) 2|3 2|4; 3->(+2.0) 3|4 3|6; 4->(-0.0); 5->(+1.0) 5|1; 6->(-0.0);.

main.c
#include <stdio.h>
#include <stdlib.h>
#include "grafolista.h"
#include "grafomatrice.h"
#include "grafoparser.h"
#include "grafo.h"

int menuIniziale(void);
char * scegliFile(void);
char * scriviGrafo(void);

int main()
{
    FILE *file;
    char *nome;
    GrafoAdj G=NULL, Gc=NULL;
    GrafoMatr M=0, Mc=0;
    int numVertici=0;
    int scelta,tipo,conv;

    scelta= menuIniziale();

    if (scelta==1) nome = scegliFile();
    else nome= scriviGrafo();

    file = fopen(nome,"r");

    printf("Crea un grafo da file\nScegli il tipo di rappresentazione:\n1)Liste di adiacenza\n2)Matrice di adiacenza\n\n");
    scanf("%d",&tipo);
    printf("\n\nINIZIO TRADUZIONE FILE...\n");
    system("PAUSE"); system("cls");
    printf("Le informazioni estratte sono le seguenti:\n\n");

    if(tipo==1) numVertici=parseGrafo(file,&G,0,tipo);        // Parse grafo
    else if(tipo==2) numVertici=parseGrafo(file,NULL,&M,tipo);

    fclose(file);

    printf("\nIl grafo creato:\n");
    if(G!=NULL) stampa(G);
    else if (M!=NULL) stampaMatr(M,numVertici);
    else
        printf("Grafo vuoto\n");

    system("PAUSE");
    system("cls");
    printf("Converti da un tipo ad un altro:\n1)Da Lista a Matrice\n2)Da Matrice a Lista\n");
    scanf("%d",&conv);
    if(conv==1)
    {
        Mc=convertToMatrice(G,Mc,numVertici);
        printf("Da : \n\n");
        stampa(G);
        printf("A: \n\n");
        stampaMatr(Mc,numVertici);
    }
    else
    {
        Gc=convertToLista(Gc,M,numVertici);
        printf("Da : \n\n");
        stampaMatr(M,numVertici);
        printf("A: \n\n");
        stampa(Gc);
    }



    system("PAUSE");
    return 0;
}

int menuIniziale(void)
{
    int x;
    printf("1)Leggi il grafo da un file;\n2)Scrivi un nuovo grafo su un file.\n");
    scanf("%d",&x);

    return x;
}

char *scegliFile(void)
{
    char *nome; int x,y;
    system("cls");
    printf("SCEGLI FILE TRA QUELLI ESISTENTI\n1) Grafo 1\n2) Grafo 2\n3) Grafo 3\n");
    scanf("%d",&x);printf("\n");
    switch(x)
    {
    case 1:
        nome="grafo1.txt";
        break;
    case 2:
        nome="grafo2.txt";
        break;
    case 3:
        nome="grafo3.txt";
        break;
    default:
        printf("::ERRORE:: La scelta non è valida!!\n\n Riprova -> 1\nPremi un tasto qualsiasi per Uscire...\n");
        scanf("%d",&y);
        if(y==1) nome=scegliFile();
        else exit(1);
    }

    return nome;
}

char * scriviGrafo()
{
    system("cls");
    int n,x,y,j,v,i;
    char *nome="grafonew.txt";
    FILE *filenuovo=fopen("grafonew.txt","w");
    printf("\t\t.:POPOLAMENTO GRAFO:.\n\n");
    printf("Quanti vertici deve contenere il grafo? ");
    scanf("%d",&n); printf("\n");
    fprintf(filenuovo,"%c%d%c",'(',n,')');

    for(i=1;i<=n;i++)
    {
        printf("\nVertice %d :\n",i);
        fprintf(filenuovo,"%c%d%s",' ',i,"->");
        printf("\n1)Crea Archi\n2)Passa al vertice successivo\n");
        scanf("%d",&x);
        if(x==2) fprintf(filenuovo,"%s","(-0.0);");
        else
        {
            printf("Quanti archi? ");
            scanf("%d",&y);printf("\n");
            fprintf(filenuovo,"%s%d%s","(+",y,".0)");
            printf("Inserisci vertici incidenti \n");
            for(j=1;j<=y;j++)
            {
                scanf("%d",&v);
                fprintf(filenuovo,"%c%d%c%d",' ',i,'|',v);
                if(j==y) fprintf(filenuovo,"%c ",';');
            }

        }

    }

    fprintf(filenuovo,"%c",'.');
    printf("FILE SCRITTO CON SUCCESSO!!!\n");
    fclose(filenuovo);
    system("PAUSE");

    return nome;
}
grafoparser.h
#ifndef GRAFOPARSER_H_INCLUDED
#define GRAFOPARSER_H_INCLUDED

typedef enum {PARSX, PARDX, NODO, PUNTO, MENO, PIU, PUNT, PUNTOV, BARRA, PESO} type; // Tipo dei simboli terminali

int parseGrafo (FILE *file, GrafoAdj *G, GrafoMatr *M, int tipo);
void verticiAdj (GrafoAdj G, GrafoMatr M, int nodo, FILE *file);
int confronto(FILE *file, type x);
void sposta (FILE *file, type x);
int traduciNumeroNodi(FILE *file);
int traduciIntero(FILE *file);
float traduciPeso (FILE *file);

#endif // GRAFOPARSER_H_INCLUDED
grafoparser.c
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#include <ctype.h>
#include "grafolista.h"
#include "grafomatrice.h"
#include "grafoparser.h"

// Elaborazione simboli NON TERMINALI

int parseGrafo (FILE *file, GrafoAdj *G, GrafoMatr *M, int tipo)
{ //Traduce il grafo [ritorna il puntatore alla radice]
    int x,n=0,val,numVertici;

    n=traduciNumeroNodi(file); //leggi il numero di nodi che dovrà contenere il grafo
    numVertici=n; //mantengo il numero dei vertici in una variabile
    if(tipo==2) *M=inizializzaMatrice(*M,n);
    printf("Numero nodi: %d\n\n",n);
    while(n)
    {
        printf("n=%d\n",n);
        x=confronto(file,NODO); //verifica che dopo il numero di nodi ci sia un nodo stesso
        if(x)
        {
            printf("Trovato nodo!\n");
            val=traduciIntero(file); //estrai il primo nodo
            printf("Il nodo %d ",val);
            if(tipo==1)
            {
                *G=creaNodoLista(*G,val);
                verticiAdj(*G,0,val,file);
            }
            else verticiAdj(NULL,*M,val,file); //traduce i vertici adiacenti al nodo
        }
        else printf(":: ERRORE VERTICE! ::\n\n");

        n=n-1;
    }
    // else ERRORE NESSUN NODO PRESENTE!!!
    return numVertici;
}

int traduciNumeroNodi(FILE *file) // DOPO LA FUNZIONE LO STREAM SI TROVA DOPO LA PARENTESI CHIUSA
{//Esamina i simboli che rappresentano il numero di nodi [se ' (numeroIntero) ' ritorna il numero, altrimenti errore]
    int n=0;
    if(confronto(file,PARSX)) //se il simbolo corrente è una parentesi aperta è verificato il primo simbolo
    {
        sposta(file,PARSX);//ci si sposta al simbolo successivo la parentesi
        if (confronto(file,NODO)) // se il simbolo corrente è del tipo nodo è verificato il secondo simbolo
            {
                n=traduciIntero(file);
                //sposta(file,NODO); //ci si sposta al simbolo successivo al nodo NON NECESSARIO
                if(confronto(file,PARDX)) //se il simbolo corrente è una parentesi chiusa è verificato anche il terzo simbolo
                    {
                        sposta(file,PARDX); //si sposta al simbolo successivo all'interno del file
                        return n;}
                }
    }
    return 0; //ritorna errore
}

int traduciIntero (FILE *file) // DOPO LA FUNZIONE LO STREAM SI TROVA DOPO L'INTERO
{//Traduci il simbolo non terminale che rappresenta un intero [ritorna il vertice intero del nodo]
	int c=0,num=0,l=0;
	while ((c=fgetc(file)) != EOF && isdigit(c)) {
		  if (num <= ((INT_MAX - (c-'0'))/10)){
		      num = num*10 + (c-'0');
		      l++;
   		  }
	     // else syntax_error("Integer ID <= 2147483647",file); // Number too big: ERROR
	}
	//if (l==0) syntax_error("Integer ID",file); // The ID is not a number
	if(c != EOF)       // If EndOfFile not yet reached
		ungetc(c,file);      // push the last character back to the file

	return num;
}

float traduciPeso (FILE *file)
{
    float peso;
    int x;
    sposta(file,PESO); //sposta al simbolo successivo a PIU o MENO che indica l'inzio del peso
    x=traduciIntero(file);
    if (confronto(file,PUNTO)) //se dopo l'intero c'è un un punto allora è un float
    {
        sposta(file,PUNTO); //sposta allo stream successivo al punto
        sposta(file,NODO); // // lo zero

    }
    else
    {
        printf("Errore Sintassi Peso! Il numero non è floating point!!\n");
        return 0;
    }

    peso=(float)x;

    sposta(file,PARDX);

    return peso;
}

void verticiAdj (GrafoAdj G, GrafoMatr M, int nodo, FILE *file)
{//Traduci vertici adiacenti
    int res,val;
    float peso;
    res=confronto(file,PUNT);  // Cerca freccia che indica a quali vertici punta il nodo in questione
    if (res)
    {// Se IL SIMBOLO PUNTATORE è stato trovata verificare che segua un peso
        sposta(file,PARSX);
        if(confronto(file,PESO))
        {
            peso=traduciPeso(file);

            if(peso>1)
                printf("ha %d figli: ", (int)peso);
            else if (peso==0)
                printf("non ha figli.");
            else
                printf("ha 1 figlio: ");

            while (peso>0)
            {
                sposta(file,NODO);
                sposta(file,BARRA); //dopo la barra si trovano i vertici adiacenti
                sposta(file,NODO);
                val=traduciIntero(file);
                printf("%d ",val);
                if(G!=NULL) G=creaNodoListaAdj(G,val,nodo);
                else M[nodo-1][val-1]=1;
                peso=peso-1;
            }

            printf("\n");

            sposta(file,PUNTOV);
        }

	}

	 else printf("ERRORE SINTASSI PESO -2!\n");
}


// Elaborazione simboli TERMINALI

int confronto(FILE *file, type x)
{ //Verifica se il tipo x corrisponde al simbolo nel file [ritorna 1  se vero, 0 altrimenti]
	char c;
	type rp;                       // Read symbol type
	int res=0;

	while(((c = fgetc(file)) == '\t') || (c== '\n') || (c== ' '))
			;
    switch(c) {               // Determine the read symbol type
        case '(': rp = PARSX; break;
        case ')': rp = PARDX; break;
        case '-':
            rp=MENO;
            if(confronto(file,PUNT)) rp=PUNT;
            else rp=PESO;
            break;
        case '>': rp=PUNT; break;
        case '+': rp=PESO; break;
        case ';': rp = PUNTOV; break;
        case '|': rp = BARRA; break;
        case '.': rp= PUNTO; break;
        default : rp = NODO; break;
    }

    ungetc(c,file); // Push the read character back to the file

    if(rp==PUNT) //Se il tipo è un puntatore effettuo uno spostamento in avanti in quanto il simbolo corrente potrebbe essere il meno perchè il simbolo del punt è fatto da '-' e '>'
        sposta(file,PUNT);

    if (rp==x)        // The expexted type et and the read symbol type rp match
			res = 1;

  return res;
}

void sposta (FILE *file, type x)
{//si sposta nel file al simbolo successivo a quello del tipo x
	int dim = 0;

    switch(x) {               // Assign the read symbol type
   	   case PARSX:; case PARDX:; case NODO:; case PUNTO:; case MENO:; case PIU:; case PUNT:; case PUNTOV:; case BARRA:; case PESO:dim=1; break;
    } //qualunque sia il simbolo ricevuto dim=1, ci si sposta di un passo

	fseek(file,dim,SEEK_CUR);   // Si muove di dim passi a partire da quello corrente all'interno del file
}
grafolista.h
#ifndef GRAFOLISTA_H_INCLUDED
#define GRAFOLISTA_H_INCLUDED

typedef struct grafo * GrafoAdj;
typedef struct lista * ListaAdj;

GrafoAdj creaNodoLista(GrafoAdj g, int val);
GrafoAdj creaNodoListaAdj (GrafoAdj g, int val, int nodo);
ListaAdj lista_insert(ListaAdj adj , int elem);
void stampa (GrafoAdj g);
void lista_stampa(ListaAdj lista);
int verificaArco(GrafoAdj G, int x, int y);
int verificaAdiacenze(ListaAdj lista, int y);

#endif // GRAFOLISTA_H_INCLUDED
grafolista.c
#include <stdio.h>
#include <stdlib.h>
#include "grafolista.h"
#include <stdbool.h>

typedef struct grafo {
int vertice;
ListaAdj adiacenze;
struct grafo * next;
}grafo;

typedef struct lista{
int vertice;
struct lista *next;
}lista;

GrafoAdj creaNodoLista (GrafoAdj g, int val)
{
    if(g!=NULL)
        g->next=creaNodoLista(g->next,val);
    else
    {
        g=(grafo *)malloc(sizeof(grafo));
        if(g==NULL) printf("Errore allocazione nodo grafo!\n");
        g->vertice=val; printf("g->vertice=%d\n",g->vertice);
        g->adiacenze=NULL;
        g->next=NULL;
    }
return g;
}

GrafoAdj creaNodoListaAdj (GrafoAdj g, int val, int nodo)
{
    if(g==NULL) printf("::Errore:: Grafo Vuoto!\n\n");
    else
    {
    if (g->vertice==nodo) // verifica che il vertice del grafo corrisponde al nodo di cui bisogna aggiungere la lista di adj
        {
            printf("g->vertice==nodo\n");
            g->adiacenze=lista_insert(g->adiacenze,val);
        }
    else
        g=creaNodoListaAdj(g->next,val,nodo);

    }

return g;
}

ListaAdj lista_insert(ListaAdj adj , int elem)
{
    if(adj==NULL)
    {
        ListaAdj tmp=(lista*)malloc(sizeof(lista));
        tmp->vertice=elem; printf("tmp->vertice = %d\n",tmp->vertice);
        tmp->next=NULL;
        return tmp;
    }
    else
    {
        adj->next=lista_insert(adj->next,elem);
        return adj;
    }
}

void stampa (GrafoAdj g)
{
    if (g==NULL) { printf("\n"); return;}
    else
    {
        if(g->adiacenze)
        {
            printf(" %d -> ",g->vertice);
            lista_stampa(g->adiacenze);
        }

        else printf(" %d -> NULL \n",g->vertice);

        stampa(g->next);

    }

}

void lista_stampa(ListaAdj lista) {

    if (lista == NULL) {printf("\n"); return;}
    else
    {
        printf(" %d",lista->vertice);
        lista_stampa(lista->next);
        }
}


int verificaArco(GrafoAdj G, int x, int y)
{
    int arco;

    if(G->vertice!=x)
        arco=verificaArco(G->next,x,y);
    else
        {
            if(G->adiacenze==NULL) return 0;
            else
            {
                printf("Per il vertice %d, G->adiacenze != NULL\n",G->vertice);
                arco=verificaAdiacenze(G->adiacenze,y);
            }

        }
    return arco;
}

int verificaAdiacenze(ListaAdj lista, int y)
{
    int arco;
    if(lista==NULL) arco=0;
    else
    {
        if (lista->vertice==y) arco=1;
        else arco=verificaAdiacenze(lista->next,y);
    }

    printf("arco in verificaAdiacenze e' %d\n",arco);
    return arco;
}

grafomatrice.h
//grafomatrice.h

#ifndef GRAFOMATRICE_H_INCLUDED
#define GRAFOMATRICE_H_INCLUDED

typedef int**  GrafoMatr;

GrafoMatr inizializzaMatrice(GrafoMatr M, int n);
void stampaMatr (GrafoMatr M, int n);

#endif // GRAFOMATRICE_H_INCLUDED
grafomatrice.c
#include <stdio.h>
#include <stdlib.h>
#include "grafomatrice.h"

GrafoMatr inizializzaMatrice(GrafoMatr M, int n)
{
    int i,j;
    M=(int**)malloc((n-1)*sizeof(int*));
    for(i=0;i<n;i++)
    {
        M[i]=(int*)malloc((n-1)*sizeof(int));
        for(j=0;j<n;j++) M[i][j]=0;
    }
    return M;
}

void stampaMatr (GrafoMatr M, int n)
{
    int i,j;
    printf("    ");
    for(i=0;i<n;i++) printf("%d ",i+1);
    printf("\n\n");
    for(i=0;i<n;i++)
    {
        printf("%d   ",i+1);
        for(j=0;j<n;j++)
            printf("%d ",M[i][j]);
        printf("\n");
    }
}
grafo.h
#ifndef GRAFO_H_INCLUDED
#define GRAFO_H_INCLUDED

GrafoMatr convertToMatrice (GrafoAdj G, GrafoMatr M, int n);
GrafoAdj convertToLista (GrafoAdj G, GrafoMatr M, int n);

#endif // GRAFO_H_INCLUDED
grafo.c
#include <stdio.h>
#include <stdlib.h>
#include "grafolista.h"
#include "grafomatrice.h"
#include "grafo.h"

GrafoMatr convertToMatrice (GrafoAdj G, GrafoMatr M, int n)
{
    int i,j,y;
    M=inizializzaMatrice(M,n);
    for(i=0;i<n;i++)
    {
        for(j=0;j<n;j++)
        {
            printf("Chiamo verificaArco per %d,%d\n",i+1,j+1);
            y=verificaArco(G,i+1,j+1);
            if(y==1)M[i][j]=1;
        }
    }

    return M;
}

GrafoAdj convertToLista (GrafoAdj G, GrafoMatr M, int n)
{
    int i,j;
    for(i=0;i<n;i++)
    {
        G=creaNodoLista(G,i+1);
        printf("E' stato aggiunto il VERTICE  %d\n", i+1);
        for(j=0;j<n;j++)
        {
            if((M[i][j])==1)
            {
                printf("Esiste un arco da %d a %d\n",i+1,j+1);
                G=creaNodoListaAdj(G,j+1,i+1);
            }

        }
    }

    return G;
}
Questo è tutto il codice. Ripeto che la funzione convertToLista è quella che mi da problemi, o almeno credo, ma certamente non ottengo il risultato sperato, ma mi restituisce solo gli ultimi vertici nella stampa delle liste.
Grazie per l'attenzione

21 Risposte

  • Re: Libreria Grafi Parsing

    Ho provato ad eseguirlo. Ho un comportamento strano nella fclose(file);
    se eseguo tramite:
    lettura file: 1)
    grafo1: 1)
    matrice di addiacenza: 2)

    Che sistema operativo usi? Che compilatore?
  • Re: Libreria Grafi Parsing

    Sto usando CodeBlocks 13.12 su Windows 7
  • Re: Libreria Grafi Parsing

    Se esegui con quella sequenza non hai errori alla fclose?
  • Re: Libreria Grafi Parsing

    Nono nessun errore.. il programma termina
  • Re: Libreria Grafi Parsing

    Il problema dovrebbe essere nella parseGrafo quando lavora come matrice, ma non riesco a determinare quale sia.
  • Re: Libreria Grafi Parsing

    Non riesco ad individuare il problema
  • Re: Libreria Grafi Parsing

    Ho lo stesso problema anche nella prima versione del programma!

    Se commento in entrambi i casi la fclose il programma va fino in fondo.
  • Re: Libreria Grafi Parsing

    Che cosa strana, io non ho alcun problema a terminare il programma...
  • Re: Libreria Grafi Parsing

    Allora quel problema l'ho risolto:

    E' nell'allocazione della matrice:
    
    GrafoMatr inizializzaMatrice(GrafoMatr M, int n) {
        int i,j;
        M=(int**)malloc((n)*sizeof(int*));
        for(i=0; i<n; i++) {
            M[i]=(int*)malloc((n)*sizeof(int));
            for(j=0; j<n; j++) M[i][j]=0;
        }
        return M;
    }
    
    Hai allocato n-1 e non n.

    Adesso vediamo che la convertToLista.
  • Re: Libreria Grafi Parsing

    Hai allocato n-1 e non n.
    Giusto! Eppure io non me ne sarei mai accorta di questo errore. Secondo te come è possibile che a te dava errore e a me no? Chiedo per il futuro..
  • Re: Libreria Grafi Parsing

    Forse perché le allocazioni di memoria della matrice nella mia macchina producevano qualche conflitto con le allocazioni di memoria del puntatore file, quindi il sistema mandava un SIGALLARM.
    Io lavoro con una macchina linux, forse per quello, non me lo spiego correttamente.

    Ad ogni modo scusami se te lo dico, ma è difficile correggere codice scritto da altri, e ci sono cose nelle strutture dati che davvero non mi piacciono, secondo me la fonte di errore sta in come allochi la struttura grafo con la lista.

    Ecco perché ti dicevo che la cosa più importante è fare un minimo di progetto, perché la manutenibilità del codice è la cosa più costosa durante l'intera vita del codice stesso e come vedi venirne a capo non è poi semplicissimo e ti fa perdere più tempo di quanto non ne abbia impiegato a scriverlo.

    Dopo provo a vedertelo ancora.
  • Re: Libreria Grafi Parsing

    Ad ogni modo scusami se te lo dico, ma è difficile correggere codice scritto da altri,
    Fai benissimo a dirmelo perchè devo correggermi altrimenti non imparerò mai.
    e ci sono cose nelle strutture dati che davvero non mi piacciono
    tipo? Quello che mi dicevi nell'altra discussione?
  • Re: Libreria Grafi Parsing

    violet_prog ha scritto:


    tipo? Quello che mi dicevi nell'altra discussione?
    Esatto!

    Correggere codice scritto da altri è di solito più difficile, proprio perché, quel codice non lo hai pensato o progettato tu; quindi, ti adegui a quello che è il progetto esistente. Ma questo è la norma, il problema è quando trovi, dal tuo punto di vista, alcune cose sbagliate concettualmente. Certo tutto poi funziona, ma trovo sia ancor più difficile venirne a capo.

    Ad ogni modo non mi permetto assolutamente di giudicare nulla, chi sarei per farlo, dicevo solo che trovo qualche difficoltà a debuggare questo codice, perché si discosta un po' da come l'avrei fatto io.
  • Re: Libreria Grafi Parsing

    il problema è quando trovi, dal tuo punto di vista, alcune cose sbagliate concettualmente. Certo tutto poi funziona, ma trovo sia ancor più difficile venirne a capo.

    Ad ogni modo non mi permetto assolutamente di giudicare nulla, chi sarei per farlo, dicevo solo che trovo qualche difficoltà a debuggare questo codice, perché si discosta un po' da come l'avrei fatto io.
    Invece per me che sto alle prime armi è essenziale capire i punti di vista delle persone più esperte per imparare, in quanto sento di non aver acquisito ancora un metodo.
Devi accedere o registrarti per scrivere nel forum
21 risposte