49

I'm struggling with the pointer sign *, I find it very confusing in how it's used in both declarations and expressions.

For example:

int *i; // i is a pointer to an int

But what is the logic behind the syntax? What does the * just before the i mean? Let's take the following example. Please correct me where I'm wrong:

char **s;
char *(*s); // added parentheses to highlight precedence

And this is where I lose track. The *s between the parantheses means: s is a pointer? But a pointer to what? And what does the * outside the parentheses mean: a pointer to what s is pointing?

So the meaning of this is: The pointer pointing to what s is pointing is a pointer to a char?

I'm at a loss. Is the * sign interpreted differently in declarations and expressions? If so, how is it interpreted differently? Where am I going wrong?

Jeffrey
  • 493
  • 1
  • 5
  • 4

10 Answers10

83

Take it this way:

int *i means the value to which i points is an integer.

char **p means that p is a pointer which is itself a pointer to a char.enter image description here

pradeepchhetri
  • 2,899
  • 6
  • 28
  • 50
79
int i; //i is an int.
int *i; //i is a pointer to an int
int **i;//i is a pointer to a pointer to an int.

Is the * sign interpreted differently in declarations and expressions?

Yes. They're completely different. in a declaration * is used to declare pointers. In an expression unary * is used to dereference a pointer (or as the binary multiplication operator)

Some examples:

int i = 10; //i is an int, it has allocated storage to store an int.
int *k; // k is an uninitialized pointer to an int. 
        //It does not store an int, but a pointer to one.
k = &i; // make k point to i. We take the address of i and store it in k
int j = *k; //here we dereference the k pointer to get at the int value it points
            //to. As it points to i, *k will get the value 10 and store it in j
nos
  • 223,662
  • 58
  • 417
  • 506
29

The rule of declaration in c is, you declare it the way you use it.

char *p means you need *p to get the char,

char **p means you need **p to get the char.

n611x007
  • 8,952
  • 8
  • 59
  • 102
burningice
  • 391
  • 2
  • 3
21

Declarations in C are expression-centric, meaning that the form of the declaration should match the form of the expression in executable code.

For example, suppose we have a pointer to an integer named p. We want to access the integer value pointed to by p, so we dereference the pointer, like so:

x = *p; 

The type of the expression *p is int; therefore, the declaration of p takes the form

int *p;

In this declaration, int is the type specifier, and *p is the declarator. The declarator introduces the name of the object being declared (p), along with additional type information not provided by the type specifier. In this case, the additional type information is that p is a pointer type. The declaration can be read as either "p is of type pointer to int" or "p is a pointer to type int". I prefer to use the second form, others prefer the first.

It's an accident of C and C++ syntax that you can write that declaration as either int *p; or int* p;. In both cases, it's parsed as int (*p); -- in other words, the * is always associated with the variable name, not the type specifier.

Now suppose we have an array of pointers to int, and we want to access the value pointed to by the i'th element of the array. We subscript into the array and dereference the result, like so:

x = *ap[i]; // parsed as *(ap[i]), since subscript has higher precedence
            // than dereference.

Again, the type of the expression *ap[i] is int, so the declaration of ap is

int *ap[N];

where the declarator *ap[N] signifies that ap is an array of pointers to int.

And just to drive the point home, now suppose we have a pointer to a pointer to int and want to access that value. Again, we deference the pointer, then we dereference that result to get at the integer value:

x = **pp; // *pp deferences pp, then **pp dereferences the result of *pp

Since the type of the expression **pp is int, the declaration is

int **pp;

The declarator **pp indicates that pp is a pointer to another pointer to an int.

Double indirection shows up a lot, typically when you want to modify a pointer value you're passing to a function, such as:

void openAndInit(FILE **p)
{
  *p = fopen("AFile.txt", "r");
  // do other stuff
}

int main(void)
{
  FILE *f = NULL;
  ...
  openAndInit(&f);
  ...
}

In this case, we want the function to update the value of f; in order to do that, we must pass a pointer to f. Since f is already a pointer type (FILE *), that means we are passing a pointer to a FILE *, hence the declaration of p as FILE **p. Remember that the expression *p in openAndInit refers to the same object that the expression f in main does.

In both declarations and expressions, both [] and () have higher precedence than unary *. For example, *ap[i] is interpreted as *(ap[i]); the expression ap[i] is a pointer type, and the * dereferences that pointer. Thus ap is an array of pointers. If you want to declare a pointer to an array, you must explicitly group the * with the array name, like so:

int (*pa)[N]; // pa is a pointer to an N-element array of int

and when you want to access a value in the array, you must deference pa before applying the subscript:

x = (*pa)[i];

Similarly with functions:

int *f(); // f is a function that returns a pointer to int
...
x = *f(); // we must dereference the result of f() to get the int value

int (*f)(); // f is a pointer to a function that returns an int
...
x = (*f)(); // we must dereference f and execute the result to get the int value
John Bode
  • 119,563
  • 19
  • 122
  • 198
14

My favorite method to parse complicated declarators is the clockwise-spiral rule.

Basically you start from the identifier and follow a clockwise spiral. See the link to learn exactly how it's used.

Two things the article doesn't mention:

1- You should separate the type specifier (int, char, etc.) from the declarator, parse the declarator and then add the type specifier.

2- If you encounter square brackets which denote an array, make sure you read the following square brackets (if there are any) as well.

tiftik
  • 978
  • 5
  • 10
6

int * i means i is a pointer to int (read backwards, read * as pointer). char **p and char *(*p) both mean a pointer to a pointer to char.

Here's some other examples

int* a[3] // a is an array of 3 pointers to int

int (*a)[3] //a is a pointer to an array of 3 ints

Armen Tsirunyan
  • 130,161
  • 59
  • 324
  • 434
3

You have the answer in your questions.

Indeed a double star is used to indicate pointer to pointer.

Shamim Hafiz - MSFT
  • 21,454
  • 43
  • 116
  • 176
3

The * in declaration means that the variable is a pointer to some other variable / constant. meaning it can hold the address of variable of the type. for example: char *c; means that c can hold the address to some char, while int *b means b can hold the address of some int, the type of the reference is important, since in pointers arithmetic, pointer + 1 is actually pointer + (1 * sizeof(*pointer)).

The * in expression means "the value stored in the address" so if c is a pointer to some char, then *c is the specific char.

char *(*s); meaning that s is a pointer to a pointer to char, so s doesn't hold the address of a char, but the address of variable that hold the address of a char.

MByD
  • 135,866
  • 28
  • 264
  • 277
1

here is a bit of information

         variable    pointer
declaring     &a           p

reading/      a            *p

processing
Akshatha
  • 599
  • 2
  • 10
  • 26
-2

Declaring &a means it points to *i. After all it is a pointer to *int. An integer is to point *i. But if consider j = *k is the pointer to the pointer this, means &k will be the value of k and k will have pointer to *int.

H. Pauwelyn
  • 13,575
  • 26
  • 81
  • 144