将文件的内容逐行加载到C中的数组中

时间:2017-12-01 18:29:40

标签: c structure file-handling dynamic-arrays

我正在编写歌曲数据库。目前,2首歌曲的数据存储在一个文本文件中,每行一个结构字段。我想逐行将文件的内容复制到一个数组中,我不明白为什么程序在调用load()后崩溃了。这是与fgets()相关的问题吗?或者当我更换' \ n'通过' \ 0'? 以下是代码的有趣部分:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include "functions.h"

int main()
{
    int menu;
    bool exit = false;
    /*char title[256];
    char artist[256];
    char album[256];*/
    int year;
    Song **songs = NULL; // base pointer to the array (of pointers to struct)
    FILE *f; // pointer to a file structure
    int n = 0; // height of array at the beginning (= number of pointers to struct)
    int i;

    f = fopen("database.txt", "r+");
    if(f == NULL)
        return 0;

    count_songs_db(f, &n); // will modify n (height of array) according to the number of existing songs
    printf("n = %d\n", n);

    songs = (Song**)malloc(n*sizeof(Song));
    load(f, songs, n);

    // MENU

    for(i = 0 ; i < n ; ++i)
        free(songs[i]);

    free(songs);
    fclose(f);

    return 0;
}

功能:

void count_songs_db(FILE *f, int *n) // calculate how many songs there are already in the database.
{
    int c, n_lines = 0;

    while ((c = getc(f)) != EOF)
        if (c == '\n')
            ++n_lines; // count number of lines
    *n = n_lines/6; // 1 song = 6 lines. Changes the height of array accordingly.
    rewind(f); // go back to beginning of file, to be able to load the db
}

void load(FILE *f, Song **songs, int n) // load existing songs (in the file) into the array
{
    int i;

    for(i = 0 ; i < n ; ++i)
    {
        fgets(songs[i]->title, 256, f); // reads a line of text
        songs[i]->title[strlen(songs[i]->title)-1] = '\0'; // to replace \n by \0 at the end // not working?
        fgets(songs[i]->artist, 256, f);
        songs[i]->title[strlen(songs[i]->artist)-1] = '\0';
        fgets(songs[i]->album, 256, f);
        songs[i]->title[strlen(songs[i]->album)-1] = '\0';
        fscanf(f, "%d\n", &(songs[i]->year)); // use it like scanf
        fgets(songs[i]->genre, 256, f);
        songs[i]->title[strlen(songs[i]->genre)-1] = '\0';
        fscanf(f, "%d:%d\n", &(songs[i]->length.m), &(songs[i]->length.s));
    }

    for(i = 0 ; i < n ; ++i)
    {
        printf("Title: %s\n", songs[i]->title);
        printf("Artist: %s\n", songs[i]->artist);
        printf("Album: %s\n", songs[i]->album);
        printf("Year of release: %d\n", songs[i]->year);
        printf("Genre: %s\n", songs[i]->genre);
        printf("Length: %d:%d\n", songs[i]->length.m, songs[i]->length.s);
    }
}

结构:

typedef struct Length {
int m, s;
} Length;

typedef struct Song {
    char title[256];
    char artist[256];
    char album[256];
    int year;
    char genre[256];
    Length length;
} Song;

感谢您的帮助。

编辑:我修改了代码以使用简单的struct数组。这是add_song()函数和save()函数:

void add_song(Song *songs, int *n)
{
    printf("Title: ");
    read(songs[*n].title, MAX_SIZE); // another function is used instead of scanf(), so the user can enter string with spaces. Also more secure.
    printf("Artist: ");
    read(songs[*n].artist, MAX_SIZE);
    printf("Album: ");
    read(songs[*n].album, MAX_SIZE);
    printf("Year of release: ");
    songs[*n].year = read_long(); // still have to check the user inputs (ie. year has to be between 1900 and 2017)
    printf("Genre: ");
    read(songs[*n].genre, MAX_SIZE);
    printf("Length: \nmin: ");
    songs[*n].length.m = read_long();
    printf("sec: ");
    songs[*n].length.s = read_long();

    ++(*n);
}

void save(FILE *f, Song *songs, int n) // save song in file
{
    fprintf(f, "%s\n%s\n%s\n%d\n%s\n%d:%d\n", songs[n-1].title, songs[n-1].artist, songs[n-1].album, songs[n-1].year, songs[n-1].genre, songs[n-1].length.m, songs[n-1].length.s); // use it like printf. Prints the data in the file.
}

1 个答案:

答案 0 :(得分:1)

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>


typedef struct Length {
    int m, s;
} Length;

typedef struct Song {
    char title[256];
    char artist[256];
    char album[256];
    int year;
    char genre[256];
    Length length;
} Song;
void count_songs_db(FILE *f, int *n) // calculate how many songs there are already in the database.
{
    int c, n_lines = 0;

    while ((c = getc(f)) != EOF)
        if (c == '\n')
            ++n_lines; // count number of lines
    *n = n_lines / 6; // 1 song = 6 lines. Changes the height of array accordingly.
    rewind(f); // go back to beginning of file, to be able to load the db
}

void load(FILE *f, Song *songs, int n) // load existing songs (in the file) into the array
{
    int i;

    for (i = 0; i < n; ++i)
    {
        fgets(songs[i].title, 256, f); // reads a line of text
        songs[i].title[strlen(songs[i].title) - 1] = '\0'; // to replace \n by \0 at the end // not working?
        fgets(songs[i].artist, 256, f);
        songs[i].title[strlen(songs[i].artist) - 1] = '\0';
        fgets(songs[i].album, 256, f);
        songs[i].title[strlen(songs[i].album) - 1] = '\0';
        fscanf(f, "%d\n", &(songs[i].year)); // use it like scanf
        fgets(songs[i].genre, 256, f);
        songs[i].title[strlen(songs[i].genre) - 1] = '\0';
        fscanf(f, "%d:%d\n", &(songs[i].length.m), &(songs[i].length.s));
    }

    for (i = 0; i < n; ++i)
    {
        printf("Title: %s\n", songs[i].title);
        printf("Artist: %s\n", songs[i].artist);
        printf("Album: %s\n", songs[i].album);
        printf("Year of release: %d\n", songs[i].year);
        printf("Genre: %s\n", songs[i].genre);
        printf("Length: %d:%d\n", songs[i].length.m, songs[i].length.s);
    }
}

int main()
{
    int menu;
    bool exit = false;
    /*char title[256];
    char artist[256];
    char album[256];*/
    int year;
    Song *songs = NULL; // base pointer to the array (of pointers to struct)
    FILE *f; // pointer to a file structure
    int n = 0; // height of array at the beginning (= number of pointers to struct)
    int i;

    f = fopen("database.txt", "r+");
    if (f == NULL)
        return 0;

    count_songs_db(f, &n); // will modify n (height of array) according to the number of existing songs
    printf("n = %d\n", n);

    songs = (Song*)malloc(n * sizeof(Song));
    load(f, songs, n);

    // MENU

    free(songs);

    fclose(f);

    return 0;
}