Author Topic: C SOME UTILITY functions ...  (Read 395406 times)

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
C SOME UTILITY functions ...
« on: May 27, 2013, 01:27:36 AM »
This space is reserved for code and links to code for C utility functions ...

After I have collected several C snippets here ...  I hope to make an index with links on this front page.

But for now, please find these little snippets of code below,  (perhaps in related usage groupings of code, on the following pages.)




You may also like to see:  C++ SOME UTILITY functions ...

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


Update 2015-04-08: 

SEE the next link for several newly improved STUDENT take in type utilities  ...
with out of bounds error handling ...
(Some VERY HANDY student utilities.)

http://developers-heaven.net/forum/index.php/topic,2608.msg3158.html#msg3158


1.  /* example of a way to fix fgets TWO sometimes very annoying problems   */
char* fixedFgets( char* str, size_t bufSize, FILE* fin );

2.  /* example of a way to trim leading and trailing ws ... */
char* stripWS( char* s );

3.  /* example of an expedient way in C to handle string input from keyboard operator ...
    especially, if design calls to repeat input until string is of 'acceptable length' */
char* takeInStr( const char* msg, char* buf, unsigned bufLen, unsigned maxStrLen );

4.  /* an example of a common design request ... to Caps on first letters */
char* toCapsOnFirstLets( char* str );

5.  /* a simple student way to handle numeric input ...
   so program won't crash on bad input */
int takeInInt( const char* msg, int myMin, int myMax );

6.  /* loop until user takes in a valid int ... after prompt(s) ...  */
int takeInValidInt( const char prompt[] );

7.  /* a handy utility for many C student coding problems ... */
char takeInChar( const char* msg );

8.  int more(); /* defaults to 'true'/'yes'/'1' ... unless 'n' or 'N' entered */

9.  /* since using 'static' buf inside, memory persists ... so can return address */
char* takeInStaticString( const char* msg, unsigned max_len );

10. /* accepts only positive (i.e. >= 0) valid int range of values ... */
int takeInValidPosIntViaStaticString( const char* prompt, int high );

11. /*  returns a valid int in range INT_MIN..INT_MAX  */
int takeInValidMinMaxIntViaStaticString( const char* prompt, int myMin, int myMax );

...

And more added below ... like binary search, an iterative and also a recursive example, date and time and valid date and valid dob and days between two dates and ...


Code: [Select]
/* returns 'int' value if in range '0'..'9' else returns -1 if NOT a digit */

int getDigit( char c )
{
    if ( c < '0' || c > '9' ) return -1;
    return c - '0';
}

/*
    Note: int( c ), where c is a char in the range '0'..'9'
    would return integers in the range 48..57
    ... but getDigit( c ) returns integers in the range 0..9
*/


Code: [Select]
/* returns int value if in range '0'..'9' else returns -1 if not a number */

int isNum( char c )
{
    if ( c < '0' || c > '9' ) return -1;
    return c - '0';
}



1.  Six Fast Steps to Programming in C

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


2.  CvecOfInt.h, CvecOfString.h, Cvec.h, Cvec_func's.h (with FUNCTION POINTERS)

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


3.  Cvec_func's.h example programs ... using FUNCTION POINTERS to facilitate reuse

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


4. ClistOfInt.h, ClistOfString.h, Clist.h, Clist_func's.h (with FUNCTION POINTERS)

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


5.  Clist_func's.h example programs ... using FUNCTION POINTERS to facilitate reuse

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


6.  split.h ... a C emulation of the Python spilt function to parse a string ...

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


7.  Binary Search Tree template class in C ++ and Simple C Version

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


8.  Beyond Beginning Computer Programming in C ...

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


9.  Send in your C++ or C student coding problem, with code inside code tags (#)

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


10. Free coding help for beginners in C or C++

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


11. Clist Insertion Sort Tutorial ... and also see a recursive merge sort of a list

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


12. First steps ... via example programs in C++ and C ...

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


13. New thread especially for students of C and C++

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


14. BEGINNING COMPUTER PROGRAMMING (using C++ or C)

http://developers-heaven.net/forum/index.php/topic,127.0.html
« Last Edit: September 11, 2018, 01:55:16 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: C SOME UTILITY functions ...
« Reply #1 on: May 27, 2013, 01:30:05 AM »
/*
    Example of a way to fix fgets sometimes TWO very annoying problems:

    1.  a 'maybe' newline at the end of the input buffer string ...
    2.  the possibility of the input string being TOO LONG for the input buffer C string

*/

Code: [Select]
#include <stdio.h>
#include <string.h>

char* fixedFgets( char* str, size_t bufSize, FILE* fin )
{
    if( fgets( str, bufSize, fin ) )
    {
        char *p = strchr( str, '\n' ), c ;
        if( p ) *p = 0; /* strip off '\n' at end ... IF it exists */
        else while( (c = fgetc( fin )) != '\n'  &&  c != EOF ) ; /* flush ... */
        return str;
    }
    else return NULL;
}


/* example of a way to trim leading and trailing ws ... */

Code: [Select]
#include <string.h>
#include <ctype.h>

char* stripWS( char* s )
{
    char *start = s, *end = s;
    while( *end ) ++end ;
    if( end == start ) return s; /* empty string */

    for( --end; s <= end && isspace(*end); --end ) ;
    end[1] = 0;

    while( isspace(*s) ) ++s;
    memmove( start, s, end+2-s ); /* 2 ... to copy terminal 0 */
    return start;
}


/*
    Take in string into buf string passed in of bufLen, but limit allowed input string length to maxStrLen
    Example of an expedient way in C to handle string input from keyboard operator ...
    especially, if design calls to repeat input until string is of 'acceptable length'

*/
Code: [Select]
char* takeInStr( const char* msg, char* buf, unsigned bufLen, unsigned maxStrLen )
{
    unsigned len = 0;
    if( maxStrLen < bufLen )
    {
        for( ; ; ) /* on example of a C 'forever loop' ...
                      until break from loop or return from function */
        {
            printf( msg ); fflush( stdout );
            fixedFgets( buf, bufLen, stdin );
            stripWS( buf );
            len = strlen( buf );
            if( len  &&  len <= maxStrLen ) return buf;
            else
            {
                if( len ) printf( "\nError! myMax input string length here "
                                  "is %d char's long ...\n"
                                  "but your string was %d char's long.\n",
                                  maxStrLen, len );
                else printf( "\nBlank lines NOT valid input here ...\n" );
            }
        }
    }
    /* else ... */
    printf( "\nERROR!  The bufLen of %d needs to be greater than %d\n",
            bufLen, maxStrLen );
    return NULL;
}


/* an example of a common design request ...  to ensure Caps on all 'first letters' */

Code: [Select]
char* toCapsOnFirstLets( char* str )
{
    char *p = str, prev = ' ';
    for( ; *p ; ++p )
    {
        if( prev == ' ' || prev == '\t' )
            *p = toupper( *p );
        prev = *p;
    }
    return str;
}
« Last Edit: August 12, 2014, 09:40:40 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: C SOME UTILITY functions ...
« Reply #2 on: May 27, 2013, 01:38:21 AM »
/*
   Some simple student ways to handle validating numeric input ...
   and to code so that program won't crash on invalid numeric input
*/


/*
   loop until user takes in a valid int ... after prompt(s) ... 
   int here is also checked and accepted iff in int range myMin..myMax
   
   uses scanf for input

   int takeInIntMinMax( const char* msg, int myMin, int myMax );
*/

Code: [Select]
#include <stdio.h>
 
/* loop until user takes in a valid int ... after prompt(s) ...  */
/* int here is also checked and accepted iff in int range myMin..myMax */
int takeInIntMinMax( const char* msg, int myMin, int myMax )
{
    int goodVal = 0, val = 0;
   
    while( !goodVal )
    {
    /* show prompt for input ...
   fflush( stdout) ensures prompt displayed right NOW
*/
        printf( msg ); fflush( stdout );
       
        /* Note logic below ...

   if scanf returns 1 below means ...
   ***there WAS ONE***
   good int data presented at first in input stream
       
           then ... if getchar() == '\n'
   ***that means that '\n' WAS the VERY NEXT CHAR***
   
   which means no space or other chars entered there
   before a '\n' char was entered ...
   so ... ***WAS good int*** data presented
   i.e. no 'junk' was entered by user 'by accident'
        (after int data was entered and before '\n' pressed)
*/

        if( scanf( "%d", &val ) == 1 && getchar() == '\n' )
        {
        goodVal = 1; /* Ok ... good so far ... */
        }
        else
        {
            printf( "\nInteger input only here please ...\n" );
            while( getchar() != '\n' ) ; /* flush stdin ... */
        }
       
        /* NOW check if input val was in the desired range myMin..myMax */

        if( goodVal && ( val < myMin || val > myMax ) )
        {
            goodVal = 0; /* reset to 'false' since val NOT in desired range */
            printf( "\nValid input only in range %d..%d\n", myMin, myMax );
        }
       
    } /* end while ... */   
   
    return val;
}



/*
   loop until user takes in a valid int ... after prompt(s) ...

   uses scanf for input

   int takeInValidInt( const char prompt[] );
*/

Code: [Select]
#include <stdio.h>

/* loop until user takes in a valid int ... after prompt(s) ...  */
int takeInValidInt( const char prompt[] )
{
    for( ; ; ) /* an other example of a C/C++ forever loop ... until 'return' */
    {
        int testInt;
        printf( prompt ); fflush( stdout );
       
       
        if( scanf( "%d", &testInt ) == 1 && getchar() == '\n' )
        {
        return testInt; /* since passed BOTH above checks ... */
        }
       
        /*else ... if reach here means failed either 1st or 2nd of above checks */
        while( getchar() != '\n' ); /* so ... 'flush' stdin ... as you go ... */
       
        puts( "Invalid input! Integers only please ..." );
    }
}



Code: [Select]
#include <stdio.h>
#include <ctype.h> /* re. tolower */

char takeInChar( const char* msg )
{
    char chr;
    printf( msg ); fflush( stdout );
    chr = getchar();
    if( chr != '\n' ) while( getchar() != '\n' ) ; /* flush stdin ... */
    return chr;
}


Code: [Select]
int more() /* defaults to 'true'/'yes'/'1' ... unless 'n' or 'N' entered */
{
    if( tolower( takeInChar( "\nMore (y/n) ? " )) == 'n' ) return 0;
    /* else ... */
    return 1;
}

readLine is readily available by including file readLine.h

http://developers-heaven.net/forum/index.php/topic,2580.msg2864.html#msg2864
« Last Edit: June 09, 2013, 04:08:35 PM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: C SOME UTILITY functions ...
« Reply #3 on: May 28, 2013, 08:15:33 AM »
A little test program featuring taking in a (fully) validated integer, (looping until have an input string that fits into an int), via taking in a STATIC C string and using atoi to convert to an int after validating that all are valid char's in the input string ... (in TWO Files ... a test program ... and a .h file that follows that needs to be included)

Code: [Select]
/* test_takeInStaticStringUtilities.h.c */  /* revised 2013-06-08 */


#include "takeInStaticStringUtilities.h"


int main()
{
int count = 0;
double sum = 0.0;

printf( "MAX number of digits, permitted in an 'int' here, is %d\n",
MAX_DIG_IN_INT );

printf( "\nINT_MIN = %d, INT_MAX  = %d\n\n", INT_MIN, INT_MAX );

do
{
sum += takeInValidPosIntViaStaticString(
"Enter next integer >= 0 to sum: ", INT_MAX );
++ count;
}
while( more() ); /* make sure stdin is 'empty' before calling 'more()' */


printf( "\nFor %d numbers entered, sum was %.0f and average was %.2f\n",
count, sum, sum/count );

count = 0;
sum = 0.0;

putchar( '\n' );

do
{
sum += takeInValidMinMaxIntViaStaticString(
"Enter next integer to sum: ", INT_MIN, INT_MAX );
++ count;
}
while( more() ); /* make sure stdin is 'empty' before calling 'more()' */

printf( "\nFor %d numbers entered, sum was %.0f and average was %.2f\n",
count, sum, sum/count );


/* keep 'Window' open until 'Enter' key is pressed ... */
takeInChar( "\nPress 'Enter' to continue/exit ... " );
return 0;
}



Code: [Select]
/* takeInStaticStringUtilities.h */  /* 2013-06-08 */


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

#ifndef TAKE_IN_STATIC_STR_UTILITIES
#define TAKE_IN_STATIC_STR_UTILITIES

#include <stdio.h>
#include <stdlib.h>  /* re. atoi ... */
#include <string.h> /* re. strlen, strcpy, strchr... */
#include <ctype.h> /* re. tolower... */
#include <limits.h> /* re. INT_MAX, INt_MIN */
#include <math.h> /* re. log10 ... */

#define BIG_BUF_LEN 1024


#define MAX_DIG_IN_INT ( (int) log10( INT_MAX ) + 1 )


#ifndef dwTAKE_IN_CHAR_MORE
#define dwTAKE_IN_CHAR_MORE

int takeInChar( const char* msg )
{
int reply;
fputs( msg, stdout ); fflush( stdout );
reply = getchar();
if( reply != '\n' )
while( getchar() != '\n' ) ; /* 'flush' stdin buffer */
return reply;
}

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

#endif


/* since using 'static' buf inside, memory persists ... so can return address */
char* takeInStaticString( const char* msg, unsigned max_len )
{
static char buf[BIG_BUF_LEN];
char* p = NULL;

for( ; ; )
{
fputs( msg, stdout ); fflush( stdout );

fgets( buf, BIG_BUF_LEN, stdin );

/* Now 'fix' fgets input string or stdin
i.e. fix what needs 'fixing') */

p = strchr( buf, '\n' );
if( p ) /* strip off '\n' char if present */
*p = 0;
else /* flush stdin to end of line */
while( getchar() != '\n' );


if( buf[0] && strlen( buf ) <= max_len )
break;
else if( !buf[0] ) printf( "\nBlank line NOT valid input here ... \n" );
else printf( "\nFor '%s', max len of %u char's was exceeded ... \n",
buf, max_len );
}

return buf;
}


/* accepts only positive (i.e. >= 0) valid int range of values ... */
int takeInValidPosIntViaStaticString( const char* prompt, int high )
{
char loc_buf[32], *tmpStr;
int good = 0, i = 0, len = 0, tmpInt = 0;

for( ; ; ) /* an example of a C/C++ forever loop ... until 'return' */
{
tmpStr = takeInStaticString( prompt, MAX_DIG_IN_INT );
len =  i = strlen( tmpStr );
good = ( i > 0 );
while( good && --i >= 0 )
{
if( !isdigit( tmpStr[i] ) ) { good = 0; break; }
}

if( good && len == MAX_DIG_IN_INT )
{
sprintf( loc_buf, "%d", INT_MAX );
if( strcmp( tmpStr, loc_buf ) > 0 ) good = 0;
}

if( good && tmpInt <= high )
{
tmpInt = atoi( tmpStr );
break;
}
/*else ...*/
printf( "\nInvalid input! Integers only please, in valid range 0..%d\n",
high );
}
return tmpInt;
}

/*  returns a valid int in range INT_MIN..INT_MAX */
int takeInValidMinMaxIntViaStaticString( const char* prompt, int myMin, int myMax )
{
char loc_buf[32];
int tmpInt;

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

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

len = i = strlen( tmp );
good = ( i > 0 && i <= MAX_DIG_IN_INT );
while( good && --i >= 0 )
{
if( !isdigit( tmp[i] ) ) good = 0;
}

if( good && len == MAX_DIG_IN_INT )
{
if( sign == 1 )
{
sprintf( loc_buf, "%d", INT_MAX );
if( strcmp( tmp, loc_buf ) > 0 ) good = 0;
}
else
{
sprintf( loc_buf, "%d", INT_MIN );
if( strcmp( tmp, &loc_buf[1] ) > 0 ) good = 0;
}
}

if( good )
{
tmpInt = sign * atoi( tmp );
if( tmpInt >= myMin && tmpInt <= myMax ) break;
}
/*else ...*/
printf( "\nInvalid input! Integers please, only in range %d..%d\n",
myMin, myMax );
}
return tmpInt;
}

