-7

Code I have:

int main(){
    char readChars[3];
    puts("Enter the value of the card please:");
    scanf(readChars);
    printf(readChars);
    printf("done");
}

All I see is: "done" after I enter some value to terminal and pressing Enter, why?

Edit:

Isn't the prototype for scanf:

int scanf(const char *format, ...);

So I should be able to use it with just one argument?

Koray Tugay
  • 22,894
  • 45
  • 188
  • 319

5 Answers5

6

The actual problem is that you are passing an uninitialized array as the format to scanf().

Also you are invoking scanf() the wrong way try this

if (scanf("%2s", readChars) == 1)
    printf("%s\n", readChars);

scanf() as well as printf() use a format string and that's actually the cause for the f in their name.

And yes you are able to use it with just one argument, scanf() scans input according to the format string, the format string uses special values that are matched against the input, if you don't specify at least one then scanf() will only be useful for input validation.

The following was extracted from C11 draft

7.21.6.2 The fscanf function

  1. The format shall be a multibyte character sequence, beginning and ending in its initial shift state. The format is composed of zero or more directives: one or more white-space characters, an ordinary multibyte character (neither % nor a white-space character), or a conversion specification. Each conversion specification is introduced by the character %. After the %, the following appear in sequence:

    • An optional assignment-suppressing character *.
    • An optional decimal integer greater than zero that specifies the maximum field width (in characters).
    • An optional length modifier that specifies the size of the receiving object.
    • A conversion specifier character that specifies the type of conversion to be applied.

as you can read above, you need to pass at least one conversion specifier, and in that case the corresponding argument to store the converted value, if you pass the conversion specifier but you don't give an argument for it, the behavior is undefined.

Iharob Al Asimi
  • 52,653
  • 6
  • 59
  • 97
  • What do you mean it will not be useful? Can you provide an example on how to use with one parameter only? – Koray Tugay Mar 15 '15 at 15:10
  • @KorayTugay please follow the link in my answer and read the documentation. For more information you can read the standard. – Iharob Al Asimi Mar 15 '15 at 15:10
  • @KorayTugay No, because I said you can call it with one parameter but you can't use it. And in your case the behavior is undefined because the passed array is not even initialized. – Iharob Al Asimi Mar 15 '15 at 15:11
  • @CoolGuy yes I did, how did I type that? Although the statement was true, it wasn't what I meant. – Iharob Al Asimi Mar 15 '15 at 15:23
  • I think you are misreading the (somewhat complex) format specifier grammar. The three alternatives "one or more white-space characters, an ordinary multibyte character[...], or a conversion specification' are all ORed, actually XORed (damn natural language). So a "directive" can either be a non-empty sequence of whitespace. OR an ordinary char. OR your common %d or whatever. That is, `scanf("abcd")` is fine (consisting of four directives of one plain char each) and would read away "abcd", if they occur in the input stream. – Peter - Reinstate Monica Mar 15 '15 at 16:46
  • In other words, Koray's invocation of `scanf` was not "wrong" but flawed and based on a misunderstanding of what it would do. It's fine to call scanf just with the format string, exactly as the manual states. It would have been written differently if at least two arguments were mandatory. – Peter - Reinstate Monica Mar 15 '15 at 16:49
  • @PeterSchneider I am thinking of it now and what you say makes sense, because it's not mandatory to capture values from the input, otherwise why would the `*` modifier and the `"%n"` specifier be useful. – Iharob Al Asimi Mar 15 '15 at 16:50
5

Yes, it is possible to call scanf with just one parameter, and it may even be useful on occasion. But it wouldn't do what you apparently thought it would. (It would just expect the characters in the argument in the input stream and skip them.) You didn't notice because you failed to do due diligence as a programmer. I'll list what you should do:

  • RTFM. scanf's first parameter is a format string. Plain characters which are not part of conversion sequences and are not whitespace are expected literally in the input. They are read and discarded. If they do not appear, conversion stops there, and the position in the input stream where the unexpected character occured is the start of subsequent reads. In your case probably no character was ever successfully read from the input, but you don't know for sure, because you didn't initialize the format string (see below). Another interesting detail is scanf's return value which indicates the number items successfully read. I'll discuss that below together with the importance to check return values.

  • Initialize locals. C doesn't automatically initialize local data for performance reasons (in today's light one would probably enforce user initialization like other languages do, or make auto initialization a default with an opt-out possibility for the few inner loops where it would hurt). Because you didn't initialize readchars, you don't know what's in it, so you don't know what scanf expected in the input stream. On top it probably is nominally undefined behaviour. (But on your PC it shouldn't do anything unexpected.)

  • Check return values. scanf probably returned 0 in your example. The manual states that scanf returns the number of items successfully read, here 0, i.e. no input conversion took place. This type of undetected failure can be fatal in long sequences of read operations because the following scanfs may read in one-off indexes from a sequence of tokens, or may stall as well (and not update their pointees at all), etc.

Please bear with me -- I do not always read the manual, check return values or (by error) initialize variables for little test programs. But if it doesn't work, it's part of my investigation. And before I ask anybody, let alone the world, I make damn sure that I have done my best to find out what I did wrong, beforehand.

Spikatrix
  • 20,225
  • 7
  • 37
  • 83
Peter - Reinstate Monica
  • 15,048
  • 4
  • 37
  • 62
  • Awesome Answer! Have an upvote ;) . "But on your PC it shouldn't do anything unexpected" Huh? Why? And how do you know that? – Spikatrix Mar 16 '15 at 10:47
  • @CoolGuy Thanks for the flowers ;-).-- For the reasons why accessing memory with arbitrary values is nominally undefined behaviour cf. http://stackoverflow.com/questions/11962457/why-is-using-an-uninitialized-variable-undefined-behavior-in-c. Basically trap representations and register "not initialized" flags (which do not apply to the array). Never heard of trap representations for integer types on x86. Yes, there *are* machines out there which do that. One discussion is at http://bytes.com/topic/c/answers/213015-trap-representation (no idea whether it's the best). – Peter - Reinstate Monica Mar 16 '15 at 11:32
  • To clarify: The `printf(readchars)` will only stop if there is a null byte somewhere, i.e. the program may crash if there is none before the current memory page ends or such. "Nothing unexpected" except what one would expect from using unknown data, I meant. – Peter - Reinstate Monica Mar 16 '15 at 11:34
3

You're not using scanf correctly:

scanf(formatstring, address_of_destination,...)

is the right way to do it.

EDIT:

Isn't the prototype for scanf:

int scanf(const char *format, ...);

So I should be able to use it with just one argument?

No, you should not. Please read documentation on scanf; format is a string specifying what scanf should read, and the ... are the things that scanf should read into.

Marcus Müller
  • 34,677
  • 4
  • 53
  • 94
  • Nitpick: although it is rare, one can call scanf with just a format string, in order to read away exactly matching input. Characters which are not part of a conversion specification are expected literally in the input. It is not an error if no conversion is specified at all. – Peter - Reinstate Monica Mar 15 '15 at 16:39
1

The first argument to scanf is the format string. What you need is:

scanf("%2s", readChars);
R Sahu
  • 204,454
  • 14
  • 159
  • 270
0

It Should provided Format specifiers in scanf function

char readChars[3];
puts("Enter the value of the card please:");
scanf("%s",readChars);
printf("%s",readChars);
printf("done");

http://www.cplusplus.com/reference/cstdio/scanf/ more info...