Author Topic: Clist_func's.h example programs ... using FUNCTION POINTERS to facilitate reuse  (Read 42284 times)

Offline David

  • Hero Member
  • *****
  • Posts: 644
    • View Profile
Update:  please see this next link:

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

you can contact me via this link ...

https://sites.google.com/site/andeveryeyeshallseehim/

(my/editor gmail link is on the 2nd page)


Ok ... here are some example programs that use the new FUNCTION POINTERS in Clist_func's.h ...

You can download a zipped file of all the (OLD) Clist.h files you need below at this next link ...
http://www.4shared.com/account/dir/eXSprBq0/_online.html#dir=104184790

The first example demos a Clist of Rec's (a struct with 3 dynamic memory C string data items) ...
Look here for a C++ STL list version ... to compare ...
http://developers-heaven.net/forum/index.php/topic,2583.msg2890.html#msg2890

Code: [Select]
/* employeeRec's_msortClist_func's.h.c */  /* this version: 2016-10-13 */


/*
    in the following:
        a List is a Node ( struct),
        a pList (i.e. List*) holds the address of a Node
        a Clist is the struct hold ing addresses of 'start' & 'end' Nodes, etc.
        a Clist* holds the address of the struct Clist
*/

/* 'C++ list emulation' using a C Clist struct ... (see demo MENU below) */


#include "takeInLIne.h" /* also includes readLine.h, stdio.h, stdlib.h, string.h and defines
                         functions myAssert and newCopy. etc...  */

#define FILENAME "employeeRecords.txt"

#define MENU      " 1. Enter a new record. \n" \
                  " 2. Retrieve a record by name (ignore case). \n" \
                  " 3. Retrieve a record by phone number. \n" \
                  " 4. Show all records. \n" \
                  " 5. Insert sort all records by name (ignore case). \n" \
                  " 6. Insert sort all records by phone number. \n" \
                  " 7. Chop exact duplicates from records (use case). \n" \
                  " 8. Edit/Delete a record. \n" \
                  " 9. Write new file of sorted unique records. \n" \
                  "10. Exit \n"
#define PROMPT    "Enter a number in range 1 to 10 : "


typedef struct employeeRec
{
    char* name;     /* since CStrings are '\0' terminated ... can get strlen */
    char* address;  /* ditto above ... */
    char* phone;    /* 3 digit area-code  +  7 digits  +  '\0'  at end */
    struct employeeRec* next;
} Node ;

typedef Node* pNode;

void clearNode( pNode r )
{
    free( r->phone );
    free( r->address );
    free( r->name );
}


/* Now can ... */
#include "Clist.h"

/* and then can ...*/
#include "Clist_func's.h"


void show( const pNode r )
{
    char phFormated[] = "(###) ###-####";
    char* p = phFormated;
    char* s = r->phone;
    for( ; *p && *s; ++p ) if( *p == '#' ) { *p = *s; ++s; }
    printf
    (
        "%-22s  %-30s  %s\n",
        r->name, r->address, phFormated
    );
}
void showAll( const Clist* list )
{
    int i = 0;
    pNode p = list->start;
    for( ; p != NULL; p = p->next )
    {
        printf("<%03d> ", ++i);
        show( p );
        if( i % 5 == 0 && i != list->size ) putchar('\n');
    }
    printf( "\nEmployee records on file = %d\n\n", list->size );
}

/* ignore case compare function ... */
int strcmpIgnoreCase( const char* s1, const char* s2 )
{
    for( ; *s1 != 0 && *s2 != 0; ++s1, ++s2 )
    {
        if( tolower(*s1) != tolower(*s2) ) break;
    }
    /* ok ... check the end conditions ... */
    return tolower(*s1) - tolower(*s2);
}
int cmpIgnoreCase( const pNode x, const pNode y )
{
    int compare1 = strcmpIgnoreCase( x->name, y->name ); /* first compare names */
    if( compare1 == 0 ) /* if the same ... */
    {
        int compare2 = strcmpIgnoreCase( x->address, y->address ); /* then address */
        if( compare2 == 0 ) /* if the same ... */
            return strcmp( x->phone, y->phone ); /* then phone number ... */
        /* else ...*/
        return compare2; /* use addresses after all  ... */
    }
    /* else ... */
    return compare1; /* use names afer all ... since names were NOT the same */
}
int cmpPhone( const pNode x, const pNode y )
{
    int compare1 = strcmp( x->phone, y->phone ); /* first compare phones */
    if( compare1 == 0 ) /* if the same ... */
    {
        int compare2 = strcmp( x->name, y->name ); /* then names */
        if( compare2 == 0 ) /* if the same ... */
            return strcmp( x->phone, y->phone ); /* then adress ... */
        /* else ...*/
        return compare2; /* use names after all  ... */
    }
    /* else ... */
    return compare1; /* use phones afer all ... since were NOT the same */
}
int cmp( const pNode x, const pNode y )
{
    int compare1 = strcmp( x->name, y->name ); /* first compare names */
    if( compare1 == 0 ) /* if the same ... */
    {
        int compare2 = strcmp( x->address, y->address ); /* then address */
        if( compare2 == 0 ) /* if the same ... */
            return strcmp( x->phone, y->phone ); /* then phone number ... */
        /* else ...*/
        return compare2; /* use addresses after all  ... */
    }
    /* else ... */
    return compare1; /* use names afer all ... since names were NOT the same */
}


/* with these, an address is passed, so NO copy made and/or original updated */
void readFile( Clist* );
int showMenuExecuteChoice( Clist* );
int isValidPhoneNum( const char* );
pNode getNameIgnoreCase( Clist*, const char* );
pNode getNumber( Clist*, const char* );
void takeInNewRec( pNode );
void takeInRecAndFile( Clist* );
void writeSortedUnique( Clist* );
void editDel( Clist* );
void edit( Clist*, pNode );
void del( Clist*, pNode );




