PROBLEMA Problema gestione file linguaggio C

saro1995

Nuovo Utente
82
3
Ciao a tutti programmatori, come dal titolo ho un piccolo problema con la gestione dei file in C.
In sostanza devo caricare un file .txt contenenti dei brani musicali. Vi Scrivo il file così che possiate comprendere meglio:
es. file:
prima riga: titolo brano musicale
seconda riga: nome cantante
terza riga: genere musicale
quarta riga: anno, durata brano;
Problema: Per esempio tra le granite e la granate ci stanno degli spazi a dividere le parole del titolo giusto? ecco... proprio questo è il problema, se metto gli spazi al posto di caricarmi il numero effettivo dei brani me ne restituisce di più, invece se metto dei trattani in modo da unire il titolo(es: tra-le-granite-e-le-granate) carica perfettamente. Vi poso sotto la mia soluzione.
il prototipo della funzione per caricare i file è la seguente: int CaricaFile(char *nomefile, TLista *lis);
sotto al file trovate la soluzione. Grazie!

il file è questo:
tra le granite e le granate
francesco gabbani
pop
2017 3:15

partiti adesso
giusy ferreri
pop
2017 2:48

Ragazza-Paradiso
Ermal-Meta
rock
2017 2:52

With or without you
u2
rock
1987 4:56

C:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define DIM 50

/*STRUTTURE DATI*/
typedef struct BranoMusicale {
    char titolo_brano[255];
    char nome_cantante[63];
    char genere_musicale[15];
    int anno;
    char durata_brano[DIM];
    int minuti, secondi;
}TBranoMusicale;

typedef struct NodoBranoMusicale {
    TBranoMusicale info;
    struct NodoBranoMusicale *next;
}TNodoBranoMusicale;
typedef TNodoBranoMusicale* TListaBraniMusicali;

typedef struct GenereMusicale {
    char genere_musicale[15];
    char durata_totale[DIM];
    int minuti, secondi;
}TGenereMusicale;

typedef struct NodoGenereMusicale {
    TGenereMusicale info;
    struct NodoGenereMusicale *next;
}TNodoGenereMusicale;
typedef struct TNodoGenereMusicale* TListaGeneriMusicali;



/*DEFINIZIONE DI FUNZIONE*/
TListaBraniMusicali CreaListaBraniMusicali() {
    return NULL;
}
TListaGeneriMusicali CreaListaGeneriMusicali() {
    return NULL;
}
//funzione menu principale
int menu() {
    int scelta;
    printf("---> Menu' Principale <---\n");
    printf("-> [1] Carica Brani Musicali\n");
    printf("-> [2] Modifica Nome Cantante\n");
    printf("-> [3] Elimina Brano\n");
    printf("-> [4] Copia Brani In Lista Generi Musicali\n");
    printf("-> [5] Stampa Lista(Generi Musicali)\n");
    printf("-> [6] Esci Dal Programma\n");
    printf("Scelta: ");
    scanf("%d", &scelta);
    while (scelta < 1 || scelta > 6) {
        printf("Scelta non valida!\n");
        printf("Scelta: ");
        scanf("%d", &scelta);
        return scelta;
    }
    return scelta;
    system("PAUSE");
}

void InserisciBraniInListaOrdinata(TListaBraniMusicali *lis, TBranoMusicale elem) {
    TListaBraniMusicali prec, curr, newnode;
    if ((newnode = (TListaBraniMusicali)malloc(sizeof(TNodoBranoMusicale))) == NULL) {
        printf("Errore nell'allocazione della memoria.\n");
        exit(1);
    }
    newnode->info = elem;
    prec = NULL;
    curr = *lis;
    while (curr != NULL && strcmp(curr->info.titolo_brano, elem.titolo_brano) < 0) {
        prec = curr;
        curr = curr->next;
    }
    newnode->next = curr;
    if (prec != NULL) {
        prec->next = newnode;
    }
    else {
        *lis = newnode;
    }
}

