Click here to Skip to main content
15,887,979 members
Please Sign up or sign in to vote.
1.00/5 (1 vote)
See more:
Write the following two functions maintaining a database of entries of type song in a file.(see .h file for the definition of the struct song)

int add_song(const char* file_name, const song s);

The function gets the name of a file, and a song. If the song is not in the file, the function adds
it to the file and returns 1. Otherwise, the function does not modify the file and returns 0.

song* find_song(const char* file_name, const char* title);

The function gets the name of a file and a title of a song. It searches the file for the song with
the given title. If a song is found, it returns a pointer to the song with all the details. If not found,
the function returns NULL. You may assume the song titles are unique.

What I have tried:

C
typedef struct {
    char* title;
    char* artist;
    int year;

} song;

song* find_song(const char* file_name, const char* title) {

    FILE *fp;

    fp = fopen(file_name, "r");

    if (fp == NULL) {
        return NULL;
    }

    char song_title[100];
    char song_artist[100];
    int song_year;


    while (fscanf(fp, "%s %s %d", song_title, song_artist, &song_year) != EOF) {

        if (song_title == title) {


            song *song_pointer = malloc(sizeof(song));
            song_pointer->title = song_title;
            song_pointer->artist = song_artist;
            song_pointer->year = song_year;
            return song_pointer;
        }


        fclose(fp);
        return NULL;
    }

}

int add_song(const char* file_name, const song s) {

    FILE *fp;

    fp = fopen("file_name", "a");


    if(fp == NULL){

        fclose(fp);
        return 0;
    }

    song *song_pointer = find_song(file_name, s.title);
    if (song_pointer != NULL){

        fprintf(fp,"%s %s %d\n", s.title, s.artist, s.year);
        fclose(fp);
        return 1;

    }else {


        fclose(fp);

        return 0;

    }
}


int main(){
    song bd = {"All Along the Watchtower", "Bob Dylan", 1968};
    song jj = {"Mercedes Benz", "Janis Joplin", 1971};
    song lz = {"Stairway to Heaven", "Led Zeppelin", 1971};

    int tmp;
    tmp = add_song("songs.db", bd);
    if (tmp == 1)
        printf("Q4-1 ok\n");
    else
        printf("Q4-1 ERROR : expected 1, return = %d\n", tmp);

    tmp = add_song("songs.db", jj);
    if (tmp == 1)
        printf("Q4-2 ok\n");
    else
        printf("Q4-2 ERROR : expected 1, return = %d\n", tmp);

    tmp = add_song("songs.db", lz);
    if (tmp == 1)
        printf("Q4-3 ok\n");
    else
        printf("Q4-3 ERROR : expected 1, return = %d\n", tmp);

    tmp = add_song("songs.db", jj);
    if (tmp == 0)
        printf("Q4-4 ok\n");
    else
        printf("Q4-4 ERROR : expected 0, return = %d\n", tmp);

    song *s_mb = find_song("songs.db", "Mercedes Benz");
        if (s_mb && strcmp(s_mb->title, "Janis Joplin") == 0)
            printf("Q4-5 ok\n");
        else
            printf("Q4-5 ERROR, Mercedes Benz not found correctly, 
        return = %d\n", tmp);
        if (s_mb)
            free(s_mb);
    song *s_ds = find_song("songs.db", "Money for Nothing");
        if (s_ds == NULL)
            printf("Q4-6 ok\n");
        else
            printf("Q4-6 ERROR, found \"Money for Nothing\"\n");
        if (s_ds)
            free(s_ds);

    return 0;
}

}
Posted
Updated 15-Oct-21 22:39pm
v2
Comments
Rick York 16-Oct-21 19:32pm    
Do you realize that your file reading code will not allow song titles or artists to have spaces in them?

You should get together with your classmate who posted this question: How do I solve this C programming question ? .[^].
 
Share this answer
 
Quote:
If a song is found, it returns a pointer to the song with all the details


That is very much untrue. What find_song does is:
- it allocates one "song" struct, which holds a year, NO title, NO artist.
- it does hold pointers to some memory you did not allocate permanently, both pointers refer to local arrays, which get allocated on the stack, and become unavailable when the function returns.

Remember: local variables get allocated on stack, and they only are available for as long as the function is active; upon return, the stack is freed and your arrays are gone; they will be overwritten by whatever will be stored on the stack later on, normally local variables of the next function you're going to call.

What you need to do is two more mallocs once the song has been found, store the title and artist in that new memory, and have your song struct point to them, only then return the struct which now really holds all information on the song.

Refinement: the two extra mallocs should not have size 100, they should have whatever size is required to store the actual title and artist (which could be much less or much more than 100 characters).

Caveat: now your song struct "owns" two chunks of memory; whenever you throw away the struct, those two chunks will be lost forever (=memory leak) unless you provide and consistently make use of a delete_song function...


PS: there is one alernative, with pros and cons: modify the song struct so it really contains the title and artist, i.e. not a pointer to chars, but actual char arrays.
 
Share this answer
 
v2
Comments
Rick York 16-Oct-21 19:33pm    
The function strdup is handy for this.
Luc Pattyn 16-Oct-21 21:02pm    
Sounds good; it didn't exist in my K&R years; learning something new every day...
Use the debugger to find out what is the problem. For comparing strings in C you must use the strcmp function.

So start learning the basics of the language in some Learn C tutorial.
 
Share this answer
 

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900