Salve a tutti! 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), oppure inserire un nuovo grafo e memorizzarlo su un nuovo file. Per il momento sono ancora alla prima parte e ho alcuni problemi...
I file sono i seguenti:
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 "grafo.h"
int menuIniziale();
int main()
{
FILE *file;
GrafoAdj G=NULL; GrafoMatr M=0;
int numVertici=0, scelta, tipo;
char * nome="grafo1.txt";
scelta=menuIniziale();
if(scelta==1)
{
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) G=parsegrafoLista(file,G); // Parse grafo
else if(tipo==2) M=parsegrafoMatrice(file,M,&numVertici);
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");
return 0;
}
int menuIniziale()
{
int x;
printf("1)Leggi il grafo da un file;\n2)Scrivi un nuovo grafo su un file.\n");
scanf("%d",&x);
return x;
}
grafolista.h
#ifndef GRAFO_H_INCLUDED
#define GRAFO_H_INCLUDED
typedef struct grafo * GrafoAdj;
typedef struct lista * ListaAdj;
GrafoAdj creaNodoLista(GrafoAdj g, int val);
ListaAdj lista_insert(ListaAdj adj , int elem);
GrafoAdj creaNodoListaAdj (GrafoAdj g, int val, int nodo);
void stampa (GrafoAdj g);
void lista_stampa(ListaAdj lista);
#endif // GRAFO_H_INCLUDED
grafolista.c
#include <stdio.h>
#include <stdlib.h>
#include "grafolista.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;
g->adiacenze=NULL;
g->next=NULL;
}
return g;
}
ListaAdj lista_insert(ListaAdj adj , int elem)
{
if(adj==NULL)
{
ListaAdj tmp=(lista*)malloc(sizeof(lista));
tmp->vertice=elem;
tmp->next=NULL;
return tmp;
}
else
{
adj->next=lista_insert(adj->next,elem);
return adj;
}
}
GrafoAdj creaNodoListaAdj (GrafoAdj g, int val, int nodo)
{
if (g->vertice==nodo) // verifica che il vertice del grafo corrisponde al nodo di cui bisogna aggiungere la lista di adj
g->adiacenze=lista_insert(g->adiacenze,val);
else
g=creaNodoListaAdj(g->next,val,nodo);
return g;
}
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);
}
}
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
GrafoAdj parsegrafoLista (FILE *file, GrafoAdj G);
GrafoMatr parsegrafoMatrice (FILE *file, GrafoMatr M, int * numVertici);
#endif // GRAFO_H_INCLUDED
grafo.c
#include <stdio.h>
#include <stdlib.h>
#include "grafolista.h"
#include "grafomatrice.h"
#include "grafoparser.h"
#include "grafo.h"
GrafoAdj parsegrafoLista (FILE *file, GrafoAdj G)
{ //Traduce il grafo [ritorna il puntatore alla radice]
int x,n=0,val;
n=traduciNumeroNodi(file); //leggi il numero di nodi che dovrà contenere il grafo
printf("Numero nodi: %d\n\n",n);
while(n)
{
x=confronto(file,NODO); //verifica che dopo il numero di nodi ci sia un nodo stesso
if(x)
{
val=traduciIntero(file); //estrai il primo nodo
G=creaNodoLista(G,val); //crea il nodo con il simbolo estratto
printf("Il nodo %d ",val);
verticiAdj(G,0,val,file); //traduce i vertici adiacenti al nodo
}
n=n-1;
}
// else ERRORE NESSUN NODO PRESENTE!!!
return G;
}
GrafoMatr parsegrafoMatrice (FILE *file, GrafoMatr M, int * numVertici)
{ //Traduce il grafo [ritorna il puntatore alla radice]
int x,n=0,val;
n=traduciNumeroNodi(file); //leggi il numero di nodi che dovrà contenere il grafo
*numVertici=n;
printf("SONO IN parsegrafoMatrice\n");
M=inizializzaMatrice(M,n);
printf("Numero nodi: %d\n\n",n);
while(n)
{
x=confronto(file,NODO); //verifica che dopo il numero di nodi ci sia un nodo stesso
if(x)
{
val=traduciIntero(file); //estrai il primo nodo
printf("Il nodo %d ",val);
verticiAdj(NULL,M,val,file); //traduce i vertici adiacenti al nodo
}
n=n-1;
}
// else ERRORE NESSUN NODO PRESENTE!!!
return M;
}
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 confronto(FILE *file, type x);
void sposta (FILE *file, type x);
void spostaIndietro (FILE *file, type x);
int traduciNumeroNodi(FILE *file);
int traduciIntero(FILE *file);
float traduciPeso (FILE *file);
void verticiAdj (GrafoAdj G, GrafoMatr M, int nodo, 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 traduciNumeroNodi(FILE *file)
{//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)
{//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 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 alla parentesi chiusa perchè la parte decimale del float è indifferente nel nostro caso
sposta(file,NODO); //salta lo 0
}
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 la parentesi è stata trovata verificare che il simbolo successivo sia il 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
}
Allora questo è tutto il codice, che innanzitutto è un po' ridodante nelle funzioni di traduzione una per ogni caso, in quanto non mi veniva altra soluzione. E inoltre se eseguo il codice funziona, la stampa del grafo corrisponde al grafo del file di testo, eppure il compilatore mi da 4 warning:
warning: implicit declaration of function 'parsegrafoLista' [-Wimplicit-function-declaration]|
warning: assignment makes pointer from integer without a cast [enabled by default]|
warning: implicit declaration of function 'parsegrafoMatrice' [-Wimplicit-function-declaration]|
warning: assignment makes pointer from integer without a cast [enabled by default]|
Premetto chiaramente che sono alle primissime armi
Grazie