int main() /* ************* MAIN BEGINS ***************** */
{
    int choice;
    Clist cl;
    initClist( &cl ); /* passing the address of cl so object gets updated */
    readFile( &cl );  /* passing the address of cl so object gets updated */
    if( cl.size == 0 )
        printf
        (
            "File %s will be created after data has been entered.\n",
            FILENAME
        );
    /* else showAll( &cl ); //// passing address to avoid making another copy */
   
    printf( "Now cl.start = 0x%p ... cl.size = %d\n\n", (void*)cl.start, cl.size );
   
    do
    {
        showAll( &cl ); /* passing address to avoid making another copy */
        choice = showMenuExecuteChoice( &cl ); /* passing address ... */
        putchar( '\n' );
    }
    while( choice != 10 ); /* i.e. exit on choice of 10 ...  */
   
    clearClist( &cl ); /* free all dynamic memory when done with it ... */
   
    printf( "\nNow cl.start = 0x%p ... cl.size = %d\n", (void*)cl.start, cl.size );

    /* if using windows ... can do this ... especially while debugging ... */
    system( "notepad " FILENAME );
    return 0;
} /* ***************** MAIN ENDS ************************ */



void readFile( Clist* list )
{
    FILE* fp = fopen(FILENAME, "r");
    if( fp )
    {
        Node d;
        while
        (
            (d.name = readLine(fp)) &&
            (d.address = readLine(fp)) &&
            (d.phone = readLine(fp))
        )
        {
            push_frontClist( list, &d );
        }
        fclose( fp );
    }
    else
        printf( "File %s NOT found ...\n", FILENAME );
}


int showMenuExecuteChoice( Clist* list )
{
    int num;
    char* tmp = NULL;

    fputs( MENU, stdout );
    num = takeInIntMinMax( PROMPT, 1, 10 );

    if( num == 1 ) takeInRecAndFile( list );
    else if( num == 2 )
    {
        pNode pd = NULL;
        fputs( "Enter the name to find: ", stdout );
        tmp = readLine(stdin);
        if( (pd = getNameIgnoreCase( list, tmp )) == NULL )
            printf( "%s not found.\n", tmp );
        else
            show( pd );
        free( tmp );
    }
    else if( num == 3 )
    {
        pNode pd;
        fputs( "Enter the number to find: ", stdout );
        tmp = readLine(stdin);
        if( (pd = getNumber( list, tmp )) == NULL )
            printf( "%s not found.\n", tmp );
        else
            show( pd );
        free( tmp );
    }
    /* else if( num == 4 ) showAll( list ); */
    else if( num == 5 ) isortClist( list, cmpIgnoreCase );
    else if( num == 6 ) isortClist( list, cmpPhone );
    else if( num == 7 ) uniqueClist( list, cmp );
    else if( num == 8 ) editDel ( list );
    else if( num == 9 ) writeSortedUnique( list );
    /* else is 10 ... so will exit ... */
   
    return num;
}

/* validates that 10 char's are present and all are numeric ... */
int isValidPhoneNum( const char* ph )
{
    if( strlen(ph) != 10 ) return 0;
    for( ; *ph != 0; ++ph )
        if( *ph < '0' || *ph >'9' ) return 0;
    return 1;
}

/* returns index ... if found ... otherwise , returns -1 if NOT found */
pNode getNameIgnoreCase( Clist* Clist, const char* nameStr )
{
    pNode pr = Clist->start;
    for( ; pr != NULL; pr = pr->next )
        if( strcmpIgnoreCase(pr->name, nameStr) == 0 ) return pr;
    return NULL;
}

pNode getNumber( Clist* Clist, const char* numStr )
{
    pNode pr = Clist->start;
    for( ; pr != NULL; pr = pr->next )
        if( strcmp(pr->phone, numStr) == 0 ) return pr;
    return NULL;

}

void takeInNewRec( pNode r )
{
    r->name = strToTitleCase(takeInLine( "Enter name: " ));
    r->address = strToTitleCase(takeInLine( "Enter address: " ));
    for( ; ; )
    {
        r->phone = takeInLine( "Enter telephone: "  );
        if( isValidPhoneNum(r->phone) ) return;
        /* else ... */
        fputs( "Only 10 digit number valid here ... ", stdout );
        free( r->phone );
    }
}

void takeInRecAndFile( Clist* list )
{
    Node d;
    takeInNewRec( &d );
 
    /* Now we have good data ... so file and add to vector if ok ?  */
    if( tolower(takeInChar( "Ok ... (y/n) ? " )) == 'y' )
    {
        FILE* pFile = fopen( FILENAME, "a" );
        myAssert( (pFile != NULL), "Error: " FILENAME " not opened." );
       
        fprintf( pFile, "%s\n",  d.name );
        fprintf( pFile, "%s\n", d.address );
        fprintf( pFile, "%s\n", d.phone );
       
        push_backClist( list, &d );
        fclose( pFile );
        printf( "Information has been filed in file %s.\n", FILENAME );
    }
    else
    {
        puts( "Aborted ..." );
        clearNode( &d );
    }
}

void writeSortedUnique( Clist* list )
{
    pNode pd;
    int i = 0;
    FILE* fp = fopen( "SU" FILENAME, "w" ); /* compiler concat's these TEXTs */
    myAssert( (fp != NULL), "Error: file SU" FILENAME " failed to open." );
   
    /* ok ... file is open ... so write all rec's to file ..*/
   
    /* first ... make sure sorted and unique */
    uniqueClist( list, cmp );
    for( pd = list->start; pd != NULL; pd = pd->next )
    {
        fprintf( fp, "<%03d> ", ++i );
        fprintf( fp, "%-24s ", pd->name );
        fprintf( fp, "%-32s ", pd->address );
        fprintf( fp, "%s\n", pd->phone );
        if( i % 5 == 0 ) fputs( "\n", fp );
    }
    fclose( fp ); /* flushes buffer ... so all written to file now ... */
    printf( "\n%d records filed in file SU%s list size %d\n\n",
            i, FILENAME,  list->size );
   
    /* and if have Windows OS ... can do this ... */
    system( "notepad SU" FILENAME ); /*compiler concat's text at compile time*/
}

