- C++ Language
- Ascii Codes
- Boolean Operations
- Numerical Bases
Basics of c++.
- Structure of a program
- Variables and types
- Basic Input/Output
- Statements and flow control
- Overloads and templates
- Name visibility
Compound data types
- Character sequences
- Dynamic memory
- Data structures
- Other data types
- Classes (I)
- Classes (II)
- Special members
- Friendship and inheritance
Other language features
- Type conversions
- Preprocessor directives
- Input/output with files
Address-of operator (&)
Dereference operator (*)
- & is the address-of operator , and can be read simply as "address of"
- * is the dereference operator , and can be read as "value pointed to by"
Pointers and arrays, pointer initialization, pointer arithmetics.
Pointers and const
Pointers and string literals.
Pointers to pointers
- c is of type char** and a value of 8092
- *c is of type char* and a value of 7230
- **c is of type char and a value of 'z'
Invalid pointers and null pointers, pointers to functions.
Declares a variable of a pointer or pointer-to-member type.
[ edit ] Syntax
A pointer declaration is any simple declaration whose declarator has the form
There are no pointers to references and there are no pointers to bit-fields . Typically, mentions of "pointers" without elaboration do not include pointers to (non-static) members.
[ edit ] Pointers
Every value of pointer type is one of the following:
- a pointer to an object or function (in which case the pointer is said to point to the object or function), or
- a pointer past the end of an object , or
- the null pointer value for that type, or
- an invalid pointer value .
A pointer that points to an object represents the address of the first byte in memory occupied by the object. A pointer past the end of an object represents the address of the first byte in memory after the end of the storage occupied by the object.
Note that two pointers that represent the same address may nonetheless have different values.
Indirection through an invalid pointer value and passing an invalid pointer value to a deallocation function have undefined behavior. Any other use of an invalid pointer value has implementation-defined behavior. Some implementations might define that copying an invalid pointer value causes a system-generated runtime fault.
[ edit ] Pointers to objects
A pointer to object can be initialized with the return value of the address-of operator applied to any expression of object type, including another pointer type:
Pointers may appear as operands to the built-in indirection operator (unary operator * ), which returns the lvalue expression identifying the pointed-to object:
Pointers to class objects may also appear as the left-hand operands of the member access operators operator-> and operator->* .
Because of the array-to-pointer implicit conversion, pointer to the first element of an array can be initialized with an expression of array type:
Because of the derived-to-base implicit conversion for pointers, pointer to a base class can be initialized with the address of a derived class:
If Derived is polymorphic , such a pointer may be used to make virtual function calls .
Certain addition, subtraction , increment, and decrement operators are defined for pointers to elements of arrays: such pointers satisfy the LegacyRandomAccessIterator requirements and allow the C++ library algorithms to work with raw arrays.
Comparison operators are defined for pointers to objects in some situations: two pointers that represent the same address compare equal, two null pointer values compare equal, pointers to elements of the same array compare the same as the array indexes of those elements, and pointers to non-static data members with the same member access compare in order of declaration of those members.
Many implementations also provide strict total ordering of pointers of random origin, e.g. if they are implemented as addresses within continuous virtual address space. Those implementations that do not (e.g. where not all bits of the pointer are part of a memory address and have to be ignored for comparison, or an additional calculation is required or otherwise pointer and integer is not a 1 to 1 relationship), provide a specialization of std::less for pointers that has that guarantee. This makes it possible to use all pointers of random origin as keys in standard associative containers such as std::set or std::map .
[ edit ] Pointers to void
Pointer to object of any type can be implicitly converted to pointer to void (optionally cv-qualified ); the pointer value is unchanged. The reverse conversion, which requires static_cast or explicit cast , yields the original pointer value:
If the original pointer is pointing to a base class subobject within an object of some polymorphic type, dynamic_cast may be used to obtain a void * that is pointing at the complete object of the most derived type.
Pointers to void have the same size, representation and alignment as pointers to char .
Pointers to void are used to pass objects of unknown type, which is common in C interfaces: std::malloc returns void * , std::qsort expects a user-provided callback that accepts two const void * arguments. pthread_create expects a user-provided callback that accepts and returns void * . In all cases, it is the caller's responsibility to cast the pointer to the correct type before use.
[ edit ] Pointers to functions
A pointer to function can be initialized with an address of a non-member function or a static member function. Because of the function-to-pointer implicit conversion, the address-of operator is optional:
Unlike functions or references to functions, pointers to functions are objects and thus can be stored in arrays, copied, assigned, etc.
Note: declarations involving pointers to functions can often be simplified with type aliases:
A pointer to function can be used as the left-hand operand of the function call operator , this invokes the pointed-to function:
Dereferencing a function pointer yields the lvalue identifying the pointed-to function:
A pointer to function may be initialized from an overload set which may include functions, function template specializations, and function templates, if only one overload matches the type of the pointer (see address of an overloaded function for more detail):
Equality comparison operators are defined for pointers to functions (they compare equal if pointing to the same function).
[ edit ] Pointers to members
[ edit ] pointers to data members.
A pointer to non-static member object m which is a member of class C can be initialized with the expression & C :: m exactly. Expressions such as & ( C :: m ) or & m inside C 's member function do not form pointers to members.
Such a pointer may be used as the right-hand operand of the pointer-to-member access operators operator. * and operator - > * :
Pointer to data member of an accessible unambiguous non-virtual base class can be implicitly converted to pointer to the same data member of a derived class:
Conversion in the opposite direction, from a pointer to data member of a derived class to a pointer to data member of an unambiguous non-virtual base class, is allowed with static_cast and explicit cast , even if the base class does not have that member (but the most-derived class does, when the pointer is used for access):
The pointed-to type of a pointer-to-member may be a pointer-to-member itself: pointers to members can be multilevel, and can be cv-qualified differently at every level. Mixed multi-level combinations of pointers and pointers-to-members are also allowed:
[ edit ] Pointers to member functions
A pointer to non-static member function f which is a member of class C can be initialized with the expression & C :: f exactly. Expressions such as & ( C :: f ) or & f inside C 's member function do not form pointers to member functions.
Such a pointer may be used as the right-hand operand of the pointer-to-member access operators operator. * and operator - > * . The resulting expression can be used only as the left-hand operand of a function-call operator:
Pointer to member function of a base class can be implicitly converted to pointer to the same member function of a derived class:
Conversion in the opposite direction, from a pointer to member function of a derived class to a pointer to member function of an unambiguous non-virtual base class, is allowed with static_cast and explicit cast , even if the base class does not have that member function (but the most-derived class does, when the pointer is used for access):
Pointers to member functions may be used as callbacks or as function objects, often after applying std::mem_fn or std::bind :
[ edit ] Null pointers
Pointers of every type have a special value known as null pointer value of that type. A pointer whose value is null does not point to an object or a function (the behavior of dereferencing a null pointer is undefined), and compares equal to all pointers of the same type whose value is also null .
To initialize a pointer to null or to assign the null value to an existing pointer, the null pointer literal nullptr , the null pointer constant NULL , or the implicit conversion from the integer literal with value 0 may be used.
Zero- and value-initialization also initialize pointers to their null values.
Null pointers can be used to indicate the absence of an object (e.g. std::function::target() ), or as other error condition indicators (e.g. dynamic_cast ). In general, a function that receives a pointer argument almost always needs to check if the value is null and handle that case differently (for example, the delete expression does nothing when a null pointer is passed).
[ edit ] Constness
- If cv appears before * in the pointer declaration, it is part of decl-specifier-seq and applies to the pointed-to object.
- If cv appears after * in the pointer declaration, it is part of declarator and applies to the pointer that's being declared.
In general, implicit conversion from one multi-level pointer to another follows the rules described in qualification conversions and in pointer comparison operators .
[ edit ] Defect reports
The following behavior-changing defect reports were applied retroactively to previously published C++ standards.
[ edit ] See also
- Recent changes
- Offline version
- What links here
- Related changes
- Upload file
- Special pages
- Printable version
- Permanent link
- Page information
- In other languages
- This page was last modified on 2 October 2023, at 23:38.
- This page has been accessed 572,955 times.
- About cppreference.com
Learn C practically and Get Certified .
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 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
- 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.
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
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; ?
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.
12.9 — Pointers and const
Consider the following code snippet:
With normal (non-const) pointers, we can change both what the pointer is pointing at (by assigning the pointer a new address to hold) or change the value at the address being held (by assigning a new value to the dereferenced pointer).
However, what happens if the value we want to point at is const?
The above snippet won’t compile -- we can’t set a normal pointer to point at a const variable. This makes sense: a const variable is one whose value cannot be changed. Allowing the programmer to set a non-const pointer to a const value would allow the programmer to dereference the pointer and change the value. That would violate the const-ness of the variable.
Pointer to const value
A pointer to a const value (sometimes called a pointer to const for short) is a (non-const) pointer that points to a constant value.
To declare a pointer to a const value, use the const keyword before the pointer’s data type:
In the above example, ptr points to a const int . Because the data type being pointed to is const, the value being pointed to can’t be changed.
However, because a pointer to const is not const itself (it just points to a const value), we can change what the pointer is pointing at by assigning the pointer a new address:
Just like a reference to const, a pointer to const can point to non-const variables too. A pointer to const treats the value being pointed to as constant, regardless of whether the object at that address was initially defined as const or not:
We can also make a pointer itself constant. A const pointer is a pointer whose address can not be changed after initialization.
To declare a const pointer, use the const keyword after the asterisk in the pointer declaration:
In the above case, ptr is a const pointer to a (non-const) int value.
Just like a normal const variable, a const pointer must be initialized upon definition, and this value can’t be changed via assignment:
However, because the value being pointed to is non-const, it is possible to change the value being pointed to via dereferencing the const pointer:
Const pointer to a const value
Finally, it is possible to declare a const pointer to a const value by using the const keyword both before the type and after the asterisk:
A const pointer to a const value can not have its address changed, nor can the value it is pointing to be changed through the pointer. It can only be dereferenced to get the value it is pointing at.
Pointer and const recap
To summarize, you only need to remember 4 rules, and they are pretty logical:
- A non-const pointer can be assigned another address to change what it is pointing at.
- A const pointer always points to the same address, and this address can not be changed.
- A pointer to a non-const value can change the value it is pointing to. These can not point to a const value.
- A pointer to a const value treats the value as const when accessed through the pointer, and thus can not change the value it is pointing to. These can be pointed to const or non-const l-values (but not r-values, which don’t have an address).
Keeping the declaration syntax straight can be a bit challenging:
- A const before the asterisk is associated with the type being pointed to. Therefore, this is a pointer to a const value, and the value cannot be modified through the pointer.
- A const after the asterisk is associated with the pointer itself. Therefore, this pointer cannot be assigned a new address.
- C Data Types
- C Operators
- C Input and Output
- C Control Flow
- C Functions
- C Preprocessors
- C File Handling
- C Cheatsheet
- C Interview Questions
- Explore Our Geeks Community
- Pointer Arithmetics in C with Examples
- Applications of Pointers in C/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
- Near, Far and Huge Pointers in C
- restrict keyword in C
Pointers are one of the core components of the C programming language. A pointer can be used to store the memory address of other variables, functions, or even other pointers. The use of pointers allows low-level memory access, dynamic memory allocation, and many other functionality in C.
In this article, we will discuss C pointers in detail, their types, uses, advantages, and disadvantages with examples.
What is a Pointer in C?
A pointer is defined as a derived data type that can store the address of other C variables or a memory location. We can access and manipulate the data stored in that memory location using pointers.
As the pointers in C store the memory addresses, their size is independent of the type of data they are pointing to. This size of pointers in C only depends on the system architecture.
Syntax of C Pointers
The syntax of pointers is similar to the variable declaration in C, but we use the ( * ) dereferencing operator in the pointer declaration.
- ptr is the name of the pointer.
- datatype is the type of data it is pointing to.
The above syntax is used to define a pointer to a variable. We can also define pointers to functions, structures, etc.
How to Use Pointers?
The use of pointers in C can be divided into three steps:
- Pointer Declaration
- Pointer Initialization
- Pointer Dereferencing
1. Pointer Declaration
In pointer declaration, we only declare the pointer but do not initialize it. To declare a pointer, we use the ( * ) dereference operator before its name.
The pointer declared here will point to some random memory address as it is not initialized. Such pointers are called wild pointers.
2. Pointer Initialization
Pointer initialization is the process where we assign some initial value to the pointer variable. We generally use the ( & ) addressof operator to get the memory address of a variable and then store it in the pointer variable.
We can also declare and initialize the pointer in a single step. This method is called pointer definition as the pointer is declared and initialized at the same time.
Note: It is recommended that the pointers should always be initialized to some value before starting using it. Otherwise, it may lead to number of errors.
3. Pointer Dereferencing
Dereferencing a pointer is the process of accessing the value stored in the memory address specified in the pointer. We use the same ( * ) dereferencing operator that we used in the pointer declaration.
Dereferencing a Pointer in C
C Pointer Example
Types of pointers in c.
Pointers in C can be classified into many different types based on the parameter on which we are defining their types. If we consider the type of variable stored in the memory location pointed by the pointer, then the pointers can be classified into the following types:
1. Integer Pointers
As the name suggests, these are the pointers that point to the integer values.
These pointers are pronounced as Pointer to Integer.
Similarly, a pointer can point to any primitive data type. It can point also point to derived data types such as arrays and user-defined data types such as structures.
2. Array Pointer
Pointers and Array are closely related to each other. Even the array name is the pointer to its first element. They are also known as Pointer to Arrays . We can create a pointer to an array using the given syntax.
Pointer to Arrays exhibits some interesting properties which we discussed later in this article.
3. Structure Pointer
The pointer pointing to the structure type is called Structure Pointer or Pointer to Structure. It can be declared in the same way as we declare the other primitive data types.
In C, structure pointers are used in data structures such as linked lists, trees, etc.
4. Function Pointers
Function pointers point to the functions. They are different from the rest of the pointers in the sense that instead of pointing to the data, they point to the code. Let’s consider a function prototype – int func (int, char) , the function pointer for this function will be
Note: The syntax of the function pointers changes according to the function prototype.
5. Double Pointers
In C language, we can define a pointer that stores the memory address of another pointer. Such pointers are called double-pointers or pointers-to-pointer . Instead of pointing to a data value, they point to another pointer.
Dereferencing Double Pointer
Note: In C, we can create multi-level pointers with any number of levels such as – ***ptr3, ****ptr4, ******ptr5 and so on.
6. NULL Pointer
The Null Pointers are those pointers that do not point to any memory location. They can be created by assigning a NULL value to the pointer. A pointer of any type can be assigned the NULL value.
It is said to be good practice to assign NULL to the pointers currently not in use.
7. Void Pointer
The Void pointers in C are the pointers of type void. It means that they do not have any associated data type. They are also called generic pointers as they can point to any type and can be typecasted to any type.
One of the main properties of void pointers is that they cannot be dereferenced.
8. Wild Pointers
The Wild Pointers are pointers that have not been initialized with something yet. These types of C-pointers can cause problems in our programs and can eventually cause them to crash.
9. Constant Pointers
In constant pointers, the memory address stored inside the pointer is constant and cannot be modified once it is defined. It will always point to the same memory address.
10. Pointer to Constant
The pointers pointing to a constant value that cannot be modified are called pointers to a constant. Here we can only access the data pointed by the pointer, but cannot modify it. Although, we can change the address stored in the pointer to constant.
Other Types of Pointers in C:
There are also the following types of pointers available to use in C apart from those specified above:
- Far pointer : A far pointer is typically 32-bit that can access memory outside the current segment.
- Dangling pointer : A pointer pointing to a memory location that has been deleted (or freed) is called a dangling pointer.
- Huge pointer : A huge pointer is 32-bit long containing segment address and offset address.
- Complex pointer: Pointers with multiple levels of indirection.
- Near pointer : Near pointer is used to store 16-bit addresses means within the current segment on a 16-bit machine.
- Normalized pointer: It is a 32-bit pointer, which has as much of its value in the segment register as possible.
- File Pointer: The pointer to a FILE data type is called a stream pointer or a file pointer.
Size of Pointers in C
The size of the pointers in C is equal for every pointer type. The size of the pointer does not depend on the type it is pointing to. It only depends on the operating system and CPU architecture. The size of pointers in C is
- 8 bytes for a 64-bit System
- 4 bytes for a 32-bit System
The reason for the same size is that the pointers store the memory addresses, no matter what type they are. As the space required to store the addresses of the different memory locations is the same, the memory required by one pointer type will be equal to the memory required by other pointer types.
How to find the size of pointers in C?
We can find the size of pointers using the sizeof operator as shown in the following program:
Example: C Program to find the size of different pointer types.
As we can see, no matter what the type of pointer it is, the size of each and every pointer is the same.
Now, one may wonder that if the size of all the pointers is the same, then why do we need to declare the pointer type in the declaration? The type declaration is needed in the pointer for dereferencing and pointer arithmetic purposes.
C Pointer Arithmetic
The Pointer Arithmetic refers to the legal or valid arithmetic operations that can be performed on a pointer. It is slightly different from the ones that we generally use for mathematical calculations as only a limited set of operations can be performed on pointers. These operations include:
- Increment in a Pointer
- Decrement in a Pointer
- Addition of integer to a pointer
- Subtraction of integer to a pointer
- Subtracting two pointers of the same type
- Comparison of pointers of the same type.
- Assignment of pointers of the same type.
C Pointers and Arrays
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. For example, if we have an array named val then val and &val can be used interchangeably.
If we assign this value to a non-constant pointer of the same type, then we can access the elements of the array using this pointer.
Example 1: Accessing Array Elements using Pointer with Array Subscript
Not only that, as the array elements are stored continuously, we can pointer arithmetic operations such as increment, decrement, addition, and subtraction of integers on pointer to move between array elements.
Example 2: Accessing Array Elements using Pointer Arithmetic
This concept is not limited to the one-dimensional array, we can refer to a multidimensional array element as well using pointers.
To know more about pointers to an array, refer to this article – Pointer to an Array
Uses of Pointers in C
The C pointer is a very powerful tool that is widely used in C programming to perform various useful operations. It is used to achieve the following functionalities in C:
- Pass Arguments by Reference
- Accessing Array Elements
- Return Multiple Values from Function
- Dynamic Memory Allocation
- Implementing Data Structures
- In System-Level Programming where memory addresses are useful.
- In locating the exact value at some memory location.
- To avoid compiler confusion for the same variable name.
- To use in Control Tables.
Advantages of Pointers
Following are the major advantages of pointers in C:
- Pointers are used for dynamic memory allocation and deallocation.
- An Array or a structure can be accessed efficiently with pointers
- Pointers are useful for accessing memory locations.
- Pointers are used to form complex data structures such as linked lists, graphs, trees, etc.
- Pointers reduce the length of the program and its execution time as well.
Disadvantages of Pointers
Pointers are vulnerable to errors and have following disadvantages:
- Memory corruption can occur if an incorrect value is provided to pointers.
- Pointers are a little bit complex to understand.
- Pointers are majorly responsible for memory leaks in C .
- Pointers are comparatively slower than variables in C.
- Uninitialized pointers might cause a segmentation fault.
In conclusion, pointers in C are very capable tools and provide C language with its distinguishing features, such as low-level memory access, referencing, etc. But as powerful as they are, they should be used with responsibility as they are one of the most vulnerable parts of the language.
FAQs on Pointers in C
Q1. define pointers..
Pointers are the variables that can store the memory address of another variable.
Q2. What is the difference between a constant pointer and a pointer to a constant?
A constant pointer points to the fixed memory location, i.e. we cannot change the memory address stored inside the constant pointer. On the other hand, the pointer to a constant point to the memory with a constant value.
Q3. What is pointer to pointer?
A pointer to a pointer (also known as a double pointer) stores the address of another pointer.
Q4. Does pointer size depends on its type?
No, the pointer size does not depend upon its type. It only depends on the operating system and CPU architecture.
Q5. What are the differences between an array and a pointer?
The following table list the differences between an array and a pointer : Pointer Array A pointer is a derived data type that can store the address of other variables. An array is a homogeneous collection of items of any type such as int, char, etc. Pointers are allocated at run time. Arrays are allocated at runtime. The pointer is a single variable. An array is a collection of variables of the same type. Dynamic in Nature Static in Nature.
Q6. Why do we need to specify the type in the pointer declaration?
Type specification in pointer declaration helps the compiler in dereferencing and pointer arithmetic operations.
- Quiz on Pointer Basics
- Quiz on Advanced Pointer
Please Login to comment...
- Prasant Nair Cricket Research
Please write us at contrib[email protected] to report any issue with the above content
Improve your Coding Skills with Practice
Section 1 -- pointer rules, 1) pointers and pointees, 2) dereferencing, 3) pointer assignment, section 2 -- binky's code example, java version, c++ version, pascal version, section 3 -- study questions.
Pointers in C Explained – They're Not as Difficult as You Think
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.
- 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
- 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
- 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:
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.
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.
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.
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; .
Five consecutive blocks of memory starting from myArray to myArray are created with garbage values in them. Each of the blocks is of size 4 bytes.
Thus, if the address of myArray 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 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 by 1.
Wait! How come &prime + 1 results in something different than the other two? And why are prime + 1 and &prime + 1 still equal? Let's answer these questions.
prime and &prime 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 , 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 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 . 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 would have pointed to the 0th element. For a 2-D array, elements are now 1-D arrays . Hence, marks and &marks 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 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 points to the 0th element of the 0th array. Similarly, marks 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 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 , "Man City" in top , 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 and top 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 whereas ptrStudent2 is a pointer to the whole array of 10 struct records . Adding 1 to ptrStudent1 would point to student .
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
404 Not found
- Data Structure Algorithm
- Language Basics
- Macro Preprocessor
- Small Application
Assign an int value using a pointer : Pointer Int « Pointer « C / ANSI-C
- Pointer Int