Developers Heaven Forum
News: To still receiving newsletters from us please subscribe to our Newsletters:
http://tech.groups.yahoo.com/group/developers-Heaven/
 
*
Welcome, Guest. Please login or register.
Did you miss your activation email?
September 04, 2010, 07:54:35 AM


Login with username, password and session length


Pages: [1]   Go Down
  Print  
Author Topic: Cvec.h, Clist.h, ClistOfString.h and split.h ...  (Read 178 times)
0 Members and 1 Guest are viewing this topic.
David
Full Member
***
Offline Offline

Posts: 146

OS:
Windows XP
Browser:
Firefox 3.6.8


View Profile
« on: August 05, 2010, 11:44:33 AM »

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

Code:
/* Rec's4qsortEditDelete2.c */ /* this version 2010-08-05 */

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

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 ;


/* Cvect.h */

#ifndef dwCVECTOR_H
#define dwCVECTOR_H

/* Note: stdlib.h and myAssert were included in "readLine.h" above */
#include <string.h> /* re. memcpy */

#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 )
        {
            free( cv->ary[i].phone );
            free( cv->ary[i].address );
            free( cv->ary[i].name );
        }
        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, bot, top = cv->size-1;

    if( !cv->isSorted ) qsortNamesIgnoreCase(cv); /* first ensure name-sorted */
    for( bot = 0; bot < top; ++bot )
    {
        i = bot;
        while( i < top && compareDatIgnoreCase( &(cv->ary[bot]), &(cv->ary[i+1]) ) == 0 )
        {
            ++i; /* increment i while next rec. up stream is a duplicate ... */
        }
        /* if duplicate(s) ... copy last duplicate rec, upstream, down-over(bot)
           (and all following) ... and reset top, bot(at top of for loop) */
        if( i-bot ) /* i.e. if i-bot > 0 */
        {
            int j = i-bot-1; /* but first free dynamic memory for duplicates */
            for( ; j >= 0; --j )
            {
                free( cv->ary[bot+j].name );
                free( cv->ary[bot+j].address );
                free( cv->ary[bot+j].phone );
            }
            memcpy( &(cv->ary[bot]), &(cv->ary[i]), (top-i+1)*sizeof(Rec) );
            top -= (i-bot);
        }
    }
    /* finally ... re-set size to new (top+1) of unique number of rec's ... */
    /* and ... leave capacity unchanged ... (for now) ...  */
    cv->size = top+1;
}

#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 ..." );
        free( d.name );
        free( d.address );
        free( d.phone );
    }

    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 ...  */
            free( cv->ary[i].name );
            free( cv->ary[i].address );
            free( cv->ary[i].phone );

            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 */
            free( cv->ary[i].name );
            free( cv->ary[i].address );
            free( cv->ary[i].phone );

            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: August 27, 2010, 03:44:11 AM by David » Logged
David
Full Member
***
Offline Offline

Posts: 146

OS:
Windows XP
Browser:
Firefox 3.6.8


View Profile
« 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:
/* contacts_4qsortEditDelete.c */ /* this ver 2010-08-05 */

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

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

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

#define FILENAME "Contacts.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 exact 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 : "

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 freeVrec( Rec* rc )
{
    free( rc->phone ); free( rc->address ); free( rc->name );
}

/* utility functions to avoid recoding to show this Rec ... */
void format( char* str, char* format )
{
    while( *str != 0 && *format != 0 )
    {
        if( *format == '#' ) *format++ = *str++;
        else ++format;
    }
}
void showVrec( Rec* rc )
{
    char buf[] = "(###) ###-####";
    format( rc->phone, buf );
    printf
    (
        "%-20s %-25s %s\n",
        rc->name, rc->address, buf
    );
}
void showPositionAndVrec( int index, Rec* rc )
{
    printf("<%03d>  ", index+1);
    showVrec( rc );
}


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

#include "Cvec.h" /* uses stdlib.h and myAssert included
                     by readLine above ...
                     Cvec.h also includes <string.h> */

