[comp.lang.c] Strange C Problem

bvickers@bonnie.ics.uci.edu (Brett J. Vickers) (05/10/89)

I've come across a very strange problem in one of my programs.  I'll
list the function that's causing the problems and then discuss what
those problems are.

Globals:  struct msg_node *first_msg, *last_msg;

void output_msgs()
{
  struct msg_node {
    char string[160];
    struct msg_node *next;
    struct msg_node *prev;
  } *current, *temp;

  current = first_msg;
  while (current != NULL) {
    printf("%s\n",current->string);
    printf("&");
    temp = current;
    current = current -> next;
    free (temp);
  }
  first_msg = NULL;
  last_msg  = NULL;
}

Now, this function is supposed to output all the messages that are on
the linked list from first to last.  But something strange happens.
After the function has output its last message, it fails to continue
on to the next line (printf("&")).  The ampersand isn't output until
the next call to output_msgs().  


Why is this happening?   All help appreciated.

--
 /*******************************************************************/
 /*  "Eritis sicut Deus, scientes  *  bvickers@bonnie.ics.uci.edu   */
 /*   bonum et malum"              *  ---------------------------   */
 /*******************************************************************/

tjc@mbunix.mitre.org (Tom J. Colley) (05/10/89)

In article <13812@paris.ics.uci.edu> bvickers@bonnie.ics.uci.edu (Brett J. Vickers) writes:
>...on to the next line (printf("&")).  The ampersand isn't output until
>the next call to output_msgs().  
>
On many systems, a output to a terminal is buffered until a newline is sent,
(or something to that effect).  I once wrote a program that displayed an 'X'
every 1000 iterations so I could see its progress (50,000 iterations).
The darn thing would run but wouldn't display any of the 'X' until the 
process completed.  If this is on a UNIX system, you might try a 'fflush'
on standard output, or something similar to this on a different system. 
Hope this helps!

Tom  (tjc@mbunix.mitre.org>

heather@maui.cs.ucla.edu (Heather Burris) (05/10/89)

In article <13812@paris.ics.uci.edu> bvickers@bonnie.ics.uci.edu (Brett J. Vickers) writes:
><stuff deleted>
>
>void output_msgs()
>{
>  <stuff>
>  while (current != NULL) {
>    printf("%s\n",current->string);
>    printf("&");
>    <other stuff>
>  }
>  <other stuff>
>}
>
>After the function has output its last message, it fails to continue
>on to the next line (printf("&")).  The ampersand isn't output until
>the next call to output_msgs().  
>Why is this happening?   All help appreciated.

The printf() function prints to stdout and the characteristics
of the what's get printed depends on the what stdout points to. Assuming
that the following program was run on UNIX and that stdout was directed
to the terminal screen, the output will be line-buffered by default; 
nothing will print out until a newline occurs in the output (some 
implementations also flush output if a read from stdin is done).  If 
stdout is redirected to a file, the output will be block buffered.
The manual page setbuf() explains the normal conventions.

If you want the output to print out even though you are not printing
a newline, use fflush(stdout).

Non-UNIX may or may not emulate the UNIX behavior (they may not be
able to if they are unable to determine whether stdout points to
a file or the terminal).

Heather Burris, UCLA

gorpong@telxon.UUCP (Gordon C. Galligher) (05/11/89)

In article <13812@paris.ics.uci.edu>, bvickers@bonnie.ics.uci.edu 
	(Brett J. Vickers) writes:
> 
[..much of example deleted..]
>   while (current != NULL) {
>     printf("%s\n",current->string);
>     printf("&");
[..rest of example deleted..]
> 
> ...strange happens.
> After the function has output its last message, it fails to continue
> on to the next line (printf("&")).  The ampersand isn't output until
> the next call to output_msgs().  

The subroutine printf() normally does its output to standard output, which on
most systems is considered a line-buffered output device.  This causes all
of the output sent to stdout to wait until it either gets a carriage return,
or if there is a request for input (the output is flushed before it waits for
input).  You can force the printing of the trailing ampersand in a few different
ways:

	1).  Change the printf from printf("&") to printf("&\n");  
		(Note this will cause an extra line feed each iteration through
		the while loop, if you do not want this, then use 2 or 3).

*	2).  Include fflush(stdout); either (i) directly after the printf() 
		(which causes it to be a wasted when more are pending) or
		(ii) put the fflush(stdout) after the WHILE loop exits and 
		before output_msg() returns.)
		(fflush(FILE *stream) is a subroutine call which flushes the
		buffer pointed at by 'stream'.  It will not cause a trailing
		new line, but will simply force the system to print out
		what is currently pending in the buffer.)

	3).  Include a putchar('\n'); after the while loop, which will put
		an extra newline after your '&' and before your next call to
		output_msg().

I would choose number '2' above because it doesn't cause any extra newlines
or carriage returns to show up in your output, but it does cause the trailing
'&' to be printed and then it will wait with it printed until you print out
any more stuff.  Because of the line-buffered nature of stdout, you will see
that you have a trailing '\n' in your first printf() line, which causes the
entire buffer to be flushed automatically.

