Author Topic: CvecOfInt.h, CvecOfString.h, Cvec.h, Cvec_func's.h (with FUNCTION POINTERS)  (Read 74346 times)

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • 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)


These next few pages are an attempt to create a mini-library of helper files to add to C  ... Cvec and Clist ... C emulations of the C++ STL vector and list ...

This 'library' for Cvec, NOW has Cvec_func's.h, that uses function pointers, so you can readily pass in your own compare functions for sorts, searches, etc.  ... of any struct you desire ... And at the end here, I plan to add links to example programs that use Cvec (Cvec.h) ...

Note:  The Clist library is available here ... (also example programs)

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


Note: when you have exhausted these following pages, you may like to see the latest versions of Cvec and Clist in files Cvec2.h and Clist2.h at the following link:

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


« Last Edit: September 06, 2018, 03:05:43 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Here is the core file, Cvec.h. 

Before you load this file, you will need to  ....

typedef a struct ... Rec

for example:
typedef struct
{
   char* str;
} Rec ;

and define a function ... 

void clearRec( Rec* r )  { /* your code to free any dynamic memory goes here */ ; }

for example:
void clearRec( Rec* r )
{
   free( r->str );
}

Also, you will need the function myAssert that is available in readLine.h or readWord.h

Also, you will need stdio.h, stdlib.h and string.h ... which are all included by including either readLine.h or readWord.h (For readLine.h and readWord.h, see below)

Code: [Select]
/* Cvec.h */ /* this version 2016-10-09 */

/*
    BEFORE loading ... you MUST FIRST typedef (struct) Rec  ...
    i.e. typedef a struct/node/element/record as Rec ...
    and define clearRec( Rec* r ); ... so can call clearRec( &(cv->ary[i]) );
*/

#ifndef dwCvec_H
#define dwCvec_H

/* #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
{
    Rec* ary;
    int size;
    int cap; /* capacity*/
    int isSorted;
} Cvec;

/* with these, an address is passed, so NO copy made and/or original updated */
void initCvec( Cvec* ); /* sets ary to NULL and size, cap to 0 and isSorted to 1 */
void push_backCvec( Cvec*, Rec* );
void enlargeCvec( Cvec* );
void reserveCvec( Cvec*, int );
void clearCvec( Cvec* );

void initCvec( Cvec* cv )
{
    cv->ary = NULL;
    cv->size = cv->cap = 0;
    cv->isSorted = 1;
}

void push_backCvec( Cvec* cv, Rec* rc )
{
    if( cv->size == cv->cap ) enlargeCvec( cv );
    /* now add in new Rec ... */
    memcpy( &(cv->ary[cv->size]), rc, sizeof(Rec) );
    /*
    cv->ary[cv->size].name = rc->name;
    cv->ary[cv->size].address = rc->address;
    cv->ary[cv->size].phone = rc->phone;
    */
    ++ cv->size;
    cv->isSorted = 0;
}

/* new array to hold 2x's records ... copies old to new */
void enlargeCvec( Cvec* cv )
{
    void* tmp;
    if( cv->cap ) cv->cap += cv->cap; /* double capacity ... */
    else cv->cap = VEC_CHUNK_SIZE; /* set initial capacity */
    tmp = realloc( cv->ary, cv->cap * sizeof(Rec) );
    if( tmp == NULL )
    {
        clearCvec( cv );
        myAssert( 0, "Error: realloc failed in enlargeCvec..." );
    }
    /* else ... */
    cv->ary = (Rec*) tmp; /* update the base address of cv->ary */
}

void reserveCvec( Cvec* cv, int newCap )
{
    if( newCap > cv->cap )
    {
        void* tmp;
        cv->cap = newCap;
        tmp = realloc(cv->ary, cv->cap * sizeof(Rec) );
        if( tmp == NULL )
        {
            clearCvec( cv );
            myAssert( 0, "Error: realloc failed in reserveCvec..." );
        }
        /* else ... */
        cv->ary = (Rec*) tmp; /* update the base address of cv->ary */
    }
}

void clearCvec( Cvec* cv )
{
    if( cv->size )
    {
        int i;
        for( i = cv->size-1; i >= 0; --i )
            clearRec( &(cv->ary[i]) );
        free( cv->ary );
        initCvec( cv );
    }
}

#endif

 
« Last Edit: October 09, 2016, 06:27:03 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
These next two files, CvecOfInt.h and CvecOfString.h, will each also load in the file Cvec.h above ...

Note that CvecOfString.h first also loads in readLine.h

(Each of CvecOfInt.h and CvecOfString.h, will also include: stdio.h, stdlib.h, string.h, myAssert ...
Note that CvecOfString.h first includes readLine.h which now also defines the function newCopy, to makes a new copy of a C string in new dynamic memory.)


Firstly, CvecOfInt.h

Code: [Select]
/* CvecOfInt.h */  /* this version: 2016-10-07 */

/*
    this version with added isortCvec (still has msortCvec)
    also added isSorted, uniqueCvec, isUniqueCvec, sumCvec, findCvec, eraseCvec
*/


#ifndef dwCvecOfInt_H
#define dwCvecOfInt_H

#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* re. memcpy */

#ifndef myType
#define myType int
#endif


typedef struct
{
    myType val;
} Rec ;

void clearRec( Rec* rc )
{
/* empty here ... since no dynamic memory (as in Cstring) to free ... */
   rc = rc; /* to keep compiler warning nessage supressed ,,, */
}

#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

/* Ok ... NOW can include ... */
#include "Cvec.h"
/* needs stdlib.h, string.h and myAssert & all included above */


/* and these ...*/

void mergeCvec( Cvec*, int, int, int, Cvec* );
void my_msort( Cvec*, int, int, Cvec* );
void msortCvec( Cvec* );
int isSortedCvec( Cvec* );

myType sumCvec( Cvec* );
/* void showCvec( Cvec* ); */
int findCvec( Cvec*, myType ); /* returns index if int value present, else -1 */
void eraseCvec( Cvec*, int ); /* if int index valid, erases element there */
void isortCvec( Cvec* );

void uniqueCvec( Cvec* cv );
int isUniqueCvec( Cvec* cv );


/* * * * * * * * * * * * * * * * mergeCvec sort * * * * * * * * * * * * * * * * * */

void mergeCvec( Cvec* cv, int bot, int mid, int top, Cvec* tmp )
{
    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... */
        if( cv->ary[h1].val < cv->ary[h2].val ) tmp->ary[j++].val = cv->ary[h1++].val;
        else tmp->ary[j++].val = cv->ary[h2++].val;
    }

    /* Note: only one of the two while loops below is executed ... */
    while( h1 <= mid ) tmp->ary[j++].val = cv->ary[h1++].val; /* copy any remaining entries (1st half) */
    while( h2 <= top ) tmp->ary[j++].val = cv->ary[h2++].val; /* copy any remaining entries (2nd half) */

    for( j = 0; j < sz; ++j ) cv->ary[bot+j].val = tmp->ary[j].val; /* copy back sorted tmp vec... */
}
void my_msort( Cvec* cv, int bot, int top, Cvec* tmp )
{
    if( bot == top ) return;
    else
    {
        int mid = ( bot + top ) / 2;
        my_msort( cv, bot, mid, tmp );      /* sort the first ... */
        my_msort( cv, mid + 1, top, tmp );  /* and the second half ...*/
        mergeCvec( cv, bot, mid, top, tmp );    /* now mergeCvec these 2 sorted chunks ... */
    }
}
void msortCvec( Cvec* cv )
{
    if( cv->size > 1 )
    {
        Cvec tmp;
        initCvec( &tmp );
        reserveCvec( &tmp, cv->size );
        my_msort( cv, 0, cv->size-1, &tmp );
        cv->isSorted = 1;
        free( tmp.ary ); /* only free ary mem that held copies of pointers */
    }
}

