345

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.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
sfactor
  • 12,592
  • 32
  • 102
  • 152
  • 31
    `if (!fgets(Name, sizeof Name, stdin))` (at the very least don't use two negations, ! and !=) –  Apr 22 '10 at 20:05
  • 7
    @Roger Pate "don't use two negations" --> hmmm, if we dig deep "don't" and "negation" are both _negations_. ;-). Perhaps "Use `if (fgets(Name, sizeof Name, stdin)) {`. – chux - Reinstate Monica Aug 24 '16 at 14:53
  • 5
    @chux, I am sure you meant `if (fgets(Name, sizeof Name, stdin) == NULL ) {` – R Sahu Apr 05 '18 at 18:50
  • @RSahu [True](https://stackoverflow.com/questions/2693776/removing-trailing-newline-character-from-fgets-input?noredirect=1#comment86370602_2693776): pesky `!`: – chux - Reinstate Monica Apr 05 '18 at 19:30

15 Answers15

620

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'.

Tim Čas
  • 10,501
  • 3
  • 26
  • 32
  • 45
    This even handles the rare `buffer` than _begins_ with `'\0'`, something that causes grief for the `buffer[strlen(buffer) - 1] = '\0';` approach. – chux - Reinstate Monica Feb 11 '15 at 19:39
  • 7
    @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: http://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". – Tim Čas Feb 11 '15 at 19:44
  • 4
    Looked into ways to _robustly_ [trim `fgets()`](http://codereview.stackexchange.com/q/67608/29485). This `strcspn()` seems to be the _only_ correct one-liner. [`strlen`](http://stackoverflow.com/a/27729970/2410359) is quicker - though not as simple. – chux - Reinstate Monica Feb 11 '15 at 20:04
  • 1
    @Stargateur: Sure it is. Old Mac OS used `\r`. Some systems even used `\n\r` (as opposed to `\r\n`). – Tim Čas Dec 25 '16 at 15:46
  • 1
    @TimČas Never mind, http://stackoverflow.com/a/18383562/7076153. That confirm me that I only want to use `'\n'`. – Stargateur Dec 25 '16 at 21:00
  • 1
    @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). – Tim Čas Dec 25 '16 at 22:48
  • 2
    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. – sidbushes Feb 20 '17 at 19:34
  • 7
    @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. – Tim Čas Apr 09 '17 at 13:44
  • @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. – sidbushes Apr 10 '17 at 12:48
  • 10
    @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. – Tim Čas May 08 '17 at 12:08
230

The elegant way:

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

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.

klutt
  • 30,332
  • 17
  • 55
  • 95
Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • 7
    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. – Michael Burr Apr 22 '10 at 21:36
  • 2
    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`. – Tim Čas Feb 11 '15 at 19:09
  • 3
    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. – Malcolm McLean Jan 08 '17 at 18:52
  • 4
    If you like one-liners and are using glibc, try `*strchrnul(Name, '\n') = '\0';`. – twobit Aug 17 '17 at 08:55
  • 1
    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. – chux - Reinstate Monica Dec 06 '17 at 22:36
86
size_t ln = strlen(name) - 1;
if (*name && name[ln] == '\n') 
    name[ln] = '\0';
P.P
  • 117,907
  • 20
  • 175
  • 238
James Morris
  • 4,867
  • 3
  • 32
  • 51
  • 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 :) – legends2k Oct 04 '12 at 08:27
  • 9
    Will probably throw exception if the string is empty, won't it? Like index out of range. – Edward Olamisan May 31 '13 at 03:26
  • @EdwardOlamisan think I'll leave that as a exercise for the reader ;-) – James Morris Jun 03 '13 at 09:35
  • 3
    @EdwardOlamisan, the string won't ever be empty however. – James Morris Jul 14 '13 at 23:27
  • 6
    @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';` – chux - Reinstate Monica Jul 02 '14 at 14:00
  • 2
    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. – abligh Mar 16 '15 at 22:38
  • @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') ...` – chux - Reinstate Monica Dec 06 '15 at 23:10
  • @chux It's much simpler than that to fix it just by testing if the string begins with 0. I just edited the same. – P.P Dec 31 '15 at 18:56
  • 3
    @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. – AnT stands with Russia Mar 29 '16 at 18:28
  • @AnT Thanks, good to know :) so this solution _maybe_ faster too! I dunno for sure since the implementation differs from compiler to compiler. – legends2k Mar 30 '16 at 06:21
