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

Offline David

  • Hero Member
  • *****
  • Posts: 644
    • View Profile
Update:

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 Cvec_func's.h ...

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

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

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


/* this version does NOT use void pointers in cmp func's ...  */

#define FILE_NAME "employeeRecords.txt"

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


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

typedef struct employeeRecord
{
    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 */
} Rec ;

void clearRec( Rec* r )
{
    free( r->phone );
    free( r->address );
    free( r->name );
}

/* now can ... */
#include "Cvec.h"
/* then can ... */
#include "Cvec_func's.h" /* this ver. does NOT use void pointers in cmp func's */


void show( const Cvec* cv, int i ) /* phone number formated to (###) ###-#### */
{
    char  phFormated[] = "(###) ###-####";
    char* s = phFormated;           /* get pointer to 1st char in string */
    char* p = cv->ary[i].phone;     /* get pointer to 1st char in string */
    for( ; *p && *s; ++s )
        if( *s == '#' ) *s = *p++;  /* traverse s, increment p when *s == '#' */
    printf
    (
        "<%03d> %-24s %-32s %s\n",
        i+1, cv->ary[i].name, cv->ary[i].address, phFormated
    );
}
void showAll( const Cvec* cv )
{
    int i;
    for( i = 0; i < cv->size; ++i )
    {
        show( cv, i );
        if( (i+1)%3 == 0  &&  (i+1) != cv->size ) putchar('\n');
    }
    printf( "\nEmployee records on file = %d, present vector capacity = %d\n\n",
            cv->size, cv->cap );
}

int myCmpName( const Rec* a, const Rec* b )
{
    int compareAdd, compareNam = strcmp(a->name, b->name);
    if( compareNam ) return compareNam;

    compareAdd = strcmp( a->address, b->address );
    if( compareAdd ) return compareAdd;

    return strcmp( a->phone, b->phone );
}
int myCmpPhone( const Rec* a, const Rec* b )
{
    int compareName, comparePh = strcmp(a->phone, b->phone);
    if( comparePh ) return comparePh;

    compareName = strcmp( a->name, b->name );
    if( compareName ) return compareName;

    return strcmp( a->address, b->address );
}

