Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

gfish

macrumors newbie
Original poster
Aug 27, 2009
8
0
I'm trying to learn C, or re-learn as the case may be. I've been stuck for a long time on something simple from Chapter 1 in the Kernighan and Ritchie C book. There is an example to read lines of text, then output the longest line entered.

The problem is that the Mac Terminal does not seem to send NULL or empty string when you don't type anything, and just hit return. So, the program will not stop until you hit control-C. I also tried the getline function from later in the book, but it doesn't solve the problem. Any help would be appreciated!

Here's the code:
Code:
#include <stdio.h>
#include <string.h>

#define MAXLINE 1000 /*maximum input line size*/

int getlineKR(char [], int);
int getline2KR(char [], int);
void copyKR(char [], char []);

/*
	print longest input line
	from Kernighan and Ritchie, 2nd edition, pg 29
	
	Changes made to allow for use of getline on pg 165
	   
	KR or 2KR added to function names
*/

int main (int argc, char * argv[]) {
	int len;		/* current line length */
	int max;		/* maximum line length */
	char line[MAXLINE];		/* current input line */
	char longest[MAXLINE];	/* longest line saved here */

	printf("Enter a line of text:\n");

	max = 0;
	while ((len = getlineKR(line, MAXLINE)) > 0)
	/* while ((len = getline2KR(line, MAXLINE)) > 0) */
		if (len > max) {
			max = len;
			copyKR(longest, line);
		}
	if (max > 0)	/* there was a line */
		printf("%s", longest);
		
    return 0;
}


/* getline: read a line from standard input into s, return length
   from Kernighan and Ritchie, 2nd edition, pg 29 */
int getlineKR(char s[], int lim)
{
  int c, i;
  for (i=0; i<lim-1 && (c=getchar())!=EOF && c!='\n'; ++i) 
    s[i] = c;
  
  if (c == '\n') {
    s[i] = c;
	++i;
  }
  s[i] = '\0';
  return i;
}


/* getline: read a line from standard input into s, return length
   from Kernighan and Ritchie, 2nd edition, pg 165 */
int getline2KR(char *line, int max) {
 if (fgets(line, max, stdin) == NULL)
    return 0;
  else
	return strlen(line);
}



/* copy: copy 'from' into 'to'; assume to is big enough
   from Kernighan and Ritchie, 2nd edition, pg 29 */
void copyKR(char to[], char from[])
{
	int i;
	
	i = 0;
	while ((to[i] = from[i]) != '\0')
		++i;
}
 
Your getlineKR() function will return a line of len 1, containing \n, when it gets an empty line. As a result, the test for a line len of 0 will never terminate. If I've read your code correctly in the quick glance I gave it.
 
Thank you! That seems to be exactly what's happening, and I changed the while loop test to this, and it worked:

Code:
while ((len = getlineKR(line, MAXLINE)) > 1)

I mostly copied the code from the book. Do you think this is an error in the book's example?
 
Thank you! That seems to be exactly what's happening, and I changed the while loop test to this, and it worked:

Code:
while ((len = getlineKR(line, MAXLINE)) > 1)

I mostly copied the code from the book. Do you think this is an error in the book's example?

I have no idea. I don't have the book. "Mostly copied" isn't "exactly copied". "Exactly copied" can contain typos unless you downloaded it from the website for the book. Authors make mistakes, both in books and in downloadable code examples. The problem might be in the while loop, or it might be in getlineKR(). Really, if you're looking for an exact explanation, it could be anything.

Look at the body of the getlineKR() function, and notice that it intentionally appends the \n to the string when \n is the incoming char. That suggests to me that the only thing that will return 0 length is EOF, which makes a certain amount of sense. Otherwise you'd never be able to read files or pipelines that contained multiple newlines (i.e. blank lines between paragraphs).

Like this.

And this.


The getline2KR() function calls fgets(), and I'm certain fgets() doesn't return 0 for an empty line. Its man page says "The newline, if any, is retained", so something is wrong if you're expecting the newline to be stripped. Either the code is wrong or your expectation is wrong.

The gets() function, however, DOES strip newlines, but it doesn't have an input buffer limit, either, which makes it dangerous whenever its input isn't constrained in some other way. Rhymes with "duffer groverflow".
 
Did you try inputting the EOF character (control-D) instead of just hitting enter with no text on the line? IIRC, a lot of the examples in the K&R book use EOF for terminating input.
 
I have no idea. I don't have the book. "Mostly copied" isn't "exactly copied". "Exactly copied" can contain typos unless you downloaded it from the website for the book. Authors make mistakes, both in books and in downloadable code examples. The problem might be in the while loop, or it might be in getlineKR(). Really, if you're looking for an exact explanation, it could be anything.

Look at the body of the getlineKR() function, and notice that it intentionally appends the \n to the string when \n is the incoming char. That suggests to me that the only thing that will return 0 length is EOF, which makes a certain amount of sense. Otherwise you'd never be able to read files or pipelines that contained multiple newlines (i.e. blank lines between paragraphs).

Like this.

And this.


The getline2KR() function calls fgets(), and I'm certain fgets() doesn't return 0 for an empty line. Its man page says "The newline, if any, is retained", so something is wrong if you're expecting the newline to be stripped. Either the code is wrong or your expectation is wrong.

The gets() function, however, DOES strip newlines, but it doesn't have an input buffer limit, either, which makes it dangerous whenever its input isn't constrained in some other way. Rhymes with "duffer groverflow".

Did you try inputting the EOF character (control-D) instead of just hitting enter with no text on the line? IIRC, a lot of the examples in the K&R book use EOF for terminating input.

That's it! My expectation was wrong; I was thinking "empty string", but I should have been thinking EOF. I see now that the newline is supposed to be there. Control-d worked with the original code. The KR book doesn't mention how to input the EOF from the keyboard. I'll have to read the bash man pages!

Thanks for the help!
 
That's it! My expectation was wrong; I was thinking "empty string", but I should have been thinking EOF. I see now that the newline is supposed to be there. Control-d worked with the original code. The KR book doesn't mention how to input the EOF from the keyboard. I'll have to read the bash man pages!

Thanks for the help!

I had the same confusion when I first read it. As far as I can tell, it never actually tells you how to input EOF, so I also had to look it up :)
 
I had the same confusion when I first read it. As far as I can tell, it never actually tells you how to input EOF, so I also had to look it up :)

I'm glad you replied to my question! I read the book, and I don't recall them mentioning how to enter EOF from the keyboard at all.
 
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.