By sfactor


2010-04-22 19:21:18 8 Comments

I am trying to get some data from the user and send it to another function in gcc. The code is something like this.

printf("Enter your Name: ");
if (!(fgets(Name, sizeof Name, stdin) != NULL)) {
    fprintf(stderr, "Error reading Name.\n");
    exit(1);
}

However, I find that it has a newline \n character in the end. So if I enter John it ends up sending John\n. How do I remove that \n and send a proper string.

13 comments

@Pawel Flajszer 2019-02-06 14:15:51

My Newbie way ;-) Please let me know if that's correct. It seems to be working for all my cases:

#define IPT_SIZE 5

int findNULL(char* arr)
{
    for (int i = 0; i < strlen(arr); i++)
    {
        if (*(arr+i) == '\n')
        {
            return i;
        }
    }
    return 0;
}

int main()
{
    char *input = malloc(IPT_SIZE + 1 * sizeof(char)), buff;
    int counter = 0;

    //prompt user for the input:
    printf("input string no longer than %i characters: ", IPT_SIZE);
    do
    {
        fgets(input, 1000, stdin);
        *(input + findNULL(input)) = '\0';
        if (strlen(input) > IPT_SIZE)
        {
            printf("error! the given string is too large. try again...\n");
            counter++;
        }
        //if the counter exceeds 3, exit the program (custom function):
        errorMsgExit(counter, 3); 
    }
    while (strlen(input) > IPT_SIZE);

//rest of the program follows

free(input)
return 0;
}

@Naveen Kumar 2015-03-16 05:45:21

For single '\n' trmming,

void remove_new_line(char* string)
{
    size_t length = strlen(string);
    if((length > 0) && (string[length-1] == '\n'))
    {
        string[length-1] ='\0';
    }
}

for multiple '\n' trimming,

void remove_multi_new_line(char* string)
{
  size_t length = strlen(string);
  while((length>0) && (string[length-1] == '\n'))
  {
      --length;
      string[length] ='\0';
  }
}

@melpomene 2018-09-17 05:26:33

Why nest if when you can simply write one condition using &&? That while loop has a strange structure; it could simply be while (length > 0 && string[length-1] == '\n') { --length; string[length] = '\0'; }.

@Naveen Kumar 2018-09-18 06:39:31

@melpomene thanks for the suggestion. Update the code.

@melpomene 2018-09-18 06:47:09

I'd suggest that the first function is more naturally defined as: size_t length = strlen(string); if (length > 0 && string[length-1] == '\n') { string[length-1] = '\0'; }. This also mirrors the second definition better (just using if instead of while).

@Naveen Kumar 2018-09-18 07:00:46

@elpomene thanks. It makes sense. I updated the code.

@Balazs Kiss 2018-05-09 10:50:37

Try this one:

        int remove_cr_lf(char *str)
        {
          int len =0;


          len = strlen(str);

          for(int i=0;i<5;i++)
          {
            if (len>0)
            if (str[len-1] == '\n')
            {
              str[len-1] = 0;
              len--;
            }

            if (len>0)
            if (str[len-1] == '\r')
            {
              str[len-1] = 0;
              len--;
            }
          }

          return 0;
        }

@melpomene 2018-09-17 05:21:33

len = strlen(str) may overflow: strlen returns size_t, not int. What's with the weird if (len>0) if (...) conditionals? Do you not know about &&? If you're going to remove multiple trailing instances of CR/LF, why limit yourself to 5? Why not remove all of them? Why does the function have an int return type when it always returns 0? Why not just return void?

@sjsam 2017-11-25 07:31:30

If using getline is an option - Not neglecting its security issues and if you wish to brace pointers - you can avoid string functions as the getline returns the number of characters. Something like below