void editDel( Clist* list )
{
    for( ; ; )
    {
        pNode pd;
        char* tmp;
        int reply = tolower(takeInChar( "Find by Name/Phone/Abort (n/p/a) ? " ));
        if( reply == 'n' )
        {
            fputs( "Enter the name to find: ", stdout );
            tmp = readLine(stdin);
            if( (pd = getNameIgnoreCase( list, tmp )) == NULL )
                printf( "%s not found.\n", tmp );
            else
            {
                show( pd );
                reply = tolower(takeInChar( "Edit/Delete/Abort (e/d/a) ? " ));
                if( reply == 'e' ) edit( list, pd );
                else if( reply == 'd' ) del( list, pd );
                else if( reply == 'a' )
                {
                    puts( "Ok, edit/delete aborted ..." );
                    free( tmp );
                    break;
                }
            }
            free( tmp );
        }
        else if( reply == 'p' )
        {
            fputs( "Enter the number to find: ", stdout );
            tmp = readLine(stdin);
            if( (pd = getNumber( list, tmp )) == NULL )
                printf( "%s not found.\n", tmp );
            else
            {
                show( pd );
                reply = tolower(takeInChar( "Edit/Delete/Abort (e/d/a) ? " ));
                if( reply == 'e' ) edit( list, pd );
                else if( reply == 'd' ) del( list, pd );
                else if( reply == 'a' )
                {
                    puts( "Ok, edit/delete aborted ..." );
                    free( tmp );
                    break;
                }
            }
            free( tmp );
        }
        else if( reply == 'a' )
        {
            puts( "Ok, edit/delete aborted ..." );
            break;
        }
        else fputs( "Only n/p/a are valid ... ", stdout );
    }
}

void edit( Clist* list, pNode pd )
{
    Node d;
    for( ; ; )
    {
        takeInNewRec( &d );
       
        /* ok ... we have some new data ... */
        if( tolower(takeInChar( "Ok ... (y/n) ? " )) == 'y' )
        {
            /* then edit ... but first free old ...  */
            clearNode( pd );

            pd->name = d.name;
            pd->address = d.address;
            pd->phone = d.phone;

            list->isSorted = 0;
            break;
        }
        else
        {
            puts( "Aborted ..." );
            clearNode( &d );
            break;
        }
    }
}

void del( Clist* list, pNode pd )
{
    for( ; ; )
    {
        int reply = tolower(takeInChar( "Really delete/abort (d/a) ? " ));
        if( reply == 'a' )
        {
            puts( "Delete aborted ..." );
            break;
        }
        else if( reply == 'd' )
        {
            eraseClist( list, pd );
            break;
        }
        /* else ... */
        fputs( "Enter 'd' and WILL delete ... or 'a' to abort ... \n", stdout );
    }
}

You will also need these 3 files before you compile the above ...

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

Clist.h
http://developers-heaven.net/forum/index.php/topic,2582.msg2877.html#msg2877

Clist_func's.h   
http://developers-heaven.net/forum/index.php/topic,2582.msg2883.html#msg2883

You may also like to see this ...
http://www.dreamincode.net/forums/topic/248797-phonebook-in-c-questions/page__view__findpost__p__1446935
« Last Edit: September 06, 2018, 03:06:46 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 644
    • View Profile
Here is a program that demo's a Clist of int's using Clist_func's.h and shows the time it takes to merge sort a large Clist ... and to find the unique Clist ...

Code: [Select]
/* msort_Clist_func_p_NO_VOID.c */ /* this version 2016-10-13 */

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

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>


#define HEADER "C program to sort 3 Million random int's from file stored " \
               "in a Clist ...\n" \
"Note: uses function pointers ... (*NO* void pointers used in msort compare)\n"


#ifndef dwMYASSERT
#define dwMYASSERT
void myAssert( int condition, const char text[] )
{
    if( !condition )
    {
        fprintf(stderr, "%s\n", text );
        fputs( "Press 'Enter' to exit program ... ", stderr );
        getchar();
        exit(1);
    }
}
#endif

typedef struct myListOfInt
{
    int val;
    struct myListOfInt* next;
} Node;
typedef Node* pNode;

void clearNode( pNode p )
{
    /* empty here ... since no dynamic memory to free here */
    p = p;
}


/* now can include these ...*/
#include "Clist.h"
#include "Clist_func's.h"

/* and ... define this ... */
int compare( const pNode a, const pNode b )
{
    return a->val - b->val ;
}


void myShowAll( const Clist* cl )
{
    int i = 0;
    pNode p = cl->start;
    for( ; p; p = p->next )
    {
        printf( "%6d  ", p->val );
        if( (++i % 20) == 0 )
        {
            char c;
            fputs( "\nPress 'Enter' to continue ... 'a' to abort ... ", stdout );
            c = getchar();
            if( c != '\n' ) while( getchar() != '\n' ); /* flush stdin */
            if( c == 'a' )
            {
                putchar('\n');
                while( i <= (cl->size - 20) ) { ++i; p = p->next; }
                for( ; p; p = p->next ) printf( "%6d  ", p->val );
                break;
            }
        }
    }
}




