Author Topic: Beyond Beginning Computer Programming in C ...  (Read 2620 times)

Offline David

  • Sr. Member
  • ****
  • Posts: 454
    • View Profile
Beyond Beginning Computer Programming in C ...
« on: April 02, 2012, 02:15:52 AM »


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 2014-08-07 */

/*  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( 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 (*freeVrec) (void* el) )
{
    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 )
    {
        clearCvec( cv, freeVrec );
        myAssert( 0, "Error: realloc failed in enlargeCvec..." );
    }
    /* else ... */
    cv->ary = tmp; /* update the base address of cv->ary */
}


void reserveCvec( Cvec* cv, int newCap, void (*freeVrec) (void* el) )
{
    if( newCap > cv->cap )
    {
        void* tmp;
        cv->cap = newCap;
        tmp = realloc( cv->ary, cv->cap * cv->elen );
        if( tmp == NULL )
        {
            clearCvec( cv, freeVrec );
            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, void (*freeVrec) (void* el) )
{
    if( cv->size == cv->cap ) enlargeCvec( cv, freeVrec );
    /* now add in new Rec ... */
    memcpy( (cv->ary + cv->size*cv->elen), el, cv->elen );
    /*
    cv->ary[cv->size].name = rc->name;
    cv->ary[cv->size].address = rc->address;
    cv->ary[cv->size].phone = rc->phone;
    */
    ++ cv->size;
}

#endif

/*

typedef struct myRec
{
    char* name;
    int id;
} Rec ;


void freeVrec( void* el )
{
    Rec* p = (Rec*) el;
    free( p->name );
}

typedef struct myRec2
{
    char* fname;
    char* lname;
    int id;
} Rec2 ;


void freeVrec2( void* el )
{
    Rec2* p = (Rec2*) el;
    free( p->lname );
    free( p->fname );
}


void showStudent( const void* ss )
{
    Rec* s = (Rec*) ss;
    printf( "%s %d", s->name, s->id );
}
void showCvec( const Cvec* s )
{
    int i;
    for( i = 0; i < s->size; ++i )
        { showStudent( s->ary + i*s->elen ); putchar( '\n' ); }
}

void showStudent2( const void* ss )
{
    Rec2* s = (Rec2*) ss;
    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( s->ary + i*s->elen ); putchar( '\n' ); }
}

*/


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

Code: [Select]
/* Cvec2_func's.h */  /* 2014-08-07 */

/*  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( (cv->ary + h1*cv->elen), (cv->ary + h2*cv->elen) ) <= 0  )
            memcpy( (tmp->ary + cv->elen*j++), (cv->ary + cv->elen*h1++), cv->elen );
            /* tmp->ary[j++] = cv->ary[h1++]; */
        else
            memcpy( (tmp->ary + cv->elen*j++), (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( (tmp->ary + cv->elen*j++), (cv->ary + cv->elen*h1++), cv->elen );
        /* tmp->ary[j++] = cv->ary[h1++]; */
    while( h2 <= top ) /* copy any remaining entries (2nd half) */
        memcpy( (tmp->ary + cv->elen*j++), (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( (cv->ary +(bot+j)*cv->elen), (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),
                void (*freeVrec) (void* el) )
{
    if( cv->size > 1 )
    {
        Cvec tmp;
        initCvec( &tmp, cv->elen );
        reserveCvec( &tmp, cv->size, freeVrec ); /* 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, (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, (cv->ary+cv->elen*j)) < 0 )
        {
            memcpy( (cv->ary + cv->elen*(j+1)), (cv->ary + cv->elen*j), cv->elen ); /* copy pointer 'up' ... */
            --j; /* decrement j in preparation for next inner loop ... */
        }
        memcpy( (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( const Cvec* cv, int (*myCmp) (const void* a, const void* b) )
{
    int size = cv->size;
    while( --size )
        if( myCmp( (cv->ary + cv->elen*(size)), (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, freeVrec ); /* first make sure, name-sorted order by case */

    for( ; j < cv->size ; ++j )
    {
        if( myCmp( (cv->ary + cv->elen*i), (cv->ary + cv->elen*j) ) != 0 )
        {
            ++i;
            if( i != j ) memcpy( (cv->ary + cv->elen*i), (cv->ary + cv->elen*j),
                                  cv->elen );
        }
        else freeVrec( cv->ary + cv->elen*j );
    }

    cv->size = ++i;
}
int isUniqueCvec( Cvec* cv, int (*myCmp) (const void* a, const void* b),
                  void (*freeVrec) (void* el) )
{
    int i;
    if( !isSortedCvec( cv, myCmp ) )
        msortCvec( cv, myCmp, freeVrec );

    for( i = cv->size-1; i > 0; --i )
        if( myCmp( (cv->ary + cv->elen*i), (cv->ary + cv->elen*(i-1)) ) == 0 )
            return 0;
    /* else ... */
    return 1;
}

/* returns index if string present, else -1 */
int findCvec( const Cvec* cv, const void* rec, int (*myCmp) (const void* a, const void* b) )
{
    int i;
    for( i = 0; i < cv->size; ++i )
        if( myCmp( (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( 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( (cv->ary + cv->elen*index), (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
« Last Edit: August 08, 2014, 10:05:45 AM by David »

Offline David

  • Sr. Member
  • ****
  • Posts: 454
    • View Profile
Re: Beyond Beginning Computer Programming in C ...
« Reply #1 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: 2014-08-07 */

/*  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;
} Rec ;
void freeVrec( void* el )
{
    Rec* p = (Rec*) el;
    free( p->name );
}

/* sorts by name ... if names the same, then sorts by id ... */
int cmpNameIdRec( const void* a, const void* b )
{
    const Rec* aa = (const Rec*)a;
    const Rec* bb = (const Rec*)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 cmpIdRec( const void* a, const void* b )
{
    const Rec* aa = (const Rec*)a;
    const Rec* bb = (const Rec*)b;
    return aa->id - bb->id;
}

typedef struct Student2
{
    char* fname;
    char* lname;
    int id;
} Rec2 ;

void freeVrec2( void* el )
{
    Rec2* p = (Rec2*) 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 cmp2NameIdRec( const void* a, const void* b )
{
    const Rec2* aa = (const Rec2*)a;
    const Rec2* bb = (const Rec2*)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 cmpIdRec2( const void* a, const void* b )
{
    const Rec2* aa = (const Rec2*)a;
    const Rec2* bb = (const Rec2*)b;
    return aa->id - bb->id;
}

int takeInChr( const char* msg );
int takeInValidInt( const char* prompt );

void inputStudent( Rec* s );
void showStudent( const void* ss );
void showCvec( const Cvec* s );

void inputStudent2( Rec2* s );
void showStudent2( const void* ss, FILE*, int );
void showCvec2( const Cvec* s, FILE*, int  );

void testRec();

int fillFromFile( Cvec* cv, void (*freeVrec) (void* el) );
void testRec2();





int main() /* ********************** BEGIN MAIN ***************************** */
{
    puts( "Testing Student ..." );
    testRec();
   
    puts( "\nTesting Student2 ..." );
    testRec2();
   
    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;
}

void inputStudent( Rec* s )
{
    for( ; ; )
    {
        s->id = takeInValidInt( "Enter id number : " );

        fputs( "Enter name : ", stdout ); fflush( stdout );
        s->name = readLine( stdin );

        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( Rec2* s )
{
    for( ; ; )
    {
        s->id = takeInValidInt( "Enter id number : " );

        fputs( "Enter first name : ", stdout ); fflush( stdout );
        s->fname = readLine( stdin );
       
        fputs( "Enter last name : ", stdout ); fflush( stdout );
        s->lname = readLine( stdin );

        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 void* ss )
{
    Rec* s = (Rec*) ss;
    printf( "Name: %s, ID: %d", s->name, s->id );
}
void showCvec( const Cvec* s )
{
    int i;
    for( i = 0; i < s->size; ++i )
        { showStudent( s->ary + i*s->elen ); putchar( '\n' ); }
    printf( "size = %d, cap = %d\n", s->size, s->cap );
}

void showStudent2( const void* ss, FILE* fp, int fileOut )
{
    Rec2* s = (Rec2*) ss;
    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( s->ary + i*s->elen, fp, fileOut );
        if( !fileOut )
        {
            putchar( '\n' );
            if( s->size-1 == i )
                printf( "size = %d, cap = %d\n",
                        s->size, s->cap );
        }
    }
}

void testRec()
{
    Cvec cv;
    Rec rTmp;
    int index;
    initCvec( &cv, sizeof(Rec) );
    do
    {
        inputStudent( &rTmp );
        index = findCvec( &cv, &rTmp, cmpIdRec ) ;
        /* printf( "Found index was %d\n", index ); */
        if( index == -1 )
        {
            push_backCvec( &cv, (void*)&rTmp, freeVrec );
            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, cmpNameIdRec, freeVrec );
    puts( "\nAfter calling msort ... the vector now is ..." );
    showCvec( &cv );
    clearCvec( &cv, freeVrec );
}


int fillFromFile( Cvec* cv, void (*freeVrec) (void* el) )
{
    FILE* fin = fopen( FNAME, "r" );
    if( fin )
    {
        Rec2 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, freeVrec );
        }
        fclose( fin );
        return 1;
    }
    else
    {
        printf( "There was a problem opening file %s to read.\n", FNAME );
        return 0;
    }
}

void testRec2()
{
    FILE* fp;
    int index = 0;
    Cvec cv;
    Rec2 rTmp;


    initCvec( &cv, sizeof(Rec2) );
    reserveCvec( &cv, 2, freeVrec2 );
   
    /* get theses records into first positions ... */
    rTmp.id    = 123;
    rTmp.fname = newCopy( "Ab");
    rTmp.lname = newCopy( "Lane");
    push_backCvec( &cv, (void*)&rTmp, freeVrec2 );
   
    rTmp.id    = 124;
    rTmp.fname = newCopy( "Bob");
    rTmp.lname = newCopy( "Lane");
    push_backCvec( &cv, (void*)&rTmp, freeVrec2 );
   
    rTmp.id    = 125;
    rTmp.fname = newCopy( "Bob");
    rTmp.lname = newCopy( "Laine");
    push_backCvec( &cv, (void*)&rTmp, freeVrec2 );
   
    rTmp.id    = 123;
    rTmp.fname = newCopy( "Ab");
    rTmp.lname = newCopy( "Lane");
    push_backCvec( &cv, (void*)&rTmp, freeVrec2 );
   
    do
    {
        inputStudent2( &rTmp );
        index = findCvec( &cv, &rTmp, cmpIdRec2 ) ;
        if( index == -1 )
        {
            push_backCvec( &cv, (void*)&rTmp, freeVrec2 );
            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, cmp2NameIdRec );
    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, freeVrec2 );
    takeInChr( "\nPress 'Enter' to continue ... " );


    printf( "\nFilling from file %s ... \n", FNAME );
    if( fillFromFile( &cv, freeVrec2 ) )
    {
        /* form a record to search/erase ... */
        Rec2* p = (Rec2*) newMem( sizeof(Rec2) );
        p->id = 124;
        p->fname = newCopy("Bob");
        p->lname = newCopy("Lane");
       
        showCvec2( &cv, stdout, 0 );

        printf( "\nis sorted = %d", isSortedCvec( &cv, cmp2NameIdRec ) );
        printf( "\nis unique = %d\n", isUniqueCvec( &cv, cmp2NameIdRec, freeVrec2 ) );

        /* 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, cmp2NameIdRec );
        if( index != -1 )
            eraseCvec( &cv, index, freeVrec2 );
        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, freeVrec2 );
            showCvec2( &cv, stdout, 0 );
        }
        freeVrec2( p );
        free( p );

        takeInChr( "\nPress 'Enter' to continue ... " );


        printf( "\nunique file %s ... \n", FNAME );
        uniqueCvec( &cv, cmp2NameIdRec, freeVrec2 );
        showCvec2( &cv, stdout, 0 );
        printf( "\nis sorted = %d", isSortedCvec( &cv, cmp2NameIdRec ) );
        printf( "\nis unique = %d\n", isUniqueCvec( &cv, cmp2NameIdRec, freeVrec2 ) );

        clearCvec( &cv, freeVrec2 );
    }
}
« Last Edit: August 08, 2014, 10:07:09 AM by David »

Offline David

  • Sr. Member
  • ****
  • Posts: 454
    • View Profile
Re: Beyond Beginning Computer Programming in C ...
« Reply #2 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 */ /* 2012-03-29 */

/*  http://developers-heaven.net/forum/index.php/topic,46.0.html  */

/*
    To USE ... you will need to define / 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* pList;


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", 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

/*

typedef struct myRec
{
    char* name;
    int id;
} Rec ;

void clearLrec( void* el )
{
    Rec* p = (Rec*) el;
    free( p->name );
    free ( p );
}

void showStudent( const void* ss )
{
    const Rec* s = (const Rec*) ss;
    printf( "Name: %s, ID: %d", 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 );
}



typedef struct myRec2
{
    char* fname;
    char* lname;
    int id;
} Rec2 ;

void clearLrec2( void* el )
{
    Rec2* p = (Rec2*) el;
    free( p->lname );
    free( p->fname );
    free ( p );
}

void showStudent2( const void* ss )
{
    const Rec2* s = (const Rec2*) ss;
    printf( "Last, First: %s, %s, ID: %d", 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 );
}

*/


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

Code: [Select]
/* Clist2_func's.h */ /* 2012-03-29 */

/*  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( 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( 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( 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", 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( 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", 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 */
        ++ list->size;
    }
    else /* if we reach here, this IS the first node ... */
    {
        n->next = head;     /* so set this node in first position */
        list->start = n;
        ++ list->size;
        if( list->size == 1 ) list->end = n;
    }
}

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
« Last Edit: April 02, 2012, 05:34:18 AM by David »

Offline David

  • Sr. Member
  • ****
  • Posts: 454
    • View Profile
Re: Beyond Beginning Computer Programming in C ...
« Reply #3 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 */ /* 2012-03-29 */

/*  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 "stud2.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 myRec
{
    char* name;
    int id;
} Rec ;
void clearLrec( void* el ) /* Rec dtor called via using function pointors ... */
{
    Rec* p = (Rec*) el;
    free( p->name );
#if debug_dwClist2_H
    printf( "Inside clearLrec at free Rec* p = %p\n", p );
#endif
}
void showStudent( const void* ss )
{
    const Rec* s = (const Rec*) ss;
    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 cmpNameIdRec( pList aa, pList bb ) /* Rec cmp via function pointers */
{
    Rec* a = (Rec*)aa->data;
    Rec* b = (Rec*)bb->data;
    int t = strcmp( a->name, b->name );
    if( t == 0 ) return a->id - b->id;
    return t;
}


/* 2nd example record has 3 fields; note: 2 fields use dynamic memory */
/* ****************************************************************** */
typedef struct myRec2
{
    char* fname;
    char* lname;
    int id;
} Rec2 ;
void clearLrec2( void* el )  /* Rec2 dtor via using function pointors ... */
{
    Rec2* p = (Rec2*) el;
    free( p->lname );
    free( p->fname );
#if debug_dwClist2_H
    printf( "Inside clearLrec2 at free Rec* p = %p\n", p );
#endif
}
void showStudent2( const void* ss )
{
    const Rec2* s = (const Rec2*) 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 cmp2NameIdRec( pList a, pList b ) /* Rec2 cmp via function pointers */
{
    const Rec2* aa = (Rec2*)a->data;
    const Rec2* bb = (Rec2*)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;
}


void inputStudent( Rec* );
void inputStudent2( Rec2* );

int getCharReply( const char* msg );
int getValidInt( const char* prompt );


void testList() /* testing Clist of Rec: push_back, isort, show, clear... */
{
    Clist cl;
    initClist( &cl );
   
    do
    {
        Rec* tmp = (Rec*)newMem( sizeof(Rec) );
        Node* p = (Node*)newMem( sizeof(Node) );
        inputStudent( tmp );
        p->data = tmp;
        push_backClist( &cl, p );
        puts( "\nList now is ..." );
        showClist( &cl );
    }
    while( getCharReply( "More (y/n) ? " ) != 'N' );
   
    puts( "\nShowing isorted ..." );
    isortClist( &cl, cmpNameIdRec );
    showClist( &cl );
    clearClist( &cl, clearLrec );
}

int fillFromFile( Clist* cl  ) /* testing Clist of Rec2 from file ... */
{
    FILE* fin = fopen( FNAME, "r" );
    if( fin )
    {
        Rec2 r;
        char* line;
        while
        (
            (r.fname = readLine( fin )) &&
            (r.lname = readLine( fin )) &&
            (line = readLine( fin ))
        )
        {
            Rec2* tmp = (Rec2*)newMem( sizeof(Rec2) );
            Node* p = (Node*)newMem( sizeof(Node) );
            r.id = atoi( line );
            free( line );
            memcpy( tmp, &r, sizeof(Rec2) );
            p->data = tmp;
            push_backClist( cl, p );
        }
        fclose( fin );
        return 1;
    }
    else
    {
        printf( "There was a problem opening file %s to read.\n", FNAME );
        return 0;
    }
}

/* testing Clist of Rec2: push_front, msort, show, clear, find, erase, unique... */
void testList2()
{
    Clist cl;
    pList index;
    /* get a copy of a record in the file to search/erase ... */
    Node* n = (Node*)newMem( sizeof(Node) );
    Rec2* r = (Rec2*)newMem( sizeof(Rec2) );
    r->fname = newCopy("Bob");
    r->lname = newCopy("Lane");
    r->id = 234;
    n->data = r;
   
    initClist( &cl );
    do
    {
        Rec2* tmp = (Rec2*)newMem( sizeof(Rec2) );
        Node* p = (Node*)newMem( sizeof(Node) );
        inputStudent2( tmp );
        p->data = tmp;
        push_backClist( &cl, p );
        puts( "\nList now is ..." );
        showClist2( &cl );
    }
    while( getCharReply( "More (y/n) ? " ) != 'N' );
   
    puts( "\nShowing msorted ..." );
    msortClist( &cl, cmp2NameIdRec );
    showClist2( &cl );
    clearClist( &cl, clearLrec2 );
   
    getCharReply( "\nPress 'Enter' to continue ... " );
   
   
    printf( "\nFilling from file %s ... \n", FNAME );
    if( fillFromFile( &cl ) )
    {
        showClist2( &cl );
        printf( "\nis sorted = %d", isSortedClist( &cl, cmp2NameIdRec ) );
        printf( "\nis unique = %d\n", isUniqueClist( &cl, cmp2NameIdRec ) );

        getCharReply( "\nPress 'Enter' to continue ... " );


        puts( "\nShowing student to find ... and erase ..." );
        showStudent2( r ); putchar( '\n' );
        index = findClist( &cl, n, cmp2NameIdRec );
        if( index  )
            eraseClist( &cl, index, clearLrec2 );

        printf( "\nAfter erasing 3 Nodes ...\n" );
        eraseClist( &cl, cl.start, clearLrec2 );
        eraseClist( &cl, cl.end, clearLrec2 );
        showClist2( &cl );


        getCharReply( "\nPress 'Enter' to continue ... " );


        printf( "\nunique file %s ... \n", FNAME );
        uniqueClist( &cl, cmp2NameIdRec, clearLrec );
        showClist2( &cl );
        printf( "\nis sorted = %d", isSortedClist( &cl, cmp2NameIdRec ) );
        printf( "\nis unique = %d\n", isUniqueClist( &cl, cmp2NameIdRec ) );

        clearClist( &cl, clearLrec2 );
    }

    clearLrec2( r ); /* also frees r ... */
    free( n );
}




int main() /* ********************* BEGIN MAIN ****************************** */
{
    puts( "Testing Student ..." );
    testList();
   
    puts( "\nTesting Student2 ..." );
    testList2();

    getCharReply( "\nPress 'Enter' to continue/exit ... " );
    return 0;
} /* ******************************* END MAIN ********-********************** */




int getCharReply( const char* msg )
{
    int reply;
    fputs( msg, stdout );  fflush( stdout );
    reply = getchar();
    if( reply != '\n' ) while( getchar() != '\n' ) ; /* 'flush' stdin  */
    return toupper( reply );
}

int getValidInt( 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 inputStudent( Rec* s )
{
    for( ;; )
    {
        s->id = getValidInt( "Enter id number : " );

        fputs( "Enter name : ", stdout ); fflush( stdout );
        s->name = readLine( stdin );

        printf( "You entered: %s :: %d\n", s->name, s->id );

        if( toupper( getCharReply( "Is this entry ok (y/n) ? ") == 'Y' ) )
            break;
        /* else ... */
        free( s->name );
        puts( "Ok ... this entry aborted ... try again ... " );
    }
}

void inputStudent2( Rec2* s )
{
    for( ;; )
    {
        s->id = getValidInt( "Enter id number : " );

        fputs( "Enter first name : ", stdout ); fflush( stdout );
        s->fname = readLine( stdin );
       
        fputs( "Enter last name : ", stdout ); fflush( stdout );
        s->lname = readLine( stdin );

        printf( "You entered: %s, %s :: %d\n", s->lname, s->fname, s->id );

        if( toupper( getCharReply( "Is this entry ok (y/n) ? ") == 'Y' ) )
            break;
        /* else ... */
        free( s->lname );
        free( s->fname );
        puts( "Ok ... this entry aborted ... try again ... " );
    }
}

// "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
*/
« Last Edit: April 17, 2012, 03:09:16 AM by David »

Offline David

  • Sr. Member
  • ****
  • Posts: 454
    • View Profile
Re: Beyond Beginning Computer Programming in C ...
« Reply #4 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 */ /* 2012-03-29 */

/* 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* cv = %p\n", cv );
#endif
    clearCvec( cv, destroyRec );
}


int getCharReply( const char* msg );
int getValidInt( const char* prompt );
double getValidDbl( const char* prompt );

void inputCvecNumElem(Cvec *cv, int num );
void showRec( const void* el );
void showCvec( const Cvec* cv );
void showCvecOfCvec( Cvec* cv );

void testCvec();

void inputMatrix( 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* 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 getCharReply( const char* msg )
{
    int reply;
    fputs( msg, stdout );  fflush( stdout );
    reply = getchar();
    if( reply != '\n' ) while( getchar() != '\n' ) ; /* 'flush' stdin  */
    return toupper( reply );
}

int getValidInt( 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 ..." );
    }
}
double getValidDbl( const char* prompt )
{
    int numGood;
    for( ; ; ) /* an example of a C/C++ forever loop ... until 'return' */
    {
        double test;
        fputs( prompt, stdout ); fflush( stdout );
        numGood = fscanf( stdin, "%lf", &test );
        while( getchar() != '\n' ); /* 'flush' stdin ... as we go ... */
        if( numGood == 1 ) return test;
        /*else ...*/
        puts( "Invalid input! Integers only please ..." );
    }
}

void inputCvecNumElem( Cvec* cv, int num )
{
    int i;
    reserveCvec( cv, num, destroyRec );
    for( i = 0; i < num; ++ i )
    {
        Rec r;           /*1234567890123456789*/
        char prompt[32] = "Enter Cvec element ";
        sprintf( prompt+19, "%02d: ", i+1 );
        r.d = getValidDbl( prompt );
        push_backCvec( cv, &r, destroyRec );
    }
}

void showRec( const void* el )
{
    const Rec* rc = (const Rec*) el;
    printf( "%f", rc->d );
}
void showCvec( const Cvec* cv )
{
    int i;
    for( i = 0; i < cv->size; ++ i )
    {
        showRec( cv->ary + i*cv->elen ); putchar( ' ' );
    }
}
void showCvecOfCvec( Cvec* cv )
{
    int i;
    for( i = 0; i < cv->size; ++i )
    {
        printf( "Row %2d: ", i+1 );
        showCvec( cv->ary + i*cv->elen );
        putchar( '\n' );
    }
}

void testCvec()
{
    Cvec cv;
    initCvec( &cv, sizeof(Rec) );
    do
    {
        int i, num = getValidInt( "Enter number of elements for this vector: " );
        inputCvecNumElem( &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( getCharReply( "More (y/n) ? " ) != 'N' );
}

void inputMatrix( Cvec* cvcv, int nrows, int ncols )
{
    int i;
    reserveCvec( cvcv, nrows, destroyCvecOfRec );
    for( i = 0; i < nrows; ++i )
    {
        Cvec cv;
        initCvec( &cv, sizeof(Rec) );
        reserveCvec( &cv, ncols, destroyRec );
        printf( "For row %d:\n", i+1 );
        inputCvecNumElem( &cv, ncols );
        push_backCvec( cvcv, &cv, destroyCvecOfRec );
    }
}

void initialMatrix( Cvec* cvcv, int nrows, int ncols )
{
    int i, j;
    reserveCvec( cvcv, nrows, destroyCvecOfRec );
    for( i = 0; i < nrows; ++i )
    {
        Cvec cv;
        Rec r;
        r.d = 0.0;
        initCvec( &cv, sizeof(Rec) );
        reserveCvec( &cv, ncols, destroyRec );
        for( j = 0; j < ncols; ++j ) push_backCvec( &cv, &r, destroyRec );
        push_backCvec( cvcv, &cv, destroyCvecOfRec );
    }
}



double getValAt( const Cvec* cv, int i )
{
    return *(double*)(cv->ary + i*cv->elen);
}

void setValAt( Cvec* cv, int i, double val )
{
    *(double*)(cv->ary + i*cv->elen) = val;
}

Cvec* getCvecAt( Cvec* cv, int i )
{
    return cv->ary + i*cv->elen ;
}

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 = getValidInt( "Enter number of rows in matrix: " );
    ncols = getValidInt( "Enter number of cols in matrix: " );

    puts( "\nGet matrix 1 ..." );
    inputMatrix( &cvcv, nrows, ncols );
   
    puts( "\nGet matrix 2 ..." );
    inputMatrix( &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 );
   
    getCharReply( "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 */ /* 2012-03-29 */

/* 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* cl = %p\n", cl );
#endif
    clearClist( cl, destroyRec );
}


int getCharReply( const char* msg );
int getValidInt( const char* prompt );
double getValidDbl( const char* prompt );

void inputClistNumElem(Clist *cl, int num );
void showRec( const void* el );
void showClist( const Clist* cl );
void showClistOfClist( Clist* cl );

void testClist();

void initialMatrix( Clist* clcl, int nrows, int ncols );
void inputMatrix( 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( 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 getCharReply( const char* msg )
{
    int reply;
    fputs( msg, stdout );  fflush( stdout );
    reply = getchar();
    if( reply != '\n' ) while( getchar() != '\n' ) ; /* 'flush' stdin  */
    return toupper( reply );
}

int getValidInt( 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 ..." );
    }
}
double getValidDbl( const char* prompt )
{
    int numGood;
    for( ; ; ) /* an example of a C/C++ forever loop ... until 'return' */
    {
        double test;
        fputs( prompt, stdout ); fflush( stdout );
        numGood = fscanf( stdin, "%lf", &test );
        while( getchar() != '\n' ); /* 'flush' stdin ... as we go ... */
        if( numGood == 1 ) return test;
        /*else ...*/
        puts( "Invalid input! Integers only please ..." );
    }
}

void inputClistNumElem( Clist* cl, int num )
{
    int i;
    for( i = 0; i < num; ++ i )
    {
        Rec* tmp = (Rec*)newMem( sizeof(Rec) );
        Node* p = (Node*)newMem( sizeof(Node) );
       
        /*                 12345678901234567890 */
        char prompt[32] = "Enter Clist element ";
        sprintf( prompt+20, "%02d: ", i+1 );
       
        tmp->d = getValidDbl( 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 )
{
    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 = getValidInt( "Enter number of elements for this list: " );
        inputClistNumElem( &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( getCharReply( "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 );
        inputClistNumElem( 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));
        Node* pi = (Node*)newMem( sizeof(Node) );
        initClist( cl );
        for( j = 0; j < ncols; ++j )
        {
            Rec* rc = (Rec*)newMem( sizeof(Rec));
            Node* pj = (Node*)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;
        Node* 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;
        Node* 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( 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 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 = getValidInt( "Enter number of rows in matrix: " );
    ncols = getValidInt( "Enter number of cols in matrix: " );

    puts( "\nGet matrix 1 ..." );
    inputMatrix( &clcl, nrows, ncols );
   
    puts( "\nGet matrix 2 ..." );
    inputMatrix( &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 );

    getCharReply( "Press 'Enter' to continue ..." );
   
   
    clearClist( &clcl3, destroyClistOfRec );
    clearClist( &clcl2, destroyClistOfRec );
    clearClist( &clcl,  destroyClistOfRec );
}


« Last Edit: April 17, 2012, 04:50:38 AM by David »

Offline David

  • Sr. Member
  • ****
  • Posts: 454
    • View Profile
Re: Beyond Beginning Computer Programming in C ...
« Reply #5 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 */ /* 2012-03-29 */

/* 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* cv = %p\n", cv );
#endif
    clearCvec( cv, destroyRec );
}


int getCharReply( const char* msg );
int getValidInt( const char* prompt );
double getValidDbl( const char* prompt );

void inputCvecNumElem(Cvec *cv, int num );
void showRec( const void* el );
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 getCharReply( const char* msg )
{
    int reply;
    fputs( msg, stdout );  fflush( stdout );
    reply = getchar();
    if( reply != '\n' ) while( getchar() != '\n' ) ; /* 'flush' stdin  */
    return toupper( reply );
}

int getValidInt( 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 inputCvecNumElem( Cvec* cv, int num )
{
    int i;
    reserveCvec( cv, num, destroyRec );
    for( i = 0; i < num; ++ i )
    {
        Rec r;
        printf( "Enter Cvec C string %02d: ", i+1 );
        r.str = readLine( stdin );
        push_backCvec( cv, &r, destroyRec );
    }
}

void showRec( const void* el )
{
    const Rec* rc = (const Rec*) el;
    printf( "%s", rc->str );
}
void showCvec( const Cvec* cv )
{
    int i;
    for( i = 0; i < cv->size; ++ i )
    {
        showRec( cv->ary + i*cv->elen ); putchar( ' ' );
    }
}
void showCvecOfCvec( Cvec* cv )
{
    int i;
    for( i = 0; i < cv->size; ++i )
    {
        printf( "Row %2d: ", i+1 );
        showCvec( cv->ary + i*cv->elen );
        putchar( '\n' );
    }
}

void testCvec()
{
    Cvec cv;
    initCvec( &cv, sizeof(Rec) );
    do
    {
        int i, num = getValidInt( "Enter number of elements for this vector: " );
        inputCvecNumElem( &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( getCharReply( "More (y/n) ? " ) != 'N' );
}

void inputMatrix( Cvec* cvcv, int nrows, int ncols )
{
    int i;
    reserveCvec( cvcv, nrows, destroyCvecOfRec );
    for( i = 0; i < nrows; ++i )
    {
        Cvec cv;
        initCvec( &cv, sizeof(Rec) );
        reserveCvec( &cv, ncols, destroyRec );
        printf( "For row %d:\n", i+1 );
        inputCvecNumElem( &cv, ncols );
        push_backCvec( cvcv, &cv, destroyCvecOfRec );
    }
}


char* getValAt( const Cvec* cv, int i ) /* Note: only a shallow copy here ... */
{
    return ( (Rec*)(cv->ary + i*cv->elen) )->str;
}

void setValAt( Cvec* cv, int i, char* val )
{
    Rec* p = (Rec*)(cv->ary + i*cv->elen);
    free( p->str );
    p->str = newCopy( val );
}

Cvec* getCvecAt( Cvec* cv, int i )
{
    return cv->ary + i*cv->elen ;
}


void testMatrix()
{
    int nrows, ncols, nr, nc;
    char* nVal;
    void* p_cv;
    Cvec cvcv;
    initCvec( &cvcv, sizeof(CvecOfRec) );

    nrows = getValidInt( "Enter number of rows in matrix: " );
    ncols = getValidInt( "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 = getValidInt( "Enter row: " );
        nc = getValidInt( "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 );
   
    getCharReply( "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 */ /* 2012-04-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* cl = %p\n", cl );
#endif
    clearClist( cl, destroyRec );
}


int getCharReply( const char* msg );
int getValidInt( const char* prompt );


void inputClistNumElem(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 getCharReply( const char* msg )
{
    int reply;
    fputs( msg, stdout );  fflush( stdout );
    reply = getchar();
    if( reply != '\n' ) while( getchar() != '\n' ) ; /* 'flush' stdin  */
    return toupper( reply );
}

int getValidInt( 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 inputClistNumElem( 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 = getValidInt( "Enter number of elements for this list: " );
        inputClistNumElem( &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( getCharReply( "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 );
        inputClistNumElem( 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 = getValidInt( "Enter number of rows in matrix: " );
    ncols = getValidInt( "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 = getValidInt( "Enter row: " );
        nc = getValidInt( "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 );

   
    getCharReply( "Press 'Enter' to continue ..." );
   
    clearClist( &clcl,  destroyClistOfRec );
}
« Last Edit: April 17, 2012, 07:56:12 AM by David »