#include<stdio.h>
#include<stdlib.h>
int main(){
char *fname,*lname;
size_t size=32,nchar; // Max size of strings and number of characters read
fname=malloc(size*sizeof *fname);
lname=malloc(size*sizeof *lname);
if(NULL == fname || NULL == lname){
 printf("Error in memory allocation.");
 exit(1);
}
printf("Enter first name ");
nchar=getline(&fname,&size,stdin);
if(nchar == -1){ // getline return -1 on failure to read a line.
 printf("Line couldn't be read.."); 
 // This if block could be repeated for next getline too
 exit(1);
}
printf("Number of characters read :%zu\n",nchar);
fname[nchar-1]='\0';
printf("Enter last name ");
nchar=getline(&lname,&size,stdin);
printf("Number of characters read :%zu\n",nchar);
lname[nchar-1]='\0';
printf("Name entered %s %s\n",fname,lname);
return 0;
}

Note: The [ security issues ] with getline shouldn't be neglected though.

@chux 2015-01-01 10:29:35

Below is a fast approach to remove a potential '\n' from a string saved by fgets().
It uses strlen(), with 2 tests.

char buffer[100];
if (fgets(buffer, sizeof buffer, stdin) != NULL) {

  size_t len = strlen(buffer);
  if (len > 0 && buffer[len-1] == '\n') {
    buffer[--len] = '\0';
  }

Now use buffer and len as needed.

This method has the side benefit of a len value for subsequent code. It can be easily faster than strchr(Name, '\n'). Ref YMMV, but both methods work.


buffer, from the original fgets() will not contain in "\n" under some circumstances:
A) The line was too long for buffer so only char preceding the '\n' is saved in buffer. The unread characters remain in the stream.
B) The last line in the file did not end with a '\n'.

If input has embedded null characters '\0' in it somewhere, the length reported by strlen() will not include the '\n' location.


Some other answers' issues:

  1. strtok(buffer, "\n"); fails to remove the '\n' when buffer is "\n". From this answer - amended after this answer to warn of this limitation.

  2. The following fails on rare occasions when the first char read by fgets() is '\0'. This happens when input begins with an embedded '\0'. Then buffer[len -1] becomes buffer[SIZE_MAX] accessing memory certainly outside the legitimate range of buffer. Something a hacker may try or found in foolishly reading UTF16 text files. This was the state of an answer when this answer was written. Later a non-OP edited it to include code like this answer's check for "".

    size_t len = strlen(buffer);
    if (buffer[len - 1] == '\n') {  // FAILS when len == 0
      buffer[len -1] = '\0';
    }
    
  3. sprintf(buffer,"%s",buffer); is undefined behavior: Ref. Further, it does not save any leading, separating or trailing whitespace. Now deleted.

  4. [Edit due to good later answer] There are no problems with the 1 liner buffer[strcspn(buffer, "\n")] = 0; other than performance as compared to the strlen() approach. Performance in trimming is usually not an issue given code is doing I/O - a black hole of CPU time. Should following code need the string's length or is highly performance conscious, use this strlen() approach. Else the strcspn() is a fine alternative.

@Rrz0 2018-11-10 10:16:57

Thanks for the helpful answer. Can we use strlen(buffer) when buffer size is dynamically allocated using malloc ?

@chux 2018-11-10 16:15:27

@Rrz0 buffer = malloc(allocation_size); length = strlen(buffer); is bad - data at memory pointed to by buffer is unknown. buffer = malloc(allocation_size_4_or_more); strcpy(buffer, "abc"); length = strlen(buffer); is OK

@Matheus Martins Jerônimo 2017-09-17 12:21:00

 for(int i = 0; i < strlen(Name); i++ )
{
    if(Name[i] == '\n') Name[i] = '\0';
}

You should give it a try. This code basically loop through the string until it finds the '\n'. When it's found the '\n' will be replaced by the null character terminator '\0'

Note that you are comparing characters and not strings in this line, then there's no need to use strcmp():

if(Name[i] == '\n') Name[i] = '\0';

since you will be using single quotes and not double quotes. Here's a link about single vs double quotes if you want to know more

@Anh Pham 2017-09-17 12:44:09

it would be better if you explain and edit the format of your code.

@Massimiliano Kraus 2017-09-17 13:28:59

Usually it's better to explain a solution instead of just posting some rows of anonymous code. You can read How do I write a good answer, and also Explaining entirely code-based answers.

