From: wirzeniu@klaava.Helsinki.FI (Lars Wirzenius)
Newsgroups: comp.lang.c
Subject: Re: Dropping a n from a fprintf()
Summary: Remove the newline from the string before printing it out
Date: 11 Sep 92 11:33:14 GMT
Organization: University of Helsinki

cee1@ra.msstate.edu (Charles Evans) asks, basically, how to get rid of
the newline on lines read with fgets and output with printf.  Attempts
to use scanf didn't work.

Printf can't strip away characters, but you can do it yourself.  You
drew a wonderful picture of the string, which I'm using here to explain
some things:

   ---------------------------------------- 
   | c | h | i | c | k | e | n | \n | \0 |
   ----------------------------------------
     0   1   2   3   4   5   6   7    8 

The problem is the \n at character position 7.  This character, aka the
newline character, is used in C to mark the end of a line in a file.  It
is present also in the file: if you read the file one char at a time,
you will get a newline character at the end of each line.  When the
newline character is output, the result is as you noted.  Note that the
newline-ends-lines -convention is true from the C language point of
view, but how the file is stored on the disk (the actualy sequence of
bytes) may be quite different.  Fortunately, it is seldom a concern, at
least when using text files. 

In order to avoid this, you need to not output the newline character (am
I intelligent or what? :).  The usual way to do this is to remove the
newline character from the string manually.  This is often beneficiary
also if you want to process the string in other ways, for example if you
store all the strings in an array and look them up later.  Since the
newline character is not really part of the string that you want to
store (you want to store "chicken", not "chicken\n"), it is easiest to
remove the newline right after you have read in the line. 

To remove the newline, you need to store an end-of-string terminator
character (null character, '\0', or plain 0, but NOT the same as NULL)
in its position, to get the following situation:

   ---------------------------------------- 
   | c | h | i | c | k | e | n | \0 | \0 |
   ----------------------------------------
     0   1   2   3   4   5   6   7    8 

You notice that now the string ends in two terminator characters. 
That's quite OK, since anything after the first terminator character is
supposed to be completely ignored.  Similarly, if we put a terminator
character into position 3, the string is effectively terminated into
"chi".  (You might instead want to think of the string being cut in two,
and the resulting strings to be "chi" and "ken".)

One easy way to do this is with code similar to the following:

	size_t len;
	char line[BIGNUM];

	/*... read in a line with fgets and check errors ... */

	len = strlen(line);
	if (len > 0 && line[len-1] == '\n')
		line[len-1] = '\0';

You might be tempted to do just:

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

which is quite a bit shorter, but has the unfortunate drawback of not
working in all circumstances.  Consider what happens if the line happens
to be longer than the buffer, in which case fgets doesn't put a newline
as the last character (it won't, because not the whole line fits into
the buffer and it can't therefore read the whole line, and especially it
can't read the newline character).  Other possible problems are if the
line happens to contain a string terminator character as its first
character, which means that the line is effectively of length 0. 

If you do the above often, you might want to put the line-reading and
newline-zapping code into a separate function, along these lines:

	char *nonl_fgets(char *line, size_t max, FILE *f) {
		size_t len;

		if (fgets(line, max, f) == NULL)
			return NULL;
		
		len = strlen(line);
		if (len > 0 && line[len-1] == '\n')
			line[len-1] = '\0';

		return line;
	}

(Untested code, sorry.)

(BTW, I could probably have explained things in less detail, not to
mention shorter, but I got carried away.  If you feel like I'm talking
to you like to a child, please don't be offended.  If, however, I failed
to explain something well enough, you flame me in e-mail as much as you
want.)

--
Lars.Wirzenius@helsinki.fi
Xref: sparky comp.lang.c:13590 alt.folklore.computers:13891