patterncMinor
Simple text file I/O for book data
Viewed 0 times
filesimplebooktextfordata
Problem
I wanted to learn how to work with file I/O properly and found an assignment in my college papers and decided to write it:
```
//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
#include
#include
/ 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);
```
//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
#include
#include
/ 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);
Solution
Regarding correctness, read_from_file has some issues:
If the file content is malformed, and there is no item for e.g. the last strcpy line to read, then strtok will return null, and strcpy will try to copy a null pointer. Crash.
If the item in the file is larger than the strcpy destination buffers (the ones in your structure), then strcpy will keep going till it gets to the end of the destination string, overwriting other variables in your memory - a buffer overrun. This is a serius security flaw.
I suggest you use fscanf instead of memcpy and strtk.
Write to file:
I suggest rather than using a while(1), you go:
Also, I suggest taking all the input first, as a dense block of fgetgs(), and then outputting the captured text for the user to confirm as a single printf statement. You can format the text like this for readability: http://dalelane.co.uk/blog/?p=88
But the comments for this function are my taste I guess.
More generally:
Why not use a YAML libary? I mean, it a way that's a dumb question - you are figuring out file IO right? But I think 'is there a libary I could use for this' is a good question to be in the habit of asking...
If the file content is malformed, and there is no item for e.g. the last strcpy line to read, then strtok will return null, and strcpy will try to copy a null pointer. Crash.
If the item in the file is larger than the strcpy destination buffers (the ones in your structure), then strcpy will keep going till it gets to the end of the destination string, overwriting other variables in your memory - a buffer overrun. This is a serius security flaw.
I suggest you use fscanf instead of memcpy and strtk.
Write to file:
I suggest rather than using a while(1), you go:
printf("Press x to exit");
char chrExitCommandIfX = getchr();
while(chrExitCommandIfX != 'x') {
...
printf("Press x to exit");
char chrExitCommandIfX = getchr();
}Also, I suggest taking all the input first, as a dense block of fgetgs(), and then outputting the captured text for the user to confirm as a single printf statement. You can format the text like this for readability: http://dalelane.co.uk/blog/?p=88
But the comments for this function are my taste I guess.
More generally:
Why not use a YAML libary? I mean, it a way that's a dumb question - you are figuring out file IO right? But I think 'is there a libary I could use for this' is a good question to be in the habit of asking...
Code Snippets
printf("Press x to exit");
char chrExitCommandIfX = getchr();
while(chrExitCommandIfX != 'x') {
...
printf("Press x to exit");
char chrExitCommandIfX = getchr();
}Context
StackExchange Code Review Q#13018, answer score: 4
Revisions (0)
No revisions yet.