-2

When working on the following code:

#define MAX_NAME_LENGHT 256
int main(void)
{
   char name[MAX_NAME_LENGHT];
   printf("Enter your name: \n");
   scanf("%s", name);
   if(strncmp(name, "John Smith", 10) == 0)
   {
      printf("Hello, John Smith!\n");
   }
   else
   {
      printf("Intruder!!!\n");
   }
   return 0;
}

Many errors occur and despite inputing John Smith the output prints Intruder!!!. However, when I replace

scanf("%s", name); 

with

fgets(name, sizeof(name), stdin); 

the output prints Hello, John Smith! Why is this?

Andre Kampling
  • 5,476
  • 2
  • 20
  • 47
user24741
  • 15
  • 4
  • 4
    Well for one thing `scanf` with the `"%s"` format reads *space delimited words*. – Some programmer dude Jul 17 '17 at 07:15
  • 1
    Have you tried printing name before the strncmp just to check what was saved there? – CIsForCookies Jul 17 '17 at 07:16
  • 1
    There is no reason to use `strncmp` here. Use `strcmp` so you don't have to count characters in the match. And *always* check the return value of `scanf` (and, for that matter, `fgets`). – rici Jul 17 '17 at 07:19
  • 3
    Your code with `fgets()` will also report "Hello, John Smith!" if you type "John Smithson" or "John Smithers" or anything else that starts `John Smith`. You need to remove the newline retained by `fgets()`. Note that when you type "John Smith" but read it with `scanf("%s", name)`, you only read the "John"; the blank and the "Smith" are still waiting to be read. – Jonathan Leffler Jul 17 '17 at 07:25
  • Formatting/indentation:( – Martin James Jul 17 '17 at 07:31
  • @rici I was recommended not to use strcmp because it is unsafe. – user24741 Jul 17 '17 at 07:32
  • 1
    @user24741: Yes but if you type something longer than `John Smith` like `John Smither` it will just compare the `John Smith` part and it seems to be equal. Use `strcmp` and take care of your string before. Use `fgets` as I said in my comment below the answer. `fgets` appends an trailing `'\0'` so that it will be a valid C-string that `strcmp` will work with. Another possibility would be to use `strncmp` with the buffer size as it would stop earlier if a `'\0'` in one string is found. – Andre Kampling Jul 17 '17 at 07:41
  • @JonathanLeffler Thank You, I was unaware of this. – user24741 Jul 17 '17 at 18:53
  • `strcmp()` is for comparing _strings_. There is nothing unsafe about `strcmp(string_a, string_b);` – chux - Reinstate Monica Jul 17 '17 at 23:08

1 Answers1

1

Try using below line for your usage, so scanf keeps taking in values until it encounters a '\n' (newline), so spaces get saved as well.

scanf("%[^\n]", name);

Remember that scanf stands for "scan formatted" and there's precious little less formatted than user-entered data. It's ideal if you have total control of the input data format but generally unsuitable for user input.

Bugs
  • 4,491
  • 9
  • 32
  • 41
Rajat Kothari
  • 300
  • 1
  • 2
  • 12
  • 1
    I just want to metion that the use of `scanf` with `%s` can lead to a buffer overflow of `name` if the user inputs a lot of data because `name` is a variable on the stack here. See [here](https://stackoverflow.com/a/2430310/8051589) for more explanation. So the use `fgets` should be the preffered way. – Andre Kampling Jul 17 '17 at 07:30
  • I think `fgets` and `scanf` return different strings as well (one includes carriage return, but I forget which) – zetavolt Jul 17 '17 at 07:31
  • That `%[^\n]s` is not valid. Should be `%[^\n]` – Ajay Brahmakshatriya Jul 17 '17 at 08:32
  • 2
    @AjayBrahmakshatriya: Strictly, the `%[^\n]s` is valid, but it isn't useful. It looks for a literal `s` after the newline has been found, and the match fails because an `s` is not a newline, but there's no way for `scanf()` to report that failure (so it doesn't). You're right — it isn't what is wanted; you're over-claiming to say it's invalid. (Consider: `"%23[^\ns]s"` — that looks for a sequence of up to 23 characters other than `s` or newline, followed by an `s` (and not a newline). There are still problems detecting whether the post-conversion match worked, but it is more nearly plausible.) – Jonathan Leffler Jul 17 '17 at 18:59
  • @JonathanLeffler I agree I worded my comment incorrectly. I meant "is not valid here" (and might cause issues). @RajatKothari please read the comment as - That `%[^\n]s` will not give correct results here. Should be `%[^\n]`. – Ajay Brahmakshatriya Jul 18 '17 at 04:55