Learn C practically and Get Certified .

Popular Tutorials

Popular examples, reference materials, learn c interactively, c introduction.

  • Keywords & Identifier
  • Variables & Constants
  • C Data Types
  • C Input/Output
  • C Operators
  • C Introduction Examples

C Flow Control

  • C if...else
  • C while Loop
  • C break and continue
  • C switch...case
  • C Programming goto
  • Control Flow Examples

C Functions

  • C Programming Functions
  • C User-defined Functions
  • C Function Types
  • C Recursion
  • C Storage Class
  • C Function Examples
  • C Programming Arrays
  • C Multi-dimensional Arrays
  • C Arrays & Function
  • C Programming Pointers
  • C Pointers & Arrays
  • C Pointers And Functions
  • C Memory Allocation
  • Array & Pointer Examples

C Programming Strings

  • C Programming String
  • C String Functions
  • C String Examples

Structure And Union

  • C Structure
  • C Struct & Pointers
  • C Struct & Function
  • C struct Examples

C Programming Files

  • C Files Input/Output
  • C Files Examples

Additional Topics

  • C Enumeration
  • C Preprocessors
  • C Standard Library
  • C Programming Examples

Relationship Between Arrays and Pointers

C Pass Addresses and Pointers

C structs and Pointers

  • Access Array Elements Using Pointer

C Dynamic Memory Allocation

  • C Array and Pointer Examples

Pointers are powerful features of C and C++ programming. Before we learn pointers, let's learn about addresses in C programming.

  • Address in C

If you have a variable var in your program, &var will give you its address in the memory.

We have used address numerous times while using the scanf() function.

Here, the value entered by the user is stored in the address of var variable. Let's take a working example.

Note: You will probably get a different address when you run the above code.

Pointers (pointer variables) are special variables that are used to store addresses rather than values.

Pointer Syntax

Here is how we can declare pointers.

Here, we have declared a pointer p of int type.

You can also declare pointers in these ways.

Let's take another example of declaring pointers.

Here, we have declared a pointer p1 and a normal variable p2 .

  • Assigning addresses to Pointers

Let's take an example.

Here, 5 is assigned to the c variable. And, the address of c is assigned to the pc pointer.

Get Value of Thing Pointed by Pointers

To get the value of the thing pointed by the pointers, we use the * operator. For example:

Here, the address of c is assigned to the pc pointer. To get the value stored in that address, we used *pc .

Note: In the above example, pc is a pointer, not *pc . You cannot and should not do something like *pc = &c ;

By the way, * is called the dereference operator (when working with pointers). It operates on a pointer and gives the value stored in that pointer.

  • Changing Value Pointed by Pointers

We have assigned the address of c to the pc pointer.

Then, we changed the value of c to 1. Since pc and the address of c is the same, *pc gives us 1.

Let's take another example.

Then, we changed *pc to 1 using *pc = 1; . Since pc and the address of c is the same, c will be equal to 1.

Let's take one more example.

Initially, the address of c is assigned to the pc pointer using pc = &c; . Since c is 5, *pc gives us 5.

Then, the address of d is assigned to the pc pointer using pc = &d; . Since d is -15, *pc gives us -15.

  • Example: Working of Pointers

Let's take a working example.

Explanation of the program

A pointer variable and a normal variable is created.

Common mistakes when working with pointers

Suppose, you want pointer pc to point to the address of c . Then,

Here's an example of pointer syntax beginners often find confusing.

Why didn't we get an error when using int *p = &c; ?

It's because

is equivalent to

In both cases, we are creating a pointer p (not *p ) and assigning &c to it.

To avoid this confusion, we can use the statement like this:

Now you know what pointers are, you will learn how pointers are related to arrays in the next tutorial.

Table of Contents

  • What is a pointer?
  • Common Mistakes

Sorry about that.

Related Tutorials

C Functions

C structures, creating pointers.

You learned from the previous chapter, that we can get the memory address of a variable with the reference operator & :

In the example above, &myAge is also known as a pointer .

A pointer is a variable that stores the memory address of another variable as its value.

A pointer variable points to a data type (like int ) of the same type, and is created with the * operator.

The address of the variable you are working with is assigned to the pointer:

Example explained

Create a pointer variable with the name ptr , that points to an int variable ( myAge ). Note that the type of the pointer has to match the type of the variable you're working with ( int in our example).

Use the & operator to store the memory address of the myAge variable, and assign it to the pointer.

Now, ptr holds the value of myAge 's memory address.

Dereference

In the example above, we used the pointer variable to get the memory address of a variable (used together with the & reference operator).

You can also get the value of the variable the pointer points to, by using the * operator (the dereference operator):

Note that the * sign can be confusing here, as it does two different things in our code:

  • When used in declaration ( int* ptr ), it creates a pointer variable .
  • When not used in declaration, it act as a dereference operator .

Good To Know: There are two ways to declare pointer variables in C:

Notes on Pointers

Pointers are one of the things that make C stand out from other programming languages, like Python and Java .

They are important in C, because they allow us to manipulate the data in the computer's memory. This can reduce the code and improve the performance. If you are familiar with data structures like lists, trees and graphs, you should know that pointers are especially useful for implementing those. And sometimes you even have to use pointers, for example when working with files .

But be careful ; pointers must be handled with care, since it is possible to damage data stored in other memory addresses.

C Exercises

Test yourself with exercises.

Create a pointer variable called ptr , that points to the int variable myAge:

Start the Exercise

Get Certified

COLOR PICKER

colorpicker

Report Error

If you want to report an error, or if you want to make a suggestion, do not hesitate to send us an e-mail:

[email protected]

Top Tutorials

Top references, top examples, get certified.

DEV Community

DEV Community

Aniket Bhattacharyea

Posted on Sep 9, 2021

(Almost) Everything You Need To Know About Pointers in C

When I was first starting out with C, pointers were something that confused me the most. I was scared of pointers and could never understand how to use them.

No, I didn't say that! In fact, pointers have always been intuitive to me. But most of the students starting to learn C are put off by the idea of pointers. It is one of those areas of C which are not explained properly to students. resulting in many misconceptions about them.

In this huge post, I have compiled almost everything that is fundamental to pointers. Of course, it is a huge topic, and it's not possible to cover the entirety of it in one post, but once you know these fundamentals, you'll be able to use them more efficiently, and hopefully will be able to tackle pointers in a program.

Let's start.

Beginning With Pointer Sorcery

One fine afternoon, you are lying on your couch and thinking about the year 2038 problem and the end of the universe, and suddenly your friend calls you and asks "Hey, I want to come over and contemplate our existence, but I do not know where your house is!"

You say, "No problem buddy. I'll give you a copy of my home."

Of course, you'd never say that. Instead, you will give him your address so that he can come over. Now, you could make him a copy of your home if you're generous enough, but it takes time and defeats the purpose of your friend coming over. He wants to come to your house, not a copy.

Now think in terms of programming. At the time when C was created, memory was scarce, and being efficient was not only needed but vital. For this reason, you'd have to be really careful while dealing with memory. You'd really not like to make unnecessary copies of something.

Another case you can consider is of having "side effect" of a function. Consider this simple program.

which just prints

Even though you are calling the function f with the variable a as a parameter, and f is changing the value of a . the change doesn't show up in the original value of a , because when you are calling the function f , you are passing a copy of a , not a itself. In other terms, you are giving your friend a copy of your house.

This is desired in most cases. You don't really want your functions to accidentally change any variable where it's not supposed to. But sometimes, you actually want the function to change a variable. You have already seen such a function that can change the actual parameter.

How does scanf change the value of n ? The answer is through pointers.

Also, take a look at this classic example of swap-

It works, except it doesn't.

swap does swap the variables, but since you are making a copy of a , and b , the change doesn't show up outside the function. But we want the function to be able to change the actual variables. So we need to have some kind of way to pass the actual a and b . But in C, there is no way you can pass "actual" variables. (which is not the case in C++).

One way you might end up doing is to make a and b global

And it now works, because swap now can access a and b , but having global variables is a real bad idea .

The way? Give swap the addresses of a and b . If it has addresses of a and b , it can change them directly.

Pointers are nothing but variables that hold the address of another variable.

Now, where does this address come from? We know how bits and bytes work . The RAM of the computer can be thought of as a mess, a really long one, with lots of rooms one after another, and each byte is a room. How does the computer know which room to put data in? It gives a number to each room, and that number is the address.

When I write