/* ignore case C string compare function ... */
int compareStrsIgnoreCase( 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 myCmpNameIgnoreCase ( const Rec* a, const Rec* b )
{
    int compareAdd, compareNam = compareStrsIgnoreCase(a->name, b->name);
    if( compareNam ) return compareNam;

    compareAdd = compareStrsIgnoreCase( a->address, b->address );
    if( compareAdd ) return compareAdd;

    return strcmp( a->phone, b->phone );
}


void readFile( Cvec* cv );
int showMenuExecuteChoice( Cvec* cv );
int isValidPhoneNum( char ph[] );
int getNameIgnoreCase( Cvec* cv, char nameStr[] );
int getNumber( Cvec* cv, char numStr[] );
void takeInNewRec( Rec* );
void takeInRecAndFile( Cvec* cv );
void writeSortedUnique( Cvec* cv );
void del( Cvec*, int );
void editDel( Cvec * cv );
void edit( Cvec* cv, int i ); /* at index i ... */



int main() /* ******************************************* */
{
    int choice;
    Cvec cv;
    initCvec( &cv );
   
    readFile( &cv ); /* we are passing the address of cv, so cv is updated */
    if( cv.size == 0 )
        printf
        (
            "File %s will be created after data has been entered.\n",
            FILE_NAME
        );
    /* else showAll( &cv ); // // passing address to avoid making another copy */
   
    printf( "Now with address of cv.ary = 0x%p,  cv.size = %d,  cv.cap = %d\n",
            (void*)cv.ary, cv.size, cv.cap );
   
    do
    {
        putchar( '\n' );
        showAll( &cv ); /* passing address to avoid making another copy */
        choice = showMenuExecuteChoice( &cv ); /* passing address ... */
    }
    while( choice != 10 ); /* i.e. exit on choice of 10 ...  */
   
    clearCvec( &cv ); /* free all dynamic memory when done with it ... */
   
    printf( "\nNow with cv.ary = 0x%p,  cv.size = %d\n",  (void*)cv.ary, cv.size );

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



void readFile( Cvec* cv )
{
    FILE* fp;
    if( (fp = fopen(FILE_NAME, "r")) )
    {
        Rec d;
        while
        (
            (d.name = readLine(fp)) &&
            (d.address = readLine(fp)) &&
            (d.phone = readLine(fp))
        )
        {
            push_backCvec( cv, &d );
        }
        fclose( fp );
    }
    else
        printf( "File %s does not exist yet in this folder ...\n", FILE_NAME );
}


int showMenuExecuteChoice( Cvec* cv )
{
    char* tmp = NULL;
    int num = takeInIntMinMax( MENU, 1, 10 );

    if( num == 1 )
        takeInRecAndFile( cv );
    else if( num == 2 )
    {
        int index;
        fputs( "Enter the name to find: ", stdout );
        tmp = readLine(stdin);
        if( (index = getNameIgnoreCase( cv, tmp )) == -1 )
            printf( "%s not found.\n", tmp );
        else
            show( cv, index );
        free( tmp );
    }
    else if( num == 3 )
    {
        int index;
        tmp = takeInLine( "Enter the number to find: " );
        if( (index = getNumber( cv, tmp )) == -1 )
            printf( "%s not found.\n", tmp );
        else
            show( cv, index );
        free( tmp );
    }
    /*else if( num == 4 ) showAll( cv );*/
    else if( num == 5 ) msortCvec( cv, myCmpNameIgnoreCase );
    else if( num == 6 ) msortCvec( cv, myCmpPhone );
    else if( num == 7 ) uniqueCvec( cv, myCmpName ); /* sort by case */
    else if( num == 8 ) editDel ( cv );
    else if( num == 9 ) writeSortedUnique( cv );
    /* else if num == 10, will exit do..while( num!=10 ) calling loop */
    /* else will do calling loop again ...*/
   
    return num;
}

/* validates that 10 char's are present and all are numeric ... */
int isValidPhoneNum( 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 */
int getNameIgnoreCase( Cvec* cv, char nameStr[] )
{
    int i;
    for( i = 0; i < cv->size; ++i)
        if( compareStrsIgnoreCase(cv->ary[i].name, nameStr) == 0 )
            return i;
    return -1;
}

int getNumber( Cvec* cv, char numStr[] )
{
    int i;
    for( i = 0; i < cv->size; ++i)
        if( strcmp(cv->ary[i].phone, numStr) == 0 )
            return i;
    return -1;

}

void takeInNewRec( Rec* r )
{
    r->name = strToTitleCase(takeInLineMaxLen( "Enter name: ", 80 ));
    r->address = strToTitleCase(takeInLineMaxLen( "Enter address: ", 80 ));
    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( Cvec* cv )
{
    Rec 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( FILE_NAME, "a" );
        myAssert( (pFile != NULL), "Error: " FILE_NAME " not opened." );
        fprintf( pFile, "%s\n",  d.name );
        fprintf( pFile, "%s\n", d.address );
        fprintf( pFile, "%s\n", d.phone );
        push_backCvec( cv, &d );
        printf( "Information has been filed in file %s.\n", FILE_NAME );
        fclose( pFile );
    }
    else
    {
        puts( "Aborted ..." );
        clearRec( &d );
    }
}

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

void editDel( Cvec* cv )
{
    for( ; ; )
    {
        char* tmp;
        int i, reply = tolower(takeInChar( "Find by Name/Phone/Abort (n/p/a) ? " ));
        if( reply == 'n' )
        {
            tmp = takeInLine( "Enter the name to find: " );
            if( (i = getNameIgnoreCase( cv, tmp )) == -1 )
                printf( "%s not found.\n", tmp );
            else
            {
                show( cv, i );
                reply = tolower(takeInChar( "Edit/Delete/Abort (e/d/a) ? " ));
                if( reply == 'e' ) edit( cv, i );
                else if( reply == 'd' ) del( cv, i );
                else if( reply == 'a' )
                {
                    puts( "Ok, edit/delete aborted ..." );
                    free( tmp );
                    break;
                }
            }
            free( tmp );
        }
        else if( reply == 'p' )
        {
            tmp = takeInLine("Enter the number to find: " );
            if( (i = getNumber( cv, tmp )) == -1 )
                printf( "%s not found.\n", tmp );
            else
            {
                show( cv, i );
                reply = tolower(takeInChar( "Edit/Delete/Abort (e/d/a) ? " ));
                if( reply == 'e' ) edit( cv, i );
                else if( reply == 'd' ) del( cv, i );
                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( Cvec* cv, int i )
{
    Rec d;
    for( ; ; )
    {
        takeInNewRec( &d );
        if( takeInChar( "Ok ... (y/n) ? " ) == 'y' )
        {
            /* then edit ... but first free old ...  */
            clearRec( & cv->ary[i] );

            cv->ary[i].name = d.name;
            cv->ary[i].address = d.address;
            cv->ary[i].phone = d.phone;
            break;
        }
        else
        {
            puts( "Aborted ..." );
            clearRec( &d );
            break;
        }
    }
}

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

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

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

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

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

Cvec_func's.h   
http://developers-heaven.net/forum/index.php/topic,2580.msg2866.html#msg2866
« Last Edit: October 09, 2016, 12:21:35 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 644
    • View Profile
Re: Cvec_func's.h example programs ... using FUNCTION POINTERS ...
« Reply #1 on: July 16, 2011, 02:59:05 AM »
Here is a program that demo's a Cvec of int's using Cvec_func's.h and shows the time it takes to merge sort a large Cvec ... and to find the unique Cvec ...

Code: [Select]
/* msort_Cvec_func_p_NO_VOID.c */  /* this version 2016-10-09 */


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

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

#define FNAME "randInt3M.txt"
#define THREE_MEG 3000000


#define HEADER "C program to sort 3 Million random int's from file stored " \
               "in a Cvec ...\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 myRecOfInt
{
    int val;
} Rec;

void clearRec( Rec* r )
{
    /* empty here ... since no dynamic memory to free here */
    r = r;
}


/* now can include these ...*/
#include "Cvec.h"
#include "Cvec_func's.h"

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


void myShowAll( Cvec* cv )
{
    int i;
    for( i = 0; i < cv->size;  )
    {
        printf( "%6d  ", cv->ary[i].val );
        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 < cv->size - 20 ) ++i;
                for( ; i < cv->size; ++i ) printf( "%6d  ", cv->ary[i].val );
                break;
            }
        }
    }
}



int main( void ) /* ************************************* */
{
    FILE* fp = NULL;
    double ti, tp;
    int i;
    Rec r;
    Cvec cv;
    initCvec( &cv ); /* Note: MUST initial to work */
    reserveCvec( &cv, THREE_MEG );
   
    puts( HEADER );
   
    ti = clock();
    fp = fopen( FNAME, "r" );
    if( !fp ) /* create file ... */
    {
        fp = fopen( FNAME, "w" );
        if(fp)
        {
            for( i = 1; i <= THREE_MEG; ++ i )
            {
                fprintf( fp, "%6d  ", rand() );
                if( (i % 10)== 0 ) fprintf( fp, "\n" );
            }
        }
        fclose(fp);
        printf( "File %s was created.\n", FNAME );
    }

    fp = fopen( FNAME, "r" );
    if( fp )
    {
        while( 1 == fscanf( fp, "%d", &r.val ) )
        {
            push_backCvec( &cv, &r ); /* since good Rec was obtained */
        }
        tp = clock() - ti;
        printf( "%d int's were read from file in %.2f sec's ... ",
                cv.size, tp/CLOCKS_PER_SEC  );

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


        ti = clock();
        uniqueCvec( &cv, compare  );
        tp = clock() - ti;
        printf( "\nunique in %.2f sec's", tp/CLOCKS_PER_SEC  );
        printf( " ... and isSortedCvec( &cv, compare ) = %d ",
                  isSortedCvec( &cv, compare ) );
        printf( "\n... and isUniqueCvec( &cv, compare ) = %d\n",
                isUniqueCvec( &cv, compare ) );
        printf( "\nAfter uniqueCvec: cv.size = %d, cv.cap = %d\n\n", cv.size, cv.cap );


        r.val = cv.ary[cv.size-1].val;
        ti = clock();
        i = findCvec( &cv, &r, compare );
        if( i != -1 )
        {
            eraseCvec( &cv, i );
            tp = clock() - ti;
            printf( "%d was erased ...", r.val);
            printf( "%d is new end val...\n", cv.ary[cv.size-1].val);
            printf( "find/ereaseCvec in %.2f sec's\n\n", tp/CLOCKS_PER_SEC  );
        }
        else printf( "%d was NOT-found/NOT-erased ...\n\n", r.val );

        myShowAll( &cv );


        printf( "Before clearCvec: cv.size = %d, cv.cap = %d\n", cv.size,cv.cap );
        clearCvec( &cv );
        printf( "After  clearCvec: cv.size = %d, cv.cap = %d\n", cv.size,cv.cap );
    }
    else
        printf( "There was a problem reading file %s\n", FNAME );
   

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

The above program needs these files ...

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

Cvec_func's.h   
http://developers-heaven.net/forum/index.php/topic,2580.msg2866.html#msg2866

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 09, 2016, 07:19:11 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 644
    • View Profile
Re: Cvec_func's.h example programs ... using FUNCTION POINTERS ...
« Reply #2 on: July 16, 2011, 03:39:29 AM »
This program reads the above test file of random int's ... (BUT READS THE INT's as dynamic C strings) ... into a Cvec of dynamic C strings, so that you can compare the time taken for a Cvec of int's vs a Cvec 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

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

Cvec_func's.h   
http://developers-heaven.net/forum/index.php/topic,2580.msg2866.html#msg2866


Code: [Select]
/* msort_Cvec_func_p_NO_VOID_Cstring.c */  /* this version 2016-10-09 */


/*
   http://developers-heaven.net/forum/index.php/topic,46.0.html
*/
#define FNAME "randInt3M.txt"
#define THREE_MEG 3000000

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


#include "readWord.h" /* includes <stdio.h>, <stdlib.h>, <strung.h> and ...
                         defines myAssert, newCopy  ... as well as readWord */
#include <time.h>


typedef struct myRecOfString
{
    char* str;
} Rec;

void clearRec( Rec* p )
{
    free( p->str );
}


/* now can include these ...*/
#include "Cvec.h"
#include "Cvec_func's.h"

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

void myShowAll( Cvec* cv )
{
    int i;
    for( i = 0; i < cv->size;  )
    {
        printf( "%6s  ", cv->ary[i].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 < cv->size - 20 ) ++i;
                for( ; i < cv->size; ++i ) printf( "%6s  ", cv->ary[i].str );
                break;
            }
        }
    }
}



int main( void ) /* ********************************************************* */
{
    FILE* fp;
    double ti, tp;
    char lastChr;
    int i;
    Rec r, r2;
    Cvec cv;
    initCvec( &cv ); /* Note: MUST initial to work */
    reserveCvec( &cv, THREE_MEG );
   
    puts( HEADER );
   
    ti = clock();
    fp = fopen( FNAME, "r" );
    while( (r.str = readWord( fp, 5, " \n", &lastChr )) )
    {
        push_backCvec( &cv, &r ); /* since good Rec was obtained */
        /* // if( cv.size == 100000 ) break; // */
    }
    tp = clock() - ti;
    printf( "%d int's were read from file in %.2f sec's ... ",
            cv.size, tp/CLOCKS_PER_SEC  );

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

    ti = clock();
    uniqueCvec( &cv, compare );
    tp = clock() - ti;
    printf( "\nuniqueCvec in %.2f sec's", tp/CLOCKS_PER_SEC  );
    printf( " ... and isSortedCvec( &cv, compare ) = %d ",
            isSortedCvec( &cv, compare ) );
    printf( "\n... and isUniqueCvec( &cv, compare ) = %d\n",
            isUniqueCvec( &cv, compare ) );
    printf( "\nAfter uniqueCvec: cv.size = %d, cv.cap = %d\n", cv.size, cv.cap );

    /* Note: 'newCopy' is now defined in readWord, as well as in readLine */
    r2.str = newCopy( cv.ary[cv.size-1].str );
    ti = clock();
    i = findCvec( &cv, &r2, compare );
    if( i != -1 )
    {
        eraseCvec( &cv, i );
        tp = clock() - ti;
        printf( "%s was erased ...", r2.str);
        printf( "%s is new end str...\n", cv.ary[cv.size-1].str);
        printf( "\nfind/ereaseCvec in %.2f sec's\n", tp/CLOCKS_PER_SEC  );
    }
    else printf( "%s was NOT-found/NOT-erased ...", r2.str);
   
    myShowAll( &cv );
   
    free( r2.str );


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

    takeInChar( "\nPress 'Enter' to continue ... " );
    return 0;
} /* ************************************************************************ */
« Last Edit: October 09, 2016, 07:55:15 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 CvecOfInt.h ... and then CvecOfString ... to sort the same large data file that the above demos did using the function pointers in Cvec_func's.h

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

Need to include ...

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

CvecOfInt.h also includes ... Cvec.h   
http://developers-heaven.net/forum/index.php/topic,2580.msg2861.html#msg2861


Code: [Select]
/* msort_CvecOfInt.c */  /* this version 2016-10-09 */


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


#define FNAME "randInt3M.txt"

#define VEC_CHUNK_SIZE 3000000 /* init Cvec cap to hold 3 Million random int's */
#define HEADER "C program to sort 3 Million random int's from file stored " \
               "in C vector Cvec ...\n"

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


void myShowAll( Cvec* cv )
{
    int i;
    for( i = 0; i < cv->size;  )
    {
        printf( "%6d  ", cv->ary[i].val );
        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 < cv->size - 20 ) ++i;
                for( ; i < cv->size; ++i ) printf( "%6d  ", cv->ary[i].val );
                break;
            }
        }
    }
}



