Skip to content Skip to main navigation Skip to footer

C Pointers

c pointers

Pointers are one of the most important concepts in C programming, and one of the most difficult to understand.

What is a Pointer?

What is a pointer? First of all, it is a value that represents a memory address, so a pointer is equivalent to a roadmap to a certain memory address.

A character * represents a pointer, usually followed by the type keyword, indicating the type of the value to which the pointer points. For example, char* represents a pointer to a character, and float* represents a pointer to a value of type float.

int* intPtr;

The above example declares a variable intPtr, which is a pointer to a memory address that stores an integer.

The asterisk * can be placed anywhere between the variable name and the type keyword, and the following writing style is valid.

int* intPtr;

int * intPtr;

int *intPtr;

In this article, we will use an asterisk after the type keyword (i.e., int* intPtr;) because this reflects the fact that a pointer variable is a normal variable, except that its value is a memory address.

One thing to note about this style of writing is that if two pointer variables are declared in the same line, they need to be written as follows.

int * foo, * bar; // Correct

int* foo, bar; // incorrect

In the above example, the second line is executed with the result that foo is an integer pointer variable and bar is an integer variable, meaning that * is only valid for the first variable.

The pointer that is pointed to may still be a pointer, which will be indicated by two asterisks **.

int** foo;

The above example shows that the variable foo is a pointer, the first pointer pointing to a pointer, and the second pointer pointing to an integer.

* Operator

In addition to representing a pointer, the pointer operator can also be used as an operator to get the value within the memory address pointed to by the pointer variable.

void increment(int* p) {
  *p = *p + 1;
}

In the above example, the argument to the increment() function is an integer pointer p. Inside the function body, *p is the value pointed to by the pointer p. Assigning a value to *p means changing the value inside the address pointed to by the pointer.

 The above function adds 1 to the value of the argument. the function does not return a value because the function is passed in the address of a variable, and the operation on the value contained in the address of the variable inside the function body affects the value outside the function, so there is no need to return a value. In fact, in C, it is common practice to pass the value inside the function to the outside via a pointer.

Another advantage of passing variable addresses into a function is that for variables that require a lot of storage space, passing variable values into the function would be a huge waste of time and space, so passing a pointer would be more efficient.

& Operator

The & operator is used to get the memory address where the variable is located.

#include <stdio.h>

int main()
{
    int x=1;
    printf("The memory address of variable x is:%p\n",&x);
}

Output:

The memory address of variable x is:0x7fff938af444

In the above example, x is an integer variable and &x is the memory address where the value of the variable x is located. %p of printf() is a placeholder for the memory address and prints out the memory address.

A function that adds 1 to an argument variable can be used like the following:

#include <stdio.h>

void increment(int* p)

{
    *p = *p+1;
}

int main()
{

    int x=1;
    increment(&x);
    printf("x value is:%d\n",x);

}

Output:

x value is:2

In the above example, the value of the variable x is increased by 1 after calling the increment() function, and the reason is that the address &x of the variable x is passed into the function.

The & operator and the * operator are inverse operators, and the following expressions are always valid.

int i = 5;
if (i == *(&i)) // correct

Initializing Pointer Variable

After declaring a pointer variable, the compiler allocates a memory space for the pointer variable itself, but the value inside this memory space is random, that is, the value pointed to by the pointer variable is random. At this point, you cannot read or write to the address pointed to by the pointer variable because the address is a random address, which is likely to lead to serious consequences.

int* p;
*p = 1; // error

The above code is wrong because the address pointed by p is random and writing 1 to this random address will lead to unexpected results.

The correct procedure is that after a pointer variable is declared, it must be pointed to an allocated address before it can be read or written, which is called initialization of a pointer variable.

int* p;
int i;
p = &i;
*p = 13;

In the above example, p is a pointer variable. After declaring this variable, p will point to a random memory address. At this point it should be pointing to an already allocated memory address. The above example is declaring an integer variable i. The compiler will allocate the memory address for i and then have p point to i's memory address (p = &i;). Once initialization is complete, you can assign a value to the memory address pointed to by p (*p = 13;).

To prevent reading and writing uninitialized pointer variables, you can make it a habit to set uninitialized pointer variables to NULL.

int* p = NULL;

NULL is a constant in C that represents a memory space with an address of 0. This address is not available and reading or writing to it will report an error.

Pointer Arithmetic

A pointer is essentially an unsigned integer that represents a memory address. It can perform arithmetic, but its rules are not those of integer arithmetic.

Addition and subtraction of integer values to pointer

The operation of a pointer with an integer value represents the movement of a pointer.

short* j;
j = (short*)0x1234;
j = j + 1; // 0x1236

In the above example, variable j is a pointer to the memory address 0x1234. You may think that j+1 equals 0x1235, but the correct answer is 0x1236. The reason is that j+1 means that the pointer will point to the next integer location, which is 2 bytes next to the current location. The short type will occupy two bytes of width, so it will move 2 bytes to the next position. Likewise, j - 1 returns 0x1232.

The value that a pointer moves is related to the type of data it points to. The data type takes up as many bytes as it moves.

Pointer addition operations

Pointer can only add or subtract with integer values, addition of two pointers is not allowed.

unsigned short* j;
unsigned short* k;
x = j + k; // error

The above example is the addition of two pointers, which is not allowed.

Pointer subtraction operations

Pointers of the same type are allowed to perform subtraction operations, returning the difference between the addresses of the two pointers. The subtraction of two pointers gives the increment between the two pointers.

The value returned by subtraction is a ptrdiff_t type, which is a signed integer type alias whose exact type varies depending on the system. The prototype of this type is defined in the header file stddef.h.

#include <stdio.h>
#include <stddef.h>

int main()
{
    short* j1;
    short* j2;

    j1=(short*)0x1234;
    j2=(short*)0x1236;

    ptrdiff_t dist= j2-j1;

    printf("dist value is:%ld\n",dist);
}

Output:

dist value is:1

In the above example, j1 and j2 are two pointers to short types, and the variable dist is the address increment between them, the type is ptrdiff_t, and the value is 1, because the difference is exactly 2 bytes to store the value of the short type.

Pointer comparison operations

The comparison operation between pointers compares which of their respective memory addresses is larger and returns an integer 1 (true) or 0 (false).

Was This Article Helpful?

1
Related Articles
0 Comments

There are no comments yet

Leave a comment

Your email address will not be published.