Part 2: Advanced

Pointer Overview

Constants and Pointers *

See also constness.

Position of const Syntax Name Description
Before * const T* pointer to constant a pointer to a constant object
Before * T const* pointer to constant a pointer to a constant object
After * T* const constant pointer a constant pointer to an object
After * const T* const constant pointer to constant a constant pointer to a constant object

Constant Pointer

A constant pointer (or const pointer) is "a constant whose type is pointer" or "a constant of pointer type", which cannot be modified after initialization and points to a fixed memory address. We cannot modify the value of the pointer itself, but we can modify the content of the pointed-to object.

int x[] = { 1, 2, 3, 4 };
int* const p = x;

for (int i = 0; i < 4; i++)
{
    int v = *(p + i);
    *(p + i) = ++v;
    printf("%d\n", v);
    //p++; // Compile Error!
}

In the above example, pointer p always points to the first element of array x, equivalent to the array name x. Because the pointer itself is a constant, operations such as ++p and p++ are not allowed, and will lead to a compilation error.

Pointer to Constant

A pointer to constant is "a pointer that points to constant data (object)". The pointed-to object is treated as a constant (though the original object is not necessarily a constant). Assignment is not allowed through the pointer. Since the pointer itself is not a constant, it can point to other locations.

int x = 1, y = 2;

int const* p = &x;
//*p = 100; ! ! // Compile Error!

p = &y;
printf("%d\n", *p);

//*p = 100; ! ! // Compile Error!

It is recommended to place const in the front for better recognition.

Some special cases are:

(1) It is said that the following code won't compile with Visual C++, but can compile with GCC:

const int x = 1;
int* p = &x;

printf("%d\n", *p);

*p = 1234;
printf("%d\n", *p);

(2) It perfectly makes sense for const int* p to point to const int, but modification (of the pointed-to value) through the pointer is not allowed.

const int x = 1;
const int* p = &x;

printf("%d\n", *p);

*p = 1234; ! ! ! // Compile Error!

(3) Declaring "a constant pointer to constant" is rare, but understandable.

int x = 10;
const int* const p = &i;

p++; ! ! ! ! // Compile Error!
*p = 20; ! ! ! // Compile Error!

It's easy to differentiate between a constant pointer and a pointer to constant by investigating what const qualifies, that is, whether * is left to or right to const. See also constants and pointers.

Pointer to Pointer

The pointer itself is a variable of data in a memory region. It can be pointed to by other pointers.

int x = 10;
int* p = &x;
int** p2 = &p;

printf("p = %p, *p = %d\n", p, *p);
printf("p2 = %p, *p2 = %x\n", p2, *p2);
printf("x = %d, %d\n",*p, **p2);

will output:

p = 0xbfba3e5c, *p = 10
p2 = 0xbfba3e58, *p2 = bfba3e5c
x = 10, 10

We can see that p2 stores the address of pointer p; that's what makes "pointer to pointer".

Pointer to Array

By default, the name of an array is a constant pointer to this array's first element.

int x[] = { 1, 2, 3, 4 };
int* p = x;

for (int i = 0; i < 4; i++)
{
    printf("%d, %d, %d\n", x[i], *(x + i), *p++);
}

We can access array elements with *(x + 1), but cannot do x++ or x-- operations.

A "pointer to array" does not have the same type as the array name. The pointer to array views the entire array as an object, not an element within.

int x[] = { 1, 2, 3, 4 };

int* p = x;
int (*p2)[] = &x;          // pointer to array

for(int i = 0; i < 4; i++)
{
    printf("%d, %d\n", *p++, (*p2)[i]);
}

See Pointer to Array for details.

Array of Pointers

An array whose element type is pointer is an array of pointers.

int x[] = { 1, 2, 3, 4 };
int* ps[] = { x, x + 1, x + 2, x + 3 };

for (int i = 0; i < 4; i++)
{
    printf("%d\n", *(ps[i]));
}

In the above code, x by default is a pointer to the array's first element, so x + n is the pointer to the subsequent element.

The array of pointers is usually used to represent a jagged array (also called array of arrays; it is not a 2-dimensional array), the most commonly seen of which is an array of strings.

void test(const char** x, int len)

    for (int i = 0; i < len; i++)
    {
        printf("test: %d = %s\n", i, *(x + i));
    }
}

int main(int argc, char* argv[])
{
    char* a = "aaa";
    char* b = "bbb";
    char* ss[] = { a, b };

    for (int i = 0; i < 2; i++)
    {
        printf("%d = %s\n", i, ss[i]);
    }

    test(ss, 2);

    return EXIT_SUCCESS;
}

See Array of Pointers for details.

Pointer to Function

By default, a function's name is the constant pointer to this function. See also pointer to function.

void inc(int* x)
{
    *x += 1;
}

int main(void)
{
    void (*f)(int*) = inc;

    int i = 100;
    f(&i);
    printf("%d\n", i);

    return 0;
}

typedef can be used to declare a function pointer type that looks better.

typedef void (*inc_t)(int*);

int main(void)
{
    inc_t f = inc;
    ... ...
}

Obviously, the following code is easier to read and understand with typedef:

inc_t getFunc()
{
    return inc;
}

int main(void)
{
    inc_t inc = getFunc();
    ... ...
}

Note the difference between:

void test()
{
    printf("test");
}

typedef void(func_t)();
typedef void(*func_ptr_t)();

int main(int argc, char* argv[])
{
    func_t* f = test;
    func_ptr_t p = test;
    f();
    p();
    return EXIT_SUCCESS;
}

Pointer to an Array

Notice the difference between pointers in the following code:

int x[] = {1,2,3,4,5,6};

int *p1 = x;      // pointer to an integer
int (*p2)[] = &x; // pointer to an array