/* 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 :: Max capacity = %d\n\n",
            cv->size, cv->cap );
}

/*
    More utility functions for 'this Cvec program' follow ...
   
    Note: if an address is passed, NO copy is made
          and original may 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 getChoice( char [] );
int showMenuGetChoice( Cvec*  );
int isValidPhoneNum( char [] );
int getIndexOfNameIgnoreCase( Cvec*, char [] );
int getIndexOfPhoneNum( Cvec*, char [] );



int main() /* ************** BEGIN MAIN **************** */
{
    int choice;
    Cvec cv;
    /* we are passing the address of cv, so cv is updated */
    initCvec( &cv );
    readFile( &cv );
    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 ...  */
   
    for( ;; )
    {
        choice = getChoice("Would you like to file these records (y/n) ? ");
        if( strchr( "yn", choice ) ) break;
        puts( "You must enter y or n ..." );
    }
    if( choice == 'y' )
        writeSortedUnique( &cv );
    else
        /* 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\n", cv.ary, cv.size );
    printf("Press 'Enter' to continue ... ");
    fflush( stdin );
    getchar();
    return 0;
} /* ******************* END MAIN ********************** */



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

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 ... */
    if( *s1 == 0  &&  *s2 == 0 ) return 0; /*  strings equal ...*/
    return tolower(*s1) - tolower(*s2);
}