#endif



Now a little different set of C utilities all in a .h file and a little test program follows ...

/*
    features ... an expedient way in C to handle string input from keyboard operator ...
    especially, if design calls to repeat input until string is of 'acceptable length'

    using a passed in C string 'buf' with passed in length of 'bufLen'

    char* takeInStr( const char* msg, char* buf, unsigned bufLen, unsigned maxStrLen );

    int takeInValidIntViaStrBuf( const char* msg );

    int takeInValidIntViaStrBufInRangeMinMax( const char* msg, int min, int max );
*/

Code: [Select]
/* Cutilities.h */  /* 2016-06-20 */

#ifndef CUTILITIES_H
#define CUTILITIES_H


#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <limits.h>

#define MAX_DIG_IN_INT (int)( log10( INT_MAX ) + 1 )


#ifndef dwTAKE_IN_CHAR_MORE
#define dwTAKE_IN_CHAR_MORE

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

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

#endif

#ifndef dwFIXEDFGETS
#define dwFIXEDFGETS

/* example of a way to fix fgets TWO, sometimes very annoying, problems */
char* fixedFgets( char* s, size_t bufSize, FILE* fin )
{
    if( fgets( s, bufSize, fin ) )
    {
        char *p = strchr( s, '\n' ),
             c ;
        if( p ) *p = 0; /* strip off '\n' at end ... iF it exists */
        else while( (c = fgetc( fin )) != '\n'  &&  c != EOF ) ; /* flush... */
        return s;
    }
    /*  else ... if reach here ... */
    return NULL;
}


#endif

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

    for( --end; s <= end && isspace(*end); --end ) ;
    end[1] = 0;

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

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

    while( isspace(*s) ) ++s;
    memmove( start, s, end+1-s ); /* 1 ... to copy terminal 0 */
    return start;
}
#endif


#ifndef dwTOCAPSONFIRSTLETS
#define dwTOCAPSONFIRSTLETS

/* an example of a common design request ... */
char* toCapsOnFirstLets( char* str )
{
    char* p = str;
    char prev = ' ';
    while( *p )
    {
        if( prev == ' ' ) *p = toupper( *p );
        prev = *p;
        ++p;
    }
    return str;
}

#endif

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

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

/*
    example of an expedient way in C to handle string input from keyboard operator ...
    especially, if design calls to repeat input until string is of 'acceptable length'

*/
char* takeInStr( const char* msg, char* buf, unsigned bufLen, unsigned maxStrLen )
{
    unsigned len = 0;
    if( maxStrLen < bufLen )
    {
        for( ; ; ) /* on example of a C 'forever loop' ...
                      until break from loop or return from function */
        {
            printf( msg ); fflush( stdout );
            fixedFgets( buf, bufLen, stdin );
            trim( buf );
            len = strlen( buf );
            if( len  &&  len <= maxStrLen ) return buf;
            else
            {
                if( len ) printf( "\nError! myMax input string length here "
                                  "is %d char's long ...\n"
                                  "but, your string was %d char's long.\n",
                                  maxStrLen, len );
                else printf( "\nBlank lines NOT valid input here ...\n" );
            }
        }
    }
    /* else ... */
    printf( "\nERROR!  The bufLen of %d needs to be greater than %d\n",
            bufLen, maxStrLen );
    return NULL;
}


/* a simple student way to handle numeric input ...
   so program won't crash on bad input */
int takeInValidIntInRangeMinMax( const char* msg, int myMin, int myMax )
{
    int good = 0, val = 0;
    while( !good )
    {
        printf( msg ); fflush( stdout );

        if( scanf( "%d", &val ) == 1 && getchar() == '\n' ) good = 1;
        else
        {
            printf( "\nInteger input only here please ...\n" );
            while( getchar() != '\n' ) ; /* flush stdin ... */
        }

        if( good &&  val >= myMin && val <= myMax ) break;
        else
        {
            good = 0;
            printf( "\nValid input only in range %d..%d\n", myMin, myMax );
        }
    }
    return val;
}

int takeInValidInt( const char* msg )
{
    int val = 0;
    while( 1 )
    {
        printf( msg ); fflush( stdout );

        if( scanf( "%d", &val ) == 1 && getchar() == '\n' )
        {
        return val;
        }
        /* else ... **/
       
        printf( "\nInteger input only here please ...\n" );
        while( getchar() != '\n' ) ; /* flush stdin ... */ 
    }
}

int takeInValidIntViaStrBuf( const char* msg )
{
char loc_buf[32], loc_buf2[32], *tmpStr;
int good = 1, i = 0, len =0, sign = 1, tmpInt = 0;

for( ; ; ) /* an example of a C/C++ forever loop ... until 'return' */
{

/* NOTE: blank lines NOT allowed as input below... and leave room for + -  */
tmpStr = takeInStr( msg, loc_buf, sizeof(loc_buf), MAX_DIG_IN_INT+1 );

/* handle sign if present ... */
if( tmpStr[0] == '+' ) ++tmpStr;
else if( tmpStr[0] == '-') { ++tmpStr; sign = -1; }

len = i = strlen( tmpStr );

/* make sure has at least 1 dig ... and NOT too many dig's ... */
good = ( i > 0 && i <= MAX_DIG_IN_INT );

/* make sure all digits ... */
while( good && --i >= 0 )
{
if( !isdigit( tmpStr[i] ) ) { good = 0; break; }
}

/* make sure fits intn an int ...*/

if( good && len == MAX_DIG_IN_INT )
{
if( sign == 1 )
{
sprintf( loc_buf2, "%d", INT_MAX );
if( strcmp( tmpStr, loc_buf2 ) > 0 ) good = 0;
}
else
{
sprintf( loc_buf2, "%d", INT_MIN );
if( strcmp( tmpStr, &loc_buf2[1] ) > 0 ) good = 0;
}

}

if( good )
{
tmpInt = atoi( loc_buf );
break;
}
/*else ...*/
printf( "\nInvalid input! Integers please, only in range %d..%d\n",
INT_MIN, INT_MAX );
}

return tmpInt;
}

int takeInValidIntViaStrBufInRangeMinMax( const char* msg, int min, int max )
{
char loc_buf[32], loc_buf2[32], *tmpStr;
int good = 1, i = 0, len =0, sign = 1, tmpInt = 0;

for( ; ; ) /* an example of a C/C++ forever loop ... until 'return' */
{

/* NOTE: blank lines NOT allowed as input below... and leave room for + -  */
tmpStr = takeInStr( msg, loc_buf, sizeof(loc_buf), MAX_DIG_IN_INT+1 );

/* handle sign if present ... */
if( tmpStr[0] == '+' ) ++tmpStr;
else if( tmpStr[0] == '-') { ++tmpStr; sign = -1; }

len = i = strlen( tmpStr );

/* make sure has at least 1 dig ... and NOT too many dig's ... */
good = ( i > 0 && i <= MAX_DIG_IN_INT );

/* make sure all digits ... */
while( good && --i >= 0 )
{
if( !isdigit( tmpStr[i] ) ) { good = 0; break; }
}

/* make sure fits intn an int ...*/

if( good && len == MAX_DIG_IN_INT )
{
if( sign == 1 )
{
sprintf( loc_buf2, "%d", INT_MAX );
if( strcmp( tmpStr, loc_buf2 ) > 0 ) good = 0;
}
else
{
sprintf( loc_buf2, "%d", INT_MIN );
if( strcmp( tmpStr, &loc_buf2[1] ) > 0 ) good = 0;
}
}

if( good )
        {
            tmpInt = atoi(loc_buf);
            if( tmpInt >=  min && tmpInt <= max  ) break;
        }
/* else ... */
printf( "\nERROR!  Valid input range here is %d..%d\n", min, max );
}
return tmpInt;
}


#endif



Code: [Select]
/* test_Cutilities.c */  /*  2013-07-11 */


#include "Cutilities.h"

void test_takeInStr()
{
char loc_buf[32];
char* tmp = takeInStr( "Enter your name(s): ",
loc_buf, sizeof(loc_buf), sizeof(loc_buf)-1 );

printf( "The string that was taken in was : '%s'\n", tmp );

toCapsOnFirstLets( tmp );
printf( "With CAPS On All First Letters   : '%s'\n", tmp );
}

void test_takeInValidInt()
{
int tmp = takeInValidInt( "Enter an int: " );
printf( "You entered %d\n", tmp );
}

void test_takeInValidIntInRangeMinMax()
{
char loc_buf[128];
int min = takeInValidInt( "Enter min value to accept: " );
int max = 0, tmpInt = 0;

while( ( max = takeInValidInt( "Enter max value to accept: " )) < min )
{
printf( "\nERROR!  Valid inout range here if %d..%d\n", min, INT_MAX );
}

/* form message ...*/
sprintf( loc_buf, "Enter integer in range %d..%d: ", min, max );
tmpInt = takeInValidIntInRangeMinMax( loc_buf, min, max );
printf( "You entered %d\n", tmpInt );
}

void test_takeInValidIntViaStringBuf()
{
int tmpInt = takeInValidIntViaStrBuf( "Enter a valid int: " );
printf( "You entered %d\n", tmpInt );
}

void test_takeInValidIntViaStrBufInRangeMinMax()
{
char loc_buf[128];
int min = takeInValidIntViaStrBuf( "Enter min value to accept: " );
int max = 0, tmpInt = 0;

while( ( max = takeInValidIntViaStrBuf( "Enter max value to accept: " )) < min )
{
printf( "\nERROR!  Valid inout range here if %d..%d\n", min, INT_MAX );
}

/* form message ...*/
sprintf( loc_buf, "Enter integer in range %d..%d: ", min, max );

tmpInt = takeInValidIntViaStrBufInRangeMinMax( loc_buf, min, max );
printf( "You entered %d\n", tmpInt );
}





int main()
{
printf( "INT_MIN = %d,  INT_MAX = %d\n\n", INT_MIN, INT_MAX );
printf( "Max mumber of digits permitted in an 'int' here is %d\n\n",
MAX_DIG_IN_INT );

do
{
puts( "Testing 'takeInStr( buf, bufLen, maxStrLen )' ..." );
test_takeInStr();

puts( "\nTesting 'takeInInt( msg )' ..." );
test_takeInValidInt();

puts( "\nTesting 'takeInValidIntInRangeMinMax( msg, min, max )' ..." );
test_takeInValidIntInRangeMinMax();

puts( "\nTesting 'takeInValidIntViaStringBuf( msg )' ..." );
test_takeInValidIntViaStringBuf();

puts( "\nTesting 'takeInValidIntViaStrBufInRangeMinMax( msg, min, max )' ..." );
test_takeInValidIntViaStrBufInRangeMinMax();

putchar( '\n' );
}
while( tolower( takeInChar( "\nMore (y/n) ? " )) != 'n' );
return 0;
}
« Last Edit: June 21, 2015, 07:12:52 PM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: C SOME UTILITY functions ...
« Reply #4 on: May 29, 2013, 10:00:30 AM »
Two files of several utilities that you may like to have to include ... the first uses fgets ... the 2nd uses readLine


Code: [Select]
/* fixedFgets.h */ /* 2012-06-01 */

/* updated to also have dwUPDOWN strToUpper and strToLower on 2013-04-03 */

#ifndef FIXEDFGETS_H
#define FIXEDFGETS_H

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


#ifndef MAX_LINE_LEN
#define MAX_LINE_LEN 1023
#endif

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

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

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

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

    for( --end; s <= end && isspace(*end); --end ) ;
    end[1] = 0;

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

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

    while( isspace(*s) ) ++s;
    memmove( start, s, end+1-s ); // 1 ... to copy terminal 0 //
    return start;
}
#endif

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

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



char* fixedFgets( char* s, size_t bufSize, FILE* fin )
{
    if( fgets( s, bufSize, fin ) )
    {
        char *p = strchr( s, '\n' ), c ;
        if( p ) *p = 0; /* strip off '\n' at end ... IF it exists */
        else while( (c = fgetc( fin )) != '\n'  &&  c != EOF ) ; /* flush... */
        return s;
    }
    else return NULL;
}

char* newFgets( FILE* fin )
{
    char buf[MAX_LINE_LEN+1];
   
    if( fgets( buf, sizeof(buf), fin ) )
    {
        char *p = strchr( buf, '\n' ), c ;
        if( p ) *p = 0; /* strip off '\n' at end ... IF it exists */
        else while( (c = fgetc( fin )) != '\n'  &&  c != EOF ) ; /* flush... */
        return newCopy( buf );
    }
    else return NULL;
}

#endif


Code: [Select]
/* takeIn_readLine_utilities.h */  /* 2015-06-21 */


#ifndef TAKEIN_READLINE_UTILITIES_H
#define TAKEIN_READLINE_UTILITIES_H


#include <math.h>
#include <limits.h>
#include "readLine.h" /* see readLine.h to see all that is included ... */


#define MAX_DIG_IN_INT (int)( log10( INT_MAX ) + 1 )