25

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.

chux - Reinstate Monica
  • 143,097
  • 13
  • 135
  • 256
  • Thanks for the helpful answer. Can we use `strlen(buffer)` when buffer size is dynamically allocated using `malloc` ? – rrz0 Nov 10 '18 at 10:16
  • @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 – chux - Reinstate Monica Nov 10 '18 at 16:15
12

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';
}
Amitabha
  • 1,693
  • 2
  • 25
  • 42
  • 1
    Note it would be [safer](http://stackoverflow.com/a/1253079/795339) to use `strnlen` instead of `strlen`. – Mike Mertsock Jun 30 '13 at 01:37
  • 3
    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." – Étienne Nov 19 '13 at 23:12
  • 4
    @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. – M.M Oct 28 '15 at 20:55
  • 4
    This fails miserably for an empty string (`""`). Also `strlen()` returns `size_t` not `int`. – alk Jun 17 '17 at 09:55
  • 5
    this is unsafe for an empty string, it will write at index -1. Don't use this. – Jean-François Fabre Jun 14 '18 at 19:38
  • It will never be empty, as it is clearly stated in this answer that "every line has '\n'". So, if you write an empty line, it would be just `'\n'`, which is not empty. – 1313e Feb 17 '21 at 03:29
2

For single '\n' trimming,

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';
  }
}
BEPP
  • 875
  • 1
  • 12
  • 36
  • 1
    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'; }`. – melpomene Sep 17 '18 at 05:26
  • @melpomene thanks for the suggestion. Update the code. – BEPP Sep 18 '18 at 06:39
  • 1
    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`). – melpomene Sep 18 '18 at 06:47
  • @elpomene thanks. It makes sense. I updated the code. – BEPP Sep 18 '18 at 07:00
1

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.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278
sjsam
  • 21,411
  • 5
  • 55
  • 102
1

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;
}
Duck Ling
  • 1,577
  • 13
  • 20
1

The steps to remove the newline character in the perhaps most obvious way:

  1. Determine the length of the string inside NAME by using strlen(), header string.h. Note that strlen() does not count the terminating \0.
size_t sl = strlen(NAME);

  1. Look if the string begins with or only includes one \0 character (empty string). In this case sl would be 0 since strlen() as I said above doesn´t count the \0 and stops at the first occurrence of it:
if(sl == 0)
{
   // Skip the newline replacement process.
}

  1. Check if the last character of the proper string is a newline character '\n'. If this is the case, replace \n with a \0. Note that index counts start at 0 so we will need to do NAME[sl - 1]:
if(NAME[sl - 1] == '\n')
{
   NAME[sl - 1] = '\0';
}

Note if you only pressed Enter at the fgets() string request (the string content was only consisted of a newline character) the string in NAME will be an empty string thereafter.


  1. We can combine step 2. and 3. together in just one if-statement by using the logic operator &&:
if(sl > 0 && NAME[sl - 1] == '\n')
{
   NAME[sl - 1] = '\0';
}

  1. The finished code:
size_t sl = strlen(NAME);
if(sl > 0 && NAME[sl - 1] == '\n')
{
   NAME[sl - 1] = '\0';
}

If you rather like a function for use this technique by handling fgets output strings in general without retyping each and every time, here is fgets_newline_kill:

void fgets_newline_kill(char a[])
{
    size_t sl = strlen(a);

    if(sl > 0 && a[sl - 1] == '\n')
    {
       a[sl - 1] = '\0';
    }
}

In your provided example, it would be:

printf("Enter your Name: ");

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

Note that this method does not work if the input string has embedded \0s in it. If that would be the case strlen() would only return the amount of characters until the first \0. But this isn´t quite a common approach, since the most string-reading functions usually stop at the first \0 and take the string until that null character.

Aside from the question on its own. Try to avoid double negations that make your code unclearer: if (!(fgets(Name, sizeof Name, stdin) != NULL) {}. You can simply do if (fgets(Name, sizeof Name, stdin) == NULL) {}.

  • Not sure why you would want to do this. The point of removing newlines isn't to null-terminate strings; it is to remove newlines. Replacing a `\n` with a `\0` at the _end_ of a string is a way of "removing" the newline. But replacing `\n` characters within a string fundamentally changes the string. It is not uncommon to have strings with intentional multiple newline characters, and this would effectively chop off the ends of those strings. To _remove_ such newlines, array contents need to shift left to over-write the `\n`. – ad absurdum Mar 05 '20 at 19:23
  • @exnihilo How can someone input a string with multiple newlines inside by using `fgets()`? – RobertS supports Monica Cellio Mar 05 '20 at 19:26
  • Well, you might concatenate strings obtained by multiple calls to `fgets()`. But I don't understand your objection: you are the one proposing code to handle multiple newlines. – ad absurdum Mar 05 '20 at 19:29
  • @exnihilo You´re right, I`ll overthink the strategy. I´d just wanted to add a very harsh but possible way to get the desired result. – RobertS supports Monica Cellio Mar 05 '20 at 21:50
  • @exnihilo Edited my answer completely and followed the main approach by using `strlen` etc. Justification for not being an duplicate: 1. Explanation of the code by steps. 2. Provided as function and context-based solution. 3. Hint to avoid double negation expressions. – RobertS supports Monica Cellio Mar 06 '20 at 09:18
