Question

Remove Trailing Newlines from fgets() Input in C

cstringgccnewlinefgets

Question

How can I remove the trailing newline character that fgets() stores when reading a user's name in C?

printf("Enter your name: ");

if (fgets(Name, sizeof Name, stdin) == NULL) {
    fprintf(stderr, "Error reading name.\n");
    exit(1);
}

For example, when the user enters John, the string passed to another function is "John\n". How can I remove the newline so that it becomes a normal null-terminated string containing only "John"?

Short Answer

You will learn why fgets() often keeps the Enter key's newline, how to remove it safely, and how to handle the important case where an input line is longer than the destination buffer.

Concept

fgets() reads characters from a stream, such as stdin, into a character array. It reads at most size - 1 characters and always adds a terminating null character ('\0') when it succeeds.

When the user presses Enter, the input stream normally contains a newline character ('\n'). If there is enough room in the array, fgets() reads and stores that newline too:

char name[20];
/* User types: John, then presses Enter */

fgets(name, sizeof name, stdin);
/* name contains: 'J' 'o' 'h' 'n' '\n' '\0' */

This behavior is useful when reading complete text lines, but it can be inconvenient for values such as names, menu choices, file paths, or IDs. A common solution is to locate the newline and replace it with the string terminator, \0.

It is important to remove a newline only when one exists. If the user enters a line longer than the buffer, fgets() stops because the buffer is full. In that case, no newline is stored, and the rest of the line remains waiting in stdin.

Mental Model

Think of fgets() as putting letters into a labelled box (the character array). Pressing Enter gives it one extra item: the newline character.

The null terminator, \0, is a stop sign that tells C where the string ends. To trim the input, find the newline and replace it with that stop sign. Everything after the new stop sign is no longer part of the string.

Take Quiz

Syntax and Examples

Use strcspn() from <string.h> to find the first newline safely, then replace it with \0.

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

int main(void) {
    char name[50];

    printf("Enter your name: ");

    if (fgets(name, sizeof name, stdin) == NULL) {
        fprintf(stderr, "Could not read input.\n");
        return 1;
    }

    name[strcspn(name, "\n")] = '\0';

    printf("Hello, %s!\n", name);
    return 0;
}

strcspn(name, "\n") returns the index of the first newline. If a newline is present, that character is replaced. If no newline is present, strcspn() returns the index of the existing null terminator, so assigning \0 there leaves the string unchanged.

For input that may come from files created on Windows, you can remove either \n or \r:

name[strcspn(name, "\r\n")] = '\0';

This handles lines ending in \n and lines ending in \r\n.

Step by Step Execution

Consider this program fragment:

char name[10];
fgets(name, sizeof name, stdin);
name[strcspn(name, "\n")] = '\0';

If the user types John and presses Enter:

  1. The input stream contains J, o, h, n, and \n.
  2. fgets() copies those characters into name and appends \0.
  3. Before trimming, the array represents "John\n".
  4. strcspn(name, "\n") finds \n at index 4.
  5. The assignment changes name[4] from \n to \0.
  6. C now sees the string as "John".

Array view:

IndexBefore trimmingAfter trimming
0JJ
1oo
2hh
3nn
4\n\0
5\0\0

Real World Use Cases

Removing the newline after fgets() is useful whenever a user enters a line intended to be a single value:

  • Login or registration tools: read a username before comparing it with stored values.
  • Command-line menus: turn "q\n" into "q" before checking the choice.
  • Configuration prompts: read a host name, directory path, or port number as text.
  • File processing: remove line endings before parsing CSV-like records or matching text.
  • API request construction: prevent an accidental newline from becoming part of an identifier or request field.
Take Quiz

Real Codebase Usage

In real C programs, a common pattern is to put line reading and trimming into one helper function. This avoids repeating error checks and makes callers receive clean strings.

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

int read_line(char *buffer, size_t size) {
    if (size == 0 || fgets(buffer, size, stdin) == NULL) {
        return 0;
    }

    buffer[strcspn(buffer, "\r\n")] = '\0';
    return 1;
}

A caller can then use a guard clause:

char name[50];

printf("Enter your name: ");
if (!read_line(name, sizeof name)) {
    fprintf(stderr, "Input error.\n");
    return 1;
}

if (name[0] == '\0') {
    fprintf(stderr, "A name is required.\n");
    return 1;
}

For fixed-size fields, production code should also decide what to do with overly long input. Often it rejects the input and discards the remaining characters up to the next newline, preventing that leftover text from corrupting the next prompt.

