tags:

views:

129

answers:

5

I thought that I was really starting to understand how pointers work, and then I came across this exercise. I was trying to recreate a chunk of code that I found in my 'Learn C' book and I got it done and it was working and I thought everything was great:

void PrintWords( char *line ) {

    bool inWord = false;

    while (*line != kByteZero) {

        if (! isspace(*line)) {

            if (inWord == false) {
                putchar('\n');
                inWord = true;

            }
            putchar(*line);
        } else {
            inWord = false; 
        }
        *line++;
    }
}

It is just a simple function that displays words of an array on separate lines. When I compared it to the code in the book, i saw one glaring difference. The final line in the book's code was 'line++' instead of '*line++'.

I thought that using 'line++' is the EXACT opposite of what we are trying to do here. I am trying to increment where the pointer points to as well as manipulate the files stored at that memory address. 'line++' seems VERY odd to me because I am not even sure what it is telling the code to do? Move from line[i] to line[i+1]?? That seems weird because then 'line' itself seems to just act as a pointer - and if that were the case why couldn't i replace every instance of *line with just 'line'?

+9  A: 

In this case, *line++ and line++ are exactly the same. The postfix ++ has higher precedence than the *. You could replace your code with:

*(line++)

Which is pretty easy to see is unnecessary. The program you show here does exactly what you say - it wants to increment the pointer to point at the next character, so it can then test it and print it or a newline. You want line to refer to the pointer, and *line to dereference the pointer and get whatever it's pointing to.

I just did a quick test with your code. I get a warning from gcc "value computed is not used" with the *.

Carl Norum
One tiny point of clarification: ++ has higher precedence than dereference * only when ++ is postfix. But that's the case here.
John at CashCommons
@John, that's true. I'll edit that to be clear.
Carl Norum
@John at CashCommons: Well, the very notion of "precedence" is only useful with unary operators when one is prefix and another is postfix. If both operators are prefix (or both are postfix) the notion of "precedence" is simply not applicable. It has no practical uses.
AndreyT
"Exactly the same" is misleading. The two expressions have different values. The *effects* are the same because this code ignores the values.
Andy Thomas-Cramer
@Andy, hence the "In this case" at the beginning of the sentence.... On my machine, *exactly* the same code is emitted by the compiler - that sounds like *exactly* the same to me.
Carl Norum
We're not explaining it to a compiler, but to someone who's learning the language.
Andy Thomas-Cramer
+2  A: 

line is a pointer.

line in this case will be some number like 0x80b34560.

*line will be something like 'c'.

So line contains the address of a memory location that contains (let's say) 'c'.

When you want line to point to the next location, you say line++, and it will be the next number (let's say 0x80b34561 which is a memory location containing 'd').

Your confusion here stems from the operator precedence at play in *line++. This is equivalent to *(line++) because ++ has higher precedence that *. So what you're doing is getting the value stored at the pointer and then throwing it away, which is useless.

Here's a diagram:

+-------------------------------+
|  var     |  address |  value  |
+-------------------------------+
| line     | 80b34560 |  'a'    |
| (line+1) | 80b34561 |  'b'    |
| line[2]  | 80b34562 |  ' '    |
| etc...   |          |         |
+-------------------------------+

Note that I've used two different notations for accessing the addresses there -- line+1 and line[2]. Your question "Move from line[i] to line[i+1]??" is correct, but rethink your conclusion.

bstpierre
+1  A: 

The expression line++ increments the pointer, which is what you're trying to do.

The expression *line++ increments the pointer, and returns the value of the character at the new address. However, you're not doing anything with the value.

The postfix operator ++ has higher precedence than the * operator.

Andy Thomas-Cramer
+2  A: 

line is a pointer. line++ will increment the pointer, i.e. shift it to the next character. As you correctly stated it yourself, it will move the pointer from line[i] to line[i + 1] (in therms of the original value of line passed to PrintWords function).

What "manipulate the files stored at that memory address" is supposed to mean is completely beyond me. What "files" are you talking about?

The meaning of your "replace every instance of *line with just 'line'" is also not clear to me. We use line when we want to work with the pointer line. We use *line when we want to work with the character pointer line is pointing to. This is as simple as that.

Finally, as a statement *line++ is exactly equivalent to line++. In both cases pointer line gets incremented. In the former case you are dereferencing the pointer as well, but since you are ignoring the result of that dereference, it makes no difference whatsoever.

AndreyT
+2  A: 

Move from line[i] to line[i+1]??

Yes, that's exactly what line++; means in the example.
See, a pointer is nothing but a variable whose value is used to indicate a position in memory. So say you have this in memory:

position | value 
    0    |   H
    1    |   e
    2    |   l
    3    |   l
    4    |   o

Now say we have line = 0;
Then *line will be H.
If we do line++;, line is now 1, which means *line is now e. If now we do (*line)++, then you are actually changing the values in memory, which will be:

position | value 
    0    |   H
    1    |   f
    2    |   l
    3    |   l
    4    |   o
filipe
Thank you, this does explain things a little better. Some days I feel like I have a grasp of pointers and other days not :)
Rob