#ifndef dwTAKE_IN_CHAR_MORE
#define dwTAKE_IN_CHAR_MORE

int takeInChar( const char* msg )
{
int reply;
fputs( msg, stdout ); fflush( stdout );
reply = getchar();
if( reply != '\n' )
while( getchar() != '\n' ) ; /* 'flush' stdin buffer */
return reply;
}

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

#endif


#ifndef dwTOCAPSONFIRSTLETS
#define dwTOCAPSONFIRSTLETS

/* an example of a common design request ... */
/* an example of a common design request ... */
char* toCapsOnFirstLets( char* str )
{
    char* p = str;
    char prev = ' ';
    while( *p )
    {
        if( prev == ' ' ) *p = toupper( *p );
        prev = *p;
        ++p;
    }
    return str;
}

#endif

/* using readLine and getting new dynamic memory  ... so can return address */
char* takeInStrMaxLen( const char* msg, unsigned maxLen )
{
char* p = NULL;

for( ; ; )
{
fputs( msg, stdout ); fflush( stdout );

p = readLine( stdin );

if( p[0] && strlen( p ) <= maxLen )
break;
else if( !p[0] ) printf( "\nBlank line NOT valid input here ... \n" );
else printf( "\nFor '%s', max len of %u char's was exceeded ... \n",
p, maxLen );
free( p );
}

return p;
}

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



/* accepts only positive (i.e. >= 0) valid int range of values ... */
int takeInValidPosInt( const char* prompt, int high )
{
char loc_buf[32], *tmpStr;
int good = 0, i = 0, len = 0, tmpInt = 0;

for( ; ; ) /* an example of a C/C++ forever loop ... until 'return' */
{
tmpStr = takeInStrMaxLen( prompt, MAX_DIG_IN_INT );
len =  i = strlen( tmpStr );
good = ( i > 0 );
while( good && --i >= 0 )
{
if( !isdigit( tmpStr[i] ) ) { good = 0; break; }
}

if( good && len == MAX_DIG_IN_INT )
{
sprintf( loc_buf, "%d", INT_MAX );
if( strcmp( tmpStr, loc_buf ) > 0 ) good = 0;
}

if( good && tmpInt <= high )
{
tmpInt = atoi( tmpStr );
free( tmpStr );
break;
}
/* else ...*/
printf( "\nInvalid input! Integers only please, in valid range 0..%d\n",
high );
free( tmpStr );
}
return tmpInt;
}

/*  returns a valid int in range INT_MIN..INT_MAX */
int takeInValidMinMaxInt( const char* prompt, int myMin, int myMax )
{
char loc_buf[32];
int tmpInt;

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


for + - */
char* tmpCpy = tmp;

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

len = i = strlen( tmp );
good = ( i > 0 && i <= MAX_DIG_IN_INT );
while( good && --i >= 0 )
{
if( !isdigit( tmp[i] ) ) good = 0;
}

if( good && len == MAX_DIG_IN_INT )
{
if( sign == 1 )
{
sprintf( loc_buf, "%d", INT_MAX );
if( strcmp( tmp, loc_buf ) > 0 ) good = 0;
}
else
{
sprintf( loc_buf, "%d", INT_MIN );
if( strcmp( tmp, &loc_buf[1] ) > 0 ) good = 0;
}
}

if( good )
{
tmpInt = atoi( tmpCpy );
if( tmpInt >= myMin && tmpInt <= myMax )
{
free( tmpCpy );
break;
}
}
/* else ...*/
printf( "\nInvalid input! Integers please, only in range %d..%d\n",
myMin, myMax );
free( tmpCpy );
}
return tmpInt;
}

/*  returns a valid int in range INT_MIN..INT_MAX */
int takeInValidInt( const char* prompt )
{
char loc_buf[32];
int tmpInt;

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


for + - */
char* tmpCpy = tmp;

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

len = i = strlen( tmp );
good = ( i > 0 && i <= MAX_DIG_IN_INT );
while( good && --i >= 0 )
{
if( !isdigit( tmp[i] ) ) good = 0;
}

if( good && len == MAX_DIG_IN_INT )
{
if( sign == 1 )
{
sprintf( loc_buf, "%d", INT_MAX );
if( strcmp( tmp, loc_buf ) > 0 ) good = 0;
}
else
{
sprintf( loc_buf, "%d", INT_MIN );
if( strcmp( tmp, &loc_buf[1] ) > 0 ) good = 0;
}
}

if( good )
{
tmpInt = atoi( tmpCpy );
free( tmpCpy );
break;
}
/* else ...*/
printf( "\nInvalid input! Integers please, only in range %d..%d\n",
INT_MIN, INT_MAX );
free( tmpCpy );
}
return tmpInt;
}

#endif
« Last Edit: June 21, 2015, 07:17:45 PM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: C SOME UTILITY functions ...
« Reply #5 on: May 29, 2013, 10:07:12 AM »
Example of binary search of array ... recursive and non recursive ...

Code: [Select]
/* test_binarySearch_intAry.c */


#include <stdio.h>

/* recursive ... */
int rBinarySearch( const int a[], int low, int high, int target )
{
    int mid;

    if( high < low ) return -1; /* NOT found ... */

    mid = low + ( ( high - low ) >> 1 ); /*  ( low + hign ) / 2   */

    if( target < a[mid] ) return rBinarySearch( a, low, mid - 1, target );
    /* else if ... */
    if( target > a[mid] ) return rBinarySearch( a, mid + 1, high, target );
    /* else ... */
    return mid; /* FOUND at this index = mid */
}

/* iterative ...
   if multiple same target values ... finds index of first target value in ary */
int iBinarySearch( const int ary[], int low, int high, int target )
{
    while( low < high )
    {
        int mid = low + ( ( high - low ) >> 1 ); /*   ( low + hign ) / 2   */

        if( ary[mid] < target  ) low = mid + 1;
        else high = mid;
    }

    /* when reach here ... */
    if( high == low && target == ary[low] ) return low;
    /* else ... */
    return -1;
}


int main()
{
    int a[] = { 0, 2, 4, 6, 8 };
    int i, j, size = sizeof(a) / sizeof(int);

    for( i = a[0]; i <= a[size-1]; ++ i)
    {
        j = iBinarySearch( a, 0, size-1, i );
        if( j == -1 )
            printf( "%d was NOT found in array ...\n", i );
        else
        {
            printf( "%d WAS found in array at index %d...\n", i, j );
        }
    }

    printf( "\nPress 'Enter' to continue/exit ... " ); fflush( stdout );
    getchar() ;
    return 0;
}
« Last Edit: May 29, 2013, 11:26:11 AM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: C SOME UTILITY functions ...
« Reply #6 on: May 31, 2013, 06:51:06 AM »
Some CTIME ... today's date and time now ... utilities ... and a little test program follows ...



Code: [Select]
/* date_ctime.h */ /* 2013-05-30 */


#ifndef GET_DATE_H
#define GET_DATE_H

#ifndef OFFSET
#define OFFSET 1
#endif

/*
    Demo of C ctime to get date/time info ...
    (uses #include <time.h>)

    Demo of table lookup ... sscanf ... sprintf

    For BEGINNING COMPUTER PROGRAMMING using HLA, Python, C/C++
    http://developers-heaven.net/forum/index.php/topic,46.0.html
*/

#include <stdio.h>
#include <stdlib.h> /* atoi */
#include <string.h> /* strcmp, strncpy, strlen */
#include <time.h>   /* time_t now = time(0); ctime(&now) */


typedef struct
{
    int year;
    int month;
    int day;
    int dow; /* day of week range 0..6 */
   
    char time[6]; /* time 00:00..23:59 */
   
    char yearStr[5];
    char monthStr[10]; /* "September" + '\0' = 10 char's */
    char dowStr[10]; /* "Wednesday" + '\0' = 10 char's */
    char dummy;
   
} DateData ;

void printDateData( const DateData* dd )
{
printf( "%04d-%02d-%02d, day of week number is %d, and time now is %s\n",
dd->year, dd->month, dd->day, dd->dow, dd->time );
}


/* If passed in ... month = 9, offset = 1, returns 'September'... */
char* getMonthStr( int month )
{
    static char* months[] =
{
    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
    "January", "February", "March", "April", "May", "June",
"July", "August", "September", "October", "November", "December", " "
} ;
    if( month > 0 && month < 13 ) return months[month-1+OFFSET*12];
    /* else ... */
    return months[24]; /*  returns " "  */
}
/* If passed in day =5, offset = 1, returns 'Friday' */
char* getWeekDayStr( int day ) /* day in range 0..6 */
{
static char* weekdays[] =
{
"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
  "Sunday", "Monday", "Tuesday", "Wednesday",
"Thursday", "Friday", "Saturday", " "
} ;
    if( day >= 0 && day <= 6 )return weekdays[day+OFFSET*7];
    /* else ...*/
    return weekdays[14]; /*  returns " "  */
}

char* getMonthNumStr( const char* monthStr )
{
static char* monthNumStr[] =
{
    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec",
    "01", "02", "03", "04", "05", "06",
    "07", "08", "09", "10", "11", "12", " "
} ;
int i;
for( i = 0; i < 12; ++i )
if( strcmp( monthNumStr[i], monthStr) == 0 )
return monthNumStr[i+12];
return monthNumStr[24];
}

char* getWeekDayNumStr( const char* dayStr )
{
static char* dayNumStr[] =
{
    "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat",
    "01", "02", "03", "04", "05", "06", "07", " "
} ;
int i;
for( i = 0; i < 7; ++i )
if( strcmp( dayNumStr[i], dayStr) == 0 )
return dayNumStr[i+7];
return dayNumStr[14];
}


char* getDateNowStr( char dateNowStr[] ) /* must be 11 or more char's long */
{
    char dateTimeStr[25]; /* leave room for '\0' at end */
    char weekDayStr[4], monthStr[4], mDayNumStr[3], timeStr[9], yearStr[5];

    time_t now = time(0);
    memcpy( dateTimeStr, ctime(&now), 24 ); /* leave off '\n' char */
    dateTimeStr[24] = 0; /* so can print out as C string, if desired */

    /* Ok ... now we can parse the string dateTimeStr into 5 sub-strings */

    /* Fri Feb 12 16:22:24 2009 */
    sscanf( dateTimeStr, "%s %s %s %s %s",
            weekDayStr, monthStr, mDayNumStr, timeStr, yearStr );
    sprintf( dateNowStr, "%s-%s-%s", yearStr, getMonthNumStr( monthStr ), mDayNumStr );
   
    return dateNowStr;
}

char* getDateNowStrPlain( char dateNowStr[] ) /* must be 9 or more char's long */
{
    char dateTimeStr[25]; /* leave room for '\0' at end */
    char weekDayStr[4], monthStr[4], mDayNumStr[3], timeStr[9], yearStr[5];

    time_t now = time(0);
    memcpy( dateTimeStr, ctime(&now), 24 ); /* leave off '\n' char */
    dateTimeStr[24] = 0; /* so can print out as C string, if desired */

    /* Ok ... now we can parse the string dateTimeStr into 5 sub-strings ... */

    /* Fri Feb 12 16:22:24 2009 */
    sscanf( dateTimeStr, "%s %s %s %s %s",
            weekDayStr, monthStr, mDayNumStr, timeStr, yearStr );
    sprintf( dateNowStr, "%s%s%s", yearStr, getMonthNumStr( monthStr ), mDayNumStr );
    return dateNowStr;
}


void getNowDateData( DateData* dd )
{
char dateTimeStr[25]; /* leave room for '\0' at end */
    char weekDayStr[4], monthStr[4], mDayNumStr[3], timeStr[9], yearStr[5];

    time_t now = time(0);
    memcpy( dateTimeStr, ctime(&now), 24 ); /* leave off '\n' char */
    dateTimeStr[24] = 0; /* so can print out as C string, if desired */

    /* Ok ... now we can parse the string dateTimeStr into 5 sub-strings ... */

    /* Fri Feb 12 16:22:24 2009 */
    sscanf( dateTimeStr, "%s %s %s %s %s",
            weekDayStr, monthStr, mDayNumStr, timeStr, yearStr );
    /* sprintf( s, "%s%s%s", yearStr, getMonthNumStr( monthStr ), mDayNumStr ); */
   
    dd->day = atoi( mDayNumStr );
    dd->month = atoi( getMonthNumStr( monthStr ) );
    dd->year = atoi( yearStr );
    dd->dow = atoi( getWeekDayNumStr( weekDayStr ) );
    memcpy( dd->time, timeStr, 5 );
    dd->time[5] = 0;
   
strcpy( dd->dowStr, getWeekDayStr( dd->dow ) );
    strcpy( dd->monthStr, getMonthStr( dd->month ) );
    sprintf( dd->yearStr, "%04d", dd->year );
}

#endif


Now ... the test program ...

Code: [Select]
/* test_date_ctime.h.c */ /* 2013-05-30 */

/* #define OFFSET 0 */ /* for short form of month and day names */

#include "date_ctime.h"