int isSortedCvec( Cvec* cv )
{
    int size = cv->size;
    while( --size )
        if( cv->ary[size].val < cv->ary[size-1].val ) return 0;
    return 1;
}

myType sumCvec( Cvec* cv )
{
    myType sum = 0;
    int i;
    for( i = cv->size -1; i >= 0; --i ) sum += cv->ary[i].val;
    return sum;
}
/*
void showCvec( Cvec* cv ) // valid here only for int's ...
{
    int i;
    for( i = 0; i < cv->size; ++i ) printf( "%d ", cv->ary[i].val );
}
*/

int findCvec( Cvec* cv, myType value ) /* returns index if present ... else -1 */
{
    int i;
    for( i = 0; i < cv->size; ++i )
        if( cv->ary[i].val == value ) return i;
    /* else if reach here ... */
    return -1;
}

void eraseCvec( Cvec* cv, int index ) /* if index valid, erases element there */
{
    /* int i; */
    if( index < 0 || index >= cv->size )
        { printf( "\nERROR! Index %d out of range 0..%d\n", index, cv->size-1 );
          return; }
    /*
    // for( i = index; i < cv->size-1; ++i ) */
    /* //{ */  /* copy each element above, down one index, so 'index' value 'erased' */
    /* //    cv->ary[i].val = cv->ary[i+1].val;
    //}
    */

    if( index < cv->size-1 )
        memcpy(&cv->ary[index], &cv->ary[index+1], (cv->size-1-index)*sizeof(Rec));
       
    /* now update size and return (by reference, since address passed in) */
    -- cv->size;
}

void isortCvec( Cvec* cv )
{
    int i, j;
    for( i = 1; i < cv->size; ++i ) /* start with an array of just the first 2 elements (if exists) */
    {
        myType cmp = cv->ary[i].val; /* get copy of this new cmp element 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 && cmp < cv->ary[j].val )
        {
            cv->ary[j+1].val = cv->ary[j].val; /* copy element 'up' ... */
            --j; /* decrement j in preparation for next inner loop ... */
        }
        cv->ary[j+1].val = cmp; /* insert element at index j+1 (since j was decremented above) */
    }
    cv->isSorted = 1;
}

void uniqueCvec( Cvec* cv )
{
    int i = 0, j = 1;
    if( !cv->isSorted ) msortCvec( cv );

    for( ; j < cv->size ; ++j )
    {
        if( cv->ary[i].val != cv->ary[j].val )
        {
            ++i;
            if( i != j ) cv->ary[i].val = cv->ary[j].val;
        }
        /* else
            freeRec( &cv->ary[j] ); // NOT needed since NO dynamic memory // */
    }
   
    cv->size = ++i;
}
int isUniqueCvec( Cvec* cv )
{
    int i;
    if( !cv->isSorted ) msortCvec( cv );
    for( i = cv->size-1; i > 0; --i )
        if( cv->ary[i].val == cv->ary[i-1].val ) return 0;
    /* else ... */
    return 1;
}


#endif
« Last Edit: October 08, 2016, 10:00:38 PM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Here is the latest readLine.h which is needed by CvecOfString.h that follows ...

Code: [Select]
/* readLine.h */  /* this version: 2016-10-08 */


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


/*
    Safe string data entry from file ... to replace gets and fgets
    BUT free new memory ... when done! Don't forget that C strings are
    pointers to a block of char, with a '\0' char at the terminal end ...

    Call like this:

        char* line = readLine( stdin );

        or ...

        while( (line = readLine( FILEp )) )
        {
            // process line ...
        }
*/

/* includes stdio.h, stdlib.h, string.h, ctype.h with myAssert, newMen, newCopy and newSubStr functions */

#ifndef dwREADLINE_H
#define dwREADLINE_H

/* can re-set/adjust here to best match your line-length */
#ifndef LINECHUNK
#define LINECHUNK 256
#endif

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h> /* re. isspace in trim ... */


#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


#ifndef dwNEWMEMORY
#define dwNEWMEMORY
char* newMem( int bytes )
{
    char* n = (char*)malloc( bytes ); /* cast for C++ compilers */
    myAssert( (n != NULL), "Error: malloc failed in 'newMem' ... " );
    return n;
}
#endif

#ifndef dwNEWCOPY
#define dwNEWCOPY
char* newCopy( const char* str )
{
    char* n = newMem( strlen(str) + 1 ); /* cast for C++ compilers */
    strcpy( n, str );
    return n;
}
#endif

#ifndef dwNEWSUBSTR
#define dwNEWSUBSTR
char* newsubstr( const char* str, int beg, int len )
{
    char* n = newMem( len + 1 ); /* cast for C++ compilers */
    strncpy( n, str+beg, len );
    n[len] = 0;
    return n;
}
#define newSubStr newsubstr
#endif

#ifndef dwTRIM
#define dwTRIM
char* trim( char* s )
{
    char *start = s, *end = s;
    while( *end ) ++end ;
    if( end == s ) return s; /* empty string */

    for( --end; s <= end && isspace(*end); --end ) ;
    end[1] = 0;
   
    while( isspace(*s) ) ++s;
    memmove( start, s, (end+2-s) ); /* 2 ... to copy terminal 0 */
    return start;
}
char* rtrim( char* s )
{
    char* end = s;
    while( *end ) ++end ;
    if( end == s ) return s; /* empty string */

    for( --end; s <= end && isspace(*end); --end ) ;
    end[1] = 0;
    return s;
}
char* ltrim( char* s )
{
    char *start = s, *end = s;
    while( *end ) ++end ;
    if( end == s ) return s; /* empty string */
   
    while( isspace(*s) ) ++s;
    memmove( start, s, (end+1-s) ); /* 1 ... to copy terminal 0 */
    return start;
}
#define strip trim
#define lstrip ltrim
#define rstrip rtrim
#endif

#ifndef dwUPDOWN
#define dwUPDOWN
char* strToUpper( char* str )
{
char* p = str;
while( *p != 0 ) { *p = toupper(*p); ++p; }
return str;
}

char* strToLower( char* str )
{
char* p = str;
while( *p != 0 ) { *p = tolower(*p); ++p; }
return str;
}

char* strToUpperFirstLetter( char* str )
{
    if( str && strlen(str) )
        str[0] = toupper(str[0]);
    return str;
}

char* strToTitleCase( char* str )
{
    char* p = strToLower(str);
    char prev = ' ';
    while( *p )
    {
        if( isspace(prev) ) *p = toupper( *p );
        prev = *p;
        ++p;
    }
    return str;
}
#endif


#ifndef dwTAKE_IN_CHAR_MORE
#define dwTAKE_IN_CHAR_MORE

/* a handy utility for many C student coding problems ... */
char takeInChar( const char* msg )
{
    char chr;
    printf( msg ); fflush( stdout );
    chr = getchar();
    if( chr != '\n' ) while( getchar() != '\n' ) ; /* flush stdin ... */
    return chr;
}

int more() /* defaults to 'true'/'yes'/'1' ... unless 'n' or 'N' entered */
{
if( tolower( takeInChar( "More (y/n) ? " )) == 'n' ) return 0;
/* else ... */
return 1;
}

#endif

