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.
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.
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.
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.
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.
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:
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.
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);
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;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With