int CaricaBraniMusicali(char *nomefile, TListaBraniMusicali *plis) {
    FILE *f;
    TBranoMusicale brano;
    int nbrani = 0;
    if ((f = fopen(nomefile, "r")) == NULL) {
        printf("Errore nell'allocazione della memoria.\n");
        exit(1);
    }
    *plis = NULL;
    while (!feof(f)) {
        fscanf(f, "%s\n", brano.titolo_brano);
        fscanf(f, "%s\n", brano.nome_cantante);
        fscanf(f, "%[^\n]s\n", brano.genere_musicale);
        fscanf(f, "%d\t", &brano.anno);
        fscanf(f, "%d:%d\n", &brano.minuti, &brano.secondi);
        InserisciBraniInListaOrdinata(plis, brano);
        nbrani++;
    }
    fclose(f);
    return nbrani;
}
/*FUNZIONE PRINCIPALE MAIN*/
int main(void) {
    char *nomefile[10];
    int scelta, n;
    TListaBraniMusicali lista_brani;
    TListaGeneriMusicali lista_generi;
    lista_brani = CreaListaBraniMusicali();
    lista_generi = CreaListaGeneriMusicali();
    while (scelta = menu()) {
        switch (scelta) {
        case 1:
            system("CLS");
            printf("\t--Funzione di caricamento da file--");
            printf("\nInseisci il nome del file da cui caricare i brani: ");
            scanf("%s", nomefile);
            n = CaricaBraniMusicali(nomefile, &lista_brani);
            printf("-> Sono stati caricati %d brani musicali.\n", n);
            system("PAUSE");
            break;
        case 2:
            system("CLS");

            system("PAUSE");
            break;
        case 3:
            system("CLS");

            system("PAUSE");
            break;
        case 4:
            system("CLS");

            system("PAUSE");
            break;
        case 5:
            system("CLS");

            system("PAUSE");
            break;
        case 6:
            system("CLS");
            printf("Grazie per aver utilizzato questo programma.\n\n");
            return 0;
            system("PAUSE");
            break;
            
        }
    }


    return 0;
}
 

rctimelines

Utente Èlite
5,143
2,023
CPU
Ryzen 7 2700X | i7-6700k@4.5 | i5-4460... altri
Dissipatore
wraith MAX | Scythe Katana2|Arctic Freezer 11LP
Scheda Madre
Asrock B450 Fatal1ty 4K | Asus Prime Z270P | Acer Veriton
HDD
Samsung 970evo m.2 | vari | Samsung 860 evo
RAM
16GB G.Skill TridentZ 3000 | 16GB CORSAIR 2133 | 8GB DDR3 1600
GPU
RadeonPro WX3100 4G | ZOTAC GTX 1070 8G | Quadro k620 2G
Monitor
DELL 2419P 2K + Benq 17" | LG Ultrawide 27''
Net
fibra 1000
OS
Windows10-pro64/OpenSUSE-QL15.1/Debian 10.3
Ma il file dei brani lo scrivi tu con un editor di testo??

Inviato dal mio Nexus 5 utilizzando Tapatalk
 

pabloski

Utente Èlite
2,868
916
Io ho dei dubbi su alcune cose. Innanzitutto perchè invocare CreaListaBraniMusicali che restituisce NULL? Non si fa prima ad assegnare NULL alla variabile?

Inoltre vedo in CaricaBraniMusicali questo *plis = NULL che mi lascia parecchio perplesso. Mi sa che hai fatto parecchio casino tra puntatori ed elementi puntati.

A margine vorrei consigliare di usare un qualche tipo di formato strutturato per il file dei brani. Una banale riga vuota è facile da dimenticare e non è particolarmente espressiva come separatore di record. Usa XML, in modo che così puoi sfruttare i gazillioni di librerie per il parsing del XML a disposizione.
 

saro1995

Nuovo Utente
82
3
Ma il file dei brani lo scrivi tu con un editor di testo??

Inviato dal mio Nexus 5 utilizzando Tapatalk
Si lo scrivo io. Creo il file .txt e poi lo leggo tramite la funzione
Post unito automaticamente:

Io ho dei dubbi su alcune cose. Innanzitutto perchè invocare CreaListaBraniMusicali che restituisce NULL? Non si fa prima ad assegnare NULL alla variabile?

Inoltre vedo in CaricaBraniMusicali questo *plis = NULL che mi lascia parecchio perplesso. Mi sa che hai fatto parecchio casino tra puntatori ed elementi puntati.

A margine vorrei consigliare di usare un qualche tipo di formato strutturato per il file dei brani. Una banale riga vuota è facile da dimenticare e non è particolarmente espressiva come separatore di record. Usa XML, in modo che così puoi sfruttare i gazillioni di librerie per il parsing del XML a disposizione.
Scusa ma non ho capito ciò che vuoi dire
 

pabloski

Utente Èlite
2,868
916
Scusa ma non ho capito ciò che vuoi dire

Mi lascia perplesso l'uso del doppio puntatore. Perchè? E perchè reimpostare lista_brani a NULL quand'è già stato fatto precedentemente?

