Libreria Personale Grafi errore funzioni implicite

di il
14 risposte

Libreria Personale Grafi errore funzioni implicite

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

14 Risposte

  • Re: Libreria Personale Grafi errore funzioni implicite

    Io rinuncerei all'idea di rappresentare un grafo
    con una stringa di testo, cosa che impone la creazione
    di una funzione di parsing. E, se il grafo e' complicato,
    e' facile digitare una stringa erronea, con le complicazioni
    che ne conseguono.

    Mi pare piu' semplice salvare su file, delle struct
    che memorizzano i dati che descrivono il grafo.

    Con la struct:
    
    typedef struct 
     {
      unsigned int nodo_1;
      unsigned int nodo_2;
      float peso;
     } arco;
    
    e' possibile, tramite ciclo, inserire i dati che descrivono
    tutti gli archi del grafo.

    Ad esempio, per inserire un grafo triangolare (non orientato)
    (1 e' collegato a 2 e 3, 2 e' collegato a 1 e 3, 3 e' collegato a 1 e 2),
    basterebbe dare in input queste triple:

    nodo_1=1, nodo_2=2, peso=3.5;
    nodo_1=1, nodo_2=3, peso=2,7;

    nodo_1=2, nodo_2=1, peso=3.5;
    nodo_1=2, nodo_2=3, peso=1.2;

    nodo_1=3, nodo_2=1, peso=2.7;
    nodo_1=3, nodo_2=2, peso=1.2.

    Se il grafo e' orientato (ad es., 1 e' collegato a 2, 2 a 3 e 3 a 1),
    le triple si riducono:

    nodo_1=1, nodo_2=2, peso=3.5;
    nodo_1=2, nodo_2=3, peso=1.2;
    nodo_1=3, nodo_2=1, peso=2.7.

    Leggendo il file delle struct cosi' costruite
    e' possibile inizializzare le strutture che servono
    per effettuare elaborazioni sul grafo, cioe' la matrice
    o la lista delle adiacenze.

    Definendo una struct analoga con, in aggiunta,
    il puntatore al prossimo arco si puo' anche costruire una lista
    concatenata, cosa che rende relativamente semplice
    modificare il grafo, aggiungendo/togliendo nodi o archi.

    Modificare un grafo rappresentato da una stringa mi pare
    un'operazione molto piu' complicata (volendola fare automaticamente,
    cioe' senza intervenire manualmente sulla stringa, ma digitando
    in un programma solo gli archi o nodi da aggiungere/togliere).

    Una variante possibile e' memorizzare i dati su due file;
    uno puo' contenere tutte le adiacenze esistenti (coi relativi pesi)
    l'altro puo' memorizzare, per ogni nodo, il numero dei nodi adiacenti
    e la posizione, nel primo file, in cui e' collocato l'elenco
    dei relativi nodi adiacenti.
  • Re: Libreria Personale Grafi errore funzioni implicite

    Ti ringrazio per la risposta, ma io sto seguendo una traccia di un esercizio ben preciso, la grammatica del file mi è stata data così, io ne sto scrivendo solo il codice, che deve fare quello specifico parsing, e l'ho fatto e funziona, traduce il file e crea il grafo. Il problema sono quei warning che non riesco a risolvere, ma è qualcosa che dipende dalla visibilità delle funzioni nelle librerie o cose simili..
  • Re: Libreria Personale Grafi errore funzioni implicite

    Ci sono cose che non mi piacciono nel progetto riguardo alla modularità.
    Ad ogni modo il problema che hai è molto banale e deriva da un copia/incolla. Il problema sta nel grafolista.h, così non permette l'inclusione di grafo.h.

    grafolista.h
    
    #ifndef GRAFO_H_INCLUDED
    #define GRAFO_H_INCLUDED
    
    ...
    
    #endif // GRAFO_H_INCLUDED
    
    Prova a sostituirlo con questo e vedrai che spariscono i warning.
    #ifndef GRAFOLISTA_H_INCLUDED
    #define GRAFOLISTA_H_INCLUDED
    
    ...
    
    #endif // GRAFOLISTA_H_INCLUDED
    P.s. Attenta ai copia/incolla perché errori come questi anche se sciocchi sono difficili da trovare e debuggare.
  • Re: Libreria Personale Grafi errore funzioni implicite

    Grazie! E' che prima questa libreria l'avevo chiamata grafo e quindi il file si era creato in quel modo in automatico, andando poi a rinominare i file mi sono dimenticata di questo particolare!
    Ci sono cose che non mi piacciono nel progetto riguardo alla modularità.
    suggerimenti?
    Sto imparando quindi dei consigli mi farebbero più che bene!
  • Re: Libreria Personale Grafi errore funzioni implicite

    Ho modificato il codice, alcune librerie, e aggiunte nuove funzioni.. ho un nuovo problema, diverso dal precedente, devo creare una nuova discussione?
  • Re: Libreria Personale Grafi errore funzioni implicite

    violet_prog ha scritto:


    Ci sono cose che non mi piacciono nel progetto riguardo alla modularità.


    suggerimenti?
    Sto imparando quindi dei consigli mi farebbero più che bene!
    Lo scopo della modularità è che ciascun modulo si occupa di qualcosa. Ciò facilita la lettura del codice e la sua manutenzione.

    Hai creato un modulo che parsifica, bene esso deve solo parsificare e non inserire anche nel grafo, sarà il grafo a disporre di funzioni per tale scopo.
    Farei diversamente anche gli ADT grafo, in maniera da rendere il tutto più trasparente per il client. Ovvero una struct che definisce il grafo, poi la funzione di inizializzazione, quella di distruzione e tutte le funzioni che servono all'ADT. Così riesci a riutilizzare le librerie che scrivi per scopi futuri.

    violet_prog ha scritto:


    ho modificato il codice, alcune librerie, e aggiunte nuove funzioni.. ho un nuovo problema, diverso dal precedente, devo creare una nuova discussione?
    Dipende dal problema che hai se proprio diverso da questo, meglio aprirne uno nuovo.
  • Re: Libreria Personale Grafi errore funzioni implicite

    Farei diversamente anche gli ADT grafo, in maniera da rendere il tutto più trasparente per il client. Ovvero una struct che definisce il grafo, poi la funzione di inizializzazione, quella di distruzione e tutte le funzioni che servono all'ADT.
    Si questo l'ho pensato anche io, è solo che siccome il codice al momento mi riporta degli errori nelle funzioni che ho già scritto volevo prima correggerli e poi apportare questa modifica.
    Apro una nuova discussione.
  • Re: Libreria Personale Grafi errore funzioni implicite

    Va bene, però, è sbagliato, perché modificare la struttura dati ti porterà a riscrivere molto codice. Conviene sempre impostare una struttura dati e far funzionare quella, altrimenti corri il rischio che finisci il lavoro e poi per modificare qualcosa hai necessità di rivedere tutto il codice.
  • Re: Libreria Personale Grafi errore funzioni implicite

    E' vero, è solo che non ho le idee molto chiare su come sarebbe il modo giusto di realizzare la struttura, per questo sto prendendo del tempo. Ho un idea approssimativa di una struttura grafo in cui includere anche l'informazione 'numero vertici', in modo da poterla inizializzare come in effetti faccio poi per la matrice. Tu intendi aggiungere una struttura grafo più esplicita, o modificare proprio quello che io ho scritto, che sostanzialmente una lista in cui ogni nodo contiene una lista.
  • Re: Libreria Personale Grafi errore funzioni implicite

    Per me una struttura dati è realizzata così:

    GRAFO.h
    
    ...
    typedef struct grafo * GRAFO;
    
    GRAFO.c
    
    ...
    typedef struct grafo{
        int nvertici;
        int **matriceadj; // per una matrice oppure Nodo_t **listaadj;
      ... // tutte le eventuali informazioni che vuoi aggiungere nella tua struttura dati
    }Grafo;
    
    funzione init indispensabile per inizializzare la struttura dati e destroy per distruggerla, più tutte le funzioni di cui hai bisogno per la gestione del grafo.
  • Re: Libreria Personale Grafi errore funzioni implicite

    SVNiko ha scritto:


    Per me una struttura dati è realizzata così:

    GRAFO.h
    
    ...
    typedef struct grafo * GRAFO;
    
    GRAFO.c
    
    ...
    typedef struct grafo{
        int nvertici;
        int **matriceadj; // per una matrice oppure Nodo_t **listaadj;
      ... // tutte le eventuali informazioni che vuoi aggiungere nella tua struttura dati
    }Grafo;
    
    funzione init indispensabile per inizializzare la struttura dati e destroy per distruggerla, più tutte le funzioni di cui hai bisogno per la gestione del grafo.

    Salve! Scusa se rispondo dopo mesi ad una discussione così vecchia.
    L'idea è quella di rinunciare a due librerie diverse grafolista.h e grafomatrice.h e accorparle in un unica grafo.h che gestisce le due rappresentazioni?
  • Re: Libreria Personale Grafi errore funzioni implicite

    Perdonami ma non ricordo la questione. Ad ogni modo non ho capito che cosa vuoi realizzare.
  • Re: Libreria Personale Grafi errore funzioni implicite

    Apro una nuova discussione
  • Re: Libreria Personale Grafi errore funzioni implicite

    Penso sia un'ottima idea!
Devi accedere o registrarti per scrivere nel forum
14 risposte