1

In general, rather than trimming data that you don't want, avoid writing it in the first place. If you don't want the newline in the buffer, don't use fgets. Instead, use getc or fgetc or scanf. Perhaps something like:

#include <stdio.h>
#include <stdlib.h>
int
main(void)
{
        char Name[256];
        char fmt[32];
        if( snprintf(fmt, sizeof fmt, "%%%zd[^\n]", sizeof Name - 1) >= (int)sizeof fmt ){
                fprintf(stderr, "Unable to write format\n");
                return EXIT_FAILURE;
        }
        if( scanf(fmt, Name) == 1 ) {
                printf("Name = %s\n", Name);
        }
        return 0;
}

Note that this particular approach will leave the newline unread, so you may want to use a format string like "%255[^\n]%*c" to discard it (eg, sprintf(fmt, "%%%zd[^\n]%%*c", sizeof Name - 1);), or perhaps follow the scanf with a getchar().

William Pursell
  • 204,365
  • 48
  • 270
  • 300
  • Do you realize that the above code snippet is vulnerable to buffer overruns? `sprintf` doesn't check the size of the buffer! – Sapphire_Brick Aug 20 '21 at 03:19
  • @Sapphire_Brick It really isn't. The length of the format string will be 7 + the number of digits in the base 10 representation of the length of name. If that length is greater than 24, you will have other issues. If you want to be safe and use `snprintf` you certainly could, but this will work for buffers that are significantly larger than a petabyte. – William Pursell Aug 20 '21 at 03:36
  • In order to overflow the buffer, you would need to be creating an automatic array that is about 8 yotta-bytes, since you won't overflow the buffer until `Name` is over 2^83 bytes in size. In practical terms, this is not a problem. But, yes, `snprintf` should always be preferred over `sprintf`. Code edited. – William Pursell Aug 20 '21 at 11:56
  • Is there any advantage of using `scanf` in this fashion rather than simply using a `getchar()` loop? – supercat Nov 24 '22 at 21:16
  • @supercat Absolutely not. IMO, `scanf` should never be used for anything, but it seems to be a popular choice and is regularly abused. – William Pursell Nov 25 '22 at 16:06
0

To expand on the answers by @Jerry Coffin and @Tim Čas:

The strchr version is by design much faster than the strcspn (and strlen versions are likely the fastest of all).

The internals of strcspn has to iterate through the "\n" string and if reasonably implemented, it only does that once and stores down the string length somewhere. Then while searching, it also has to use a nested for loop going through the "\n" string.

Ignoring things like word size that a library-quality implementation of these functions would take in account, naive implementations may look like this:

char* my_strchr (const char *s, int c)
{
  while(*s != '\0')
  {
    if(*s == c)
      return (char*)s;
    s++;
  }
  return NULL;
}

