Thread: Library database using single linked lists

  1. #1
    Registered User
    Join Date
    Jan 2015
    Location
    Rydułtowy, Poland
    Posts
    4

    Library database using single linked lists

    Hello everyone!
    I am kinda new to programming in general, so please be gentle I'm a freshman student and programming is one of the courses I'm enrolled in... you've probably read this kinda bollocks a load of times
    Anyway, I have an assignment in which I'm supposed to create a program to be used in a library. Basically a database storing all books currently outside the library along with who and when borrowed them. It also says I should use single linked lists.
    Now, I've got a general idea of how to make it work but I've stumbled upon a problem. Since the program has to write all the data put into the database in a file and be able to tell the user whether a book has been kept too long by the reader, I figured I'd implement the struct tm to convert the date when the book was borrowed (or rent, whatever, English is not my first language ;p) into UNIX time. Then, when I'd like the program to tell me which books are being kept hostage by the readers the program would look for a certain record (like a string inside a certain struct) and compare the date inside that record with current date and then the result of this comparison would be compared with a given, defined time limit. Although this is all a different kinda function, it's a bit simplier, I guess, and I think I'll work it out. However to get there at all I need to be able to store the data correctly and there is a problem, which I'll explain on the other end of the code
    Here is the code I came up with:

    Code:
    #include <stdio.h>#include <string.h>
    #include <stdlib.h>
    #include <time.h>
    
    
    int DisplayMenu();
    int ReturnToMenu();
    int AddBooks(char *filename);
    
    
    typedef struct node
    {
        char title[90];
        char reader_name[30];
        double unix_date;
        struct node *next;
    }book;
    
    
    int DisplayMenu()
    {
        system("cls");
    
    
        int choice;
        printf("*****MENU***** \n\n"
            "1. Add books \n"
            "2. Remove books \n"
            "3. Find a book \n"
            "4. Find a reader \n"
            "5. Find overdue positions \n"
            "6. Exit \n\n");
        scanf("%d", &choice);
    
    
        return choice;
    }
    
    
    int main()
    {
        int choice;
        while ((choice = DisplayMenu()) != 6)
        {
            switch (choice)
            {
            case 1:
                AddBooks("database.txt");
                break;
            case 2:
                
            case 3:
    
    
            case 4:
    
    
            case 5:
    
    
            default:
                printf("Invalid selection. Try again.\n");
            }
        }
        system("cls");
        printf("The program will exit. Press any key to continue.\n");
    
    
        system("pause");
        return 0;
    }
    
    
    int ReturnToMenu()
    {
        int back;
    
    
        printf("Would you like to return to the Menu[1] or exit[0] the program?\n\n");
        scanf("%d", &back);
    
    
        while (back != 0)
        {
            switch (back)
            {
            case 1:
                DisplayMenu();
                break;
    
    
            default:
                printf("Invalid selection. Try again.\n");
            }
        }
        printf("The program will exit. Press any key to continue.\n");
    
    
        return back;
    }
    
    
    int AddBooks(char *filename)
    {
        FILE *fp;
        book newbook;
        struct tm date;
    
    
        system("cls");
    
    
        fp = fopen(filename, "wb");
        if (!fp)
        {
            printf("Error reading database file!\n");
            return -1;
        }
        else
        {
            int flag = 0;
            do
            {
                printf("Please type in the book's title: \n");
                gets(newbook.title);
                if (strcmp(newbook.title, "") == 0)
                {
                    printf("Wrong input. Try again.\n");
                    flag = 1;
                    system("cls");
                }
                else
                {
                    flag = 0;
                }
            } while (flag == 1);
    
    
            int flag0 = 0;
            do
            {
                printf("\nPlease type in the reader's name: \n");
                gets(newbook.reader_name);
                if (strcmp(newbook.reader_name, "") == 0)
                {
                    printf("Wrong input. Try again.\n");
                    flag0 = 1;
                    system("cls");
                }
            } while (flag0 == 1);
    
    
            int d, m, y;
            int days_month[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
            int minyear = 1900;
            printf("\nPlease enter the date of rent:\n\n");
    
    
            int flag1 = 0;
            do
            {
                printf("Year(yyyy):\t");
                scanf("%d", &y);
                if (y < minyear)
                {
                    printf("Wrong input. Try again.\n\n");
                    flag1 = 1;
                }
                else if ((y % 4) == 0 && y % 100 != 0 || y % 400 == 0)
                {
                    days_month[2] = 29;
                    flag1 = 0;
                }
                else
                {
                    days_month[2] = 28;
                    flag1 = 0;
                }
            } while (flag1 == 1);
    
    
            int flag2 = 0;
            do
            {
                printf("\nMonth(mm):\t");
                scanf("%d", &m);
                if (m < 1 || m>12)
                {
                    printf("Wrong input. Try again.\n\n");
                    flag2 = 1;
                }
                else
                    flag2 = 0;
            } while (flag2 == 1);
    
    
            int flag3 = 0;
            do
            {
                printf("\nDay(dd):\t");
                scanf("%d", &d);
                if (d < 1 || d>days_month[m])
                {
                    printf("Wrong input. Try again.\n\n");
                    flag3 = 1;
                }
                else
                    flag3 = 0;
            } while (flag3 == 1);
    
    
            date.tm_mday = d;
            date.tm_mon = m - 1;
            date.tm_year = y - 1900;
    
    
            newbook.unix_date = mktime(&date);
    
    
            fwrite(&newbook, sizeof(book), 1, fp);
    
    
            system("cls");
            printf("Item successfully added to the registry.\n\n");
    
    
            fclose(fp);
        }
        ReturnToMenu();
    }
    So, my problem is as follows: the date seems to be stored alright, but it's wrong. For checking I had a
    Code:
    printf("%d", mktime(&date)");
    added and it returned "-1"... As I said, I'm relatively new to coding/programming and my knowledge is rather rudimentary.
    This website/forum has been very helpful to me so far and I'm very grateful to all the people forming this community for sharing knowledge so freely and competently.

    By the way: I had one more gremlin haunting me on this one. Namely at the begining of the input to the AddBooks function:
    Code:
     int flag = 0;        do
            {
                printf("Please type in the book's title: \n");
                gets(newbook.title);
                if (strcmp(newbook.title, "") == 0)
                {
                    printf("Wrong input. Try again.\n");
                    flag = 1;
                    system("cls");
                }
                else
                {
                    flag = 0;
                }
            } while (flag == 1);
    The do while loop is to ensure 'unempty' input. Without this loop however, the program would display the message "Please type in the book's title:" but it wouldn't wait for input. It's simply jump to the next printf and wait for input then... I figured it might be becuase it took the 'Enter' that was somehow still in the memory after the user confirms his selection in the menu... It's just a guess, though.

    Any help or suggestions greatly appreciated. Thanks in advance

  2. #2
    Ultraviolence Connoisseur
    Join Date
    Mar 2004
    Posts
    555
    First off, the overall structure you have is somewhat decent. You need to breakdown the operations in AddBook a bit more though. You have a couple of repeated patterns. Look how much easier the code is starting to look if you pull out the input patterns:
    Code:
    void get_string(const char * prompt, char * buf, size_t size)
    {
        printf("%s", prompt);
        if (!fgets(buf, size, stdin)) {
            perror("get_string");
            *buf = 0;
        }
    }
    
    /* Accept int within a range */
    int get_int(const char * prompt, int rstart, int rend)
    {
        int again, value;
    
        do {
            again = 0;
            printf("%s", prompt);
            if (!scanf(" %d", value) || value < rstart || (rend > 0 && value > rend)) {
                printf("Error: please enter a valid value\n");
                again = 1;
            }
        } while (again);
    
        return value;
    }
    
    int AddBooks(char *filename)
    {
        FILE *fp;
        book newbook;
        struct tm date;
     
        system("cls");
     
        fp = fopen(filename, "wb");
        if (!fp) {
            printf("Error reading database file!\n");
            return -1;
        }
    
        get_string("Please type in the book's title:\n", 
                   newbook.title, 
                   sizeof newbook.title
        );
    
        get_string("Please type in the reader's name:\n",
                   newbook.reader_name,
                   sizeof newbook.reader_name
        );
    
        int d, m, y;
        int days_month[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
        int minyear = 1900;
        printf("\nPlease enter the date of rent:\n\n");
    
        y = get_int("Year (yyyy): ", minyear, -1);
        /* Calculate leapyear */
        if ((y % 4) == 0 && y % 100 != 0 || y % 400 == 0)
            days_month[2] = 29;
        else
            days_month[2] = 28;
        m = get_int("Month (mm): ", 1, 12);
        d = get_int("Day (dd): ", 1, days_months[m]);
    
        date.tm_mday = d;
        date.tm_mon = m - 1;
        date.tm_year = y - 1900;
    
        newbook.unix_date = mktime(&date);
    
        fwrite(&newbook, sizeof(book), 1, fp);
    
        system("cls");
        printf("Item successfully added to the registry.\n\n");
    
        fclose(fp);
        ReturnToMenu();
    }
    Now some issues. Number one you do not want to write out your data directly to file in raw binary format as you are doing. For one, you said it was a linked list right? So you need to load the whole file into memory, re-substantiate all the links to form the list (from the structures stored, presumably in sequential order..) then add the item to the list, then write out the whole list to the file again. That would be the only way to actually maintain the database structure in memory and in a file.

    For that reason you probably would only want to read/write the list to file once each per run of your program, not every single time you do every operation. So you may want to think about that a bit.

    Beyond all that, writing the data structure raw with an fwrite() call you will run into issues if you copy those files to another computer, or try to send them over the network to someone else etc.. or even use them with another version of your program, due to byte ordering and structure padding (which has been explained billions of times, you need to read the FAQ).


    Finally, yes the problem of your scanf() calls being consumed "magically" as it would seem, is in fact because they are consuming the "enter" key as you put it. This is again probably the most commonly asked question on the forum and likely why you haven't gotten an answer. You need to read the FAQ. In general you can solve this problem by placing a space in front of your scanf() call as I have done in the code above. This consumes the whitespace left in the buffer prior to trying to read another integer.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 3
    Last Post: 04-19-2014, 10:01 PM
  2. Double Linked Dynamic Lists Vs Unrolled Linked Lists
    By lantzvillian in forum C Programming
    Replies: 6
    Last Post: 02-14-2012, 01:07 PM
  3. create a book library without linked lists
    By limilou in forum C Programming
    Replies: 7
    Last Post: 03-22-2011, 10:14 AM
  4. question on linked lists(stack with linked lists)
    By dionys in forum C Programming
    Replies: 1
    Last Post: 06-02-2004, 11:08 AM
  5. Database Library or Api
    By face_master in forum C++ Programming
    Replies: 1
    Last Post: 11-02-2002, 07:49 AM

Tags for this Thread