int main( void ) /* ************************************* */
{
    FILE* fp;
    /* int i = 0; /// i is used below as an index counter ... */
    double ti, tp;
    Node r, *r3;
    Clist cl;
    initClist( &cl ); /* Note: MUST initial to work */
   
    puts( HEADER );
   
    ti = clock();
    fp = fopen( "randInt3M.txt", "r" );
    while( 1 == fscanf( fp, "%d", &r.val ) )
    {
        push_backClist( &cl, &r ); /* since good Rec was obtained */
        /* // ++i; */
    }
    tp = clock() - ti;
    printf( "%d int's were read from file in %.2f sec's ... ",
            cl.size, tp/CLOCKS_PER_SEC  );

    ti = clock();
    msortClist( &cl, compare );
    tp = clock() - ti;
    printf( "merge sorted in %.2f sec's", tp/CLOCKS_PER_SEC  );
    printf( "\nand isSortedClist( &cl, compare ) = %d\n",
            isSortedClist( &cl, compare ) );
           

    ti = clock();
    uniqueClist( &cl, compare );
    tp = clock() - ti;
    printf( "\nuniqueClist in %.2f sec's ", tp/CLOCKS_PER_SEC  );
    printf( "... and isSortedClist( &cl, compare ) = %d",
            isSortedClist( &cl, compare ) );
    printf( "\n... and isUniqueClist( &cl, compare ) = %d\n",
            isUniqueClist( &cl, compare ) );
    printf( "\nAfter uniqueClist: cl.size = %d\n", cl.size );


    r.val = cl.end->val;
    ti = clock();
    r3 = findClist( &cl, &r, compare );
    if( r3 )
    {
        eraseClist( &cl, r3 );
        tp = clock() - ti;
        printf( "%d was erased ...", r.val );
        printf( "%d is new end val...\n", cl.end->val );
        printf( "\nfind/ereaseClist in %.2f sec's\n", tp/CLOCKS_PER_SEC  );
    }
    else printf( "%d was NOT-found/NOT-erased ...", r.val );

    myShowAll( &cl );



    printf( "Before clearClist: cl.size = %d\n", cl.size );
    clearClist( &cl );
    printf( "After  clearClist: cl.size = %d\n", cl.size );


    fputs( "\nPress 'Enter' to continue ... ", stdout );
    getchar();
    return 0;
} /* **************************************************** */

The above program needs these files ...

Clist.h   
http://developers-heaven.net/forum/index.php/topic,2582.msg2877.html#msg2877

Clist_func's.h   
http://developers-heaven.net/forum/index.php/topic,2582.msg2883.html#msg2883

And here is a link to a test data file, randInt3M.txt, but with JUST 300k random int's here ...
http://www.4shared.com/document/hLwtMVzV/randInt3M.html
« Last Edit: October 17, 2016, 01:34:24 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 644
    • View Profile
This program reads the above test file of random int's ... (BUT READS THE INT's as dynamic C strings) ... into a Clist of dynamic C strings, so that you can compare the time taken for a Clist of int's vs a Clist of dynamic C strings of the same data ... and uses the same 3 files linked above ... and also ... readWord.h

This program also uses ... readWord.h ... the 2nd file at ...
http://developers-heaven.net/forum/index.php/topic,2580.msg2864.html#msg2864

Clist.h   
http://developers-heaven.net/forum/index.php/topic,2582.msg2877.html#msg2877

Clist_func's.h   
http://developers-heaven.net/forum/index.php/topic,2582.msg2883.html#msg2883

test data file, randInt3M.txt, but with JUST 300k random int's ...
http://www.4shared.com/document/hLwtMVzV/randInt3M.html


Code: [Select]
/* msort_Clist_func_p_NO_VOID_Cstring.c */  /* this version 2016-10-16 */

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

#define HEADER "C program to sort 3 Million random int's from file stored " \
               "in a Clist ...\n" \
               "(as C strings) ...\n" \
"Note: uses function pointers ... (*NO* void pointers used in msort compare)\n"

#include "readWord.h"
#include <time.h>


typedef struct myListOfString
{
    char* str;
    struct myListOfString* next;
} Node;

typedef Node* pNode;

void clearNode( pNode p )
{
    free( p->str );
}


/* now can include these ...*/
#include "Clist.h"
#include "Clist_func's.h"

/* and ... define this ... */
int compare( const pNode a, const pNode b )
{
    return strcmp(a->str, b->str ) ;
}

void myShowAll( Clist* cl )
{
    int i = 0;
    pNode p = cl->start;
    for( ; p; p = p->next )
    {
        printf( "%6s  ", p->str );
        if( (++i % 20) == 0 )
        {
            char c;
            fputs( "\nPress 'Enter' to continue ... 'a' to abort ... ", stdout );
            c = getchar();
            if( c != '\n' ) while( getchar() != '\n' ) ; /* flush stdin */
            if( c == 'a' )
            {
                putchar( '\n' );
                while( i <= (cl->size - 20) ) { ++i; p = p->next; }
                for( ; p; p = p->next ) printf( "%6s  ", p->str );
                break;
            }
        }
    }
}



int main( void ) /* ************************************* */
{
    FILE* fp;
    double ti, tp;
    char lastChr;
    Node r, r2, *r3 = NULL;
    Clist cl;
    initClist( &cl ); /* Note: MUST initial to work */
   
    puts( HEADER );
   
    ti = clock();
    fp = fopen( "randInt3M.txt", "r" );
    while( (r.str = readWord( fp, 5, " \n", &lastChr )) )
    {
        push_backClist( &cl, &r ); /* since good Rec was obtained */
    }
    tp = clock() - ti;
    printf( "%d int's were read from file in %.2f sec's ... ",
            cl.size, tp/CLOCKS_PER_SEC  );

    ti = clock();
    msortClist( &cl, compare );
    tp = clock() - ti;
    printf( "merge sorted in %.2f sec's", tp/CLOCKS_PER_SEC  );
    printf( "\nand isSortedClist( &cl, compare ) = %d\n",
            isSortedClist( &cl, compare ) );

    ti = clock();
    uniqueClist( &cl, compare );
    tp = clock() - ti;
    printf( "\nuniqueClist in %.2f sec's", tp/CLOCKS_PER_SEC  );
    printf( " ... and isSortedClist( &cl, compare ) = %d",
            isSortedClist( &cl, compare ) );
    printf( "\n... and isUniqueClist( &cl, compare ) = %d\n",
            isUniqueClist( &cl, compare ) );
    printf( "\nAfter uniqueClist: cl.size = %d\n", cl.size );

   
    r2.str = newCopy( cl.end->str ); /* 'newCopy' def'd in readWord/readLine */
    ti = clock();
    r3 = findClist( &cl, &r2, compare );
    if( r3 )
    {
        eraseClist( &cl, r3 );
        tp = clock() - ti;
        printf( "%s was erased ...", r2.str);
        printf( "%s is new end str...\n", cl.end->str);
        printf( "\nfind/ereaseClist in %.2f sec's\n", tp/CLOCKS_PER_SEC  );
    }
    else printf( "%s was NOT-found/NOT-erased ...", r2.str);
   
    myShowAll( &cl );
   
    free( r2.str );


    printf( "Before clearClist: cl.size = %d\n", cl.size );
    clearClist( &cl );
    printf( "After  clearClist: cl.size = %d\n", cl.size );

    fputs( "\nPress 'Enter' to continue ... ", stdout );
    getchar();
    return 0;
} /* **************************************************** */
« Last Edit: October 17, 2016, 01:38:58 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 644
    • View Profile
