Reputation: 13072
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.
Upvotes: 368
Views: 595286
Reputation: 3314
If you are using glib (note: not the same as glibc), g_strstrip
does this concisely:
g_strstrip (Name);
That's it, the string is mutated in-place.
Upvotes: 0
Reputation: 154601
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';
}
// `len` now represents the length of the string, shortened or not.
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:
strtok(buffer, "\n");
fails to remove the '\n'
when buffer
is "\n"
. From this answer - amended after this answer to warn of this limitation.
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';
}
sprintf(buffer,"%s",buffer);
is undefined behavior: Ref. Further, it does not save any leading, separating or trailing whitespace. Now deleted.
[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.
Upvotes: 29
Reputation: 21975
If using POSIX 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.
Upvotes: 1
Reputation: 215360
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 strlen
only 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.
Upvotes: 0
Reputation: 7
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';
}
}
Upvotes: -2
Reputation: 212684
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()
.
Upvotes: 1
Reputation: 490808
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.
Upvotes: 243
Reputation: 15082
The steps to remove the newline character in the perhaps most obvious way:
NAME
by using strlen()
, header string.h
. Note that strlen()
does not count the terminating \0
.size_t sl = strlen(NAME);
\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.
}
'\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.
if
-statement by using the logic operator &&
:if(sl > 0 && NAME[sl - 1] == '\n')
{
NAME[sl - 1] = '\0';
}
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 \0
s 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) {}
.
Upvotes: 1
Reputation: 955
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';
}
}
Upvotes: 2
Reputation: 2180
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;
}
Upvotes: 1
Reputation: 33
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
Upvotes: -2
Reputation: 2955
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;
}
Upvotes: -1
Reputation: 1233
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
Upvotes: -2
Reputation: 4955
size_t ln = strlen(name) - 1;
if (*name && name[ln] == '\n')
name[ln] = '\0';
Upvotes: 88
Reputation: 10867
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'
.
Upvotes: 652
Reputation: 1733
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';
}
Upvotes: 12