What is the Terminal NULL or empty string? (Help with simple I/O)

Discussion in 'Mac Programming' started by gfish, Aug 27, 2009.

  1. gfish macrumors newbie

    Joined:
    Aug 27, 2009
    #1
    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;
    }
     
  2. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #2
    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.
     
  3. gfish thread starter macrumors newbie

    Joined:
    Aug 27, 2009
    #3
    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?
     
  4. chown33 macrumors 604

    Joined:
    Aug 9, 2009
    #4
    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".
     
  5. Cinder6 macrumors 6502

    Cinder6

    Joined:
    Jul 9, 2009
    #5
    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.
     
  6. gfish thread starter macrumors newbie

    Joined:
    Aug 27, 2009
    #6
    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!
     
  7. Cinder6 macrumors 6502

    Cinder6

    Joined:
    Jul 9, 2009
    #7
    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 :)
     
  8. gfish thread starter macrumors newbie

    Joined:
    Aug 27, 2009
    #8
    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.
     

Share This Page