@Matheus Martins Jerônimo 2017-09-17 22:46:01

I'm sorry this was my first contribution here. I will fix it. Thanks for the feedback

@chux 2017-12-06 22:03:29

Inefficient: for(int i = 0; i < strlen(Name); i++ ) will call strlen(Name) many times (loop changes Name[]) so with a length N, this is a O(N*N) solution. Only 1 call to strlen(Name), if any , is needed to provide an O(N)` solution. Unclear why int i is used instead of size_t i. Consider for(size_t i = 0; i < Name[i]; i++ )

@melpomene 2018-09-17 05:24:30

@chux More like for (size_t i = 0; Name[i]; i++) { if (Name[i] == '\n') { Name[i] = '\0'; break; } }

@chux 2018-09-17 05:33:15

@melpomene Yes that would be direct and good. Yet if the break was not there, i++ would occur and the following Name[i] would be 0, stopping the loop. Your good idea has the advantage of i being the string length after the loop.

@melpomene 2018-09-17 05:34:03

@chux The main point was that i < Name[i] makes no sense.

@chux 2018-09-17 05:36:21

@melpomene I see now. yes for(size_t i = 0; i < Name[i]; i++ ) should have been for(size_t i = 0; Name[i]; i++ )

@Jerry Coffin 2010-04-22 19:26:52

The slightly ugly way:

char *pos;
if ((pos=strchr(Name, '\n')) != NULL)
    *pos = '\0';
else
    /* input too long for buffer, flag error */

The slightly strange way:

strtok(Name, "\n");

Note that the strtok function doesn't work as expected if the user enters an empty string (i.e. presses only Enter). It leaves the \n character intact.

There are others as well, of course.

@frankc 2010-04-22 20:42:04

Careful with the strtok way...not thread safe

@Michael Burr 2010-04-22 21:36:51

Any C runtime library that is thread aware (which is to say, most any that target a multi-threaded platform), strtok() will be thread safe (it will use thread local storage for the 'inter-call' state). That said, it's still generally better to use the non-standard (but common enough) strtok_r() variant.

@Tim Čas 2015-02-11 19:09:02

See my answer for completely thread-safe and reentrant variant, similar to your strtok approach (and it works with empty inputs). In fact, a good way to implement strtok is to use strcspn and strspn.

@Malcolm McLean 2017-01-08 18:52:50

It's important to handle the else case if you are in an environment where there is a risk of over-long lines. Silently truncating input can cause very damaging bugs.

@twobit 2017-08-17 08:55:03

If you like one-liners and are using glibc, try *strchrnul(Name, '\n') = '\0';.

@chux 2017-12-06 22:36:03

When strchr(Name, '\n') == NULL, then aside from "input too long for buffer, flag error", other possibilities exist: Last text in stdin did not end with a '\n' or a rare embedded null character was read.

@rajarajan2809 2018-04-27 11:34:42

thanks guys, that worked like a charm

@Philippe A. 2015-11-18 17:43:26

Tim Čas one liner is amazing for strings obtained by a call to fgets, because you know they contain a single newline at the end.

If you are in a different context and want to handle strings that may contain more than one newline, you might be looking for strrspn. It is not POSIX, meaning you will not find it on all Unices. I wrote one for my own needs.

/* Returns the length of the segment leading to the last 
   characters of s in accept. */
size_t strrspn (const char *s, const char *accept)
{
  const char *ch;
  size_t len = strlen(s);

more: 
  if (len > 0) {
    for (ch = accept ; *ch != 0 ; ch++) {
      if (s[len - 1] == *ch) {
        len--;
        goto more;
      }
    }
  }
  return len;
}

For those looking for a Perl chomp equivalent in C, I think this is it (chomp only removes the trailing newline).

line[strrspn(string, "\r\n")] = 0;

The strrcspn function:

/* Returns the length of the segment leading to the last 
   character of reject in s. */
size_t strrcspn (const char *s, const char *reject)
{
  const char *ch;
  size_t len = strlen(s);
  size_t origlen = len;

  while (len > 0) {
    for (ch = reject ; *ch != 0 ; ch++) {
      if (s[len - 1] == *ch) {
        return len;
      }
    }
    len--;
  }
  return origlen;
}

@chux 2015-11-18 17:59:12

"because you know they contain a single newline at the end." --> It even works when there is no '\n' (or if the string is "").

@Philippe A. 2015-11-18 18:14:58

In response to your first comment chux, my answer preserves that. I had to throw resetlen in strrcspn for when there is no \n.

@chqrlie 2016-08-17 14:48:05

Why use goto end; instead of return len; ?

@Philippe A. 2016-11-29 20:48:55

@chqrlie I needed to get out of this inelegant 2-level loop I got into. The harm was done. Why not a goto?

@chqrlie 2016-11-29 23:04:08

You have two kinds of gotos in your code: a useless goto that can be replaced with a return statement and a backwards goto that is considered evil. Using strchr helps implement strrspn and strrcspn in a simpler fashion: size_t strrspn(const char *s, const char *accept) { size_t len = strlen(s); while (len > 0 && strchr(accept, s[len - 1])) { len--; } return len; } and size_t strrcspn(const char *s, const char *reject) { size_t len = strlen(s); while (len > 0 && !strchr(reject, s[len - 1])) { len--; } return len; }

@Philippe A. 2016-11-30 20:16:02

I would agree with strchr if it did not run up to the last character of the string s. I agree a return would be best. It would replace two instructions for one. But that does not mean the goto in the other function should go. If you don't like gotos, don't use them. Spare me the all-gotos-are-evil rhetoric.

@fnisi 2016-02-18 00:41:19

The function below is a part of string processing library I am maintaining on Github. It removes and unwanted characters from a string, exactly what you want

int zstring_search_chr(const char *token,char s){
    if (!token || s=='\0')
        return 0;

    for (;*token; token++)
        if (*token == s)
            return 1;

    return 0;
}

char *zstring_remove_chr(char *str,const char *bad) {
    char *src = str , *dst = str;
    while(*src)
        if(zstring_search_chr(bad,*src))
            src++;
        else
            *dst++ = *src++;  /* assign first, then incement */

    *dst='\0';
        return str;
}

An example usage could be

Example Usage
      char s[]="this is a trial string to test the function.";
      char const *d=" .";
      printf("%s\n",zstring_remove_chr(s,d));

  Example Output
      thisisatrialstringtotestthefunction

You may want to check other available functions, or even contribute to the project :) https://github.com/fnoyanisi/zString

@chqrlie 2016-08-17 14:43:35

You should remove the * in *src++; and make bad, token and d const char *. Also why not use strchr instead of zChrSearch? *src cannot be '\0' in your zStrrmv function.

@fnisi 2016-10-21 08:30:56

Thanks @chqrlie! updated the code to reflect your suggestions..... zstring started as a fun project with the aim of creating a string manipulation library without using any standard library functions, hence I did not use strchr

@melpomene 2018-09-17 05:29:24

Writing a "string manipulation library without using any standard library functions" is a nice exercise, but why tell other people to use it? If anything, it's going to be slower and less tested than any standard library.

@Jonathan Leffler 2018-10-14 07:53:12

This is doing a different job from what the question asks about. It probably can be used to get rid of the only newline, but it feels like overkill.

@James Morris 2010-04-22 19:26:55

size_t ln = strlen(name) - 1;
if (*name && name[ln] == '\n') 
    name[ln] = '\0';

@legends2k 2012-10-04 08:27:24

I don't find JerryCoffin's solution better than this since, it's not optimized or something (since both search the string char by char), just that it's less verbose and slightly buggy due to @Smi's comment. I find your solution cleaner :)

@Bitterblue 2013-01-11 13:13:44

I also think this is the better one. More efficient probably too.

@Edward Olamisan 2013-05-31 03:26:12

Will probably throw exception if the string is empty, won't it? Like index out of range.

@James Morris 2013-06-03 09:35:50

@EdwardOlamisan think I'll leave that as a exercise for the reader ;-)

@James Morris 2013-07-14 23:27:01

@EdwardOlamisan, the string won't ever be empty however.

@chux 2014-07-02 14:00:50

@James Morris In unusual cases fgets(buf, size, ....) --> strlen(buf) == 0. 1) fgets() reads as the first char a '\0'. 2) size == 1 3) fgets() returns NULL then buf contents could be anything. (OP's code does test for NULL though) Suggest: size_t ln = strlen(name); if (ln > 0 && name[ln-1] == '\n') name[--ln] = '\0';

@abligh 2015-03-16 22:38:15

What if the string is empty? ln would be -1, save for the fact size_t is unsigned, thus writing to random memory. I think you want to use ssize_t and check ln is >0.

@chux 2015-12-06 23:10:30

@abligh Agree about name[0] could have the value of '\0'. Yet ssize_t ln = strlen(name) - 1; if(ln > 0) ...` may not work either as ssize_t is non-C standard and may be able to represent strlen("") - 1 as a positive number. Simply enough to code size_t ln = strlen(name); if (ln > 0 && name[ln-1] == '\n') ...

