User Input: Strings and Numbers [C]

Updated Dave Sinkula 10 Tallied Votes 8K Views Share

Very early on when attempting to learn programming in C, you often do exercises that read in and print out strings and numbers. Now you might assume that C has a simple function that will get user input, and indeed it does, but there are a couple of gotchas that can easily trip up those new to programming in C.

There are two things to vigorously avoid, and unfortunately they are all too commonly seen:

char text[20];
gets(text); /* NEVER USE gets() */
scanf("%s", text); /* MANY HIDDEN GOTCHAS */

So how do you do it right? The short answer is to use fgets to read a line of text. However, please note that when you enter text, you press the [Enter] or [Return] key and this character does not just vanish, it remains in the input buffer.

For example:

#include <stdio.h>
 
int main()
{
   char text[20];
   fputs("enter some text: ", stdout);
   fflush(stdout); /* http://c-faq.com/stdio/fflush.html */
   fgets(text, sizeof text, stdin);
   printf("text = \"%s\"\n", text);
   return 0;
}

enter some text: hello world
text = "hello world
"

So when reading strings, you often want to remove this newline. Be careful though, because it is not always there! When the incoming text is one less than the size of the buffer, the newline is retained. You can search for the newline and overwrite it with a null terminator.

--- skimmers start here ---

#include <stdio.h>
#include <string.h>
 
int main()
{
   char text[20];
   fputs("enter some text: ", stdout);
   fflush(stdout);
   if ( fgets(text, sizeof text, stdin) != NULL )
   {
      char *newline = strchr(text, '\n'); /* search for newline character */
      if ( newline != NULL )
      {
         *newline = '\0'; /* overwrite trailing newline */
      }
      printf("text = \"%s\"\n", text);
   }
   return 0;
}

enter some text: hello world
text = "hello world"

There are many other ways to do this, but this is very frequently recommended and always correct.

--- skimmers stop here ---

If you are reading a number, then first read in the input string and consequently follow it with a call to sscanf or strtol to convert it to a number.

#include <stdio.h>
 
int main()
{
   char text[20];
   fputs("enter some number: ", stdout);
   fflush(stdout);
   if ( fgets(text, sizeof text, stdin) )
   {
      int number;
      if ( sscanf(text, "%d", &number) == 1 )
      {
         printf("number = %d\n", number);
      }
   }
   return 0;
}

enter some number: 42
number = 42

The newline does not need to be removed, unless you choose to, because it is whitespace and is not part of a valid number. You may find the following related code snippets regarding the input of numbers and text useful:

To recap, here is why not to do what I said not to do! First, never use gets . It is included as a standard library function only as a holdover from pre-C89 code (the standards committee opted in the interest of not breaking existing code). But it is inherently and notoriously unsafe because there is no way to tell it the size of the buffer into which data will be read. So it is always a risk for buffer overflow , which may be used as an exploit . If you ever want to be employed as a programmer, it's best not to ever let a potential employer see you use this function!

As for scanf it is a truly complicated beast, and should certainly not be the first choice for someone just starting out programming in C. One of the first issues with scanf("%s", str); is it suffers from a very similar problem as gets , which is the incoming buffer size is not specified. If you didn't look up the description of %s you may not have known that this directive is whitespace-delimited. Which means that it if the user enters hello world , then str will be hello . There are more gotchas, such as if you are also using scanf to read integers, perhaps using scanf("%d", &i); , then the same whitespace issue may bite you. Remember that when you enter text you press the [Enter] or [Return] key and it remains in the input buffer. This can cause issues when mixed with other input functions such as getchar . There is also another insidious issue that comes up when using scanf : the "need" to flush the input buffer.

And don't think I presented a comprehensive list of gotchas associated with scanf , these were merely some common ones!

kvprajapati commented: Excellent +6
ravi4mahajan 0 Newbie Poster

if i want to print * character insted of printing letters while scaning it from keybord just like ATM bank password application what will be code for it in C
whenever i type letter from keyboard i want to see it only *****

Dave Sinkula 2,398 long time no c Team Colleague

This question unfortunately is both frequently asked and has nothing to do with standard C.

Hopefully this may help you, though.

Dave Sinkula 2,398 long time no c Team Colleague

This tutorial's original ending:

Or again, it is widely known by good programmers and potential employers that these are things to avoid. But if you still aren't convinced, listed below are many FAQs that say pretty much the same thing (mostly because I'm saying pretty much what they are saying).

And there is another insidious issue that comes up when using scanf: the "need" to flush the input buffer. All too often we see fflush(stdin); used to "fix" this. But actually this one problem with scanf breeds another:

