2

I'm trying to figure out a way to exit my program by pressing the Enter key when the program asks for a number.

I tried this if statement within my main() but it does not seem to work.

int main()
{
  while(1){
    int val;
    printf("\nnumber to convert:\n ");
    scanf("%i", &val);

    ibits(val);
    if (val = '\n')
    {
      break;
    }
  }

  return 0;
}
the Tin Man
  • 158,662
  • 42
  • 215
  • 303
  • 1
    By the least, you should change the `=` inside the `if` statement to `==`. – goodvibration Oct 21 '19 at 22:14
  • 4
    **Always** check the return value from `scanf()`. In this case, it's probably returning zero meaning no fields were actually read and converted. – Andrew Henle Oct 21 '19 at 22:16
  • And AFAIK, `scanf("%i", &val)` will scan your input correctly only if it's a numeric string (i.e., it won't scan the character `\n` into `val`). – goodvibration Oct 21 '19 at 22:16
  • Note that the "f" in `scanf()` meant "formatted" originally, as `scanf()` was developed to scan formatted data, and it therefore has very little ability to handle anything not in the expected format, or to allow you to recover from unexpected input. And if `scanf()` is for formatted data, it's important to remember input typed by a user is not formatted at all.... – Andrew Henle Oct 21 '19 at 22:19
  • Put `getchar();` at the end of your program. – S.S. Anne Oct 21 '19 at 22:40

1 Answers1

3

You really shouldn't use scanf directly... especially if you're expecting multiple possible formats.

Consider using fread instead and then converting the input to the proper format.

i.e.:

int main() {
  while (1) {
    char buf[1024];
    printf("\nnumber to convert:\n ");
    unsigned long len = fread(buf, 1, 1023, stdin);
    buf[len] = 0;
    if (len == 0 || (len == 1 && buf[0] == '\n') ||
        (len == 2 && buf[0] == '\r' && buf[1] == '\n'))
      break;
    int val = atoi(buf);
    ibits(val);
  }
  return 0;
}

This will also allow you to validate input and test for overflow attacks:

int main() {
  while (1) {
    char buf[1024];
    printf("\nnumber to convert:\n ");
    unsigned long len = fread(buf, 1, 1023, stdin);
    buf[len] = 0;
    if (len > 11)
      goto under_attack;
    if (len == 0 || (len == 1 && buf[0] == '\n') ||
        (len == 2 && buf[0] == '\r' && buf[1] == '\n'))
      break;
    if (buf[0] != '-' && (buf[0] < '0' || buf[0] > '9'))
      goto under_attack;
    int val = atoi(buf);
    ibits(val);
  }
  return 0;

under_attack:
  fprintf(stderr, "Under attack?!\n");
  return -1;
}
S.S. Anne
  • 15,171
  • 8
  • 38
  • 76
Myst
  • 18,516
  • 2
  • 45
  • 67
  • 1
    @JL2210 - actually, this is the perfect use case for a `goto`, for 2 reasons: 1. (most important) it makes the code easier to read - no need to read the error branches when reading the main body of the function; 2. less sophisticated compilers will place the less likely branch at the end of the machine code, improving performance. ... I know Universities tell students not to use `goto` - but in real world implementations, `goto` is the best place for error branches. – Myst Oct 21 '19 at 22:53