11

Just getting into C++. I'm getting constantly thrown off track when I see the symbol for multiply (*) being used to denote the dereferencing of a variable

for example: unsigned char * pixels = vidgrabber.getPixels();

Does this throw other people off? What's the tip for getting my head around this?

Thank you.


p.s. I have another reasonably simple question, that didn't get answered :( here: beginner question: add/subtract to value rather than just be that value pretty please! and thanks for your time!

Community
  • 1
  • 1
Arif Driessen
  • 587
  • 2
  • 6
  • 8
  • 3
    Your example isn't dereferencing - it's just part of the type of the variable `pixels`. But I know what you mean. – Cascabel Aug 18 '10 at 18:15
  • 3
    You asked *What's the tip for getting my head around this?* (meaning: C pointer notation here) - I'd say: **by getting used to it**. How do people get their heads around producing biological weapons in a modern laboratory? Same thing. – rubber boots Aug 18 '10 at 18:16
  • Adopting a consistent style is key. For example, never use spaces on both sides of the `*` unless you're using it as a multiplication operator. Instead of `char * pixels`, choose `char* pixels` or `char *pixels`. – user229044 Aug 18 '10 at 18:21
  • I find it interesting that C pointer notation is compared to the production of biological weapons. But yes, what everybody else here said is correct. Spending time with the language will make you more comfortable with its syntax. – Eric Finn Aug 18 '10 at 18:22
  • @Eric, thats not really a comparision (but might be look like one) - its rather a opinion on a class of crazy things that people do every day because they think they have no choice. Thats called "alienation" in philosophical terms. (BTW. I'm a C programmer (later C++) since about 20 years) – rubber boots Aug 18 '10 at 18:57
  • I've been so warped by C that I get confused when I see * being used for multiplication :) – Arnold Spence Aug 18 '10 at 19:29

7 Answers7

24

C, and by inheritance C++, are swamped with operators and are inherently context-sensitive. You will have to get used to it:

If * appears before the name of a variable that is being declared (or defined), it's a type modifier and makes that variable a pointer.
If it is a unary prefix operator for a variable that is part of an expression, it's dereferencing (or whatever it's been overloaded to).
If it is a binary infix operator for two variables that are part of an expression, it's multiplication (or whatever it's been overloaded to).

(From this you can see that the * in your unsigned char * pixel isn't a dereferencing unary prefix, but a type modifier.)

Note that & pretty much resembles *, only it's meaning is different: it makes a variable a reference, is the address-of operator, or the binary AND.

sbi
  • 219,715
  • 46
  • 258
  • 445
  • 2
    +1 for a good answer to the generalization of this question as well as this question itself. I particularly like 'context-sensitive' – Cam Aug 18 '10 at 18:17
  • +1 for explaining in detail the different usages of *. How about explaining more on difference between & and *? – Sulla Aug 18 '10 at 18:34
  • 1
    @Arun: I'm not sure what you're expecting. – sbi Aug 18 '10 at 18:55
8

One recommendation when writing your own code is to "cuddle" the * when using as a pointer/deref:

unsigned char *pixels = ...

if (*pixels == ...)

and to space the * when using as a multiply:

int y = x * 7;

There are other clues you can use (such as the fact that pointer deref is a unary operator while multiple is a binary operator).

R Samuel Klatchko
  • 74,869
  • 16
  • 134
  • 187
2

The answer is: practice. Every new programming language will look funny to some extent, some funnier than others. Learn to use it and it will become natural.

David Thornley
  • 56,304
  • 9
  • 91
  • 158
1

You can distinguish the dereference operator from the multiplication operaotr by the fact that, usually, a multiplicator operator doesn't have a type name on his left.

Federico klez Culloca
  • 26,308
  • 17
  • 56
  • 95
1

Contrived Example

You wrote about dereferencing in C. Can you tell the result from just looking at it? ==>

int v[] = {5,6}, w[] = {7,8};
int m[][2] = { {1,2}, {3,4} };

int result = * v * * * m * * w;

Regards

rbo

rubber boots
  • 14,924
  • 5
  • 33
  • 44
  • 3
    The meaning of `* v * * * m * * w` is that the cat's been up on the keyboard again. (It does that a lot when it's fighting for attention.) – sbi Aug 18 '10 at 18:33
  • 1
    Great answer! A beginner who's new to pointers will surely benefit from this. – Cam Aug 18 '10 at 18:40
  • 1
    Off the top of my head I think "* * m" is going to produce something wonky.. *m is 1, but **m the contents of memory address 0x00000001 which could be anything on some platforms. Anyway, whatever that is, the result will be that times 35. – Sparr Aug 18 '10 at 18:51
  • 1
    There can always be only one multiplicator after a variable, all others are dereferences. So just follow the advice to keep dereferences close (= no space) to the variable, so it changes to `int result = *v * **m * *w` and solution is quite simple. – IanH Aug 18 '10 at 19:01
  • @Sparr: I thought, damn you're right (and thus my answer wrong), but disassembly proves you wrong. – IanH Aug 18 '10 at 19:14
  • Why is `*m` 1? `m` is an array of arrays, so `*m` is {1, 2}, and `**m` is 1. The result is 35. – jv110 Aug 21 '17 at 18:16
1

The same way English speakers get around the fact that the same word can have different meanings depending on the context. Once you are somewhat immersed in the context, it will usually be obvious what the operator is doing.

JohnMcG
  • 8,709
  • 6
  • 42
  • 49
1

An important thing to note about C compared with other languages is that in when multiple declarations are combined in one statement, the asterisk applies to individual items, not the set as a whole. For example:

int* foo,bar;

creates an int-pointer called foo, and an int called bar. I always peg the asterisk to the variable, and I avoid mixing pointers and non-pointers in one statement thus:

int *foo;
int *ptr1,*ptr2,*ptr3;
int bar,boz,baz;

It's also important to note that storage-class qualifiers like 'const' and 'volatile' may not always bind as one would expect. The statement

volatile int *foo;
does not mean that 'foo' is a volatile, but rather that what 'foo' points to is a volatile. If foo itself is the 'volatile' thing, one must write "int * volatile foo;"
supercat
  • 77,689
  • 9
  • 166
  • 211