Example programs, like the 2 right above, but without using function pointers, to let you see the tiny bit of time added by passing function pointers ... These 2 examples use ClistOfInt.h ... and then ClistOfString ... to sort the same large data file that the above demos did using the function pointers in Clist_func's.h

Firstly, using ClistOfInt.h (NO function pointers passed here) ...

Need to include ...

ClistOfInt.h
http://developers-heaven.net/forum/index.php/topic,2582.msg2880.html#msg2880

ClistOfInt.h also includes ... Clist.h   
http://developers-heaven.net/forum/index.php/topic,2582.msg2877.html#msg2877

test data file, randInt3M.txt, but with JUST 300k random int's ...
http://www.4shared.com/document/hLwtMVzV/randInt3M.html

Code: [Select]
/* msort_ClistOfInt.c */  /* this version 2016-10-13 */

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

#define HEADER "C progr am to sort 3 Million random int's from file stored " \
               "in a C list using ... ClistOfInt ...\n"


#include "ClistOfInt.h"
#include <time.h>


void myShowAll( Clist* cl )
{
    int i = 0;
    pNode p = cl->start;
    for( ; p; p = p->next )
    {
        printf( "%6d  ", p->val );
        if( (++i % 20) == 0 )
        {
            char c;
            fputs( "\nPress 'Enter' to continue ... 'a' to abort ... ", stdout );
            c = getchar();
            if( c != '\n' ) while( getchar() != '\n' ) ; /* flush stdin */
            if( c == 'a' )
            {
                putchar('\n' );
                while( i <= (cl->size - 20) ) { ++i; p = p->next; }
                for( ; p; p = p->next ) printf( "%6d  ", p->val );
                break;
            }
        }
    }
}



int main( void ) /* ************************************* */
{
    FILE* fp;
    double ti, tp;
    int valToFind;
    Node r, *r3;
    Clist cl;
    initClist( &cl ); /* Note: MUST initial to work */
   
    puts( HEADER );
   
    ti = clock();
    fp = fopen( "randInt3M.txt", "r" );
    while( 1 == fscanf( fp, "%d", &r.val ) )
    {
        push_backClist( &cl, &r ); /* since good Rec was obtained */
        /* ++i; */
    }
    tp = clock() - ti;
    printf( "%d int's were read from file in %.2f sec's ... ",
            cl.size, tp/CLOCKS_PER_SEC  );

    ti = clock();
    msortClist( &cl );
    tp = clock() - ti;
    printf( "merge sorted in %.2f sec's", tp/CLOCKS_PER_SEC  );
    printf( "\nand isSorted( &cl ) = %d\n", isSortedClist( &cl ) );
   
    ti = clock();
    uniqueClist( &cl );
    tp = clock() - ti;
    printf( "\nunique in %.2f sec's ", tp/CLOCKS_PER_SEC  );
    printf( "... and isSorted( &cl ) = %d", isSortedClist( &cl ) );
    printf( "\n... and isUnique( &cl ) = %d\n", isUniqueClist( &cl ) );
    printf( "\nAfter unique: cl.size = %d\n", cl.size );
   
 
    valToFind = cl.end->val;
    ti = clock();
    r3 = findClist( &cl, valToFind );
    if( r3 )
    {
        eraseClist( &cl, r3 );
        tp = clock() - ti;
        printf( "%d was erased ...", valToFind);
        printf( "%d is new end val...\n", cl.end->val);
        printf( "\nfind/ereaseClist in %.2f sec's\n", tp/CLOCKS_PER_SEC  );
    }
    else printf( "%d was NOT-found/NOT-erased ...", valToFind );

    myShowAll( &cl );


    printf( "Before clearClist: cl.size = %d\n", cl.size );
    clearClist( &cl );
    printf( "After  clearClist: cl.size = %d\n", cl.size );


    fputs( "\nPress 'Enter' to continue ... ", stdout );
    getchar();
    return 0;
} /* **************************************************** */
« Last Edit: October 17, 2016, 02:04:25 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 644
    • View Profile
Secondly, using ClistOfString.h (NO function pointers passed here) ...

Need to include ...

CListOfString.h
http://developers-heaven.net/forum/index.php/topic,2582.msg2882.html#msg2882

Note: ClistOfString.h also includes readLine.h and Clist.h
http://developers-heaven.net/forum/index.php/topic,2580.msg2864.html#msg2864   
http://developers-heaven.net/forum/index.php/topic,2582.msg2877.html#msg2877

test data file, randInt3M.txt, but with JUST 300k random int's ...
http://www.4shared.com/document/hLwtMVzV/randInt3M.html

Code: [Select]
/* msort_ClistOfString.c */  /* this version 2016-10-20 */

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

#define HEADER "C program to sort 3 Million random int's from file stored " \
               "in a Clist ...\n ... as C strings ...  " \
"(Note: using ClistOfString.h in this program)\n"

#include "readWord.h"
#include "ClistOfString.h" /* also includes readLine, but using readWord here */
#include <time.h>

