mborja (9) Nov 21, 2009 at 9:42am UTC
Safer alternative to scanf() for reading user input as strings:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
#include <iostream>
using namespace std;
#define MAXINPUTLEN 64
int main()
{
char input[MAXINPUTLEN] = "" ;
char cur_input;
printf("Input: " );
for (int i=0; i <= MAXINPUTLEN; i++) {
cur_input = getchar();
if (cur_input != '\n' )
input[i] = cur_input;
else
break ;
}
printf("%s\n" , input);
return 0;
}
Last edited on Nov 21, 2009 at 9:42am UTC
jsmith (3099) Nov 21, 2009 at 9:42am UTC
But also useless, since the user can't use BACKSPACE to fix typos.
string s;
getline( cin, s );
done.
mborja (9) Nov 21, 2009 at 9:42am UTC
But also useless, since the user can't use BACKSPACE to fix typos.
string s;
getline( cin, s );
done.
/me needs no BACKSPACE :-)
Perhaps it's Cygwin or my compiler platform, but I don't find any problems backspacing to correct typos on the command line where input is accept. I can type:
asdf
...backspace once and type:
asd1
...and it's read without any problems into my input array of characters. Perhaps a better explanation is in order about why the user can't use a backspace?
Last edited on Nov 21, 2009 at 9:42am UTC
jsmith (3099) Nov 21, 2009 at 9:42am UTC
Because your input buffer looks like
a s d f \8 1
when that gets printed, it looks like asd1 because the terminal honors the backspace.
print out strlen( input ) or do strcmp( input, "asd1" ) when you type asdf <bs> 1 and
you'll see the length is 6 and the strings are not equal.
mborja (9) Nov 21, 2009 at 9:42am UTC
printf("%s (size: %d)\n" , input, strlen(input));
When run:
1 2 3
$ ./inputecho
Input: asdf<BACKSPACE><BACKSPACE>
as (size: 2)
By the way, have you actually compiled this program for yourself? At any rate, still not seeing the problem.
Last edited on Nov 21, 2009 at 9:42am UTC
jsmith (3099) Nov 21, 2009 at 9:42am UTC
Ah, it's because getchar() doesn't actually return until the user presses ENTER so the input is being pre-processed before it gets to the program.
jsmith (3099) Nov 21, 2009 at 9:42am UTC
Actually, though, now that I think about it,
1 2
char * buf = 0;
scanf( "%as" , &buf );
does the same thing as your code, except it does not have the arbitrary input buffer size limitation. Though %as is not standard, IIRC.
Anyways being a C++ forum, I'd use streams instead.
Here's a little function I cobbled up that is not only buffer overflow-proof, but also handles entry of any type so long as it is streamable:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
#include <iostream>
#include <boost/lexical_cast.hpp>
#include <boost/lambda/lambda.hpp> // For test purposes only
#include <string>
using namespace std;
using namespace boost::lambda;
struct accept_all
{
template < typename T >
bool operator ()( const T& ) const
{ return true ; }
};
template < typename T, typename Fn >
T GetInput( const string& prompt, Fn validator )
{
do {
cout << prompt << ": " << ends;
string s;
getline( cin, s );
try {
T result = boost::lexical_cast<T>( s );
if ( validator( result ) )
return result;
} catch ( const boost::bad_lexical_cast& ) {
// Just ask again.
}
cout << "Invalid input. Try again." << endl;
} while ( 1 );
// Appease compiler
return T(); // should never get here
}
template < typename T >
T GetInput( const string& prompt )
{
return GetInput<T, accept_all>( prompt, accept_all() );
}
template < typename T >
struct accept_range
{
accept_range( T lower, T upper = std::numeric_limits<T>::max() ) :
lower( lower ), upper( upper ) {}
bool operator ()( T value ) const
{ return lower <= value && value <= upper; }
private :
T lower;
T upper;
};
template < typename T >
accept_range<T> range( T min, T max = std::numeric_limits<T>::max() )
{
return accept_range<T>( min, max );
}
int main() {
int x = GetInput<int >( "Enter a positive integer" , range( 1 ) );
int y = GetInput<int >( "Enter an integer (1-10)" , range( 1, 10 ) );
int z = GetInput<int >( "Enter an integer (1-100)" , _1 >= 1 && _1 <= 100 );
double f = GetInput<double >( "Enter a double (-1.0...1.0)" , range( -1.0, 1.0 ) );
string s = GetInput<string>( "Enter a string" );
cout << "You entered:" << endl
<< " integer = " << x << endl
<< " int(1-10) = " << y << endl
<< " int(1-100) = " << z << endl
<< " double(-1.0...1.0) = " << f << endl
<< " string = " << s << endl;
}
This topic is archived - New replies not allowed.