int main()
{
char loc_buf[128];
DateData today;

getNowDateData( &today );
printDateData( &today );

printf( "getDateNowStr( loc_buf ) = %s\n", getDateNowStr( loc_buf ) );
printf( "getDateNowStrPlain( loc_buf ) = %s\n", getDateNowStrPlain( loc_buf ) );
printf( "%s %s %d, %d @ %s\n",
today.dowStr, today.monthStr, today.day, today.year, today.time );

printf( "\nPress 'Enter' to exit ... " ); fflush( stdout );
getchar();

return 0;
}

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: C SOME UTILITY functions ...
« Reply #7 on: May 31, 2013, 10:33:18 AM »
isValidDate ... isValidDOB ... inclusive days between two dates (first the test file then the new include .h file ... which also includes file date_ctime.h  ... and the test program needs to also include ... Cutilities.h ... so all together here, you will need all FOUR FILES in your working folder/directory before you compile this next 'test' file ...



Code: [Select]
/* test_isValidDate.h.c */  /* 2013-05-31 */

#include "isValidDate.h"

#include "Cutilities.h"




int main()
{
char locBuf[128], locBuf2[128], *date, *date2, *today;

int dayOfWeek = 0, iDaysBetween = 0;

do
{
for( ; ; )
{
date = takeInStr( "Enter valid date yyyymmdd : ", locBuf, sizeof(locBuf), 8 );
if( isValidDate( date ) ) break;
/* else ... */
printf( "\nTry again ... %s was NOT a valid date.\n", date );
}
printf( "\nYou took in date %s\n", date );
dayOfWeek = getDayOfWeek( date );
printf( "%s was on a %s\n", date, getWeekDayStr( dayOfWeek ) );

for( ; ; )
{
date2 = takeInStr( "\nEnter valid date yyyymmdd : ", locBuf2, sizeof(locBuf2), 8 );
if( isValidDate( date2 ) ) break;
/* else ... */
printf( "\nTry again ... %s was NOT a valid date.\n", date2 );
}
printf( "\nYou took in date %s\n", date2 );
dayOfWeek = getDayOfWeek( date2 );
printf( "%s is %s\n", date2, getWeekDayStr( dayOfWeek ) );

iDaysBetween = inclusiveDaysBetween( date, date2 );
printf( "\nInclusive days between %s and %s = %d\n", date, date2, iDaysBetween );

today  = getDateNowStrPlain( locBuf2 );
printf( "\nToday is %s\n", today );
dayOfWeek = getDayOfWeek( today );
printf( "%s was on a %s\n", today, getWeekDayStr(dayOfWeek ) );

iDaysBetween = inclusiveDaysBetween( date, today );
printf( "\nInclusive days between %s and %s = %d\n", date, today, iDaysBetween );

putchar( '\n' ) ;

for( ; ; )
{
date = takeInStr( "\nEnter valid dob yyyymmdd : ", locBuf, sizeof(locBuf), 8 );
if( isValidDOB( date ) ) break;
/* else ... */
printf( "\nTry again ... %s was NOT a valid date.\n", date );
}
printf( "\nYou took in date %s\n", date );
dayOfWeek = getDayOfWeek( date );
printf( "%s was on a %s\n", date, getWeekDayStr( dayOfWeek ) );

for( ; ; )
{
date2 = takeInStr( "\nEnter valid dob yyyymmdd : ", locBuf2, sizeof(locBuf2), 8 );
if( isValidDOB( date2 ) ) break;
/* else ... */
printf( "\nTry again ... %s was NOT a valid date.\n", date2 );
}
printf( "\nYou took in date %s\n", date2 );
dayOfWeek = getDayOfWeek( date2 );
printf( "%s was on a %s\n", date2, getWeekDayStr( dayOfWeek ) );

iDaysBetween = inclusiveDaysBetween( date, date2 );
printf( "\nInclusive days between %s and %s = %d\n", date, date2, iDaysBetween );

putchar( '\n' ) ;
}
while( more() );

return 0;
}


And the new include file ...

Code: [Select]
/* isValidDate.h */ /* 2013-05-31 */



/* needs stdlib.h ( atoi ), string.h ( strlen, strncpy )*/

#ifndef IS_VALID_DATE_H
#define IS_VALID_DATE_H

#include "date_ctime.h" /* includes stdio.h, stdlib.h, string.h, time.h */


typedef struct
{
int year;
int month;
int day;
} YMD ;

void initYMD( YMD* date )
{
char loc_buf[16];
getDateNowStrPlain( loc_buf );
date->day = atoi( loc_buf + 6 );

loc_buf[6] = 0;
date->month = atoi( loc_buf + 4 );

loc_buf[4] = 0;
date->year = atoi( loc_buf );
}

YMD getYMD( const char* plainDate )
{
char loc_buf[16];
YMD date;
strcpy( loc_buf, plainDate );

date.day = atoi( loc_buf + 6 );

loc_buf[6] = 0;
date.month = atoi( loc_buf + 4 );

loc_buf[4] = 0;
date.year = atoi( loc_buf );

return date;
}



/* forward declarations ... */

int isLeapYear( int y );
int daysInMonth( int m, int y );
int isValidDOB( const char* dob ); /* 20120526 ... must be 8 char's long */
int isValidDate( const char* test );

void nextDay( char date[] ); /* updates 8 char date to next day ... */
void prevDay( char date[] ); /* updates 8 char date to prev day ... */
int inclusiveDaysBetween( const char* date1, const char* date2 );

int getDayOfWeek( const char* date );



/* definitions ... */

int isLeapYear( int y )
{
    if( y % 4 != 0 ) return 0;
    if( y % 100 == 0 && y % 400 != 0 ) return 0;
    return 1;
}

int daysInMonth( int m, int y )
{   /* -------------------> jan feb mar apr may jun jul aug sep oct nov dec */
    int daysInMonth[] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
    int days = daysInMonth[m];
    if( m == 2 && isLeapYear( y )) ++days;
    return days;
}

int isValidDOB( const char* dob )
{
    /* char date[9]; */
    YMD dOfB, d;

    if( strlen( dob ) != 8 ) return 0;
   
    /* getDateNowStrPlain( date );
    d = getYMD( date ); */
    initYMD( &d );
   
    dOfB = getYMD( dob );

    if( dOfB.year < 1600 || dOfB.year > d.year )
        return 0; /* since not valid year here */
 
    if( dOfB.year < d.year )
    {
        if( dOfB.month < 1 || dOfB.month > 12 ) return 0; /* since not valid month */
    }
    else /* dOfB.y == d.y */
    {
        if(dOfB.month < 1 || dOfB.month > d.month ) return 0; /* since not valid month */
    }

    if( dOfB.year < d.year )
    {
        if( dOfB.year < 1 || dOfB.day > daysInMonth( dOfB.month, dOfB.year ) )
            return 0; /* since not valid day */
    }
    else /* y == yy */
    {
        if( dOfB.month < d.month )
        {
            if( dOfB.day < 1 || dOfB.day > daysInMonth( dOfB.month, dOfB.year ) )
                return 0; /* since not valid day */
        }
        else /* m == mm */
        {
            if( dOfB.day < 1 || dOfB.day > d.day )
                return 0; /* since not valid day */
        }
    }
   
    /* else ... if reach here ... must be valid date, so ... */
    return 1;   
}

int isValidDate( const char* test )
{
    char buffer[5] = { 0 };
    int y, m, d;

    if( strlen( test ) != 8 ) return 0;


    memcpy( buffer, test, 4 );
    y = atoi( buffer );
    if( y < 1600 ) return 0; /* since not valid year here ... */


    memcpy( buffer, test+4, 2 );
    buffer[2] = 0; /* 0 terminate ... */
    m = atoi( buffer );
    if(m < 1 || m > 12) return 0; /* since not valid month */


    d = atoi( test+6 );
    if( d < 1 || d > daysInMonth( m, y )) return 0; /* since not valid day */

    /* else ... if reach here ... must be valid date, so ... */
    return 1;
}

void nextDay( char* date )
{
    /* get year, month, day ... */
    YMD d = getYMD( date );

    ++d.day;
    if( d.day > daysInMonth( d.month, d.year ) )
    {
        d.day = 1;
        ++d.month;
        if( d.month > 12 )
        {
            d.month = 1;
            ++d.year;
        }
    }
    sprintf( date, "%04d%02d%02d", d.year, d.month, d.day );
}

void prevDay( char* date )
{
    /* get  d, m, y ... */
    YMD d = getYMD( date );

    --d.day;
    if( d.day < 1 )
    {
        --d.month;
        if( d.month < 1 )
        {
            --d.year;
            d.month = 12;
            d.day = 31;
        }
        else d.day = daysInMonth( d.month, d.year );
    }
    sprintf( date, "%04d%02d%02d", d.year, d.month, d.day );
}

int inclusiveDaysBetween( const char* date1, const char* date2 )
{
    char buf[9];
    int days = 1;
    if( strcmp( date1, date2 ) == 0 ) return 1;

    else if( strcmp( date1, date2 ) < 0 )
    {
        memcpy( buf, date1, 9 );
        while( strcmp( buf, date2 ) < 0 ) { ++days; nextDay( buf ); }
    }
    else
    {
        memcpy( buf, date1, 9 );
        while( strcmp( buf, date2 ) > 0 ) { ++days; prevDay( buf ); }
    }
    return days;
}


int getDayOfWeek( const char* date )
{
    if( isValidDate( date ) )
    {
        int daysDif;
        char today[9];
        DateData dd;
getNowDateData( &dd );
        sprintf( today, "%04d%02d%02d", dd.year, dd.month, dd.day );
        daysDif = inclusiveDaysBetween( date, today );
        --daysDif;

        /* return (7*daysDif + dd.dOfWeek-1-daysDif) % 7; */
        return (6*daysDif + dd.dow-1) % 7 ;
    }
    printf( "%s is NOT a valid date. Returning -1 ...\n", date );
    return -1; /* 0..6 */
}

#endif

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: C SOME UTILITY functions ...
« Reply #8 on: May 31, 2013, 11:16:46 AM »
* Doesn't use windows.h ....
* Uses a call to a NOT so well known library function ...
* strftime( bufferStr, bufsize, formatString, pointer_to_struc_tm_info )



Code: [Select]
/* dateTime1.c */ /* 2013-05-31 */

/*
* Doesn't use windows.h ....
* Uses a call to a NOT so well known library function ...
* strftime( bufferStr, bufsize, formatString, pointer_to_struc_tm_info )
*
* For BEGINNING COMPUTER PROGRAMMING using HLA, Python, C/C++
* http://developers-heaven.net/forum/index.php/topic,46.0.html
*/

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

int main ()
{
char buffer [128];
    time_t rawtime;
struct tm* timeinfo;

    time( &rawtime );
    timeinfo = localtime( &rawtime ); /* to access LOCAL date/time info*/

    strftime( buffer, 128, "Time now is %I:%M %p", timeinfo );
    printf( "%s ...\n\n", buffer );

    strftime( buffer, 128, "%A %B %d, day %j of year %Y, %X %Z.", timeinfo );
    printf( "%s\n\n", buffer );

    strftime( buffer, 128, "%Y-%m-%d %X or if you like 'am/pm' it is %I:%M:%S %p", timeinfo );
    printf( "%s\n\n", buffer );

    strftime( buffer, 128, "%a %b %d, 20%y at %I:%M:%S %p", timeinfo );
    printf( "%s\n\n", buffer );

    /* Or ... get the 'bits' just the way you like ... */

    strftime( buffer, 128, "%A %B", timeinfo );
    printf( "%s", buffer ); /* print the fullDay fullMonth*/

    strftime( buffer, 128, "%d", timeinfo );
    printf( " %d, ", atoi(buffer) ); /* print the day number as an integer so NO leading '0' */

    strftime( buffer, 128, "%Y at %I:%M:%S %p", timeinfo );
    printf( "%s ", buffer ); /* print 'YYYY at hh:mm:ssAM/PM' */

    printf( "\n\nPress 'Enter' to continue ... " );
    getchar(); /* To keep Window open ... if needed. */
    return 0;
}

/*
%a    Abbreviated weekday name *                                               Thu
%A    Full weekday name *                                                 Thursday
%b    Abbreviated month name *                                                 Aug
%B    Full month name *                                                     August
%c    Date and time representation *                      Thu Aug 23 14:55:02 2001
%d    Day of the month (01-31)                                                  23
%H    Hour in 24h format (00-23)                                                14
%I    Hour in 12h format (01-12)                                                02
%j    Day of the year (001-366)                                                235
%m    Month as a decimal number (01-12)                                         08
%M    Minute (00-59)                                                            55
%p    AM or PM designation                                                      PM
%S    Second (00-61)                                                            02
%U    Week number with the first Sunday as the first day of week one (00-53)    33
%w    Weekday as a decimal number with Sunday as 0 (0-6)                         4
%W    Week number with the first Monday as the first day of week one (00-53)    34
%x    Date representation *                                               08/23/01
%X    Time representation *                                               14:55:02
%y    Year, last two digits (00-99)                                             01
%Y    Year                                                                    2001
%Z    Timezone name or abbreviation                                            CDT
%%    A % sign

    * The above specifiers whose description is marked
      with an asterisk (*) are locale-dependent.
*/




Code: [Select]
/* dateTime2.c */

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

#define SIZE_BUF 128
/*
    For BEGINNING COMPUTER PROGRAMMING using HLA, Python, C/C++
    http://developers-heaven.net/forum/index.php/topic,46.0.html
*/

int main()
{
    time_t val_time_t;
    struct tm* now;
    char buf[SIZE_BUF];

    /*  11:07:38 PM (Friday, February 19)*/
    char formatStr1[] = "%I:%M:%S %p (%A %B %d, %Y)";

    /*                 2010 050 07  5 NOTE: add 1 to j, add 1 to U */
    char formatStr2[] = "%Y %j %U %w";
    int year, dayNum, weekNum, dOfWeekNum;

    /* Get local date and time */
    val_time_t = time( NULL );
    now = localtime( &val_time_t );

    printf( "Default   : %s\n", ctime(&val_time_t) );
   
    printf
    (
        "Date/Time : %d-%02d-%02d %02d:%02d:%02d\n\n",
        now->tm_year+1900, now->tm_mon+1, now->tm_mday, /* year, month, day*/
        now->tm_hour, now->tm_min, now->tm_sec /* hours, minutes, seconds*/
    );
   
    fputs( "My format : ", stdout );
    /* using sscanf ... get int value for year, dayNum, weekNum, dOfWeekNum */
    strftime( buf, sizeof(buf), formatStr2, now ); /* use foramtStr2 ... */
    sscanf( buf, "%d %d %d %d", &year, &dayNum, &weekNum, &dOfWeekNum );
    printf("%d day %d week %d weekday %d ",
            year, dayNum, weekNum+1, dOfWeekNum+1);
    strftime( buf, sizeof(buf), formatStr1, now ); /* use formatStr1 ... */
    puts( buf );

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


/*
%a    Abbreviated weekday name *                                               Thu
%A    Full weekday name *                                                 Thursday
%b    Abbreviated month name *                                                 Aug
%B    Full month name *                                                     August
%c    Date and time representation *                      Thu Aug 23 14:55:02 2001
%d    Day of the month (01-31)                                                  23
%H    Hour in 24h format (00-23)                                                14
%I    Hour in 12h format (01-12)                                                02
%j    Day of the year (001-366)                                                235
%m    Month as a decimal number (01-12)                                         08
%M    Minute (00-59)                                                            55
%p    AM or PM designation                                                      PM
%S    Second (00-61)                                                            02
%U    Week number with the first Sunday as the first day of week one (00-53)    33
%w    Weekday as a decimal number with Sunday as 0 (0-6)                         4
%W    Week number with the first Monday as the first day of week one (00-53)    34
%x    Date representation *                                               08/23/01
%X    Time representation *                                               14:55:02
%y    Year, last two digits (00-99)                                             01
%Y    Year                                                                    2001
%Z    Timezone name or abbreviation                                            CDT
%%    A % sign

    * The above specifiers whose description is marked
      with an asterisk (*) are locale-dependent.
*/

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: C SOME UTILITY functions ...
« Reply #9 on: May 31, 2013, 12:53:20 PM »
/* findMinMaxAvgDynamicAry.c */


Code: [Select]
/* findMinMaxAvgDynamicAry.c */ /* this version 2013-06-08 */

/* error in cal of avg fixed here now ... */

/*
    C program to find minimum, maximum and average of an array of numbers ...
    (using here a dynamic array of doubles)
*/

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

/* pass in ary and size ... and ref's to min, max and avg.. */
void getMinMaxAvg( const double[], int, double*, double*,  double* );



int main( void )
{
int i, size = 0, numGood = 0;
double* obs; /* 'obs' is type 'pointer to double', a var to hold an address */
double max, min, avg;

while( size <= 0 )
{
printf( "Please enter the desired number of observations : " );
scanf( "%d", &size );
while( getchar() != '\n' ) ; /* flush all chars in stdin stream */
if( size <= 0 )
printf( "Input error! ONLY POSITIVE integers valid here... \n" );
}

if( size > 10 )
{
printf( "Sorry, %d not valid here ... so changed to 'Max = 10'\n", size );
size = 10;
}

   
obs = (double*) malloc(sizeof(double) * size);
if( obs == NULL ) return -1; /* malloc failed above ... */

/* 
now obs holds the address of the start of memory
just allocated to hold size 'doubles'
*/

for( i = 0 ; i < size  ; )
{
printf( "Observation %03d : ", i+1 );
numGood = scanf( "%lf", &obs[i] ); /*  Note: 'lf' for correct input of doubles */
while( getchar() != '\n' ) ; /* flush all chars in stdin stream */
if( numGood != 1 ) continue;
++i;
}

printf( "\nYou entered ...\n\n" );
for( i = 0; i < size; ++i )
{
printf( "%03d : ", i+1 );
printf( "%+e\n", obs[i] ); /* Note: 'e' handles doubles and float */
}
   
/* get variables to hold info returned by 'ref' */

/* Note: obs below is alread an 'address' to the array of doubles */
/* pass 'addresses' to pointer variables */
getMinMaxAvg( obs, size, &min, &max, &avg );

printf( "\nThe info you desired is : \n\n" );
printf( "Min: %e  Max: %e  Avg: %e\n\n", min, max, avg );

free( obs );

fputs( "Press 'Enter' to continue/exit ... ", stdout ); fflush( stdout );
getchar();
return 0;
}

/* note .... where we are catching 'addresses' .... */
/*  ...  inside ... we have to use the value at that address by using *var   */
void getMinMaxAvg( const double obs[], int size,
double* min, double* max,  double* avg )
{
*min = *max = *avg = 0.0; /* initial all (handles empty array size 0) */

if( size )
{
int i = 0;
*min = *max = *avg = obs[0]; /* use this as the 'opening' value */
for( i = 1; i < size; ++i ) /* start at 1 since already used 0 above */
{
*avg += obs[i]; /* sum = sum + obs[i] */
if( obs[i] < *min ) *min = obs[i]; /* update as applies */
if( obs[i] > *max ) *max = obs[i];       
}
*avg /= size;
/* when we reach here, we have updated max, min and avg */
}
}



/* findMinMaxAvgCvec.c */  /* also uses file "readLine.h" and file "Cvec.h" linked below ... */

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


/*
C program to find minimum, maximum and average of an array of numbers ...
using here a Cvec of doubles
Note: Cvec is an emulation in C of the C++ vector container ...
Cvec provides a reusable and readily expandable dynamic array in C
*/


#include "readLine.h" /* re. myAssert & also includes ...takeInChar.
stdio.h, stdlib.h, string.h, ctype.h, etc... */

typedef struct myDoubles
{
double val;
} Rec ;

void clearRec( Rec* p )
{
/* NO dynamic memory to free here,
   so to compile without warning re. 'p' ...
   set ... */
p->val = 0;
}

/* after above def's of 'Rec' and 'freeVrec' ... can NOW ... */
#include "Cvec.h"

/* pass in ref's to cv, min, max and avg... */
void getMinMaxAvg( const Cvec*, double*, double*, double* );




int main( void )
{
int i = 0;
double max, min, avg;
Rec r;
Cvec cv;
initCvec( &cv ); /* MUST initial to work ok ... */
   
for( ; ;  )
{
printf( "Enter observation %03d : ", i+1 );
if( scanf( "%lf", &r.val ) == 1 && getchar() == '\n')
{
    if( tolower(takeInChar( "Ok to accept (y/n) ? " )) == 'y' )
    {
                ++i;
                push_backCvec( &cv, &r );
                if( tolower(takeInChar( "More (y/n) ? " )) == 'n' )  break;
            }
        }
        else
        {
            while( getchar() != '\n' ) ; /* flush all chars in stdin stream */
            printf( "\nInput not accepted ... \n" );
        }
}

printf( "\nYou entered ...\n\n" );
for( i = 0; i < cv.size; ++i )
{
printf( "%03d : ", i+1 );
/* Note: 'e' handles doubles and float */
printf( "%+e\n", cv.ary[i].val );
}
   
/* get variables to hold info returned by 'ref' */


/* pass in 'addresses' to pointer variables */
getMinMaxAvg( &cv, &min, &max, &avg );

printf( "\nThe info you desired is : \n\n" );
printf( "Min: %e  Max: %e  Avg: %e\n\n", min, max, avg );

clearCvec( &cv );

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




/*  note .... 'when we are passing addresses' ....
    inside ... we have to take the value at that address by using *var   
*/
void getMinMaxAvg( const Cvec* cv, double* min, double* max,  double* avg )
{
*min = *max = *avg = 0.0; /* initial all (handles empty array size 0) */

if( cv->size )
{
int i = 0;
*min = *max = *avg = cv->ary[0].val; /* use this as the 'opening' value */
for( i = 1; i < cv->size; ++i ) /* start at 1 since already used 0 above */
{
*avg += cv->ary[i].val;
/* update as applies ... */
if( cv->ary[i].val < *min ) *min = cv->ary[i].val;
if( cv->ary[i].val > *max ) *max = cv->ary[i].val;       
}
*avg /= cv->size;
/* when we reach here, we have updated max, min and avg */
}
}



/* findMinMaxAvgClist.c */  /* also uses file "readLine.h" and file "Clist.h" linked below ... */

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


/*
C program to find minimum, maximum and average of an array of numbers ...
using here a Clist of doubles
Note: Clist is an emulation in C of the C++ list container ...
Clist provides a reusable and readily expandable dynamic list in C
*/

#include "readLine.h" /* re. myAssert & also includes ...
stdio.h, stdlib.h, string.h, cttype.h, etc... */

typedef struct myDoubles
{
double val;
struct myDoubles* next;
} Node ;

typedef Node* pNode ;

void clearNode( pNode p )
{
/* NO dynamic memory to free here,
   so to compile without warning re. 'not using p' ...
   set ... */
p->val = 0;
}

/* after above def's of 'List', 'pList' and 'clearLrec' ... can NOW ... */
#include "Clist.h"

/* Note: passing in ref's to Clist, cv, min, max ... */
void getMinMaxAvg( const Clist*, double*, double*,  double* );



int main( void )
{
int i = 0, numGood = 0;
double max, min, avg;
pNode p;
Node r;
Clist cl;
initClist( &cl ); /* MUST initial to work ok ... */
   
for( ; ;  )
{
printf( "Enter observation %03d : ", i+1 );
numGood = scanf( "%lf", &r.val ); /* 'lf' for correct input of doubles */
while( getchar() != '\n' ) ; /* flush all chars in stdin stream */
if( numGood == 1 && tolower( takeInChar( "Ok to accept (y/n) ? " )) == 'y' )
{
++i;
push_backClist( &cl, &r );
if( tolower(takeInChar( "More (y/n) ? " )) == 'n' )  break;
}
else printf( "\nInput not accepted ... \n" );
}

printf( "\nYou entered ...\n\n" );
p = cl.start;
for( ; p != NULL; p = p->next  )
{
printf( "%03d : ", ++i );
/* Note: 'e' handles doubles and float */
printf( "%+e\n", p->val );
}

/* get variables to hold info returned by 'ref' */


/* pass in 'addresses' to pointer variables */
getMinMaxAvg( &cl, &min, &max, &avg );

printf( "\nThe info you desired is : \n\n" );
printf( "Min: %e  Max: %e  Avg: %e\n\n", min, max, avg );

clearClist( &cl );

fputs( "Press 'Enter' to continue/exit ... ", stdout ); fflush( stdout );
getchar();
return 0;
}




/*  note .... 'when we are passing addresses' ....
    inside ... we have to take the value at that address by using *var   
*/
void getMinMaxAvg( const Clist* cl, double* min, double* max,  double* avg )
{
*min = *max = *avg = 0.0; /* initial all (handles empty list size 0) */

if( cl->size )
{
pNode p = cl->start;
*min = *max = *avg = p->val; /* use this as the 'opening' value */
p = p->next;
for( ; p != NULL; p = p->next )
{
*avg += p->val;
/* update as applies ... */
if( p->val < *min ) *min = p->val;
if( p->val > *max ) *max = p->val;       
}
*avg /= cl->size;
/* when we reach here, we have updated max, min and avg */
}
}



And now the links to the include files needed above ...

readLine.h

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


Cvec.h

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


Clist.h

http://developers-heaven.net/forum/index.php/topic,2582.0.html
« Last Edit: October 09, 2016, 01:45:45 PM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: C SOME UTILITY functions ...
« Reply #10 on: June 05, 2013, 06:54:40 PM »
This next series of programs illustrates possible solutions to a fairly common student problem ... a grades management system ... and by the end of this series ... I hope you can see the ease of coding that comes when you already have at hand some utility functions in .h files that can readily be included to ease your C coding.

Firstly ... the hard slugging to code it all in one big file, which file will have to be spread over TWO pages here, since that ONE BIG file has too many bytes to fit within the max page size permitted here.

Note: needs to include file"takeIn_readLine_utilities.h" and file "readLine.h"

Code: [Select]
/* StudentGradesManagementList.c */  /* revised 2016-11-02 */

/* NOTE!
         Also needed here are include files:
         takeInLine.h
         and
         readLine.h

    C/C++ students may like to see ...
   
    http://developers-heaven.net/forum/index.php/topic,127.0.html
    http://developers-heaven.net/forum/index.php/topic,134.0.html
    http://developers-heaven.net/forum/index.php/topic,106.0.html
    http://developers-heaven.net/forum/index.php/topic,46.0.html
*/

/* Globals ... */

#include "takeInLine.h" /* also includes readLine.h */

#define header1 "Student GRADES MANAGEMENT SYSTEM"
#define header2 "1. (I)nitialize Student record list in RAM\n" \
                "2. (A)dd i.e. insert in order, by name, a NEW Student record\n" \
                "3. view/(D)elete a Student record\n" \
                "4. view/(E)dit a Student record\n" \
                "5. (S)how all Student records (as inserted BY NAME above)\n" \
                "6. (F)ile all Student records presently in RAM\n" \
                "7. (R)ead all Student records on file into RAM\n" \
                "8. set/change (P)assword\n" \
                "9. e(X)it"

#define FNAME "Studentinfo.txt"
#define FNAME_PW "StudentPW.txt"
#define MIN_PW_LEN 8
#define MAX_STR_LEN 23
#define MAX_STR_LEN_STR "23"
#define MAX_ID_NUM 9999


typedef struct myStudent
{
    int id;
    char* last;
    char* first;
    int test1;
    int test2;
    int assignment;
    int labtest;
    int finalexam;
    struct myStudent* next;
} Student ;

typedef Student* pStudent;


/* can use these global var's to keep function calls much simpler ... */
pStudent pHead = NULL;
int numStudents = 0; /* to hold 'the number of Student records in memory' ...*/
int fileFlag = 0;    /* fileFlag indicates 'the need to update the file' ... */


/* forward declarations */

pStudent pFindID( int );
void add();
void insert( pStudent );
void showAll();
void viewEdit();
void viewDelete();
void view( const pStudent ) ;
void edit( pStudent );
void delStudent( pStudent );
void delAll();
void init();
void scramble( char[] );
void unscramble( char[] );
void writeAllToFile();
void exitNowYes();
int writeFile();
int readFile();
int passWord();
int newPW();
int StudentCmp( const pStudent, const pStudent );

int showMenuGetChoice()
{
    puts( header1 );

    if( numStudents != 1 )
        printf( "Presently there are %d records.\n\n", numStudents );
    else
        puts( "Presently there is 1 record in RAM.\n" );

    puts( header2 );
    return takeInChar( "\nPlease enter your selection  : " );
}



int main() /* **************  main start **************** */
{
    passWord();

    numStudents = readFile();

    for( ; ; ) /* Loop forever ... until 'return' ... */
    {
        int choice = -1; /*  error flag */
        choice = showMenuGetChoice();
        /* printf("You picked %d ... \n", choice ); */
        switch( choice )
        {
            case '1': case 'i': case 'I': init(); break; /* out of 'switch' */
            case '2': case 'a': case 'A': add(); break;
            case '3': case 'd': case 'D': viewDelete(); break;
            case '4': case 'e': case 'E': viewEdit(); break;
            case '5': case 's': case 'S': showAll(); break;
            case '6': case 'f': case 'F': writeAllToFile(); break;
            case '7': case 'r': case 'R':
            {
                /* If any were read ... will update Global variable pHead */
                int readNum = readFile();
                if( readNum > 0 )
                    numStudents = readNum; /* update Global numStudents */
            }
            break;
            case '8': case 'p': case 'P': newPW(); break;
            case '9': case 'x': case 'X': exitNowYes(); break;
            default: puts("\nNot implemented yet ...");
       
        } /* end switch */
       
    } /* end for ... */
    return 0;

} /* ******************* main end *********************** */



/* Function definitions ... */

/* A function to compare two Student records to permit sorting ... */
int StudentCmp( const pStudent pS1, const pStudent pS2 )
{
    int compare = strcmp(pS1->last, pS2->last);
    if( compare == 0 )
        return strcmp(pS1->first, pS2->first);
    return compare;
}

/* Return a pointer to the Student if ID found in list; else return NULL */
pStudent pFindID( int id )
{
    pStudent p = pHead;
    while( p != NULL )
    {
        if( p->id == id )
            return p; /* id number entered was already used */

        /* Else ... get next p to compare */
        p = p->next;
    }

    /* If reach here ... then id number not in list so ... */
    return NULL;
}

void exitNowYes()
{
    int quit = takeInChar( "\nPress 'X' to eXit  ... " );
    if( quit=='x' || quit=='X' )
    {
        if( fileFlag )
            writeAllToFile();

        printf("\nPress 'Enter' to exit right now ... ");
        if( (quit = getchar()) == '\n' )
        {
            delAll();
            exit(0);
        }
        else
            while(quit != '\n') quit = getchar(); /* flush stdin ... */
    }
}

void add() /* ... and insert in the proper place in the list. */
{
    pStudent pS;
    int ID = takeInIntPosMax        ( "Enter ID          : ", MAX_ID_NUM );

    if( pFindID(ID) || ID <= 0  ) /* i.e. if pointer returned is NOT NULL,
the id IS used */
    {
        printf( "\nID %d is NOT available.\n", ID );
        return; /* Exit to showMenuGetChoice right now ... */
    }

    /* If program reaches here, the ID just entered is available to use. */
    pS = (pStudent) newMem( sizeof(Student) );
    pS->id = ID;

    pS->last  = takeInLineMaxLen    ( "Enter Last  Name  : ", MAX_STR_LEN );
    strToTitleCase( pS->last );
    pS->first = takeInLineMaxLen    ( "Enter First Name  : ", MAX_STR_LEN );
    strToTitleCase( pS->first );

    pS->test1 = takeInIntPosMax     ( "Enter Test1       : ", 100 );
    pS->test2 = takeInIntPosMax     ( "Enter Test2       : ", 100 );
    pS->labtest = takeInIntPosMax   ( "Enter Lab Test    : ", 100 );
    pS->assignment = takeInIntPosMax( "Enter Assignmemt  : ", 100 );
    pS->finalexam = takeInIntPosMax ( "Enter Final Exam  : ", 100 );

    view( pS );

    /* Set up link to this node */
    insert( pS );
}

/* insert in list in proper order of: last name, first name */
void insert( pStudent pS )
{
    /* Firstly, we can handle the case where 'this' should be the first element. */
    if( pHead == NULL || StudentCmp( pS, pHead ) < 0 )
    {
        /* So ... it now becomes the first element ... */
        pS->next = pHead; /* old pHead becomes 2nd in list ... */
        pHead = pS; /* and ... this pS ... becomes the head of the list */
    }
    else /* NOT first ... so search the linked list for the right spot */
    {
        pStudent prev = pHead; /* Get a working copy of pHead in prev */
        /* Start comparing with element AFTER 'q' ... i.e. the 'next in' ... */
        while( prev->next != NULL && StudentCmp( prev->next, pS ) < 0 )
            prev = prev->next; /* Traverse the list ... */
        /*
            Ok, insert after 'q' by relinking the pointers (similar to above)
            ( Includes inserting at end position ... where q->next == NULL )
        */
        pS->next = prev->next; /* Inserted 'pS' is linked to 'upstream element' */
        prev->next = pS;  /* Now 'prev' is linked to the inserted 'pS' element */
    }

    /* update global variables */
    ++ numStudents;
    fileFlag = 1;
}

void showAll()
{
    pStudent p = pHead;
    int c;

    if (pHead==NULL)
    {
        puts("\nNo records in memory at present.") ;
        return;
    }

    /* If reach here ... */

    while( p!=NULL )
    {
        view( p );
        c = takeInChar( "\nPress 'Enter' to continue ... "
                        "or enter 'A' to abort ... ");
        if( c == 'a' || c == 'A' )
            return;
        p = p->next;
    }
}

void viewEdit()
{
    int yes = 0;
    int ID = takeInIntPosMax( "Enter the id number to View/Edit : ",
                              MAX_ID_NUM );
    /* see if pointer exists, i.e. get value or NULL */
    pStudent p = pFindID( ID );
    if( p ) /* if pointer returned above was not NULL ... */
    {
        view( p );
        yes = takeInChar( "\nEdit (y/n) ? " );
        if( yes=='y' || yes=='Y' )
            edit( p );
    }
    else
        printf( "\nStudent with ID number %d not found.\n", ID );
}

void view( const pStudent pS )
{
    printf
    (
        "ID number  : %d\n"
        "Last Name  : %s\n"
        "First Name : %s\n"
        "Test 1     : %d\n"
        "Test 2     : %d\n"
        "Assignment : %d\n"
        "Lab Test   : %d\n"
        "Final Exam : %d\n",
        pS->id, pS->last, pS->first,
        pS->test1, pS->test2, pS->assignment,
        pS->labtest, pS->finalexam
    );
}

void edit( pStudent pS )
{
    int ID;
    int idTmp = pS->id; /* Firstly get a backup copy of this id ... */

    pS->id = -1; /* Now ... reset old id number to a dummy value ... */

    ID = takeInIntPosMax( "Edit ID          : ", MAX_ID_NUM );
    if( pFindID( ID ) ) /* i.e. if pointer returned is not NULL, this 'ID' IS USED */
    {
        printf( "\nid %d is NOT available.\n", ID );
        pS->id = idTmp; /* Restore the id since this pS was NOT  edited */
        return; /* Exit to showMenuGetChoice right now ... */
    }

    /* If reach hear ... */

    delStudent( pS );/* Delete old record ... etc */

    pS = ( pStudent) newMem( sizeof( Student ) ); /* get new memory for new record */
    pS->id = ID;

    pS->last = takeInLineMaxLen( "Edit Last Name   : ", MAX_STR_LEN );
    strToTitleCase( pS->last );
    pS->first = takeInLineMaxLen( "Edit First Name  : ", MAX_STR_LEN );
    strToTitleCase( pS->first );

    pS->test1 = takeInIntPosMax     ( "Edit Test1       : ", 100 );
    pS->test2  = takeInIntPosMax    ( "Edit Test2       : ", 100 );
    pS->assignment = takeInIntPosMax( "Edit Assignment  : ", 100 );
    pS->labtest = takeInIntPosMax   ( "Edit Lab Test    : ", 100 );
    pS->finalexam = takeInIntPosMax ( "Edit Final Exam  : ", 100 );

    insert( pS );
}

void viewDelete()
{
    pStudent p;
    int yes = 0, ID = 0;

    ID = takeInInt( "Enter the id number to View/Delete : " );

    p = pFindID( ID ); /* see if pointer exists; i.e. get value or NULL */
    if( p ) /* i.e. if pointer returned above was not NULL ... */
    {
        view( p );
        yes = takeInChar( "\nDelete (y/n) ? " );
        if( yes == 'y' || yes == 'Y' )
            delStudent( p );
    }
    else printf("\nStudent with ID number %d not found.\n", ID);
}

void delStudent( pStudent pS )
{
    /* handle special case of 'first in list' */
    if( pS == pHead )
    {
        pHead = pS->next;
        free( pS->first );
        free( pS->last );
        free( pS );
        /* update globals ... */
        --numStudents;
        fileFlag = 1;
        return;
    }

    /* else NOT first in list, so ... */
    if( numStudents > 1 )
    {
        pStudent prev = pHead; /* set p to this initial value to start loop */
        pStudent cur = pHead->next;
        /* now find the pointer to the previous record */
        while( cur != pS )
        {
            prev = cur; /* pp holds previous pointer value ... */
            cur = cur->next; /* set to next pointer in link list chain */
        }
        /*
            Now we have a pointer to the previous Student record, so ...
            we can now point that previous record to one past this pS record
        */
        prev->next = pS->next;
        /* Now free the memory for this record ... */
        free( pS->first );
        free( pS->last );
        free( pS);
        /* and update globals */
        --numStudents;
        fileFlag = 1;
    }
}

void delAll()
{
    while( pHead != NULL )
    {
        pStudent pNext = pHead->next; /* Get a pointer to the next record. */
        free( pHead->first );
        free( pHead->last );
        free( pHead );
        pHead = pNext; /* Update pHead ... */
    }

    /* Update globals ...  */
    /* pHead = NULL; */ /* Note was updated to NULL above */
    numStudents = 0;
    fileFlag = 1;
}

/* Note: calling delAll() here ... will re-set globals as above ... */
void init()
{
    if( pHead != NULL )
    {
        if( tolower( takeInChar( "\nDo you wish to overwrite the "
                                 "records in memory y/n ? " )) == 'y' )
            delAll(); /* re-sets globals ... */
        else
        {
            if( numStudents == 1 )
                puts( "1 Student Record was left intact in memory." );
            else
                printf( "%d Student Records were left intact in memory.\n",
                        numStudents );
        }
    }
    else puts( "\nThere were no records in memory to clear." );
}
« Last Edit: November 06, 2016, 06:54:34 PM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: C SOME UTILITY functions ...
« Reply #11 on: June 05, 2013, 06:57:11 PM »
File for ...

/* StudentGradesManagement.c */ /* revised 2016-11-02 */*/

continued on this page (since it wouldn't all fit into the one page above) ...

Code: [Select]
void scramble( char s[] )
{
    int i = 0;
    int code[] = {3,1,4,1,5,9,8,6,7,0,7,0,2,8,6,9,5,3,4,2};
    while( s[i]!=0 )
    {
        s[i] = (char) ((int)s[i] - code[i]);
        ++i;
    }
}

void unscramble( char s[] )
{
    int i = 0;
    int code[] = {3,1,4,1,5,9,8,6,7,0,7,0,2,8,6,9,5,3,4,2};
    while( s[i]!=0 )
    {
        s[i] = (char) ((int)s[i] + code[i]);
        ++i;
    }
}


int passWord()
{
    /*
        Get the password in the file, if it exists, into buffer2
        and compare it with the user entry in buffer1.
    */
    char* buffer1;
    char buffer2[MAX_STR_LEN+1];
    int attempts;

    int pwOK = 0;
    FILE* fp = fopen( FNAME_PW, "r" );

    if( !fp ) /* i.e. if file FNAME_PW doesn't exit ... */
    {
        pwOK = newPW(); /* get new password ...*/
        if( pwOK ) return 1; /* report this match of passwords back ...*/
    }
    else /* File FNAME_PW does exist ... so ... */
    {
        fscanf( fp, "%s", buffer2 );
        fclose( fp );
        unscramble( buffer2 );

        /* Now ... get password entered by user into a string in buffer1. */
        for( attempts = 0; attempts < 3; ++ attempts )
        {
            buffer1 = takeInLine( "Enter password: " );
            if( strcmp( buffer1, buffer2 ) == 0 ) /* If true ... passwords matched. */
            {
                puts( "Match!\n" );
                free( buffer1 );
                return 1; /* Report this match of passwords back ...*/
            }
            free( buffer1 );
        }
    }
    /* if reach here ...*/

    printf( "NO MATCH! ... Press 'Enter' to exit ... " );
    getchar();
    exit(1); /* Quit the program right now ... */
}

int newPW()
{
    FILE* fp;
    char* buffer1;
    char* buffer2;

    for( ; ; )
    {
        /* Get the new password into a string in buffer1. */
        buffer1 =  takeInLineMaxLen( "Enter the new password (8 to " MAX_STR_LEN_STR
                                     " characters): ", MAX_STR_LEN );
        if( strlen(buffer1) >= MIN_PW_LEN )
            break;

        printf("Your password must be at least %d characters ...\n", MIN_PW_LEN );
        free( buffer1 ); /* ... and try again ...*/
    }

    /*
        Get a 'verify copy' of the new password into buffer2
        and compare it with the password in buffer1.
    */
    buffer2 = takeInLine( "Enter the new password again: " );
    if(strcmp(buffer1, buffer2)==0) /* If true ... passwords matched. */
    {
        fp = fopen(FNAME_PW, "w");
        if(fp==NULL)
        {
            printf("Error opening file %s ... Press 'Enter' to exit ... ", FNAME_PW);
            free(buffer2);
            free(buffer1);
            getchar();
            exit(2);
        }
        else
        {
            puts( "Match!\n" );
            scramble(buffer1);
            fprintf( fp, "%s", buffer1 );
            fclose( fp );
            free(buffer2);
            free(buffer1);
            return 1; /* Report this match of passwords back ...*/
        }
    }

    /* If reach here ...*/

    printf( "NO MATCH! ... Press 'Enter' to exit ... " );
    free(buffer2);
    free(buffer1);
    getchar();
    exit(3); /* Quit the program right now ... */
}

/* -------------------------------------------------------*/


void writeAllToFile()
{
    if( !fileFlag ) return;

    if( numStudents == writeFile() )
    {
        if( numStudents > 0 )
        {
            if( numStudents == 1 )
                puts("\nThe 1 Student record was safely filed.");
            else
                printf
                (
                    "\nAll %d Student records safely filed.\n",
                    numStudents
                );
        }
        fileFlag = 0;
    }
    else
    {
        printf
        (
            "\nAn error occured while filing the Student records."
            "\nPlease see the programmer for help with the problem.\n"
            "\nExiting the program now.  Press 'Enter' to continue ... "
        );
        getchar(); /* Holds window open to show above message. */
        exit(0); /* Return error number to system. */
    }
}

int writeFile()
{
    int count; /* to track the records actually written to the file */
    FILE* fp;
    pStudent p = pHead;

    if( pHead==NULL )
    {
        puts("\nNo records available ... so NO records written to file.") ;
        return 0;
    }

    fp = fopen( FNAME, "w" );
    if( fp==NULL )
    {
        printf("\nError opening file %s.  Press 'Enter' to continue ... ", FNAME);
        getchar();
        return 0;
    }

    count = 0; /* to track the records actually written to the file */
    while( p!=NULL )
    {
        fprintf
        (
            fp,
            "%d\n"
            "%s\n"
            "%s\n"
            "%d\n"
            "%d\n"
            "%d\n"
            "%d\n"
            "%d\n",
            p->id, p->last, p->first,
            p->test1, p->test2, p->assignment,
            p->labtest, p->finalexam
        );

        ++count;
        p = p->next;
    }

    fclose( fp );
    return count; /* Number of records written. */
}

int readFile()
{
    int numRecs = 0;
    FILE* fin = fopen( FNAME, "r" );
    if( fin )
    {
        Student stud;
        char* line;
        int i = 0;
        while( ( line = readLine( fin ) ) )
        {
            ++i;
            switch( i )
            {
                case 1: stud.id= atof(line); free( line ); break;
                case 2: stud.last = line; break;
                case 3: stud.first = line; break;
                case 4: stud.test1 = atof(line); free( line ); break;
                case 5: stud.test2 = atof(line); free( line ); break;
                case 6: stud.assignment = atof(line); free( line ); break;
                case 7: stud.labtest = atof(line); free( line ); break;
                default: /* i.e. case 8 */
                {
                    pStudent p;
                    stud.finalexam = atof(line);
                    free( line );
                    p = (pStudent) newMem( sizeof( Student ) );
                    memcpy( p, &stud, sizeof( Student ) );
                    insert( p );
                    ++ numRecs;
                    i = 0;
                }
            }
        }
        fclose( fin );
        fileFlag = 0;
        return numRecs;
    }
    return 0;
}
« Last Edit: November 06, 2016, 06:56:49 PM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: C SOME UTILITY functions ...
« Reply #12 on: June 05, 2013, 07:05:22 PM »
Now ... a version that INCLUDES FILE "takeInLine.h"

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

AND SO ... uses readLine ...  THUS, YOU WILL NEED TO HAVE FILE readLine.h TO INCLUDE ALSO!

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


Code: [Select]
/* StudentGradesManagementList.c */ /* revised 2013-07-11 */


#include "takeIn_readLine_utilities.h" /* revised 2013-07-11 */


/*
    C/C++ students may like to see ...
   
    http://developers-heaven.net/forum/index.php/topic,127.0.html
    http://developers-heaven.net/forum/index.php/topic,134.0.html
    http://developers-heaven.net/forum/index.php/topic,106.0.html
    http://developers-heaven.net/forum/index.php/topic,46.0.html
*/

/* Globals ... */

#define header1 "Student GRADES MANAGEMENT SYSTEM"
#define header2 "1. (I)nitialize Student record list in RAM\n" \
                "2. (A)dd i.e. insert in order, by name, a NEW Student record\n" \
                "3. view/(D)elete a Student record\n" \
                "4. view/(E)dit a Student record\n" \
                "5. (S)how all Student records (as inserted BY NAME above)\n" \
                "6. (F)ile all Student records presently in RAM\n" \
                "7. (R)ead all Student records on file into RAM\n" \
                "8. set/change (P)assword\n" \
                "9. e(X)it"
               
#define FNAME "Studentinfo.txt"
#define FNAME_PW "StudentPW.txt"
#define MIN_PW_LEN 8
#define MAX_STR_LEN 23
#define MAX_STR_LEN_STR "23"

#define sortRead 1

typedef struct myStudent
{
    int id;
    char* last;
    char* first;
    float test1;
    float test2;
    float assignment;
    float labtest;
    float finalexam;
    struct myStudent* next;
   
} Student ;

typedef Student* pStudent;

/* can use these global var's to keep function calls much simpler ... */
pStudent phead = NULL;
int numStudents = 0; /* to hold 'the number of Student records in memory' ...*/
int pwOK = 0;        /* to hold 'the password was OK' flag; 0=false & 1=true */
int fileFlag = 0;    /* fileFlag indicates 'the need to update the file' ... */

typedef struct
{
pStudent phead;
int numStudents; /* to hold 'the number of Student records in memory' ...*/
int pwOK; /* to hold 'the password was OK' flag; 0=false & 1=true */
int fileFlag; /* fileFlag indicates 'the need to update the file' ... */
} List;

void initList( List* myLst )
{
myLst->phead = NULL;
myLst->numStudents = 0;
myLst->pwOK = 0;
myLst->fileFlag = 0;
}

/* forward declarations */

pStudent pFindID( int id );
/* char* newCopy( char* str ); */
void add();
void insert( pStudent pS );
void flushStdin();
void showAll();
void viewEdit();
void viewDel();
void view( const pStudent pS) ;
void edit(pStudent pS);
void del(pStudent pS);
void delAll();
void init();
void scramble( char s[] );
void unscramble( char s[] );
void writeAllToFile();
void exitNowYes();
int writeFile();
int readFile();
int passWord();
int newPW();
int StudentCmp( pStudent pS1, pStudent pS2 );



int showMemuGetChoice()
{
    puts( header1 );
   
    if( numStudents != 1 )
printf( "Presently there are %d records.\n\n", numStudents );
    else
puts( "Presently there is 1 record in RAM.\n" );

    puts( header2 );
    return takeInChar( "\nPlease enter your selection  : " );
}




int main() /* main start * * * * * * * * * * * * * * * * * * * * * * * * * * */
{   
    int choice, readNum;
    List myLst;
    initList( & myLst );
   
    pwOK = passWord();
    myLst.pwOK = pwOK;
   
    numStudents = readFile();
    myLst.numStudents = numStudents;
   
    for( ; ; ) /* Loop forever ... until 'return' ... */
    {
        if( !pwOK )
            pwOK = passWord();
       
        choice = -1; /*  error flag */
        choice = showMemuGetChoice();
        /* printf("You picked %d ... \n", choice ); */
        switch( choice )
        {
            case '1': case 'i': case 'I': init(); break; /* out of 'switch' */
            case '2': case 'a': case 'A': add();  break;
            case '3': case 'd': case 'D': viewDel(); break;
            case '4': case 'e': case 'E': viewEdit(); break;
            case '5': case 's': case 'S': showAll(); break;
            case '6': case 'f': case 'F': writeAllToFile(); break;
            case '7': case 'r': case 'R':
            {
                /* If any were read ... will update Global variable phead */
                readNum = readFile();
                if( readNum > 0 )
                    numStudents = readNum; /* update Global numStudents */
            }
            break;
            case '8': case 'p': case 'P': pwOK = newPW(); break;
            case '9': case 'x': case 'X': exitNowYes(); break;
            default: puts("\nNot implemented yet ...");
        } /* end switch */
    } /* end for ... */
    return 0;
   
} /* main end * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */





/* Function definitions ... */


/* Return a pointer to the Student if ID found in list; else return NULL */
pStudent pFindID( int id )
{
    pStudent p = phead;
    if( p==NULL )
        return NULL; /* List empty ... so all id numbers are available */
   
    while( p != NULL )
    {
        if( p->id == id )
            return p; /* id number entered was already used */

        /* Else ... get next p to compare */
        p = p->next;
    } 
       
    /* If reach here ... then id number not in list so ... */
    return NULL;
}


void flushStdin()
{
    while( getchar() != '\n' );
}

void exitNowYes()
{
    int c, quit;
   
    printf("\nPress 'X' to eXit  ... ");
    c = quit = getchar();
    while(c != '\n') c=getchar(); /* flush stdin ... */
    if( quit=='x' || quit=='X' )
    {
        if( fileFlag )
            writeAllToFile();
           
        printf("\nPress 'Enter' to exit right now ... ");
        if( (c=getchar()) == '\n' )
            exit(0);
        else
            while(c != '\n') c=getchar(); /* flush stdin ... */
    }
}

void add() /* ... and insert in the proper place in the list. */
{
pStudent pS;
int ID = takeInValidInt( "Enter ID          :  " );

if( pFindID(ID) || ID <= 0  ) /* i.e. if pointer returned is NOT NULL,
the id IS used */
{
printf( "\nID %d is NOT available.\n", ID );
return; /* Exit to showMemuGetChoice right now ... */
}

/* If program reaches here, the ID just entered is available to use. */
pS = (pStudent) malloc( sizeof(Student) );
myAssert( ( pS != NULL ), "\nmalloc failed in add student ... \n" );

pS->id = ID;

pS->last  = takeInStrMaxLen         ( "Enter Last  Name  :  ", 20 );
pS->first = takeInStrMaxLen         ( "Enter First Name  :  ", 20 );

pS->test1 = takeInValidMinMaxInt    ( "Enter Test1       : ", 0, 100 );
pS->test2 = takeInValidMinMaxInt    ( "Enter Test2       : ", 0, 100 );
pS->labtest = takeInValidMinMaxInt  ( "Enter Assignmemt  : ", 0, 100 );
pS->finalexam = takeInValidMinMaxInt( "Enter Final Exam  : ", 0, 100 );

view( pS );

/* Set up link to this node */
insert( pS );
}

/* insert in list with last & first names in proper order */
void insert( pStudent pS )
{
    pStudent q;
   
    /* Firstly, we handle the case where 'this' should be the first element. */
    if(phead == NULL || StudentCmp(pS, phead) < 0)
    {
        /* So ... it now becomes the first element ... */
        pS->next = phead; /* old phead becomes 2nd in list ... */
        phead = pS; /* and ... this pS ... becomes the head of the list */
    }
    else /* If here ... search the linked list for the right location ... */
    {
        q = phead; /* Get a working copy of phead in q */
        /* Start comparing with element AFTER 'q' ... i.e. the 'next in' ... */
        while(q->next != NULL && StudentCmp(q->next, pS) < 0)
        {
            q = q->next; /* Traverse the list ... */
        }
        /*
            Ok, insert after 'q' by relinking the pointers (similar to above)
            ( Includes inserting at end position ... where q->next == NULL )
        */
        pS->next = q->next; /* Inserted 'pS' is linked to 'upstream element' */
        q->next = pS;  /* Now 'q' is updated to link to the new 'pS' element */
    }
   
    /* Update global variables. */
    ++numStudents;
    fileFlag = 1;
}

void showAll()
{
    pStudent p = phead;
    int c;

    if (phead==NULL)
    {
        puts("\nNo records in memory at present.") ;
        return;
    }
   
    /* If reach here ... */
   
    while( p!=NULL )
    {
        view( p );
        printf("\nPress 'Enter' to continue ... or enter 'A' to abort ... ");
        if( (c=getchar()) == 'a' || c == 'A' )
        {
            flushStdin();
            return;
        }
        while(c != '\n') c=getchar(); /* flush stdin ... */
        p = p->next;
    }
}

void viewEdit()
{
    int yes = 0, ID = 0;
    pStudent p;
   
    printf("Enter the id number to View/Edit : ");
    scanf("%d",&ID); flushStdin();
   
    p = pFindID(ID); /* See if pointer exists; i.e. get value or NULL */
    if( p )     /* i.e. if pointer returned above was not NULL ... */
    {
        view(p);
        printf("\nEdit (y/n) ? ");
        yes = getchar();
        if( yes=='y' || yes=='Y' )
        {
            while( yes!='\n' ) yes=getchar(); /* flush stdin */
            edit(p);
        }
        else while( yes!='\n' ) yes=getchar(); /* flush stdin */
    }
    else printf("\nStudent with ID number %d not found.\n", ID);
}

void view( const pStudent pS)
{
    printf
    (
        "ID number  : %d\n"
        "Last Name  : %s\n"
        "First Name : %s\n"
        "Test 1     : %.2f\n"
        "Test 2     : %.2f\n"       
        "Assignment : %.2f\n"
        "Lab Test   : %.2f\n"
        "Final Exam : %.2f\n",
        pS->id, pS->last, pS->first,
        pS->test1, pS->test2, pS->assignment,
        pS->labtest, pS->finalexam
    );   
}

void edit(pStudent pS)
{
    int ID;
    int idTmp = pS->id; /* Firstly get a backup copy of this id ... */
   
    pS->id = -1; /* Now ... reset old id number to a dummy value ... */

    printf("Edit ID          : ");
    ID = 0;
    scanf("%d", &ID); flushStdin();
   
    if( pFindID(ID) ) /* i.e. if pointer returned is not NULL, this 'ID' IS USED */
    {
        printf("\nid %d is NOT available.\n", ID );
        pS->id = idTmp; /* Restore the id since this pS was NOT  edited */
        return; /* Exit to showMemuGetChoice right now ... */
    }
   
    /* If reach hear ... */
   
    del(pS);/* Delete old record ... etc */
   
    pS = (pStudent) malloc(sizeof(Student)); /* get new memory for new record */
    pS->id = ID;
   
    printf("Edit Last Name   : ");
    pS->last = readLine(stdin);
    printf("Edit First Name  : ");
    pS->first = readLine(stdin);     

    printf("Edit Test1       : ");
    scanf( "%f", &pS->test1 );      flushStdin();       
    printf("Edit Test2       : ");
    scanf( "%f", &pS->test2 );      flushStdin(); 
    printf("Edit Assignment  : ");
    scanf( "%f", &pS->assignment ); flushStdin();       
    printf("Edit Lab Test    : ");
    scanf( "%f", &pS->labtest );    flushStdin();
    printf("Edit Final Exam  : ");
    scanf( "%f", &pS->finalexam );  flushStdin();
   
    insert( pS );
}

void viewDel()
{
    pStudent p;
    int yes = 0, ID = 0;

    printf("Enter the id number to View/Delete : ");
    scanf("%d",&ID); flushStdin();
   
    p = pFindID(ID); /* See if pointer exists; i.e. get value or NULL */
    if( p ) /* i.e. if pointer returned above was not NULL ... */
    {
        view(p);
        printf("\nDelete (y/n) ? ");
        yes = getchar();
        if( yes=='y' || yes=='Y' ) { del(p); fileFlag = 1; }
        while( yes!='\n' ) yes=getchar(); /* flush stdin */
    }
    else printf("\nStudent with ID number %d not found.\n", ID);
}

void del(pStudent pS)
{
    pStudent p,
             pp; /* to hold the pointer to the previous record */

    /* Handle special case of 'first in list' */
    if( pS==phead )
    {
        phead = pS->next;
        free( pS->first );
        free( pS->last );
        free( pS );
        --numStudents; /* update globals ... */
        fileFlag = 1;
        return;   
    }
   
    /* Else not first in list, so ... */
   
    p = phead; /* set p to this initial value to start loop */
   
    /* Now find the pointer to the previous record. */
    while( p != pS )
    {
        pp = p; /* pp holds previous pointer value ... */
        p = p->next; /* set to next pointer in link list chain */
    }
   
    /*
        Now we have a pointer to the previous Student record, so ...
        we can now point that previous record to one past this pS record           
    */
    pp->next = pS->next;
   
    /* Now free the memory for this record and update the globals ... */
    free( pS->first );
    free( pS->last );
    free( pS);
    --numStudents;
    fileFlag = 1;
}

void delAll()
{
    pStudent p = phead; /* Set p to this initial value to start loop */
    pStudent pNext;     /* To hold the pointer to the next record */
   
    while( p != NULL )
    {
        pNext = p->next; /* Get a pointer to the next record. */
        free( p->first );
        free( p->last );
        free( p );
        p = pNext; /* Update p ... */
    }
   
    /* Update globals ...  */
    phead = NULL;
    numStudents = 0;
    fileFlag = 0;
}

/* Note: calling delAll() here ... will re-set globals as above ... */
void init()
{
    if( phead != NULL )
    {
        if( tolower( takeInChar( "\nDo you wish to overwrite the "
"records in memory y/n ? " )) == 'y' )
            delAll(); /* re-sets globals ... */
        else
        {
            if( numStudents == 1 )
                puts( "1 Student Record was left intact in memory." );
            else
                printf( "%d Student Records were left intact in memory.\n",
                       numStudents );
        }
    }
    else puts( "\nThere were no records in memory to clear." );
}

/*  PLEASE NOTE!  THE REST OF CODE TO THIS PROGRAM IS ON THE FOLLOWING PAGE ... */
« Last Edit: November 06, 2016, 07:04:32 PM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: C SOME UTILITY functions ...
« Reply #13 on: June 05, 2013, 07:07:21 PM »
/* THE REST OF THE CODE FROM THE PROGRAM FILE "StudentGradesManagementList.c" ON THE ABOVE PAGE CONTINUES HERE ... */


Code: [Select]
void scramble( char s[] )
{
    int i = 0;
    int code[] = {3,1,4,1,5,9,8,6,7,0,7,0,2,8,6,9,5,3,4,2};
    while( s[i]!=0 ) { s[i] = (char) ((int)s[i] - code[i]); ++i; }
}

void unscramble( char s[] )
{   
    int i = 0;
    int code[] = {3,1,4,1,5,9,8,6,7,0,7,0,2,8,6,9,5,3,4,2};
    while( s[i]!=0 ) { s[i] = (char) ((int)s[i] + code[i]); ++i; }
}

void writeAllToFile()
{
    if( !fileFlag ) return;
   
    if( numStudents == writeFile() )
    {
        if( numStudents > 0 )
        {
            if( numStudents == 1 )
                puts("\nThe 1 Student record was safely filed.");
            else
                printf
                (
                    "\nAll %d Student records safely filed.\n",
                    numStudents
                );
        }   
    }
    else
    {
        printf
        (
            "\nAn error occured while filing the Student records."
            "\nPlease see the programmer for help with the problem.\n"
            "\nExiting the program now.  Press 'Enter' to continue ... "
        );
        flushStdin(); /* Holds window open to show above message. */
        exit(0); /* Return error number to system. */
    }   
}

int writeFile()
{   
    int count; /* to track the records actually written to the file */
    FILE* fp;
    pStudent p = phead;

    if( phead==NULL )
    {
        puts("\nNo records available ... so NO records written to file.") ;
        return 0;
    }
   
    fp = fopen( FNAME, "w" );
    if( fp==NULL )
    {
        printf("\nError opening file %s.  Press 'Enter' to continue ... ", FNAME);
        flushStdin();
        return 0;
    }
   
    count = 0; /* to track the records actually written to the file */
    while( p!=NULL )
    {
        fprintf
        (
            fp,
            "%d\n"
            "%s\n"
            "%s\n"
            "%.2f\n"
            "%.2f\n"       
            "%.2f\n"
            "%.2f\n"
            "%.2f\n",
            p->id, p->last, p->first,
            p->test1, p->test2, p->assignment,
            p->labtest, p->finalexam
        );
       
        ++count;
        p = p->next;
    }
   
    fclose( fp );
    fileFlag = 0;
    return count; /* Number of records written. */
}

int readFile()
{
    int count, ID;
    /* char buffer[MAX_STR_LEN+1]; */
    FILE *fp;

    pStudent pS;
#if !sortRead
    pStudent pp=NULL;
#endif

    fp = fopen( FNAME, "r" );
    if( fp==NULL )
    {
        printf
        (
            "\nError opening file %s.\n"
            "Perhaps it hasn't been created yet?\n"
            "Press 'Enter' to continue ... ",
            FNAME
        );
        flushStdin();
        return 0;
    }
   
    /* BUT!!! may need to delete any records in memory first. */
    init();
   
    /*
        NOTE: we need phead to be equal to NULL in the following ...
        to be permitted to set phead ... 
        to point to the first Student record in memory (read in from the file).
    */
    if( phead != NULL ) /* then exit with message ... */
    {
        if(numStudents==1)
            puts("\nThe 1 former Student record was left in memory.");
        else
            printf("\nThe %d former Student records were left in memory.\n", numStudents);
        return 0; /* So ...old count of Student records will NOT be updated. */
    }
   
    /* If the program reaches here ... then ... */
   
    count = 0;

    while(  fscanf( fp, "%d", &ID) != EOF  )
    {
        pS = (pStudent) malloc(sizeof(Student));
        pS->id = ID;
        #if 0
        //fscanf( fp, "%s", buffer );
        //pS->last = newCopy( buffer );
        #endif
        fgetc(fp); /* eats up the '\n' char left over from above 'ID read' */
        pS->last = readLine(fp);
       
        #if 0
        //fscanf( fp, "%s", buffer );
        //pS->first = newCopy( buffer );
        #endif
        pS->first = readLine(fp);

        fscanf( fp, "%f", &pS->test1 );     
        fscanf( fp, "%f", &pS->test2 );
        fscanf( fp, "%f", &pS->assignment );       
        fscanf( fp, "%f", &pS->labtest );
        fscanf( fp, "%f", &pS->finalexam );
#if !sortRead           
        if ( pp != NULL )   /* for 2nd and up records ...*/
            pp->next = pS;  /* now previous record points to this new one */
        else phead =pS;     /* first record only has base pointer */
           
        pS->next = 0; /* NULL terminate list ... */
        pp = pS; /* Keep a copy of address of this pS in pp for next while loop. */
#else
        insert( pS );
#endif     
        ++count;
        /* printf( "\nRecord number is %d\n", count ); */
    }
    fclose( fp );
    if(count==1)
        puts("\n1 record was read into memory from the disk file.");
    else
        printf("\n%d records were read into memory from the disk file.\n", count);
       
    fileFlag = 0;
    return count; /* Total number of Student records found in the file. */
}

int passWord()
{
    /*
        Get the password in the file, if it exists, into buffer2
        and compare it with the user entry in buffer1.
    */
    char* buffer1;
    char buffer2[MAX_STR_LEN+1];
    int attempts;

    int pwOK = 0;
    FILE* fp;
    fp = fopen(FNAME_PW, "r");

    if(fp==NULL) /* i.e. if file FNAME_PW doesn't exit ... */
    {
        pwOK = newPW(); /* get new password ...*/
        if( pwOK == 1 ) return 1; /* report this match of passwords back ...*/
    }
    else /* File FNAME_PW does exist ... so ... */
    {
        fscanf( fp, "%s", buffer2 );
        fclose( fp );
        unscramble( buffer2 );
       
        /* Now ... get password entered by user into a string in buffer1. */
        for( attempts=0; attempts<3; ++attempts )
        {
            printf("Enter password: ");
            /* //scanf( "%s", buffer1 ); flushStdin(); */
            buffer1 = readLine(stdin);
            if(strcmp(buffer1, buffer2)==0) /* If true ... passwords matched. */
            {
                puts( "Match!\n" );
                free( buffer1 );
                return 1; /* Report this match of passwords back ...*/
            }
            free( buffer1 );
        }
    }
    /* if reach here ...*/
   
    printf( "NO MATCH! ... Press 'Enter' to exit ... " );
    flushStdin();
    exit(1); /* Quit the program right now ... */
}

int newPW()
{
    FILE* fp;
    char* buffer1;
    char* buffer2;
   
    for( ; ; )
    {
/* Get the new password into a string in buffer1. */
buffer1 =  takeInStrMaxLen( "Enter the new password (8 to " MAX_STR_LEN_STR
" characters): ", MAX_STR_LEN );
if( strlen(buffer1) >= MIN_PW_LEN )
break;
       
        printf("Your password must be at least %d characters ...\n", MIN_PW_LEN );
        free( buffer1 ); /* ... and try again ...*/
    }
   
    /*
        Get a 'verify copy' of the new password into buffer2
        and compare it with the password in buffer1.
    */
    printf("Enter the new password again: ");
    buffer2 = readLine(stdin);
    if(strcmp(buffer1, buffer2)==0) /* If true ... passwords matched. */
    {
        fp = fopen(FNAME_PW, "w");
        if(fp==NULL)
        {
            printf("Error opening file %s ... Press 'Enter' to exit ... ", FNAME_PW);
            flushStdin();
            free(buffer2);
            free(buffer1);
            exit(2);
        }
        else
        {
            puts( "Match!\n" );
            scramble(buffer1);
            fprintf( fp, "%s", buffer1 );       
            fclose( fp );
            free(buffer2);
            free(buffer1);
            return 1; /* Report this match of passwords back ...*/
        }
    }
   
    /* If reach here ...*/
       
    printf( "NO MATCH! ... Press 'Enter' to exit ... " );
    flushStdin();
    free(buffer2);
    free(buffer1);
    exit(3); /* Quit the program right now ... */
}

/* A function to compare two Student records to permit sorting ... */
int StudentCmp( pStudent pS1, pStudent pS2 )
{
    int compare = strcmp(pS1->last, pS2->last);
    if ( compare == 0 )
        return strcmp(pS1->first, pS2->first);
   
    return compare;
}
« Last Edit: June 05, 2013, 07:09:36 PM by David »

Offline David

  • Hero Member
  • *****
  • Posts: 647
    • View Profile
Re: C SOME UTILITY functions ...
« Reply #14 on: June 05, 2013, 07:20:15 PM »
Here ... the Student List code is split off into its own separate file ...

"Student_List.h "

which file, needs to be included in the program

"StudentGradesManagementList2.c"

that follows on the next page ...

Code: [Select]
/* Student_List.h */  /* 2016-11-02 */


#ifndef STUDENT_LIST_H
#define STUDENT_LIST_H


/* only myAssert (and includes) from readLine.h used here,
   but other stuff used in 'main' */
#include "takeInLine.h"


typedef struct myStudent
{
    int id;
    char* last;
    char* first;
    float test1;
    float test2;
    float assignment;
    float labtest;
    float finalexam;
    struct myStudent* next;

} Student ;

typedef Student* pStudent;

void clearStudent( pStudent cur )
{
    free( cur->first );
    free( cur->last );
}

void showStudent( const pStudent pS )
{
    printf
    (
        "ID number  : %d\n"
        "Last Name  : %s\n"
        "First Name : %s\n"
        "Test 1     : %.2f\n"
        "Test 2     : %.2f\n"
        "Assignment : %.2f\n"
        "Lab Test   : %.2f\n"
        "Final Exam : %.2f\n",
        pS->id, pS->last, pS->first,
        pS->test1, pS->test2, pS->assignment,
        pS->labtest, pS->finalexam
    );
}


/* A function to compare two Student records to permit sorting ... */
int StudentCmp( const pStudent pS1, const pStudent pS2 )
{
    int compare = strcmp( pS1->last, pS2->last );
    if ( compare == 0 )
        return strcmp( pS1->first, pS2->first) ;
    return compare;
}




typedef struct
{
    pStudent head;
    pStudent tail;
    int size; /* to hold 'the number of Student records in memory' ...*/
    int pwOK; /* to hold 'the password was OK' flag; 0=false & 1=true */
    int fileFlag; /* fileFlag indicates 'the need to update the file' ... */
} List;

void initList( List* myLst )
{
    myLst->head = NULL;
    myLst->tail = NULL;
    myLst->size = 0;
    myLst->pwOK = 0;
    myLst->fileFlag = 0;
}

void clearList( List* lst )
{
    pStudent cur = lst->head;
    for( ; cur != NULL; cur = lst->head  )
    {
        lst->head = cur->next;
        clearStudent( cur );
        free( cur );
    }
    initList( lst );
}

void push_backList( List* lst, Student* stud )
{
    Student* p = (Student*) malloc( sizeof(Student) );
    if( p == NULL )
    {
        clearList( lst );
        myAssert( 0, "Error: malloc failed in push_back..." );
    }

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

    p->next = NULL;
    ++ lst->size;
    if( lst->size > 1 )
    {
        lst->tail->next = p;
        lst->tail = p;
    }
    else
        lst->head = lst->tail = p;
}

/* insertList in list with last & first names in proper order */
void insertList( List* lst, pStudent pS )
{
    pStudent q, phead = lst->head;

    /* 1st, handle the more probable case where 'this' is NOT the first element */
    if( phead && StudentCmp( pS, phead ) >= 0 )
    {
        /* If here ... search the linked list for the right location */

        q = phead; /* Get a working copy of phead in q */

        /* Start comparing with element AFTER 'q' ... i.e. the 'next in' ... */
        while( q->next != NULL && StudentCmp( q->next, pS) <= 0 )
        {
            q = q->next; /* Traverse the list ... */
        }
        /*
        Ok, insertList after 'q' by relinking the pointers (similar to above)
        ( Includes inserting at end position ... where q->next == NULL )
        */
        pS->next = q->next; /* Inserted 'pS' is linked to 'upstream element' */
        q->next = pS;  /* Now 'q' is updated to link to the new 'pS' element */

        if( pS->next == NULL ) lst->tail = pS;
    }
    else /* Yeah ... the first element ... */
    {
        pS->next = phead; /* old phead becomes 2nd in list ... */
        lst->head = pS; /* and ... this pS ... becomes the head of the list */
        if( !lst->size ) lst->tail = pS;
    }

    /* Update List variables... */
    ++lst->size;
    lst->fileFlag = 1;
}

/* Return a pointer to the Student if ID found in list; else return NULL */
pStudent pFindID( const List* lst, int id )
{
    pStudent p = lst->head;

    while( p != NULL )
    {
        if( p->id == id )
            return p; /* id number entered was already used */

        /* Else ... get next p to compare */
        p = p->next;
    }

    /* If reach here ... then id number not in list so ... */
    return NULL;
}

void delList( List* lst, pStudent pS )
{
    pStudent p,
             pp; /* to hold the pointer to the previous record */

    /* Handle special case of 'first in list' */
    if( pS == lst->head )
    {
        lst->head = pS->next;
        clearStudent( pS );
        free( pS );
        -- lst->size;
        if( lst->size == 0 ) lst->tail = NULL;
        lst->fileFlag = 1;
        return;
    }

    /* Else not first in list, so ... */

    p = lst->head; /* set p to this initial value to start loop */

    /* Now find the pointer to the previous record. */
    while( p != pS )
    {
        pp = p; /* pp holds previous pointer value ... */
        p = p->next; /* set to next pointer in link list chain */
    }

    /*
        Now we have a pointer to the previous Student record, so ...
        we can now point that previous record to one past this pS record
    */
    pp->next = pS->next;
    if( pp->next == NULL ) lst->tail = pp;

    /* Now free the memory for this record and update the list variables */
    clearStudent( pS );
    free( pS);
    -- lst->size;
    lst->fileFlag = 1;
}

#endif

CLICK ON 2 in lower left corner here to go to the next pages ...
« Last Edit: November 06, 2016, 07:07:11 PM by David »