void myShowAll( Clist* cl )
{
    int i = 0;
    pNode p = cl->start;
    for( ; p; p = p->next )
    {
        printf( "%6s  ", p->str );
        if( (++i % 20) == 0 )
        {
            char c, c2;
            fputs( "\nPress 'Enter' to continue ... 'a' to abort ... ", stdout );
            c2 = c = getchar();
            while( c != '\n' ) c = getchar(); /* flush stdin ... */
            if( c2 == 'a' )
            {
                putchar('\n');
                while( i <= (cl->size - 20 ) ) { ++i; p = p->next; }
                for( ; p; p = p->next ) printf( "%6s  ", p->str );
                break;
            }
        }
    }
}


int main( void ) /* ********************************************************* */
{
    FILE* fp;
    double ti, tp;
    char lastChr, *s;
    int i;
    Node r, r2, *r3 = NULL;
    Clist cl;
    initClist( &cl ); /* Note: MUST initial to work */
   
    puts( HEADER );
   
    ti = clock();
    fp = fopen( "randInt3M.txt", "r" );
    while( (r.str = readWord( fp, 5, " \n", &lastChr )) )
    {
        push_backClist( &cl, &r ); /* since good Rec was obtained */
    }
    tp = clock() - ti;
    printf( "%d int's were read from file in %.2f sec's ... ",
            cl.size, tp/CLOCKS_PER_SEC  );

    ti = clock();
    msortClist( &cl );
    tp = clock() - ti;
    printf( "merge sorted in %.2f sec's", tp/CLOCKS_PER_SEC  );
    printf( "\nand isSorted( &cl ) = %d\n", isSortedClist( &cl ) );

    ti = clock();
    uniqueClist( &cl );
    tp = clock() - ti;
    printf( "\nunique in %.2f sec's ", tp/CLOCKS_PER_SEC  );
    printf( "... and isSorted( &cl ) = %d", isSortedClist( &cl ) );
    printf( "\n... and isUnique( &cl ) = %d\n", isUniqueClist( &cl ) );
    printf( "\nAfter unique: cl.size = %d\n", cl.size );

   
    r2.str = newCopy( cl.end->str ); /* 'newCopy' def'd in readWord/readLine */
    ti = clock();
    r3 = findClist( &cl, r2.str );
    if( r3 )
    {
        eraseClist( &cl, r3 );
        tp = clock() - ti;
        printf( "%s was erased ...", r2.str);
        printf( "%s is new end str...\n", cl.end->str);
        printf( "\nfind/ereaseClist in %f sec's\n", tp/CLOCKS_PER_SEC  );
    }
    else printf( "%s was NOT-found/NOT-erased ...", r2.str);
   
    myShowAll( &cl );
   
    free( r2.str );
   
   
    ti = clock();
    s =  joinClist( &cl, "," );
    tp = clock() - ti;
    printf( "\njoinClist( &cl, \",\" ) in %f sec's ... ", tp/CLOCKS_PER_SEC  );

    ti = clock();
    i = strlen( s );
    tp = clock() - ti;
    printf( "\nstrlen(s) = %d in %f sec's ... ", i, tp/CLOCKS_PER_SEC  );

    puts( "\nFirst 70 char's in joined Clist dynamic C string is :" );
    s[70] = 0;
    puts( s );

    puts( "\nLast 70 char's in joined Clist dynamic C string is :" );
    puts( &s[i-70] );

    free( s );


    printf( "\nBefore clearClist: cl.size = %d\n", cl.size );
    clearClist( &cl );
    printf( "After  clearClist: cl.size = %d\n", cl.size );

    fputs( "\nPress 'Enter' to continue ... ", stdout );
    getchar();
    return 0;
} /* ************************************************************************ */
« Last Edit: October 17, 2016, 02:07:44 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 644
    • View Profile
And now a C++ STL list version of the top Clist program ...

Code: [Select]
/* employeeRec's_list.cpp */ /* this version: 2011-08-08 */

#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <list>
#include <cstdlib> /* re. atoi */
#include <cctype> /* re. tolower */

using namespace std;

#define FILENAME "employeeRecords.txt"

#define MENU      " 1. Enter a new record. \n" \
                  " 2. Retrieve a record by name (ignore case). \n" \
                  " 3. Retrieve a record by phone number. \n" \
                  " 4. Show all records. \n" \
                  " 5. Sort all records by name (ignore case). \n" \
                  " 6. Sort all records by phone number. \n" \
                  " 7. Chop exact duplicates from records (use case). \n" \
                  " 8. Edit/Delete a record. \n" \
                  " 9. Write new file of sorted unique records. \n" \
                  "10. Exit \n"
#define PROMPT    "Enter a number in range 1 to 10 : "


struct Employee
{
    string name;
    string address;
    string phone;
} ;

typedef list< Employee > myList;
typedef list< Employee >::iterator myIter;
typedef list< Employee >::const_iterator c_myIter;


int strcmpIgnoreCase( const string&, const string& );
int strcmpWithCase( const string&, const string& );
bool cmpIgnoreCase( const Employee&, const Employee& );
bool cmpWithCase( const Employee&, const Employee& );
bool cmpPhone( const Employee&, const Employee& );
bool operator == ( const Employee&, const Employee& ); // for unique ...


void show( const Employee& r )
{
    char phFormated[] = "(###) ###-####";
    char* p = phFormated;
    for( int i = 0; *p ; ++p ) if( *p == '#' ) { *p = r.phone[i]; ++i; }
    cout << left << setw(22) << r.name << " "
         << setw(30) << r.address << " " << phFormated << right << endl;
}
void showAll( const myList& lst )
{
    size_t i = 0;
    for( c_myIter p = lst.begin(); p != lst.end(); ++p )
    {
        cout << "<" << setfill('0') << setw(3) << ++i << "> " << setfill(' ');
        show( *p );
        if( i % 5 == 0 && i != lst.size() ) cout << endl;
    }
    cout << "\nEmployee records on file = " << lst.size() << endl << endl;
}