/* returns a string in new memory holding each word ... or NULL if EOF */
char* readLine( FILE* fp  )
{
    int c, cap = LINECHUNK, size = 0; /* c to hold each char ... */
    void* tmp;
    char* strData = (char*) malloc( cap ); /* cast for C++ compilers ... */
   
    myAssert( (strData != NULL), "Error: malloc failed at top of 'readLine' ... " );

    while( (c = fgetc(fp)) != '\n'  &&  c != EOF )
    {
        if( size == cap-1 ) /* skip while size < cap-1 */
        {
            cap += cap; /* double memory capacity ... */
            if( (tmp = realloc(strData, cap)) == NULL )
            {
                free(strData);
                myAssert( 0, "Error: realloc failed in 'readLine' ... " );
            }
            /* else ...  good realloc above, so update strData pointer */
            strData = (char*) tmp;
        }
        /* now ... since reached here ... */
        strData[size++] = c; /* append this char ... */
    }
    strData[size] = 0; /* '\0' terminate */

    if( c == EOF && strData[0] == 0 )  { free(strData); return NULL; }
       
    /* else ... since didn't return NULL above, compact string to right-size */
    if( (tmp = realloc(strData, size+1)) == NULL ) /* size+1 to hold 0 at end */
    {
        free(strData);
        myAssert( 0, "Error: realloc failed in compacting C string ... " );
    }
    return (char*) tmp; /* return the string with NO extra capacity ... */
}

#endif


And the most recent version of the file: "readWord.h"

Code: [Select]
/* readWord.h */  /* this ver 2016-10-09 */


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

/*
    Safe string data entry from file or keyboard ...
    BUT ... free new memory when done with it!
    Don't forget that C strings are pointers to a block of char,
    with a '\0' char at the terminal end ... Call like this:

    char* word = readWord(stdin, 31, "\n\t ,.;:", &lastChr);//note delimiter str

    or ...

    while((word = readWord(FILEp, startChunkSize, delimiterStr, &lastCharRead)))
    {
        // do stuff ...
    }

    Note 1: select your initial word chunk size to minimize calls to realloc
    Note 2: address of last char passed in/out so can flush stdin or file line
*/

#ifndef dwREADWORD_H
#define dwREADWORD_H

#include <stdio.h>
#include <stdlib.h>
#include <string.h> /* re. strchr */
#include <ctype.h> /* re. isspace in trim ... */

#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


#ifndef dwNEWMEMORY
#define dwNEWMEMORY
char* newMem( int bytes )
{
    char* n = (char*) malloc( bytes ); /* cast for C++ compilers */
    myAssert( (n != NULL), "Error: malloc failed in 'newMem' ... " );
    return n;
}
#endif

#ifndef dwNEWCOPY
#define dwNEWCOPY
char* newCopy( const char* str )
{
    char* n = newMem( strlen(str) + 1 ); /* cast for C++ compilers */
    strcpy( n, str );
    return n;   
}
#endif

#ifndef dwNEWSUBSTR
#define dwNEWSUBSTR
char* newsubstr( const char* str, int beg, int len )
{
    char* n = newMem( len + 1 ); /* cast for C++ compilers */
    strncpy( n, str+beg, len );
    n[len] = 0;
    return n;
}
#endif

#ifndef dwTRIM
#define dwTRIM
char* trim( char* s )
{
    char *start = s, *end = s;
    while( *end ) ++end ;
    if( end == s ) return s; /* empty string */

    for( --end; s <= end && isspace(*end); --end ) ;
    end[1] = 0;
   
    while( isspace(*s) ) ++s;
    memmove( start, s, end+2-s ); /* 2 ... to copy terminal 0 */
    return start;
}
char* rtrim( char* s )
{
    char* end = s;
    while( *end ) ++end ;
    if( end == s ) return s; /* empty string */

    for( --end; s <= end && isspace(*end); --end ) ;
    end[1] = 0;
    return s;
}
char* ltrim( char* s )
{
    char *start = s, *end = s;
    while( *end ) ++end ;
    if( end == s ) return s; /* empty string */
   
    while( isspace(*s) ) ++s;
    memmove( start, s, end+1-s ); /* 1 ... to copy terminal 0 */
    return start;
}
#endif

#ifndef dwUPDOWN
#define dwUPDOWN
char* strToUpper( char* str )
{
char* p = str;
while( *p != 0 ) { *p = toupper(*p); ++p; }
return str;
}

char* strToLower( char* str )
{
char* p = str;
while( *p != 0 ) { *p = tolower(*p); ++p; }
return str;
}

char* strToUpperFirstLetter( char* str )
{
    if( str && strlen(str) )
        str[0] = toupper(str[0]);
    return str;
}

char* strToTitleCase( char* str )
{
    char* p = strToLower(str);
    char prev = ' ';
    while( *p )
    {
        if( isspace(prev) ) *p = toupper( *p );
        prev = *p;
        ++p;
    }
    return str;
}
#endif


#ifndef dwTAKE_IN_CHAR_MORE
#define dwTAKE_IN_CHAR_MORE

/* a handy utility for many C student coding problems ... */
char takeInChar( const char* msg )
{
    char chr;
    printf( msg ); fflush( stdout );
    chr = getchar();
    if( chr != '\n' ) while( getchar() != '\n' ) ; /* flush stdin ... */
    return chr;
}

int more() /* defaults to 'true'/'yes'/'1' ... unless 'n' or 'N' entered */
{
if( tolower( takeInChar( "More (y/n) ? " )) == 'n' ) return 0;
/* else ... */
return 1;
}

#endif


/* returns a string into new memory to hold each word ...
  or NULL if EOF */
char* readWord( FILE* fp, int chunk_len, const char delimits[], char* c)
{
    char *strData, *tmp;
    int i = 0; /* i for index in string, *c to hold each char */
    if( chunk_len < 4 )
        chunk_len = 4; /* set to min. starting chunk size */
    else if( chunk_len %4 )
        chunk_len = chunk_len + ( 4 - chunk_len%4 );

    /* cast added for C++ compilers */
    strData = (char*) malloc( chunk_len );
    myAssert( (strData != NULL), "Error: malloc failed in readWord (1)" );

    while( ( *c = fgetc( fp )) != EOF && strchr( delimits, *c ))
        ; /* advance over any whitespace i.e. delimits */
       
    if( *c != EOF ) /* ok ... get this first char ... */
        strData[i++] = *c;
    else
    {
        free( strData );
        return NULL; /* at EOF or all 'delimits' ... */
    }

    while( (*c = fgetc( fp )) != EOF && !strchr( delimits, *c ) )
    {
        if( i == chunk_len-1 ) /* skip while i <= chunk_len-2 */
        {
            chunk_len += chunk_len; /* double memory ...*/
            if( ( tmp = (char*) realloc( strData, chunk_len )) == NULL )
            {
                free( strData );
                myAssert( 0, "Error: realloc failed in readWord (2)" );
            }
            /* if reach here, realloc above was a success,
               so update strData */
            strData = tmp;
        }
        /* now can ... */
        strData[i++] = *c;
    }
    strData[i] = 0; /* assure '\0' termination */

    /* if EOF and empty strData, quit reading file,
       BUT FIRST, free this strData */
    if( *c == EOF && strData[0] == 0  )
        { free( strData ); return NULL; }

    /* else ... and note ... i is index of '\0' */
    if( (tmp = (char*) realloc( strData, i+1 )) == NULL )
    {
        free( strData );
        myAssert( 0, "Error: realloc failed in readWord (3)" );
    }
    /* if reach here, realloc above was a success, program NOT aborted, so ...*/
    return tmp;
}

#endif



And a link to the new takeInLine functions ...

with line input for string, char, int and doubles and with a passed in prompt,
to the particular takeIn function, to guide the input from the keyboard user ...

