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