0

I have a program below that acts like a library manager to help organize my books collection but somehow when I update the file with new information when I exist the program, the information in the file is is deleted and nothing is saved into the file.

What this program does is add new books into a structure and then when the user types in 8 to exit the program the information from the structure is saved into file and when the program is run the next time, the information from the file is initialized back into the structure. Somehow my implementations is not working right or somewhere I am doing wrong that needs another pair of eyes to see.

#define MAX 100
#define OUT 1
#define IN  0
#define RETURNTIME 30

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

struct date
{
    int nYear, nMonth, nDay;
};

struct BOOK {
    int     nID;
    char    chTitle[50];
    char    chType[50];
    char    chPublisher[50];
    int     nPages;
    float   nPrice;
    int     nPubYear;
    int     nStatus; //0=available, 1=checked-out
    char    userName;
    struct  date issued, due;
}BOOK[100];

FILE *fp;
FILE *fpin;

//Function calls
void addBookFunction();
void checkOutBookFunction();
void checkInBookFunction();
void displayAllBookFunction();
void displayAllAvailableBookFunction();
void displayAllCheckedOutBookFunction();

int checkID(int t);

int count;

int main(int argc, const char * argv[])
{
    int nInput;
    char buffer[100];
    char *token;

    fpin = fopen("books.txt", "r");
    if (fpin == NULL)
    {
        printf("Unable to open the file");
        exit(0);
    }
    while (!feof(fpin))
    {
        fgets(buffer, sizeof(buffer), fpin);
        int i = 1;
        token = strtok(buffer, ",-");
        while (token != NULL)
        {
            if (i == 1)
            {
                BOOK->nID = atoi(token);
            }
            if (i == 2)
            {
                strcpy(BOOK->chTitle, token);
            }
            if (i == 3)
            {
                strcpy(BOOK->chType, token);
            }
            if (i == 4)
            {
                strcpy(BOOK->chPublisher, token);
            }
            if (i == 5)
            {
                BOOK->nPages = atoi(token);
            }
            if (i == 6)
            {
                BOOK->nPages = atoi(token);
            }
            if (i == 7)
            {
                BOOK->nPubYear = atoi(token);
            }
            if (i == 8)
            {
                BOOK->nStatus = atoi(token);
            }
            if (i == 9)
            {
                BOOK->due.nYear = atoi(token);
            }
            if (i == 10)
            {
                BOOK->due.nDay = atoi(token);
            }
            if (i == 11)
            {
                BOOK->due.nMonth = atoi(token);
            }
            token = strtok(NULL, ",-");
            i++;
        }
    }

    while (1)
    {
        printf("\n\t\t~~MENU~~\n");
        printf("1. Add a new book\n");
        printf("2. Remove a book (input ISBN)\n");
        printf("3. Check out a book (input ISBN)\n");
        printf("4. Check in a book (input ISBN)\n");
        printf("5. Display all book details\n");
        printf("6. Display all available book details\n");
        printf("7. Display all checked out books\n");
        printf("8. Exit program\n");
        printf("Make your selection: ");
        scanf("%d", &nInput);

        switch (nInput)
        {
            case 1:
                addBookFunction();
                getchar();
                break;
            case 2:
                break;
            case 3:
                checkOutBookFunction();
                break;
            case 4:
                checkInBookFunction();
                break;
            case 5:
                break;
            case 6:
                //Display_all_Available_Book_Details();
                break;
            case 7:
                displayAllCheckedOutBookFunction();
                break;
            case 8:
                printf("\nGoodby!!! Thanks for using The Libray Manager\n");
                fp = fopen("books.txt", "ab+");
                fseek(fp, 0, SEEK_END);
                for (int j = 0; j<count; j++)
                {
                    fprintf(fp, "%d, %s, %s, %s, %d, %0.2f, %d, %d, %d-%d-%d\n", BOOK[j].nID, BOOK[j].chTitle, BOOK[j].chType, BOOK[j].chPublisher, BOOK[j].nPages, BOOK[j].nPrice, BOOK[j].nPubYear, BOOK[j].nStatus, BOOK[j].due.nYear,BOOK[j].due.nDay,BOOK[j].due.nMonth);
                }
                fclose(fp);
                exit(1);
                break;
            default:
                printf("\n\t\t~~Invalid Input~~\n");
                break;
        }
    }
    return 0;
}

void addBookFunction()
{
    int bookId;
    if (count == 9)
    {
        printf("\n no more spaces\n");
        return;
    }
    printf("\n Enter Book Details\n");
    printf("Enter book ISBN: ");
    scanf("%d", &bookId);
    if (BOOK[count].nID == bookId)
    {
        printf("\nSorry another book with that id: Try again!\n");
        addBookFunction();
    }
    else
    {
        BOOK[count].nID = bookId;
        printf("Enter book title: ");
        scanf("%s", BOOK[count].chTitle);
        printf("Enter book type (eg. magazine, novel): ");
        scanf("%s", BOOK[count].chType);
        printf("Enter book publisher (eg. UTA): ");
        scanf("%s", BOOK[count].chPublisher);
        printf("Enter book's number of pages: ");
        scanf("%d", &BOOK[count].nPages);
        printf("Enter book's price: ");
        scanf("%f", &BOOK[count].nPrice);
        printf("Enter year published: ");
        scanf("%d", &BOOK[count].nPubYear);
        BOOK[count].nStatus = IN;
        count++;
    }
}

