2017-12-01 4 views
0

私はソングデータベースをコーディングしています。今のところ、2曲のデータは1行に1つの構造体フィールドであるテキストファイルに格納されます。私は、ファイルの内容を行ごとに配列にコピーしたいのですが、load()を呼び出した後にプログラムがクラッシュする理由はありません。 fgets()に関連する問題ですか?または '\ n'を '\ 0'に置き換えるとどうなりますか?ファイルの内容をC言語の配列に1行ずつ読み込みます

#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; 

おかげでここ は、コードの興味深い部分です。

を編集します。単純な構造体の配列を使用するようにコードを変更しました。ここでadd_song()関数があると、保存()関数:

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. 
} 
+2

'ソング**歌= NULL;'と '曲=(​​ソング**)はmalloc(n個の*のはsizeof(ソング)); 'マッチしない。 'Song * songs = NULL;'に変更し、 'songs [i] - > title'を' 'song [i] .title'などに変更します。 –

+0

' malloc'の結果をキャストすべきではありませんCでは、正しいポインタ型に安全に昇格され、キャストはコンパイラエラーを隠すことがあります。 –

+0

テキストファイルはasciiエンコーディングで保存して、1つのchar = 1バイトにする必要があります。この行の曲[i] - > title [strlen(songs [i] - > album)-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; 
} 
+0

本当にありがとうございました。コードを編集しましたが、add_song()関数で問題が発生しました。たとえば、既に2曲が存在する場合は、曲[2]に曲を追加します。 – Parallel

関連する問題