Poi ho anche notato char *nomefile[10]; che poi viene usato così senza essere allocato. Quel char* significa che stai definendo nomefile che contiene 10 puntatori a char e non una stringa di 10 caratteri.
 

rctimelines

Utente Èlite
5,143
2,023
CPU
Ryzen 7 2700X | i7-6700k@4.5 | i5-4460... altri
Dissipatore
wraith MAX | Scythe Katana2|Arctic Freezer 11LP
Scheda Madre
Asrock B450 Fatal1ty 4K | Asus Prime Z270P | Acer Veriton
HDD
Samsung 970evo m.2 | vari | Samsung 860 evo
RAM
16GB G.Skill TridentZ 3000 | 16GB CORSAIR 2133 | 8GB DDR3 1600
GPU
RadeonPro WX3100 4G | ZOTAC GTX 1070 8G | Quadro k620 2G
Monitor
DELL 2419P 2K + Benq 17" | LG Ultrawide 27''
Net
fibra 1000
OS
Windows10-pro64/OpenSUSE-QL15.1/Debian 10.3
Come fai a caricare distintamente anno e durata? Ammesso che alla fine di ogni riga ci metti un CR

Devi scrivere ogni riga un dato con un carattere di di delimitazione della riga come, appunto un CR.

Inviato dal mio Nexus 5 utilizzando Tapatalk
 

Eduadie

Utente Attivo
204
24
Ti suggerisco inoltre di creare già la funzione di stampa lista in modo da vedere come ti salva i record. Mi sembra molto un progetto universitario quindi ci può stare che si usi un file txt come questo...
 

rctimelines

Utente Èlite
5,143
2,023
CPU
Ryzen 7 2700X | i7-6700k@4.5 | i5-4460... altri
Dissipatore
wraith MAX | Scythe Katana2|Arctic Freezer 11LP
Scheda Madre
Asrock B450 Fatal1ty 4K | Asus Prime Z270P | Acer Veriton
HDD
Samsung 970evo m.2 | vari | Samsung 860 evo
RAM
16GB G.Skill TridentZ 3000 | 16GB CORSAIR 2133 | 8GB DDR3 1600
GPU
RadeonPro WX3100 4G | ZOTAC GTX 1070 8G | Quadro k620 2G
Monitor
DELL 2419P 2K + Benq 17" | LG Ultrawide 27''
Net
fibra 1000
OS
Windows10-pro64/OpenSUSE-QL15.1/Debian 10.3
A parte che ti spieghi malissimo! Sai quello che stai facendo? Quando dici che carica più dati cosa succede in realtà? Forse interpreta lo spazio come separatore e inserisce ogni parola in un campo?

Stai semplicemente caricando un file sequenziale e quella formattazione è effettivamente debolissima anche perché non so come tu possa lasciare un campo vuoto!

Si tratta di un "progetto" universitario, come detto sopra??? spero decisamente di no!

Inviato dal mio Nexus 5 utilizzando Tapatalk
 

saro1995

Nuovo Utente
82
3
A parte che ti spieghi malissimo! Sai quello che stai facendo? Quando dici che carica più dati cosa succede in realtà? Forse interpreta lo spazio come separatore e inserisce ogni parola in un campo?

Stai semplicemente caricando un file sequenziale e quella formattazione è effettivamente debolissima anche perché non so come tu possa lasciare un campo vuoto!

Si tratta di un "progetto" universitario, come detto sopra??? spero decisamente di no!

Inviato dal mio Nexus 5 utilizzando Tapatalk
Si è un progetto universitario, sto solo imparando/cercando di imparare a programmare in C. Si impara sbagliando. Ditemi dove sbaglio che magari posso migliorare. Sono uno studente e sono qui per chiarimenti e imparare da persone più esperte. Invece di fare polemiche mi dica gentilmente dove sbaglio e una possibile soluzione.
Post unito automaticamente:

Ti suggerisco inoltre di creare già la funzione di stampa lista in modo da vedere come ti salva i record. Mi sembra molto un progetto universitario quindi ci può stare che si usi un file txt come questo...
si è un progetto universitario. Sono obbligato ad usare un file .txt perchè lo richiede il compito. Su visual studio inserisco il file, lo scrito manualmente e lo carico. Il professore svolge così i compiti. Poi che sia un metodo "debole" come già detto io non lo so perchè non conosco altri metodi.
 

Eduadie

