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