int main( void ) /* ************************************* */
{
    FILE* fp;
    double ti, tp;
    int i, valToFind;
    Rec r;
    Cvec cv;
    initCvec( &cv ); /* Note: MUST initial Cvec v ... for Cvec to work */
   
    puts( HEADER );
   
    ti = clock();
    fp = fopen( FNAME, "r" );
    while( 1 == fscanf( fp, "%d", &r.val ) )
        push_backCvec( &cv, &r ); /* since good Rec was obtained */

    tp = clock() - ti;
    printf( "%d int's were read from file in %.2f sec's ... ",
            cv.size, tp/CLOCKS_PER_SEC  );

    ti = clock();
    msortCvec( &cv );
    tp = clock() - ti;
    printf( "merge sorted in %.2f sec's", tp/CLOCKS_PER_SEC  );
    printf( "\nand isSortedCvec( &v ) = %d\n", isSortedCvec( &cv ) );


    ti = clock();
    uniqueCvec( &cv );
    tp = clock() - ti;
    printf( "\nuniqueCvec in %.2f sec's", tp/CLOCKS_PER_SEC  );
    printf( " ... and isSortedCvec( &cv ) = %d ", isSortedCvec( &cv ) );
    printf( "\n... and isUniqueCvec( &cv ) = %d\n",
            isUniqueCvec( &cv ) & cv.isSorted );
    printf( "\nAfter uniqueCvec: cv.size = %d, cv.cap = %d\n\n", cv.size, cv.cap );
   

    valToFind = cv.ary[cv.size-1].val;
    ti = clock();
    i = findCvec( &cv, valToFind );
    if( i != -1 )
    {
        eraseCvec( &cv, i );
        tp = clock() - ti;
        printf( "%d was erased ...", valToFind);
        printf( "%d is new end val...\n", cv.ary[cv.size-1].val);
        printf( "find/ereaseCvec in %.2f sec's\n\n", tp/CLOCKS_PER_SEC  );
    }
    else printf( "%d was NOT-found/NOT-erased ...\n\n", valToFind );

    myShowAll( &cv );

    printf( "Before clearCvec: cv.size = %d, cv.cap = %d\n", cv.size, cv.cap );
    clearCvec( &cv );
    printf( "After  clearCvec: cv.size = %d, cv.cap = %d\n", cv.size, cv.cap );
   
    fclose( fp );


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

Offline David

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

Need to include ...

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

Note: CvecOfString.h also include readLine.h and Cvec.h
http://developers-heaven.net/forum/index.php/topic,2580.msg2864.html#msg2864   
http://developers-heaven.net/forum/index.php/topic,2580.msg2861.html#msg2861


Code: [Select]
/* msort_CvecOfString.c */  /* this version 2016-10-09 */


/*
   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 Cvec ...\n ... as C strings ...  " \
               "(Note: using CvecOfString.h in this program)\n"

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

void myShowAll( Cvec* cv )
{
    int i;
    for( i = 0; i < cv->size;  )
    {
        printf( "%6s  ", cv->ary[i].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 < cv->size - 20 ) ++i;
                for( ; i < cv->size; ++i ) printf( "%6s  ", cv->ary[i].str );
                break;
            }
        }
    }
}



int main( void ) /* ********************************************************* */
{
    FILE* fp;
    double ti, tp;
    char lastChr, *s;
    int i;
    Rec r, r2;
    Cvec cv;
    initCvec( &cv ); /* Note: MUST initial to work */
    reserveCvec( &cv, 3000000 );

    puts( HEADER );

    ti = clock();
    fp = fopen( "randInt3M.txt", "r" );
    while( (r.str = readWord( fp, 5, " \n", &lastChr )) )
    {
        push_backCvec( &cv, &r ); /* since good Rec was obtained */
        /* // if( cv.size == 32768*4 ) break; // *11 ... to get all num's 0..32767 // */
    }
    tp = clock() - ti;
    printf( "%d int's were read from file in %.2f sec's ... ",
            cv.size, tp/CLOCKS_PER_SEC  );

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


    ti = clock();
    uniqueCvec( &cv );
    tp = clock() - ti;
    printf( "\nuniqueCvec in %.2f sec's", tp/CLOCKS_PER_SEC  );
    printf( " ... and isSortedCvec( &cv ) = %d ", isSortedCvec( &cv ) );
    printf( "\n... and isUniqueCvec( &cv ) = %d\n", isUniqueCvec( &cv ) );
    printf( "\nAfter uniqueCvec: cv.size = %d, cv.cap = %d\n\n", cv.size, cv.cap );


    r2.str = newCopy( cv.ary[cv.size-1].str ); /* 'newCopy' def'd in readWord/readLine */
    ti = clock();
    i = findCvec( &cv, r2.str );
    if( i != -1 )
    {
        eraseCvec( &cv, i );
        tp = clock() - ti;
        printf( "%s was erased ...", r2.str);
        printf( "%s is new end str...\n", cv.ary[cv.size-1].str);
        printf( "\nfind/ereaseCvec in %f sec's\n", tp/CLOCKS_PER_SEC  );
    }
    else printf( "%s was NOT-found/NOT-erased ...", r2.str);

    myShowAll( &cv );

    free( r2.str );
   
   
    ti = clock();
    s =  joinCvec( &cv, "," );
    tp = clock() - ti;
    printf( "\njoinCvec( &cv, \",\" ) 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 Cvec dynamic C string is :" );
    s[70] = 0;
    puts( s );

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

   
    free( s );

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

    takeInChar( "\nPress 'Enter' to continue ... ");
    return 0;
} /* ************************************************************************ */
« Last Edit: October 09, 2016, 08:27:59 AM by David »

Offline David

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

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

#include <iostream>
#include <iomanip>
#include <fstream>
#include <string>
#include <vector>
#include <algorithm> /* re. vector sort, unique */
#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 vector< Employee > myVec;
typedef vector< Employee >::iterator myIter;
typedef vector< 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 myVec& vec )
{
    size_t i = 0;
    for( c_myIter p = vec.begin(); p != vec.end(); ++p )
    {
        cout << "<" << setfill('0') << setw(3) << ++i << "> " << setfill(' ');
        show( *p );
        if( i % 5 == 0 && i != vec.size() ) cout << endl;
    }
    cout << "\nEmployee records on file = " << vec.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( myVec& );
void readFile( myVec& );
bool isValidPhoneNum( const string& );
myIter getNameIgnoreCase( myVec&, const string& );
myIter getNumber( myVec&, const string& );

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



int main() /* ********************* MAIN BEGINS ***************************** */
{
    int choice;
    myVec 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( myVec& vec )
{
    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 )
        )
        {
            vec.push_back( d );
        }
        fin.close();
    }
}

