Dereferencing an unknown memory location : C programmers mostly use scanf() function to take input, but sometimes a small mistake can bring a bug or even crash whole program.
The syntax for scanf() is scanf(“%d”, &a);. It might be possible to miss a & and write &a as a so now scanf(“%d”, a); is dereferencing to an unknown location.
Now either the program may terminate with an exception or it may correspond to a valid location(not related to current program but to some other program) and may get overwritten which may cause unknown effect later.
#include <stdio.h>
int main()
{
int a;
scanf ( "%d" , a);
printf ( "%d" , a);
return 0;
}
|
Reading an uninitialized Memory. In C, beginners generally use malloc() to provide run time memory but with malloc() the memory block do not get initialized and one may access .
#include <stdio.h>
int main()
{
int * p = ( int *) malloc ( sizeof ( int ) * 4);
int i;
for (i = 0; i < 4; i++)
p[i] += 100;
}
|
A solution is to use calloc() instead which initialize block to 0.
Buffer overflow : This is a very common mistake that occur in C and this become even more common due to presence of a faulty function in C itself i.e. gets() function which is used to take string as input. It does not check the memory provided to store string in the program due to which if a user enter string of greater size then gets() with overwrite memory location after the string and cause overflow.
void read()
{
char str[20];
gets (str);
printf ( "%s" , str);
return ;
}
|
The code suffers from Buffer Overflow as gets() doesn’t do any array bound testing. gets() keeps on reading until it sees a newline character. To avoid Buffer Overflow, fgets() should be used instead of gets() as fgets() makes sure that not more than MAX_LIMIT characters are read.
#define MAX_LIMIT 20
void read()
{
char str[MAX_LIMIT];
fgets (str, MAX_LIMIT, stdin);
printf ( "%s" , str);
return ;
}
|
Memory leaks This situation arises when the used heap memory is not de-allocated due to which the main memory get eventually filled up and free memory become less.
#include <stdlib.h>
void f()
{
int * ptr = ( int *) malloc ( sizeof ( int ));
return ;
}
|
We should use free() after malloc() if memory is not used anymore.
#include <stdlib.h>
void f()
{
int * ptr = ( int *) malloc ( sizeof ( int ));
free (ptr);
return ;
}
|
Bug due to precedence Less understanding of operator and their precedence can produce a bug especially with pointers like
#include <stdlib.h>
int demo()
{
int a = 10;
int * p = &a;
*p++;
}
|
Precedence of * (dereference/indirection operator not multiplication) and postfix ++ are not same but prefix ++ and * has same, and hence, first the value of p will increase and will point to a bad memory area and then dereference and will overwrite that location or program may get terminated. Please see Difference between ++*p, *p++ and *++p for details.
Sending address of non-existing variable Returning address of a local variable causes problems,
#include <stdlib.h>
int fun()
{
int x = 10;
return &x;
}
int main()
{
int * p = fun();
*p = 20;
}
|
When function fun() is called variable a is created but as soon function returns, it get destroyed. Since function is returned its address p will point to a memory area in stack area and if another function is called then a change by pointer p may result in error.
Pointer arithmetic Pointer arithmetic can be confusing let’s take an example suppose integer is of 4 Bytes.
int main()
{
int x[10] = { 0 }, i = 0, *p;
p = &x[0];
while (i < 10) {
*p = 10;
p = p + 4;
i++;
}
}
|
Although it seems correct as integer is of 4 byte and p is at starting location so adding 4 to it will cause p to point at next integer in array n but pointer arithmetic work according to size of its data type so adding 1 to a pointer of integer then sizeof(int) will get added to it same applies for pointer to any other data type.
int main()
{
int x[10] = { 0 }, i = 0, *p;
p = &x[0];
while (i < 10) {
*p = 10;
p++;
i++;
}
}
|
Passing array as parameter When we pass an array to a function, it is always treated as a pointer in the function. That’s why we should never use sizeof on array parameter. We should rather always pass size as a second parameter.
#include <stdio.h>
void printArray( int arr[])
{
int i;
int arr_size = sizeof (arr) / sizeof (arr[0]);
for (i = 0; i < arr_size; i++) {
printf ( "%d " , arr[i]);
}
}
int main()
{
int arr[4] = { 1, 2, 3, 4 };
printArray(arr);
return 0;
}
|
Below is the corrected code
#include <stdio.h>
void printArray( int arr[], int arr_size)
{
int i;
for (i = 0; i < arr_size; i++) {
printf ( "%d " , arr[i]);
}
}
int main()
{
int arr[] = { 1, 2, 3, 4 };
int arr_size = sizeof (arr) / sizeof (arr[0]);
printArray(arr, arr_size);
return 0;
}
|
Reference :
Computer Systems :A programmer’s Perspective