size_t my_strcspn (const char *s1, const char *s2)
{
  size_t s2_length = strlen(s2);
  size_t i;
  for(i=0; s1[i] != '\0'; i++)
  {
    for(size_t j=0; j<s2_length; j++)
    {
      if(s1[i] == s2[j])
      {
        return i;
      }
    }
  }
  return i;
}
  • In case of strchr, there are two branches per character. One searching for the null terminator and other comparing the current character with the one searched for.

  • In case of strcspn, it either has to pre-calculate s2 size as in my example, or alternatively iterate through it while looking for null as well as the search key. The latter is essentially just what strchr does, so the inner loop could have been replaced with strchr. No matter how we implement it, there will be a lot of extra branching.

    An attentive language lawyer might also spot the absence of restrict in the strcspn standard library definition. Meaning that the compiler is not allowed to assume that s1 and s2 are different strings. This blocks some optimizations too.

The strlen version will be faster than both, since strlenonly needs to check for null termination and nothing else. Though as mentioned in the answer by @chux - Reinstate Monica, there are some situations where it won't work, so it is slightly more brittle than the other versions.

The root of the problem is the bad API of the fgets function - if it had been implemented better back in the days, it would have returned a size corresponding to the number of characters actually read, which would have been great. Or alternatively a pointer to the last character read like strchr. Instead the standard lib wasted the return value by returning a pointer to the first character in the string passed, which is mildly useful.

Lundin
  • 195,001
  • 40
  • 254
  • 396
  • Imagine if we had a function like `char* result = fgetsane(s,n,stdin); if(result != NULL) { size_t size = result - s; if(*result == '\n') *result = '\0'; }`. Swoosh, both trailing `\n` fixed and the actual size read obtained, just like that. If only the old Unix folks had only spent like 5 minutes longer considering the API of the function... – Lundin Mar 13 '23 at 10:49
-1

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;
}
Philippe A.
  • 2,885
  • 2
  • 28
  • 37
  • 2
    "because you know they contain a single newline at the end." --> It even works when there is no `'\n'` (or if the string is `""`). – chux - Reinstate Monica Nov 18 '15 at 17:59
  • In response to your first comment chux, my answer preserves that. I had to throw resetlen in `strrcspn` for when there is no `\n`. – Philippe A. Nov 18 '15 at 18:14
  • Why use `goto end;` instead of `return len;` ? – chqrlie Aug 17 '16 at 14:48
  • @chqrlie I needed to get out of this inelegant 2-level loop I got into. The harm was done. Why not a goto? – Philippe A. Nov 29 '16 at 20:48
  • You have two kinds of `goto`s 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; }` – chqrlie Nov 29 '16 at 23:04
  • 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. – Philippe A. Nov 30 '16 at 20:16
-2

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

fnisi
  • 1,181
  • 1
  • 14
  • 24
  • 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. – chqrlie Aug 17 '16 at 14:43
  • 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` – fnisi Oct 21 '16 at 08:30
  • 3
    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. – melpomene Sep 17 '18 at 05:29
  • 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. – Jonathan Leffler Oct 14 '18 at 07:53
-2
 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

  • 3
    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++ )` – chux - Reinstate Monica Dec 06 '17 at 22:03
  • @chux More like `for (size_t i = 0; Name[i]; i++) { if (Name[i] == '\n') { Name[i] = '\0'; break; } }` – melpomene Sep 17 '18 at 05:24
  • @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. – chux - Reinstate Monica Sep 17 '18 at 05:33
  • @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++ )` – chux - Reinstate Monica Sep 17 '18 at 05:36
-2

This is my solution. Very simple.

// Delete new line
// char preDelete[256]  include "\n" as newline after fgets

char deletedWords[256];
int iLeng = strlen(preDelete);
int iFinal = 0;
for (int i = 0; i < iLeng; i++) {
    if (preDelete[i] == '\n') {

    }
    else {
        deletedWords[iFinal]  = preDelete[i];
        iFinal++;
    }
    if (i == iLeng -1 ) {
        deletedWords[iFinal] = '\0';
    }
}