/* Cvec2.h */ /* this version 2015-06-15 */
/* http://developers-heaven.net/forum/index.php/topic,46.0.html */
/*
TO USE ... you will need to define / typedef (struct) some record structure
for example: typedef a struct/node/element/record as Rec ...
and define freeVrec( void* r ); ... so can call freeVrec( cv->ary +i*cv->elen );
SEE EXAMPLES at bottom ...
*/
#ifndef dwCvec2_H
#define dwCvec2_H
#ifndef debug_dwCvec2_H
#define debug_dwCvec2_H 0 /* set debug default to 'off' ...*/
#endif
#ifndef dwREADLINE_H
#include "readLine.h" /* includes stdio.h, stdlib.h, string.h, ctype.h, etc */
#endif
/* #include <stdlib.h> // re. realloc */
/* #include <string.h> // re. memcopy */
/* re-set this starting num of rec's to minimize realloc's */
#ifndef VEC_CHUNK_SIZE
#define VEC_CHUNK_SIZE 8
#endif
typedef struct myCvec
{
void* ary;
int elen;
int size;
int cap;
} Cvec;
void initCvec( Cvec* cv, int el_size )
{
cv->ary = NULL;
cv->elen = el_size;
cv->cap = cv->size = 0;
}
void clearCvec( Cvec* cv, void (*freeVrec) (void* el) )
{
if( cv->size )
{
int i;
for( i = cv->size-1; i >= 0; --i )
freeVrec( (char*)cv->ary + i * cv->elen );
#if debug_dwCvec2_H
printf( "Inside clearCvec at free( cv->ary ) = %p\n", cv->ary );
#endif
free( cv->ary );
initCvec( cv, cv->elen );
}
}
/* new array to hold 2x's records ... copies old to new */
void enlargeCvec( Cvec* cv )
{
void* tmp;
if( cv->cap ) cv->cap += cv->cap; /* double capacity ... */
else cv->cap = VEC_CHUNK_SIZE; /* set initial capacity */
tmp = realloc( cv->ary, cv->cap * cv->elen );
if( tmp == NULL )
{
myAssert( 0, "Error: realloc failed in enlargeCvec..." );
}
/* else ... */
cv->ary = tmp; /* update the base address of cv->ary */
}
void reserveCvec( Cvec* cv, int newCap )
{
if( newCap > cv->cap )
{
void* tmp;
cv->cap = newCap;
tmp = realloc( cv->ary, cv->cap * cv->elen );
if( tmp == NULL )
{
myAssert( 0, "Error: realloc failed in reserveCvec..." );
}
/* else ... */
cv->ary = tmp; /* update the base address of cv->ary */
}
}
void push_backCvec( Cvec* cv, void* el )
{
if( cv->size == cv->cap ) enlargeCvec( cv );
/* now add in new Rec ... */
memcpy( ((char*)cv->ary + cv->size*cv->elen), el, cv->elen );
++ cv->size;
}
#endif
/*
typedef struct myStudent
{
char* name;
int id;
} Student ;
void freeStudent( void* el )
{
Student* p = (Student*) el;
free( p->name );
}
typedef struct myStudent2
{
char* fname;
char* lname;
int id;
} Student2 ;
void freeStudent2( void* el )
{
Student2* p = (Student2*) el;
free( p->lname );
free( p->fname );
}
void showStudent( const Student* s )
{
printf( "%s %d", s->name, s->id );
}
void showCvec( const Cvec* s )
{
int i;
for( i = 0; i < s->size; ++i )
{ showRec( (Student*)s->ary + i ); putchar( '\n' ); }
}
void showStudent2( const Student2* s )
{
printf( "%s, %s :: %d", s->lname, s->fname, s->id );
}
void showCvec2( const Cvec* s )
{
int i;
for( i = 0; i < s->size; ++i )
{ showStudent2( (Student2*)s->ary + i ); putchar( '\n' ); }
}
*/
/* Cvec2_func's.h */ /* 2015-06-15 */
/* http://developers-heaven.net/forum/index.php/topic,46.0.html */
/*
this ver: using function pointers ...
msortCvec, isortCvec, isSortedCvec, UniqueCvec,
isUniqueCvec, findCvec, eraseCvec (i.e. find/erase Rec)
*/
#ifndef dwCvec2_funcs_H
#define dwCvec2_funcs_H
#ifndef dwCvec2_H
#include "Cvec2.h"
#endif
void mergeCvec( Cvec* cv, int bot, int top, Cvec* tmp,
int (*myCmp) (const void* a, const void* b) )
{
int mid = (bot+top)/2;
int sz = top - bot + 1; /* size of the range to be merged */
int j = 0; /* next open index in tmp */
int h1 = bot; /* next index to consider in the 1st half */
int h2 = mid + 1; /* next index to consider in the 2nd half */
/* while indexes h1 and h2 are not past their ends ... */
while( h1 <= mid && h2 <= top )
{ /* move the smaller element into the tmp vec next ... */
if( myCmp( ((char*)cv->ary + h1*cv->elen), ((char*)cv->ary + h2*cv->elen) ) <= 0 )
memcpy( ((char*)tmp->ary + cv->elen*j++), ((char*)cv->ary + cv->elen*h1++), cv->elen );
/* tmp->ary[j++] = cv->ary[h1++]; */
else
memcpy( ((char*)tmp->ary + cv->elen*j++), ((char*)cv->ary + cv->elen*h2++), cv->elen );
/* tmp->ary[j++] = cv->ary[h2++]; */
}
/* Note: only one, at most, of the two 'while's' below is executed ... */
while( h1 <= mid ) /* copy any remaining entries (1st half) */
memcpy( ((char*)tmp->ary + cv->elen*j++), ((char*)cv->ary + cv->elen*h1++), cv->elen );
/* tmp->ary[j++] = cv->ary[h1++]; */
while( h2 <= top ) /* copy any remaining entries (2nd half) */
memcpy( ((char*)tmp->ary + cv->elen*j++), ((char*)cv->ary + cv->elen*h2++), cv->elen );
/* tmp->ary[j++] = cv->ary[h2++]; */
for( j = 0; j < sz; ++j ) /* copy back sorted tmp vec... */
memcpy( ((char*)cv->ary +(bot+j)*cv->elen), ((char*)tmp->ary + j*cv->elen), cv->elen );
/* cv->ary[bot+j] = tmp->ary[j]; */
}
void my_msortCvec( Cvec* cv, int bot, int top, Cvec* tmp,
int (*myCmp) (const void* a, const void* b) )
{
if( bot == top ) return;
else
{
int mid = ( bot + top ) / 2;
my_msortCvec( cv, bot, mid, tmp, myCmp ); /* sort the first ... */
my_msortCvec( cv, mid+1, top, tmp, myCmp ); /* and the second half */
mergeCvec( cv, bot, top, tmp, myCmp ); /* now merge 2 sorted chunks */
}
}
/* *NOTE* Calling msortCvec sets the returned by ref Cvec to *** isSorted *** */
void msortCvec( Cvec* cv, int (*myCmp) (const void* a, const void* b) )
{
if( cv->size > 1 )
{
Cvec tmp;
initCvec( &tmp, cv->elen );
reserveCvec( &tmp, cv->size ); /* Note: resets cap, BUT size still 0 */
my_msortCvec( cv, 0, cv->size-1, &tmp, myCmp );
free( tmp.ary ); /* only free ary mem that held copies of pointers */
}
}
void isortCvec( Cvec* cv, int (*myCmp) (const void* a, const void* b) )
{
int i, j;
void* cmp = (void*) newMem( cv->elen );
for( i = 1; i < cv->size; ++i ) /* start with an array of just the first 2 elements (if exists) */
{
memcpy( cmp, ((char*)cv->ary + i*cv->elen), cv->elen ); /* get copy of this new cmp pointer on each outer loop ... */
j = i-1; /* get index of element just to the left of the above 'cmp' to start comparisons */
while( j >= 0 && myCmp(cmp, ((char*)cv->ary+cv->elen*j)) < 0 )
{
memcpy( ((char*)cv->ary + cv->elen*(j+1)), ((char*)cv->ary + cv->elen*j), cv->elen ); /* copy pointer 'up' ... */
--j; /* decrement j in preparation for next inner loop ... */
}
memcpy( ((char*)cv->ary + cv->elen*(j+1)), cmp, cv->elen ); /* insert pointer at index j+1 (since j was decremented above) */
}
free( cmp );
} /* size hasn't changed ... */
int isSortedCvec( Cvec* cv, int (*myCmp) (const void* a, const void* b) )
{
int size = cv->size;
while( --size )
if( myCmp( ((char*)cv->ary + cv->elen*(size)), ((char*)cv->ary + cv->elen*(size-1)) )
< 0 ) return 0;
return 1;
}
void uniqueCvec( Cvec* cv, int (*myCmp) (const void* a, const void* b),
void (*freeVrec) (void* el) )
{
int i = 0, j = 1;
if( !isSortedCvec( cv, myCmp ) )
msortCvec( cv, myCmp ); /* first make sure, name-sorted order by case */
for( ; j < cv->size ; ++j )
{
if( myCmp( ((char*)cv->ary + cv->elen*i), ((char*)cv->ary + cv->elen*j) ) != 0 )
{
++i;
if( i != j ) memcpy( ((char*)cv->ary + cv->elen*i), ((char*)cv->ary + cv->elen*j),
cv->elen );
}
else freeVrec( (char*)cv->ary + cv->elen*j );
}
cv->size = ++i;
}
int isUniqueCvec( Cvec* cv, int (*myCmp) (const void* a, const void* b) )
{
int i;
if( !isSortedCvec( cv, myCmp ) )
msortCvec( cv, myCmp );
for( i = cv->size-1; i > 0; --i )
if( myCmp( ((char*)cv->ary + cv->elen*i), ((char*)cv->ary + cv->elen*(i-1)) ) == 0 )
return 0;
/* else ... */
return 1;
}
/* returns index if string present, else -1 */
int findCvec( Cvec* cv, const void* rec, int (*myCmp) (const void* a, const void* b) )
{
int i;
for( i = 0; i < cv->size; ++i )
if( myCmp( ((char*)cv->ary + cv->elen*i), rec ) == 0 ) return i;
/* else if reach here ... */
return -1;
}
/* if int index valid, erases element there */
void eraseCvec( Cvec* cv, int index, void (*freeVrec) (void* el) )
{
/* int i; */
if( index < 0 || index >= cv->size )
{ printf( "\nERROR! Index %d out of range 0..%d\n", index, cv->size-1 );
return; }
freeVrec( (char*)cv->ary + cv->elen*index ); /* needed here for dynamic memory types */
/* copy each (set of pointers above) down one index */
/* for( i = index; i < cv->size-1; ++i ) */
/* memcpy(&cv->ary[i], &cv->ary[i+1], sizeof(Rec)); */
if( index < cv->size-1 )
memcpy( ((char*)cv->ary + cv->elen*index), ((char*)cv->ary + cv->elen*(index+1)),
(cv->size-1-index)*cv->elen);
/* now update size and return (by reference, since address passed in) */
-- cv->size;
}
#endif
/* test1_Cvec2.h.c */ /* this revision: 2015-06-15 */
/* http://developers-heaven.net/forum/index.php/topic,46.0.html */
#define FNAME "stud2.txt"
#define VEC_CHUNK_SIZE 1
#include "Cvec2_func's.h" /* also includes Cvec2.h, readLine.h, etc... */
/* need to define 'both these' ... for each typedef Recx */
typedef struct Student
{
char* name;
int id;
} Student ;
void freeStudent( void* el )
{
Student* p = (Student*) el;
free( p->name );
}
/* sorts by name ... if names the same, then sorts by id ... */
int cmpNameIdStudent( const void* a, const void* b )
{
const Student* aa = (const Student*)a;
const Student* bb = (const Student*)b;
int t = strcmp( aa->name, bb->name );
if( t == 0 ) return aa->id - bb->id;
return t;
}
/* re. find by id ... to see if id already used ... */
int cmpIdStudent( const void* a, const void* b )
{
const Student* aa = (const Student*)a;
const Student* bb = (const Student*)b;
return aa->id - bb->id;
}
typedef struct Student2
{
char* fname;
char* lname;
int id;
} Student2 ;
void freeStudent2( void* el )
{
Student2* p = (Student2*) el;
free( p->lname );
free( p->fname );
}
/*
sorts by lname ...
if lnames the same, then sorts by fname ...
if fnames the same, then sorts by id
*/
int cmpNameIdStudent2( const void* a, const void* b )
{
const Student2* aa = (const Student2*)a;
const Student2* bb = (const Student2*)b;
int t = strcmp( aa->lname, bb->lname );
if( t == 0 )
{
int t2 = strcmp( aa->fname, bb->fname );
if( t2 == 0 ) return aa->id - bb->id;
return t2;
}
return t;
}
/* re. find by id ... to see if id already used ... */
int cmpIdStudent2( const void* a, const void* b )
{
const Student2* aa = (const Student2*)a;
const Student2* bb = (const Student2*)b;
return aa->id - bb->id;
}
int takeInChr( const char* msg );
int takeInValidInt( const char* prompt );
char* takeInStr( const char* prompt );
void inputStudent( Student* s );
void showStudent( const Student* );
void showCvec( const Cvec* s );
void inputStudent2( Student2* s );
void showStudent2( const Student2* s, FILE*, int );
void showCvec2( const Cvec* s, FILE*, int );
void testStudent();
int fillFromFile( Cvec* cv );
void testStudent2();
int main() /* ********************** BEGIN MAIN ***************************** */
{
puts( "Testing Student ..." );
testStudent();
puts( "\nTesting Student2 ..." );
testStudent2();
takeInChr( "\nPress 'Enter' to continue/exit ... " );
return 0;
} /* ******************************** END MAIN ****************************** */
int takeInChr( const char* msg )
{
int reply;
fputs( msg, stdout ); fflush( stdout );
reply = getchar();
if( reply != '\n' )
while( getchar() != '\n' ) ; /* 'flush' stdin */
return reply;
}
int takeInValidInt( const char* prompt )
{
int tmpInt;
for( ; ; ) /* an example of a C/C++ forever loop ... until 'return' */
{
fputs( prompt, stdout ); fflush( stdout );
if( fscanf( stdin, "%d", &tmpInt ) == 1 && getchar() == '\n' )
break;
/*else ...*/
while( getchar() != '\n' ); /* 'flush' stdin ... as we go ... */
puts( "Invalid input! Integers only please ..." );
}
return tmpInt;
}
char* takeInStr( const char* prompt )
{
fputs( prompt, stdout ); fflush( stdout );
return readLine( stdin );
}
void inputStudent( Student* s )
{
for( ; ; )
{
s->id = takeInValidInt( "Enter unique id number : " );
s->name = takeInStr( "Enter name : " );
printf( "You entered: %s :: %d\n", s->name, s->id );
if( tolower( takeInChr( "Is this entry ok (y/n) ? ") == 'y' ) )
break;
/* else ... */
free( s->name );
puts( "Ok ... this entry aborted ... try again ... " );
}
}
void inputStudent2( Student2* s )
{
for( ; ; )
{
s->id = takeInValidInt( "Enter id number : " );
s->fname = takeInStr( "Enter 1st name : " );
s->lname = takeInStr( "Enter 2nd name : " );
printf( "You entered: %s, %s :: %d\n", s->lname, s->fname, s->id );
if( tolower( takeInChr( "Is this entry ok (y/n) ? ") == 'y' ) )
break;
/* else ... */
free( s->lname );
free( s->fname );
puts( "Ok ... this entry aborted ... try again ... " );
}
}
void showStudent( const Student* s )
{
printf( "Name: %s, ID: %d", s->name, s->id );
}
void showCvec( const Cvec* s )
{
int i;
for( i = 0; i < s->size; ++i )
{ showStudent( (Student*)s->ary + i ); putchar( '\n' ); }
printf( "size = %d, cap = %d\n", s->size, s->cap );
}
void showStudent2( const Student2* s, FILE* fp, int fileOut )
{
if( !fileOut )
printf( "Last, First: %s, %s, ID: %d",
s->lname, s->fname, s->id );
else
fprintf( fp, "%s\n%s\n%d\n",
s->lname, s->fname, s->id );
}
void showCvec2( const Cvec* s, FILE* fp, int fileOut )
{
int i;
for( i = 0; i < s->size; ++i )
{
showStudent2( (Student2*)s->ary + i, fp, fileOut );
if( !fileOut )
{
putchar( '\n' );
if( s->size-1 == i )
printf( "size = %d, cap = %d\n",
s->size, s->cap );
}
}
}
void testStudent()
{
Cvec cv;
Student rTmp;
int index;
initCvec( &cv, sizeof(Student) );
do
{
inputStudent( &rTmp );
index = findCvec( &cv, &rTmp, cmpIdStudent ) ;
/* printf( "Found index was %d\n", index ); */
if( index == -1 )
{
/* push_backCvec( &cv, (void*)&rTmp, freeStudent ); */
push_backCvec( &cv, &rTmp );
puts( "\nNow the vector is ..." );
showCvec( &cv );
}
else
printf( "NOT added since id '%d' is already taken ...\n",
rTmp.id );
}
while( toupper(takeInChr( "More (y/n) ? " )) != 'N' );
msortCvec( &cv, cmpNameIdStudent );
puts( "\nAfter calling msort ... the vector now is ..." );
showCvec( &cv );
clearCvec( &cv, freeStudent );
}
int fillFromFile( Cvec* cv )
{
FILE* fin = fopen( FNAME, "r" );
if( fin )
{
Student2 r;
char* line;
while
(
(r.lname = readLine( fin )) &&
(r.fname = readLine( fin )) &&
(line = readLine( fin ))
)
{
r.id = atoi( line );
free( line );
/* push_backCvec( cv, (void*)&r, freeStudent ); */
push_backCvec( cv, &r );
}
fclose( fin );
return 1;
}
else
{
printf( "There was a problem opening file %s to read.\n", FNAME );
return 0;
}
}
void testStudent2()
{
FILE* fp;
int index = 0;
Cvec cv;
Student2 rTmp;
initCvec( &cv, sizeof(Student2) );
reserveCvec( &cv, 2 );
/* get theses records into first positions ... */
rTmp.id = 123;
rTmp.fname = newCopy( "Ab");
rTmp.lname = newCopy( "Lane");
/* push_backCvec( &cv, (void*)&rTmp, freeStudent2 ); */
push_backCvec( &cv, &rTmp );
rTmp.id = 124;
rTmp.fname = newCopy( "Bob");
rTmp.lname = newCopy( "Lane");
/* push_backCvec( &cv, (void*)&rTmp, freeStudent2 ); */
push_backCvec( &cv, &rTmp );
rTmp.id = 125;
rTmp.fname = newCopy( "Bob");
rTmp.lname = newCopy( "Laine");
/* push_backCvec( &cv, (void*)&rTmp, freeStudent2 ); */
push_backCvec( &cv, &rTmp );
rTmp.id = 123;
rTmp.fname = newCopy( "Ab");
rTmp.lname = newCopy( "Lane");
/* push_backCvec( &cv, (void*)&rTmp, freeStudent2 ); */
push_backCvec( &cv, &rTmp );
do
{
inputStudent2( &rTmp );
index = findCvec( &cv, &rTmp, cmpIdStudent2 ) ;
if( index == -1 )
{
push_backCvec( &cv, (void*)&rTmp );
puts( "\nNow the vector is ..." );
showCvec2( &cv, stdout, 0 );
}
else
printf( "NOT added since id '%d' is already taken ...\n",
rTmp.id );
}
while( toupper(takeInChr( "More (y/n) ? " )) != 'N' );
isortCvec( &cv, cmpNameIdStudent2 );
puts( "\nAfter calling isortCvec ... the vector now is ..." );
showCvec2( &cv, stdout, 0 );
printf( "\nPrinting to file %s ... \n", FNAME );
fp = fopen( FNAME, "w" );
if( fp )
{
showCvec2( &cv, fp, 1 );
fclose( fp );
}
else
printf( "\nThere was a problem opening file %s\n",
FNAME );
clearCvec( &cv, freeStudent2 );
takeInChr( "\nPress 'Enter' to continue ... " );
printf( "\nFilling from file %s ... \n", FNAME );
if( fillFromFile( &cv ) )
{
/* form a record to search/erase ... */
Student2* p = (Student2*) newMem( sizeof(Student2) );
p->id = 124;
p->fname = newCopy("Bob");
p->lname = newCopy("Lane");
showCvec2( &cv, stdout, 0 );
printf( "\nis sorted = %d", isSortedCvec( &cv, cmpNameIdStudent2 ) );
printf( "\nis unique = %d\n", isUniqueCvec( &cv, cmpNameIdStudent2 ) );
/* pause ... */
takeInChr( "\nNote: calling isUniqueCvec leaves the vector sorted ..."
"\n\nPress 'Enter' to continue ... " );
puts( "\nShowing student to find ... and erase ..." );
showStudent2( p, stdout, 0 ); putchar( '\n' );
index = findCvec( &cv, p, cmpNameIdStudent2 );
if( index != -1 )
eraseCvec( &cv, index, freeStudent2 );
else
{
showStudent2( p, stdout, 0 );
puts( " was NOT found." );
}
if( cv.size > 2 )
{
printf( "\nAnd also sfter erasing index %d ...\n",
0 );
eraseCvec( &cv, 0, freeStudent2 );
showCvec2( &cv, stdout, 0 );
}
freeStudent2( p );
free( p );
takeInChr( "\nPress 'Enter' to continue ... " );
printf( "\nunique file %s ... \n", FNAME );
uniqueCvec( &cv, cmpNameIdStudent2, freeStudent2 );
showCvec2( &cv, stdout, 0 );
printf( "\nis sorted = %d", isSortedCvec( &cv, cmpNameIdStudent2 ) );
printf( "\nis unique = %d\n", isUniqueCvec( &cv, cmpNameIdStudent2 ) );
clearCvec( &cv, freeStudent2 );
}
}
/* Clist2.h */ /* 2015-06-16 */
/* http://developers-heaven.net/forum/index.php/topic,46.0.html */
/*
To USE ... you will need to have typedef (struct) some record structure
and get new memory for each new Rec and Node, and define clearLrec( void* r )
so can call clearLrec( p ) and free all new dynamic memory ... (for example:
3 parts if dynamic C strings used SEE EXAMPLES at bottom ... )
*/
#ifndef dwClist2_H
#define dwClist2_H
#ifndef debug_dwClist2_H
#define debug_dwClist2_H 0 /* default is 'off' ... */
#endif
#ifndef dwREADLINE_H
#include "readLine.h" /* includes stdio.h, stdlib.h, string.h, ctype.h, etc */
#endif
/* #include <stdlib.h> // re. realloc */
/* #include <string.h> // re. memcopy */
typedef struct myNode
{
void* data;
struct myNode* next;
} Node;
typedef Node* pNode;
#define pList pNode /* equate */
typedef struct myClist
{
Node* start;
Node* end;
int size;
} Clist;
/* with these, an address is passed, so NO copy made and/or
original updated */
void initClist( Clist* cl )
{
cl->start = cl->end = NULL;
cl->size = 0;
}
void clearClist( Clist* cl, void (*clearLrec) (void* el) )
{
if( cl->size )
{
Node* cur = cl->start;
for( ; cur != NULL; cur = cl->start )
{
cl->start = cur->next;
clearLrec( cur->data );
#if debug_dwClist2_H
printf( "Inside clearClist at clearLrec( cur->data ) = %p\n", cur->data );
printf( "Inside clearClist at free cur = %p\n", (void*)cur );
#endif
free( cur );
}
initClist( cl );
}
}
void push_frontClist( Clist* cl, Node* n )
{
n->next = cl->start;
cl->start = n;
if( !cl->size ) cl->end = n;
++ cl->size;
}
void push_backClist( Clist* cl, Node* n )
{
n->next = NULL;
if( cl->size )
{
cl->end->next = n;
cl->end = n;
}
else
cl->start = cl->end = n;
++ cl->size;
}
#endif
/*
void clearStudent( void* el ) // Student dtor called via using function pointors ... //
{
Student* p = (Student*) el;
free( p->name );
#if debug_dwClist2_H
printf( "Inside clearStudent at free Student* p = %p\n", (void*)p );
#endif
}
void showStudent( const Student* s )
{
printf( "Name, ID: %15s, %10d", s->name, s->id );
}
void showClist( const Clist* cl )
{
Node* p;
for( p = cl->start; p != NULL; p = p->next )
{ showStudent( p->data ); putchar( '\n' ); }
printf( "size = %d\n", cl->size );
}
int cmpNameIdStudent( pList aa, pList bb ) // Student cmp via function pointers //
{
Student* a = (Student*)aa->data;
Student* b = (Student*)bb->data;
int t = strcmp( a->name, b->name );
if( t == 0 ) return a->id - b->id;
return t;
}
typedef struct myStudent2
{
char* fname;
char* lname;
int id;
} Student2 ;
void clearStudent2( void* el ) // Student2 dtor via using function pointors ... //
{
Student2* p = (Student2*) el;
free( p->lname );
free( p->fname );
#if debug_dwClist2_H
printf( "Inside clearStudent2 at free Student* p = %p\n", (void*)p );
#endif
}
void showStudent2( const void* ss )
{
const Student2* s = (const Student2*) ss;
printf( "Last, First ID: %15s, %15s, %10d", s->lname, s->fname, s->id );
}
void showClist2( const Clist* cl )
{
Node* p;
for( p = cl->start; p != NULL; p = p->next )
{ showStudent2( p->data ); putchar( '\n' ); }
printf( "size = %d\n", cl->size );
}
int cmpNameIdStudent2( pList a, pList b ) // Student2 cmp via function pointers //
{
const Student2* aa = (Student2*)a->data;
const Student2* bb = (Student2*)b->data;
int t = strcmp( aa->lname, bb->lname );
if( t == 0 )
{
int t2 = strcmp( aa->fname, bb->fname );
if( t2 == 0 ) return aa->id - bb->id;
return t2;
}
return t;
}
*/
/* Clist2_func's.h */ /* 2015-06-16 */
/* http://developers-heaven.net/forum/index.php/topic,46.0.html */
/*
this version using function pointers ... has ...
msortClist, isortClist, insert_sortedClist, isSortedClist,
uniqueClist, isUniqueClist, findClist, eraseClist (i.e. erase node)
*/
#ifndef dwClist2_funcs_H
#define dwClist2_funcs_H
#ifndef dwClist2_H
#include "Clist2.h"
#endif
/* function protoypes ...*/
void msortClist( Clist*, int (*myCmp) (const pList, const pList) );
void mergesortClist( Clist*, int (*myCmp) (const pList, const pList) );
pList mergeClists( Clist*, Clist*, int (*myCmp) (const pList, const pList) );
void update_end( Clist* );
void insert_sortedClist( Clist*, pList, int (*myCmp) (const pList, const pList) );
void isortClist( Clist*, int (*myCmp) (const pList , const pList) );
int isSortedClist( const Clist*, int (*myCmp) (const pList, const pList) );
void uniqueClist( Clist*, int (*myCmp) (const pList, const pList), void (*clearLrec) (void* el) );
int isUniqueClist( Clist*, int (*myCmp) (const pList a, const pList b) );
pList findClist( const Clist*, const pList, int (*myCmp) (const pList, const pList) );
void eraseClist( Clist*, pList, void (*clearLrec) (void* el) );
/* function definitions ...*/
/* a recursive mergesort ... */
void mergesortClist(Clist* list, int (*myCmp) (const pList r1, const pList r2) )
{
pList cur = list->start;
Clist a, b;
/* base case is a Clist of length 0 or 1 ... */
if ((cur == NULL) || (cur->next == NULL)) return;
/* split Clist into 'a' and 'b' sublists ... */
a.start = cur;
b.start = cur->next;
while((b.start != NULL) && (b.start->next != NULL))
{
cur = cur->next;
b.start = b.start->next->next;
}
b.start = cur->next;
cur->next = NULL; /* Clist divided into 2 roughly equal parts now ... */
/* recursively sort the sublists ... */
mergesortClist(&a, myCmp);
mergesortClist(&b, myCmp);
/* merge the two sorted Clists together ... */
list->start = mergeClists(&a, &b, myCmp);
}
/* merge two sorted Clists with heads 'a' and 'b' ... in sorted order */
pList mergeClists(Clist* a, Clist* b, int (*myCmp) (const pList r1, const pList r2) )
{
pList sorted, new_merged_head;
if( a->start == NULL ) return b->start;
if( b->start == NULL ) return a->start;
if( myCmp(a->start, b->start) <= 0 )
{
sorted = a->start;
a->start = a->start->next;
}
else
{
sorted = b->start;
b->start = b->start->next;
}
new_merged_head = sorted;
/* now ... */
while( a->start != NULL && b->start != NULL )
{
if( myCmp(a->start, b->start) <= 0 )
{
sorted->next = a->start;
sorted = a->start;
a->start = a->start->next;
}
else
{
sorted->next = b->start;
sorted = b->start;
b->start = b->start->next;
}
}
/* and finally ... */
if( a->start != NULL )
sorted->next = a->start;
else if( b->start != NULL )
sorted->next = b->start;
return new_merged_head;
}
void update_end( Clist* list ) /* after sort */
{
if( list->size > 1 )
{
pList cur;
for( cur = list->start; cur->next != NULL; cur = cur->next ) ;
list->end = cur;
list->end->next = NULL;
}
}
void msortClist( Clist* clst, int (*myCmp) (const pList r1, const pList r2) )
{
mergesortClist( clst, myCmp );
update_end( clst );
}
int isSortedClist( const Clist* c, int (*myCmp) (const pList r1, const pList r2) )
{
pList p = c->start;
for( ; p != NULL && p->next != NULL; p = p->next )
if( myCmp(p->next, p) < 0 ) return 0;
return 1;
}
void uniqueClist( Clist* c, int (*myCmp) (const pList r1, const pList r2),
void (*clearLrec) (void* el) )
{
pList p;
if( !isSortedClist(c, myCmp) ) msortClist( c, myCmp );
p = c->start;
while( p->next != NULL )
{
if( myCmp(p, p->next) == 0 )
{
pList tmp = p->next;
p->next = p->next->next;
clearLrec( tmp->data ); /* needed here for dynamic elements... */
#if debug_dwClist2_H
printf( "Inside uniqueClist at free cur = %p\n", (void*)tmp );
#endif
free( tmp );
-- c->size;
}
else p = p->next;
}
update_end( c ) ; /* update end ... */
}
int isUniqueClist( Clist* cl, int (*myCmp) (const pList a, const pList b) )
{
pList p = cl->start;
if( cl->size < 2 ) return 1;
if( !isSortedClist( cl, myCmp ) ) msortClist( cl, myCmp );
for( ; p->next != NULL; p = p->next )
{
if( myCmp( p, p->next ) == 0 ) return 0;
}
/* else */
return 1;
}
/* returns pointer if present, else returns NULL */
pList findClist( const Clist* cl, const pList pr, int (*myCmp) (const pList r1, const pList r2) )
{
pList p;
for( p = cl->start; p != NULL; p = p->next )
if( myCmp(p, pr) == 0 ) return p;
/* else if reach here ... */
return NULL;
}
/* if p valid, erase element there */
void eraseClist( Clist* cl, pList p, void (*clearLrec) (void* el) )
{
pList prev = NULL, cur = cl->start;
for( ; cur != NULL && cur != p; cur = cur->next ) prev = cur;
if( cur == NULL )
{ puts( "\neraseClist ERROR! Pointer NOT found ..."); return; }
if( prev != NULL ) prev->next = cur->next; /* case of NOT FIRST element*/
else cl->start = cl->start->next; /* case of IS FIRST element*/
if( cur == cl->end ) cl->end = prev; /* case of IS LAST element*/
clearLrec( cur->data ); /* needed here for types like dynamic C strings, etc */
#if debug_dwClist2_H
printf( "Inside eraseClist at free cur = %p\n", (void*)cur );
#endif
free( cur ); /* free memory for dynamic Node ... */
/* now update size and return (by reference, since address passed in) */
-- cl->size;
}
/* pass in the address of the Clist and the new Node to insert ... */
void insert_sortedClist( Clist* list, pList n, int (*myCmp) (const pList r1, const pList r2) )
{
pList head;
if( !isSortedClist( list, myCmp )) msortClist( list, myCmp );
head = list->start;
/* firstly, we handle most common case where 'n' is NOT the first Node */
if( head != NULL && myCmp( n, head ) >= 0 ) /* NEED >= */
{
/* so search the linked list for the right location */
pList cur = head;
while( cur->next != NULL && myCmp( cur->next, n ) <= 0 )
{
cur = cur->next;
}
if( cur == list->end ) list->end = n;
n->next = cur->next;
cur->next = n;
/* list->start = head; // unchanged */
}
else /* if we reach here, this IS the first node ... */
{
n->next = head; /* so set this node in first position */
list->start = n;
if( ! list->size ) list->end = n;
}
++ list->size;
}
void isortClist( Clist* list, int (*myCmp) (const pList r1, const pList r2) )
{
pList cur,
nextNode;
Clist nClist;
initClist( &nClist );
for( cur = list->start; cur != NULL; cur = nextNode )
{
nextNode = cur->next; /* get copy here before next is changed below ...*/
insert_sortedClist( &nClist, cur, myCmp ); /* 'cur' already is a Node pointer */
}
/* now ... update old list with new front and back ... */
list->start = nClist.start;
list->end = nClist.end;
/* size hasn't changed ... */
}
#endif
/* test1_Clist2.h.c */ /* 2015-06-16 */
/* http://developers-heaven.net/forum/index.php/topic,46.0.html */
/* a little demo in C of a re-usable sl linked-list container with sorts, etc */
/*
Note:
NEW dynamic memory is created as needed/as we go in the main program
BUT ... released when done ...
by Clist 'destructor' calls using function pointers ...
also function pointers used to define sorts, isSorted, searches, unique
*/
#define FNAME "stud2Clist2.txt"
#define debug_dwClist2_H 1 /* change 1 to 0 to turn off debugging here ... */
#include "Clist2_func's.h" /* includes "Clist2.h". "readLine.h" and ... */
/* ****************************************************************** */
/* 1st example record has 2 fields; note: 1 field uses dynamic memory */
/* ****************************************************************** */
typedef struct myStudent
{
char* name;
int id;
} Student ;
void clearStudent( void* el ) /* Student dtor called via using function pointors ... */
{
Student* p = (Student*) el;
free( p->name );
#if debug_dwClist2_H
printf( "Inside clearStudent at free Student* p = %p\n", (void*)p );
#endif
}
void showStudent( const Student* s )
{
printf( "Name, ID: %15s, %10d", s->name, s->id );
}
void showClist( const Clist* cl )
{
pNode p;
for( p = cl->start; p != NULL; p = p->next )
{ showStudent( p->data ); putchar( '\n' ); }
printf( "size = %d\n", cl->size );
}
int cmpNameIdStudent( const pNode aa, const pNode bb ) /* Student cmp via function pointers */
{
const Student* a = (const Student*)aa->data;
const Student* b = (const Student*)bb->data;
int t = strcmp( a->name, b->name );
if( t == 0 ) return a->id - b->id;
return t;
}
int cmpIdStudent( const pNode aa, const pNode bb ) /* Student cmp via function pointers */
{
const Student* a = (const Student*)aa->data;
const Student* b = (const Student*)bb->data;
return a->id - b->id;
}
/* ****************************************************************** */
/* 2nd example record has 3 fields; note: 2 fields use dynamic memory */
/* ****************************************************************** */
typedef struct myStudent2
{
char* fname;
char* lname;
int id;
} Student2 ;
void clearStudent2( void* el ) /* Student2 dtor via using function pointors ... */
{
Student2* p = (Student2*) el;
free( p->lname );
free( p->fname );
#if debug_dwClist2_H
printf( "Inside clearStudent2 at free Student* p = %p\n", (void*)p );
#endif
}
void showStudent2( const void* ss )
{
const Student2* s = (const Student2*) ss;
printf( "Last, First ID: %15s, %15s, %10d", s->lname, s->fname, s->id );
}
void showClist2( const Clist* cl )
{
pNode p;
for( p = cl->start; p != NULL; p = p->next )
{ showStudent2( p->data ); putchar( '\n' ); }
printf( "size = %d\n", cl->size );
}
int cmpNameIdStudent2( const pNode a, const pNode b ) /* Student2 cmp via function pointers */
{
const Student2* aa = (const Student2*)a->data;
const Student2* bb = (const Student2*)b->data;
int t = strcmp( aa->lname, bb->lname );
if( t == 0 )
{
int t2 = strcmp( aa->fname, bb->fname );
if( t2 == 0 ) return aa->id - bb->id;
return t2;
}
return t;
}
int cmpIdStudent2( const pNode a, const pNode b ) /* Student2 cmp via function pointers */
{
const Student2* aa = (const Student2*)a->data;
const Student2* bb = (const Student2*)b->data;
return aa->id - bb->id;
}
void takeInStudent( Student*, Clist* );
void takeInStudent2( Student2*, Clist* );
int takeInChr( const char* msg );
int getValidInt( const char* prompt );
char* takeInStr( const char* prompt );
void testList() ; /* testing Clist of Student: push_back, isort, show, clear... */
int fillFromFile( Clist* cl ) ; /* testing Clist of Student2 from file ... */
/* testing Clist of Student2: push_front, msort, show, clear, find, erase, unique... */
void testList2() ;
int main() /* *************** BEGIN MAIN **************** */
{
puts( "Testing Student ..." );
testList();
puts( "\nTesting Student2 ..." );
testList2();
takeInChr( "\nPress 'Enter' to continue/exit ... " );
return 0;
} /* ************************ END MAIN ****************** */
int takeInChr( const char* msg )
{
int reply;
fputs( msg, stdout ); fflush( stdout );
reply = getchar();
if( reply != '\n' )
while( getchar() != '\n' ) ; /* 'flush' stdin */
return reply;
}
char* takeInStr( const char* prompt )
{
fputs( prompt, stdout ); fflush( stdout );
return readLine( stdin );
}
int takeInValidInt( const char* prompt )
{
for( ; ; ) /* an example of a C/C++ forever loop ... until 'return' */
{
int numGood, testInt;
fputs( prompt, stdout ); fflush( stdout );
numGood = fscanf( stdin, "%d", &testInt );
while( getchar() != '\n' ); /* 'flush' stdin ... as we go ... */
if( numGood == 1 ) return testInt;
/*else ...*/
puts( "Invalid input! Integers only please ..." );
}
}
void takeInStudent( Student* s, Clist* cl )
{
for( ; ; )
{
for( ; ; )
{
Node tmp;
s->id = takeInValidInt( "Enter unique id number : " );
tmp.data = s;
if( !findClist( cl, &tmp, cmpIdStudent ) ) break;
puts( "All ready used ..." );
}
s->name = takeInStr( "Enter name : " );
printf( "You entered: %s :: %d\n", s->name, s->id );
if( tolower( takeInChr( "Is this entry ok (y/n) ? ") == 'y' ) )
break;
/* else ... */
free( s->name );
puts( "Ok ... this entry aborted ... try again ... " );
}
}
void takeInStudent2( Student2* s, Clist* cl )
{
for( ; ; )
{
for( ; ; )
{
Node tmp;
s->id = takeInValidInt( "Enter unique id number : " );
tmp.data = s;
if( !findClist( cl, &tmp, cmpIdStudent2 ) ) break;
puts( "All ready used ..." );
}
s->fname = takeInStr( "Enter 1st name : " );
s->lname = takeInStr( "Enter 2nd name : " );
printf( "You entered: %s, %s :: %d\n", s->lname, s->fname, s->id );
if( tolower( takeInChr( "Is this entry ok (y/n) ? ") == 'y' ) )
break;
/* else ... */
free( s->lname );
free( s->fname );
puts( "Ok ... this entry aborted ... try again ... " );
}
}
void testList() /* testing Clist of Student: push_back, isort, show, clear... */
{
Clist cl;
initClist( &cl );
do
{
Student* pTmp = (Student*)newMem( sizeof(Student) );
pNode pNewNode = (pNode)newMem( sizeof(Node) );
takeInStudent( pTmp, &cl );
pNewNode->data = pTmp;
push_backClist( &cl, pNewNode );
puts( "\nList now is ..." );
showClist( &cl );
}
while( tolower( takeInChr( "More (y/n) ? " )) != 'n' );
puts( "\nShowing isorted ..." );
isortClist( &cl, cmpNameIdStudent );
showClist( &cl );
clearClist( &cl, clearStudent );
}
int fillFromFile( Clist* cl ) /* testing Clist of Student2 from file ... */
{
FILE* fin = fopen( FNAME, "r" );
if( fin )
{
Student2 st2;
char* line;
while
(
(st2.fname = readLine( fin )) &&
(st2.lname = readLine( fin )) &&
(line = readLine( fin ))
)
{
Student2* pTmp = (Student2*)newMem( sizeof(Student2) );
pNode pNewNode = (pNode)newMem( sizeof(Node) );
st2.id = atoi( line );
free( line );
memcpy( pTmp, &st2, sizeof(Student2) );
pNewNode->data = pTmp;
push_backClist( cl, pNewNode );
}
fclose( fin );
return 1;
}
/* else ... if reach here ... */
printf( "There was a problem opening file %s to read.\n", FNAME );
return 0;
}
/* testing Clist of Student2: push_front, msort, show, clear, find, erase, unique... */
void testList2()
{
Clist cl;
pNode pStudent2;
/* get memory to hold */
pNode newNode = (pNode)newMem( sizeof(Node) );
initClist( &cl );
/* take in some new Students via keyboard user ... */
do
{
Student2* pTmp = (Student2*)newMem( sizeof(Student2) );
pNode pNewNode = (pNode)newMem( sizeof(Node) );
takeInStudent2( pTmp, &cl );
pNewNode->data = pTmp;
push_backClist( &cl, pNewNode );
puts( "\nList now is ..." );
showClist2( &cl );
}
while( tolower( takeInChr( "More (y/n) ? " )) != 'n' );
puts( "\nShowing msorted ..." );
msortClist( &cl, cmpNameIdStudent2 );
showClist2( &cl );
clearClist( &cl, clearStudent2 );
takeInChr( "\nList cleared ... Press 'Enter' to continue ... " );
printf( "\nNow filling from file %s ... \n", FNAME );
if( fillFromFile( &cl ) )
{
int count = 0;
Student2* pTmp;
newNode->data = cl.start->data;
pTmp = (Student2*)newNode->data;
showClist2( &cl );
printf( "\nis sorted = %d", isSortedClist( &cl, cmpNameIdStudent2 ) );
printf( "\nis unique = %d\n", isUniqueClist( &cl, cmpNameIdStudent2 ) );
takeInChr( "\nPress 'Enter' to continue ... " );
puts( "\nShowing student to find ... and erase ..." );
showStudent2( pTmp ); putchar( '\n' );
pStudent2 = findClist( &cl, newNode, cmpNameIdStudent2 );
if( pStudent2 )
{ eraseClist( &cl, pStudent2, clearStudent2 ); ++ count; }
else printf( "'pStudent2' not found ...\n" );
eraseClist( &cl, cl.start, clearStudent2 );
eraseClist( &cl, cl.end, clearStudent2 );
count += 2;
printf( "\nList now ... after erasing %d Nodes ...\n", count );
showClist2( &cl );
takeInChr( "\nPress 'Enter' to continue ... " );
printf( "\nShowing unique list from file '%s' ... \n", FNAME );
uniqueClist( &cl, cmpNameIdStudent2, clearStudent );
showClist2( &cl );
printf( "\nis sorted = %d", isSortedClist( &cl, cmpNameIdStudent2 ) );
printf( "\nis unique = %d\n", isUniqueClist( &cl, cmpNameIdStudent2 ) );
clearClist( &cl, clearStudent2 );
}
free( newNode );
}
/* "stud2.txt" // Note: has lots of duplicates to test unique ... */
/*
Sam
Smith
123
Bill
Jones
345
Bob
Lane
234
Anne
Mills
678
Sam
Smith
123
Bill
Jones
345
Bob
Lane
234
Anne
Mills
678
Sam
Smith
123
Bill
Jones
345
Bob
Lane
234
Anne
Mills
678
*/
/* test2_Cvec2.h.c */ /* 2015-06-16 */
/* http://developers-heaven.net/forum/index.php/topic,46.0.html */
/* testing a Cvec of Cvec ... (A MATRIX) ... using the new file "Cvec2.h" ... */
#define debug_dwCvec2_H 1 /* change 1 to 0 to turn off debugging here ... */
#include "Cvec2.h"
typedef struct myRec
{
double d;
} Rec ;
void destroyRec( void* el ) /* re. function pointer */
{
/* NO dynamic memory at this level to destruct ... */
#if debug_dwCvec2_H
puts( "destroyRec called ..." );
#endif
}
typedef struct myVecOfRec
{
Cvec cv ;
} CvecOfRec ;
void destroyCvecOfRec( void* el ) /* re. function pointer */
{
Cvec* cv = (Cvec*) el;
#if debug_dwCvec2_H
printf( "\ndestroyCvecOfRec called to destroy Cvec* at %p\n", (void*)cv );
#endif
clearCvec( cv, destroyRec );
}
int takeInChr( const char* msg );
int takeInInt( const char* prompt );
double takeInDbl( const char* prompt );
void takeInCvecNumElem(Cvec *cv, int num );
void showRec( const Rec* );
void showCvec( const Cvec* );
void showCvecOfCvec( const Cvec* );
void testCvec();
void takeInMatrix( Cvec* cvcv, int nrows, int ncols );
void getSum( Cvec* cvcv, Cvec* cvcv2, Cvec* cvcv3 );
void testMatrix();
double getValAt( const Cvec* cv, int i );
void setValAt( Cvec* cv, int i, double val );
Cvec* getCvecAt( Cvec*, int );
int main() /* ****************** BEGIN MAIN ********************************* */
{
testCvec();
putchar( '\n' );
testMatrix();
fputs( "\nPress 'Enter' to continue/exit ... ", stdout); fflush( stdout );
getchar(); /* keep 'Window' open until 'Enter' key is pressed ... */
return 0;
} /* **************************** END MAIN ********************************** */
int takeInChr( const char* msg )
{
int chr;
fputs( msg, stdout ); fflush( stdout );
chr = getchar();
if( chr != '\n' ) while( getchar() != '\n' ) ; /* 'flush' stdin */
return chr;
}
int takeInInt( const char* prompt )
{
for( ; ; ) /* an example of a C/C++ forever loop ... until 'return' */
{
int val;
fputs( prompt, stdout ); fflush( stdout );
if( fscanf( stdin, "%d", &val ) == 1 && getchar() == '\n' )
return val;
/* else ... if reach here ... */
while( getchar() != '\n' ); /* 'flush' stdin ... as we go ... */
puts( "Invalid input! Integers only please ..." );
}
}
double takeInDbl( const char* prompt )
{
for( ; ; ) /* an example of a C/C++ forever loop ... until 'return' */
{
double val;
fputs( prompt, stdout ); fflush( stdout );
if( fscanf( stdin, "%lf", &val ) == 1 && getchar() == '\n' )
return val;
/* else ... if reach here ... */
while( getchar() != '\n' ); /* 'flush' stdin ... as we go ... */
puts( "Invalid input! Numbers only please ..." );
}
}
void takeInCvecNumElem( Cvec* cv, int num )
{
int i;
Rec rc; /*1234567890123456789*/
char prompt[32] = "Enter Cvec element ";
reserveCvec( cv, num );
for( i = 0; i < num; ++ i )
{
sprintf( prompt+19, "%02d: ", i+1 );
rc.d = takeInDbl( prompt );
push_backCvec( cv, &rc );
}
}
void showRec( const Rec* rc )
{
printf( "%f", rc->d );
}
void showCvec( const Cvec* cv )
{
int i;
for( i = 0; i < cv->size; ++ i )
{
showRec( (const Rec*)cv->ary + i );
putchar( ' ' );
}
}
void showCvecOfCvec( const Cvec* cv )
{
int i;
for( i = 0; i < cv->size; ++i )
{
printf( "Row %2d: ", i+1 );
showCvec( (const Cvec*)cv->ary + i );
putchar( '\n' );
}
}
void testCvec()
{
Cvec cv;
initCvec( &cv, sizeof(Rec) );
do
{
int i,
num = takeInInt( "Enter number of elements for this vector: " );
takeInCvecNumElem( &cv, num );
showCvec( &cv ); putchar( '\n' );
for( i = 0; i < cv.size; ++i )
{
printf( "v(%d) = %f ", i+1, getValAt( &cv, i ) );
}
putchar( '\n' );
clearCvec( &cv, destroyRec );
}
while( tolower(takeInChr( "More (y/n) ? " ))!= 'n' );
}
void takeInMatrix( Cvec* cvcv, int nrows, int ncols )
{
int i;
reserveCvec( cvcv, nrows );
for( i = 0; i < nrows; ++i )
{
Cvec cv;
initCvec( &cv, sizeof(Rec) );
reserveCvec( &cv, ncols );
printf( "For row %d:\n", i+1 );
takeInCvecNumElem( &cv, ncols );
push_backCvec( cvcv, &cv );
}
}
void initialMatrix( Cvec* cvcv, int nrows, int ncols )
{
int i, j;
reserveCvec( cvcv, nrows );
for( i = 0; i < nrows; ++i )
{
Cvec cv;
Rec r;
r.d = 0.0;
initCvec( &cv, sizeof(Rec) );
reserveCvec( &cv, ncols );
for( j = 0; j < ncols; ++j ) push_backCvec( &cv, &r );
push_backCvec( cvcv, &cv );
}
}
double getValAt( const Cvec* cv, int i )
{
return *((double*) ((const char*)cv->ary + i*cv->elen));
}
void setValAt( Cvec* cv, int i, double val )
{
*(double*)((char*)cv->ary + i*cv->elen) = val;
}
Cvec* getCvecAt( Cvec* cv, int i )
{
return (Cvec*)cv->ary + i ;
}
void getSum( Cvec* cvcv, Cvec* cvcv2, Cvec* cvcv3 )
{
int i, j;
for( i = 0; i < cvcv->size; ++i )
{
Cvec* inner = getCvecAt( cvcv, i );
Cvec* inner2 = getCvecAt( cvcv2, i );
Cvec* inner3 = getCvecAt( cvcv3, i );
for( j = 0; j < inner->size; ++ j )
setValAt( inner3, j, getValAt(inner, j) + getValAt(inner2, j) );
}
}
void testMatrix()
{
int nrows, ncols;
Cvec cvcv, cvcv2, cvcv3;
initCvec( &cvcv, sizeof(CvecOfRec) );
initCvec( &cvcv2, sizeof(CvecOfRec) );
initCvec( &cvcv3, sizeof(CvecOfRec) );
nrows = takeInInt( "Enter number of rows in matrix: " );
ncols = takeInInt( "Enter number of cols in matrix: " );
puts( "\nGet matrix 1 ..." );
takeInMatrix( &cvcv, nrows, ncols );
puts( "\nGet matrix 2 ..." );
takeInMatrix( &cvcv2, nrows, ncols );
puts( "\nMatrix 1:" );
showCvecOfCvec( &cvcv );
puts( " + Matrix 2:" );
showCvecOfCvec( &cvcv2 );
initialMatrix(&cvcv3, nrows, ncols );
getSum( &cvcv, &cvcv2, &cvcv3 );
puts( "= Matrix 3:" );
showCvecOfCvec( &cvcv3 );
takeInChr( "Press 'Enter' to continue ..." );
clearCvec( &cvcv3, destroyCvecOfRec );
clearCvec( &cvcv2, destroyCvecOfRec );
clearCvec( &cvcv, destroyCvecOfRec );
}
/* test2_Clist2.h.c */ /* 2015-06-16 */
/* http://developers-heaven.net/forum/index.php/topic,46.0.html */
/* testing a Clist of Clist... (A MATRIX) ... using the new file "Clist2.h" ... */
#define debug_dwClist2_H 1 /* change 1 to 0 to turn off debugging here ... */
#include "Clist2.h"
typedef struct myRec
{
double d;
} Rec ;
void destroyRec( void* el ) /* re. function pointer */
{
/* NO dynamic memory at this level to destruct ... */
#if debug_dwClist2_H
puts( "destroyRec called ..." );
#endif
}
typedef struct myListOfRec
{
Clist cl ;
} ClistOfRec ;
void destroyClistOfRec( void* el ) /* re. function pointer */
{
Clist* cl = (Clist*) el;
#if debug_dwClist2_H
printf( "\ndestroyClistOfRec called to destroy Clist* at %p\n", (void*)cl );
#endif
clearClist( cl, destroyRec );
}
int takeInChr( const char* msg );
int takeInInt( const char* prompt );
double takeInDbl( const char* prompt );
void takeInClistNumElem( Clist *cl, int num );
void showRec( const void* el );
void showClist( const Clist* cl );
void showClistOfClist( const Clist* cl );
void testClist();
void initialMatrix( Clist* clcl, int nrows, int ncols );
void takeInMatrix( Clist* clcl, int nrows, int ncols );
void getSum( Clist* clcl, Clist* clcl2, Clist* clcl3 );
void testMatrix();
double getValAt( const Clist* cl, int i );
void setValAt( Clist* cl, int i, double val );
Clist* getClistAt( const Clist* cl, int i );
int main() /* ****************** BEGIN MAIN ********************************* */
{
testClist();
putchar( '\n' );
testMatrix();
fputs( "\nPress 'Enter' to continue/exit ... ", stdout); fflush( stdout );
getchar(); /* keep 'Window' open until 'Enter' key is pressed ... */
return 0;
} /* **************************** END MAIN ********************************** */
int takeInChr( const char* msg )
{
int reply;
fputs( msg, stdout ); fflush( stdout );
reply = getchar();
if( reply != '\n' ) while( getchar() != '\n' ) ; /* 'flush' stdin */
return toupper( reply );
}
int takeInInt( const char* prompt )
{
for( ; ; ) /* an example of a C/C++ forever loop ... until 'return' */
{
int val;
fputs( prompt, stdout ); fflush( stdout );
if( fscanf( stdin, "%d", &val ) == 1 && getchar() == '\n' )
return val;
/* else ... if rech here ... */
while( getchar() != '\n' ); /* 'flush' stdin ... as we go ... */
puts( "Invalid input! Integers only please ..." );
}
}
double takeInDbl( const char* prompt )
{
for( ; ; ) /* an example of a C/C++ forever loop ... until 'return' */
{
double val;
fputs( prompt, stdout ); fflush( stdout );
if( fscanf( stdin, "%lf", &val ) == 1 && getchar() == '\n' )
return val;
/*else ...*/
while( getchar() != '\n' ); /* 'flush' stdin ... as we go ... */
puts( "Invalid input! Numbers only please ..." );
}
}
void takeInClistNumElem( Clist* cl, int num )
{
int i;
for( i = 0; i < num; ++ i )
{
Rec* tmp = (Rec*)newMem( sizeof(Rec) );
pNode p = (pNode)newMem( sizeof(Node) );
/* 12345678901234567890 */
char prompt[32] = "Enter Clist element ";
sprintf( prompt+20, "%02d: ", i+1 );
tmp->d = takeInDbl( prompt );
p->data = tmp;
push_backClist( cl, p );
}
}
void showRec( const void* el )
{
const Rec* rc = (const Rec*) el;
printf( "%f", rc->d );
}
void showClist( const Clist* cl )
{
pNode i;
for( i = cl->start; i != NULL; i = i->next )
{
showRec( i->data ); putchar( ' ' );
}
}
void showClistOfClist( const Clist* cl )
{
pNode i;
int j = 0;
for( i = cl->start; i != NULL; i = i->next )
{
printf( "Row %2d: ", ++j );
showClist( i->data );
putchar( '\n' );
}
}
void testClist()
{
Clist cl;
initClist( &cl );
do
{
int i,
num = takeInInt( "Enter number of elements for this list: " );
takeInClistNumElem( &cl, num );
showClist( &cl ); putchar( '\n' );
for( i = 0; i < cl.size; ++i )
{
printf( "v(%d) = %f ", i+1, getValAt( &cl, i ) );
}
putchar( '\n' );
clearClist( &cl, destroyRec );
}
while( takeInChr( "More (y/n) ? " ) != 'N' );
}
void takeInMatrix( Clist* clcl, int nrows, int ncols )
{
int i;
for( i = 0; i < nrows; ++i )
{
Clist* cl = (Clist*)newMem( sizeof(Clist));
pNode p = (pNode)newMem( sizeof(Node) );
initClist( cl );
printf( "For row %d:\n", i+1 );
takeInClistNumElem( cl, ncols );
p->data = cl;
push_backClist( clcl, p );
}
}
void initialMatrix( Clist* clcl, int nrows, int ncols )
{
int i, j;
for( i = 0; i < nrows; ++i )
{
Clist* cl = (Clist*)newMem( sizeof(Clist));
pNode pi = (pNode)newMem( sizeof(Node) );
initClist( cl );
for( j = 0; j < ncols; ++j )
{
Rec* rc = (Rec*)newMem( sizeof(Rec));
pNode pj = (pNode)newMem( sizeof(Node) );
rc->d = 0.0;
pj->data = rc;
push_backClist( cl, pj );
}
pi->data = cl;
push_backClist( clcl, pi );
}
}
double getValAt( const Clist* cl, int i )
{
if( i >= 0 && i < cl->size )
{
int j;
pNode cur;
for( j = 0, cur = cl->start; cur != NULL; ++j, cur = cur->next )
if( j == i ) return ((Rec*)(cur->data))->d;
}
/* else */
printf( "Index %d out of valid range 0 to %d, returning 0.0", i, cl->size );
return 0.0;
}
void setValAt( Clist* cl, int i, double val )
{
if( i >= 0 && i < cl->size )
{
int j;
pNode cur;
for( j = 0, cur = cl->start; cur != NULL; ++j, cur = cur->next )
{
if( j == i ) { ((Rec*)(cur->data))->d = val; return; }
}
}
/* else */
printf( "Index %d out of valid range 0 to %d, returning 0.0", i, cl->size );
}
Clist* getClistAt( const Clist* cl, int i )
{
if( i < cl->size )
{
int j;
pNode cur;
for( j = 0, cur = cl->start; cur != NULL; ++j, cur = cur->next )
{
if( j == i ) return (Clist*)(cur->data);
}
}
/* else */
printf( "Index %d out of valid range 0 to %d, returning NULL", i, cl->size );
return NULL ;
}
void getSum( Clist* clcl, Clist* clcl2, Clist* clcl3 )
{
int i, j;
for( i = 0; i < clcl->size; ++i )
{
Clist* inner = getClistAt( clcl, i );
Clist* inner2 = getClistAt( clcl2, i );
Clist* inner3 = getClistAt( clcl3, i );
for( j = 0; j < inner->size; ++ j )
{
setValAt( inner3, j, getValAt(inner, j) + getValAt(inner2, j) );
}
}
}
void testMatrix()
{
int nrows, ncols;
Clist clcl, clcl2, clcl3;
initClist( &clcl );
initClist( &clcl2 );
initClist( &clcl3 );
nrows = takeInInt( "Enter number of rows in matrix: " );
ncols = takeInInt( "Enter number of cols in matrix: " );
puts( "\nGet matrix 1 ..." );
takeInMatrix( &clcl, nrows, ncols );
puts( "\nGet matrix 2 ..." );
takeInMatrix( &clcl2, nrows, ncols );
puts( "\nMatrix 1:" );
showClistOfClist( &clcl );
puts( " + Matrix 2:" );
showClistOfClist( &clcl2 );
initialMatrix(&clcl3, nrows, ncols );
getSum( &clcl, &clcl2, &clcl3 );
puts( "= Matrix 3:" );
showClistOfClist( &clcl3 );
takeInChr( "Press 'Enter' to continue ..." );
clearClist( &clcl3, destroyClistOfRec );
clearClist( &clcl2, destroyClistOfRec );
clearClist( &clcl, destroyClistOfRec );
}
/* test3_Cvec2.h.c */ /* 2016-06-16 */
/* http://developers-heaven.net/forum/index.php/topic,46.0.html */
/*
testing a Cvec of Cvec ... (A MATRIX of dynamic C strings) ...
using the new file "Cvec2.h" ...
*/
#define debug_dwCvec2_H 1 /* change 1 to 0 to turn off debugging here ... */
#include "Cvec2.h"
typedef struct myRec
{
char* str;
} Rec ;
void destroyRec( void* el ) /* re. function pointer */
{
Rec* p = (Rec*) el;
free( p->str );
#if debug_dwCvec2_H
puts( "destroyRec called ..." );
#endif
}
typedef struct myVecOfRec
{
Cvec cv ;
} CvecOfRec ;
void destroyCvecOfRec( void* el ) /* re. function pointer */
{
Cvec* cv = (Cvec*) el;
#if debug_dwCvec2_H
printf( "\ndestroyCvecOfRec called to destroy Cvec* at %p\n", (void*)cv );
#endif
clearCvec( cv, destroyRec );
}
int takeInChr( const char* msg );
int takeInInt( const char* prompt );
void takeInCvecNumElem( Cvec* cv, int num );
void showRec( const Rec* );
void showCvec( const Cvec* cv );
void showCvecOfCvec( Cvec* cv );
void testCvec();
void inputMatrix( Cvec* cvcv, int nrows, int ncols );
void testMatrix();
char* getValAt( const Cvec* cv, int i );
void setValAt( Cvec* cv, int i, char* val );
Cvec* getCvecAt( Cvec* cv, int i );
int main() /* *********** BEGIN MAIN ******************** */
{
testCvec();
putchar( '\n' );
testMatrix();
fputs( "\nPress 'Enter' to continue/exit ... ", stdout); fflush( stdout );
getchar(); /* keep 'Window' open until 'Enter' key is pressed ... */
return 0;
} /* ********************* END MAIN ********************* */
int takeInChr( const char* msg )
{
int chr;
fputs( msg, stdout ); fflush( stdout );
chr = getchar();
if( chr != '\n' ) while( getchar() != '\n' ) ; /* 'flush' stdin */
return chr;
}
int takeInInt( const char* prompt )
{
for( ; ; ) /* an example of a C/C++ forever loop ... until 'return' */
{
int val;
fputs( prompt, stdout ); fflush( stdout );
if( fscanf( stdin, "%d", &val ) == 1 && getchar() == '\n' )
return val;
/*else ...*/
while( getchar() != '\n' ); /* 'flush' stdin ... as we go ... */
puts( "Invalid input! Integers only please ..." );
}
}
void takeInCvecNumElem( Cvec* cv, int num )
{
int i;
reserveCvec( cv, num );
for( i = 0; i < num; ++ i )
{
Rec r;
printf( "Enter Cvec C string %02d: ", i+1 );
r.str = readLine( stdin );
push_backCvec( cv, &r );
}
}
void showRec( const Rec* rc )
{
printf( "%s", rc->str );
}
void showCvec( const Cvec* cv )
{
int i;
for( i = 0; i < cv->size; ++ i )
{
showRec( (Rec*)cv->ary + i );
putchar( ' ' );
}
}
void showCvecOfCvec( Cvec* cv )
{
int i;
for( i = 0; i < cv->size; ++i )
{
printf( "Row %2d: ", i+1 );
showCvec( (Cvec*)cv->ary + i );
putchar( '\n' );
}
}
void testCvec()
{
Cvec cv;
initCvec( &cv, sizeof(Rec) );
do
{
int i, num = takeInInt( "Enter number of elements for this vector: " );
takeInCvecNumElem( &cv, num );
showCvec( &cv ); putchar( '\n' );
puts( "\nTesting 'getValAt( &cv, i ) ..." );
for( i = 0; i < cv.size; ++i )
{
printf( "v(%d) = %s ", i+1, getValAt( &cv, i ) );
}
putchar( '\n' );
clearCvec( &cv, destroyRec );
}
while( tolower( takeInChr( "More (y/n) ? " )) != 'n' );
}
void inputMatrix( Cvec* cvcv, int nrows, int ncols )
{
int i;
reserveCvec( cvcv, nrows );
for( i = 0; i < nrows; ++i )
{
Cvec cv;
initCvec( &cv, sizeof(Rec) );
reserveCvec( &cv, ncols );
printf( "For row %d:\n", i+1 );
takeInCvecNumElem( &cv, ncols );
push_backCvec( cvcv, &cv );
}
}
char* getValAt( const Cvec* cv, int i ) /* Note: only a shallow copy here ... */
{
return ((Rec*)cv->ary + i)->str;
}
void setValAt( Cvec* cv, int i, char* val )
{
Rec* p = ((Rec*)cv->ary + i);
free( p->str );
p->str = newCopy( val );
}
Cvec* getCvecAt( Cvec* cv, int i )
{
return (Cvec*)cv->ary + i ;
}
void testMatrix()
{
int nrows, ncols, nr, nc;
char* nVal;
void* p_cv;
Cvec cvcv;
initCvec( &cvcv, sizeof(CvecOfRec) );
nrows = takeInInt( "Enter number of rows in matrix: " );
ncols = takeInInt( "Enter number of cols in matrix: " );
puts( "\nGet matrix ..." );
inputMatrix( &cvcv, nrows, ncols );
puts( "\nShowing matrix ..." );
showCvecOfCvec( &cvcv );
puts( "\nTesting 'getCvecAt' and 'setValAt' ... " );
for( ;; )
{
puts( "\nEnter matrix row and col to change ..." );
nr = takeInInt( "Enter row: " );
nc = takeInInt( "Enter col: " );
if( nr > 0 && nr <= nrows && nc > 0 && nc <= ncols ) break;
printf( "ERROR ... row %d, col %d out of bounds ...", nr, nc );
}
printf( "Enter new value to put at row %d, column %d: ", nr, nc );
nVal = readLine( stdin );
p_cv = getCvecAt( &cvcv, nr-1 );
setValAt( p_cv, nc-1, nVal );
puts( "\nShowing changed matrix ..." );
showCvecOfCvec( &cvcv );
takeInChr( "Press 'Enter' to continue ..." );
clearCvec( &cvcv, destroyCvecOfRec );
}
/* test3_Clist2.h.c */ /* 2015-06-16 */
/* http://developers-heaven.net/forum/index.php/topic,46.0.html */
/* testing a Clist of Clist... (A MATRIX) ... using the new file "Clist2.h" ... */
#define debug_dwClist2_H 1 /* change 1 to 0 to turn off debugging here ... */
#include "Clist2.h"
typedef struct myRec
{
char* str;
} Rec ;
void destroyRec( void* el ) /* re. function pointer */
{
Rec* rc = (Rec*) el;
#if debug_dwClist2_H
printf( "destroyRec called ... freeing string at %p\n", rc->str );
#endif
free( rc->str );
}
typedef struct myListOfRec
{
Clist cl ;
} ClistOfRec ;
void destroyClistOfRec( void* el ) /* re. function pointer */
{
Clist* cl = (Clist*) el;
#if debug_dwClist2_H
printf( "\ndestroyClistOfRec called to destroy Clist* at %p\n", (void*)cl );
#endif
clearClist( cl, destroyRec );
}
int takeInChr( const char* msg );
int takeInInt( const char* prompt );
void takeInClistNumElem(Clist *cl, int num );
void showRec( const void* el );
void showClist( const Clist* cl );
void showClistOfClist( Clist* cl );
void testClist();
void inputMatrix( Clist* clcl, int nrows, int ncols );
void testMatrix();
char* getValAt( const Clist* cl, int i );
void setClistAt( Clist* cl, int i, char* val );
Clist* getClistAt( Clist* cl, int i );
int main() /* ****************** BEGIN MAIN ********************************* */
{
testClist();
putchar( '\n' );
testMatrix();
fputs( "\nPress 'Enter' to continue/exit ... ", stdout); fflush( stdout );
getchar(); /* keep 'Window' open until 'Enter' key is pressed ... */
return 0;
} /* **************************** END MAIN ********************************** */
int takeInChr( const char* msg )
{
int reply;
fputs( msg, stdout ); fflush( stdout );
reply = getchar();
if( reply != '\n' ) while( getchar() != '\n' ) ; /* 'flush' stdin */
return toupper( reply );
}
int takeInInt( const char* prompt )
{
for( ; ; ) /* an example of a C/C++ forever loop ... until 'return' */
{
int val;
fputs( prompt, stdout ); fflush( stdout );
if( fscanf( stdin, "%d", &val ) == 1 && getchar() == '\n' )
return val;
/*else ...*/
while( getchar() != '\n' ); /* 'flush' stdin ... as we go ... */
puts( "Invalid input! Integers only please ..." );
}
}
void takeInClistNumElem( Clist* cl, int num )
{
int i;
for( i = 0; i < num; ++ i )
{
Rec* tmp = (Rec*)newMem( sizeof(Rec) );
Node* p = (Node*)newMem( sizeof(Node) );
printf( "Enter Clist C string %02d: ", i+1 );
tmp->str = readLine( stdin );
p->data = tmp;
push_backClist( cl, p );
}
}
void showRec( const void* el )
{
const Rec* rc = (const Rec*) el;
printf( "%s", rc->str );
}
void showClist( const Clist* cl )
{
Node* i;
for( i = cl->start; i != NULL; i = i->next )
{
showRec( i->data ); putchar( ' ' );
}
}
void showClistOfClist( Clist* cl )
{
Node* i;
int j = 0;
for( i = cl->start; i != NULL; i = i->next )
{
printf( "Row %2d: ", ++j );
showClist( i->data );
putchar( '\n' );
}
}
void testClist()
{
Clist cl;
initClist( &cl );
do
{
int i,
num = takeInInt( "Enter number of elements for this list: " );
takeInClistNumElem( &cl, num );
showClist( &cl ); putchar( '\n' );
for( i = 0; i < cl.size; ++i )
{
printf( "v(%d) = %s ", i+1, getValAt( &cl, i ) );
}
putchar( '\n' );
clearClist( &cl, destroyRec );
}
while( tolower( takeInChr( "More (y/n) ? " )) != 'n' );
}
void inputMatrix( Clist* clcl, int nrows, int ncols )
{
int i;
for( i = 0; i < nrows; ++i )
{
Clist* cl = (Clist*)newMem( sizeof(Clist));
Node* p = (Node*)newMem( sizeof(Node) );
initClist( cl );
printf( "For row %d:\n", i+1 );
takeInClistNumElem( cl, ncols );
p->data = cl;
push_backClist( clcl, p );
}
}
char* getValAt( const Clist* cl, int i )
{
if( i >= 0 && i < cl->size )
{
int j;
Node* cur;
for( j = 0, cur = cl->start; cur != NULL; ++j, cur = cur->next )
if( j == i ) return ((Rec*)(cur->data))->str;
}
/* else */
printf( "Index %d out of valid range 0 to %d, returning 0.0", i, cl->size );
return 0;
}
void setClistAt( Clist* cl, int i, char* val )
{
if( i >= 0 && i < cl->size )
{
int j;
Node* cur;
for( j = 0, cur = cl->start; cur != NULL; ++j, cur = cur->next )
{
if( j == i )
{
Rec* pr =(Rec*)cur->data;
free( pr->str );
pr->str = newCopy( val );
return;
}
}
}
/* else */
printf( "Index %d out of valid range 0 to %d, returning 0.0", i, cl->size );
}
Clist* getClistAt( Clist* cl, int i )
{
if( i < cl->size )
{
int j;
Node* cur;
for( j = 0, cur = cl->start; cur != NULL; ++j, cur = cur->next )
{
if( j == i ) return (Clist*)(cur->data);
}
}
/* else */
printf( "Index %d out of valid range 0 to %d, returning NULL", i, cl->size );
return NULL ;
}
void testMatrix()
{
char* nVal;
int nrows, ncols, nr, nc;
Clist* p_cl;
Clist clcl;
initClist( &clcl );
nrows = takeInInt( "Enter number of rows in matrix: " );
ncols = takeInInt( "Enter number of cols in matrix: " );
puts( "\nGet matrix ..." );
inputMatrix( &clcl, nrows, ncols );
puts( "\nMatrix:" );
showClistOfClist( &clcl );
puts( "\nTesting 'getClistAt' and 'setClistAt' ... " );
for( ;; )
{
puts( "\nEnter matrix row and col to change ..." );
nr = takeInInt( "Enter row: " );
nc = takeInInt( "Enter col: " );
if( nr > 0 && nr <= nrows && nc > 0 && nc <= ncols ) break;
printf( "ERROR ... row %d, col %d out of bounds ...", nr, nc );
}
printf( "Enter new value to put at row %d, column %d: ", nr, nc );
nVal = readLine( stdin );
p_cl = getClistAt( &clcl, nr-1 );
setClistAt( p_cl, nc-1, nVal );
puts( "\nShowing changed matrix ..." );
showClistOfClist( &clcl );
takeInChr( "Press 'Enter' to continue ..." );
clearClist( &clcl, destroyClistOfRec );
}