A pointer in C language is a variable which holds the address of another variable of same data type. Pointers are used to access memory and manipulate the address.
Whenever a variable is defined, a memory allocation is assigned for it to hold the assigned value. We can easily check this memory address using the & symbol.
If var
is the name of the variable, then &var
will give its address.
#include <stdio.h>
int main() {
int var = 7;
printf("Value of the variable var is: %d\n", var);
printf("Memory address of the variable var is: %x\n", &var);
return 0;
}
; Like a variable, before using a pointer, you have to declare it. First, you specify the data type of the variable that the pointer point to. Second, you put an asterisk in front of the pointer name. Next you give the name for the pointer.
int *ptr;
To initialize a pointer, you assign the memory address of another variable to the pointer.
int a = 100;
int *ptr;
ptr = &a;
Once a pointer has been assigned the address of a variable, to access the value of the variable pointer, you use the indirection operator or dereferencing operator *
.
#include <stdio.h>
int main()
{
int a, *p; // declaring the variable and pointer
a = 10;
p = &a; // initializing the pointer
printf("value of a : %d", *p); //this will print the value of 'a'
printf("value of a : %d", *&a); //this will also print the value of 'a'
printf("address of a : %u", &a); //this will print the address of 'a'
printf("address of a : %u", p); //this will also print the address of 'a'
printf("address of p : %u", &p); //this will print the address of 'p'
return 0;
}
If you are not sure about which variable’s address to assign to a pointer variable while declaration, it is recommended to assign a NULL
variable to your pointer variable. A pointer which is assigned a NULL
value is called a NULL pointer.
#include <stdio.h>
int main()
{
int *ptr = NULL;
return 0;
}
Pointer to Pointer
When a pointer variable stores the address of another pointer variable, it’s known as Pointer to Pointer variable or Double Pointer.
#include <stdio.h>
int main()
{
int a = 10;
int *p1; // used to store the address of a variable
int **p2; // used to store the address of a variable pointer
p1 = &a;
p2 = &p1;
printf("Address of a = %u\n", &a);
printf("Address of p1 = %u\n", &p1);
printf("Address of p2 = %u\n\n", &p2);
// below print statement will give the address of 'a'
printf("Value at the address stored by p2 = %u\n", *p2);
printf("Value at the address stored by p1 = %d\n\n", *p1);
printf("Value of **p2 = %d\n", **p2); // read this *(*p2)
return 0;
}
Pointer to Array
We can use a pointer to point to an array, and then we can use that pointer to access the array elements.
#include <stdio.h>
int main()
{
int i;
int a[5] = {1, 2, 3, 4, 5};
int *p = a; // same as int *p = &a[0]
for (i = 0; i < 5; i++)
{
printf("%d", *p);
p++;
}
return 0;
}
The generalized form for using pointer with an array *(a+i)
is the same as a[i]
.
The generalized form for using pointer with multidimensional arrays *(*(a + i) + j)
, which is the same as a[i][j]
.
Pointer can also be used to create strings. Pointer variables of char
type are treated as string.
#include <stdio.h>
int main()
{
char *str = "Hello";
printf("%s\n", str);
return 0;
}
The string created using char
pointer can be assigned a value at runtime.
#include <stdio.h>
int main()
{
char *str;
str = "Hello"
printf("%s\n", str);
return 0;
}
We can also have array of pointers. Pointers are very helpful in handling character array with rows of varying length.
char *name[3] = {
"Adam",
"chris",
"Deniel"
};
Pointer to Structure
We can also have pointer to a single structure variable, but it is mostly used when we are dealing with array of structure variables.
A structure’s member can be accessed through pointer in two ways
- Accessing structure member through pointer by referencing pointer to another address to access the memory
- Accessing structure member through pointer using dynamic memory allocation
Accessing structure member through pointer by referencing pointer to another address to access the memory
#include <stdio.h>
typedef struct person
{
int age;
float weight;
char name[30];
};
int main()
{
struct person person1;
struct person *personPtr;
personPtr = &person1; // Referencing pointer to memory address of person1
printf("Enter name: ");
scanf("%s", (*personPtr).name);
printf("Enter age: ");
scanf("%d", &(*personPtr).age);
printf("Enter weight: ");
scanf("%f", &(*personPtr).weight);
printf("Displaying: ");
printf("%s\t%d\t%f\n", (*personPtr).name, (*personPtr).age, (*personPtr).weight);
return 0;
}
Accessing structure member through pointer using dynamic memory allocation
#include <stdio.h>
#include <stdlib.h>
struct person {
int age;
float weight;
char name[30];
};
int main()
{
struct person *ptr;
int i, num;
printf("Enter number of persons: ");
scanf("%d", &num);
ptr = (struct person*) malloc(num * sizeof(struct person)); // allocates the memory for n structures with pointer personPtr pointing to base address
for(i = 0; i < num; ++i)
{
printf("Enter name, age and weight of the person respectively:\n");
scanf("%s%d%f", (ptr+i)->name, &(ptr+i)->age, &(ptr+i)->weight);
}
printf("Displaying Infromation:\n");
for(i = 0; i < num; ++i)
printf("%s\t%d\t%.2f\n", (ptr+i)->name, (ptr+i)->age, (ptr+i)->weight);
return 0;
}
Pointers as Function Argument
Pointer as a function argument is used to hold addresses of arguments passed during function call. This is also known as call by reference. When a function is called by reference any change made the reference variable will effect the original variable.
#include <stdio.h>
void swap(int *a, int *b);
int main()
{
int m = 10, n = 20;
printf("m = %d\n", m);
printf("n = %d\n\n", n);
swap(&m, &n); //passing address of m and n to the swap function
printf("After Swapping:\n\n");
printf("m = %d\n", m);
printf("n = %d", n);
return 0;
}
/*
pointer 'a' and 'b' holds and
points to the address of 'm' and 'n'
*/
void swap(int *a, int *b)
{
int temp;
temp = *a;
*a = *b;
*b = temp;
}
A function can also return a pointer to the calling function.
#include <stdio.h>
int* larger(int*, int*);
void main()
{
int a = 15;
int b = 92;
int *p;
p = larger(&a, &b);
printf("%d is larger", *p);
}
int* larger(int *x, int *y)
{
if(*x > *y)
return x;
else
return y;
}
Pointer to Function
A function pointer is a pointer that refers to the address of a function.
#include <stdio.h>
int sum(int x, int y)
{
return x+y;
}
int main()
{
int (*fp)(int, int); // declaring a function pointer
fp = sum; // initializing a function pointer
int s = fp(10, 15);
printf("Sum is %d", s);
return 0;
}
How to Read Complex C Variables
Reading C simple declarations
int foo[5]; // foo is an array of 5 ints
char *foo; // foo is a pointer to char
double foo(); // foo is a function returning a double
- * is read as pointer to ...
- [] is read as array of ...
- () is read as function returning ...
The “array of” [] and “function returning” () type operators have higher precedence than “pointer to” *. So these are the rules to read complex variable declaration:
- always start with the variable name: foo is …
- always end with the data type : foo is … int
- the “filling in the middle” part can be summarized with this rule: “go right when you can, go left when you must”
We will start with a simple example
long **foo[7];
Steps to read the declaration as follow
- start with the variable name and end with the data type:
long **foo[7]
foo is … long - then, the rule is to go right when you can:
long **foo[7]
foo is array of 7 … long - because we’ve gone as far right as possible, now we go left:
long **foo[7]
foo is array of 7 pointer to pointer to long
Next, we will start with a more complex example
char *(*(**foo [][8])())[];
Steps to read the declaration as follow
- start with the variable name and end with the data type:
char *(*(**foo [][8])())[]
foo is … char - the rule is to go right when you can:
char *(*(**foo [][8])())[]
foo is array of … char - because we still can go right then we go right:
char *(*(**foo [][8])())[]
foo is array of array of 8 … char - now, we’ve hit parenthesis used for grouping and this halts our march to the right. So we have to backtrack to the left:
char *(*(**foo [][8])())[]
foo is array of array of 8 pointer to … char - we still can go left:
char *(*(**foo [][8])())[]
foo is array of array of 8 pointer to pointer to … char - now we’ve hit parenthesis used for grouping, this finished off the entire parenthesized subexpression. then we go
right again:
char *(*(**foo[][8])())[]
foo is array of array of 8 pointer to pointer to function returning … char - again we are backtracking to the left:
char *(*(**foo[][8])())[]
foo is array of array of 8 pointer to pointer to function returning pointer to … char - again we hit grouping parenthesis, so backtrack to the right:
char *(*(**foo[][8])())[]
foo is array of array of 8 pointer to pointer to function returning pointer to array of … char - finally, we’re left with only “pointer to” on the left:
char *(*(**foo[][8])())[]
foo is array of array of 8 pointer to pointer to function returning pointer to array of pointer to char
Things to notice when declaring complex variables:
- can’t have array of function returning. Use array of pointer to function returning instead
- Functions can’t return functions. Use function returning pointer to function returning instead
- in arrays, only the leftmost [] can be undimensioned.
char foo[]
andchar foo[][5]
are legal, butchar foo[5][]
is not void
type is restricted. pointer to voidvoid *foo
and function returning voidvoid foo()
are legal, but array of voidvoid char[]
and declaring a variable of typevoid
are not legal