Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>Personally, I advise ditching <code>scanf</code> altogether for interactive user input, especially for numeric input. It just isn't robust enough to handle certain bad cases. </p> <p>The <code>%d</code> conversion specifier tells <code>scanf</code> to read up to the next non-numeric character (ignoring any <em>leading</em> whitespace). Assume the call</p> <pre><code>scanf("%d", &amp;val); </code></pre> <p>If your input stream looks like {'\n', '\t', ' ', '1', '2', '3', '\n'}, <code>scanf</code> will skip over the leading whitespace characters, read and convert "123", and stop at the trailing newline character. The value <code>123</code> will be assigned to <code>val</code>, and <code>scanf</code> will return a value of 1, indicating the number of successful assignments. </p> <p>If your input stream looks like {'a', 'b', 'c', '\n'}, <code>scanf</code> will stop reading at the <code>a</code>, not assign anything to <code>val</code>, and return 0 (indicating no successful assignments). </p> <p>So far, so good, right? Well, here's an ugly case: suppose your user types in "12w4". You'd probably like to reject this entire input as invalid. Unfortunately, <code>scanf</code> will happily convert and assign the "12" and leave the "w4" in the input stream, fouling up the next read. It will return a 1, indicating a successful assignment.</p> <p>Here's another ugly case: suppose your user types in an obnoxiously long number, like "1234567890123456789012345678901234567890". Again, you'd probably like to reject this input outright, but <code>scanf</code> will go ahead and convert and assign it, regardless of whether the target data type can represent that value or not. </p> <p>To properly handle those cases, you need to use a different tool. A better option is to read the input as text using <code>fgets</code> (protecting against buffer overflows), and manually convert the string using <code>strtol</code>. Advantages: you can detect and reject bad strings like "12w4", you can reject inputs that are obviously too long and out of range, and you don't leave any garbage in the input stream. Disadvantages: it's a bit more work. </p> <p>Here's an example:</p> <pre><code>#include &lt;string.h&gt; #include &lt;stdlib.h&gt; #include &lt;stdio.h&gt; ... #define DIGITS ... // maximum number of digits for your target data type; // for example, a signed 16-bit integer has up to 5 digits. #define BUFSIZ (DIGITS)+3 // Account for sign character, newline, and 0 terminator ... char input[BUFSIZ]; if (!fgets(input, sizeof input, stdin)) { // read error on input - panic exit(-1); } else { /** * Make sure the user didn't enter a string longer than the buffer * was sized to hold by looking for a newline character. If a newline * isn't present, we reject the input and read from the stream until * we see a newline or get an error. */ if (!strchr(input, '\n')) { // input too long while (fgets(input, sizeof input, stdin) &amp;&amp; !strchr(input, '\n')) ; } else { char *chk; int tmp = (int) strtol(input, &amp;chk, 10); /** * chk points to the first character not converted. If * it's whitespace or 0, then the input string was a valid * integer */ if (isspace(*chk) || *chk == 0) val = tmp; else printf("%s is not a valid integer input\n", input); } } </code></pre>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload