Search code examples
cstringcursorscanffgets

Why fgets takes cursor to next line?


I have taken a string from the keyboard using the fgets() function. However, when I print the string using printf(), the cursor goes to a new line.

Below is the code.

#include<stdio.h>
int main()
{
    char name[25];

    printf("Enter your name: ");
    fgets(name, 24, stdin);
    printf("%s",name);

    return 0;
}

And below is the output.

-bash-4.1$ ./a.out
Enter your name: NJACK1 HERO
NJACK1 HERO 
-bash-4.1$

Why is the cursor going to the next line even though I have not added a \n in the printf()?

However, I have noticed that if I read a string using scanf(), and then print it using printf() (without using \n), the cursor does not go to next line.

Does fgets() append a \n in the string ? If it does, will it append \0 first then \n, or \n first and then \0?


Solution

  • The reason printf is outputting a newline is that you have one in your string.

    fgets is not "adding" a newline --- it is simply reading it from the input as well. Reading for fgets stops just after the newline (if any).

    Excerpt from the manpage, emphasis mine:

    The fgets() function reads at most one less than the number of characters specified by size from the given stream and stores them in the string str. Reading stops when a newline character is found, at end-of-file or error. The newline, if any, is retained. If any characters are read and there is no error, a `\0' character is appended to end the string.

    An easy way to check if there's a newline is to use the help of one of my favorite little-known functions --- strcspn():

    size_t newline_pos = strcspn(name, "\r\n");
    if(name[newline_pos])
    {
        /* we had a newline, so name is complete; do whatever you want here */
        //...
    
        /* if this is the only thing you do
           you do *not* need the `if` statement above (just this line) */
        name[newline_pos] = 0;
    }
    else
    {
        /* `name` was truncated (the line was longer than 24 characters) */
    }
    

    Or, as an one-liner:

    // WARNING: This means you have no way of knowing if the name was truncated!
    name[strcspn(name, "\r\n")] = 0;