http://developers-heaven.net/forum/index.php/topic,2580.msg3207.html#msg3207
« Last Edit: October 21, 2016, 12:02:24 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Now ... CvecOfString.h ... to supply all you need to readily handle vectors (expandable dynamic arrays) of dynamic C strings (and readLine, or readWord, let you input C strings almost as easily as C++ strings that use getline) ...


Code: [Select]
/* CvecOfString.h */  /* this version: 2016-10-07 */

/*
    this version with added isortCvec (still has msort)
    also added isSorted, uniqueCvec, isUniqueCvec, showCvec, findCvec, eraseCvec
*/

#ifndef dwCvecOfString_H
#define dwCvecOfString_H

#include "readline.h" /* includes stdio.h, stdlib.h, string.h, <ctype.h>
                         myAssert, newCopy */

typedef struct
{
    char* str;
} Rec ;

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

/* Ok ... NOW can include ... */
#include "Cvec.h"
/* needs stdlib.h, string.h and myAssert & all included above */


/* and these ...*/

void mergeCvec( Cvec*, int, int, int, Cvec* );
void my_msortCvec( Cvec*, int, int, Cvec* );
void msortCvec( Cvec* );
int isSortedCvec( Cvec* );

int findCvec( Cvec*, const char* ); /* returns index if string present, else -1 */
void eraseCvec( Cvec*, int ); /* if int index valid, erases element there */
void isortCvec( Cvec* );
void showCvec( const Cvec* );

void uniqueCvec( Cvec* cv );
int isUniqueCvec( Cvec* cv );

char* joinCvec( Cvec*, const char* );



/* * * * * * * * * * * * * * * * merge sort * * * * * * * * * * * * * * * * * */

void mergeCvec( Cvec* cv, int bot, int mid, int top, Cvec* tmp )
{
    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... */
        if( strcmp(cv->ary[h1].str, cv->ary[h2].str) <= 0 )
            tmp->ary[j++].str = cv->ary[h1++].str;
        else
            tmp->ary[j++].str = cv->ary[h2++].str;
    }

    /* Note: only one of the two while loops below is executed ... */
    while( h1 <= mid ) /* copy any remaining entries (1st half) */
        tmp->ary[j++].str = cv->ary[h1++].str;
    while( h2 <= top ) /* copy any remaining entries (2nd half) */
        tmp->ary[j++].str = cv->ary[h2++].str;

    for( j = 0; j < sz; ++j ) /* copy back sorted tmp vec... */
        cv->ary[bot+j].str = tmp->ary[j].str;
}
void my_msortCvec( Cvec* cv, int bot, int top, Cvec* tmp )
{
    if( bot == top ) return;
    else
    {
        int mid = ( bot + top ) / 2;
        my_msortCvec( cv, bot, mid, tmp );      /* sort the first ... */
        my_msortCvec( cv, mid + 1, top, tmp );  /* and the second half ... */
        mergeCvec( cv, bot, mid, top, tmp );    /* now merge these 2 sorted chunks ... */
    }
}
void msortCvec( Cvec* cv )
{
    if( cv->size > 1 )
    {
        Cvec tmp;
        initCvec( &tmp );
        reserveCvec( &tmp, cv->size );
        my_msortCvec( cv, 0, cv->size-1, &tmp );
        cv->isSorted = 1;
        free( tmp.ary ); /* only free ary mem that held copies of pointers */
    }
}

int isSortedCvec( Cvec* cv )
{
    int size = cv->size;
    while( --size )
        if( strcmp(cv->ary[size].str, cv->ary[size-1].str) < 0 ) return 0;
    return 1;
}

int findCvec( Cvec* cv, const char* s ) /* returns index if present ... else -1 */
{
    int i;
    for( i = 0; i < cv->size; ++i )
        if( strcmp(cv->ary[i].str, s) == 0 ) return i;
    /* else if reach here ... */
    return -1;
}

void eraseCvec( Cvec* cv, int index ) /* if index valid, erases element there */
{
    /* int i; */
    if( index < 0 || index >= cv->size )
        { printf( "\nERROR! Index %d out of range 0..%d\n", index, cv->size-1 );
          return; }
         
    clearRec( &(cv->ary[index]) ); /* needed here for dynamic memory types */
   
    /* copy each pointer above down one index */
    /* //for( i = index; i < cv->size-1; ++i )
        //cv->ary[i].str = cv->ary[i+1].str;
    //if( index < cv->size-1 ) */
    memcpy(&cv->ary[index], &cv->ary[index+1], (cv->size-1-index)*sizeof(Rec));

    /* now update size and return (by reference, since address passed in) */
    -- cv->size;
}

void isortCvec( Cvec* cv )
{
    int i, j;
    for( i = 1; i < cv->size; ++i ) /* start with an array of just the first 2 elements (if exists) */
    {
        char* cmp = cv->ary[i].str; /* 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 && strcmp(cmp, cv->ary[j].str) < 0 )
        {
            cv->ary[j+1].str = cv->ary[j].str; /* copy pointer 'up' ... */
            --j; /* decrement j in preparation for next inner loop ... */
        }
        cv->ary[j+1].str = cmp; /* insert pointer at index j+1 (since j was decremented above) */
    }
    cv->isSorted = 1;
}

void showCvec( const Cvec* cv )
{
    int i;
    for(  i = 0; i < cv->size; ++i ) printf( "%s ", cv->ary[i].str );
}

void uniqueCvec( Cvec* cv )
{
    if( cv->size > 1 )
    {
        int i = 0, j = 1;
        if( !cv->isSorted ) msortCvec( cv );

        for( ; j < cv->size ; ++j )
        {
            if( strcmp( cv->ary[i].str, cv->ary[j].str ) != 0 )
            {
                ++i;
                if( i != j ) cv->ary[i].str = cv->ary[j].str;
            }
            else clearRec( &cv->ary[j] );
        }
       
        cv->size = ++i;
    }
}
int isUniqueCvec( Cvec* cv )
{
    int i;
    if( !cv->isSorted ) msortCvec( cv );
    for( i = cv->size-1; i > 0; --i )
        if( strcmp( cv->ary[i].str, cv->ary[i-1].str ) == 0 ) return 0;
    /*  else ... */
    return 1;
}

char* joinCvec( Cvec* cv, const char* s )
{
    char* concatStr;
    int i, sumsize = 0;
    int add = strlen( s );
    for( i = 0; i < cv->size; ++i ) sumsize += strlen(cv->ary[i].str) + add;
    concatStr = (char*) malloc( sumsize-add+1 );
    myAssert( (concatStr != NULL), "Error, malloc failed to allocate memory for concatStr" );
    concatStr[0] = 0;
    for( i = 0; i < cv->size; ++i )
    {
        strcat( concatStr, cv->ary[i].str );
        if( i < cv->size-1 ) strcat( concatStr, s );
    }
    return concatStr;
}

#endif
« Last Edit: October 08, 2016, 10:01:41 PM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
And finally, this is the NEW version ... with FUNCTION POINTERS ... to handle C vectors (Cvec) of any struct you make ...

At the top, include stdio.h, stdlib.h, string.h ... (Note: these are all included if you include the file readLine.h or the file readWord.h)

And then ...you will first need to typedef your struct ... Rec and define your freeVrec functions (as above) ...

Also ... #include "Cvec.h"

Then you can ... #include "Cvec_func's.h"

Also ... you will need to define your compare Rec function(s) ... before your call ...

Code: [Select]
/* your compare function prototype(s) looks like this */
int myCompare( const Rec* a, const Rec* b );


Code: [Select]
/* Cvec_func's.h */  /* 2016-10-07 */

/*
    this ver:   using function pointers ...
                msortCvec, isortCvec, isSortedCvec, UniqueCvec,
                isUniqueCvec, findCvec, eraseCvec (i.e. erase Rec)
*/

