Developers Heaven Forum

Desktop Programming => C/C++ & Visual C++ => Topic started by: David on April 02, 2012, 02:15:52 AM

Title: Beyond Beginning Computer Programming in C ...
Post by: David on April 02, 2012, 02:15:52 AM
Update: FREE homework help NOW available ...

You can contact me via:
http://sites.google.com/site/andeveryeyeshallseehim/home/he-comes
http://developers-heaven.net/forum/index.php/board,9.0.html


These following pages will be about a way to use void pointers and function pointers in C  ... to demonstrate how they might be used together to emulate/provide the functionality in C of the C++ vector and list containers.

Previously, (see the following links),

http://developers-heaven.net/forum/index.php?topic=2580.0

http://developers-heaven.net/forum/index.php?topic=2582.0

using Cvec.h and Clist.h and function pointers, but NOT void pointers, we provided this functionality, but it was some-what limited ... limited to just one type of vector and one type of list per program ... for example ... we could not have in the same program, a vector of doubles and also a vector of an other type ... we needed to make one a list and the other a vector container.  Also, we could not have a vector of vector ... or a list of list ... only allowed then, (in the same program), was a vector of list ... or a list of vector.

But with the added use of the void pointers below, we can now accommodate, in the same program, as many types of vectors and/or lists as needed, just like in C++ ... also you now can code for a vector of vector ... or a list of list ... just like in C++

Firstly, take a look at the new Cvec2.h file and the new Cvec2_func's.h file ... also the slightly augmented files readLine.h and readWord.h, with an added function now with prototype:  char* newMem( int bytes );

Code: [Select]
/* 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' ); }
}

*/


And now the file Cvec2_func's.h ...

Code: [Select]
/* 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


Now the new readLine.h

See this link for latest version:

http://developers-heaven.net/forum/index.php/topic,2580.msg2864.html#msg2864
Title: Re: Beyond Beginning Computer Programming in C ...
Post by: David on April 02, 2012, 02:44:37 AM
And the latest version of  readWord.h

http://developers-heaven.net/forum/index.php/topic,2580.msg2864.html#msg2864

Note: readLine.h is also available at the above link.


And now a little test program ...

Code: [Select]
/* 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 );
    }
}
Title: Re: Beyond Beginning Computer Programming in C ...
Post by: David on April 02, 2012, 02:47:10 AM
And the new Clist2.h ... to provide in C ... the functionality available with the C++ STL list ...

Note: here we have opted to create the new memory for each node and each record in that node as we go ... as opposed to have that handled by our 'list class'  in Clist2.h... (as was done for the 'vector class' above in Cvec2.h) ... but the Clist will provide a function (via receiving a function pointer) to handle freeing the new dynamic list memory.

Code: [Select]
/* 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;
}

*/


And now the file Clist2_func's.h ...

Code: [Select]
/* 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
Title: Re: Beyond Beginning Computer Programming in C ...
Post by: David on April 02, 2012, 03:13:05 AM
And a little test program for this new Clist2.h Clist list ... note how we create the new memory for each node and record in that node ... 'as we go' ... in the program.


Code: [Select]
/* 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
*/
Title: Re: Beyond Beginning Computer Programming in C ...
Post by: David on April 17, 2012, 04:16:42 AM
A vector of vector of double example using Cvec2.h ... (Note: needs to include file Cvec2.h above)

Code: [Select]
/* 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 );
}


A list of list of double example ... (Note: need to include file Clist2.h above ... and ... note how we create the new memory for each node and record in that node ... 'as we go' ... in the program.)

Code: [Select]
/* 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 );
}


Title: Re: Beyond Beginning Computer Programming in C ...
Post by: David on April 17, 2012, 04:42:42 AM
A vector of vector (a matrix) of dynamic C strings ... (using Cvec2.h above)

Code: [Select]
/* 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 );
}


A list of list (a matrix) of dynamic C strings ... (Note: need to include file Clist2.h above ... and ... note how we create the new memory for each node and record in that node ... 'as we go' ... in the program.)

Code: [Select]
/* 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 );
}