Allocating memory for a single element
In the above examples a pointer held the address of an existing variable. We can also allocate memory dynamically ( that is at run time when the program is running ) and assign the address to a pointer. The size of the memory could be for say a single integer or even a block of 10 integers. In either case the pointer holds the address. In the case of a block the starting address of the block is stored in the pointer. Memory allocated dynamically is always stored on the heap.
File: "alloc1.c"
#include<stdio.h>
#include<stdlib.h>
int main()
{
int* ptr1 ;
//Allocating space a single int
//We need to tell the exact size
//and type cast from void* to int*
ptr1 = (int*)malloc( sizeof(int) * 1 ) ;
*ptr1 = 100 ;
printf("%d\n" , *ptr1 );
free( ptr1 ) ;
return(0) ;
}
The above code shows how memory for a single int can be allocated on the heap dynamically.
ptr1 = (int*)malloc( sizeof(int) * 1 ) ;
We want to allocate memory for a single int . With "malloc" we have to specify the exact number of bytes that need to be allocated. The function
"sizeof(int)"
tells us the size of integer on this machine. Remember the sizes of a data type might be different depending on the computer hardware and the operating system. We are multiplying by 1 to explicitly show that we are only interested in 1 integer. We also
need to type cast with "(int*)" telling us what sort of memory has been allocated. In this case memory for a single int has been allocated. The type returned by "malloc" will always be a pointer holding an address. We may allocate space for a single integer or allocate space for a block of integers or even allocate space for a block of pointers.
Once we get the address we can place a value at the address with the statement:
*ptr1 = 100 ;
Once we are done with the pointer then we can free the memory that got allocated with the statement:
free( ptr1 ) ;
File: "alloc2.c"
What is wrong with the following program ?
#include<stdio.h>
#include<stdlib.h>
int main()
{
int* ptr1 ;
ptr1 =(int*)malloc( sizeof(int) * 1 ) ;
*ptr1 = 100 ;
printf("%d\n" , *ptr1 );
ptr1 = ptr1 + 1 ;
printf("%d\n" , *ptr1 );
free( ptr1 ) ;
}
Memory allocated using malloc is allocated on the heap. It is only freed when we manually free it with the call "free" .
File: "heap1.c"
#include<stdio.h>
#include<stdlib.h>
int* method1()
{
int* ptr1 ;
//Allocating space for 10 integers
ptr1 = (int*) malloc( sizeof(int) * 1 ) ;
*ptr1 = 100 ;
return( ptr1 ) ;
}
int main()
{
int* ptr2 ;
ptr2 = method1() ;
//Value persists beyond the method1 call
printf( "%d\n" , *ptr2 ) ;
//Now the memory allocated is free
free( ptr2 ) ;
return(0) ;
}
Allocating a block of Memory
Let's take a look at the below program:
File: "alloc3.c"
#include<stdio.h>
#include<stdlib.h>
int main()
{
int* ptr1 ;
//Allocate space for 10 integers
ptr1 = (int*)malloc( sizeof(int) * 10 ) ;
ptr1[0] = 100 ;
ptr1[1] = 200 ;
printf( "%d : %d\n" , ptr1[0], ptr1[1] ) ;
printf( "%d : %d\n" , *ptr1, *( ptr1 + 1 ) ) ;
free( ptr1 ) ;
return(0) ;
}
Output:
100:200
100:200
The lines :
//Allocate space for 10 integers
ptr1 = (int*)malloc( sizeof(int) * 10 ) ;
ptr1[0] = 100 ;
ptr1[1] = 200 ;
printf( "%d : %d\n" , ptr1[0], ptr1[1] ) ;
printf( "%d : %d\n" , *ptr1, *( ptr1 + 1 ) ) ;
allocate a block of 10 integers . Conceptually our RAM diagram looks like:
RAM
0
1
ptr1 2 6
3
4
5
6 ^
| Block of
| 10 integers
|
Our pointer "ptr1" still holds as address . However this address now is the starting address of the block. We know we can access the value using "*ptr1" location. However we can also access the value using the array index notation.
printf( "%d : %d\n" , ptr1[0], ptr1[1] ) ;
printf( "%d : %d\n" , *ptr1, *( ptr1 + 1 ) ) ;
If we say "ptr1[0]" then we go to the address of "ptr1" and fetch the value there. It's the same exact thing as "*ptr" . Similarly if we say "ptr1[1]" that means go to where the address "ptr1" is and move 1 element down. It is the same as "*(ptr1+1)" . In fact arrays and pointers are almost the same thing in C.
NULL value
We can assign the special zero value indicated by "NULL" to indicate that the pointer has not been initialized yet.
File: "null1.c"
#include<stdio.h>
#include<stdlib.h>
int main()
{
int* ptr1 ;
ptr1 = NULL ;
//Same thing but nul is preferred.
ptr1 = 0 ;
ptr1 = (int*) malloc( sizeof(int) * 1 ) ;
//Use
*ptr1 = 100 ;
free( ptr1 ) ;
}
Using free
We know that every time we use "malloc" the memory gets created in the heap section and we must use "free" to free up the memory. However we cannot use "free" twice as that leads to a program crash.
File: "free1.c"
#include<stdio.h>
#include<stdlib.h>
int main()
{
int* ptr1 ;
ptr1 = NULL ;
//Same thing but nul is preferred.
ptr1 = 0 ;
ptr1 = (int*) malloc( sizeof(int) * 1 ) ;
//Use
*ptr1 = 100 ;
free( ptr1 ) ;
free( ptr1 ) ;
}
Output:
$ gcc free1.c ; ./a.exe
Aborted (core dumped)
Exercises
Ex 1
Explain what the below program does:
#include<stdio.h>
#include<stdlib.h>
int main()
{
int* ptr1 ;
//Allocating space for 10 integers
ptr1 = (int*) malloc( sizeof(int) * 10 ) ;
for( int i1=0 ; i1<10 ; i1++ )
{
ptr1[i1] = i1 ;
*( ptr1 + i1 ) += i1 ;
} //for
for( int i1=0 ; i1<10 ; i1++ )
{
printf( "%d " , ptr1[i1] ) ;
} //for
free( ptr1 ) ;
return(0) ;
}
Output:
0 2 4 6 8 10 12 14 16 18