Common Mistakes

Removing the last character unconditionally

This is unsafe when no newline was read:

/* Broken: removes a real character if the input filled the buffer. */
name[strlen(name) - 1] = '\0';

If the user enters more characters than fit, fgets() may not store \n. The code above would delete the final valid character. Use strcspn() instead.

Forgetting that a long line remains in stdin

char name[5];
fgets(name, sizeof name, stdin);

If the user enters Alexander, this reads only "Alex". The rest of the input, including the newline, remains for the next read. Detect this situation and discard the remainder when appropriate:

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

if (strchr(name, '\n') == NULL) {
    int ch;
    while ((ch = getchar()) != '\n' && ch != EOF) {
        /* discard remaining input */
    }
}

Using gets()

/* Never use this. gets() cannot limit the input size. */
gets(name);

gets() is removed from the C standard because it can overflow the destination array. Prefer fgets().

Checking fgets() in a confusing way

This works but is harder to read:

if (!(fgets(Name, sizeof Name, stdin) != NULL)) {
    /* ... */
}

Prefer the direct condition:

if (fgets(name, sizeof name, stdin) == NULL) {
    /* handle error or end of input */
}

Assuming every platform uses only \n

Console input commonly uses \n, but text files may contain Windows-style \r\n. Use "\r\n" with strcspn() when handling input from multiple sources.

Comparisons

ApproachSafe when no newline exists?Notes
name[strcspn(name, "\n")] = '\0';YesClear and concise; a strong default.
name[strcspn(name, "\r\n")] = '\0';YesAlso handles Windows-style line endings.
char *p = strchr(name, '\n'); if (p) *p = '\0';YesExplicitly checks whether the newline was found.
name[strlen(name) - 1] = '\0';NoOnly safe after proving the last character is a newline.
scanf("%s", name)Not applicableSkips leading whitespace and stops at spaces, so it cannot read full names like Mary Jane.

fgets() is generally a better starting point for interactive text input because it has a buffer-size limit and can read spaces. Trim its newline afterward if the application does not need it.

Take Quiz

Cheat Sheet

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

char text[100];

if (fgets(text, sizeof text, stdin) == NULL) {
    /* error or end of input */
}

/* Remove one of: \n or \r */
text[strcspn(text, "\r\n")] = '\0';
  • fgets(buffer, size, stdin) reads at most size - 1 characters.
  • On success, fgets() null-terminates the array.
  • The newline is stored only if it fits in the buffer.
  • strcspn(text, "\r\n") is safe even when neither line-ending character exists.
  • If no newline was stored, the user may have entered a line longer than the buffer.
  • Never use gets().
  • Use sizeof array only when the buffer is an actual array in the current scope; use the supplied size for a pointer parameter.

FAQ

Does fgets() always include a newline?

No. It includes \n only when it reads one before reaching its size - 1 character limit. End-of-file can also end input without a newline.

Why does fgets() keep the newline?

fgets() is designed to read a line from a stream. The newline is part of that line, so it preserves it when space allows.

Is strcspn() safe if there is no newline?

Yes. It returns the length of the string, which is the position of its existing null terminator. Writing \0 there changes nothing.

Can I use strchr() instead of strcspn()?

Yes.

char *newline = strchr(name, '\n');
if (newline != NULL) {
    *newline = '\0';
}

Use strcspn() when you want to remove either \r or \n with one statement.

How do I read a name containing spaces?

Use fgets(), not scanf("%s", ...). fgets() can read Mary Jane; trim its ending newline afterward.

What should I do if the user enters more text than my buffer holds?

Choose a policy: reject it and discard the rest of the line, dynamically allocate a larger buffer, or read the line in chunks. Do not let leftover characters silently become the next answer.

Should I trim whitespace with the newline?

Usually, remove only line endings first. Removing leading or trailing spaces may be incorrect for some data, so do it only when the application's rules require it.

Take Quiz

Mini Project

Description

Build a small console profile prompt that reads a full name and a city. The program demonstrates safe line input with fgets(), newline trimming, empty-value validation, and cleanup of input that is too long for the buffer.

Goal

Collect and print a clean user profile without storing trailing newline characters or allowing leftover input to affect the next prompt.

Requirements

Use fgets() to read both the name and city. Trim \n and \r from each successful input. Reject empty values. Detect input that does not fit in the buffer. Print the completed profile only after both values are valid.

Take Quiz

Keep learning

Related questions

View more