Utente Attivo
204
24
Io ti sto aiutando suggerendo di crearti già la funzione per mostrare la lista (che sicuramente sarà prevista) in modo da capire perfettamente cosa ti salva e in che modo. In questo modo se poi ci dai più indicazioni sappiamo aiutarti meglio anche noi.
Post unito automaticamente:

Aggiungo inoltre che ti è stato già segnalato un errore importante. La dichiarazione del nome file come l'hai fatta tu indica che allochi spazio per 10 puntatori a char, mentre credo che tu voglia dire allocami una sola stringa di dimensione 10 e quindi non c'è bisogno che utilizzi il puntatore.
Post unito automaticamente:

Ora che ci penso non tieni conto della riga vuota quando scansioni il file.
 
Ultima modifica:

pabloski

Utente Èlite
2,868
916
Ad ogni modo il tuo problema sono quelle fscanf, perchè %s significa "sequenza di caratteri senza spazi bianchi". Cioè per lui uno spazio equivale a \n.

La lettura falla così

C:
        fgets(brano.titolo_brano,sizeof(brano.titolo_brano),f);
        fgets(brano.nome_cantante,sizeof(brano.nome_cantante),f);
        fgets(brano.genere_musicale,sizeof(brano.genere_musicale),f);
        fscanf(f, "%d\t", &brano.anno);
        fscanf(f, "%d:%d\n", &brano.minuti, &brano.secondi);

Il perchè continuano ad esserci due fscanf dovrebbe essere chiaro dal formato che hai dato ad anno e durata.

p.s. su quella cosa dei doppi puntatori hai fatto bene, anche se è meglio evitarli e avresti potuto farlo dichiarando lista_brani come variabile globale. Comunque funziona lo stesso.

mettici pure una funziona di stampa per verificare che la lista venga letta correttamente ed ordinata

C:
void StampaListaBrani(TListaBraniMusicali plis) {
    while (plis != NULL) {
        printf("Titolo: %s -- Nome cantante: %s -- Genere: %s -- Anno: %d -- Durata %d:%d\n", plis->info.titolo_brano, plis->info.nome_cantante, plis->info.genere_musicale, plis->info.anno, plis->info.minuti, plis->info.secondi);
        
        plis = plis->next;
    }
}

non meravigliarti quando vedrai che l'ordinamento sarà

Ragazza-Paradiso
With or without you
partiti adesso
tra le granite e le granate

non significa che non funziona, ma che nella tabella ASCII le maiuscole vengono prima delle minuscole e quell'ordinamento è perfettamente corretto dal punto di vista della macchina
 
Ultima modifica:
  • Mi piace
Reazioni: saro1995 e Eduadie

saro1995

Nuovo Utente
82
3
Ad ogni modo il tuo problema sono quelle fscanf, perchè %s significa "sequenza di caratteri senza spazi bianchi". Cioè per lui uno spazio equivale a \n.

La lettura falla così

C:
        fgets(brano.titolo_brano,sizeof(brano.titolo_brano),f);
        fgets(brano.nome_cantante,sizeof(brano.nome_cantante),f);
        fgets(brano.genere_musicale,sizeof(brano.genere_musicale),f);
        fscanf(f, "%d\t", &brano.anno);
        fscanf(f, "%d:%d\n", &brano.minuti, &brano.secondi);

Il perchè continuano ad esserci due fscanf dovrebbe essere chiaro dal formato che hai dato ad anno e durata.

p.s. su quella cosa dei doppi puntatori hai fatto bene, anche se è meglio evitarli e avresti potuto farlo dichiarando lista_brani come variabile globale. Comunque funziona lo stesso.

mettici pure una funziona di stampa per verificare che la lista venga letta correttamente ed ordinata

C:
void StampaListaBrani(TListaBraniMusicali plis) {
    while (plis != NULL) {
        printf("Titolo: %s -- Nome cantante: %s -- Genere: %s -- Anno: %d -- Durata %d:%d\n", plis->info.titolo_brano, plis->info.nome_cantante, plis->info.genere_musicale, plis->info.anno, plis->info.minuti, plis->info.secondi);
       
        plis = plis->next;
    }
}

non meravigliarti quando vedrai che l'ordinamento sarà

Ragazza-Paradiso
With or without you
partiti adesso
tra le granite e le granate

non significa che non funziona, ma che nella tabella ASCII le maiuscole vengono prima delle minuscole e quell'ordinamento è perfettamente corretto dal punto di vista della macchina
Non so come ringraziarti.
 

Entra

oppure Accedi utilizzando
Discord Ufficiale Entra ora!