I tell the compiler "Buddy, reserve one room in the mess, and call it a " . Why one room? Because the size of char is 1 byte. (Note that C's definition of a byte is basically the sizeof char , which in some rare cases might not be actually 1 byte in the machine, however, it is always 1 byte in C)

I tell the compiler to reserve the number of rooms necessary for int and call it b .

Side rant: People coming from Turbo C, and being told size of int is 2 bytes, it's not necessarily so, and probably not so in any modern computer. The C standard guarantees at least 2 bytes for int and on my machine sizeof(int) is 4, so we will stick to that for the rest of this post.

Now that our b has 4 rooms, it will stay in the rooms starting from the first one. So that when we say "address of b", we actually mean "address of the starting or ending byte of b". (See big endian and little endian . For this tutorial, let's assume it's the ending byte because it is so on my machine)

In order to get the address of b and store it, we need to use a pointer variable. Just like any other variable, a pointer also has a type, defined by the type of the thing it points to. The syntax is type_of_the_thing_it_points_to *name

Note that the asterisk need not be adjoined to the variable name. Any of these is valid -

We will prefer the 2nd syntax. We will see in a short while why.

Let's first see how to assign a value to a pointer. In order to make a pointer point to a variable, we have to store the address of the variable in the pointer. The syntax for getting the address of a variable is &variable_name .

If you run this program, you will see something like 0x7ffc2fc4ff27 . That is the value of the pointer, which is the address of the variable a (this is in hexadecimal). This value is not fixed. If you run the program again, the value will likely change, because a will be stored somewhere else.

One thing you might have noticed. Although we are declaring it as *pa , the * is not used when printing the pointer. In fact, * is not a part of the name of the pointer. The name of the pointer is just pa . The * is instead used to get the value of whatever thing the pointer is pointing to (known as dereferencing).

So, quickly revise -

  • pa is the value of the pointer, which is the address of a .
  • *pa is the value of the thing pa is pointing to, in this case a .

One more time.

  • pointer_name is the value of the pointer itself.
  • *pointer_name is the value of the thing the pointer points to.

Now, this should be clear.

Now we can rewrite the swap function as follows -

And call it with the addresses swap(&a, &b) . This works and the change shows up outside the function too. Because once you have the address of a variable, you know where it lives in memory so you can freely change it.

You might have a valid question. Since all pointers are just addresses, which are basically numbers, why is the type of the thing it points to necessary? Why do we distinguish between char* and int* although both of them are just some numbers?

The answer is clear. When you dereference a pointer, the compiler needs to know what data type is the object. Remember that address of a variable is just the address of the ending byte of the variable. In order to read the variable, the compiler needs to know its type so that it knows how many bytes to read.

Consider this program

It prints (ignore the compiler warning)

What happened here?

If you represent 1101214537 in binary it is 01000001 10100011 00110011 01001001 . So &a which is the address of a points to the byte in memory that contains the last byte of the number, which is 01001001 . When I dereference pa , the compiler sees that it points to char so it reads only one byte at that address, giving the value 01001001 which 73 , the ASCII for I . This is why the type is absolutely and you should not mix and match types unless you are absolutely sure of what you are doing. (We'll see a few examples)

Remember we told that we will prefer int *pa rather than int* pa although they are the same? The reason is to safeguard against the following common misconception. Can you find the difference?

If you are a beginner, you will assume that since int a, b makes both a and b as int , then int* pa, pb will make both pa and pb as int* . But it doesn't. The reason is * "binds" to the variable name, not the type name. If instead, you'd have written

you'd rightly conclude pa is a pointer to int, and pb is just int . Hence I prefer to write the * with the variable name, however, there are compelling reasons for the other style as well, and if you are careful enough, you can use the other style as well.

NULL and void pointer

These two are a special types of pointers in C. The Null pointer is used to denote that the pointer doesn't point to a valid memory location.

We use Null pointer in various ways, for example, to denote failure, or mark the end of a list of unknown size, etc. Dereferencing a Null pointer is undefined behavior and your program will likely crash.

Note that the Null pointer is not the same as pointer to memory address 0, although it's very likely to be so. There are exceptions, for example in small embedded devices where address 0 might be a valid location.

Void pointer is one more interesting pointer in C. Basically void pointer "throws away" the type of a pointer. It is a general-purpose pointer that can hold any type of pointer and can be cast to any type of pointer. The following are all valid -

But you can't dereference a void * because it doesn't have a type. Trying to dereference a void * will give you an error. However, you can cast it to anything you want and then dereference it, although it's not a very good idea and it violates the type aliasing rules.

Here we're removing the type of &a through p and casting it to a char * . Essentially a is getting read as a char and this prints A .

Be careful during casting. You should use void pointers only if you are absolutely sure of what you're doing.

Sometimes you'll see char * used as a generic pointer as well. This is because void * was not present in old versions of C, and some practice remains, or maybe the code needs to do pointer arithmetic on that pointer.

Generally void * i s used in places where you expect to work with pointers to multiple types. As an example, consider the famous memcpy function which copies a block of memory. Here is the signature of memcpy -

As you see, it accepts void * , which means it works with any type of pointers. As for an example (copied from cplusplus ) -

In line 15, we invoked memcpy with char * and in line 19, we invoked memcpy with a pointer to structure, and they both work.

Pointer arithmetic

Since pointers are just like other variables, you'd expect that we should be able to do arithmetic with them. We can, but there's a catch. First of all, we are only allowed these 2 operations -

  • Addition (and hence subtraction) of an integer constant to a pointer.
  • Subtraction of two pointers of the same type.

Let's see them one by one

This prints

Strangely, it seems pa+1 increments the pointer by 4, and not by 1. The reason lies in the datatype of the thing it points to, in this case, int . Remember that a pointer must always point to something. When you increment the pointer by 1, it points to the next thing.

In this case, pa points to an int . Where is the next int ? After 4 bytes of course, because the size of int is 4 bytes.

Similarly pa-1 points to the previous int which lies 4 bytes before.

By the same logic, pa+2 points to the int 2 places after a that is 4 * 2 = 8 bytes after a , and pa+n points to the integer n places after a which is 4n bytes after a .

An observant reader might have noticed that things are looking almost like an array, and he/she is not wrong completely. In a few minutes, we shall explore the idea of array using pointers. Before let's talk about the subtraction of pointers.

Similar to the previous case, although the difference between pa and pb is of 8 bytes as numbers, as pointers the difference is 2. The negative sign of pa-pb implies that pb points after pa .

To quickly summarise -

  • If I have some_data_type *p , then pa + n increments the pointer by n * sizeof(some_data_type) bytes.
  • If I have some_data_type *p, *q then p - q is equal to the difference in bytes divided by sizeof(some_data_type)

Let's consider what happens if we mix indirection and prefix or postfix increment/decrement operators. Can you guess what each of these does? I have omitted the data types so that you can't guess ;-). Assume p points to int

In order to answer, you have to remember the precedence -

  • Postfix ++ and -- have higher precedence than *
  • Prefix ++ and -- have the same precedence as * .

Since the * operator is itself a prefix, you'll never have a problem with prefix increment or decrement. You can tell just by the order of the operator. For the postfix operator, remember that postfix works first, then indirection.

So *p++ is same as *(p++) . So, the value of p will be used in the expression, then p will be incremented. So x gets the value of *p and p becomes p+1 , so that the type of x ought to be int too.

++*p will probably not arise confusion. This is the same as ++ (*p) . So, first p is dereferenced, and then ++ is applied. So whatever p was pointing to gets incremented by 1 and then it is assigned to x , and p is unchanged. So the type of x is again int .

And finally * ++p is same as * (++p) . So, first p gets incremented by 1, and then it is dereferenced. So x gets the value of whatever is this incremented pointer pointing to.

We can also compare pointers using relational operators like == , <= etc. but there's a catch. You can only compare two pointers using <=, <, >=, > if they both are pointers of the same type, and of the same array or same aggregate object. Otherwise, it is undefined behavior.

Quoting C11 -

When two pointers are compared, the result depends on the relative locations in the address space of the objects pointed to. If two pointers to object types both point to the same object, or both point one past the last element of the same array object, they compare equal. If the objects pointed to are members of the same aggregate object, pointers to structure members declared later compare greater than pointers to members declared earlier in the structure, and pointers to array elements with larger subscript values compare greater than pointers to elements of the same array with lower subscript values. All pointers to members of the same union object compare equal. If the expression P points to an element of an array object and the expression Q points to the last element of the same array object, the pointer expression Q+1 compares greater than P . * In all other cases, the behavior is undefined. *

Take a look -

This prints Bye . Well first of all this comparison is valid since p and q are both pointers to int and also they both point to elements of the same struct . Since q was declared later in some_struct , q compares greater to p

For equality, the restriction is a bit slack. You can compare any two pointers as long as they have the same type, or one of them is a null pointer or void pointer. And they compare equal if they point to the same object, or if both are null (doesn't matter if types don't match), or if both are pointing to members of the same union.

Let's demonstrate the last point.

This prints Equal although p and q point to different things, they are within the same union.

Since pointers are just numbers, can you put any integer in them? The answer is yes, but be careful of what you put. In fact, be careful when you dereference it. If you try to dereference an invalid address, your program will likely segfault and crash.

This instantly segfaults.

Admitted to Hogwarts School Of Pointer Magic

Pointers and arrays.

Let's now move to some advanced sorcery - array and pointers.

We know that an array stores its elements contiguously in memory. Which means the elements are stored in order one after another. So if we have int arr[10] , we know arr[1] lies right after arr[0] , arr[2] lies right after arr[1] and so on. So if I have a pointer to arr[0] and I increment it by 1, it should point to arr[1] . If I increment it by 1 again, it should point to arr[2] .

In fact, there are so many similarities between arrays and pointers, that we can talk about the equivalence of arrays and pointers.

Word of caution! This does not mean arrays and pointers are the same and you can use one in place of another. This misconception is quite common and ends up being harmful. Arrays and pointers are very different things, but pointer arithmetic and array indexing are equivalent.

For starters, the name of an array "decays" into a pointer to the first element. What do I mean by that? Consider this code -

But aren't we mixing up datatypes in the case of pb ? pb is a pointer to int and arr is an array of int!

Turns out that arr is converted to a pointer to the first element. So that arr and &(arr[0]) is equivalent.

Quick note: indexing operator [] has higher precendence than * so that * arr[0] is same as * (arr[0])

Let's do even more funny stuff -

The first printf is ok. arr[1] means the 2nd element of arr .

We just reasoned about the 2nd line. pa points to the first element of arr . So pa+1 will point to the next int in memory, which is arr[1] because array elements are stored contiguously.

But in the 3rd and 4th lines, aren't we mixing up array and pointer syntax? Well, turns out that arr[i] is just the same as *(arr + i) and this is (almost) what happens internally when you write arr[i] .

Similarly *(pa + i) is the same as pa[i] . Pointer arithmetic works both on arrays and pointers. Similarly, array indexing works on both pointers and arrays.

And for the last part, arr[1] is the same as *(arr + 1) which is the same as *(1 + arr) which should be the same as 1[arr] . This is one of those weird quirks of C.

Does this mean you can mix and match pointers and arrays? The answer is a big fat no. The reason is although arr[i] and pa[i] give you the same result, i. e. the 2nd element of arr , the way they reach there is quite different.

Consider the code

Let's look at the assembly code generated by the compiler. I used Compiler Explorer . Don't worry if you can't read assembly. We'll go together.

We are interested in lines 5 and 6. Here's the related assembly for int arr[3] = {1, 2, 3} .

In case you are seeing assembly for the first time, rbp is the base pointer register that holds the memory address of the base of the current stack frame. Don't worry about what that means. For now think of rbp as a pointer variable, which points to some location in memory.

Here the contents of arr is being put in memory. For example, consider the first line. The mov instruction puts the value 1 somewhere in memory. The DWORD PTR tells that it is of size 32 bit or 4 bytes as it is an int . The syntax [rbp - 28] means the content of the memory location at the address rbp-28 . Remember that rbp is like a pointer. So it is the same as doing * (rbp - 28) .

Putting everything together, we see that the first line puts the value 1 in the memory address pointed by rbp-28 . The next value should be stored right after it, i. e. after 4 bytes. Which should be pointed by rbp-24 and indeed that is where 2 is stored. And finally, 3 is stored in the memory address pointed by rbp-20 .

So, we see that the address of the first element is rbp-28 . So we'd expect this should be reflected in the line int *pa = arr; . And indeed it is -

lea means load effective address which calculates rbp-28 and stores the address in rax rather than fetching the content of the memory address   rbp-28 and storing the content . In other words, it just copies the address of the first element in rax register and then in the memory location rbp-8 which is our pa .

Now let's look at int a = arr[1]

So here first the content of rbp-24 is loaded into eax and then stored in rbp-12 which is our a . The interesting thing to notice is that the compiler knows the first element of arr is at rbp-28 so when you write arr[1] it directly offsets the base address by and gets rbp-24`. This happens in compile time.

Now let's look at int b = pa[1];

Here we see first the value stored at rbp-8 is moved to rax . Remember this was our pa variable? So first the value stored at pa is read. Then it is offset by 1, so we get rax + 4 and we read the value at rax+4 and store it to eax . Finally, we store the value from eax to rbp-16 which is the b variable.

The noticeable difference is that it takes one extra instruction in case of pointer. Because array address is fixed, when you write arr , the compiler knows what you're talking about. But a pointer value can be changed. So when you write pa , the value of pa needs to be read first and then it can be used.

Now suppose something like this. You have two files. One contains a global array like

And in another file, you get carried away by the equivalence of array and pointer and write

In other words, you have declared arr as a pointer but defined as an array. What will happen if you write int a = arr[1] ?

The answer is - something catastrophic. Let's see why.

Let's assume the array elements are stored just like before -

But in our second file, we are doing arr[1] . So it will do something like

Can you see the problem? We are reading the content at rbp-28 , but the content is 1, the first element of the array. So, essentially we are reading the content of memory address 1+4=5 which is an invalid location!

Bottom line: Don't mix and match.

Another difference is that a pointer name is a variable, but an array name is not. So you can do pa++ and pa=arr but you cannot do arr=pa and arr++

But, there is a case where arrays and pointers are the same. That is in function parameters -

What is the difference between arr and pa ? There is no difference

The compiler treats arr and pa both as pointers, and that's about the only case you can be certain that using pointer in place of array works.

Technically, this is an illustration of an array-like syntax being used to declare pointers, rather than an example of pointers and arrays being the same.

Since pointers are like any other variable, you can have a pointer to pointers too.

Here pa is a pointer to pointer to int . So, *pa will give you a pointer to int , and finally **pa will give you an int

You can have pointers to array too. But before that, remember [] has higher precedence than *

What's the difference between pointer to an array and normal pointer? Consider

So, essentially they all point to the same location. And we already know arr is the same as a pointer to the first element. Now we see that &arr also contains the location of the first element.

Although pa and pb point to the same location, what they point to is very different. pb is a pointer to [int] so it points to a [int] which is the first element of arr whereas pa is a pointer to [array of 3 elements] so it points to an [array of 3 elements] i. e. the whole arr .

This is evident when you try to do arithmetic -

pb is a pointer to int . So pb+1 points to the next int 4 bytes after. Whereas pa is a pointer to array of 3 int . So pa+1 will point to the next array of 3 int which is 3 * 4 = 12 bytes after, and indeed, pa+1 is 12 bytes after pa . ( 0x7fff2632cc90 - 0x7fff2632cc84 = 12, these are in hexadecimal in case you're confused).

You can use a pointer to array just like a normal variable. Just remember the precedence -

The easiest way to remember is "Declaration follows usage." So the usage of a pointer will look like the way it was defined. Since we defined pa as (*pa)[] , its usage will also look the same.

One common mistake that students do, with the fact that arrays decay down to pointers in function parameters is working with multidimensional arrays.

If you have something like

you might think since array names decay to pointers in function parameter, an array of array should decay to a pointer to pointer. So you might write the declaration of f as

Unfortunately, this is wrong and will give a warning (but will compile)

What happened here? It's easy.

If an array of [int] decays down to a pointer to [int], what should an array of [array of int] decay down to? Of course a pointer to [array of int]. Remember that the size is also part of arrays type. So, in our case, arr is an array of [4 element array of int]. So, it decays down to pointer to [4 element array of int].

So you should write

Or, you can just take an array of array

Note that only the size of the rightmost column is required in the formal parameters list.

Pointers and Structures and Unions

Now we move on to struct and union . We can have pointers to them too.

Or if you prefer a typedef

An interesting situation occurs when you want to access members of struct using pointer. Suppose you want to access the member p through pa . You might do

Except, this doesn't do what you expect. The operator . has higher precedence than * so *pa.p is same as *(pa.p) . So instead of dereferencing pa and then accessing the member p , you end up accessing the member p and then dereferencing it. But pa doesn't have a member p . So, it gives a compiler error.

Instead, you want to write this

Which works the way you want. But writing this is tedious, and turns out that we write this so much that they have a special operator ->

pa -> p is same as (*pa).p but looks neat and clean.

The case of unions is a little bit involved. Quoting cppreference -

A pointer to a union can be cast to a pointer to each of its members (if a union has bit field members, the pointer to a union can be cast to the pointer to the bit field's underlying type). Likewise, a pointer to any member of a union can be cast to a pointer to the enclosing union.

What it means is that, if you have a pointer to a union, you can cast it to any of its members, and vice versa. Take a look

Here, I could cast the pointer to a to an int* and it automatically pointed to the member p . Similarly, if I had cast it to char* it would point to q .

Conversely, if I had a pointer to p , I could cast it to a pointer to some_union and it would point to a

This prints a as expected.

Ministry of Pointer Magic

Pointers and function.

It is possible to have pointers to functions too. Remember that the return type, the number of parameters it takes, and the type of each parameter - these 3 are parts of the type of a function. Hence you must provide these during pointer declaration. Also worth noting () has higher precedence than *

A pointer to function can be used just like other pointers -

This prints 2 as you'd expect.

Remember I talked about declaration follows usage? Well, turns out that in the case of pointer to functions, that rule can be ignored. For example, this works

And so does this

And weirdly enough, this too

So, in the case of functions, not only you can dereference as many times as you want, you can drop the dereferencing altogether and just use the pointer as if it were a function itself . Another one of those C quirks.

Finally, you can get wild with pointers and arrays and function like

You get the idea. Yes, it can get pretty messy, but once you know the syntax, and you have cdecl , you can easily breeze through them (or read my article )

As for how you can use a function pointer. here's an example of a simple calculator

We are storing all 4 operations in an array and when the user enters a number, we call the corresponding operation.

Qualified types

Each type in C can be qualified by using qualifiers. In particular we have 3 - const , volatile , and restrict . Here we will look at const and restrict .

Adding const to a type effectively marks it read-only, so that attempting to change the value will result in a compiler error.

Turns out, int const and const int both are valid. Now if I throw pointers into the party, I get some fun stuff

Can you guess which one is what?

To untangle this, we will remember some_data_type *p declares p to be a pointer to some_data_type

Hence, const int *p can be thought of as (const int) *p . So that p is a pointer to a const int . It means, whatever p is pointing to is a const int and you cannot change that. However, p itself is not const and can be changed.

For the second one compare it with int const p which declares p as a read only int . So, int * const p should declare p as read-only int* . This means the pointer itself is const and you can't change p , but you can change what p is pointing to.

And finally, const int * const p declares that both p and *p are read-only. So you can neither change p nor *p .

Now let's look at the restrict keyword. The restrict keyword, when applied to a pointer p , tells the compiler that as long as p is in scope, only p and pointers directly or indirectly derived from it (e. g. p+1 ) will access the thing it's pointing to.

Confused? Let's see an example.

Here is the assembly generated after enabling optimization -

The problem in this function is, p , q and v might point to the same location. So that when you do *p += *v , it might happen that *v also gets changed because p and v were pointing to the same location.

This is why *v is first loaded into eax by mov     eax, DWORD PTR [rdx] . Then it is added to *p . Again, we have to load *v because at this point, we are not sure if *v has changed or not.

Now if I update the function as follows -

the compiler is free to assume that p , q and v all point to different locations, and can load *v only once, and indeed it does

Note that it is up to the programmer to guarantee that the pointers do not overlap. In case they do, it is undefined behavior.

You can read more about restrict here .

That's probably enough for one post. To quickly recap, you have learned -

  • What pointers are.
  • How to declare and dereference pointers.
  • Pointer arithmetic.
  • Pointer comparison.
  • Pointer to array and array of pointers.
  • Pointers and arrays are not the same.
  • Pointer arithmetic and array indexing are equivalent.
  • Array in function parameter decay to a pointer.
  • Pointers to a multidimensional array.
  • Pointers to structures and unions.
  • Pointer to functions.
  • Pointer to wild exotic types.
  • const and restrict with pointers.

Note that most of these hold true in C++ also, although you have minor changes, and some new stuff like smart pointers.

Hopefully, you learned something new in this post. Subscribe to my blog for more.

Top comments (0)

pic

Templates let you quickly answer FAQs or store snippets for re-use.

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment's permalink .

Hide child comments as well

For further actions, you may consider blocking this person and/or reporting abuse

jakepage91 profile image

The guide to Git I never had.

Jake Page - Apr 10

julianlasso profile image

How to install Docker CLI on Windows without Docker Desktop and not die trying

Julian Lasso 🇨🇴 - Mar 27

Are hackers watching your screen right now?

Lev Nahar - Apr 10

krste profile image

Software Architecture Should Not Be the Enemy

Krste Šižgorić - Apr 5

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

DevsENV

  • C Programming

Pointer in C Programming Language with Practical Examples

  • Conceptual View of a Variable in Memory
  • Declaration of Pointer
  • Initialization of Pointer
  • Dereferencing Pointer
  • Null Pointers
  • Void Pointers
  • Regular Pointers
  • Function Pointers
  • Pointer to Pointer
  • Addition and Subtraction
  • Comparison of Pointers of Same Types
  • More Examples

In C programming, a Pointer variable stores memory address of another variable, pointing to where other variable resides in memory. Pointer variables Provide direct access and manipulation of memory, enhancing code flexibility and efficiency.

¶ Conceptual View of a Variable in Memory

Every variable is assigned a specific memory location, allowing the program to store and retrieve data. This memory can be conceptualized as a contiguous sequence of bytes, each with a unique address. Let’s see how an variable is stored inside memory.

Representation of a Variable in Memory in C programming

Here, an integer variable var stores 13 at memory location 1001 and pointer variable ptr stores the memory location 1001 of var .

Though different data types require different amounts of memory to store a variable, all pointer variables require the same amount of memory for the memory address. The size of a memory address is architecture-dependent, with 64-bit architectures requiring 8 bytes , and 32-bit architectures requiring 4 bytes .

¶ Declaration of Pointer

The declaration of a pointer involves specifying the data type it points to, followed by an asterisk (*) known as dereference operator. This asterisk indicates that the variable is a pointer.

¶ Initialization of Pointer

Pointers can be initialized by assigning the memory address of a variable to them. The address-of operator (&) is used for this purpose.

Here, when we assign &var to a pointer variable ptr it stores the memory address ( 1001 ) of the variable. Now, we can indirectly manipulate data in the address 1001 through ptr .

¶ Dereferencing Pointer

Dereferencing a pointer is accomplished using the dereference operator *. This operator, when applied to a pointer, retrieves the value stored at the memory address pointed to by that pointer.

When we print value in ptr it prints a memory location in hexadecimal as it stores a memory location. But when we dereference it with * it prints the value in the memory location stored in it.

¶ Types of Pointers in C Programming

Depending on the types of data that pointer variables point to, they are mainly classified as follows,

¶ Null Pointers

A null pointer is a pointer that does not point to any memory location. It is often used to indicate the absence of a valid memory address. In C, a null pointer is represented by assigning the value NULL to a pointer.

¶ Void Pointers

Void pointers, or generic pointers, are pointers that can point to objects of any data type. They can be casted to different types according to need. Thus, providing a way to achieve flexibility in handling different data types without explicitly specifying the type. But they can not be dereferenced.

¶ Regular Pointers

They are the pointers that point to specific data types like int, char, or float. These pointers are essential for efficiently manipulating and accessing individual elements of basic data types. Examples we have seen so far are mostly of this type.

¶ Function Pointers

Function pointers point to functions instead of data. They are particularly useful in scenarios where different functions need to be called based on certain conditions. They actually point to the code segment in the memory of the function it is pointing to, allowing the execution of the function through the pointer.

¶ Pointer to Pointer

A pointer to a pointer, also known as a multilevel pointer, stores the address of another pointer. This type of pointer is especially useful in dynamic memory allocation and multidimensional arrays.

¶ Pointer Arithmetic

Pointer arithmetic is different from other variables. Pointer arithmetic supports following operations,

¶ Addition and Subtraction

Adding or subtracting an integer value to a pointer results in moving in memory by a distance calculated based on the size of the data type the pointer points to. For integers, pointers move 4 bytes.

¶ Comparison of Pointers of Same Types

We cam compare two pointers of the same type using relational operators. When comparing pointers, you are comparing the memory addresses they hold.

¶ More Examples

  • Print an Array Using Pointer
  • Swap Two Numbers using Pointers

All Tutorials in this playlist

What is C Programming and How to Start C Programming

What is C Programming and How to Start C Programming

Getting Started Your First Coding With C Programming

Getting Started Your First Coding With C Programming

Variable and Data Types with Practical Examples in C Programming

Variable and Data Types with Practical Examples in C Programming

Input and Output in C Programming

Input and Output in C Programming

Conditional in C Programming - if-else, elseif, switch-case

Conditional in C Programming - if-else, elseif, switch-case

Loops in C Programming - for loop, while loop and do-while loop

Loops in C Programming - for loop, while loop and do-while loop

Functions in C Programming - with Practical examples

Functions in C Programming - with Practical examples

Arrays in C Programming - Algorithm and Practical examples

Arrays in C Programming - Algorithm and Practical examples

Recursion in C Programming Language with Practical Examples

Recursion in C Programming Language with Practical Examples

Structure in C Programming Language with practical examples

Structure in C Programming Language with practical examples

File Handling in C Programming Language with Practical Examples

File Handling in C Programming Language with Practical Examples

Pointer in C Programming Language with Practical Examples

Student Management Complete Application Using C Programming

C Project - Complete Calculator Application using C Programming

C Project - Complete Calculator Application using C Programming

Popular tutorials, vue js 3 - complete advance crud example with vuex, vue-validate, pagination, searching and everything, laravel eloquent vs db query builder [performance and other statistics], laravel role permission management system full example with source code, start wordpress plugin development with react js easily in just few steps, laravel membership management full project demo with source codes, numerical methods for engineers ebook & solution download - download pdf, connect your react app with websocket to get real time data, #ajax with laravel api and more - learn laravel beyond the limit, laravel ecommerce complete web application with admin panel, what is seeder in laravel and why we need it.

  • Artificial Intelligence (AI)
  • Bash Scripting

Bootstrap CSS

  • Code Editor
  • Computer Engineering
  • Data Structure and Algorithm

Design Pattern in PHP

Design Patterns - Clean Code

  • Git Commands

Interview Prepration

Java Programming

Laravel PHP Framework

Online Business

  • Programming

React Native

Rust Programming

Tailwind CSS

Uncategorized

Windows Operating system

  • Woocommerce

WordPress Development

  • C-sharp programming
  • Design pattern
  • Mathematics
  • Rust Programming Language
  • Windows terminal
  • WordPress Plugin Development

Pointers in C Explained – They're Not as Difficult as You Think

Srijan

Pointers are arguably the most difficult feature of C to understand. But, they are one of the features which make C an excellent language.

In this article, we will go from the very basics of pointers to their usage with arrays, functions, and structure.

So relax, grab a coffee, and get ready to learn all about pointers.

A. Fundamentals

  • What exactly are pointers?
  • Definition and Notation
  • Some Special Pointers
  • Pointer Arithmetic

B. Arrays and Strings

  • Why pointers and arrays?
  • Array of Pointers
  • Pointer to Array

C. Functions

  • Call by Value v/s Call by Reference
  • Pointers as Function Arguments
  • Pointers as Function Return
  • Pointer to Function
  • Array Of Pointers to Functions
  • Pointer to Function as an Argument

D. Structure

  • Pointer to Structure
  • Array of Structure
  • Pointer to Structure as an Argument

E. Pointer to Pointer

F. conclusion, a. definition, notation, types and arithmetic, 1. what exactly are pointers.

Before we get to the definition of pointers, let us understand what happens when we write the following code:

What exactly are pointers?

A block of memory is reserved by the compiler to hold an int value. The name of this block is digit and the value stored in this block is 42 .

Now, to remember the block, it is assigned with an address or a location number (say, 24650).

The value of the location number is not important for us, as it is a random value. But, we can access this address using the & (ampersand) or address of operator.

We can get the value of the variable digit from its address using another operator * (asterisk), called the indirection or dereferencing or value at address operator.

2. Definition and Notation

The address of a variable can be stored in another variable known as a pointer variable. The syntax for storing a variable's address to a pointer is:

For our digit variable, this can be written like this:

or like this:

This can be read as - A pointer to int (integer) addressOfDigit stores the address of(&) digit variable.

Few points to understand:

dataType – We need to tell the computer what the data type of the variable is whose address we are going to store. Here, int was the data type of digit .

It does not mean that addressOfDigit will store a value of type int . An integer pointer (like addressOfDigit ) can only store the address of variables of integer type.

* – A pointer variable is a special variable in the sense that it is used to store an address of another variable. To differentiate it from other variables that do not store an address, we use * as a symbol in the declaration.

Here, we can assign the address of variable1 and variable2 to the integer pointer addressOfVariables but not to variable3 since it is of type char . We will need a character pointer variable to store its address.

We can use our addressOfDigit pointer variable to print the address and the value of digit as below:

Here, *addressOfDigit can  be read as the value at the address stored in addressOfDigit .

Notice we used %d as the format identifier for addressOfDigit . Well, this is not completely correct. The correct identifier would be %p .

Using %p , the address is displayed as a hexadecimal value. But the memory address can be displayed in integers as well as octal values. Still, since it is not an entirely correct way, a warning is shown.

The output according to the compiler I'm using is the following:

This is the warning shown when you use  %d - " warning: format '%d' expects argument of type 'int', but argument 2 has type 'int *' ".

3. Some Special Pointers

The wild pointer.

When we defined our character pointer alphabetAddress , we did not initialize it.

Such pointers are known as wild pointers . They store a garbage value (that is, memory address) of a byte that we don't know is reserved or not (remember int digit = 42; , we reserved a memory address when we declared it).

Suppose we dereference a wild pointer and assign a value to the memory address it is pointing at. This will lead to unexpected behaviour since we will write data at a  memory block that may be free or reserved.

Null Pointer

To make sure that we do not have a wild pointer, we can initialize a pointer with a NULL value, making it a null pointer .

A null pointer points at nothing, or at a memory address that users can not access.

Void Pointer

A void pointer can be used to point at a variable of any data type. It can be reused to point at any data type we want to. It is declared like this:

Since they are very general in nature, they are also known as generic pointers .

With their flexibility, void pointers also bring some constraints. Void pointers cannot be dereferenced as any other pointer. Appropriate typecasting is necessary.

Similarly, void pointers need to be typecasted for performing arithmetic operations.

Void pointers are of great use in C. Library functions malloc() and calloc() which dynamically allocate memory return void pointers. qsort() , an inbuilt sorting function in C, has a function as its argument which itself takes void pointers as its argument.

Dangling Pointer

A dangling pointer points to a memory address which used to hold a variable. Since the address it points at is no longer reserved, using it will lead to unexpected results.

Though the memory has been deallocated by free(ptr) , the pointer to integer ptr still points to that unreserved memory address.

4. Pointer Arithmetic

We know by now that pointers are not like any other variable. They do not store any value but the address of memory blocks.

So it should be quite clear that not all arithmetic operations would be valid with them. Would multiplying or dividing two pointers ( having addresses ) make sense?

Pointers have few but immensely useful valid operations:

  • You can assign the value of one pointer to another only if they are of the same type (unless they're typecasted or one of them is void * ).

2.   You can only add or subtract integers to pointers.

When you add (or subtract) an integer (say n) to a pointer, you are not actually adding (or subtracting) n bytes to the pointer value. You are actually adding (or subtracting) n- times the size of the data type of the variable being pointed bytes.

The value stored in newAddress will not be 103, rather 112 .

3.   Subtraction and comparison of pointers is valid only if both are members of the same array. The subtraction of pointers gives the number of elements separating them.

4.  You can assign or compare a pointer with NULL .

The only exception to the above rules is that the address of the first memory block after the last element of an array follows pointer arithmetic.

Pointer and arrays exist together. These valid manipulations of pointers are immensely useful with arrays, which will be discussed in the next section.

1. Why pointers and arrays?

In C, pointers and arrays have quite a strong relationship.

The reason they should be discussed together is because what you can achieve with array notation ( arrayName[index] ) can also be achieved with pointers, but generally faster.

2. 1-D Arrays

Let us look at what happens when we write int myArray[5]; .

Five consecutive blocks of memory starting from myArray[0] to myArray[4] are created with garbage values in them. Each of the blocks is of size 4 bytes.

Thus, if the address of myArray[0] is 100 (say), the address of the rest of the blocks would be 104 , 108 , 112 , and 116 .

Have a look at the following code:

So, &prime , prime , and &prime[0] all give the same address, right? Well, wait and read because you are in for a surprise (and maybe some confusion).

Let's try to increment each of &prime , prime , and &prime[0] by 1.

Wait! How come &prime + 1 results in something different than the other two? And why are prime + 1 and &prime[0] + 1 still equal? Let's answer these questions.

prime and &prime[0] both point to the 0th element of the array prime . Thus, the name of an array is itself a pointer to the 0th element of the array .

Here, both point to the first element of size 4 bytes. When you add 1 to them, they now point to the 1st element in the array. Therefore this results in an increase in the address by 4.

&prime , on the other hand, is a pointer to an int array of size 5 . It stores the base address of the array prime[5] , which is equal to the address of the first element. However, an increase by 1 to it results in an address with an increase of 5 x 4 = 20 bytes.

In short, arrayName and &arrayName[0] point to the 0th element whereas &arrayName points to the whole array.

We can access the array elements using subscripted variables like this:

We can do the same using pointers which are always faster than using subscripts.

Both methods give the output:

Thus, &arrayName[i] and arrayName[i] are the same as arrayName + i and   *(arrayName + i) , respectively.

3. 2-D Arrays

Two-dimensional arrays are an array of arrays.

Here, marks can be thought of as an array of 5 elements, each of which is a one-dimensional array containing 3 integers. Let us work through a series of programs to understand different subscripted expressions.

Like 1-D arrays, &marks points to the whole 2-D array, marks[5][3] . Thus, incrementing to it by 1 ( = 5 arrays X 3 integers each X 4 bytes = 60) results in an increment by 60 bytes.

If marks was a 1-D array, marks and &marks[0] would have pointed to the 0th element. For a 2-D array, elements are now 1-D arrays . Hence, marks and &marks[0] point to the 0th array (element), and the addition of 1 point to the 1st array.

And now comes the difference. For a 1-D array, marks[0] would give the value of the 0th element. An increment by 1 would increase the value by 1.

But, in a 2-D array, marks[0] points to the 0th element of the 0th array. Similarly, marks[1] points to the 0th element of the 1st array. An increment by 1 would point to the 1st element in the 1st array.

This is the new part. marks[i][j] gives the value of the jth element of the ith array. An increment to it changes the value stored at marks[i][j] . Now, let us try to write marks[i][j] in terms of pointers.

We know marks[i] + j would point to the ith element of the jth array from our previous discussion. Dereferencing it would mean the value at that address. Thus, marks[i][j] is the same as   *(marks[i] + j) .

From our discussion on 1-D arrays, marks[i] is the same as *(marks + i) . Thus, marks[i][j] can be written as *(*(marks + i) + j) in terms of pointers.

Here is a summary of notations comparing 1-D and 2-D arrays.

A string is a one-dimensional array of characters terminated by a null(\0) . When we write char name[] = "Srijan"; , each character occupies one byte of memory with the last one always being \0 .

Similar to the arrays we have seen, name and &name[0] points to the 0th character in the string, while &name points to the whole string. Also, name[i] can be written as *(name + i) .

A two-dimensional array of characters or an array of strings can also be accessed and manipulated as discussed before.

5. Array of Pointers

Like an array of int s and an array of char s, there is an array of pointers as well. Such an array would simply be a collection of addresses. Those addresses could point to individual variables or another array as well.

The syntax for declaring a pointer array is the following:

Following the operators precedence , the first example can be read as -   example1 is an array( [] ) of 5 pointers to int . Similarly, example2 is an array of 8 pointers to char .

We can store the two-dimensional array to string top using a pointer array and save memory as well.

top will contain the base addresses of all the respective names. The base address of "Liverpool" will be stored in top[0] , "Man City" in top[1] , and so on.

In the earlier declaration, we required 90 bytes to store the names. Here, we only require ( 58 (sum of bytes of names) + 12 ( bytes required to store the address in the array) ) 70 bytes.

The manipulation of strings or integers becomes a lot easier when using an array of pointers.

If we try to put "Leicester" ahead of "Chelsea" , we just need to switch the values of top[3] and top[4] like below:

Without pointers, we would have to exchange every character of the strings, which would have taken more time. That's why strings are generally declared using pointers.

6. Pointer to Array

Like "pointer to int " or "pointer to char ", we have pointer to array as well. This pointer points to whole array rather than its elements.

Remember we discussed how &arrayName points to the whole array? Well, it is a pointer to array.

A pointer to array can be declared like this:

Notice the parentheses. Without them, these would be an array of pointers. The first example can be read as - ptr1 is a pointer to an array of 5 int (integers) .

When we dereference a pointer, it gives the value at that address. Similarly, by dereferencing a pointer to array, we get the array and the name of the array points to the base address. We can confirm that *pointerToGoals gives the array goals if we find its size.

If we dereference it again, we will get the value stored in that address. We can print all the elements using pointerToGoals .

Pointers and pointer to arrays are quite useful when paired up with functions. Coming up in the next section!

1. Call by Value vs Call by Reference

Have a look at the program below:

The function multiply() takes two int arguments and returns their product as int .

In the function call multiply(x,y) , we passed the value of x and y ( of main() ), which are actual arguments , to multiply() .

The values of the actual arguments are passed or copied to the formal arguments x and y ( of multiply() ). The x and y of multiply() are different from those of main() . This can be verified by printing their addresses.

Since we created stored values in a new location, it costs us memory. Wouldn't it be better if we could perform the same task without wasting space?

Call by reference helps us achieve this. We pass the address or reference of the variables to the function which does not create a copy. Using the dereferencing operator * , we can access the value stored at those addresses.

We can rewrite the above program using call by reference as well.

2. Pointers as Function Arguments

In this section, we will look at various programs where we give int , char , arrays and strings as arguments using pointers.

We created four functions, add() , subtract() , multiply() and divide() to perform arithmetic operations on the two numbers a and b .

The address of a and b was passed to the functions. Inside the function using * we accessed the values and printed the result.

Similarly, we can give arrays as arguments using a pointer to its first element.

Since the name of an array itself is a pointer to the first element, we send that as an argument to the function greatestOfAll() . In the function, we traverse through the array using loop and pointer.

Here, we pass in the string name to wish() using a pointer and print the message.

3. Pointers as Function Return

The function multiply() takes two pointers to int . It returns a pointer to int as well which stores the address where the product is stored.

It is very easy to think that the output would be 15. But it is not!

When multiply() is called, the execution of main() pauses and memory is now allocated for the execution of multiply() . After its execution is completed, the memory allocated to multiply() is deallocated.

Therefore, though c ( local to main() ) stores the address of the product, the data there is not guaranteed since that memory has been deallocated.

So does that mean pointers cannot be returned by a function? No!

We can do two things. Either store the address in the heap or global section or declare the variable to be static so that their values persist.

Static variables can simply be created by using the keyword static before data type while declaring the variable.

To store addresses in heap, we can use library functions malloc() and calloc() which allocate memory dynamically.

The following programs will explain both the methods. Both methods return the output as 15.

4. Pointer to Function

Like pointer to different data types, we also have a pointer to function as well.

A pointer to function or function pointer stores the address of the function. Though it doesn't point to any data. It points to the first instruction in the function.

The syntax for declaring a pointer to function is:

The below example will make it clearer.

The declaration for the pointer p to function multiply() can be read as ( following operator precedence ) - p is a pointer to function with two int eger pointers ( or two pointers to int ) as parameters and returning a pointer to int .

Since the name of the function is also a pointer to the function, the use of & is not necessary. Also removing * from the function call doesn't affect the program.

5. Array of Pointers to Functions

We have already seen how to create an array of pointers to int , char , and so on. Similarly, we can create an array of pointers to function.

In this array, every element will store an address of a function, where all the functions are of the same type. That is, they have the same type and number of parameters and return types.

We will modify a program discussed earlier in this section. We will store the addresses of add() , subtract() , multiply() and divide() in an array make a function call through subscript.

The declaration here can be read as - p is an array of pointer to functions with two float pointers as parameters and returning void .

6. Pointer to Function as an Argument

Like any other pointer, function pointers can also be passed to another function, therefore known as a callback function or called function . The function to which it is passed is known as a calling function .

A better way to understand would be to look at qsort() , which is an inbuilt function in C. It is used to sort an array of integers, strings, structures, and so on. The declaration for qsort() is:

qsort() takes four arguments:

  • a void pointer to the start of an array
  • number of elements
  • size of each element
  • a function pointer that takes in two void pointers as arguments and returns an int

The function pointer points to a comparison function that returns an integer that is greater than, equal to, or less than zero if the first argument is respectively greater than, equal to, or less than the second argument.

The following program showcases its usage:

Since a function name is itself a pointer, we can write compareIntegers as the fourth argument.

1. Pointer to Structure

Like integer pointers, array pointers, and function pointers, we have pointer to structures or structure pointers as well.

Here, we have declared a pointer ptrStudent of type struct records . We have assigned the address of student to ptrStudent .

ptrStudent stores the base address of student , which is the base address of the first member of the structure. Incrementing by 1 would increase the address by sizeof(student) bytes.

We can access the members of student using ptrStudent in two ways. Using our old friend * or using -> ( infix or arrow operator ).

With * , we will continue to use the . ( dot operator) whereas with -> we won't need the dot operator.

Similarly, we can access and modify other members as well. Note that the brackets are necessary while using * since the dot operator( . ) has higher precedence over * .

2. Array Of Structure

We can create an array of type struct records and use a pointer to access the elements and their members.

Note that ptrStudent1 is a pointer to student[0] whereas ptrStudent2 is a pointer to the whole array of  10 struct records . Adding 1 to ptrStudent1 would point to student[1] .

We can use ptrStudent1 with a loop to traverse through the elements and their members.

3. Pointer to Structure as an Argument

We can also pass the address of a structure variable to a function.

Note that the structure struct records is declared outside main() . This is to ensure that it is available globally and printRecords() can use it.

If the structure is defined inside main() , its scope will be limited to main() . Also structure must be declared before the function declaration as well.

Like structures, we can have pointers to unions and can access members using the arrow operator ( -> ).

So far we have looked at pointer to various primitive data types, arrays, strings, functions, structures, and unions.

The automatic question that comes to the mind is – what about pointer to pointer?

Well, good news for you! They too exist.

To store the address of int variable var , we have the pointer to int ptr_var . We would need another pointer to store the address of ptr_var .

Since ptr_var is of type int * , to store its address we would have to create a pointer to int * . The code below shows how this can be done.

We can use ptr_ptrvar to access the address of ptr_var and use double dereferencing to access var.

It is not required to use brackets when dereferencing ptr_ptrvar . But it is a good practice to use them. We can create another pointer ptr_ptrptrvar , which will store the address of ptr_ptrvar .

Since ptr_ptrvar is of type int** , the declaration for ptr_ptrptrvar will be

We can again access ptr_ptrvar , ptr_var and var using ptr_ptrptrvar .

If we change the value at any of the pointer(s) using ptr_ptrptrvar or ptr_ptrvar , the pointer(s) will stop pointing to the variable.

Phew! Yeah, we're finished. We started from pointers and ended with pointers (in a way). Don't they say that the curve of learning is a circle!

Try to recap all the sub-topics that you read. If you can recollect them, well done! Read the ones you can't remember again.

This article is done, but you shouldn't be done with pointers. Play with them. Next, you can look into Dynamic Memory Allocation to get to know pointers better .

Stay home, stay safe.

Sachin. Cricket. Dhoni. De Villiers. Buttler. In that order.

If you read this far, thank the author to show them you care. Say Thanks

Learn to code for free. freeCodeCamp's open source curriculum has helped more than 40,000 people get jobs as developers. Get started

CProgramming Tutorial

  • C Programming Tutorial
  • C - Overview
  • C - Features
  • C - History
  • C - Environment Setup
  • C - Program Structure
  • C - Hello World
  • C - Compilation Process
  • C - Comments
  • C - Keywords
  • C - Identifiers
  • C - User Input
  • C - Basic Syntax
  • C - Data Types
  • C - Variables
  • C - Integer Promotions
  • C - Type Conversion
  • C - Constants
  • C - Literals
  • C - Escape sequences
  • C - Format Specifiers
  • C - Storage Classes
  • C - Operators
  • C - Decision Making
  • C - if statement
  • C - if...else statement
  • C - nested if statements
  • C - switch statement
  • C - nested switch statements
  • C - While loop
  • C - For loop
  • C - Do...while loop
  • C - Nested loop
  • C - Infinite loop
  • C - Break Statement
  • C - Continue Statement
  • C - goto Statement
  • C - Functions
  • C - Main Functions
  • C - Return Statement
  • C - Recursion
  • C - Scope Rules
  • C - Properties of Array
  • C - Multi-Dimensional Arrays
  • C - Passing Arrays to Function
  • C - Return Array from Function
  • C - Variable Length Arrays
  • C - Pointers
  • C - Pointer Arithmetics
  • C - Passing Pointers to Functions
  • C - Strings
  • C - Array of Strings
  • C - Structures
  • C - Structures and Functions
  • C - Arrays of Structures
  • C - Pointers to Structures
  • C - Self-Referential Structures
  • C - Nested Structures
  • C - Bit Fields
  • C - Typedef
  • C - Input & Output
  • C - File I/O
  • C - Preprocessors
  • C - Header Files
  • C - Type Casting
  • C - Error Handling
  • C - Variable Arguments
  • C - Memory Management
  • C - Command Line Arguments
  • C Programming Resources
  • C - Questions & Answers
  • C - Quick Guide
  • C - Useful Resources
  • C - Discussion
  • Selected Reading
  • UPSC IAS Exams Notes
  • Developer's Best Practices
  • Questions and Answers
  • Effective Resume Writing
  • HR Interview Questions
  • Computer Glossary

Pointers in C

Pointers in C are easy and fun to learn. Some complex C programming tasks can be performed more easily with pointers, while some other tasks such as dynamic memory allocation cannot be performed without using pointers. So it becomes necessary to learn pointers to become a perfect C programmer.

With pointers, you can access and modify the data located in the memory, pass the data efficiently between the functions, and create dynamic data structures like linked lists, trees, and graphs.

Example: Address of the Variables

As you know, every variable is a memory location and every memory location has its address defined which can be accessed using the ampersand (&) operator, which denotes an address in memory.

Consider the following example, which prints the address of the variables defined −

When the above code is compiled and executed, it will print the address of the variables −

What are Pointers?

A pointer is a variable that stores the reference to another variable, which may be of any type such as int, float or char, an array (one or multidimensional), struct or union, or even a pointer type itself.

A pointer is a variable whose value is the address of another variable, i.e., the direct address of a memory location. Like any variable or constant, you must declare a pointer before using it to store any variable address. The general form of a pointer variable declaration is −

Here, type is the pointer's base type; it must be a valid C data type and var-name is the name of the pointer variable. The asterisk * used to declare a pointer is the same asterisk used for multiplication. However, in this statement the asterisk is being used to designate a variable as a pointer. Take a look at some of the valid pointer declarations −

The actual data type of the value of all pointers, whether integer, float, character, or otherwise, is the same, a long hexadecimal number that represents a memory address. The only difference between pointers of different data types is the data type of the variable or constant that the pointer points to.

Referencing and Dereferencing in C

A pointer references a location in memory. Obtaining the value stored at that location is known as dereferencing the pointer .

In C, it is important to understand the purpose of the following two operators in the context of pointer mechanism −

  • The & Operator − It is also known as the "Address-of operator". It is used for Referencing which means taking the address of an existing variable (using & ) to set a pointer variable.
  • The * Operator − It is also known as the "dereference operator". Dereferencing a pointer is carried out using the * operator to get the value from the memory address that is pointed by the pointer.

Pointers are used to pass parameters by reference. This is useful if a programmer wants a function's modifications to a parameter to be visible to the function's caller. This is also useful for returning multiple values from a function.

How to Use Pointers?

There are a few important operations, which we will do with the help of pointers very frequently. (a) We define a pointer variable, (b) assign the address of a variable to a pointer and (c) finally access the value at the address available in the pointer variable. This is done by using unary operator * that returns the value of the variable located at the address specified by its operand.

Example 1: Using Pointers in C

The following example shows how you can use the & and * operators to carry out pointer-related opeartions in C −

Execute the code and check its output −

To declare a pointer variable , the following syntax is to be used −

The name of the variable must be prefixed with an asterisk (*).

The data type indicates the type of variable the address of which it can store. For example, " int *x; ". Here, the variable "x" is meant to store the address of another int variable.

Similarly, in " float *y; the variable "y" is a pointer that stores the memory location of a float variable.

The & operator returns the address of an existing variable. We can assign it to the pointer variable. Take a look at the following code snippet −

Assuming that the compiler creates the variable "a" at the address 1000 and "x" at the address 2000, then the address of "a" is stored in "x".

variable at the address

The deference operator returns the value at the address stored in the pointer variable. Here "*x" will return the value of "a", i.e., the value stored in the memory address 1000, which in fact is the value of "x". Let us understand this with the help of the following example.

We will declare an int variable and display its value and address −

Run the code and check its output −

We can also use %p format specifier to obtain the hexadecimal number of the memory address.

In this example, the address of var is stored in the intptr variable with & operator

Now let's take an example of a float variable and find its address −

We can see that the address of this variable (any type of variable for that matter) is an integer. So, if we try to store it in a pointer variable of "float" type, see what happens −

The compiler doesn’t accept this, and reports the following error −

Note: The type of a variable and the type of its pointer must be same.

In C, variables have specific data types that define their size and how they store values. Declaring a pointer with a matching type (e.g., float *) enforces "type compatibility" between the pointer and the data it points to.

Different data types occupy different amounts of memory space in C. For example, an "int" typically takes 4 bytes, while a "float" might take 4 or 8 bytes depending on the system. Adding or subtracting integers from pointers moves them in memory based on the size of the data they point to.

In this example, we declare a variable "floatptr" of "float *" type.

The * operator is called the dereference operator. It returns the value of the variable that the pointer is pointing to.

Take a look at the following example −

We may have a pointer variable that stores the address of another pointer itself.

Pointer Variable

In the above figure, "a" is a normal "int" variable, whose pointer is "x". In turn, the variable stores the address of "x".

Note that "y" is declared as "int **" to indicate that it is a pointer to another pointer variable. Obviously, "y" will return the address of "x" and "*y" is the value in "x" (which is the address of "a").

To obtain the value of "a" from "y", we need to use the expression "**y". Usually, "y" will be called as the pointer to a pointer .

You can have a pointer to an array as well as a derived type defined with struct . Pointers have important applications. They are used while calling a function by passing the reference. Pointers also help in overcoming the limitation of a function’s ability to return only a single value. With pointers, you can get the effect of returning multiple values or arrays.

NULL Pointers

It is always a good practice to assign a NULL value to a pointer variable in case you do not have an exact address to be assigned. This is done at the time of variable declaration. A pointer that is assigned NULL is called a null pointer.

The NULL pointer is a constant with a value of "0" defined in several standard libraries.

Consider the following program −

When the above code is compiled and executed, it produces the following result −

In most operating systems, programs are not permitted to access memory at address "0" because that memory is reserved by the operating system.

The memory address "0" has a special significance; it signals that the pointer is not intended to point to an accessible memory location. But by convention, if a pointer contains the null (zero) value, it is assumed to point to nothing.

To check for a null pointer, you can use an if statement as follows −

Pointers in Detail

Pointers have many but easy concepts and they are very important to C programming. The following important pointer concepts should be clear to any C programmer −

Codeforwin

Pointer programming exercises and solutions in C

Pointer is a variable that stores memory addresses. Unlike normal variables it does not store user given or processed value, instead it stores valid computer memory address.

Pointer allows various magical things to be performed in C.

  • Pointers are more efficient in handling arrays and structures.
  • Pointers are used to return multiple values from a function.
  • Pointer allows dynamic memory allocation and deallocation (creation and deletion of variables at runtime) in C. Which undoubtedly is the biggest advantage of pointers.
  • Pointer allows to refer and pass a function as a parameter to functions.

and many more…

For beginners pointers can be a bad dream if not practiced well. However, once mastered you can do anything you want to do in C programming language.

In this exercise I will cover most of the pointer related topics from a beginner level. Always feel free to drop your queries and suggestion down below in the comments section .

Pointer to Pointer (Double pointer) memory representation

Required knowledge

Pointers , Pointer Arithmetic , Pointer to Pointer , Pointer and Arrays , Function Pointer

Please go through above tutorials to get a good grasp of following examples.

List of pointer programming exercises

  • Write a C program to create, initialize and use pointers .
  • Write a C program to add two numbers using pointers .
  • Write a C program to swap two numbers using pointers .
  • Write a C program to input and print array elements using pointer .
  • Write a C program to copy one array to another using pointers .
  • Write a C program to swap two arrays using pointers .
  • Write a C program to reverse an array using pointers .
  • Write a C program to search an element in array using pointers .
  • Write a C program to access two dimensional array using pointers .
  • Write a C program to add two matrix using pointers .
  • Write a C program to multiply two matrix using pointers .
  • Write a C program to find length of string using pointers .
  • Write a C program to copy one string to another using pointers .
  • Write a C program to concatenate two strings using pointers .
  • Write a C program to compare two strings using pointers .
  • Write a C program to find reverse of a string using pointers .
  • Write a C program to sort array using pointers .
  • Write a C program to return multiple value from function using pointers .
  • C Data Types
  • C Operators
  • C Input and Output
  • C Control Flow
  • C Functions
  • C Preprocessors
  • C File Handling
  • C Cheatsheet
  • C Interview Questions

Pointer Arithmetics in C with Examples

  • Applications of Pointers in C
  • Passing Pointers to Functions in C
  • C - Pointer to Pointer (Double Pointer)
  • Chain of Pointers in C with Examples
  • Function Pointer in C
  • How to declare a pointer to a function?
  • Pointer to an Array | Array Pointer
  • Difference between constant pointer, pointers to constant, and constant pointers to constants
  • Pointer vs Array in C
  • NULL Pointer in C
  • Dangling, Void , Null and Wild Pointers in C
  • Near, Far and Huge Pointers in C
  • restrict keyword in C

Pointer Arithmetic is the set of valid arithmetic operations that can be performed on pointers. The pointer variables store the memory address of another variable. It doesn’t store any value. 

Hence, there are only a few operations that are allowed to perform on Pointers in C language. The C pointer arithmetic operations are slightly different from the ones that we generally use for mathematical calculations. These operations are:

  • Increment/Decrement of a Pointer
  • Addition of integer to a pointer
  • Subtraction of integer to a pointer
  • Subtracting two pointers of the same type
  • Comparison of pointers

1. Increment/Decrement of a Pointer

Increment: It is a condition that also comes under addition. When a pointer is incremented, it actually increments by the number equal to the size of the data type for which it is a pointer. 

For Example: If an integer pointer that stores address 1000 is incremented, then it will increment by 4( size of an int ), and the new address will point to 1004 . While if a float type pointer is incremented then it will increment by 4( size of a float ) and the new address will be 1004 .

Decrement: It is a condition that also comes under subtraction. When a pointer is decremented, it actually decrements by the number equal to the size of the data type for which it is a pointer. 

For Example: If an integer pointer that stores address 1000 is decremented, then it will decrement by 4( size of an int ), and the new address will point to 996 . While if a float type pointer is decremented then it will decrement by 4( size of a float ) and the new address will be 996 .

pointer increment and decrement

Note: It is assumed here that the architecture is 64-bit and all the data types are sized accordingly. For example, integer is of 4 bytes.

Example of Pointer Increment and Decrement

Below is the program to illustrate pointer increment/decrement:

Note: Pointers can be outputted using %p, since, most of the computers store the address value in hexadecimal form using %p gives the value in that form. But for simplicity and understanding we can also use %u to get the value in Unsigned int form.

2. Addition of Integer to Pointer

When a pointer is added with an integer value, the value is first multiplied by the size of the data type and then added to the pointer.

For Example: Consider the same example as above where the ptr is an integer pointer that stores 1000 as an address. If we add integer 5 to it using the expression, ptr = ptr + 5, then, the final address stored in the ptr will be ptr = 1000 + sizeof(int) * 5 = 1020.

pointer addition

Example of Addition of Integer to Pointer

3. subtraction  of integer to pointer.

When a pointer is subtracted with an integer value, the value is first multiplied by the size of the data type and then subtracted from the pointer similar to addition.

For Example: Consider the same example as above where the ptr is an integer pointer that stores 1000 as an address. If we subtract integer 5 from it using the expression, ptr = ptr – 5, then, the final address stored in the ptr will be ptr = 1000 – sizeof(int) * 5 = 980.

pointer substraction

Example of Subtraction of Integer from Pointer

Below is the program to illustrate pointer Subtraction:

4. Subtraction of Two Pointers

The subtraction of two pointers is possible only when they have the same data type. The result is generated by calculating the difference between the addresses of the two pointers and calculating how many bits of data it is according to the pointer data type. The subtraction of two pointers gives the increments between the two pointers. 

For Example:   Two integer pointers say ptr1(address:1000) and ptr2(address:1004) are subtracted. The difference between addresses is 4 bytes. Since the size of int is 4 bytes, therefore the increment between ptr1 and ptr2 is given by (4/4) = 1 .

Example of Subtraction of Two Pointer

Below is the implementation to illustrate the Subtraction of Two Pointers:

5. Comparison of Pointers

We can compare the two pointers by using the comparison operators in C. We can implement this by using all operators in C >, >=, <, <=, ==, !=.   It returns true for the valid condition and returns false for the unsatisfied condition. 

  • Step 1: Initialize the integer values and point these integer values to the pointer.
  • Step 2: Now, check the condition by using comparison or relational operators on pointer variables.
  • Step 3: Display the output.

Example of Pointer Comparision

Comparison to null.

A pointer can be compared or assigned a NULL value irrespective of what is the pointer type. Such pointers are called NULL pointers and are used in various pointer-related error-handling methods.

Comparison operators on Pointers using an array

In the below approach, it results in the count of odd numbers and even numbers in an array. We are going to implement this by using a pointer.

  • Step 1: First, declare the length of an array and array elements.
  • Step 2: Declare the pointer variable and point it to the first element of an array.
  • Step 3: Initialize the count_even and count_odd. Iterate the for loop and check the conditions for the number of odd elements and even elements in an array
  • Step 4: Increment the pointer location ptr++ to the next element in an array for further iteration.
  • Step 5: Print the result.

Example of Pointer Comparison in Array

Pointer arithmetic on arrays.

Pointers contain addresses. Adding two addresses makes no sense because there is no idea what it would point to. Subtracting two addresses lets you compute the offset between the two addresses. An array name acts like a pointer constant. The value of this pointer constant is the address of the first element.

For Example: if an array is named arr then arr and &arr[0] can be used to reference the array as a pointer.

Below is the program to illustrate the Pointer Arithmetic on arrays:

Program 1:  

Program 2:  

Please Login to comment...

Similar reads.

  • C-Advanced Pointer
  • C-Pointer Basics
  • What are Tiktok AI Avatars?
  • Poe Introduces A Price-per-message Revenue Model For AI Bot Creators
  • Truecaller For Web Now Available For Android Users In India
  • Google Introduces New AI-powered Vids App
  • 30 OOPs Interview Questions and Answers (2024)

Improve your Coding Skills with Practice

 alt=

What kind of Experience do you want to share?

  • Skip to main content
  • Skip to primary sidebar
  • Skip to secondary sidebar
  • Skip to footer

Computer Notes

  • Computer Fundamental
  • Computer Memory
  • DBMS Tutorial
  • Operating System
  • Computer Networking
  • C Programming
  • C++ Programming
  • Java Programming
  • C# Programming
  • SQL Tutorial
  • Management Tutorial
  • Computer Graphics
  • Compiler Design
  • Style Sheet
  • JavaScript Tutorial
  • Html Tutorial
  • Wordpress Tutorial
  • Python Tutorial
  • PHP Tutorial
  • JSP Tutorial
  • AngularJS Tutorial
  • Data Structures
  • E Commerce Tutorial
  • Visual Basic
  • Structs2 Tutorial
  • Digital Electronics
  • Internet Terms
  • Servlet Tutorial
  • Software Engineering
  • Interviews Questions
  • Basic Terms
  • Troubleshooting

Header Right

How to pointer assignment and initialization in c.

By Dinesh Thakur

When we declare a pointer, it does not point to any specific variable. We must initialize it to point to the desired variable. This is achieved by assigning the address of that variable to the pointer variable, as shown below.

int a = 10;

pa = &a; /* pointer variable pa now points to variable a */

In this example, the first line declares an int variable named a and initializes it to 10. The second line declares a pointer pa of type pointer to int. Finally, the address of variable a is assigned to pa.Now pa is said to point to variable a.

We can also initialize a pointer when it is declared using the format given below.

type * ptr_var = init_expr ;

where init_expr is an expression that specifies the address of a previously defined variable of appropriate type or it can be NULL, a constant defined in the <stdio.h> header file.

Consider the example given below.

float x = 0.5;

float *px = &x;

int *p = NULL;

The second line declares a pointer variable px of type float * and initializes it with the address of variable x declared in the first line. Thus, pointer px now points to variable x. The third line declares pointer variable p of type int * and initializes it to NULL. Thus, pointer p does not point to any variable and it is an error to dereference such a pointer.

Note that a character pointer can be initialized using a character string constant as in

char *msg = “Hello, world!”;

Here, the C compiler allocates the required memory for the string constant (14 characters, in the above example, including the null terminator), stores the string constant in this memory and then assigns the initial address of this memory to pointer msg,as iliustrated in Fig.

pointer variable pointing to a string constant

The C language also permits initialization of more that one pointer variable in a single statement using the format shown below.

type *ptr_var1 = init_expr1, *ptr_var2 = init_expr2, … ;

It is also possible to mix the declaration and initialization of ordinary variables and pointers. However, we should avoid it to maintain program readability.

Example of Pointer Assignment and Initialization

char a= ‘A’;

char *pa = &a;

printf(“The address of character variable a: %p\n”, pa);

printf(“The address of pointer variable pa : %p\n”, &pa);

printf(“The value pointed by pointer variable pa: %c\n”, *pa);

Here, pa is a character pointer variable that is initialized with the address of character variable a defined in the first line. Thus, pa points to variable a. The first two printf statements print the address of variables a and pa using the %p (p for pointer) conversion. The last printf statement prints the value of a using the pointer variable pa. When the program containing this code is executed in Code::Blocks, the output is displayed as shown below. ·

The address of character variable a: 0022FF1F

The address of pointer variable pa : 0022FF18

The value pointed by pointer variable pa: A

Note that the addresses displayed in the output will usually be different depending on other variables declared in the program and the compiler/IDE used.

Another example is given below in which pointers are initialized with the addresses of variables of incompatible type.

char c = ‘Z’;

int i = 10;

float f = 1.1;

char *pcl = &i, *pc2 = &f;

int *pil = &c, *pi2 = &f;

float *pfl = &c, *pf2 = &i;

printf(“Character: %c %c\n”, *pcl, *pc2);

printf(“Integer : %d %d\n”, *pil, *pi2);

printf (“Float : %f %f\n”, =pfl, *pf2);

Note that the character pointer variables pcl and pc2 are initialized with the addresses of the int and float variables, respectively. Similarly, the int and float pointer variables are also initialized with addresses of variables of incompatible type. When the program containing this code is compiled in Code::Blocks, the compiler reports six warning messages (initialization from incompatible pointer type), one for each incompatible pointer initialization.

It is not a good idea to ignore such warnings associated with pointers. Although, the program executes in the presence of these warnings, it displays wrong results as shown below.

Integer : 90 1066192077

Float : 0.000000 0.000000

You’ll also like:

  • Write A C++ Program To Signify Importance Of Assignment (=) And Shorthand Assignment (+=) Operator.
  • Write C++ Example to illustrate two dimensional array implemented as pointer to a pointer.
  • Two-Dimensional Arrays Using a Pointer to Pointer
  • Declaration and Initialization of Pointers in C
  • Initialization of Two Dimensional Arrays Java

Dinesh Thakur

Dinesh Thakur is a Freelance Writer who helps different clients from all over the globe. Dinesh has written over 500+ blogs, 30+ eBooks, and 10000+ Posts for all types of clients.

For any type of query or something that you think is missing, please feel free to Contact us .

Basic Course

  • Database System
  • Management System
  • Electronic Commerce

Programming

  • Structured Query (SQL)
  • Java Servlet

World Wide Web

  • Java Script
  • HTML Language
  • Cascading Style Sheet
  • Java Server Pages

cropped-Learning-Monkey-Logo-1.jpg

Pointer Assignment

In this class, we will try to understand Pointer Assignment.

We have already discussed the basic concepts of pointer variables and indirection operators in or previous classes.

Table of Contents

The pointer variables of the same type can be assigned to each other.

Practice examples

We will try to understand the concept of pointer assignment by using the example, as shown in the image below.

Pointer Assignment Example 1

We have the visualization of each line of code with their respective images.

After executing the first line of code, the memory space for i, j, p, and q are created, as shown in the image below.

Pointer Assignment First Line Ex 1

In the second line of code, pointer p is assigned the address of i. Now p is pointing to ‘i’, as shown in the image below.

Pointer Assignment Second Line Ex 1

In the third line, the pointer variable p is assigned to q.

Here the assignment of the pointer is done where the value in p will get stored in q.

Now q will also point to ‘i’, as shown in the image below.

Pointer Assignment Third Line Ex 1

In the fourth line of code, using the indirection operator, i is assigned with 10, as shown in the image below.

Pointer Assignment Fourth Line Ex 1

In the fifth line of code, using the indirection operator, i is modified with 20, as shown in the image below.

Pointer Assignment Fifth Line Ex 1

The image below is the second example for practice.

Pointer Assignment Example 2

In the second and third lines of code, pointer p and pointer q are assigned the ‘address of’ i and, j respectively.

Pointer Assignment Second and Third Line Ex 2

In the fourth line, the variable i is assigned to 1.

Pointer Assignment Fourth Line Ex 2

In the fifth line, the value stored in the memory location where the pointer variable p is pointing is assigned to the pointer variable q using the indirection operator.

Pointer Assignment Fifth Line Ex 2

In the sixth line, the value stored in pointer variable p, the address 100, is assigned to the pointer variable q.

Now the pointer variable q is pointing to the new location, as shown in the image below.

Pointer Assignment Sixth Line Ex 2

In the seventh line of code, the value in the memory location to which the pointer variable q is pointing is updated to 2.

Pointer Assignment Seventh Line Ex 2

MarketSplash

What Is Pointers In C++ And How To Use It

Navigating memory management is a fundamental aspect of C++ programming, and pointers are at the core of this. In this article, we’ll explore the mechanics and usage of pointers in C++, from basic pointer operations to smart pointers, diving into real code examples to cement your understanding.

💡 KEY INSIGHTS

  • Understanding Smart Pointers is essential in modern C++ development, as they provide automatic memory management and prevent common pitfalls like memory leaks and dangling pointers.
  • The RAII (Resource Acquisition Is Initialization) principle is a powerful technique in C++ that simplifies resource management, ensuring timely cleanup and preventing resource leaks.
  • Shared Pointers facilitate efficient memory sharing among multiple objects, reducing memory overhead and enhancing program performance when dealing with shared data structures.
  • Leveraging Unique Pointers can enforce exclusive ownership of resources, preventing accidental resource duplication and ensuring safer and more robust code in C++ applications.

Pointers in C++ are a fundamental concept that can significantly enhance your coding capabilities. They allow for direct memory manipulation, making your programs more efficient and opening doors to advanced programming techniques. While pointers can seem complex at first, a clear understanding of how they work will become an invaluable tool in your programming toolbox.

pointer assignment in c programming

What Is Pointers In C++

Declaring and initializing pointers, pointer arithmetic and operations, pointers and arrays, pointers to functions, memory management with pointers, pointers and classes, common pointer mistakes and how to avoid them, smart pointers in c++, frequently asked questions, pointer initialization, syntax and indirection, pointers and function arguments.

A pointer in C++ is a variable that stores a memory address, serving as a direct link to the value stored at that location. It functions as a gateway, allowing us to read and write to the memory locations it points to.

When declaring a pointer, it’s essential to initialize it , either to another pointer or to nullptr . This ensures it doesn't point to an arbitrary memory location, potentially leading to undefined behavior.

The * symbol serves a dual role; in declarations, it specifies a type is a pointer. When used in expressions, it acts as the dereference operator and accesses the value pointed to.

Pointers are often used as function arguments to allow functions to modify variables from the calling function. This is commonly termed as passing by reference .

Using pointers effectively can make your code more flexible and efficient. However, it is crucial to manage the memory pointers are associated with responsibly to avoid errors and undefined behavior.

Initializing Pointers

Pointer assignment.

To start working with pointers in C++, you first need to declare a pointer variable. This involves specifying the data type that the pointer is going to point to, followed by the asterisk symbol (*) before the pointer name.

Here, we have declared a pointer named 'ptr' that is intended to point to an integer. The data type of 'ptr' is "pointer to int".

After declaration, it’s important to initialize the pointer, either with the address of a variable or with the NULL value. Uninitialized pointers can lead to undefined behavior.

In this example, 'ptr' is a pointer that holds the address of the variable 'num'. The ampersand (&) is used to get the address of 'num'.

Alternatively, pointers can be initialized to NULL , which means they are pointing to no location. This is often a good practice, as it makes it clear that the pointer is not yet pointing to a valid location.

Initializing to 'NULL' is a way to signify that the pointer 'ptr' is not pointing to any memory location initially. In C++11 and later, you can also use 'nullptr' instead of 'NULL'.

Pointers can also be assigned to hold the address of a variable of the appropriate type at any time after their declaration.

Here, 'ptr' is assigned the address of 'num' after its declaration. Again, the ampersand (&) symbol is used to obtain the address of 'num'.

In C++, pointers can be manipulated using a set of specific arithmetic operations, often referred to as pointer arithmetic . These operations enable you to navigate through memory, making pointers a powerful tool for array manipulation and data handling.

Basic Pointer Operations

Subtracting pointers, comparing pointers.

The basic arithmetic operations for pointers include increment ( ++ ), decrement ( -- ), addition ( + ), and subtraction ( - ).

In this example, 'ptr' initially points to the first element of 'arr'. After the increments, it points to the third element (which holds the value '40').

You can subtract two pointers of the same type to find the offset between them. This is useful when you need to calculate the distance between two elements in an array.

Here, 'distance' will hold the value '4', which represents the number of elements between 'start' and 'end'.

Pointers can also be compared using relational operators ( < , > , == , != , <= , >= ). This is useful for checking the positions of two pointers relative to each other.

This condition checks whether 'ptr1' and 'ptr2' are pointing to the same memory location.

It is important to remember that pointer arithmetic is only valid among pointers that point to elements of the same array , or one past the last element of that array. Attempting to perform arithmetic with pointers that don't satisfy this can lead to undefined behavior.

Accessing Array Elements With Pointers

Using pointers to traverse arrays, pointer arithmetic vs array indexing, pointers and multidimensional arrays.

In C++, arrays and pointers are closely related. An array name essentially acts as a constant pointer to the first element of the array. This relationship is fundamental in understanding how to navigate arrays using pointers.

Instead of using array indices, you can use pointer arithmetic to access elements of an array. Incrementing a pointer moves it to the next array element, while decrementing moves it to the previous element.

After this sequence of operations, 'ptr' points to the fourth element of 'arr', which is '4'.

You can use pointers to loop through an array, similar to how you would use an index with a traditional loop.

This loop uses 'ptr' to traverse the array. The loop prints each element of 'arr', outputting "1 2 3 4 5".

While array indexing is more common and usually more readable, pointer arithmetic can be more efficient because it often involves fewer machine instructions.

Both of these lines set the variable (value1 or value2) to the fourth element of 'arr'. They are equivalent operations.

For multidimensional arrays , pointers can also be used to navigate through the elements. In a 2D array, for example, you need a pointer to a pointer to traverse the array.

Here, 'ptr' is a pointer to an array of 3 integers. It points to the first "row" of 'arr'. You can move it to the next row with 'ptr++'.

It is important to use pointers correctly when working with arrays, ensuring you stay within the bounds of the array, to avoid undefined behavior and potential program crashes.

pointer assignment in c programming

More about arrays

Declaring Pointers To Functions

Assigning a function to a pointer, calling a function through a pointer, using function pointers as parameters.

In C++, you can have pointers to functions , allowing functions to be passed as parameters to other functions, stored in data structures, and returned from other functions, much like other data types. This enables a high degree of code reusability and can be used to implement callback functions, table of functions, and more.

To declare a pointer to a function , you need to specify the function’s return type, followed by an asterisk, and then the name of the pointer variable, along with the parameter types of the function.

Here, 'functionPtr' is a pointer to a function that takes an integer and a double as parameters and returns no value (void).

To assign a function to a function pointer , you simply use the name of the function without parentheses.

'exampleFunction' is assigned to the function pointer 'functionPtr'. Note that we are not calling 'exampleFunction'; we are just assigning its address to 'functionPtr'.

Once a function is assigned to a pointer, you can call the function using the pointer in the same way you would call the function directly.

This line of code calls 'exampleFunction' through the 'functionPtr' with arguments '5' and '3.14'. It’s equivalent to calling 'exampleFunction(5, 3.14);' directly.

images

“Learning to write programs stretches your mind, and helps you think better, creates a way of thinking about things that I think is helpful in all domains.

Source: Udacity

Function pointers can also be passed as parameters to other functions , enabling callbacks and higher-order functions.

In this example, 'applyFunction' is a function that takes two parameters, as well as a function pointer 'func'. It calls the function pointed to by 'func' with the provided parameters.

Using pointers to functions can make your code more modular and enable you to use functions as first-class citizens, similar to objects and basic types, thereby facilitating more dynamic and flexible programming designs.

In C++, pointers play a crucial role in memory management . They allow you to have direct control over memory allocation and deallocation. This low-level control is a double-edged sword: it can lead to efficient use of memory, but also to issues like memory leaks and undefined behavior if not used carefully.

Here, 'ptr' is a pointer to an int allocated on the heap. We then store the value '42' in this memory location.

After calling delete , the memory is freed, and 'ptr' should be set to nullptr to avoid undefined behavior.

This code snippet creates a dynamic array of '5' integers and then deallocates the memory.

In this code, if the allocation of a large block of memory fails, a std::bad_alloc exception is caught and an error message is printed.

Here, 'smartPtr' is a std::unique_ptr that takes ownership of a dynamically allocated int . When 'smartPtr' goes out of scope, it automatically deletes the managed memory.

Using smart pointers is a modern and safer approach to memory management in C++, as they help in reducing the risk of memory leaks by ensuring that memory is deallocated when it is no longer needed.

In C++, pointers can be used with classes to create dynamic instances of classes, to implement polymorphic behavior, and to optimize performance by avoiding unnecessary copying of objects. Working with pointers to classes is a fundamental concept, especially when designing complex data structures and systems.

Creating Dynamic Objects

Accessing members via pointers, deleting dynamic objects, pointers and polymorphism, smart pointers and classes.

Using the new operator , you can allocate memory for an instance of a class on the heap, which returns a pointer to the object .

Here, 'objPtr' is a pointer to an object of 'MyClass'. This object is dynamically allocated and initialized with '5'.

To access class members via a pointer to a class object , the arrow operator -> is used.

In this example, we are accessing the 'x' member of the 'MyClass' object pointed to by 'objPtr' and setting it to '10'.

When a class object is created dynamically, it is crucial to release the allocated memory using the delete operator .

After this, the memory used by the object is released, and 'objPtr' is set to nullptr to avoid a dangling pointer.

One of the powerful uses of pointers in C++ is to achieve polymorphism . Using base class pointers , you can point to objects of derived classes.

In this example, 'bPtr' is a pointer of type 'Base', but it is pointing to an object of type 'Derived'. The show function of 'Derived' class is called, demonstrating polymorphism.

Smart pointers , like std::unique_ptr and std::shared_ptr , can also be used with class objects to manage their lifetimes automatically.

Here, 'smartObjPtr' is a std::unique_ptr that takes ownership of a dynamically allocated 'MyClass' object. When 'smartObjPtr' goes out of scope, it automatically deletes the managed object.

Using pointers in conjunction with classes enables advanced programming techniques like polymorphism and dynamic object creation, which are central in object-oriented programming in C++.

Uninitialized pointers can point to random memory locations. Always initialize pointers, either to a valid address or to nullptr .

In the code above, 'p' is an uninitialized pointer, and dereferencing it results in undefined behavior. Initialize 'p' to nullptr or a valid address to avoid this.

In this example, we first check if 'ptr' is not nullptr before attempting to dereference it. This avoids null pointer dereferencing.

Above, we allocate an array of integers dynamically and later release the memory using delete[] . Failing to delete 'arr' would result in a memory leak.

Here, after deleting 'p', we set it to `nullptr'. This avoids a dangling pointer, as 'p' no longer points to an undefined memory location.

In this code, 'ptr' moves outside of 'arr', which is dangerous. Always ensure that pointer arithmetic stays within array bounds.

In this example, 'x' is deleted twice, which is not allowed. Ensure that each new operation has exactly one corresponding delete operation.

pointer assignment in c programming

Common pointer mistakes can lead to serious bugs. Being mindful of these issues and adopting good practices, such as using smart pointers and consistently checking for nullptr before dereferencing, can significantly reduce these risks.

Smart pointers are a modern C++ feature that manage the memory of their underlying objects, helping to avoid common memory management errors. They automatically release memory when no longer needed.

Here, unique_ptr takes ownership of a dynamically allocated int , while shared_ptr is initialized using make_shared . Memory is automatically released when these pointers go out of scope.

std::unique_ptr is a unique pointer that takes ownership of a dynamically allocated object. When the unique_ptr goes out of scope, it deletes its underlying object .

The unique_ptr 'uptr' owns its int object and cannot be copied. When 'uptr' goes out of scope, the memory is released automatically.

std::shared_ptr is a shared pointer that allows multiple shared_ptr instances to share ownership of an object. The object is deleted when the last owning shared_ptr is destroyed .

Here, 'sptr1' and 'sptr2' share ownership of an int . The int is deleted only after both 'sptr1' and 'sptr2' are destroyed.

std::weak_ptr is a weak pointer that observes an object owned by shared_ptr , but doesn't prevent its destruction. It’s useful to break circular references between shared_ptr instances.

Here, 'wk_ptr' is a weak_ptr observing an int owned by 'sh_ptr'. It does not extend the lifetime of the int object.

You can convert a weak_ptr to a shared_ptr to temporarily gain shared ownership of the object.

In this code, 'wk_ptr.lock()' creates a shared_ptr (here 'temp_sptr') from 'wk_ptr'. It’s essential to check for nullptr before using 'temp_sptr' to ensure the object is still alive.

How Do Smart Pointers Avoid Memory Leaks?

Smart pointers automatically delete their underlying objects when those objects are no longer needed. This ensures that the memory occupied by these objects is released, effectively preventing memory leaks that can occur due to manual memory management.

When Should I Use std::unique_ptr ?

Use std::unique_ptr when you want a single owner for a dynamically allocated object. It’s perfect when you want to ensure that only one pointer has the responsibility to delete the object it points to, which happens automatically when the std::unique_ptr goes out of scope.

Can I Copy a std::unique_ptr ?

No, std::unique_ptr instances cannot be copied, because they are designed to have sole ownership of their managed object. However, you can move a std::unique_ptr , transferring ownership from one to another.

When Should I Use std::shared_ptr ?

Use std::shared_ptr when you want multiple pointers to share ownership of a dynamically allocated object. When the last shared_ptr that owns the object is destroyed or reset, the object is automatically deleted.

When and Why Should I Use std::weak_ptr ?

Use std::weak_ptr when you want to observe an object owned by a shared_ptr , but you don’t want to extend the object’s lifetime. This is useful for avoiding circular references that can lead to memory leaks with shared_ptr .

Let’s test your knowledge!

Which of the following is used to declare a pointer in C++?

Continue Learning With These C++ Guides

  • C++ Setlist: What It Is And How To Use It
  • What Is C++ Iterators And How To Use It
  • C++ Deque And Its Efficient Applications
  • What Is Class C++: Functions And Implementation
  • Understanding And Implementing Sort C++ In Your Code

Subscribe to our newsletter

Subscribe to be notified of new content on marketsplash..

IMAGES

  1. C Pointers

    pointer assignment in c programming

  2. Pointer Expressions in C with Examples

    pointer assignment in c programming

  3. Unlock the Mysteries of Pointers in C

    pointer assignment in c programming

  4. Pointer Expressions in C with Examples

    pointer assignment in c programming

  5. Pointer Expressions in C with Examples

    pointer assignment in c programming

  6. Introduction to Pointers in C

    pointer assignment in c programming

VIDEO

  1. 1. Introduction to Pointers in C

  2. Pointer Programming in C

  3. POINTER 01: C PROGRAMMING

  4. Pointer Concept in C programming Language

  5. What are Pointers? How to Use Them? and How they can Improve your C++ Programming Skills

  6. Programming in C Pointer to a Function

COMMENTS

  1. C Pointers (With Examples)

    Explanation of the program. int* pc, c; Here, a pointer pc and a normal variable c, both of type int, is created. Since pc and c are not initialized at initially, pointer pc points to either no address or a random address. And, variable c has an address but contains random garbage value.; c = 22; This assigns 22 to the variable c.That is, 22 is stored in the memory location of variable c.

  2. Directly assigning values to C Pointers

    You need to create an int variable somewhere in memory for the int * variable to point at. Your second example does this, but it does other things that aren't relevant here. Here's the simplest thing you need to do: int main(){. int variable; int *ptr = &variable; *ptr = 20; printf("%d", *ptr); return 0;

  3. C Pointers

    Comparison of pointers of the same type. Assignment of pointers of the same type. C // C program to illustrate Pointer Arithmetic #include <stdio.h> int main () ... In C programming language, pointers and arrays are closely related. An array name acts like a pointer constant. The value of this pointer constant is the address of the first element.

  4. How C-Pointers Works: A Step-by-Step Beginner's Tutorial

    We then use an if statement to check if the pointer is NULL. Since it is, the program will print "The pointer is NULL." This illustrates how NULL pointers are commonly used to check if a pointer has been initialized or assigned a valid memory address. conclusion: You've embarked on a comprehensive journey through the intricacies of C pointers.

  5. How to Use Pointers in C Programming

    How to Declare a Pointer. To declare a pointer variable in C, we use the asterisk * symbol before the variable name. There are two ways to declare pointer variables in C: int *p; int* p; Both of these declarations are equivalent and they declare a pointer variable named "p" that can hold the memory address of an integer.

  6. Pointer Expressions in C with Examples

    When we need to initialize a pointer with variable's location, we use ampersand sign (&) before the variable name. Example: C. int var=10; int *pointer=&var; The ampersand (&) is used to get the address of a variable. We can directly find the location of any identifier by just preceding it with an ampersand (&) sign.

  7. C Pointers

    Good To Know: There are two ways to declare pointer variables in C: int* myNum; int *myNum; Notes on Pointers. Pointers are one of the things that make C stand out from other programming languages, like Python and Java. They are important in C, because they allow us to manipulate the data in the computer's memory.

  8. (Almost) Everything You Need To Know About Pointers in C

    char *pa = &a; // pa now contains the address of a. printf("%p", pa); // %p is the format specifier to print a pointer. If you run this program, you will see something like 0x7ffc2fc4ff27. That is the value of the pointer, which is the address of the variable a (this is in hexadecimal). This value is not fixed.

  9. Pointers in C Programming with examples

    By using * operator we can access the value of a variable through a pointer. For example: double a = 10; double *p; p = &a; *p would give us the value of the variable a. The following statement would display 10 as output. printf("%d", *p); Similarly if we assign a value to *pointer like this: *p = 200;

  10. Pointer in C Programming Language with Practical Examples

    Pointers can be initialized by assigning the memory address of a variable to them. The address-of operator (&) is used for this purpose. int var = 15; int *ptr = &var; Here, when we assign &var to a pointer variable ptr it stores the memory address ( 1001) of the variable. Now, we can indirectly manipulate data in the address 1001 through ptr.

  11. Pointers in C Explained

    4. Strings. A string is a one-dimensional array of characters terminated by a null(\0).When we write char name[] = "Srijan";, each character occupies one byte of memory with the last one always being \0.. Similar to the arrays we have seen, name and &name[0] points to the 0th character in the string, while &name points to the whole string. Also, name[i] can be written as *(name + i).

  12. Pointers in C

    The general form of a pointer variable declaration is −. type * var - name; Here, type is the pointer's base type; it must be a valid C data type and var-name is the name of the pointer variable. The asterisk * used to declare a pointer is the same asterisk used for multiplication.

  13. Pointer Assignment

    C Programming: Pointer Assignment in C Programming.Topics discussed:1) Assigning the content of one pointer to another pointer.2) q = p VS *q = *pC Programmi...

  14. Pointer programming exercises and solutions in C

    List of pointer programming exercises. Write a C program to create, initialize and use pointers. Write a C program to add two numbers using pointers. Write a C program to swap two numbers using pointers. Write a C program to input and print array elements using pointer. Write a C program to copy one array to another using pointers.

  15. Pointer Arithmetics in C with Examples

    Step 1: First, declare the length of an array and array elements. Step 2: Declare the pointer variable and point it to the first element of an array. Step 3: Initialize the count_even and count_odd. Iterate the for loop and check the conditions for the number of odd elements and even elements in an array.

  16. How to Pointer Assignment and Initialization in C

    This is achieved by assigning the address of that variable to the pointer variable, as shown below. int a = 10; int *pa; pa = &a; /* pointer variable pa now points to variable a */. In this example, the first line declares an int variable named a and initializes it to 10. The second line declares a pointer pa of type pointer to int.

  17. Pointer Assignment

    Pointer Assignment Example 2. After executing the first line of code, the memory space for i, j, p, and q are created, as shown in the image below. First Line Ex 2. In the second and third lines of code, pointer p and pointer q are assigned the 'address of' i and, j respectively. Second and Third Line Ex 2. In the fourth line, the variable ...

  18. Pointer Assignment in C

    Notes for You:: Pointer Assignment in C.- A pointer variable can be assigned with the address of another memory location or NULL.- If 2 pointer variables are...

  19. c

    However, this returns a char. So your assignment. cString1 = strToLower(cString1); has different types on each side of the assignment operator .. you're actually assigning a 'char' (sort of integer) to an array, which resolves to a simple pointer. Due to C++'s implicit conversion rules this works, but the result is rubbish and further access to ...

  20. What Is Pointers In C++ And How To Use It

    Navigating memory management is a fundamental aspect of C++ programming, and pointers are at the core of this. In this article, we'll explore the mechanics and usage of pointers in C++, from basic pointer operations to smart pointers, diving into real code examples to cement your understanding. ... Pointer Assignment. Pointers can also be ...

  21. C pointers and arrays: [Warning] assignment makes pointer from integer

    In this case a[4] is the 5th integer in the array a, ap is a pointer to integer, so you are assigning an integer to a pointer and that's the warning. So ap now holds 45 and when you try to de-reference it (by doing *ap) you are trying to access a memory at address 45, which is an invalid address, so your program crashes.. You should do ap = &(a[4]); or ap = a + 4;