void chopDups( Cvec* cv )
{
    int i, bot, top = cv->size-1;

    if( !cv->isSorted )
        qsortNamesIgnoreCase(cv); /* first ensure name-sorted */
    for( bot = 0; bot < top; ++bot )
    {
        i = bot;
        while( i < top &&
               compareRecIgnoreCase( &(cv->ary[bot]),
                                     &(cv->ary[i+1]) ) == 0 )
        {
            ++i; /* increment i while next rec. up stream is a duplicate ... */
        }
        /* if duplicate(s) ... copy last duplicate rec, upstream, down-over(bot)
           (and all following) ... and reset top, bot(at top of for loop) */
        if( i-bot ) /* i.e. if i-bot > 0 */
        {
            int j = i-bot-1; /* but first free dynamic memory for duplicates */
            for( ; j >= 0; --j )
            {
                freeVrec( &(cv->ary[bot+j]) );
            }
            memcpy( &(cv->ary[bot]), &(cv->ary[i]), (top-i+1)*sizeof(Rec) );
            top -= (i-bot);
        }
    }
    /* finally ... re-set size to new (top+1) of
       unique number of rec's ...
       and ... leave capacity unchanged ... (for now) */
    cv->size = top+1;
}



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 )
{
    /* Note: inside this function cv is already a pointer */
    int num, index;
    char* tmpStr = NULL;

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

    if( num == 1 )
        takeInRec( cv );
    else if( num == 2 )
    {
        fputs( "Enter the name to find: ", stdout );
        tmpStr = readLine(stdin);
        if( (index = getIndexOfNameIgnoreCase( cv, tmpStr )) == -1 )
            printf( "%s not found.\n", tmpStr );
        else
            showPositionAndVrec( index, &(cv->ary[index]) );
        free( tmpStr );
    }
    else if( num == 3 )
    {
        fputs( "Enter the number to find: ", stdout );
        tmpStr = readLine(stdin);
        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 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 takeInRec( Cvec* cv )
{
    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;
        }
        /* 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' )
        push_backCvec( cv, &d );
    else
    {
        puts( "Aborted ..." );
        freeVrec( &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 = getChoice( "Find by Name/Phone/Index/Abort (n/p/i/a) ? " );
        if( reply == 'n' )
        {
            fputs( "Enter the name to find: ", stdout );
            tmpStr = readLine(stdin);
            if( (index = getIndexOfNameIgnoreCase( cv, tmpStr )) == -1 )
                printf( "%s ... not found.\n", tmpStr );
            else
            {
                showPositionAndVrec( index, &(cv->ary[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( tmpStr );
                    break;
                }
            }
            free( tmpStr );
        }
        else if( reply == 'p' )
        {
            fputs( "Enter the number to find: ", stdout );
            tmpStr = readLine(stdin);
            if( (index = getIndexOfPhoneNum( cv, tmpStr )) == -1 )
                printf( "%s ... not found.\n", tmpStr );
            else
            {
                showPositionAndVrec( index, &(cv->ary[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( tmpStr );
                    break;
                }
            }
            free( tmpStr );
        }
        else if ( reply == 'i' )
        {
            fputs( "Enter the index to find: ", stdout );
            tmpStr = readLine(stdin);
            int index = atoi(tmpStr) -1;
            if( index < 0 || index > cv->size-1 )
                printf( "%s out of valid range 0..%d\n", tmpStr, cv->size-1 );
            else
            {
                showPositionAndVrec( index, &(cv->ary[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( tmpStr );
                    break;
                }
            }
            free( tmpStr );
        }
        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;
        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 a new record ... */
        if( getChoice( "Ok ... (y/n) ? " ) == 'y' )
        {
            /* then edit ... but first free old ...  */
            freeVrec( &(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 ..." );
            freeVrec( &d );
            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;
}


And see Cvec.h on the next page ...
« Last Edit: August 27, 2010, 03:44:41 AM by David » Logged
David
Full Member
***
Offline Offline

Posts: 146

OS:
Windows XP
Browser:
Firefox 3.6.8


View Profile
« Reply #2 on: August 05, 2010, 12:05:54 PM »

Ok ... here is the core ... the engine for C vector ... Cvec.h

Code:
/* Cvec.h */ /* this version 2010-08-05 */

/* Note: to use Cvec, struct 'Rec' MUST be defined FIRST
   also ... freeRec( &(cv->ary[i]) );
   also ... needs myAssert and stdlib.h to use realloc */

#ifndef dwCVECTOR
#define dwCVECTOR

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

/* re-set this starting num of rec's to minimize realloc's */
#define VEC_CHUNK_SIZE 8

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 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;
    if( cv->size > 1 ) 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 ..." );
    }
    /* else ... */
    cv->ary = (Rec*) tmp; /* 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 );
    }
}

#endif


And readline.h is maintained here ...

http://developers-heaven.net/forum/index.php/topic,106.msg564.html#msg564
« Last Edit: August 27, 2010, 03:44:59 AM by David » Logged
David
Full Member
***
Offline Offline

Posts: 146

OS:
Windows XP
Browser:
Firefox 3.6.8


View Profile
« 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:
/* Cvec_minMaxAvg.c */ /* this version 2010-08-05 */

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

#include <stdio.h>
#include <stdlib.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 freeVrec( Rec* rc )
{
/* empty here ...don't have any Cstrings, etc... to free */
}

#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" /* includes <string.h>, ... and ...
                     needs above ...
                     <stdlib.h> and myAssert and ...
                     Rec def'n and freeRec def'n */


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: August 27, 2010, 03:45:40 AM by David » Logged
David
Full Member
***
Offline Offline

Posts: 146

OS:
Windows XP
Browser:
Firefox 3.6.8


View Profile
« Reply #4 on: August 05, 2010, 02:54:14 PM »

Now ... on to Clist.h, ClistOfString.h and split.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:
/* split_demo_word_count2.c */ /* this version 2010-08-26 */

/*
    See DIC tutorial re. split.h at ...
    http://www.dreamincode.net/forums/topic/174862-splith/

    Updates of split.h, ClistOfString.h, Clist.h and
    readLine.h are maintained at ...
    http://developers-heaven.net/forum/index.php/topic,466.0.html
*/

/* 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 string.h and ...
                        readlLine.h ... that includes ...
                        stdio.h, stdlib.h, myAssert
                        ClistOfString.h also includes
                        Clist.h
                    */
                   
#include <ctype.h> // re. toupper
void toAllCaps( char* a )
{
    while( *a != 0 )
    {
        *a = toupper(*a) ;
        ++ a;
    }
}

/* 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 tmpStrBuffer[64];
   
    Clist myList; // construct my ClistOfString ...
    pList 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 )) )
    {
        toAllCaps( newLine );
        split( &myList, newLine ); // ADD words in line to list
        free( newLine );
    }
    fclose( fpIn );


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

    msort( &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 );
   
    strcpy( tmpStrBuffer, "notepad " ); // if Win OS
    strcat( tmpStrBuffer, outFileName );
    system( tmpStrBuffer ); // if Win OS
   


    // 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 );
    if( pp == NULL ) exit(2);
   
    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 );

    system( tmpStrBuffer ); // if Win OS
   

    free( pp );

    clearClist( &myList );
    free( outFileName );
    free( inFileName );
   
    while( getchar() != '\n' ) ;
    getchar();
 
    return 0;
} /* ****************** END MAIN *********************** */
« Last Edit: August 27, 2010, 04:29:38 AM by David » Logged
David
Full Member
***
Offline Offline

Posts: 146

OS:
Windows XP
Browser:
Firefox 3.6.8


View Profile
« Reply #5 on: August 05, 2010, 02:56:35 PM »

Here is split.h ...

Code:
/* split.h */ /* this version: 2010-08-26 */

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

#ifndef dwSPLIT_H
#define dwSPLIT_H

#ifndef DELIMITS
#define DELIMITS  " \t"
#endif

#define NUM_DLMTS  sizeof(DELIMITS) -1

/* adds string.h, readLine, stdio.h, stdlib.h, myAssert */
#include "ClistOfString.h"

#ifndef PUSH_CLIST
#define PUSH_CLIST  push_backClist
#endif


char* createNewString( int len )
{
    char* n;
    if( len < 0 ) len = 0;
    n = (char*) malloc(len+1);
    myAssert( (n!=NULL), "Error: malloc failed to allocate memory." );
    n[0] = 0;
    return n;
}

char* newCopy( const char* s )
{
    int slen = strlen(s);
    char* ncopy = createNewString(slen);
    strcpy(ncopy, s);
    return ncopy;
}

char* substr( const char* start, const char* end )
{
    int len = end-start+1;
    char* newCpy = createNewString(len);
    strncpy( newCpy, start, len );
    newCpy[len] = 0;
    return newCpy;
}

/* returns POSITION 1..len if in string ... otherwise, returns 0 */

int chrInString( const char* s, char c )
{
    int i;
    for( i =0; s[i] != 0; ++i )
        if( c ==  s[i] )
            return i+1;
    return 0;
}

void split( Clist* lst, char* s )
{
    char *p1 = s, *p2;
    List ml;
    for( ; ; ) /* loop forever ... until break */
    {
        while( *p1 != 0 && strchr(DELIMITS, *p1) ) ++p1;
        if( *p1 == 0 )
break; /* i.e. if empty or all delimits */

        p2 = p1+1;
        while( *p2 != 0 && !strchr(DELIMITS, *p2) ) ++p2;
        ml.str = substr( p1, p2-1 ); /* new copy in new memory in ml.line */
        PUSH_CLIST( lst, &ml ); /* default is push_backClist */
        p1 = p2;
    }
}


#endif
« Last Edit: August 27, 2010, 03:33:33 AM by David » Logged
David
Full Member
***
Offline Offline

Posts: 146

OS:
Windows XP
Browser:
Firefox 3.6.8


View Profile
« Reply #6 on: August 05, 2010, 03:00:14 PM »

And an updated version of ClistOfString.h that has the core engine separated out ... and now in Clist.h ...

Code:
/* ClistOfString.h */ /* this version: 2010-08-26 */

#ifndef dwClistOfString_H
#define dwClistOfString_H

#ifndef sort_offset
#define sort_offset 0
#endif

/* using readLine here ... instead of gets and fgets */

#include "readLine.h" /* includes stdio.h, stdlib.h and myAssert */

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

typedef struct ClistOfString
{
    char* str;     /* since CStrings are '\0' terminated ... can get strlen */
    struct ClistOfString* next;
} List ;

typedef List* pList;

void clearLrec( pList p )
{
    free( p->str );
}

void showLrec( pList p )
{
    printf( "%s\n", p->str );
}


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



/* and these ...*/
void msort( Clist* );
void mergesort( Clist* );
pList merge( Clist*, Clist* );
void update_end( Clist* );


/* a recursive mergesort ... */
void mergesort(Clist* list)
{
    pList cur = list->start;
    Clist a, b;

    /* base case is a Clist of length 0 or 1 ... */
    if ((cur == NULL) || (cur->next == NULL))  return;

    /* split Clist into 'a' and 'b' sublists ... */
    a.start = cur;
    b.start = cur->next;
    while((b.start != NULL) && (b.start->next != NULL))
    {
        cur = cur->next;
        b.start = b.start->next->next;
    }
    b.start = cur->next;
    cur->next = NULL; /* Clist divided into 2 roughly equal parts now ... */

    /* recursively sort the sublists ... */
    mergesort(&a);
    mergesort(&b);

    /* merge the two sorted Clists together ... */
    list->start = merge(&a, &b);
    list->isSorted = 0;
}


/* merge two sorted Clists with heads 'a' and 'b' ... in sorted order */
pList merge(Clist* a, Clist* b )
{
    pList sorted, new_merged_head;

    if( a->start == NULL ) return b->start;
    if( b->start == NULL ) return a->start;

    if( strcmp(a->start->str + sort_offset, b->start->str + sort_offset) <= 0 )
    {
        sorted = a->start;
        a->start = a->start->next;
    }
    else
    {
        sorted = b->start;
        b->start = b->start->next;
    }
    new_merged_head = sorted;

    /* now ... */
    while( a->start != NULL && b->start != NULL )
    {
        if( strcmp(a->start->str + sort_offset, b->start->str + sort_offset) <= 0 )
        {
            sorted->next = a->start;
            sorted = a->start;
            a->start = a->start->next;
        }
        else
        {
            sorted->next = b->start;
            sorted = b->start;
            b->start = b->start->next;
        }
    }

    /* and finally ... */
    if( a->start != NULL )
        sorted->next = a->start;
    else if( b->start != NULL )
        sorted->next = b->start;

    return new_merged_head;
}

void update_end( Clist* list ) /* after sort */
{
    if( list->size > 1 )
    {
        pList cur;
        for( cur = list->start; cur->next != NULL; cur = cur->next ) ;
        list->end = cur;
        list->end->next = NULL;
    }
}

void msort( Clist* clst )
{
    mergesort( clst );
    update_end( clst );
}

#endif /* end of ifndef dwSTRING_H ... */
« Last Edit: August 27, 2010, 03:34:25 AM by David » Logged
David
Full Member
***
Offline Offline

Posts: 146

OS:
Windows XP
Browser:
Firefox 3.6.8


View Profile
« Reply #7 on: August 05, 2010, 03:03:58 PM »

And now, Clist.h ... just the central core here ... the engine   Cool

Code:
/* Clist.h */ /* 2010-08-05 */

#ifndef dwClist_H
#define dwClist_H


typedef struct myClist
{
    pList start;
    pList end;
    int size;
    int isSorted;
} Clist;


/* with these, an address is passed, so NO copy made and/or
  original updated */

/* sets start to NULL, size to 0. isSorted to 1 */
void initClist( Clist* );
void push_frontClist( Clist*, List* );
void push_backClist( Clist*, List* );
void clearClist( Clist* );
void showClist( Clist* );


void initClist( Clist* list )
{
    list->start = list->end = NULL;
    list->size = 0;
    list->isSorted = 1;
}

void push_frontClist( Clist* list, List* d )
{
    pList p = (pList) malloc( sizeof(List) );
    if( p == NULL )
    {
        clearClist( list );
        myAssert( 0, "Error: malloc failed ...." );
    }

    /* now add in ALL new dat ... (assuming next pointer is last of dat) */
    memcpy( p, d, sizeof(List)-sizeof(pList) ); /* -sizeof(any_pointer) is ok */
    /* and set pointers to next ... and start ...*/
    p->next = list->start;
    list->start = p;

    ++ list->size;
    if( list->size > 1 ) list->isSorted = 0;
    else list->end = list->start;
}

void push_backClist( Clist* list, List* d )
{
    pList p = (pList) malloc( sizeof(List) );
    if( p == NULL )
    {
        clearClist( list );
        myAssert( 0, "Error: malloc failed ..." );
    }

    /* now add in ALL new dat ... (assuming next pointer is last of dat) */
    memcpy( p, d, sizeof(List)-sizeof(pList) ); /* -sizeof(any_pointer) is ok */
    /* and set pointers to next ... and start ...*/

    p->next = NULL;
    ++ list->size;
    if( list->size > 1 )
    {
        list->end->next = p;
        list->end = p;
        list->isSorted = 0;
    }
    else
        list->start = list->end = p;
}

void clearClist( Clist* list )
{
    //printf( "\nFreeing list->size  of %d ... \n", list->size );
    if( list->size > 0 )
    {
        pList cur = list->start;
        for( ; cur != NULL; cur = list->start  )
        {
            list->start = cur->next;
            clearLrec( cur );
            free( cur );
        }
        initClist( list );
    }
}


void showClist( Clist* list )
{
    if( list->size )
    {
pList p = list->start;
for( ; p != NULL; p = p->next )
showLrec( p );
printf( "List size = %d\n", list->size );
    }
    else puts( "The list is empty ... " );
}

#endif

Note: here is the link to readLine.h  ... (that is also needed here!)

http://developers-heaven.net/forum/index.php/topic,106.msg564.html#msg564
« Last Edit: August 27, 2010, 03:35:03 AM by David » Logged
David
Full Member
***
Offline Offline

Posts: 146

OS:
Windows XP
Browser:
Firefox 3.6.8


View Profile
« 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:
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:
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 » Logged
David
Full Member
***
Offline Offline

Posts: 146

OS:
Windows XP
Browser:
Firefox 3.6.8


View Profile
« 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:
/* Cvec_readWord_demo_wordcount.c */ /* this version 2010-08-05 */

/*
    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 freeVrec( 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 ); */
}


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

/* used re. sorting so all Caps... */
void toAllCaps( char* a )
{
    while( *a != 0 )
    {
        *a = toupper(*a) ;
        ++ a;
    }
}

/* 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;
        toAllCaps( 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 );
   
    strcpy( tmpStrBuffer, "notepad " ); /* if Win OS */
    strcat( tmpStrBuffer, outFileName );
    system( tmpStrBuffer ); /* if Win OS */
   

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

    system( tmpStrBuffer ); /* if Win OS */
   
    clearCvec( &cv );
    free( outFileName );
    free( inFileName );

    printf( "Press 'Enter' to continue ... " );
    fflush( stdin );
    while( getchar() != '\n' ) ;
    getchar();
 
    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: August 27, 2010, 03:46:25 AM by David » Logged
David
Full Member
***
Offline Offline

Posts: 146

OS:
Windows XP
Browser:
Firefox 3.6.8


View Profile
« 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

Logged
Pages: [1]   Go Up
  Print  
 
Jump to:  

Powered by MySQL Powered by PHP Powered by SMF 1.1.4 | SMF © 2006-2007, Simple Machines LLC

Copyright © Developers-Heaven.net 2008. All rights reserved.
Valid XHTML 1.0! Valid CSS! Dilber MC Theme by HarzeM