1

Some guy told me that for reading a string in C you can use this:

#include <stdio.h>
#include <conio.h>
#include <stdlib.h>

int main() {
    char str[100], str2[100];
    clrscr();
    printf("\nenter a string: ");
    scanf("%s", str);
    scanf("\n");
    printf("\nenter a string2: ");
    scanf("%[^\n]%*c", str2);
    printf("\nstring 1: %s", str);
    printf("\nstring 2: %s", str2);
    getch();
    return 0;
}

but the problem is this doesn't work on my computer. But if I use fflush(stdin) in place of scanf("\n") it works like a charm. I know that fflush(stdin) will flush the input stream but why doesn't the first code with scanf("\n") work?

chqrlie
  • 98,886
  • 10
  • 89
  • 149
  • 1
    `fflush(stdin);` invokes *undefined behavior*. [c - Using fflush(stdin) - Stack Overflow](https://stackoverflow.com/questions/2979209/using-fflushstdin) – MikeCAT Sep 26 '20 at 05:37
  • Just put a space at the beginning of the second `scanf()` format string, to skip over whitespace, including the newline. – Barmar Sep 26 '20 at 05:37
  • But the best way to read a line at a time is to use `fgets()`, not `scanf()`. – Barmar Sep 26 '20 at 05:38

2 Answers2

2

I think the reason why your scanf is not working because of using scanf("%[^\n]%*c",str2);. I think this call picks up the newline left in stdin during first input. I don't think scanf("\n") is consuming newline. scanf("\n") consumes as many leading whitespace characters from standard input as it can. It returns 0 if no error occurred, EOF otherwise.

As pointed out in comments, fflush() is typically used for output stream only. Its purpose is to clear (or flush) the output buffer and move the buffered data to console (in case of stdout) or disk (in case of file output stream). As per C standard, it is undefined behavior to use fflush(stdin). However some compilers allow it. The best way to read a whole line is to use fgets(). Here is how you would do it:

int main() {
    char str[100],str2[100];
    printf("Enter a string: ");
    fgets(str, 100, stdin);
    printf("Enter a string2: ");
    fgets(str2, 100, stdin);

    printf("You entered: \n");
    puts(str);
    puts(str2);
    return 0;
}

Edit: fgets() might add a newline at the end of the string read. If you're not okay with that. You would need to trim trailing newline at the end:

size_t ln = strlen(str) - 1;
if (str[ln] == '\n')
  str[ln] = '\0';
Rohan Kumar
  • 4,060
  • 6
  • 23
  • 33
  • 1
    You will want to show how to trim the trialing `'\n'` from `str` and `str2`. E.g. `str[strcspn(str, "\n")] = 0;` – David C. Rankin Sep 26 '20 at 08:33
  • *`fgets()` might add a newline at the end of the string read*: more precisely: `fgets()` keeps the trailing newline in the destination buffer. Reasons for it not to store the newline are 1) if the line does not fit in the destination buffer, 2) if the file does not have a trailing newline and you read the last line. – chqrlie Sep 26 '20 at 09:19
1

The guy gave you confusing advice:

  • #include <conio.h> is non standard and non portable.
  • scanf("%s", str); is a security flaw: if you type more than 99 letters, you will cause a buffer overrun with undefined behavior. Either use scanf("%99s", str); to read a single word or fgets(str, sizeof str, stdin); to read a full line of input.
  • scanf("\n"); will skip any whitespace. Hitting enter will not suffice, you will need to type a non blank character, which will be read by the next scanf() or other input operation.
  • fflush(stdin) has undefined behavior. If you want to read the rest of the current input line, use int c; while ((c = getchar()) != EOF && c != '\n') continue;
  • scanf("%[^\n]%*c", str2); has a security flaw, just like the previous case.
  • getch() is non portable. Just use getchar() after reading the rest of the pending line.

Here is a modified version using scanf():

#include <stdio.h>

int main() {
    char str[100] = "", str2[100] = "";
    int c;

    printf("Enter a string: ");
    scanf("%99[^\n]", str);
    while ((c = getchar()) != EOF && c != '\n')
        continue;    
    printf("Enter a string2: ");
    scanf("%99[^\n]", str2);
    while ((c = getchar()) != EOF && c != '\n')
        continue;    

    printf("string 1: %s\n", str);
    printf("string 2: %s\n", str2);
    getchar(); // prevent legacy system from closing terminal window
    return 0;
}

Here is a simpler version using fgets():

#include <stdio.h>
#include <string.h>

int main() {
    char str[100] = "", str2[100] = "";

    printf("Enter a string: ");
    fgets(str, 100, stdin);
    str[strcspn(str, "\n")] = '\0';    // strip the trailing newline if any
    printf("Enter a string2: ");
    fgets(str2, 100, stdin);
    str2[strcspn(str2, "\n")] = '\0';  // strip the trailing newline if any

    printf("string 1: %s\n", str);
    printf("string 2: %s\n", str2);
    getchar(); // prevent legacy system from closing terminal window
    return 0;
}
chqrlie
  • 98,886
  • 10
  • 89
  • 149