0

I want my user to put 3 different ages into brackets and separate them with comma. So it would look like this {int,int,int}.

I tried:

int a,b,c;
if(scanf("{ %d , %d , %d }", &a,&b,&c)!=3){
printf("Bad format");
}

but it doesn't correctly reject an input like { 1, 2, 3,

I want to allow:

{1,2,3}
{ 1 , 2 ,3 }
{ 1 ,    2 ,       3}

and reject:

{1,2,3,4}
{1 2 3 4}
1234
1 2 3 4

etc.

Thanks.

rici
  • 234,347
  • 28
  • 237
  • 341

2 Answers2

1

(Some of this answer is opinionated. Sorry. I have opinions.)

scanf is really not the ideal tool for precise verification of input. In particular, the fact that it does not normally distinguish between newlines and other whitespace makes it really very difficult to validate strictly line-oriented input.

On the other hand, if you've got all that punctuation in there, maybe you should be prepared to accept more free-form input. Why shouldn't the user enter the data on two lines, or even five lines:

{
  1,
  2,
  3
}

(Or pythonesquely:

{ 1
, 2
, 3
}

:-) )

Unless you go to heroic lengths to forbid them, or use the fgets/sscanf workaround usually suggested here, all of the above will be accepted. Which might make some user happy, you never know.

However, there is another issue which is possibly worth trying to solve. Here, you want to ensure that the triple is correctly terminated with a close brace }, and you can't do that by just putting } into the pattern. If you need to validate a character which comes after the the last conversion, you need to make that character a conversion (so that it becomes the last conversion). Otherwise, scanf will simply leave the unmatched input character in the input stream and report that all data conversions were successful.

So you could use something like this:

int a,b,c;
char brace;
if (scanf("{ %d , %d , %d %c", &a, &b, &c, &brace) != 4
    || brace != '}') {
  printf("Bad format");
}

That guarantees that there is a }, possibly preceded by whitespace. However, it doesn't guarantee that the } is the last thing on the line. Since it carefully does not skip whitespace after the pattern, you could check that the rest of the line is empty by reading it with fgets (which will read up to and including the trailing newline character), and then checking the characters read to make sure they all satisfy isspace().

Or you could just let the user put newlines wherever they want to.

rici
  • 234,347
  • 28
  • 237
  • 341
0

An easy way to read a line of input and test it for a format that includes trailing characters like " }" is to use fgets() and sscanf() with " %n".

"%n" records the offset of the scan so far - if it made it that far.

// Sample code
#define INT_TEXT_SIZE 11
#define FMT3 "{ %d , %d , %d }"
#define LINE_EXPECTED_MAX_SIZE (sizeof FMT3 + 3*INT_TEXT_SIZE);

// Use 2x expected max size to allow for extra spaces, leading 0, etc.
char buf[LINE_EXPECTED_MAX_SIZE * 2 + 1];  

if (fgets(buf, sizeof buf, stdin)) {
  int n = 0;
  sscanf(buf, FMT3 " %n",  &a, &b, &c, &n);

  // if scanning was incomplete or extra junk at the end...
  if (n == 0 || buf[n]) {
    printf("Bad format <%s>", buf);
  } else {
    printf("Succcess %d %d %d\n", a,b,c);
  }
}

Shortcomings with the above.

int overflow not detected.

#define INT_TEXT_SIZE 11 assumes 32-bit or smaller int. The text needs of an int are about log2(integer bit size) so code could INT_DEC_TEXT from here.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • Thank you. I willy probably use it. But do you know a way only with scanf? Thank you again but i still wonder how to do it only with scanf. – Petr Konecny Oct 29 '18 at 21:08
  • @PetrKonecny To use only `scanf()` has challenges 1) Define precisely what you want code to do when invalid or partial invalid code is entered. Including how much of the invalid input should remain in `stdin`. 2) Code could use `scanf(FMT3 " %n", &a, &b, &c, &n);`, yet that is a) not _line_ orientated and b) leaves unclear data in `stdin` on a mis-match. 3) Why do you want to _only_ use `scanf()`? Use the right tool for the job, not [this](https://smartmonkeywebworks.com/8-common-mistakes-small-businesses-make-websites/). – chux - Reinstate Monica Oct 29 '18 at 21:15