int showMenuGetChoice( myVec& vec )
{
    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( vec );
    else if( num == 2 )
    {
        cout << "Enter the name to find: " << flush;
        getline(cin, tmp);
        myIter it;
        if( (it = getNameIgnoreCase( vec, tmp )) == vec.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( vec, tmp )) == vec.end() )
            cout << tmp << " not found." << endl;
        else
            show( *it );
    }
    //else if( num == 4 ) showAll( vector );
    else if( num == 5 ) sort( vec.begin(), vec.end(), cmpIgnoreCase );
    else if( num == 6 ) sort( vec.begin(), vec.end(), cmpPhone );
else if( num == 7 )
    {
        sort( vec.begin(), vec.end(), cmpWithCase );
        vec.erase( unique(vec.begin(), vec.end()), vec.end() );
    }
    else if( num == 8 ) editDel ( vec );
    else if( num == 9 ) writeSortedUnique( vec );
    /* 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( myVec& 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( myVec& 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( myVec& vec )
{
    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;
        vec.push_back( d );
        cout << "Information has been filed in file " << FILENAME << endl;
    }
    else
    {
        cout << "Aborted ..." << endl;
}

    fout.close();
}

void writeSortedUnique( myVec& vec )
{
    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 */
    sort( vec.begin(), vec.end(), cmpWithCase );
    vec.erase( unique(vec.begin(), vec.end()), vec.end() );

int i = 0;
    for( c_myIter it = vec.begin(); it != vec.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
         << ", vector size " << vec.size() << endl << endl;

    /* and if have Windows OS ... can do this ... */
    system( "notepad SU" FILENAME ); /*compiler concat's text at compile time*/
}

void editDel( myVec& vec )
{
    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( vec, tmp )) == vec.end() )
                cout << tmp << " not found." << endl;
            else
            {
                show( *it );
                reply = getChoice( "Edit/Delete/Abort (e/d/a) ? " );
                if( reply == 'e' ) edit( vec, it );
                else if( reply == 'd' ) del( vec, 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( vec, tmp )) == vec.end() )
                cout << tmp << " not found." << endl;
            else
            {
                show( *it );
                reply = getChoice( "Edit/Delete/Abort (e/d/a) ? " );
                if( reply == 'e' ) edit( vec, it );
                else if( reply == 'd' ) del( vec, 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( myVec& vec, 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( myVec& vec, myIter& it )
{
    for( ; ; )
    {
        int reply = getChoice( "Really delete/abort (d/a) ? " );
        if( reply == 'a' )
        {
            cout << "Delete aborted ..." << flush;
            return;
        }
/* else ... */
        if( reply == 'd' )
        {
vec.erase( it );
            return;
        }
        /* else ... */
        cout << "Enter 'd' and WILL delete ... or 'a' to abort ..." << endl;
    }
}
« Last Edit: August 09, 2011, 01:50:40 PM by David »