Author Topic: Cvec.h, Clist.h, ClistOfString.h and split.h ...  (Read 22802 times)

Offline David

  • Hero Member
  • *****
  • Posts: 644
    • View Profile
Cvec.h, Clist.h, ClistOfString.h and split.h ...
« on: August 05, 2010, 11:44:33 AM »
Update!   FREE homework help NOW available via e-mail ... (or in person if in Toronto Ontario Canada region.)


Update2:

most recent updates of Cvec, CvecOfInt, CvecOfString, Cvec_func's.h, readLine and readWord.h at this new link:
http://developers-heaven.net/forum/index.php/topic,2580.0.html

most recent updates of Clist, ClistOfInt, ClistOfString, Clist_func's.h, split.h,  readLine and readWord.h at this new link:
http://developers-heaven.net/forum/index.php/topic,2582.0.htm


Here is a little demo of a Contacts program that uses Cvec.h...

Code: [Select]
/* Rec's4qsortEditDelete2.c */ /* this version 2011-07-30 */

/* C 'vector emulation' using a dynamic array of rec's (see demo MENU below) */

#include <ctype.h> /* re. tolower */

#define FILENAME "Contacts.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. QSort all records by name (ignore case). \n" \
                  " 6. QSort all records by phone number. \n" \
                  " 7. Chop exact duplicates from records (ignore 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 : "

/* using readLine here ... instead of gets and fgets */
#include "readLine.h" /* includes stdio.h, stdlib.h, string.h and myAssert and newCopy */

typedef struct Contacts
{
    char* name; /* since CStrings are '\0' terminated, can get strlen */
    char* address;
    char* phone; /* 3 digit area-code + 7 digits + '\0' at end */
} Rec ;

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

/* Cvec.h */

#ifndef dwCVECTOR_H
#define dwCVECTOR_H

#define VEC_CHUNK_SIZE 4 /* re-set/increase this to best match your data size */

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 */

/* sets ary to NULL and size, cap to 0 and isSorted to 1 */
void initCvec( Cvec* );
void push_backCvec( Cvec*, Rec* );
void enlargeCvec( Cvec* );
void clearCvec( Cvec* );
void showCrec( Cvec*, int ); /* showCrec rec. at int index */
void showCvec( Cvec* );

void qsortNamesIgnoreCase( Cvec* );
void qsortPhones( Cvec* );
int compareDatIgnoreCase( const void*, const void* );
int comparePhone( const void*, const void* );
int strcmpIgnoreCase( char [], char [] );
void chopDups( 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 dat ... */
    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;
    if( cv->size > 1 ) cv->isSorted = 0;
}

/* get new array to hold one more record than before, copies old to new ...*/
void enlargeCvec( Cvec* cv )
{
    void* p;
    if( cv->cap ) cv->cap += cv->cap; // double capacity ...
    else cv->cap = VEC_CHUNK_SIZE; // set initial capacity

    p = realloc(cv->ary, cv->cap * sizeof(Rec) );
    if( p == NULL )
    {
        clearCvec( cv );
        myAssert( 0, "Error: realloc failed to allocate memory." );
    }
    /* else ... */
    cv->ary = (Rec*)p; /* update the base address of cv->ary */
}

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

void showCrec( Cvec* cv, int i )
{
    printf
    (
        "<%03d> Name: %s,  Address: %s,  Phone: %s\n",
        i+1, cv->ary[i].name, cv->ary[i].address, cv->ary[i].phone
    );
}

void showCvec( Cvec* cv )
{
    int i;
    for( i = 0; i < cv->size; ++i ) showCrec( cv, i );
    printf( "Records in memory = %d :: Max capacity = %d\n\n",
            cv->size, cv->cap );
}

void qsortNamesIgnoreCase( Cvec* cv )
{
    qsort( cv->ary, cv->size, sizeof(Rec), compareDatIgnoreCase );
    cv->isSorted = 1;
}

void qsortPhones( Cvec* cv )
{
    qsort( cv->ary, cv->size, sizeof(Rec), comparePhone );
    cv->isSorted = 0; /* i.e. NOT sorted by name ... */
}

int compareDatIgnoreCase( const void* x, const void* y )
{
    Rec* a = (Rec*) x;
    Rec* b = (Rec*) y;
    int compare1 = strcmpIgnoreCase( a->name, b->name ); /* first compare names */
    if( compare1 == 0 ) /* if the same ... */
    {
        int compare2 = strcmpIgnoreCase( a->address, b->address ); /* then addresses */
        if( compare2 == 0 ) /* if the same ... */
            return strcmp( a->phone, b->phone ); /* then use phone numbers */
        /* else ...*/
        return compare2; /* use addresses after all  ... */
    }
    /* else ... */
    return compare1; /* use names afer all ... since names were NOT the same */
}

int comparePhone( const void* x, const void* y )
{
    Rec* a = (Rec*) x;
    Rec* b = (Rec*) y;
    int compare = strcmp( a->phone, b->phone );
    if( compare == 0 ) /* if numbers the same ... */
        return strcmpIgnoreCase( a->name, b->name ); /* then use names ... */
    /* else ... */
    return compare; /* use numbers ... since number's were NOT the same ...*/
}

/* ignore case compare function ... */
int strcmpIgnoreCase( char s1[], char s2[] )
{
    for( ; *s1 != 0 && *s2 != 0; ++s1, ++s2 )
    {
        if( tolower(*s1) != tolower(*s2) ) break;
    }
    /* ok ... check the end conditions ... */
    if( *s1 == 0  &&  *s2 == 0 ) return 0; /*  strings equal ...*/
    return tolower(*s1) - tolower(*s2);
}

void chopDups( Cvec* cv )
{
    int i = 0, j = 1;
if( !cv->isSorted ) qsortNamesIgnoreCase(cv); /* first ensure name-sorted */
       
    for( ; j < cv->size ; ++j )
    {
        if( compareDatIgnoreCase( &cv->ary[i], &cv->ary[j] ) != 0 )
        {
            ++i;
            if( i != j ) memcpy( &cv->ary[i], &cv->ary[j], sizeof(Rec) );
        }
        else freeVrec( &cv->ary[j] );
    }
   
    cv->size = ++i;
}

#endif


/* with these, an address is passed, so NO copy made and/or original updated */
void readFile( Cvec* );
int showMenuGetChoice( Cvec*  );
int isValidPhoneNum( char [] );
int getIndexOfNameIgnoreCase( Cvec*, char [] );
int getIndexOfPhoneNum( Cvec*, char [] );
void takeInDatAndFile( Cvec* );
void writeSortedUnique( Cvec* );
void editDel( Cvec* );
void edit( Cvec*, int ); /* at int index */
void del( Cvec*, int );
int getChoice( char [] );