#ifndef dwCvec_funcs_H
#define dwCvec_funcs_H


/* function protoypes ...*/

void mergeCvec( Cvec* cv, int bot, int top, Cvec* tmp,
                int (*myCmp) (const Rec* a, const Rec* b) );
void my_msortCvec( Cvec* cv, int bot, int top, Cvec* tmp,
                   int (*myCmp) (const Rec* a, const Rec* b) );
void msortCvec( Cvec* cv, int (*myCmp) (const Rec* a, const Rec* b) );

void isortCvec( Cvec*, int (*myCmp) (const Rec* , const Rec*) );

int isSortedCvec( Cvec*, int (*myCmp) (const Rec*, const Rec*) );

void uniqueCvec( Cvec*, int (*myCmp) (const Rec*, const Rec*) );
int isUniqueCvec( Cvec* cv, int (*myCmp) (const Rec* a, const Rec* b) );

/* returns index if string present, else -1 */
int findCvec( Cvec*, const Rec*, int (*myCmp) (const Rec*, const Rec*) );
/* if int index valid, erases element there ... ( Note: --size but same cap ) */
void eraseCvec( Cvec*, int );



/* function definitions ...*/

void mergeCvec( Cvec* cv, int bot, int top, Cvec* tmp,
            int (*myCmp) (const Rec* a, const Rec* 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->ary[h2]) ) <= 0  )
            tmp->ary[j++] = cv->ary[h1++];
        else
            tmp->ary[j++] = cv->ary[h2++];
    }
    /* Note: only one of the two 'while's' below is executed ... */
    while( h1 <= mid ) /* copy any remaining entries (1st half) */
        tmp->ary[j++] = cv->ary[h1++];
    while( h2 <= top ) /* copy any remaining entries (2nd half) */
        tmp->ary[j++] = cv->ary[h2++];

    for( j = 0; j < sz; ++j ) /* copy back sorted tmp vec... */
        cv->ary[bot+j] = tmp->ary[j];
}
void my_msortCvec( Cvec* cv, int bot, int top, Cvec* tmp,
               int (*myCmp) (const Rec* a, const Rec* 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 Rec* a, const Rec* b) )
{
    if( cv->size > 1 )
    {
        Cvec tmp;
        initCvec( &tmp );
        reserveCvec( &tmp, cv->size ); /* Note: resets cap, BUT size still 0 */
        my_msortCvec( cv, 0, cv->size-1, &tmp, myCmp );
        cv->isSorted = 1;
        free( tmp.ary ); /* only free ary mem that held copies of pointers */
    }
}


int isSortedCvec( Cvec* cv, int (*myCmp) (const Rec* a, const Rec* b) )
{
    int size = cv->size;
    while( --size )
        if( myCmp(&cv->ary[size], &cv->ary[size-1]) < 0 ) return 0;
    return 1;
}


void uniqueCvec( Cvec* cv, int (*myCmp) (const Rec* a, const Rec* b) )
{
    if( cv->size > 1 )
    {
        int i = 0, j = 1;
        if( !isSortedCvec( cv, myCmp ))
            msortCvec( cv, myCmp ); /* first make sure, name-sorted order by case */
           
        for( ; j < cv->size ; ++j )
        {
            if( myCmp( &cv->ary[i], &cv->ary[j] ) != 0 )
            {
                ++i;
                if( i != j ) memcpy( &cv->ary[i], &cv->ary[j], sizeof(Rec) );
            }
            else clearRec( &cv->ary[j] );
        }
       
        cv->size = ++i;
    }
}
int isUniqueCvec( Cvec* cv, int (*myCmp) (const Rec* a, const Rec* b) )
{
    int i;
    if( !cv->isSorted ) msortCvec( cv, myCmp );
   
    for( i = cv->size-1; i > 0; --i )
        if( myCmp( &cv->ary[i], &cv->ary[i-1] ) == 0 ) return 0;
    /* else ... */
    return 1;
}

/* returns index if string present, else -1 */
int findCvec( Cvec* cv, const Rec* r, int (*myCmp) (const Rec* a, const Rec* b) )
{
    int i;
    for( i = 0; i < cv->size; ++i )
        if( myCmp(&cv->ary[i], r) == 0 ) return i;
    /* else if reach here ... */
    return -1;
}

/* if int index valid, erases element there */
void eraseCvec( Cvec* cv, int index )
{
    /* int i; */
    if( index < 0 || index >= cv->size )
        { printf( "\nERROR! Index %d out of range 0..%d\n", index, cv->size-1 );
          return; }

    clearRec( &(cv->ary[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[index], &cv->ary[index+1], (cv->size-1-index)*sizeof(Rec));

    /* now update size and return (by reference, since address passed in) */
    -- cv->size;
}

void isortCvec( Cvec* cv, int (*myCmp) (const Rec* a, const Rec* b) )
{
    int i, j;
    Rec cmp;
    for( i = 1; i < cv->size; ++i ) /* start with an array of just the first 2 elements (if exists) */
    {
        memcpy( &cmp, &cv->ary[i], sizeof(Rec) ); /* 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[j]) < 0 )
        {
            memcpy( &cv->ary[j+1], &cv->ary[j], sizeof(Rec) ); /* copy pointer 'up' ... */
            --j; /* decrement j in preparation for next inner loop ... */
        }
        memcpy( &cv->ary[j+1], &cmp, sizeof(Rec) ); /* insert pointer at index j+1 (since j was decremented above) */
    }
    cv->isSorted = 1;
} /* size hasn't changed ... */


#endif
« Last Edit: October 21, 2016, 12:06:54 AM by David »

Offline David

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

you will, below, need the LARGE data file,

"randInt3M.txt",

produced, if missing, by the compiled/running main function in the following linked program:

http://developers-heaven.net/forum/index.php/topic,2581.msg2870.html#msg2870


These next pages provide links to example programs that use the above Cvec.h files ...

1. An example that uses 3 dynamic C strings in the struct Rec ... employee records from file into a Cvec ... that also demos using the function pointers in Cvec_func's.h

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

Also see ...
http://www.dreamincode.net/forums/topic/248797-phonebook-in-c-questions/page__view__findpost__p__1446935

and ...
http://developers-heaven.net/forum/index.php/topic,2022.msg2911.html#msg2911

2. Example programs of a Cvec of int and then a Cvec of dynamic C strings of a large data file ... that also demos using the function pointers in Cvec_func's.h

http://developers-heaven.net/forum/index.php/topic,2581.msg2870.html#msg2870

Cvec of dynamic C strings of SAME large data file ..
http://developers-heaven.net/forum/index.php/topic,2581.msg2871.html#msg2871
« Last Edit: October 17, 2016, 01:46:59 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
3. Example programs, like the 2 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) ...
http://developers-heaven.net/forum/index.php/topic,2581.msg2873.html#msg2873

Then, using CvecOfString.h (NO function pointers passed here) ...
http://developers-heaven.net/forum/index.php/topic,2581.msg2873.html#msg2874


An upgraded dynamic C string demo follows here ...
http://developers-heaven.net/forum/index.php/topic,2582.msg3142.html#msg3142
« Last Edit: June 21, 2015, 06:33:49 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Ok ... a new takeInLine.h file that and uses (includes) the above file: readLine.h

and for example, for integers, accepts ONLY integers in the VALID range an int can hold.

Has function calls:
    char* takeInLine( const char* msg );
    char* takeInLineNotBlank( const char* msg );
    char* takeInLineMaxLen( const char* msg, unsigned maxLen );
    int takeInInt( const char* prompt );
    int takeInIntMinMax( const char* prompt, int min, int max );
    int takeInIntPosMax( const char* prompt, int max );
    double takeInDouble( const char* prompt );
    double takeInDoubleMinMax( const char* prompt, double min, double max );
    double takeInDoublePosMax( const char* prompt, double max );

