57

Edit: for my class I have to use scanf. So recommending other ways of input is not the solution I am looking for (if there is one that involves scanf).


If I am reading in user input for a small project (for example, a game). Lets say I ask would you like to play? This would accept a yes or no answer. So i write up some simple code like this:

#include <stdio.h>

int main(void)
{
     char string[3]; //The max number of letters for "yes".

     printf("Would you like to play?");
     scanf("%s", string);
}

So this code should simply ask them to input yes or no. I am setting the length of my char array to size 3. This way it is large enough to hold yes and also no. But if someone were to enter invalid input such as yesss, I know how to compare the string afterwards to handle such an event, but wouldn't this technically/possibly overwrite other local variables I have declared because it would extend outside the length of my array? If so, is there a way to handle this to restrict 3 input characters or something? And if not, why/how does it know to only input for the size of 3?

Neuron
  • 5,141
  • 5
  • 38
  • 59
MrHappyAsthma
  • 6,332
  • 9
  • 48
  • 78
  • Probably safer to do it character by character. I'm not sure exactly if C has anything that does this for you. – chris Sep 06 '12 at 18:55
  • Could you explain how to do that? Would I just do a bunch of "%c" things in the "scanf" and then how would I assign them to a character of the array? [i.e. would I need &string[0] or something]. Plus what if they enter "no", then I would only use 2 of the 3 "%c". – MrHappyAsthma Sep 06 '12 at 18:57
  • 1
    Doing it by yourself to handle any length entails an array that can change size at runtime and inserting characters from the input as they come while making sure not to overflow the array. Luckily, it seems `scanf` has the feature built in. – chris Sep 06 '12 at 18:59

4 Answers4

73

Your array needs to be able to hold four chars, since it must also contain the 0-terminator. With that fixed, specifying a maximal length in the format,

scanf("%3s", string);

ensures that scanf reads no more than 3 characters.

Daniel Fischer
  • 181,706
  • 17
  • 308
  • 431
  • 1
    As an aside, since the width specifier only indicates the *maximum* number of characters to read, if you need to read an *exact* number, use the above approach and then check the number of characters consumed (via [`%n`](http://stackoverflow.com/questions/13503135/get-number-of-characters-read-by-sscanf)). – sevko Jul 10 '15 at 18:18
  • 2
    I just want to know that this is super great thing , then why do people keep saying scanf is unsafe obviously they could do this to limit input and stop buffer overflow exploit. ?? – Suraj Jain Apr 11 '17 at 04:53
  • 5
    "ensures that scanf reads no more than 3 characters." --> Not quite. `"%3s"` will first read an unlimited number of leading white-space characters. Then it will read and save up to 3 non-white-space characters. Finally appending a _null character_. – chux - Reinstate Monica Sep 23 '18 at 23:28
  • 4
    @SurajJain People generally recommend against scanf not because it cannot be used safely, but because it is difficult to use. When people are first learning C, they would be better served by learning to parse input strings than by spending time learning the foibles of the scanf format language. scanf is rarely used in production code; in the vast majority of places it might be appropriate, C is the wrong language anyway. – William Pursell May 05 '19 at 13:59
21

the safest way is to use

fgets(string, 4, stdin);

here you can store maximum 3 characters including one space reserved for NULL ('\0') character.

Neuron
  • 5,141
  • 5
  • 38
  • 59
Timothy Malche
  • 211
  • 1
  • 2
10

You should use the width modifier of scanf() and set it to be one less than the size of your string, so that you ensure that space exists for the NULL terminator.

So, if you want to store "yes", you will firstly need a bigger array than the one you have; one with size 4, 3 characters plus 1 for the null terminator. Moreover, you should instruct scanf() to read no more than size - 1 characters, where size is the length of your array, thus 3 in this case, like this:

#include <stdio.h>

int main(void)
{
     char string[4];
     scanf("%3s", string);
}
gsamaras
  • 71,951
  • 46
  • 188
  • 305
5

http://www.cplusplus.com/reference/clibrary/cstdio/scanf/

use the "width" modifier;

%[*][width][modifiers]type
ronalchn
  • 12,225
  • 10
  • 51
  • 61
anonymous
  • 51
  • 1