void checkOutBookFunction()
{
    int nInput, i = 0;
    char buffer[5];

    printf("Enter the ISBN: ");
    scanf("%d", &nInput);
    if (checkID(nInput) == 0)
    {
        time_t now;

        if ( time(&now) != (time_t)(-1) )
        {
            struct tm *d = localtime(&now);
            if ( strftime(buffer, sizeof(buffer), "%Y", d) )
            {
                BOOK->issued.nYear = atoi(buffer);
                BOOK->issued.nMonth = d->tm_mon;
                BOOK->issued.nDay = d->tm_mday;
            }
        }
        BOOK->due.nDay = BOOK[i].issued.nDay+RETURNTIME;
        BOOK->due.nMonth = BOOK[i].issued.nMonth;
        BOOK->due.nYear = BOOK[i].issued.nYear;

        if (BOOK->due.nDay > 30)
        {
            BOOK->due.nMonth += BOOK->due.nDay/30;
            BOOK->due.nDay -= 30;
        }
        if (BOOK->due.nMonth > 12)
        {
            BOOK->due.nYear += BOOK->due.nMonth/12;
            BOOK->due.nMonth -=12;
        }

        printf("Issued date = %d-%d-%d\n", BOOK->issued.nYear,BOOK->issued.nMonth, BOOK->issued.nMonth);
        printf("Return date = %d-%d-%d", BOOK->due.nYear, BOOK->due.nMonth, BOOK->due.nDay);

        BOOK[i].nStatus += OUT;
    }
    else{
        printf("No book with that id");
    }
}

void checkInBookFunction()
{
    int nInput, i;
    printf("Enter the ISBN: ");
    scanf("%d", &nInput);
    if (checkID(nInput) == 0)
    {
        printf("Book Found");
        BOOK[i].nStatus = IN;
    }
}

void displayAllBookFunction()
{
}

void displayAllAvailableBookFunction()
{
}

void displayAllCheckedOutBookFunction()
{

    if (BOOK->nStatus == OUT)
    {
        printf("%d, %s", BOOK->nID, BOOK->chTitle);
    }else{
        printf("\n\t\t~~NO BOOKS HAS BEEN CHECKED OUT~~\n");
    }
}

int checkID(int t)
{
    int i;
    while (i < MAX)
        if (BOOK[i].nID == t)
            return 0;
    return 1;
}
GeekyCoder
  • 67
  • 1
  • 11
  • 1
    There are a lot of error in your code, please compile it with `-Wall` `-Wextra` and `-Werror`, if you are using gcc. For example, `i` in the `checkID()` is uninitialized, and `fpin` is not closed with `fclose()`. – SSC Nov 20 '14 at 03:10
  • 1
    Note that all capitals is normally reserved for macros and enumeration constants. It is unusual (not technically wrong, just unusual) to see `struct BOOK { … } BOOK[100];`. It would be better to use `struct Book { … } book[100];` or thereabouts. (Yes, the standard C `FILE` structure is an exception to the all caps rule. There are historical reasons for the deviance.) – Jonathan Leffler Nov 20 '14 at 04:37

2 Answers2

1

To reiterate what @SSC has already indicated, you need to initialize variables in C to remove undefined behavior. Using the code you wrote I found two cases where variables were not initialized -

void checkInBookFunction()
{
    int nInput = 0, i = 0; // Changed both variables to initialize to zero.
    // Rest of function code.
}

AND

int checkID(int t)
{
    int i = 0; // Changed this variable as well to initialize to zero.
    // Rest of function code here
}

I was able to write to the file using your code as it is although you might want to look over how to handle string inputs.

You are reading several strings into your structure, although C has the capacity to read strings you are using scanf which is not always the best for these situations. Please refer to C - scanf() vs gets() vs fgets() for more information on how to handle user input.

Community
  • 1
  • 1
KillaBytes
  • 447
  • 3
  • 10
0

In addition to uninitialised variables as pointed above, few observations:

  1. No check to restrict user input string lengths that can be accommodated within the structure without memory overrun. E.g., chTitle, user can enter string longer than 50 bytes allocated for it.
  2. The file, books.txt can contain lines longer than 100 bytes (depending on the data entered by the user). But the buffer used to read each line is 100 bytes, and not checking if you have read complete line. In such case, further token parsing will have unexpected results.
AndersNS
  • 1,597
  • 16
  • 24