(and followiing, please see several new programs that demo using these functions in this new file: takeInLine)

Code: [Select]
/* takeInLine.h */  /* 2016-10-19 */

#ifndef dwTAKE_IN_LINE_H
#define dwTAKE_IN_LINE_H


#include "readLine.h"
#include <math.h>
#include <limits.h>

#define MAX_DIG_IN_INT (int)log10(INT_MAX) + 1.
#define ERR_BLANK_LINE "\nBlank line NOT valid input here!\n"


char* takeInLine( const char* msg )
{
    fputs( msg, stdout );
    fflush( stdout );
    return readLine( stdin );
}

char* takeInLineNotBlank( const char* msg )
{
    char* line = NULL;
    for(  ; ; )
    {
        line = takeInLine( msg );
        if( line[0] ) /* i.e. if NOT BLANK LINE ... */
            break;
        /* else ... */
        printf( ERR_BLANK_LINE );
        free( line );
    }
    return line;
}

/* using readLine and getting new dynamic memory  ... so can return address */
/* LOOPS until entered line_length > 0 and line_length <= maxLen ... */
char* takeInLineMaxLen( const char* msg, unsigned maxLen )
{
    char* line = NULL;
    for( ; ; )
    {
        line = takeInLineNotBlank( msg );

        if( strlen( line ) <= maxLen )
            break;
        /* else ... */
        printf( "\nFor '%s', maximum length of %u char's was exceeded!\n",
                line, maxLen );
        free( line );
    }
    return line;
}

/*  returns a valid int in range INT_MIN..INT_MAX */
int takeInInt( const char* prompt )
{
    /* make extra large to hold 10 chars & sign & terminal '\0' char */
    char loc_buf[16];
    int tmpInt;

    for( ; ; ) /* an example of a C/C++ forever loop ... until 'return' */
    {
        int good = 1, i = 0, len = 0, sign = 1;
        char* tmp = takeInLineNotBlank( prompt );
        char* tmpCpy = tmp;

        if( tmp[0] == '+' )
            ++tmp;
        else if( tmp[0] == '-')
        {
            ++tmp;
            sign = -1;
        }

        len = i = strlen( tmp );
        /* check len ok ... */
        good = ( len <= MAX_DIG_IN_INT );
        /* check all digits (after any single leading sign) ... */
        while( good && --i >= 0 )
            good = isdigit( tmp[i] );
        /* check in range that can be held by an int ... */
        if( good && len == MAX_DIG_IN_INT )
        {
            if( sign == 1 )
            {
                sprintf( loc_buf, "%d", INT_MAX );
                if( strcmp( tmp, loc_buf ) > 0 )
                    good = 0;
            }
            else
            {
                sprintf( loc_buf, "%d", INT_MIN );
                if( strcmp( tmp, &loc_buf[1] ) > 0 )
                    good = 0;
            }
        }

        if( good )
        {
            tmpInt = atoi( tmpCpy );
            free( tmpCpy );
            break;
        }
        /* else ...*/
        printf( "\n'%s' is NOT valid input here!\n", tmpCpy ) ;
        free( tmpCpy );
    }
    return tmpInt;
}


/*  returns a valid int in range min..max */
int takeInIntMinMax( const char* prompt, int min, int max )
{
    int tmpInt;
    for( ; ; ) /* an example of a C/C++ forever loop ... until 'return' */
    {
        tmpInt = takeInInt( prompt );
        if( tmpInt >= min && tmpInt <= max )
            break;
        /* else ...*/
        printf( "\nValid input here is an integer in range %d..%d!\n",
                min, max );
    }
    return tmpInt;
}

/* accepts only int's in range 0..max */
int takeInIntPosMax( const char* prompt, int max )
{
    return takeInIntMinMax( prompt, 0, max );
}


double takeInDouble( const char* prompt )
{
    char buf[80];
    double val = 0;
    for( ; ; )
    {
        char* line = takeInLineNotBlank( prompt );

        if( sscanf( line, "%lf%s", &val, buf ) == 1 )
        {
            free( line );
            break;
        }
        /* else .. */
        printf( "\n'%s' is NOT valid input here!\n", line );
        free( line );
    }
    return val;
}

/*  returns a valid decimal in range min..max */
double takeInDoubleMinMax( const char* prompt, double min, double max )
{
    double val;
    for( ; ; ) /* an example of a C/C++ forever loop ... until 'return' */
    {
        val = takeInDouble( prompt );
        if( val >= min && val <= max )
            break;
        /* else ...*/
        printf( "\nValid input here is a decimal value in range %.2e..%.2e!\n",
                min, max );
    }
    return val;
}

/* accepts only deciamal's in range 0..max */
double takeInDoublePosMax( const char* prompt, double max )
{
    return takeInDoubleMinMax( prompt, 0, max );
}

#endif


And a little test program:

Code: [Select]
/* test_takeInLine.c */  /* 2016-10-20 */


#include "takeInLine.h" /* includes file readLine.h and that has ... */


const char* getSex( const char sex )
{
    if( sex == 'M' )
        return "MALE";
    return "FEMALE";
}



int main()
{
    char gender;
    int id;
    double amount;
    do
    {
        char* name = strToTitleCase(takeInLineMaxLen( "Enter student name:  ", 80 ));
        for ( ; ; )
        {
            gender = toupper(takeInChar( "Enter gender (m/f) "));
            if( gender == 'M' || gender == 'F' )
                break;
            /* else ... */
            puts( "Must enter either of m or f to proceed." );
        }
        id = takeInIntMinMax( "Enter ID in range 1..999  :  ", 1, 999 );
        amount = takeInDoublePosMax( "Enter $ amount tution due in range 0..100000:  ", 100000 );

        printf( "Name: %s, Gender: %s, ID: %d, Tution Due: %.2f dollars.\n",
                name, getSex(gender), id, amount );

        printf( "\nOn to next student?\n" );
        printf( "Whenever you are ready, enter y or n, " );
        printf( "or just press the Enter key for 'y'.\n" );

        free( name );
    }
    while( more() );

    return 0;
}
« Last Edit: October 21, 2016, 12:16:59 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
1.
Code: [Select]
/* more2.c */  /* 2016-10-07 */


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


#include "takeInLine.h" /* uses/needs custom file: "readLine.h" */



int main()
{
    int count = 0;
    double sum = 0.0;
   
    for( ; ; ) /* an example C/C++ forever loop ... until 'break' */
    {
        int testInt = takeInInt( "Enter next integer to sum: " );
        ++count;
        sum += testInt;
        if( !more() ) break;
    }
   
    printf( "\nFor %d numbers entered, sum was %.0f and average was %.2f\n",
            count, sum, sum/count );
           
    takeInChar( "\nPress 'Enter' to continue/exit ... " );
    return 0;
}


2.
Code: [Select]
/* arrayInt2.c */  /* 2016-10-07 */


/* enters integer data, finds sum, average, sorts, finds value, erase, show ...*/

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


#include "takeInLine.h" /* uses/needs custom file: "readLine.h" */

#define MAX_SIZE 6 /* using a small size here for simple testing purposes ... */


long sumAry( const int ary[], int size )
{
    long sum = 0;
    for(  --size; size >= 0; --size ) sum += ary[size];
    return sum;
}

void showAry( const int ary[], int size )
{
    int i;
    for( i = 0; i < size; ++i ) printf( "%d ", ary[i] );
}

int findAry( const int ary[], int size, int value ) /* if found, returns index */
{
    int i;
    for( i = 0; i < size; ++i )
        if( ary[i] == value ) return i;
    /* else if reach here ... */
    return -1;
}

void eraseAry( int ary[], int* size, int index ) /* if valid index erase element */
{
    int i;
    if( index < 0 || index >= *size )
        { printf( "\nERROR! Index %d out of range 0..%d\n", index, *size-1 );
          return; }
    for( i = index; i < *size-1; ++i )
        ary[i] = ary[i+1]; /* copy each element above, down one index, so erased */
    /* now update size and return new size ... (by ref.) */
    -- *size;
}

void isortAry( int ary[], int size )
{
    int i, j, cmp;
    for( i = 1; i < size; ++i ) /* start with an array of just the first 2 elements (if exists) */
    {
        cmp = ary[i]; /* get copy of this new cmp element 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 && cmp < ary[j] )
        {
            ary[j+1] = ary[j]; /* copy element 'up' ... */
            --j; /* decrement j in preparation for next inner loop ... */
        }
        ary[j+1] = cmp; /* insert element at index j+1 (since j was decremented above) */
    }
}



int main()
{
    int my_ary[ MAX_SIZE ]; /* create array to hold upto MAX_SIZE int's */
    int i = 0, index, last;
    long sum;       
    do
    {
        my_ary[i] = takeInInt( "Enter next integer to sum: " );
        ++i;
        if( i == MAX_SIZE )
        {
            printf( "You have reached %d, the max size.\n", MAX_SIZE );
            break;
        }
    }
    while( more() ); /* make sure stdin is 'empty' before calling more() */
   
    sum = sumAry( my_ary, i );
   
    printf( "\nFor %d numbers entered, sum was %ld and array average was %.2f\n",
            i, sum, (float)sum/i );
         
    printf( "\nshowAry: " ); showAry( my_ary, i );
   
    last = my_ary[i-1];
   
    printf( "\n\nAfter sorting ..." );
    isortAry( my_ary, i );
    printf( "\nshowAry: " ); showAry( my_ary, i );
         
    index = findAry( my_ary, i, last );
    if( index >= 0 )
    {
        /* Note: below, need to pass address of i ... so i can be updated */
        eraseAry( my_ary, &i, index );

        printf( "\n\nAfter erasing %d ...", last );
        printf( "\nshowAry: " ); showAry( my_ary, i );
    }
    else printf( "%d NOT found in my_ary.\n", last );
                   
    takeInChar( "\nPress 'Enter' to continue/exit ... " );
    return 0;
}


3.
Code: [Select]
/* CvecInt2.c */  /* 2016-10-07 */


/* enters integer data, finds sum, average, sorts, finds value, erase, show ...*/

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


#include "CvecOfInt.h" /* uses/needs custom file: "Cvec.h" */
#include "takeInLine.h" /* uses/needs custom file: "readLine.h" */


void showCvec( Cvec* cv )
{
    Rec* p = cv->ary;
    for( ; p != &cv->ary[cv->size]; ++p ) printf( "%d ", p->val );
    printf( "\nsizeCvec = %d\n", cv->size );
}



int main()
{
    int index, last;
    long sum;
    Cvec cv; /* create CvecOfInt to hold all the int's to be input */
    Rec tmp; /* typedef struct ... Rec has int member 'val' ... */
    initCvec( &cv );     
    do
    {
        tmp.val = takeInInt( "Enter next integer to sum: " );
        push_backCvec( &cv, &tmp );
    }
    while( more() ); /* make sure stdin is 'empty' before calling more() */
   
    sum = sumCvec( &cv );
   
    printf( "\nFor %d numbers entered, sum was %ld and Cvec average was %.2f\n",
            cv.size, sum, (float)sum/cv.size );
         
    printf( "\nshowCvec: " ); showCvec( &cv );
   
    last = cv.ary[ cv.size-1 ].val;
   
    msortCvec( &cv );
    printf( "\nAfter msort ... " );
    printf( "isSortedCvec( &cv ) = %d\n", isSortedCvec( &cv ) );
    printf( "showCvec: " ); showCvec( &cv );
         
    index = findCvec( &cv, last );
    if( index >= 0 )
    {
        eraseCvec( &cv, index );

        printf( "\nAfter erasing %d ...", last );
        printf( "\nshowCvec: " ); showCvec( &cv );
    }
    else printf( "\n%d NOT found in Cvec.\n", last );
   
    tmp.val = takeInInt( "\nEnter a new integer to isort: " );
    push_backCvec( &cv, &tmp );
    isortCvec( &cv );
    printf( "After isortCvec ... " );
    printf( "isSortedCvec( &cv ) = %d\n", isSortedCvec( &cv ) );
    printf( "showCvec: " ); showCvec( &cv );   
   
   
    clearCvec( &cv );
    printf( "\nAfter clearCvec ...\n" );
    printf( "The size of Cvec is now %d\n", cv.size );   
                   
    takeInChar( "\nPress 'Enter' to continue/exit ... " );
    return 0;
}


4.
Code: [Select]
/* CvecString2.c */  /* 2016-10-07 */


/* enters dynamic C string data,  sorts, finds value, erase, show ...*/

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


#include "CvecOfString.h" /* uses/needs custom files: "Cvec.h", "readLine.h" */
#include "takeInLine.h" /* ALSO ...     uses/needs custom file: "readLine.h" */


void showLines( const Cvec* cv )
{
    int i;
    for( i = 0; i < cv->size; ++ i ) printf( "%s\n", cv->ary[i].str );
}


int main()
{
    char last[80];
    Cvec cv;
    Rec rc;
    int index;
    initCvec( &cv );
    do
    {
        rc.str = takeInLine( "Enter a line of text: " );
        push_backCvec( &cv, &rc );
    }
    while( more() ); /* make sure stdin is 'empty' before calling more() */
   
    printf( "\nshowLines:\n" ); showLines( &cv );
    printf( "isSortedCvec( &cv ) = %d\n", isSortedCvec( &cv ) );

    strcpy( last, cv.ary[ cv.size - 1 ].str );
   
    printf( "\nAfter sorting ..." );
    isortCvec( &cv );
    printf( "\nshowLines:\n" );
    showLines( &cv );
    printf( "isSortedCvec( &cv ) = %d\n", isSortedCvec( &cv ) );
   
    index = findCvec( &cv, last );
    if( index >= 0 )
    {
        /* Note: below, need to pass address of i ... so i can be updated */
        eraseCvec( &cv, index );

        printf( "\nAfter erasing '%s'\n", last );
        printf( "showLines:\n" ); showLines( &cv );
    }
    else printf( "%s NOT found in my_ary.\n", last );
   
    /* free all dynamic C strings ... */
    clearCvec( &cv );

    takeInChar( "\nPress 'Enter' to continue/exit ... " );
    return 0;
}


5.
Code: [Select]
/* CvecPrson2.c */  /* 2016-10-07 */


/* enters dynamic C string data,  sorts, finds value, erase, show ...*/

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


#include "takeInLine.h"  /* uses/needs file: readLine.h */


typedef struct Person
{
    char* name;
    char* phone;
} Rec;

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

/* OK ... NOW can include both these 2 */
#include "Cvec.h"
#include "Cvec_func's.h"


void showLines( const Cvec* cv )
{
    int i;
    for( i = 0; i < cv->size; ++i )
        printf( "%s, %s\n", cv->ary[i].name, cv->ary[i].phone );
}

int cmpNames( const Rec* a, const Rec* b )
{
    return strcmp( a->name, b->name );
}

char* toCapsFirstLetter( char* str )
{
    if( str && strlen(str) )
        str[0] = toupper(str[0]);
    return str;
}