/* ignore case compare function ... */
int strcmpIgnoreCase( const string& a, const string& b )
{
size_t i, lenA = a.size(), lenB = b.size();
    for( i = 0; i < lenA && i < lenB; ++i )
    {
        if( tolower(a[i]) != tolower(b[i]) ) break;
    }
    /* ok ... check the end conditions ... */
    if( i < lenA )
    {
        if( i < lenB )  return tolower(a[i]) - tolower(b[i]);
        //else ...
        return 1; // i.e. b < a
    }
    // else // if reach here ... i == lenA
    if( i < lenB ) return -1; // i.e. a < b
   
    // else // if reach here ... i == lenA ...AND... i == lenB
    return 0; // i.e. a == b
}
/* case compare function ... */
int strcmpWithCase( const string& a, const string& b )
{
size_t i, lenA = a.size(), lenB = b.size();
    for( i = 0; i < lenA && i < lenB; ++i )
    {
        if( a[i] != b[i] ) break;
    }
    /* ok ... check the end conditions ... */
    if( i < lenA )
    {
        if( i < lenB )  return a[i] - b[i];
        //else ...
        return 1; // i.e. b < a
    }
    // else // if reach here ... i == lenA
    if( i < lenB ) return -1; // i.e. a < b

    // else // if reach here ... i == lenA ...AND... i == lenB
    return 0; // i.e. a == b
}

bool cmpIgnoreCase( const Employee& x, const Employee& y )
{
    int compare1 = strcmpIgnoreCase( x.name, y.name ); /* first compare names */
    if( compare1 == 0 ) /* if the same ... */
    {
int compare2 = strcmpIgnoreCase( x.address, y.address ); /* then address */
        if( compare2 == 0 ) /* if the same ... */
return x.phone < y.phone; /* then phone number ... */
        /* else ...*/
        return compare2 < 0; /* use addresses after all  ... */
    }
    /* else ... */
    return compare1 < 0; /* use names afer all ... since names were NOT the same */
}
bool cmpWithCase( const Employee& x, const Employee& y )
{
    int compare1 = strcmpWithCase( x.name, y.name ); /* first compare names */
    if( compare1 == 0 ) /* if the same ... */
    {
int compare2 = strcmpWithCase( x.address, y.address ); /* then address */
        if( compare2 == 0 ) /* if the same ... */
return x.phone < y.phone; /* then phone number ... */
        /* else ...*/
        return compare2 < 0; /* use addresses after all  ... */
    }
    /* else ... */
    return compare1 < 0; /* use names afer all ... since names were NOT the same */
}
bool cmpPhone( const Employee& x, const Employee& y )
{
    int compare1 = strcmpWithCase( x.phone, y.phone ); /* first compare phones */
    if( compare1 == 0 ) /* if the same ... */
    {
        int compare2 = strcmpWithCase( x.name, y.name ); /* then names */
        if( compare2 == 0 ) /* if the same ... */
            return x.address < y.address; /* then address ... */
        /* else ...*/
        return compare2 < 0; /* use names after all  ... */
    }
    /* else ... */
    return compare1 < 0; /* use phones afer all ... since were NOT the same */
}
bool operator ==( const Employee& x, const Employee& y )
{
    if( x.name != y.name ) return false; /* first compare names */
if( x.address != y.address ) return false; /* then address */
if( x.phone != y.phone ) return false; /* then phone number ... */
//else ...
return true;
}


int getChoice( const string& );
int showMenuGetChoice( myList& );
void readFile( myList& );
bool isValidPhoneNum( const string& );
myIter getNameIgnoreCase( myList&, const string& );
myIter getNumber( myList&, const string& );

Employee enterEmployee();
void takeInRecAndFile( myList& );
void writeSortedUnique( myList& );
void editDel( myList& );
void edit( myList&, myIter& );
void del( myList&, myIter& );



int main() /* ********************* MAIN BEGINS ***************************** */
{
    int choice;
    myList ml;
    readFile( ml );  /* passing ml by reference so object gets updated */
    if( ml.size() == 0 )
        cout << "File " << FILENAME
             << " will be created after data has been entered." << endl;
    else
        cout << "Now &(*ml.begin()) = " << hex << &(*ml.begin()) << " and "
             << "ml.size = " << dec << ml.size() << endl << endl;
   
    do
    {
        showAll( ml ); /* passing ml by reference to avoid making another copy */
        choice = showMenuGetChoice( ml ); /* passing address ... */
        cout << endl;
    }
    while( choice != 10 ); /* i.e. exit on choice of 10 ...  */
   
   
    cout << "Now &(*ml.begin()) = 0x" << hex << &(*ml.begin()) << " and "
         << "ml.size = " << ml.size() << endl << endl;

    /* if using windows ... can do this ... especially while debugging */
    system( "notepad " FILENAME );
   
} /* **************************** MAIN ENDS ********************************* */



int getChoice( const string& text )
{
    cout << text << flush;
    int reply = tolower( cin.get() );
    cin.sync();
    return reply;
}

void readFile( myList& lst )
{
    ifstream fin( FILENAME );
    if( !fin )
    {
        cout << "File " << FILENAME << " NOT found ..." << endl;
    }
    else
    {
        Employee d;
        while
        (
getline( fin, d.name ) && getline( fin, d.address )
            && getline( fin, d.phone )
        )
        {
            lst.push_back( d );
        }
        fin.close();
    }
}

int showMenuGetChoice( myList& lst )
{
    int num;
    string tmp;
    cout << MENU << flush;
   
    while
    (
        cout << PROMPT
        && getline( cin, tmp )
        && ( (num = atoi(tmp.c_str())) < 1 || num > 10 )
    )
    {
        cout << "Out of valid range 1..10  " << flush;
    }

    if( num == 1 ) takeInRecAndFile( lst );
    else if( num == 2 )
    {
        cout << "Enter the name to find: " << flush;
        getline(cin, tmp);
        myIter it;
        if( (it = getNameIgnoreCase( lst, tmp )) == lst.end() )
            cout << tmp << " not found." << endl;
        else
            show( *it );
    }
    else if( num == 3 )
    {
        cout << "Enter the number to find: " << flush;
        getline(cin, tmp);
        myIter it;
        if( (it = getNumber( lst, tmp )) == lst.end() )
            cout << tmp << " not found." << endl;
        else
            show( *it );
    }
    //else if( num == 4 ) showAll( list );
    else if( num == 5 ) lst.sort( cmpIgnoreCase );
    else if( num == 6 ) lst.sort( cmpPhone );
else if( num == 7 ) { lst.sort( cmpWithCase ); lst.unique(); }
    else if( num == 8 ) editDel ( lst );
    else if( num == 9 ) writeSortedUnique( lst );
    /* else is 10 ... so will exit ... */
    return num;
}

