delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/1998/07/13/17:02:01

From: horst DOT kraemer AT snafu DOT de (Horst Kraemer)
Newsgroups: comp.os.msdos.djgpp
Subject: Re: Buffered input
Date: Mon, 13 Jul 1998 20:57:36 GMT
Organization: Unlimited Surprise Systems, Berlin
Lines: 96
Message-ID: <35aa57ab.28188165@news.snafu.de>
References: <6_Ap1.22$s7 DOT 1149262 AT alpha DOT sky DOT net>
NNTP-Posting-Host: n33-177.berlin.snafu.de
To: djgpp AT delorie DOT com
DJ-Gateway: from newsgroup comp.os.msdos.djgpp

On Sat, 11 Jul 1998 03:29:06 GMT, "David P. Hack" <hack AT sky DOT net>
wrote:

>I am a green C programmer and have a question about djgpp's handling of
>input and the scanf() function.
>
>The following program goes into a loop if a correct input is not received.
>What I expected it to do was to reprompt if a correct input is not received.
>When I compile this source and run it under Turbo C, it reprompts but under
>djgpp it loops.  I assume this has something to do with djgpp's use of
>buffered input and I have read some of the bug descriptions that seem to be
>related to this but I am confused.  Can anyone help me understand why this
>loops and why it runs differently from Turbo C?
>
>Thanks
>Dave Hack
>
>/* shel06.c */
>/* Validate a single character input with scanf */
>#include <stdio.h>
>#include <conio.h>
>main()
>{
>  char c;               /* input character */
>  int intScanres;       /* scanf function return value */
>  clrscr();
>  do
>  {
>    fflush(stdin);

fflush(stdin) is undefined and meaningless in Standard C and in DJGPP.
If it seems to work somehow in Borland C, this is a non-portable
compiler extension.

>    printf("Please input (Y)es or (N)o: ");
>    intScanres = scanf("%[YyNn]", &c);

This is _very_ unsafe. The format specifier %[ will not read
specifically _one_ character but the _longest_ sequence consisting of
any yYnY and assign it to c. If the user enters
nnnn (because his keyboard is repeating unintentionally) scanf will
assign 4 consecutive n's to the address &c and trash you memory. You
have to provide a field width 1 : %1[nNyY] for safety.

>    printf("intScanres is %d\n",intScanres);
>  } while(intScanres != 1);
>  printf("The character entered is: %c",c);
>  return 0;     /* end of main() function */
>}


If you absolutely want to use scanf for character input, the sequence
should perhaps look like this:

#include <stdio.h>

int main()
{
  char c;
  int scanRes;
  do {
    puts("Enter one of [nNyY]");

    scanRes=scanf(" %1[yYnN]",&c);
    /* returns the first non-whitespace chararacter
       and stores it to c. The blank in front of
       % is _important_ */

    scanf("%*[^\n]");
    /* reads away every input after yYnN,
       or every input if the first char
       after whithespace is not in [nNyY]
       _whithout_ assigning it,
       leaving a pending \n which is skipped
       by the leading blank in " %1[yYnY]"
    */
  }
  while (scanRes!=1);
  /* Now the buffer will contain a pending \n.
    This is normal when using scanf as all format
    specifier except %c and %[ will automatically
    skip leading whitespace.
    A blank in a scanf format string instructs
    scanf to skip every whitespace character
    such as blank,tab, newline (return).
  */

  return 0;
}

This sequence is quite safe for test programs - if you don't enter
Ctrl-Z or F6 which will signal an end of file.

Regards
Horst

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019