int main()
{
    int i;
    Cvec cv;
    Rec rc;
    initCvec( &cv );
   
    for( ; ; )
    {
        rc.name = toCapsFirstLetter(takeInLineMaxLen( "Enter name: ", 80 ));
        rc.phone = takeInLine( "Enter phone: " );
        push_backCvec( &cv, &rc );

        if( !more() ) /* make sure stdin is 'empty' before calling more() */
            break;
    }
         
    printf( "\nshowLines:\n" ); showLines( &cv );
   
    rc.name = cv.ary[cv.size-1].name;
    rc.phone = cv.ary[cv.size-1].phone;

    printf( "\nAfter sorting by name ..." );
    msortCvec( &cv, cmpNames );
    printf( "\nshowLines:\n" );
    showLines( &cv );

    i = findCvec( &cv, &rc, cmpNames );
    if( i >= 0 )
    {
        printf( "\nNOW erasing: '%s, %s'\n", rc.name, rc.phone );
        eraseCvec( &cv, i );
        printf( "showLines:\n" ); showLines( &cv );
    }
    else printf( "%s NOT found in lines.\n", rc.name );

    /* free all dynamic C strings ... */
    clearCvec( &cv );

    takeInChar( "\nPress 'Enter' to continue/exit ... " );
    return 0;
}
« Last Edit: October 08, 2016, 10:18:39 PM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
6.
Code: [Select]
/* ClistInt2.c */  /* 2016-10-07 */


/* enters integer data, finds sum, average, sorts, finds value, erase, show ...*/

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


#include "ClistOfInt.h" /* uses/needs custom file: "Clist.h" */
#include "takeInLine.h" /* uses/needs custom file: "readLine.h" */


void showClist( Clist* cl )
{
    pNode p = cl->start;
    for( ; p != NULL; p = p->next ) printf( "%d ", p->val );
    printf( "size = %d", cl->size );
}



int main()
{
    int last;
    long sum;
    pNode p;
    Clist cl; /* create ClistOfInt to hold all the int's to be input */   
    initClist( &cl );     
    do
    {
        Node tmp; /* typedef struct ... List has int member 'val' ... */
        tmp.val = takeInInt( "Enter next integer to sum: " );
        push_backClist( &cl, &tmp );
    }
    while( more() ); /* make sure stdin is 'empty' before calling more() */
   
    sum = sumClist( &cl );
   
    printf( "\nFor %d numbers entered, sum was %ld and list average was %.2f\n",
            cl.size, sum, (float)sum/cl.size );
         
    printf( "\nshowClist: " ); showClist( &cl );
   
    last = cl.end->val;
   
    msortClist( &cl );
    printf( "\n\nAfter merge sorting ..." );
    printf( "isSortedClist( &cl ) = %d\n", isSortedClist( &cl ) );
    printf( "\nshowClist " ); showClist( &cl );
         
    p = findClist( &cl, last );
    if( p != NULL )
    {
        eraseClist( &cl, p );

        printf( "\n\nAfter erasing %d ...", last );
        printf( "\nshowClist: " ); showClist( &cl );
    }
    else printf( "%d NOT found in Clist.\n", last );
   
   
    clearClist( &cl );
    printf( "\n\nAfter clearClist ...\n" );
    showClist( &cl );
                   
    takeInChar( "\nPress 'Enter' to continue/exit ... " );
    return 0;;
}


7.
Code: [Select]
/* ClistString2.c */  /* 2016-10-07 */


/* enters dynamic C string data,  sorts, finds value, erase, show ...*/

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


#include "ClistOfString.h" /* uses/needs custom files: "Clist.h", "readLine.h" */
#include "takeInLine.h" /* uses/needs custom file: "readLine.h" */


void showLines( const Clist* cl )
{
    pNode p = cl->start;
    for( ; p != NULL; p = p->next ) printf( "%s\n", p->str );
}



int main()
{
    char last[80];
    Clist cl;
    Node nd;
    pNode p;
    initClist( &cl );
   
    do
    {
        nd.str = takeInLine( "Enter line of text: " );
        push_backClist( &cl, &nd );
    }
    while( more() ); /* make sure stdin is 'empty' before calling more() */
         
    printf( "\nshowLines:\n" ); showLines( &cl );

    strcpy( last, cl.end->str );
   
    printf( "\nAfter sorting ..." );
    msortClist( &cl );
    printf( "\nshowLines:\n" );
    showLines( &cl );
   
    p = findClist( &cl, last );
    if( p )
    {
        eraseClist( &cl, p );

        printf( "\nAfter erasing '%s'\n", last );
        printf( "showLines:\n" ); showLines( &cl );
    }
    else printf( "%s NOT found in my_ary.\n", last );
   
    /* free all dynamic C strings ... */
    clearClist( &cl );

    takeInChar( "\nPress 'Enter' to continue/exit ... " );
    return 0;
}


8.
Code: [Select]
/* ClistPrson2.c */  /* 2016-10-07 */


/* enters dynamic C string data,  sorts, finds value, erase, show ...*/

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


#include "takeInLine.h" /* uses/needs custom file: "readLine.h" */


typedef struct Person
{
    char* name;
    char* phone;
    struct Person* next;
} Node;

typedef Node* pNode;

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

/* OK ... NOW can include both these 2 */
#include "Clist.h"
#include "Clist_func's.h"


void showLines( const Clist* cl )
{
    pNode p = cl->start;
    for( ; p != NULL; p = p->next ) printf( "%s, %s\n", p->name, p->phone );
}

int cmpNames( const pNode a, const pNode b )
{
    return strcmp( a->name, b->name );
}

char* toTitleCase( char* str )
{
    char* p = str;
    char prev = ' ';
    while( *p )
    {
        if( prev == ' ' ) *p = toupper( *p );
        prev = *p;
        ++p;
    }
    return str;
}

int allDigits( const char* str )
{
    int len = strlen(str);
    while( len--  ) if( !isdigit(str[len] )) return 0;
    return 1;
}



int main()
{
    Clist cl;
    Node nd;
    pNode p, plast;
    initClist( &cl );
   
    for( ; ; )
    {
        nd.name = toTitleCase( takeInLineMaxLen( "Enter name: ", 80 ) );
        for( ; ; )
        {
            nd.phone = takeInLine( "Enter phone: " );
            if( allDigits(nd.phone) && 10 == strlen(nd.phone) ) break;
            /* else ...*/
            free( nd.phone );
            puts( "Phone number must be 10 digits!" );
        }
       
        push_backClist( &cl, &nd );

        if( !more() ) /* make sure stdin is 'empty' before calling more() */
            break;
    }
         
    printf( "\nshowLines:\n" ); showLines( &cl );
   
    plast = cl.end;

    printf( "\nAfter sorting by name ..." );
    msortClist( &cl, cmpNames );
    printf( "\nshowLines:\n" );
    showLines( &cl );

    p = findClist( &cl, plast, cmpNames );
    if( p )
    {
        printf( "\nNOW erasing: '%s, %s'\n", plast->name, plast->phone );
        eraseClist( &cl, p );
        printf( "showLines:\n" ); showLines( &cl );
    }
    else printf( "%s NOT found in lines.\n", plast->name );

    /* free all dynamic C strings ... */
    clearClist( &cl );

    takeInChar( "\nPress 'Enter' to continue/exit ... " );
    return 0;
}







PLEASE NOTE for the next few days from 2016-10-08:
ALL the Cvec and Clist pages and programs are in process of being updated.
So until update of ALL examples is complete, some old examples WILL NOT compile.
« Last Edit: October 08, 2016, 10:22:44 PM by David »