3

I seem to understand the program now, except the getline function is not very intuitive as it seems to copy everything getchar() returns to a character array s[] which is never really used for anything important.

int getline(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;
}

The function could just as easily ignore the line s[i] = c; because all the function is really doing is counting the number of characters until it reaches EOF or '\n' returns from getchar()

What I really do not understand is why the program progressed forward as the main loop is as follows:

main()
{
    int len; /* current line length */
    int max; /* maximum length seen so far */
    char line[MAXLINE]; /* current input line */
    char longest[MAXLINE]; /* longest line saved here */

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

The only explanation would be that the getchar() function does its magic after the user has entered in a full line of text, and hits the enter key. So it would appear to work during run-time is my guess.

Is this how the program progresses? Does the program first enter the while loop, and then wait for a user to enter a line of text, and once the user hits enter, the getline function's for-loop is iterated? I feel like this would be the case, since the user can enter backspace during input.

My question is, how exactly does the program move forward at all? Is it all because of the getchar() function?

When I hit ctrl-D in the terminal, some other confusing stuff happens. If I hit ctrl-D at the start of a newline, the program will terminate. If I hit ctrl-D at the end of a line filled with some text, it does not terminate and it does not act the same way as hitting enter. If I hit ctrl-D a few times in a line with text, the program will finally end.

Is this just the way my terminal is treating the session, or is this all stuff I should not be worrying about if I just want to learn C?

The reason why I ask is that I like to trace the program to get a good understanding of it, but the getchar() function makes that tricky.

melpomene
  • 84,125
  • 8
  • 85
  • 148
Leonardo
  • 1,452
  • 3
  • 15
  • 26

4 Answers4

3

getchar reads a character from standard input. So if that's you sitting at the terminal, it blocks the program until it receives a character you've typed, then it's done. But standard input is line buffered when its interactive, so what you type isn't processed by the program until you press enter. That means that getchar will be able to keep reading all the characters you typed, as they're read from the buffer.

You're mistaken about the function. The array is passed to the function*, and it stores each character read by getchar (except for EOF or newline) in successive elements. That's the point of it - not to count the characters, but to store them in the array.

(*a pointer is actually passed, but the function here can still treat it like an array.)

teppic
  • 8,039
  • 2
  • 24
  • 37
  • Thanks, I understand that now. But now I am confused about how the program ends. Why does pressing Ctrl-D not work the same as pressing enter? – Leonardo Mar 28 '13 at 23:58
  • 1
    It depends on what your system does with Ctrl-D. Sometimes you have to press it twice to send an EOF. – teppic Mar 29 '13 at 00:07
  • It's not strictly correct that the array is "passed to the function". What's actually passed (by value, as all C arguments are passed) is a pointer to the array's first element. – Keith Thompson Mar 29 '13 at 00:12
  • @KeithThompson - I was just keeping the explanation as simple as possible. Since the function treats it as if it were an array, I didn't see any need to bring in pointers. – teppic Mar 29 '13 at 00:13
  • @teppic: You can get away with that kind of assumption for a while, but eventually you're going to wonder how big `s[]` is, and why `sizeof s` gives you the size of a pointer. (I'm not suggesting that you don't understand this.) And strictly speaking, the function treats `s` like a pointer; the `[]` operator is defined in terms of pointer arithmetic. – Keith Thompson Mar 29 '13 at 00:20
  • @KeithThompson - I agree with that. I've clarified the answer a little. By treat I mean just in terms of syntax. – teppic Mar 29 '13 at 00:22
  • "It depends on what your system does with Ctrl-D. Sometimes you have to press it twice to send an EOF." -- It's quite well defined. ^D on a terminal ends the `read` without adding anything to the terminal's buffer (as opposed to enter, which terminates the read call after adding \n to the buffer). Thus, if you type ^D as the first key pressed on the terminal, or immediately after typing enter, or immediately after another ^D, `read` returns 0 because the terminal's buffer is empty. Almost all POSIX software interprets this as EOF. Some software may get confused by lines that don't end with \n – Jim Balter Apr 02 '13 at 04:49
  • @JimBalter - again it was only simplification. Though I probably should have said 'Once on a non-empty line won't generate EOF, but twice will'. – teppic Apr 02 '13 at 12:49
  • "again it was only simplification" ... and I spelled it out, carefully. Since nothing I wrote was incorrect, it didn't warrant a response. – Jim Balter Apr 06 '13 at 03:06
3

In a parameter declaration (and only in that context), char s[] really means char *s. The way the C standard describes this is that:

A declaration of a parameter as "array of type" shall be adjusted to "qualified pointer to type".

So s really is a pointer, of type char*, and when the function modifies s[i] it's modifying the ith element of line.

On the call:

getline(line, MAXLINE)

line is an array, but in most contexts an array expression is implicitly converted to a pointer to the array's first element.

These two rules almost seem to be part of a conspiracy to make it look like arrays and pointers are really the same thing in C. They most definitely are not. A pointer object contains the address of some object (or a null pointer that doesn't point to any object); an array object contains an ordered sequence of elements. But most manipulation of arrays in C is done via pointers to the array's elements, with pointer arithmetic used to advance from one element to the next.

Suggested reading (I say this a lot): section 6 of the comp.lang.c FAQ.

Keith Thompson
  • 254,901
  • 44
  • 429
  • 631
1

The array is used for something important: it is provided by the caller and returned modified with the new content. From a reasonable point of view, filling in the array is the purpose of calling the function.

wallyk
  • 56,922
  • 16
  • 83
  • 148
0

That array (an array reference) is actually a pointer, char s[] is the same as char *s. so it's building its result in that array, which is why it's copied later in main. there is rarely any "magic" in K&R.

wallyk
  • 56,922
  • 16
  • 83
  • 148
Peter Wooster
  • 6,009
  • 2
  • 27
  • 39
  • -1: arrays are not pointers, pointers are not arrays. I suggest you read section 6 of [comp.lang.c FAQ](http://c-faq.com/). – pmg Mar 28 '13 at 23:52
  • Okay now I understand what the getline function is really doing. But then does the `getchar()` function also cause the program the progress through the input as I suspected? I was just a little confused about how the program knows to start reading new things. But it would make sense the `getchar()` function progressively moves the program forward with any new input. I am a little confused about how the program terminates however. – Leonardo Mar 28 '13 at 23:55
  • @pmg read A7.3.1 of K&R, array reference, arrays aren't pointers but references to them are, and that array is an array reference. – Peter Wooster Mar 28 '13 at 23:55
  • I revoked the -1, but arrays are not pointers -- they get converted to pointers to their first element in many usages. – pmg Mar 29 '13 at 00:03
  • Arrays are not pointers, but in the context of a parameter declaration (and *only* in that context), `char s[]` really means `char *s`. – Keith Thompson Mar 29 '13 at 00:04
  • Thank you, array references, which this one is since it's a function parameter are pointers, at least in K&R. – Peter Wooster Mar 29 '13 at 00:05
  • @PeterWooster: It's not clear what you mean by "array references". There are two relevant rules: the compile-time adjustment of an array parameter to a pointer parameter, and the implicit conversion (in most contexts) of an array expression to a pointer to the array's first element. – Keith Thompson Mar 29 '13 at 00:11
  • @KeithThompson that's a term used but not defined in K&R in the section A7 on expressions. I take it to mean a reference to an array, not the array itself. – Peter Wooster Mar 29 '13 at 00:37
  • @PeterWooster: I don't have my K&R handy. Is that the 1st or second edition? (The ISO standard uses the phrase "an expression that has type ‘‘array of *type*’’", which strike me as being more precise.) – Keith Thompson Mar 29 '13 at 01:24
  • @KeithThompson that phrase is also used. The term "array reference" is only used in A7.3.1 when discussing "postfix expressions". The version of K&R is the Second Edition 1988. – Peter Wooster Mar 29 '13 at 02:33