@P.P. 2015-12-31 18:56:08

@chux It's much simpler than that to fix it just by testing if the string begins with 0. I just edited the same.

@AnT 2016-03-29 18:28:17

@legends2k: A search for a compile-time value (especially a zero value as in strlen) can be implemented much more efficiently than a plain char-by-char search. For which reason I'd consider this solution better than a strchr or strcspn based ones.

@legends2k 2016-03-30 06:21:37

@AnT Thanks, good to know :) so this solution maybe faster too! I dunno for sure since the implementation differs from compiler to compiler.

@Tim Čas 2015-02-11 18:54:56

Perhaps the simplest solution uses one of my favorite little-known functions, strcspn():

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

If you want it to also handle '\r' (say, if the stream is binary):

buffer[strcspn(buffer, "\r\n")] = 0; // works for LF, CR, CRLF, LFCR, ...

The function counts the number of characters until it hits a '\r' or a '\n' (in other words, it finds the first '\r' or '\n'). If it doesn't hit anything, it stops at the '\0' (returning the length of the string).

Note that this works fine even if there is no newline, because strcspn stops at a '\0'. In that case, the entire line is simply replacing '\0' with '\0'.

@chux 2015-02-11 19:39:34

This even handles the rare buffer than begins with '\0', something that causes grief for the buffer[strlen(buffer) - 1] = '\0'; approach.

