Here are 3 simple examples that use the new Cvec.h, Cvec_func's.h, readLine.h, etc... files ... that are linked above. They demo reading from file and writing to file ... and various sorts, (insert sort - isort and merge sort - msort) ... using both Clist and Cvec data record containers.
1. This is just a very simple example that reads a file of 'Student Records' ... structured as below ... into a Cvec ( a dynamic array ) of C struc's, each struct holding one student record. The program demo's filling a Cvec of struct from file and then displaying the contents of that C vector, on the console screen. Note: this simple example also demo's using readLine, provided by including the file "readLine.h" to read dynamic C strings into your struct from file.
/* stud_Cvec_1.c */ /* 2016-10-21 */
#include "readLine.h" /* see file readLine.h to see all that it includes ... */
#define FNAME "students.txt"
/* the file students.txt is 'structured' as per below ... */
/*
Zak
002
M
Chemistry
Sam
123
M
History
Anne Marie
234
F
Biology
*/
/* first, define (typedef) your Rec (your record, i.e. each element in Cvec) */
typedef struct myStudent
{
char* name;
int id;
char gender;
char* course;
} Rec ; /* Rec is used/needed by Cvec.h that is included below ... */
/* freeVrec is used/needed by Cvec.h that is included below ... */
void clearRec( Rec* p )
{
free( p->course ); /* free all dynamic memory allocated by Cvec */
free( p->name ); /* free all dynamic memory allocated by Cvec */
}
/* ok ... now, after above 'two' definitions ... can ... */
#include "Cvec.h"
/* and can now define these utility functions used in 'main' ... */
void showRec( Rec* p )
{
printf( "%s, %d, %c, %s\n", p->name, p->id, p->gender, p->course );
}
void showCvec( Cvec* cv )
{
int i;
for( i = 0; i < cv->size; ++i )
showRec( &cv->ary[i] );
}
void fillFromFile( Cvec* cv )
{
FILE* fin = fopen( FNAME, "r" ); /* recall FNAME is a GLOBAL variable */
Rec tmp;
char* lineID, *lineG;
if( fin )
{
while
(
(tmp.name = readLine(fin)) &&
(lineID = readLine(fin)) &&
(lineG = readLine(fin)) &&
(tmp.course = readLine(fin))
)
{
tmp.id = atoi( lineID ); /* atoi in stdlib.h included by readLine.h */
tmp.gender = lineG[0];
free( lineG ); free( lineID );
push_backCvec( cv, &tmp ); /* Note: 'cv' is already an address */
}
fclose( fin );
}
else printf( "There was an error opening file %s to read ...\n", FNAME );
}
int main()
{
Cvec studs; /* create an empty Cvec im memory labeled 'studs' */
/*NOTE: MUST inital before using ... */
initCvec( &studs ); /* Note: address passed in so 'original updated' */
fillFromFile( &studs ); /* Note: address passed in so 'original updated' */
showCvec( &studs ); /* Note: address passed in to 'avoid making a copy' */
clearCvec( &studs ); /* free dynamic memory when done with it ... */
takeInChar( "\nPress 'Enter' to continue/exit ... " );
return 0;
}
2. This next example expands on the above simple start ... showing how to also use the file "Cvec_func's.h" that provides several functions for you, ready to use, on your Cvec of struct ... including merge sort (msortCvec) and insert sort (isortCvec) ... and how to define a compare function to use for your sorts, searches, etc... This program also demos reformating a file structure and using 'delimter' separated variables in your files that you write and then later, read back into a Cvec of struc ...
/* stud_Cvec_2.c */ /* 2016-10-21 */
#include "readLine.h" /* see file readLine.h to see all it includes/provides */
#define FNAME "students.txt"
/* first ... define (typedef) your Rec (your record - each element in Cvec) */
typedef struct myStudent
{
char* name;
int id;
char gender;
char* course;
} Rec ; /* Rec is used/needed by Cvec.h that is included below ... */
/* freeVrec is used/needed by Cvec.h that is included below ... */
void clearRec( Rec* p )
{
free( p->course ); /* free all dynamic memory allocated by Cvec */
free( p->name ); /* free all dynamic memory allocated by Cvec */
}
/* ok ... now, after above 'two' definitions ... can ... */
#include "Cvec.h"
/* and can ...*/
#include "Cvec_func's.h" /* includes sorts, etc... */
/* and can also define these compare functions needed to sort ... */
int cmpByName( const Rec* a, const Rec* b )
{
return strcmp( a->name, b->name );
}
int cmpByID( const Rec* a, const Rec* b )
{
if( a->id < b->id ) return -1;
if( a->id == b->id ) return 0;
/* else ... equal ... so ... */
return 1;
}
int cmpByCourse( const Rec* a, const Rec* b )
{
return strcmp( a->course, b->course );
}
int cmpByGender( const Rec* a, const Rec* b )
{
return a->gender - b->gender ;
}
void showRec( Rec* p )
{
printf( "%s, %d, %c, %s\n", p->name, p->id, p->gender, p->course );
}
void showCvec( Cvec* cv )
{
int i;
for( i = 0; i < cv->size; ++i )
showRec( &cv->ary[i] );
}
void fillFromFile( Cvec* cv )
{
FILE* fin = fopen( FNAME, "r" ); /* recall FNAME is a GLOBAL variable */
Rec tmp;
char* lineID, *lineG;
if( fin )
{
while
(
(tmp.name = readLine(fin)) &&
(lineID = readLine(fin)) &&
(lineG = readLine(fin)) &&
(tmp.course = readLine(fin))
)
{
tmp.id = atoi( lineID ); /* atoi in stdlib.h included by readLine.h */
tmp.gender = lineG[0];
free( lineG ); free( lineID );
push_backCvec( cv, &tmp ); /* Note: 'cv' is already an address */
}
fclose( fin );
}
else printf( "There was an error opening file %s to read ...\n", FNAME );
}
void fillFromNewFile( Cvec* cv, char* delimiters )
{
/* Note: compiler concats the 2 'text' strings below at compile time */
FILE* fin = fopen( "new" FNAME, "r" ); /* ... FNAME a GLOBAL variable */
Rec tmp;
char* line;
if( fin )
{
while( (line = readLine(fin)) )
{
char* p = line;
int i = 0;
p = strtok( line, delimiters );
while( p != NULL )
{
/* Note: readLine.h also defines 'newCopy' used here ... */
if( i == 0 ) tmp.name = newCopy(p);
if( i == 1 ) tmp.id = atoi(p); /* uses stdlib.h in readLine.h */
if( i == 2 ) tmp.gender = p[0];
if( i == 3 ) tmp.course = newCopy(p);
++i;
p = strtok( NULL, delimiters );
}
free( line );
push_backCvec( cv, &tmp ); /* Note: 'cv' is already an address */
/*
puts( "Inside fill..." );
showRec( &tmp );
getchar();
*/
}
fclose( fin );
}
else printf( "There was an error opening file %s to read ...\n", FNAME );
}
void writeNewFile( Cvec* cv, char delimter )
{
FILE* fout = fopen( "new" FNAME, "w" ); /* FNAME is a GLOBAL variable */
if( fout )
{
int i = 0;
for( ; i < cv->size; ++ i )
fprintf
(
fout, "%s%c%d%c%c%c%s\n",
cv->ary[i].name, delimter,
cv->ary[i].id, delimter,
cv->ary[i].gender, delimter,
cv->ary[i].course
);
fclose( fout );
if( i == cv->size )
printf( "All %d records were filed ok ...\n", i );
else
printf( "ERROR! Only %d of %d records were filed ...\n", i, cv->size );
}
else printf( "There was an error opening file %s to write ...\n", FNAME );
}
int main()
{
char* reply;
Cvec studs;
initCvec( &studs );
printf( "Enter n or ; to read file "
"(n)newline or (;)semi-colon delimited (n/;) ? " );
fflush( stdout );
reply = readLine( stdin );
if( reply[0] == ';' ) fillFromNewFile( &studs, ";" );
else fillFromFile( &studs );
free( reply );
showCvec( &studs );
isortCvec( &studs, cmpByName );
puts( "\nAfter sorting by Name ..." );
showCvec( &studs );
isortCvec( &studs, cmpByGender );
puts( "\nAfter sorting by Gender ..." );
showCvec( &studs );
isortCvec( &studs, cmpByID );
puts( "\nAfter sorting by ID ..." );
showCvec( &studs );
isortCvec( &studs, cmpByCourse );
puts( "\nAfter sorting by Course ..." );
showCvec( &studs );
writeNewFile( &studs, ';' );
clearCvec( &studs ); /* free dynamic memory when done with it ... */
takeInChar( "\nPress 'Enter' to continue/exit ... " );
return 0;
}
3. This 3rd example shows how to use a Clist (instead of a Cvec - note that only a very few changes are needed in your code to recode your Cvec program to use a Clist instead). This program also shows how to define several compare functions to use for your various sorting needs ... (searches, etc.)
/* stud_Clist.c */ /* 2016-10-21 */
#include "readLine.h"
#define FNAME "students.txt"
typedef struct myStudent
{
char* name;
char* id;
char gender;
char* course;
struct myStudent* next;
} Node ;
typedef Node* pNode;
void clearNode( pNode p )
{
free( p->course );
free( p->id );
free( p->name );
}
/* ok ... now can ... */
#include "Clist.h"
/* and can ...*/
#include "Clist_func's.h"
int cmpByName( const pNode a, const pNode b )
{
return strcmp( a->name, b->name );
}
int cmpByID( const pNode a, const pNode b )
{
return strcmp( a->id, b->id );
}
int cmpByCourse( const pNode a, const pNode b )
{
return strcmp( a->course, b->course );
}
int cmpByGender( const pNode a, const pNode b )
{
return a->gender - b->gender ;
}
void showNode( const pNode p )
{
printf( "%s, %s, %c, %s\n", p->name, p->id, p->gender, p->course );
}
void showClist( const Clist* myClst )
{
pNode cur;
for( cur = myClst->start; cur != NULL; cur = cur->next )
showNode( cur );
}
void fillFromFile( Clist* myLst )
{
FILE* fin = fopen( FNAME, "r" ); /* recall FNAME is a GLOBAL variable */
Node tmp;
char* line;
if( fin)
{
while
(
(tmp.name = readLine(fin)) &&
(tmp.id = readLine(fin)) &&
(line = readLine(fin)) &&
(tmp.course = readLine(fin))
)
{
tmp.gender = line[0];
free( line );
push_backClist( myLst, &tmp );
}
}
}
int main()
{
Clist studs;
initClist( &studs );
fillFromFile( &studs );
showClist( &studs );
msortClist( &studs, cmpByName );
puts( "\nAfter sorting by Name ..." );
showClist( &studs );
msortClist( &studs, cmpByGender );
puts( "\nAfter sorting by Gender ..." );
showClist( &studs );
msortClist( &studs, cmpByID );
puts( "\nAfter sorting by ID ..." );
showClist( &studs );
msortClist( &studs, cmpByCourse );
puts( "\nAfter sorting by Course ..." );
showClist( &studs );
clearClist( &studs );
takeInChar( "\nPress 'Enter' to continue/exit ... " );
return 0;
}