Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deallocate dynamic memory within a function

Tags:

c++

c++11

First time with an account here but I've enjoyed the site a fair deal.

I'm attempting to create a function that receives a const char array and returns a portion indicated of said array. Along with the array the function receives two values indicating the index of the first character in the portion to be extracted and the index of the last character.

The tricky part about what I'm attempting is that I'm creating a temporary array variable to hold this portion inside a function and given that the size of the portion isn't guaranteed to be a constant I'm using dynamic memory to allocated the necessary space and here's where I'm having my issue.

Whenever the function returns any information the function ends and the program doesn't have a chance of deallocating the spared memory. If I delete the variable I'm unable to return the information.

I tried creating a separate pointer variable to point to the information after it's formed but once the memory is deallocated the information doesn't seem to be able to be recovered.

Program with issues dealllocating:

char* seperateString(const char* a, int b, int c) {

                // This is simply to assure that I don't allocated a negative size
        if (b < c) {
                cout << "***Error with \"seperateString\" function***" << endl << endl;
                return '\0';
        }

        char* seperated = new char[c - b + 2];

        int i = 0;
        int j = b;

        for (; i <= c - b; i++)
                seperated[i] = a[j++];

        seperated[i] = '\0';

        char* send = seperated;
        delete[] seperated;

        return send;
}

int main() {
        cout << "Program Iniciated." << endl << endl;

        const int a = 6, b = 11;


        const char* toBeSeperated = "Hello there, I have missed you.";
        char *ari = seperateString(toBeSeperated, 6, 11);

        cout << "Sentence is: " << toBeSeperated << endl << endl
            << "Extracted portion is: " << ari << endl << endl;

        cin.get();
        return 0;
}

Program working as intended in the main function.

int main() {
        cout << "Program Iniciated." << endl << endl;

            // variable a and b hold the beginning and last index values of the portion 
            // that is wanted to extract. 
        const int a = 6, b = 11;


            // This is an example sentence  |------| this is the portion being extracted.
        const char* toBeSeperated = "Hello there, I have missed you.";

            // variable holding extracted portion.
            // created with the size necessary to hold the portion plus a \0.
        char* seperated = new char[b  -a  +2];
                                                                //Given that a and b are index values 1 has to be added for size
                                                                //Additionally an extra space is require for \0

            //i is held outside the for loop to allow to access it after it completes the cycle
          //so it's able to assing \0 after the last character.
        int i = 0;

          //j holds the value of the first index
        int j = a;

        for (; i <= b - a; i++)
                seperated[i] = toBeSeperated[j++];

        seperated[i] = '\0';

        cout << "Sentence is: " << toBeSeperated << endl << endl
                << "Extracted portion is: " << seperated << endl << endl;

        delete[] seperated;
        cin.get();
        return 0;
}

In closing, this is about preventing memory leakage.

like image 233
Pichuu64 Avatar asked Aug 06 '19 03:08

Pichuu64


People also ask

What happens if we do not deallocate dynamic memory?

If you don't delete them, they will remain there (but won't be accessible -> this is called memory leak) until your process exits, when the operating system will deallocate them.

Which function do you use to deallocate memory in C?

In C, the library function malloc is used to allocate a block of memory on the heap. The program accesses this block of memory via a pointer that malloc returns. When the memory is no longer needed, the pointer is passed to free which deallocates the memory so that it can be used for other purposes.

How does free () work in deallocating memory?

The free() function is used to deallocate memory while it is allocated using malloc(), calloc() and realloc(). The syntax of the free is simple. We simply use free with the pointer. Then it can clean up the memory.

Which is the correct syntax to deallocate memory dynamically in C++?

Since it is programmer's responsibility to deallocate dynamically allocated memory, programmers are provided delete operator by C++ language. Syntax: // Release memory pointed by pointer-variable delete pointer-variable; Here, pointer-variable is the pointer that points to the data object created by new.


3 Answers

As you pointed out, we must have memory that actually stores the result of the function, so we can't free the dynamically allocated array before we return. That leaves us with two options:

  1. Allocate the memory before we call, and provide a pointer to and size of that memory to the called function (less than elegant)
  2. Make sure that we pass back a pointer to the allocated memory in a safe way

In both cases, however, we have to make sure to manually deallocate the memory. Smart pointers are perfectly suited for this use-case, specifically std::unique_ptr.

Here's a functioning program:

#include <iostream>
#include <memory>

std::unique_ptr<char[]> seperateString(const char* a, int b, int c) {
    using namespace std;
    // This is simply to assure that I don't allocated a negative size
    if (c < b) {
        cout << "***Error with \"seperateString\" function***" << endl << endl;
        return '\0';
    }

    auto seperated = std::unique_ptr<char[]>(new char[c - b + 2]);

    int i = 0;
    int j = b;

    for (; i <= c - b; i++)
        seperated[i] = a[j++];

    seperated[i] = '\0';

    return seperated;
}

int main() {
    using namespace std;
    cout << "Program Iniciated." << endl << endl;

    const int a = 6, b = 11;


    const char* toBeSeperated = "Hello there, I have missed you.";
    auto ari = seperateString(toBeSeperated, 0, 5);

    cout << "Sentence is: " << toBeSeperated << endl << endl
        << "Extracted portion is: " << ari.get() << endl << endl;

    cin.get();
    return 0;
}

Unique pointer takes ownership of the dynamically allocated resource, and releases (i.e. deallocates) the resource when it itself is destroyed on leaving scope.

In function seperateString, we construct the unique_ptr with a pointer to a dynamically allocated array of characters via operator new[]. From this point on, we don't need to manage the dynamically allocated memory as it is bound to the lifetime of the smart pointer seperated. Whenever seperated is destroyed, its destructor will call operator delete[] on the array pointer we assigned to it upon construction.

But wait, seperated is destroyed as the function returns, so aren't we back to square one as the memory is freed before we get to use it in the calling code? No, because we are returning the unique_ptr<char[]> by value, the compiler moves ownership of the resource from the function-local seperated unique pointer to the call-site-local ari unique pointer, constructing it via a move-constructor. Now the fate of the memory allocated in the function call is tied to the lifetime of ari, and when it goes out of scope the memory is freed with no leaks.

like image 87
Skrino Avatar answered Sep 18 '22 12:09

Skrino


You just reimplemented std::string::substr() for no good reason.

You can delete your function altogether, replace your const char* strings with std::string, and replace calls to your old function with calls to std::string::substr():

std::string toBeSeperated = "Hello there, I have missed you.";
auto ari = toBeSeperated.substr(0, 5);
like image 39
Nikos C. Avatar answered Sep 18 '22 12:09

Nikos C.


The below code usesSTL containers in C++ and these will be automatically managed by C++, Read this to know more. You can also use SMART Pointers. You can also do in this way to extract the sub-string.

#include<iostream>
#include<vector>
#include<memory>

using namespace std;

std::vector<char> seperateString(const char* a,const int b,const int c) {

        std::vector<char> extracted_array;
        for(int i=b;i<=c;i++ ) extracted_array.push_back(a[i]);
        return extracted_array;
}

int main(){
        cout << "Program Iniciated." << endl << endl; // Initiated not Iniciated, Lol.

        int a = 11, b = 0; // here 'const' restricts your freedom to modify them.


        const char* toBeSeperated = "Hello there, I have missed you.";
        auto after_extraction = seperateString(toBeSeperated, a, b);

        for(const auto i : after_extraction) cout<<i;  // to print the extraxcted portion;
        return 0;
} 
like image 22
Kranthi Kumar Avatar answered Sep 22 '22 12:09

Kranthi Kumar