@Tim Čas 2015-02-11 19:44:59

@chux: Yup, I wish more people had known about strcspn(). One of the more useful functions in the library, IMO. I've decided to write and publish a bunch of common C hacks like this one today; a strtok_r implementation using strcspn and strspn was one of the first: codepad.org/2lBkZk0w (Warning: I can't guarantee that it's without bugs; it was written hastily and probably has a few). I dunno where I'll publish 'em yet, though, but I intend to make it in the spirit of the famous "bit twiddling hacks".

@chux 2015-02-11 20:04:45

Looked into ways to robustly trim fgets(). This strcspn() seems to be the only correct one-liner. strlen is quicker - though not as simple.

@Tim Čas 2016-12-25 15:46:01

@Stargateur: Sure it is. Old Mac OS used \r. Some systems even used \n\r (as opposed to \r\n).

@Stargateur 2016-12-25 21:00:32

@TimČas Never mind, stackoverflow.com/a/18383562/7076153. That confirm me that I only want to use '\n'.

@Tim Čas 2016-12-25 22:48:57

@Stargateur: Read my answer again. I mentioned both. I said it's "\n" in the usual case, but "\r\n" if the stream is binary (and if one wants to handle all 3 common types of line endings: CR, LF, and CRLF).

@sidbushes 2017-02-20 19:34:27

This is great for terminating a string at its first newline, but the question asks about a trailing newline. For fgets this distinction is unimportant but it matters if someone wants to use this in a general case.

@Tim Čas 2017-04-09 13:44:05

@sidbushes: The question, both in the title and the content, asks about the trailing newline from fgets() input. Which is always also the first newline.

@sidbushes 2017-04-10 12:48:40

