Rotate image (square matrix) by 90 deg
Tue, 06 May 2025
Those who use languages like C and C++ that support user-defined pointer variables put utmost emphasis on implementing the pointers correctly.
And rightfully so, A pointer wrongly handled can be catastrophic. And that's an understatement :).
Let's consider the below code which read and print n numbers using pointers:
// Memory leaks...
int *ptr;
for(int i=0; i<n; i++){
ptr = (int*) malloc(sizeof(int));
scanf("%d", ptr);
printf(" You entered : %d", *ptr);
}
The code is written in C, but an equivalent code can be written in C++ using new, delete, cin & cout. I can hear you shouting "Bad code". I promise to use it as a bad example only.
Lets consider the problems in above code :
line-1: ptr is a dangling pointer, C language don't initialize the auto variables with a default value. Though it will not create any problem in the above code because its most simplistic code. But if you develop a habit of not initializing pointers, and keep writing codes like above, then a day will code when some else, if not you, will come and write a code between line-1 & line-2 and may try to dereference it.
line-4: we don't check for ptr being null (or if an exception has occurred during the memory allocation). What if compiler does not have enough memory to allocate, it will either return a null pointer (C) or will trow an exception (C++), but we didn't put a check for either.
line-6: we didn't free the memory allocated to ptr. That's like breaking the most important & obvious rule of the game. You must return the heap memory before the last pointer pointing to the memory goes out of focus (and ideally as-soon-as you think you don't need it.
My friend says that “people are not difficult, they are different!”, I say the same for pointers. while dealing with pointers, you only need to take care of the two problems, Dangling pointers and Memory leaks.1. Dangling pointers: A dangling pointer is a pointer which points to an invalid object. We can have dangling pointers because of multiple reasons:
An un-initialized, non-static local pointer variable is a dangling pointer. auto variables are not initialized in C & C++. the value they contain is garbage. For example in the above code
int * ptr;
ptr is a dangling pointer. Sometimes, such dangling pointers are also called wild pointers. Some languages (like java) gives compile time error if you try to use a variable which is not explicitly initialized.
Note that the below is not a dangling pointer because static variables are initialized to zero (NULL)
static int * ptr; // Not a dangling pointer
destroying the stack frame (the variable which the pointer points to goes out of scope)
int *ptr = NULL;
{
int temp = 10;
ptr = &temp
} // temp goes out of scope and ptr becomes dangling after this point
explicitly deleting the memory, which the pointer points to
int * ptr = new int;
delete ptr; // ptr is dangling pointer now.
ptr = NULL; // best practice to always assign NULL after deleting a pointer.
Sometimes, this is done indirectly, as shown below,
int * ptr = new int;
int *new_ptr = ptr
delete ptr;
ptr = NULL; // Ok
In the above code ptr is not a dangling pointer but since new_ptr also points to the same memory location, new_ptr becomes a dangling pointer. (Because the memory location to which it points is deallocated).
Returning address of a local variable on stack.
int * function func()
{
int abc;
return &abc; // returning address of a local variable
}
The stack-frame (activation record) of the function, on which abc resides will be deallocated when the function returns. So the address returned from the function does not points to the allocated memory.
2. Memory leaks:A memory leak is a situation when there exist a memory, which is allocated to the program but cannot be accessed. Such memory develops on heap, when a user allocate the memory but change the pointer which hold the address to that location. Below are few example of how a developer manufactures them:
Reassign a pointer before deleting what the pointer was originally pointing to. One example of this is seen in the for loop of our main example, another example is shown below:
// Memory allocated on heap and address stored in ptr
int * ptr = new int;

// the previous memory is now a memory leak
ptr = new int;

Not deleting the pointer before it goes out of focus. (This may look as another variation of the above).
void func()
{
int * ptr = new int;
// do some work..
}
the memory allocated to ptr will be a leak.
This problem is actually more complex than it looks. Suppose you write the below ‘good code'
void func()
{
int * ptr = new int;
// do some work..
delete ptr;
}
But then an exception occurs in the code before the delete command. Since you do nothing to handle the exception, that exception will be propagated to the calling function. Even if the calling function handles the exception gracefully, there will be a leak in the above function.
A solution to this may be to put the entire code in try catch and then delete the pointer in the catch part as well.
void func()
{
int * ptr = new int;
try{
// do some work..
}
catch (…) // … means catch all exceptions
{
delete ptr; // avoid memory leak when an exception is thrown
throw; // propagate exception to caller
}
delete ptr;
}
The above code solves the problem of memory leak, though at the cost of making the code less readable.
C++ has a concept of smart pointers which come to rescue in above situations where you want to avoid memory leak and don't want to clutter your code. I reserve the discussion of smart pointer and auto_ptr for some later post.
Tue, 06 May 2025
Tue, 06 May 2025
Tue, 06 May 2025
Leave a comment