/* validates that 10 char's are present and all are numeric ... */
bool isValidPhoneNum( const string& ph )
{
    if( ph.size() != 10 ) return false;
    for( int i = 0; i < 10; ++i )
        if( ph[i] < '0' || ph[i] >'9' ) return false;
    return true;
}

/* returns valid iterbif found ... otherwise, returns ml.end() if NOT found */
myIter getNameIgnoreCase( myList& ml, const string& nameStr )
{
    for( myIter it = ml.begin(); it != ml.end(); ++it )
        if( strcmpIgnoreCase(it->name, nameStr) == 0 ) return it;
    return ml.end();
}

myIter getNumber( myList& ml, const string& numStr )
{
    for( myIter it = ml.begin(); it != ml.end(); ++it )
        if( strcmpWithCase(it->phone, numStr) == 0 ) return it;
    return ml.end();

}

Employee enterEmployee()
{
Employee d;
    cout << "Enter name: " << flush;
    getline( cin, d.name );
    cout << "Enter address: "<< flush;
getline( cin, d.address );
    for( ; ; )
    {
        cout << "Enter telephone: " << flush;
getline( cin, d.phone );
        if( isValidPhoneNum(d.phone) )
        {
            break;
        }
        /* else ... */
        cout << "Only 10 digit number valid here ... " << flush;
    }
return d;
}

void takeInRecAndFile( myList& lst )
{
    ofstream fout( FILENAME, ios::app );
    if( !fout )
{
cout << "Error: " << FILENAME << " not opened." << endl;
return;
}
   
Employee d = enterEmployee();

    /* Now we have good data ... so file and add to vector if ok ?  */
    if( getChoice( "Ok ... (y/n) ? " ) == 'y' )
    {
        fout << d.name << '\n' << d.address << '\n' << d.phone << endl;
        lst.push_back( d );
        cout << "Information has been filed in file " << FILENAME << endl;
    }
    else
    {
        cout << "Aborted ..." << endl;
}

    fout.close();
}

void writeSortedUnique( myList& lst )
{
    ofstream fout( "SU" FILENAME ); /* compiler concat's the text's ... */
if( !fout )
{
cout << "Error: file SU" << FILENAME << " failed to open." << endl;
return;
}
   
    /* ok ... file is open ... so write all rec's to file ..*/
   
    /* first ... make sure sorted and unique */
lst.sort( cmpWithCase );
lst.unique();
int i = 0;
    for( c_myIter it = lst.begin(); it != lst.end(); ++it )
    {
        fout <<  "<" << setfill('0') << setw(3) << ++i << "> "
             << setfill(' ') << left << setw(24) << it->name << " "
             << setw(32) << it->address << " "
             << it->phone << right << endl;
        if( i % 5 == 0 ) fout << endl;
    }
    fout.close(); /* flushes buffer ... so all written to file now ... */
    cout << i << " records filed in file SU" << FILENAME
         << ", list size " << lst.size() << endl << endl;
   
    /* and if have Windows OS ... can do this ... */
    system( "notepad SU" FILENAME ); /*compiler concat's text at compile time*/
}

void editDel( myList& lst )
{
    myIter it;
    string tmp;
    for( ; ; )
    {
        int reply = getChoice( "Find by Name/Phone/Abort (n/p/a) ? " );
        if( reply == 'n' )
        {
            cout << "Enter the name to find: " << flush;
            getline( cin, tmp );
            if( (it = getNameIgnoreCase( lst, tmp )) == lst.end() )
                cout << tmp << " not found." << endl;
            else
            {
                show( *it );
                reply = getChoice( "Edit/Delete/Abort (e/d/a) ? " );
                if( reply == 'e' ) edit( lst, it );
                else if( reply == 'd' ) del( lst, it );
                else if( reply == 'a' )
                {
                    cout << "Ok, edit/delete aborted ..."<< endl;
                    break;
                }
            }
        }
        else if( reply == 'p' )
        {
            cout << "Enter the number to find: " << flush;
            getline(cin, tmp);
            if( (it = getNumber( lst, tmp )) == lst.end() )
                cout << tmp << " not found." << endl;
            else
            {
                show( *it );
                reply = getChoice( "Edit/Delete/Abort (e/d/a) ? " );
                if( reply == 'e' ) edit( lst, it );
                else if( reply == 'd' ) del( lst, it );
                else if( reply == 'a' )
                {
                    cout << "Ok, edit/delete aborted ..." << flush;
                    break;
                }
}
        }
        else if( reply == 'a' )
        {
            cout << "Ok, edit/delete aborted ..." << flush;
            break;
        }
        else cout << "Only n/p/a are valid ... " << flush;
    }
}

void edit( myList& lst, myIter& it )
{
Employee d = enterEmployee();

/* ok ... we have some new data ... */
if( getChoice( "Ok ... (y/n) ? " ) == 'y' )
{ /* then edit ...  */
it->name =d.name;
it->address =d.address;
it->phone =d.phone;
return;
}
/* else ... */
cout << "Aborted ..." << endl;
}

void del( myList& lst, myIter& it )
{
    for( ; ; )
    {
        int reply = getChoice( "Really delete/abort (d/a) ? " );
        if( reply == 'a' )
        {
            cout << "Delete aborted ..." << flush;
            return;
        }
/* else ... */
        if( reply == 'd' )
        {
lst.erase( it );
            return;
        }
        /* else ... */
        cout << "Enter 'd' and WILL delete ... or 'a' to abort ..." << endl;
    }
}
« Last Edit: August 09, 2011, 01:49:45 PM by David »