@TimČas Yes, I am well aware of that. Let me post it again: For fgets this distinction is unimportant but it matters if someone wants to use this in a general case. A Google search back when, for if there was a C/C++ equivalent yet for Perl's chomp, led me here. Anyone else looking for that, who finds this and does not recognize the distinction, may end up with problems.

@Tim Čas 2017-05-08 12:08:51

@sidbushes: I understand where you're coming from, but I cannot be held responsible for Google search results for specific terms. Talk to Google, not me.

@Amitabha 2013-06-30 01:15:09

Direct to remove the '\n' from the fgets output if every line has '\n'

line[strlen(line) - 1] = '\0';

Otherwise:

void remove_newline_ch(char *line)
{
    int new_line = strlen(line) -1;
    if (line[new_line] == '\n')
        line[new_line] = '\0';
}

@Mike Mertsock 2013-06-30 01:37:18

Note it would be safer to use strnlen instead of strlen.

@Étienne 2013-11-19 23:12:08

A comment to the first answer in the question linked states "Note that strlen(), strcmp() and strdup() are safe. The 'n' alternatives give you additional functionality."

@M.M 2015-10-28 20:55:35

@esker no, it wouldn't. inserting an n does not magically increase safety, in this case it in fact would make the code more dangerous. Similarly with strncpy, a terribly unsafe function. The post you linked to is bad advice.

@alk 2017-06-17 09:55:58

This fails miserably for an empty string (""). Also strlen() returns size_t not int.

@Jean-François Fabre 2018-06-14 19:38:04

this is unsafe for an empty string, it will write at index -1. Don't use this.

@draebek 2010-04-22 19:30:18

char name[1024];
unsigned int len;

printf("Enter your name: ");
fflush(stdout);
if (fgets(name, sizeof(name), stdin) == NULL) {
    fprintf(stderr, "error reading name\n");
    exit(1);
}
len = strlen(name);
if (name[len - 1] == '\n')
    name[len - 1] = '\0';

@alk 2017-06-17 09:56:30

This fails miserably for an empty string (""). Also strlen() returns size_t not int.

Related Questions

Sponsored Content

1 Answered Questions

[SOLVED] fgets reads newline character from prompt

  • 2018-12-11 13:06:35
  • boston
  • 61 View
  • 0 Score
  • 1 Answer
  • Tags:   c shell fgets stdio

26 Answered Questions

[SOLVED] How can I remove a trailing newline in Python?

  • 2008-11-08 18:25:24
  • RidingThisToTheTop
  • 1442821 View
  • 1455 Score
  • 26 Answer
  • Tags:   python newline trailing

1 Answered Questions

[SOLVED] using fgets() with stdin as input: ^D fails to signal EOF

  • 2018-10-13 15:59:53
  • ctt25
  • 81 View
  • 1 Score
  • 1 Answer
  • Tags:   c fgets eof

1 Answered Questions

[SOLVED] Trimming a trailing \0 from fgets() in C

  • 2018-09-13 17:12:03
  • Alexander Nenartovich
  • 74 View
  • 2 Score
  • 1 Answer
  • Tags:   c tokenize fgets

11 Answered Questions

[SOLVED] How to replace a character by a newline in Vim?

15 Answered Questions

[SOLVED] JavaScript string newline character?

  • 2009-07-20 20:08:52
  • Landon Kuhn
  • 972183 View
  • 375 Score
  • 15 Answer
  • Tags:   javascript newline

1 Answered Questions

[SOLVED] Remove newline from fgets() input

4 Answered Questions

[SOLVED] Clear input stream after fgets set null char before newline

  • 2017-08-02 19:56:22
  • Miket25
  • 678 View
  • 2 Score
  • 4 Answer
  • Tags:   c fgets

1 Answered Questions

[SOLVED] How to remove multiple trailing newlines after fgets()?

2 Answered Questions

[SOLVED] C - fgets() - length of newline char

  • 2012-11-17 14:18:10
  • user10099
  • 3516 View
  • 2 Score
  • 2 Answer
  • Tags:   c char newline fgets

Sponsored Content