Link to home
Start Free TrialLog in
Avatar of webusername
webusername

asked on

getting input from stdin in C

I am running a program in C that takes input from the stdin . I did this
char input[2];
scanf("%s",input);
The user is able to enter more than 2 characters into input even though the size of the array is 2 .
What is wrong with scanf? I want to be able to restrict the number of characters only to 2 .
Thank You .
ASKER CERTIFIED SOLUTION
Avatar of ddunlea
ddunlea

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Avatar of Kent Olsen
Kent Olsen
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Hi Kent,

>There's lots of choices, but the terminal i/o routines (scanf(), gets(), etc) are poor ones
This should work
scanf("%2s",input);

cheers
sunnycoder
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Thanks for the info sunnycoder,

Here is somre additional ifno

Gets - agree I was actually referring to the fgets solution used earlier on - left the f off - there you have control over how much you read in.

In terms of fflush - this is what MSDN has to say about fflush

The fflush function flushes a stream. If the file associated with stream is open for output, fflush writes to that file the contents of the buffer associated with the stream. If the stream is open for input, fflush clears the contents of the buffer. fflush negates the effect of any prior call to ungetc against stream. Also, fflush(NULL) flushes all streams opened for output. The stream remains open after the call. fflush has no effect on an unbuffered stream.

So, the solution does have validity within MS environments.

However, I do agree with the principle that it should not be used if it is not a standard across all environments - the information in your posts was news to me - you learn something new everyday.
Hi Sunny,

>>There's lots of choices, but the terminal i/o routines (scanf(), gets(), etc) are poor ones
>This should work
>scanf("%2s",input);

In this limit scope, that's quite true.  But it tends to hide problems when program changes are made.  I'm a supporter of defining the length of the object (#define OBJECT_LENGTH 10) and using the length as a parameter to the function.  When things change later, you're less likely to get bit.

(Heading you off at the pass....)  You can certainly use these constants with scanf(), but it produces some ugly code.

scanf ("%*s", OBJECT_LENGTH, input);

Try THAT with 10 items to decode.  :)


Kent
Avatar of Member_3480671
Member_3480671

Hi, webusername

It may be easyier to create a while loop: every cycle you call kbhit, this will return 1 if a key has been pressed and 0 otherwise. if a key has been pressed, you can use getch to read this char. if the char is enter or it's the second char typed, you abort the loop by calling break.
Avatar of webusername

ASKER

kdo
i tried
char input[BUFFER_SIZE+2];  /*  The number of characters plus 1 for new-line plus 1 for end-of-line  */

  fgets (input, BUFFER_SIZE+2, stdin);  /*  Read up to two characters, new-line, and end-of-line  */


now, the program skips the first line and goes to the second question. i am pulling my hair...
webusername,

My earlier post (if you are using MSVC) would work but as sunnycoder pointed out this is not portable.

Here is another option for you to try

#include <stdio.h>

int main(int argc, char* argv[])
{
      char s[20];
      int d;

      scanf("%2s",s ) ;
      fseek ( stdin, 0, SEEK_END ) ;
      printf ( "%s\n", s ) ;
      scanf ( "%d", &d ) ;
      printf ( "%d\n", d);
      return 0;
}

input: ab10
output: ab
input: 123
output: 123

A word on kdo's post. This is a good point but if you need to do type conversion then it makes it a bit easier i.e.

scanf ("%d", &number) as opposed to
fgets ( s, BUFFSIZE+1, stdin ) ;
number = atoi(s) ; etc

However, here is some code that does the above but with fgets

#include <stdio.h>

#define BUFFER_SIZE 2
int main(int argc, char* argv[])
{
      char s[BUFFER_SIZE+1];
      int d;

      fgets ( s,BUFFER_SIZE + 1, stdin ) ;
      fseek ( stdin, 0, SEEK_END ) ;
      printf ( "%s\n", s ) ;
      // the next line is to show that the extra chars input on the line are being dumped.
      scanf ( "%d", &d ) ;
      printf ( "%d\n", d);
      return 0;
}
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
This still suffers from the problem that if more chars are entered the next scanf or fgets or gets will read the remaining characters from the previous entry.

i.e.

scanf ( "%2[^\n]", str ) ;

If you enter
ab10

str will contain "ab".

However the next scanf will read the 10 and return without prompting the user for any input.

so

scanf ( "%2[^\n]", str ) ;
printf ( "%s\n", str ) ;
scanf ("%d", &d) ;
printf( "%d\n", d ) ;

with an input of "ab10"

will output

ab
10

but only one prompt.
Ok so the problem of the to many read still persists. One can try to get away with
scanf("%2[^\n]%*s", str );
....


Regards
Friedrich

>kdo
>i tried
>char input[BUFFER_SIZE+2];  /*  The number of characters plus 1 for new-line plus 1 for end-of-line  */

>  fgets (input, BUFFER_SIZE+2, stdin);  /*  Read up to two characters, new-line, and end-of-line  */

>now, the program skips the first line and goes to the second question. i am pulling my hair...


There are a number of caveats with this approach.  For instance, if one character is entered before the new-line, you get just the character and the new-line.  If three characters are entered before the new-line, you get those three characters, but NOT the new-line, etc...

Kent
You may use this constuction
This code is slower but aviod buffer overflow(safe code)

#define sz 10

char input[sz];
for(int i=0;i<sz;i++)
{
      input[i]=getchar();
}

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

int main()
{
  char buf[BUFSIZ];
  char *p;
 
  printf ("Please enter a line of text, max %d characters\n", sizeof(buf));
 
  if (fgets(buf, sizeof(buf), stdin) != NULL)
  {
    printf ("Thank you, you entered >%s<\n", buf);
   
    /*
     *  Now test for, and remove that newline character
     */
    if ((p = strchr(buf, '\n')) != NULL)
      *p = '\0';
     
    printf ("And now it's >%s<\n", buf);
  }
 
  return 0;
}


/*
 Program output:

Please enter a line of text, max 512 characters
this is a test
Thank you, you entered >this is a test
<
And now it's >this is a test<
*/
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Hi webusername,

   Is your question answered?
   If yes, please close this question.
   If not, please give feedback, so that we can continue the discussion.

-ssnkumar