And don't think I presented a comprehensive list of gotchas associated with scanf , these were merely some common ones.

vegaseat 1,735 DaniWeb's Hypocrite Team Colleague

What is missing here is an example of a text entry followed by a numeric entry. I tried to combine the code presented and should the text exceed its length of 19 and have numbers at the end, ouch!

Dave Sinkula 2,398 long time no c Team Colleague

Why not post this failing example so I know what you mean?

Brought up recently by tux4life and explained by Narue, the fgets/sscanf code is not bulletproof. I must admit, though, I don't quite follow this bit:

Imagine how confusing that would be to a beginner since scanf() and sscanf() are so similar.

I usually use a generously-size input buffer given by BUFSIZ (but that makes posting some input that fails more difficult). The larger input buffer tends to weed out more input issues, but again -- not bulletproof. There was a link to a snippet in which excess characters are discarded, and this could further bump up the input handling. But no doubt that brings a design decision that one could argue against.

I suppose I should also mention, since I hadn't back in the day when I could edit the snippet, that this post got quite long. I posted other snippets that went a little bit further with this -- this being an initial start and not a be-all end-all. In fact, even the other linked snippets are not bulletproof and I believe at least a few mention this explicitly.

But again, can you clarify your comment for me?

vegaseat 1,735 DaniWeb's Hypocrite Team Colleague

Ah, thanks the explanation by Narue explains it all in detail. Thanks again!

mohammadmonir 0 Newbie Poster

what typpes of questiions in the exam if it is the subject of B.Sc(hon's) computer scienece

xavier666 commented: Too shocked for words... +0
Ancient Dragon 5,243 Achieved Level 70 Team Colleague Featured Poster

However, please note that when you enter text, you press the [Enter] or [Return] key and this character does not just vanish, it remains in the input buffer.

That is only true when using scanf(). Both gets() nor fgets() extract the '\n' from the keyboard buffer.

Dave Sinkula commented: A bump to defend gets()? -2
WaltP commented: Not a defense of gets() -- simply an observation on 2 functions we wish didn't exist. +11
Aia commented: I do not care for the observation. If we truly wish that it did not exist, do not bring it up in such a confusing statement. -2
Ancient Dragon 5,243 Achieved Level 70 Team Colleague Featured Poster

>>A bump to defend gets()? - Dave Sinkula
Dave: Just what in the hell makes you think I was defending gets()??? I just don't understand all the negative reps I got for my post.

Dave Sinkula 2,398 long time no c Team Colleague

Let's take a look:

However, please note that when you enter text, you press the [Enter] or [Return] key and this character does not just vanish, it remains in the input buffer.

That is only true when using scanf(). Both gets() nor fgets() extract the '\n' from the keyboard buffer.

The function gets() will extract the newline. You seem confused as to what both/nor mean.

It's not only true for scanf(). Many directives for scanf will leave a newline in the input stream.

It is well known that fgets() leaves the newline in the stream.

What, exactly, was your point? That you are not quite sure what you're talking about? Or that your post is confusing (a reason for bad rep, BTW)? Or that you can't be troubled to think about these things and I'm supposed to put up with erroneous comments because you haven't figured this one out yet?

You're not "defending gets()", but what is it that you are doing? Perhaps that we should prefer gets() and/or scanf() to read strings? What?

Aia commented: For dealing with misleading and confusing post. +8
Ancient Dragon 5,243 Achieved Level 70 Team Colleague Featured Poster

@Dave: I didn't realize I had written a malformed sentence. Thanks for pointing that out. The word "nor" should have been "and". Ok I will accept the bad rep for that confusing sentence.

Both gets() and fgets() extract the '\n' from the keyboard buffer.

>>It is well known that fgets() leaves the newline in the stream.
It MAY leave it in, only if there is not enough room in the input buffer for it. But I KNOW you know that too :) But assuming the input buffer is large enough fgets() will remove the newline from the stream, which scanf("%s") and scanf("%d") will not. I suppose that was the point of my previous post.

Ene Uran 638 Posting Virtuoso

What happens to a string that should contain a newline character?

Lowchernhwee 0 Newbie Poster

the 3rd example...
after trying it -i get the point that it somehow protects the code....
still dun understand the real meaning behind the codes...
fputs fflush fgets
difference between sscanf and scanf....
please enlighten me thx

WaltP 2,905 Posting Sage w/ dash of thyme Team Colleague

I'm sure the meaning can be found
1) in your book if you have one
2) in the tutorial you are using, if you are using one
3) from GOOGLE, which knows everything and can explain stuff better than we can.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.