Skip to main content

C simple text file i/o

I wanted to learn how to work with file I/O properly so i've found an assignment in my college papers and decided to write it.

So here it is.

//Write a C program which reads data about books and inputs them into a file named books.txt, like this:
//
//book_name#author_name#page_num#code#is_lent#
//
//book_name is an array of a maximum of 50 characters, author_name is an array of a maximum of 50 characters,
//page_num is an integer, code is an integer, is_lent is an integer of interval [0, 1] where 1
//means that the book is lent, and 0 that it isn't.
//Program creates a new file if it exists or opens an existing one and appends new
//data on the end. Input ends when the book name is 'x'.
//Print the contents of the file.

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

/*   Function prototypes    */
void buff_clr( void );
void write_to_file( FILE *fp );
void read_from_file( FILE *fp );
void remove_newline( char *string );

int main()
{
    FILE *fp;

    fp = fopen( "Books.txt" , "a+" );

    if( fp == NULL )
    {
        fprintf( stderr , "Error opening file" );
        exit( 1 );
    }

    write_to_file( fp );
    read_from_file( fp );
    fclose( fp );
    return 0;
}

/*   Removes newline from strings caused by fgets()    */
void remove_newline(char *string)
{
    char *ptr;

    if ( ( ptr = strchr( string , '\n' ) ) != NULL )
      *ptr = '\0';
}

/*   Picks up left over characters from the buffer in case there are any    */
void buff_clr(void)
{
    char garbage;
    do
    {
        garbage = getchar();
    }while( garbage != '\n' );
}

/*   Requests input and writes it to file   */
void write_to_file( FILE *fp )
{
    struct book_s
    {
        char book_title[50];
        char author_name[50];
        unsigned int page_num;
        unsigned int code;
        unsigned int is_lent;
    }book;

    while(1)
    {
        /*          Data input into struct        */
        printf( "Book title: " );

        fgets( book.book_title , 50 , stdin );

        remove_newline(book.book_title);

        if( strcmp( book.book_title , "x") == 0 )
        {
            break;
        }

        printf( "Name of the author: ");

        fgets( book.author_name , 50 , stdin );

        remove_newline(book.author_name);

        printf( "Number of pages: " );

        scanf( "%d" , &book.page_num );

        printf( "Book code: " );

        scanf( "%d" , &book.code );

        do
        {
            printf( "Is book lent(1 = yes , 0 = no):" );

            scanf( "%d" , &book.is_lent );
        }while(book.is_lent > 1);

        /*           Data input into file          */

        fprintf( fp , "%s#%s#%d#%d#%d#\n", book.book_title , book.author_name , book.page_num , book.code , book.is_lent );

        printf( "\n\n" );

        buff_clr(); //Using this here because without it a '\n' sneaks into book title on next iteration for some reason
    }
}

/*  Reads the file we've just written to    */
void read_from_file( FILE *fp )
{
    struct book_s
    {
        char book_title[50];
        char author_name[50];
        char page_num[5];
        char code[20];
        char is_lent[1];
    }book;

    char line[BUFSIZ];

    //Rewind to start of file
    fseek(fp, 0, SEEK_SET);

    while( fgets( line , sizeof(line) , fp ) != NULL )
    {
        strcpy( book.book_title , strtok( line , "#" ) );
        strcpy( book.author_name , strtok( NULL , "#" ) );
        strcpy( book.page_num , strtok( NULL , "#" ) );
        strcpy( book.code , strtok( NULL , "#" ) );
        strcpy( book.is_lent , strtok( NULL , "#" ) );

        printf( "\nBook title: %s", book.book_title );
        printf( "\nName of the author: %s", book.author_name );
        printf( "\nPage num: %s", book.page_num );
        printf( "\nBook code: %s", book.code );
        printf( "\nIs book lent: %s", book.is_lent );
        printf( "\n\n" );
    }
}

Now this all works within the confines of the assigment. But what i am wondering is is my code too long? Could this have been written any shorter? Could this have been written any better? Did i miss anything? Are there any mistakes?

A few things to note. I know i don't really need structs but i had an idea of using them to create arrays of data and then print them one by one but i decided to scrap that idea since the only thing i'd accomplish is more lines of code and more memory wasted, but i liked the look of the struct so i kept it.

Oh and is there a way i could read all the data in their rightful forms without having to read them all as a string and then parse them and then convert them (i didn't convert integers here since i didn't really need to)? I know i can't use fscanf which would read strings until the whitespace character so it would try to gobble the whole line up since there aren't any.

Also what if i had to read multiple lines of varying lengths and file types? for example if instead of book_name#author_name#page_num#code#is_lent# being all one line what if it was

book_name#page_num#

author_name#code#is_lent#

What would be the ways of reading such input?

MrPlow
  • 489
  • 2
  • 5
  • 13