int main() /* ********************* MAIN BEGINS ***************************** */
{
    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",
            FILENAME
        );
    else showCvec( &cv ); /* passing address to avoid making another copy */
   
    printf( "Now cv.ary = 0x%p ... cv.size = %d\n\n", cv.ary, cv.size );
   
    do
    {
        choice = showMenuGetChoice( &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 cv.ary = 0x%p ... cv.size = %d\n", cv.ary, cv.size );

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



void readFile( Cvec* cv )
{
    FILE* fp;
    if( !(fp = fopen(FILENAME, "r")) )
    {
        printf( "File %s NOT found ...\n", FILENAME );
    }
    else
    {
        Rec d;
        while
        (
            (d.name = readLine(fp)) &&
            (d.address = readLine(fp)) &&
            (d.phone = readLine(fp))
        )
        {
            push_backCvec( cv, &d );
        }
        fclose( fp );
    }
}

int showMenuGetChoice( Cvec* cv )
{
    int num;
    char* tmp = NULL;

    fputs( MENU, stdout );
    while
    (
        printf( PROMPT ) &&
        (tmp = readLine(stdin)) != NULL &&
        ( (num = atoi(tmp)) < 1 || num > 10 )
    )
    {
        fputs( "Out of valid range 1..10  ", stdout );
        free(tmp);
    }
    free(tmp);

    if( num == 1 ) takeInDatAndFile( cv );
    else if( num == 2 )
    {
        int index;
        fputs( "Enter the name to find: ", stdout );
        tmp = readLine(stdin);
        if( (index = getIndexOfNameIgnoreCase( cv, tmp )) == -1 )
            printf( "%s not found.\n", tmp );
        else
            showCrec( cv, index );
        free( tmp );
    }
    else if( num == 3 )
    {
        int index;
        fputs( "Enter the number to find: ", stdout );
        tmp = readLine(stdin);
        if( (index = getIndexOfPhoneNum( cv, tmp )) == -1 )
            printf( "%s not found.\n", tmp );
        else
            showCrec( cv, index );
        free( tmp );
    }
    else if( num == 4 ) showCvec( cv );
    else if( num == 5 ) qsortNamesIgnoreCase( cv );
    else if( num == 6 ) qsortPhones( cv );
    else if( num == 7 ) chopDups( cv );
    else if( num == 8 ) editDel ( cv );
    else if( num == 9 ) writeSortedUnique( cv );
    /* else is 10 ... so will exit ... */
   
    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 getIndexOfNameIgnoreCase( Cvec* cv, char nameStr[] )
{
    int i;
    for( i = 0; i < cv->size; ++i)
        if( strcmpIgnoreCase(cv->ary[i].name, nameStr) == 0 )
            return i;
    return -1;
}

int getIndexOfPhoneNum( 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 takeInDatAndFile( Cvec* cv )
{
    Rec d;
    FILE* pFile = fopen( FILENAME, "a" );
    myAssert( (pFile != NULL), "Error: " FILENAME " not opened." );
   
    fputs( "Enter name: ", stdout );
    d.name = readLine( stdin );
    fputs( "Enter address: ", stdout );
    d.address = readLine( stdin );
    for( ; ; )
    {
        fputs( "Enter telephone: ", stdout );
        d.phone = readLine( stdin );
        if( isValidPhoneNum(d.phone) )
        {
            break;
        }
        /* else ... */
        fputs( "Only 10 digit number valid here ... ", stdout );
        free( d.phone );
    }

    /* Now we have good data ... so file and add to vector if ok ?  */
    if( getChoice( "Ok ... (y/n) ? " ) == 'y' )
    {
        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", FILENAME );
    }
    else
    {
        puts( "Aborted ..." );
        freeVrec( &d );
    }

    fclose( pFile );
}

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

void editDel( Cvec* cv )
{
    for( ; ; )
    {
        char* tmp;
        int index;
        int reply = getChoice( "Find by Name/Phone/Abort (n/p/a) ? " );
        if( reply == 'n' )
        {
            fputs( "Enter the name to find: ", stdout );
            tmp = readLine(stdin);
            if( (index = getIndexOfNameIgnoreCase( cv, tmp )) == -1 )
                printf( "%s not found.\n", tmp );
            else
            {
                showCrec( cv, index );
                reply = getChoice( "Edit/Delete/Abort (e/d/a) ? " );
                if( reply == 'e' ) edit( cv, index );
                else if( reply == 'd' ) del( cv, index );
                else if( reply == 'a' )
                {
                    puts( "Ok, edit/delete aborted ..." );
                    free( tmp );
                    break;
                }
            }
            free( tmp );
        }
        else if( reply == 'p' )
        {
            fputs( "Enter the number to find: ", stdout );
            tmp = readLine(stdin);
            if( (index = getIndexOfPhoneNum( cv, tmp )) == -1 )
                printf( "%s not found.\n", tmp );
            else
            {
                showCrec( cv, index );
                reply = getChoice( "Edit/Delete/Abort (e/d/a) ? " );
                if( reply == 'e' ) edit( cv, index );
                else if( reply == 'd' ) del( cv, index );
                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 puts( "Only n/p/a are valid ... " );
    }
}

void edit( Cvec* cv, int i )
{
    for( ; ; )
    {
        Rec d;
        fputs( "Enter name: ", stdout );
        d.name = readLine( stdin );
        fputs( "Enter address: ", stdout );
        d.address = readLine( stdin );
        for( ; ; )
        {
            fputs( "Enter telephone: ", stdout );
            d.phone = readLine( stdin );
            if( isValidPhoneNum(d.phone) ) break; /* out of INNER for loop ...*/
            /* else ... */
            fputs( "Only 10 digit number valid here ... ", stdout );
            free( d.phone );
        }
        /* ok ... we have some new data ... */
        if( getChoice( "Ok ... (y/n) ? " ) == 'y' )
        {
            /* then edit ... but first free old ...  */
            freeVrec( &cv->ary[i] );

            cv->ary[i].name =d.name;
            cv->ary[i].address =d.address;
            cv->ary[i].phone =d.phone;

            cv->isSorted = 0;
            break;
        }
        else
        {
            puts( "Aborted ..." );
            free( d.name );
            free( d.address );
            free( d.phone );
            break;
        }
    }
}

void del( Cvec* cv, int i )
{
    for( ; ; )
    {
        int reply = getChoice( "Really delete/abort (d/a) ? " );
        if( reply == 'a' )
        {
            puts( "Delete aborted ..." );
            break;
        }
        else if( reply == 'd' )
        {
            /* first free dynamic memory */
            freeVrec( &cv->ary[i] );

            memcpy( &(cv->ary[i]), &(cv->ary[i+1]), (cv->size-1-i)*sizeof(Rec) );
            -- cv->size;
            /* but leave cap unchamged  ... */
            break;
        }
        /* else ... */
        puts( "Enter 'd' and WILL delete ... or 'a' to abort ..." );
    }
   
    if( cv->size < 2 ) cv->isSorted = 1;
}

int getChoice( char text[] )
{
    int c, reply;
    fputs( text, stdout );
    c = reply = tolower( getchar() );
    while( c != '\n' ) c = getchar(); /* flush stdin ... */
    return reply;
}
« Last Edit: April 17, 2012, 05:15:55 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 644
    • View Profile
Re: Cvec.h, Clist.h, ClistOfString.h and split.h ...
« Reply #1 on: August 05, 2010, 12:04:48 PM »
And here the core Cvec part ... is separated out into a separate file ... Cvec.h to facilitate reuse ...

Code: [Select]
/* contacts_4qsortEditDelete_Cvec.c */  /* 2016-10-09 */


#define FILENAME "employeeRecords.txt"


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


#include "takeInLine.h" /* using latest readLine here instead of gets and fgets */
/* includes stdio.h, stdlib.h, string.h and myAssert and newCopy */


typedef struct Contact
{
    char* name; /* since CStrings are '\0' terminated, can get strlen */
    char* address;
    char* phone; /* 3 digit area-code + 7 digits + '\0' at end */
} Rec ;

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

/* NOW can include Cvec that USES struct Rec & clearRec() */

#include "Cvec.h" /* uses stdlib.h, string.h and myAssert included
                     by readLine above ... */


/* utility functions to reformat when showing this Rec ... */
void format( char* str, char* formatStr )
{
    while( *str != 0 && *formatStr != 0 )
    {
        if( *formatStr == '#' ) *formatStr++ = *str++;
        else ++formatStr;
    }
}
void showVrec( Rec* rc )
{
    char reformatStr[] = "(###) ###-####";
    format( rc->phone, reformatStr );
    printf
    (
        "%-24s %-32s %s\n",
        rc->name, rc->address, reformatStr
    );
}
void showPositionAndVrec( int index, Rec* rc )
{
    printf("<%03d> ", index+1);
    showVrec( rc );
}


/* and NOW can define this also ... */
void showCvec( Cvec* cv )
{
    int i;
    for( i = 0; i < cv->size; ++i )
        showPositionAndVrec( i, &(cv->ary[i]) );
    printf( "Records presently in memory = %d :: present capacity = %d\n\n",
            cv->size, cv->cap );
}

/*
    More utility functions for 'this Cvec program' follow ...

    Note: if an object's address is passed, NO local copy of object is made
          and original object might be updated ...
*/
int compareRecIgnoreCase( const void*, const void* );
int comparePhone( const void*, const void* );
int strcmpIgnoreCase( char [], char [] );
void qsortNamesIgnoreCase( Cvec* );
void qsortPhones( Cvec* );
void chopDups( Cvec* );


void readFile( Cvec* );
void takeInRec( Cvec* );
void writeSortedUnique( Cvec* );
void editDel( Cvec* );
void edit( Cvec*, int ); /* at int index */
void del( Cvec*, int );
int showMenuExecuteChoice( Cvec*  );
int isValidPhoneNum( char [] );
int getIndexOfNameIgnoreCase( Cvec*, char [] );
int getIndexOfPhoneNum( Cvec*, char [] );




int main() /* *************** BEGIN MAIN **************** */
{
    FILE* f = NULL;
    int choice;
    Cvec cv;

    initCvec( &cv ); /* we are passing the address of cv, so cv is updated */
    readFile( &cv );
    if( cv.size )
showCvec( &cv ); /* passing address to avoid making another copy */
    else
printf( "File %s will be created after data entered.\n",FILENAME );

    do
    {
        choice = showMenuExecuteChoice( &cv ); /* passing address ... */
    }
    while( choice != 10 ); /* i.e. exit on choice of 10 ...  */

    for( ; ; )
    {
        choice = tolower( takeInChar("File sorted unique records (y/n) ? ") );
        if( strchr( "yn", choice ) ) break;
        puts( "You must enter y or n ..." );
    }
    if( choice == 'y' )
        writeSortedUnique( &cv );
    else if( (f= fopen( FILENAME, "r" )) )
    {
        fclose( f );
        /* if using windows ... can do this ...
           especially while debugging ... */
        system( "notepad " FILENAME );
    }

    clearCvec( &cv ); /* free all dynamic memory when done with it ... */
    printf( "\nNow cv.ary = 0x%p ... cv.size = %d, cv.cap = %d\n",
            (void*)cv.ary, cv.size, cv.cap );
   
    takeInChar("\nPress 'Enter' to continue ... ");
    return 0;
   
} /* ******************** END MAIN ********************** */




int compareRecIgnoreCase( const void* x, const void* y )
{
    Rec* a = (Rec*) x;
    Rec* b = (Rec*) y;
    int compare1 = strcmpIgnoreCase( a->name, b->name ); /* first compare names */
    if( compare1 == 0 ) /* if the same ... */
    {
        int compare2 = strcmpIgnoreCase( a->address, b->address ); /* then addresses */
        if( compare2 == 0 ) /* if the same ... */
            return strcmp( a->phone, b->phone ); /* then use phone numbers */
        /* else ...*/
        return compare2; /* use addresses after all  ... */
    }
    /* else ... */
    return compare1; /* use names afer all ... since names were NOT the same */
}

int comparePhone( const void* p1, const void* p2 )
{
    Rec* a = (Rec*) p1;
    Rec* b = (Rec*) p2;
    int compare = strcmp( a->phone, b->phone );
    if( compare == 0 ) /* if numbers the same ... */
        return strcmpIgnoreCase( a->name, b->name ); /* then use names ... */
    /* else ... */
    return compare; /* use numbers ... since number's were NOT the same ...*/
}

/* ignore case compare function ... */
int strcmpIgnoreCase( char s1[], 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);
}


void qsortNamesIgnoreCase( Cvec* cv )
{
    qsort( cv->ary, cv->size, sizeof(Rec), compareRecIgnoreCase );
    cv->isSorted = 1;
}

void qsortPhones( Cvec* cv )
{
    qsort( cv->ary, cv->size, sizeof(Rec), comparePhone );
    cv->isSorted = 0; /* i.e. NOT sorted by name ... */
}

void chopDups( Cvec* cv )
{
    int i = 0, j = 1;
if( !cv->isSorted ) qsortNamesIgnoreCase(cv); /* first ensure name-sorted */

    for( ; j < cv->size ; ++j )
    {
        if( compareRecIgnoreCase( &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;
}

void readFile( Cvec* cv )
{
    FILE* fp = fopen(FILENAME, "r");
    if( fp )
    {
        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 NOT found ...\n", FILENAME );
}

int showMenuExecuteChoice( Cvec* cv )
{
    /* Note: inside this function cv is already a pointer */
    int num, index;
    char* tmpStr = NULL;

    num = takeInIntMinMax( MENU, 1, 10 );
    if( num == 1 )
        takeInRec( cv );
    else if( num == 2 )
    {
        tmpStr = takeInLine( "Enter the name to find: " );
        if( (index = getIndexOfNameIgnoreCase( cv, tmpStr )) == -1 )
            printf( "%s not found.\n", tmpStr );
        else
            showPositionAndVrec( index, &(cv->ary[index]) );
        free( tmpStr );
    }
    else if( num == 3 )
    {
        tmpStr = takeInLine( "Enter the number to find: " );
        if( (index = getIndexOfPhoneNum( cv, tmpStr )) == -1 )
            printf( "%s not found.\n", tmpStr );
        else
            showPositionAndVrec( index, &(cv->ary[index]) );
        free( tmpStr );
    }
    else if( num == 4 ) showCvec( cv );
    else if( num == 5 ) qsortNamesIgnoreCase( cv );
    else if( num == 6 ) qsortPhones( cv );
    else if( num == 7 ) chopDups( cv );
    else if( num == 8 ) editDel ( cv );
    else if( num == 9 ) writeSortedUnique( cv );
    /* else is 0 ... so will exit ... */

    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 getIndexOfNameIgnoreCase( Cvec* cv, char nameStr[] )
{
    int i;
    for( i = 0; i < cv->size; ++i)
        if( strcmpIgnoreCase(cv->ary[i].name, nameStr) == 0 )
            return i;
    return -1;
}

int getIndexOfPhoneNum( 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 takeInRec( Cvec* cv )
{
    Rec d;
    d.name = strToTitleCase(takeInLine( "Enter name: " ));
    d.address = strToTitleCase(takeInLine( "Enter address: " ));
    for( ; ; )
    {
        d.phone = takeInLine( "Enter telephone: " );
        if( isValidPhoneNum(d.phone) )
            break;

        /* else ... */
        fputs( "Only 10 digit number valid here ... ", stdout );
        free( d.phone );
    }

    /* Now we have good data, so file and add to vector if ok ?  */
    if( tolower(takeInChar( "Ok ... (y/n) ? " )) == 'y' )
        push_backCvec( cv, &d );
    else
    {
        puts( "Aborted ..." );
        clearRec( &d );
    }
}

void writeSortedUnique( Cvec* cv )
{
    int i;
    FILE* fp = fopen( FILENAME, "w" ); /* compiler concat's these TEXTs */
    myAssert( (fp != NULL), "Error: file " FILENAME " failed to open." );

    /* ok ... file is open ... so write all rec's to file ..*/

    chopDups( cv ); /* But first ... just to make sure sorted and unique ... */
    for( i = 0; i < cv->size; ++i )
    {
        fprintf( fp, "%s\n", cv->ary[i].name );
        fprintf( fp, "%s\n", cv->ary[i].address );
        fprintf( fp, "%s\n", cv->ary[i].phone );
    }
    fclose( fp ); /* flushes buffer ... so all written to file now ... */
    printf( "\n%d records copied to file %s\n\n", i, FILENAME );

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

void editDel( Cvec* cv )
{
    for( ; ; )
    {
        char* tmpStr;
        int index;
        int reply = tolower(takeInChar( "Find by Name/Phone/Index/Abort (n/p/i/a) ? " ));
        if( reply == 'n' )
        {
            tmpStr = takeInLine( "Enter the name to find: " );
            if( (index = getIndexOfNameIgnoreCase( cv, tmpStr )) == -1 )
                printf( "%s ... not found.\n", tmpStr );
            else
            {
                showPositionAndVrec( index, &(cv->ary[index]) );
                reply = tolower(takeInChar( "Edit/Delete/Abort (e/d/a) ? " ));
                if( reply == 'e' ) edit( cv, index );
                else if( reply == 'd' ) del( cv, index );
                else if( reply == 'a' )
                {
                    puts( "Ok, edit/delete aborted ..." );
                    free( tmpStr );
                    break;
                }
            }
            free( tmpStr );
        }
        else if( reply == 'p' )
        {
            tmpStr = takeInLine( "Enter the number to find: " );
            if( (index = getIndexOfPhoneNum( cv, tmpStr )) == -1 )
                printf( "%s ... not found.\n", tmpStr );
            else
            {
                showPositionAndVrec( index, &(cv->ary[index]) );
                reply = tolower(takeInChar( "Edit/Delete/Abort (e/d/a) ? " ));
                if( reply == 'e' ) edit( cv, index );
                else if( reply == 'd' ) del( cv, index );
                else if( reply == 'a' )
                {
                    puts( "Ok, edit/delete aborted ..." );
                    free( tmpStr );
                    break;
                }
            }
            free( tmpStr );
        }
        else if ( reply == 'i' )
        {
            int index = takeInInt( "Enter the index to find: " );
            -- index;
            if( index < 0 || index > cv->size-1 )
                printf( "%d out of valid range 0..%d\n", index, cv->size-1 );
            else
            {
                showPositionAndVrec( index, &(cv->ary[index]) );
                reply = tolower(takeInChar( "Edit/Delete/Abort (e/d/a) ? " ));
                if( reply == 'e' ) edit( cv, index );
                else if( reply == 'd' ) del( cv, index );
                else if( reply == 'a' )
                {
                    puts( "Ok, edit/delete aborted ..." );
                    break;
                }
            }
        }
        else if( reply == 'a' || reply == '\n' )
        {
            puts( "Ok, edit/delete aborted ..." );
            break;
        }
        else puts( "Only n/p/a are valid ... " );
    }
}

void edit( Cvec* cv, int i )
{
    for( ; ; )
    {
        Rec d;
        d.name = takeInLine( "Enter name: " ) ;
        d.address = takeInLine("Enter address: " ) ;
        for( ; ; )
        {
            d.phone = takeInLine( "Enter telephone: " );
            if( isValidPhoneNum(d.phone) ) break; /* out of INNER for loop ...*/
            /* else ... */
            fputs( "Only 10 digit number valid here ... ", stdout );
            free( d.phone );
        }
        /* ok ... we have a new record ... */
        if( tolower(takeInChar( "Ok ... (y/n) ? " ) == 'y' ))
        {
            /* then edit ... but first free old ...  */
            clearRec( &(cv->ary[i]) );

            /* now copy pointers to NEW info for this Contact */
            cv->ary[i].name =d.name;
            cv->ary[i].address =d.address;
            cv->ary[i].phone =d.phone;

            cv->isSorted = 0;
            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' )
        {
            /* first free dynamic memory */
            clearRec( &(cv->ary[i]) );

            memcpy( &(cv->ary[i]), &(cv->ary[i+1]), (cv->size-1-i)*sizeof(Rec) );
            -- cv->size;
            /* but leave cap unchamged  ... */
            break;
        }
        /* else ... */
        puts( "Enter 'd' and WILL delete ... or 'a' to abort ..." );
    }

    if( cv->size < 2 ) cv->isSorted = 1;
}



Note: Cvec.h is  on the next page ...
« Last Edit: October 09, 2016, 11:46:52 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 644
    • View Profile
Re: Cvec.h, Clist.h, ClistOfString.h and split.h ...
« Reply #2 on: August 05, 2010, 12:05:54 PM »
Ok ... here is the core ... the engine for C vector ... Cvec.h

Update: latest Cvec.h and related files, including readLine.h and readWord.h, are now maintained here ...

http://developers-heaven.net/forum/index.php/topic,2580.msg2862.html#msg2862
« Last Edit: July 18, 2011, 09:45:40 PM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 644
    • View Profile
Re: Cvec.h, Clist.h, ClistOfString.h and split.h ...
« Reply #3 on: August 05, 2010, 01:29:03 PM »
And a simple demo that uses a Cvec of numbers to input data to find min, max and average ...
(uses the above file cVec.h)

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

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

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

#define HEADER "C program to find minimum, maximum, average " \
               "of a 'C vector' of doubles ...\n"


typedef int myType;
#define ints    1
#define doubles 0

typedef struct
{
    myType val;
} Rec ;

void clearRec( Rec* rc )
{
    /* empty here ...since don't have any Cstrings, etc... to free */
    rc = rc; /* surpress compiler warning 'unused ' */
}

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


#include "Cvec.h" /* needs stdio.h, stdlib.h, string.h and myAssert and
                     Rec def'n and freeVrec def'n as per above ... */


void getInfoRe( Cvec* cv,  myType* min, myType* max, double* avg );
int more( void );

int main( void ) /* ********************************************************* */
{
    int i = 0; /* i is used below as an index counter ... */
    myType min, max;
    double avg; /* variables to hold info returned by 'ref' */
    Cvec v;
    initCvec( &v ); /* Note: MUST initCvecial Cvec v ... for Cvec to work */
   
    puts( HEADER );
    for( ; ; )
    {
        Rec d;
        int numGoodVars;
        printf( "Observation %-3d: ", i+1 );
#if doubles
        numGoodVars = scanf( "%lf", &d.val );
#elif ints
        numGoodVars = scanf( "%d", &d.val );
#endif
        while( getchar() != '\n' ) ; /* flush all char's in stdin stream */ ;
        if( numGoodVars != 1 ) puts( "Numbers only please ..." );
        else
        {
            push_backCvec( &v, &d ); /* since good Reca was obtained */
            if( !more() ) break;
            /* else ...*/
            ++i;
        }
    }

    puts( "\n You entered ...\n" );
    for( i = 0; i < v.size; ++i )
    {
        printf( "%-3d: ", i+1 ); /* left justify in a 3 char wide field */
#if doubles
        printf( "%0.4f\n", v.ary[i].val ); /* Note: 'f' here handles double and float */
#elif ints
        printf( "%d\n", v.ary[i].val );
#endif
    }

    /* Note: 'cvdresses' are passed here ... to receiving pointer variables */
    getInfoRe( &v, &min, &max, &avg );
#if doubles
    printf( "\n Min: %0.4f  Max: %0.4f  Average: %0.4f\n", min, max, avg );
#elif ints
    printf( "\n Min: %d  Max: %d  Average: %0.4f\n", min, max, avg );
#endif
    printf( "\n Before clearCvec: v.size = %d, v.cap = %d\n", v.size, v.cap );
    clearCvec( &v );
    printf( "\n After  clearCvec: v.size = %d, v.cap = %d\n", v.size, v.cap );
   
    fputs( "\n Press 'Enter' to continue ... ", stdout );
    getchar();
    return 0;
} /* ************************************************************************ */


/* note where we are catching 'cvdresses' .... and note inside ... */
/* we have to use (i.e. dereference) the value at that cvdress by using *var  */
void getInfoRe( Cvec* cv, myType* min, myType* max, double* avg )
{
    int i;
    double sum = 0;
    *min = *max = cv->ary[0].val; /* to start, use this actual value */
    for( i = 1; i < cv->size; ++i ) /* start at 1 since alrecvy used 0 above */
    {
        sum += cv->ary[i].val;
        if( cv->ary[i].val < *min ) *min = cv->ary[i].val; /* upRece ... */
        if( cv->ary[i].val > *max ) *max = cv->ary[i].val;
    }
    /* when we reach ... we have max, min and sum ... So can find average */
    *avg = sum/cv->size; /*  Note:  double/int ... yields a double */
}

int more( void )
{
    int c, reply;
    fputs( "More (y/n) ? ", stdout );
    reply = c = getchar();
    while( c != '\n' ) c = getchar(); /* flush stdin ... */
    return !(reply=='n' || reply=='N');
}
« Last Edit: October 17, 2016, 03:39:25 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 644
    • View Profile
Re: Cvec.h, Clist.h, ClistOfString.h and split.h ...
« Reply #4 on: August 05, 2010, 02:54:14 PM »
Now ... on to split.h, ClistOfString.h and Clist.h ...

This demo program counts the unique words in a text ...

I am using a text from Genesis 1 and John chapter 1 in this example ...

Note: this program uses ... split.h, ClistOfString.h, Clist.h and readLine.h all provided below ...

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


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


/* if don't define ... becomes "\t " */
#define DELIMITS "* .?!,;:\t-0123456789¶[]()"

#include "split.h"  /*
                        includes ClistOfString.h
                        that includes readLine.h ...
                            that includes stdio.h, stdlib.h, string.h
                            and defines myAssert, newCopy
                        ClistOfString.h also includes Clist.h
                    */

/* re. qsort array of C strings ... but ... */
/* sort here in order of numeric first part of string */
int compare (const void* a, const void* b )
{
    int x = atoi( *(char**)a );
    int y = atoi( *(char**)b );
    /* return strcmp( *( char** ) a , *( char** ) b ); */
    return x - y;
}

int main() /* ********* BEGIN MAIN ********************* */
{
    FILE *fpIn, *fpOut;
    char *newLine, *inFileName, *outFileName;
    char **pp; /* for an array of C strings ... */
    char *tmpBuf;
   
    Clist myList; /* construct my ClistOfString ... */
    pNode pTmp; /* get a pointer to hold address of element */
    int i, sum, thisWordCount, uniqueCount;


    /* Note! MUST initial list for it to work properly */
    initClist( &myList );


    /* get names of input, output files ... and open */
    printf("Enter name of file to open (for example, word.txt) : ");
    inFileName = readLine( stdin );
   
    printf("Enter name of output file (for example, wordsCounted.txt): ");
    outFileName = readLine( stdin );
   
    fpIn = fopen( inFileName, "r" );
    fpOut = fopen( outFileName, "w" );
    myAssert( (fpIn && fpOut), "Error: Unable to open files." );


    /* get words in the file, line by line, into myList */
    while( (newLine = readLine( fpIn )) )
    {
        strToUpper( newLine );
        split( &myList, newLine ); /* ADD words in line to list */
        free( newLine );
    }
    fclose( fpIn );


    printf( "For delimits '%s', \n", DELIMITS );

    msortClist( &myList ); /* merge_sort the list ... */

    puts( "\nAfter msort ... " );
    showClist( &myList );


    /* get unique words in the list, into output word file */
   
    pTmp = myList.start; /* get address of 'start' */
    thisWordCount = sum = uniqueCount = 0;
    while( pTmp != NULL && pTmp->next != NULL )
    {
        ++ sum;
        if( strcmp( pTmp->str, pTmp->next->str ) == 0 )
        {
            ++ thisWordCount;
            if( pTmp->next->next == NULL )
            {
                fprintf( fpOut, "%2d  %s \n",
                         ++thisWordCount, pTmp->str );
                ++ uniqueCount;
                ++ sum;
                break;
            }
        }
        else /* output this unique with its count ... */
        {
            fprintf( fpOut, "%2d  %s \n", ++thisWordCount, pTmp->str );
            thisWordCount = 0; /* reset to zero */
            ++ uniqueCount;
            if( pTmp->next->next == NULL ) /* test if NO MORE loops */
            {
                ++ uniqueCount;
                fprintf( fpOut, "%2d  %s \n", ++thisWordCount, pTmp->next->str );
                ++ sum;
                break;
            }
        }

        pTmp = pTmp->next;
    }
   
    fprintf( fpOut, "Total number of words counted was %d.\n", sum );
    fprintf( fpOut, "Total number of unique words was %d.\n\n\n\n",
                uniqueCount );
    fclose( fpOut );
   
     /* if you have a Win OS ... */
    tmpBuf = newMem( strlen("notepad ") + strlen(outFileName) + 1 );
    strcpy( tmpBuf, "notepad " ); /* if Win OS */
    strcat( tmpBuf, outFileName );
   
    /* if you have a Win OS ... */
    system( tmpBuf );
   


    /* sort in order of frequency ... */
   
    fpIn = fopen( outFileName, "a+" );
    myAssert( (fpIn != NULL), "Error: unable to openfile." );
   
    /* get memory for array of C strings  ... */
    pp = (char**) malloc( sizeof(char*) * uniqueCount );
    myAssert( pp != NULL, "Error allocating dynamic array" );
   
    i = 0;
    while( i < uniqueCount && (newLine = readLine( fpIn )) )
    {
        pp[i++] = newLine; /* add line to array ... */
    }

    qsort( pp, uniqueCount, sizeof(char*), compare );

    fseek( fpIn, 0, SEEK_END ); /* move to end of read/write file */

    i = sum = 0;
    for( i = 0; i < uniqueCount; ++i )
    {
        printf( "%s\n", pp[i] );
        sum += atoi( pp[i] );
        fprintf( fpIn, "%s\n", pp[i] ); /* append line ... */
    }
    fclose( fpIn );
    printf( "The total number of words was %d\n", sum );

    /* if you have a Win OS ... */
    system( tmpBuf ); /* if Win OS */
   
    free( tmpBuf );
    free( pp );

    clearClist( &myList );
    free( outFileName );
    free( inFileName );
   
    takeInChar( "Press 'Enter' to continue/exit ... " );
    return 0;
} /* ******************* END MAIN *********************** */
« Last Edit: October 09, 2016, 09:57:05 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 644
    • View Profile
Re: Cvec.h, Clist.h, ClistOfString.h and split.h ...
« Reply #5 on: August 05, 2010, 02:56:35 PM »
« Last Edit: July 19, 2011, 01:34:36 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 644
    • View Profile
Re: Cvec.h, Clist.h, ClistOfString.h and split.h ...
« Reply #6 on: August 05, 2010, 03:00:14 PM »
And the NEW link to ClistOfString.h (that has the core engine separated out ... and now in Clist.h) ...

CListOfString.h
http://developers-heaven.net/forum/index.php/topic,2582.msg2882.html#msg2882
« Last Edit: July 19, 2011, 01:40:38 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 644
    • View Profile
Re: Cvec.h, Clist.h, ClistOfString.h and split.h ...
« Reply #7 on: August 05, 2010, 03:03:58 PM »
And NEW links ...

1. Clist.h ... just the central core here ... the engine   8)

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

2. readLine.h  ... (that is also needed here!)

readLine.h
http://developers-heaven.net/forum/index.php/topic,2580.msg2864.html#msg2864
« Last Edit: July 19, 2011, 01:42:18 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 644
    • View Profile
Re: Cvec.h, Clist.h, ClistOfString.h and split.h ...
« Reply #8 on: August 05, 2010, 03:13:14 PM »
And since I can't seem to attach the 2 test ... text files ... here they are:

1. word.txt

Code: [Select]
1 ¶  In the beginning God created the heaven and the earth.
2  And the earth was without form, and void; and darkness was upon the face of the deep. And the Spirit of God moved upon the face of the waters.
3 ¶  And God said, Let there be light: and there was light.
4  And God saw the light, that it was good: and God divided the light from the darkness.
5  And God called the light Day, and the darkness he called Night. And the evening and the morning were the first day.
6 ¶  And God said, Let there be a firmament in the midst of the waters, and let it divide the waters from the waters.
7  And God made the firmament, and divided the waters which were under the firmament from the waters which were above the firmament: and it was so.
8  And God called the firmament Heaven. And the evening and the morning were the second day.
9 ¶  And God said, Let the waters under the heaven be gathered together unto one place, and let the dry land appear: and it was so.
10  And God called the dry land Earth; and the gathering together of the waters called he Seas: and God saw that it was good.
11  And God said, Let the earth bring forth grass, the herb yielding seed, and the fruit tree yielding fruit after his kind, whose seed is in itself, upon the earth: and it was so.
12  And the earth brought forth grass, and herb yielding seed after his kind, and the tree yielding fruit, whose seed was in itself, after his kind: and God saw that it was good.
13  And the evening and the morning were the third day.
14 ¶  And God said, Let there be lights in the firmament of the heaven to divide the day from the night; and let them be for signs, and for seasons, and for days, and years:
15  And let them be for lights in the firmament of the heaven to give light upon the earth: and it was so.
16  And God made two great lights; the greater light to rule the day, and the lesser light to rule the night: he made the stars also.
17  And God set them in the firmament of the heaven to give light upon the earth,
18  And to rule over the day and over the night, and to divide the light from the darkness: and God saw that it was good.
19  And the evening and the morning were the fourth day.
20 ¶  And God said, Let the waters bring forth abundantly the moving creature that hath life, and fowl that may fly above the earth in the open firmament of heaven.
21  And God created great whales, and every living creature that moveth, which the waters brought forth abundantly, after their kind, and every winged fowl after his kind: and God saw that it was good.
22  And God blessed them, saying, Be fruitful, and multiply, and fill the waters in the seas, and let fowl multiply in the earth.
23  And the evening and the morning were the fifth day.
24 ¶  And God said, Let the earth bring forth the living creature after his kind, cattle, and creeping thing, and beast of the earth after his kind: and it was so.
25  And God made the beast of the earth after his kind, and cattle after their kind, and every thing that creepeth upon the earth after his kind: and God saw that it was good.
26 ¶  And God said, Let us make man in our image, after our likeness: and let them have dominion over the fish of the sea, and over the fowl of the air, and over the cattle, and over all the earth, and over every creeping thing that creepeth upon the earth.
27  So God created man in his own image, in the image of God created he him; male and female created he them.
28  And God blessed them, and God said unto them, Be fruitful, and multiply, and replenish the earth, and subdue it: and have dominion over the fish of the sea, and over the fowl of the air, and over every living thing that moveth upon the earth.
29 ¶  And God said, Behold, I have given you every herb bearing seed, which is upon the face of all the earth, and every tree, in the which is the fruit of a tree yielding seed; to you it shall be for meat.
30  And to every beast of the earth, and to every fowl of the air, and to every thing that creepeth upon the earth, wherein there is life, I have given every green herb for meat: and it was so.
31 ¶  And God saw every thing that he had made, and, behold, it was very good. And the evening and the morning were the sixth day.
1 ¶  Thus the heavens and the earth were finished, and all the host of them.
2  And on the seventh day God ended his work which he had made; and he rested on the seventh day from all his work which he had made.
3  And God blessed the seventh day, and sanctified it: because that in it he had rested from all his work which God created and made.

2. John1.txt

Code: [Select]
1 ¶  In the beginning was the Word, and the Word was with God, and the Word was God.
2  The same was in the beginning with God.
3  All things were made by him; and without him was not any thing made that was made.
4  In him was life; and the life was the light of men.
5 ¶  And the light shineth in darkness; and the darkness comprehended it not.
6  There was a man sent from God, whose name was John.
7  The same came for a witness, to bear witness of the Light, that all men through him might believe.
8  He was not that Light, but was sent to bear witness of that Light.
9  That was the true Light, which lighteth every man that cometh into the world.
10  He was in the world, and the world was made by him, and the world knew him not.
11  He came unto his own, and his own received him not.
12  But as many as received him, to them gave he power to become the sons of God, even to them that believe on his name:
13  Which were born, not of blood, nor of the will of the flesh, nor of the will of man, but of God.
14  And the Word was made flesh, and dwelt among us, (and we beheld his glory, the glory as of the only begotten of the Father,) full of grace and truth.
15 ¶  John bare witness of him, and cried, saying, This was he of whom I spake, He that cometh after me is preferred before me: for he was before me.
16  And of his fulness have all we received, and grace for grace.
17  For the law was given by Moses, but grace and truth came by Jesus Christ.
18  No man hath seen God at any time; the only begotten Son, which is in the bosom of the Father, he hath declared him.
19 ¶  And this is the record of John, when the Jews sent priests and Levites from Jerusalem to ask him, Who art thou?
20  And he confessed, and denied not; but confessed, I am not the Christ.
21  And they asked him, What then? Art thou Elias? And he saith, I am not. Art thou that prophet? And he answered, No.
22  Then said they unto him, Who art thou? that we may give an answer to them that sent us. What sayest thou of thyself?
23  He said, I am the voice of one crying in the wilderness, Make straight the way of the Lord, as said the prophet Esaias.
24  And they which were sent were of the Pharisees.
25  And they asked him, and said unto him, Why baptizest thou then, if thou be not that Christ, nor Elias, neither that prophet?
26  John answered them, saying, I baptize with water: but there standeth one among you, whom ye know not;
27  He it is, who coming after me is preferred before me, whose shoe’s latchet I am not worthy to unloose.
28  These things were done in Bethabara beyond Jordan, where John was baptizing.
29 ¶  The next day John seeth Jesus coming unto him, and saith, Behold the Lamb of God, which taketh away the sin of the world.
30  This is he of whom I said, After me cometh a man which is preferred before me: for he was before me.
31  And I knew him not: but that he should be made manifest to Israel, therefore am I come baptizing with water.
32  And John bare record, saying, I saw the Spirit descending from heaven like a dove, and it abode upon him.
33  And I knew him not: but he that sent me to baptize with water, the same said unto me, Upon whom thou shalt see the Spirit descending, and remaining on him, the same is he which baptizeth with the Holy Ghost.
34  And I saw, and bare record that this is the Son of God.
35  Again the next day after John stood, and two of his disciples;
36  And looking upon Jesus as he walked, he saith, Behold the Lamb of God!
37 ¶  And the two disciples heard him speak, and they followed Jesus.
38  Then Jesus turned, and saw them following, and saith unto them, What seek ye? They said unto him, Rabbi, (which is to say, being interpreted, Master,) where dwellest thou?
39  He saith unto them, Come and see. They came and saw where he dwelt, and abode with him that day: for it was about the tenth hour.
40  One of the two which heard John speak, and followed him, was Andrew, Simon Peter’s brother.
41  He first findeth his own brother Simon, and saith unto him, We have found the Messias, which is, being interpreted, the Christ.
42  And he brought him to Jesus. And when Jesus beheld him, he said, Thou art Simon the son of Jona: thou shalt be called Cephas, which is by interpretation, A stone.
43 ¶  The day following Jesus would go forth into Galilee, and findeth Philip, and saith unto him, Follow me.
44  Now Philip was of Bethsaida, the city of Andrew and Peter.
45  Philip findeth Nathanael, and saith unto him, We have found him, of whom Moses in the law, and the prophets, did write, Jesus of Nazareth, the son of Joseph.
46  And Nathanael said unto him, Can there any good thing come out of Nazareth? Philip saith unto him, Come and see.
47  Jesus saw Nathanael coming to him, and saith of him, Behold an Israelite indeed, in whom is no guile!
48  Nathanael saith unto him, Whence knowest thou me? Jesus answered and said unto him, Before that Philip called thee, when thou wast under the fig tree, I saw thee.
49  Nathanael answered and saith unto him, Rabbi, thou art the Son of God; thou art the King of Israel.
50  Jesus answered and said unto him, Because I said unto thee, I saw thee under the fig tree, believest thou? thou shalt see greater things than these.
51  And he saith unto him, Verily, verily, I say unto you, Hereafter ye shall see heaven open, and the angels of God ascending and descending upon the Son of man.
« Last Edit: August 05, 2010, 03:17:27 PM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 644
    • View Profile
Re: Cvec.h, Clist.h, ClistOfString.h and split.h ...
« Reply #9 on: August 05, 2010, 07:14:29 PM »
Ok ... this demo accomplishes the same thing very simply ...

by just using readWord (to parse the words ) in the whole text and then using Cvec (of C string) to hold them all.

Code: [Select]
/* Cvec_readWord_demo_wordcount.c */  /* this version 2016-10-016 */


/*
    readWord, readLine.h (include files) are maintained at ...

    http://developers-heaven.net/forum/index.php/topic,106.msg591.html#msg591
*/


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



/* if don't define ... becomes "\t " */
/* Note: '\n' is included here ... so '\n' also skipped */
#define DELIMITS "* .?!,;:\t\n-0123456789¶[]()"

#include "readWord.h" /* includes stdio.h, stdlib.h,
                         string.h, and myAssert ... */
                         
                         
typedef struct CvecOfString
{
    char* wordStr; /* since '\0' terminated can get strlen */
} Rec ;

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

/* Ok, having defined the above, we now can include ... */
#include "Cvec.h"


/* Also ... let's define a 'showCvec' ... */
void showCvec( Cvec* cv )
{
    int i;
    for( i =0; i< cv->size; ++i )
    {
        printf( "%4d %s\n", i+1, cv->ary[i].wordStr );
    }
    /* printf( "The number of words in cv is %d.", cv->size ); */
}


/* re. qsort array of C strings ... but ... */
/* sort here in order of numeric first part of string */
int compare (const void* a, const void* b )
{
    int x = atoi( *(char**)a );
    int y = atoi( *(char**)b );
    return x - y;
}

/* re. qsort array of C strings ...  */
int compareStr (const void* a, const void* b )
{
    return strcmp( *( char** ) a , *( char** ) b );
}




int main() /* ********** BEGIN MAIN ********************* */
{
    FILE *fpIn, *fpOut;
    char *newWord, *inFileName, *outFileName;
    char tmpStrBuffer[64];
   
    Cvec cv; /* construct my cv vector ... */
    int i, sum, thisWordCount, uniqueCount;
   
    char c; /* to hold the last char in readWord ... */


    /* Note! MUST initial Cvec for it to work properly */
    initCvec( &cv );


    /* get names of input, output files ... and open */
    printf("Enter name of file to open (for example, word.txt) : ");
    inFileName = readWord( stdin, 64, "\n", &c );
   
    printf("Enter name of output file (for example, wordsCounted.txt): ");
    outFileName = readWord( stdin, 64, "\n", &c );
   
    fpIn = fopen( inFileName, "r" );
    fpOut = fopen( outFileName, "w" );
    myAssert( (fpIn && fpOut), "Error: Unable to open files." );


    /* get all words in the file into Cvec cv ... */
    while( (newWord = readWord( fpIn, 32, DELIMITS, &c )) )
    {
        Rec r;
        strToUpper( newWord );
        r.wordStr = newWord;
        push_backCvec( &cv, &r  ); /* ADD word to vector */
    }
    fclose( fpIn );


    qsort( cv.ary, cv.size, sizeof(char*), compareStr );

    printf( "For delimits '%s', \n", DELIMITS );
    puts( "\nAfter qsort ... " );
    showCvec( &cv );


    /* get unique words in the list, into output word file */

    i = 0;
    thisWordCount = sum = uniqueCount = 0;
    while( i < cv.size-1 )
    {
        ++ sum;
        if( strcmp( cv.ary[i].wordStr, cv.ary[i+1].wordStr ) == 0 )
        {
            ++ thisWordCount;
            if( i == cv.size-2 )
            {
                fprintf( fpOut, "%2d  %s \n",
                         ++thisWordCount, cv.ary[i].wordStr );
                ++ uniqueCount;
                ++ sum;
                break;
            }
        }
        else /* output this unique with its count ... */
        {
            fprintf( fpOut, "%2d  %s \n", ++thisWordCount, cv.ary[i].wordStr );
            thisWordCount = 0; /* reset to zero */
            ++ uniqueCount;
            if( i == cv.size-2 ) /* test if NO MORE loops */
            {
                ++ uniqueCount;
                fprintf( fpOut, "%2d  %s \n", ++thisWordCount, cv.ary[i+1].wordStr );
                ++ sum;
                break;
            }
        }
        ++i;
    }
   
    fprintf( fpOut, "Total number of words counted was %d.\n", sum );
    fprintf( fpOut, "Total number of unique words was %d.\n\n\n",
                uniqueCount );

    fclose( fpOut );
   
    /* if Win OS */
    strcpy( tmpStrBuffer, "notepad " );
    strcat( tmpStrBuffer, outFileName );
   
    /* if Win OS */
    system( tmpStrBuffer );
   

    /* sort in order of frequency ... */
   
    fpIn = fopen( outFileName, "a+" );
    myAssert( (fpIn != NULL), "Error: unable to openfile." );
   
    /* free dynamic memory for all strings and ary ... */
    clearCvec( &cv ); /* and initial to NULL, 0 size, cap */
    i = 0;
    while( i < uniqueCount &&
           (newWord = readWord( fpIn, 64, "\n", &c )) )
    {
        Rec r;
        r.wordStr = newWord;
        push_backCvec( &cv, &r );
        ++i;
    }

    /* sort in NUMERIC order of increasing frequency */
    qsort( cv.ary, cv.size, sizeof(char*), compare );

    fseek( fpIn, 0, SEEK_END ); /* move to end of read/write file */

    sum = 0; /* to cross-check word count ... */
    for( i = 0; i < cv.size; ++i )
    {
        printf( "%s\n", cv.ary[i].wordStr ); /* screen ..*/
        sum += atoi( cv.ary[i].wordStr );
        fprintf( fpIn, "%s\n", cv.ary[i].wordStr ); /* file ... */
    }
    fclose( fpIn );
   
    printf( "The total number of words was %d\n", sum );
   
    /* if Win OS */
    system( tmpStrBuffer );
   
    clearCvec( &cv );
    free( outFileName );
    free( inFileName );

    takeInChar( "Press 'Enter' to continue ... " );
    return 0;
} /* ******************* END MAIN *********************** */


Recall ... that a copy of Cvec.h is just above ... and here is a link to readWord.h ...

http://developers-heaven.net/forum/index.php/topic,106.msg564.html#msg564
« Last Edit: October 17, 2016, 03:44:15 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 644
    • View Profile
Re: Cvec.h, Clist.h, ClistOfString.h and split.h ...
« Reply #10 on: August 27, 2010, 09:19:31 AM »
Here are more demos of using split.h, ClistOfString.h, Clist.h, readLine.h ... and Cvec.h and readWord.h ...

to parse an input line of words and show the words in reversed order ...

http://www.dreamincode.net/forums/topic/187823-need-urgent-help/page__view__findpost__p__1101292

or just to parse an input line ...

http://www.dreamincode.net/forums/topic/189293-whats-wrong-with-my-c-linked-list-implementation/page__view__findpost__p__1110448

« Last Edit: September 08, 2010, 07:49:33 AM by David »