> --
>  /*******************************************************************/
>  /*  "Eritis sicut Deus, scientes  *  bvickers@bonnie.ics.uci.edu   */
>  /*   bonum et malum"              *  ---------------------------   */
>  /*******************************************************************/

I hope this helps.

		-- Gordon.

-- 
Gordon C. Galligher  <|> ...!uunet!telxon!gorpong <|> gorpong@teleng.uucp.uu.net
Telxon Corporation   <|> "Captain, I hardly believe that insults are within your
Akron, Ohio, 44313   <|> prerogative as my commanding officer" - Spock
(216) 867-3700 (3512)<|>   (City on the Edge of Forever (Starring Joan Collins))

ark@alice.UUCP (Andrew Koenig) (05/11/89)

In article <13812@paris.ics.uci.edu>, bvickers@bonnie.ics.uci.edu (Brett J. Vickers) writes:

>   current = first_msg;
>   while (current != NULL) {
>     printf("%s\n",current->string);
>     printf("&");
>     temp = current;
>     current = current -> next;
>     free (temp);
>   }
>   first_msg = NULL;
>   last_msg  = NULL;
> }

> Now, this function is supposed to output all the messages that are on
> the linked list from first to last.  But something strange happens.
> After the function has output its last message, it fails to continue
> on to the next line (printf("&")).  The ampersand isn't output until
> the next call to output_msgs().  

I wouldn't be surprised to find that your terminal output
is line-buffered.  Try this:

  current = first_msg;
  while (current != NULL) {
    printf("%s\n",current->string);
    printf("&");
    fflush(stdout);		/* insert this line */
    temp = current;
    current = current -> next;
    free (temp);
  }
  first_msg = NULL;
  last_msg  = NULL;
}

-- 
				--Andrew Koenig
				  ark@europa.att.com

kemnitz@mitisft.Convergent.COM (Gregory Kemnitz) (05/11/89)

In article <13812@paris.ics.uci.edu>, bvickers@bonnie.ics.uci.edu (Brett J. Vickers) writes:
. 
. I've come across a very strange problem in one of my programs.  I'll
. list the function that's causing the problems and then discuss what
. those problems are.
. 
. Globals:  struct msg_node *first_msg, *last_msg;
. 
. void output_msgs()
. {
.   struct msg_node {
.     char string[160];
.     struct msg_node *next;
.     struct msg_node *prev;
.   } *current, *temp;
. 
.   current = first_msg;
.   while (current != NULL) {
.     printf("%s\n",current->string);
.     printf("&");
.     temp = current;
.     current = current -> next;
.     free (temp);
.   }
.   first_msg = NULL;
.   last_msg  = NULL;
. }
. 
. Now, this function is supposed to output all the messages that are on
. the linked list from first to last.  But something strange happens.
. After the function has output its last message, it fails to continue
. on to the next line (printf("&")).  The ampersand isn't output until
                       ^^^^^^^^^^^
. the next call to output_msgs().  
. 
. 
. Why is this happening?   All help appreciated.
. 

No mystery here...

printf needs a newline to print its string.  the &'s are being buffered
by this routine until the printf with a newline is called.  A fix would
be to rework the printf's in the loop or to put a printf("\n") at the
end of the routine.  This routine may also have a bug in that
its first call will not have the ampersand before the string, but all
calls after it will.

Greg Kemnitz

jcbst3@cisunx.UUCP (James C. Benz) (05/11/89)

In article <13812@paris.ics.uci.edu> bvickers@bonnie.ics.uci.edu (Brett J. Vickers) writes:
>  current = first_msg;
>  while (current != NULL) {
>    printf("%s\n",current->string);
>    printf("&");
>    temp = current;
>    current = current -> next;
>    free (temp);
>  }
>  first_msg = NULL;
>  last_msg  = NULL;
>}
>After the function has output its last message, it fails to continue
>on to the next line (printf("&")).  The ampersand isn't output until
>the next call to output_msgs().  

In case nobody has answered this yet, (unlikely, but I'm gonna do it anyway)

First, your line that prints the string has a \n in it.  It is followed by 
a printf that prints a single (special!) character WITHOUT a newline.  The
way your loop is set up, this second printf executes after EACH string from
the linked list is output, not after the whole list.  Further, since no
newline is output following the printf("&") the output buffer is not flushed
(stdout is only flushed on receipt of a newline.  Stderr is flushed on each
character)  So when the last printf("&") is executed, it waits in the stdout
buffer until the next call to printf("%s\n",.....), which is only when you
call output_msg again.  Try putting a printf("\n") OUTSIDE the loop before
exiting the function.  Or look up fflush in the manual.

Newsgroups: comp.lang.c
Subject: Re: mutual reference in structures
Summary: 
Expires: 
References: <6712@medusa.cs.purdue.edu> <539@lakart.UUCP>
Sender: 
Reply-To: jcbst3@unix.cis.pittsburgh.edu (James C. Benz)
Followup-To: 
Distribution: 
Organization: Univ. of Pittsburgh, Comp & Info Sys
Keywords: 

 
-- 
Jim Benz 		     jcbst3@unix.cis.pittsburgh.edu     If a modem 
University of Pittsburgh					 answers,
UCIR			     (412) 648-5930			 hang up!