Deleting a dynamically allocated jagged array - c++

I have an array of pointers that point to arrays of ints.
I have made a hard coded array of ints (check 'array' below) and I want to insert it into the array of pointers (check 'bar' below), as far as I can tell, it is still an array of pointers that point to arrays of ints.
It compiles fine; no warnings.
It runs fine; and closes fine;
Until at least, I introduce the currently commented out delete statement in the destructor.
I imagine my compiler would make a better destructor at this point, but I'm interested as to what I'm doing wrong. The terminal window just throws out a gigantic memory map; and googling and searching SO didn't help much.
class foo {
public:
int **bar;
int aSize;
//CONSTRUCTOR
foo(int aSize) {
this->aSize = aSize;
bar = new int*[aSize];
for (int i=0;i<aSize;i++) {
bar[i] = new int[aSize + i];
for (int j=0;j<(aSize + i);j++) {
bar[i][j] = 0;
}
}
}
void myfunc(int *pointer) {
bar[0] = pointer;
}
~foo() {
for (int i=0;i<aSize;i++) {
//delete[] bar[i];
}
delete[] bar;
}
};
int main() {
foo *obj = new foo(5);
int array[] = {1,2,3,4};
obj->myfunc(array);
delete obj;
return 0;
};
I know I've probably done something tragic; I just don't know what it is yet.
There is a reason why I am not using STL or other templates, it is simply because I'm interested in learning this.
Maximum criticism appreciated.

The myfunc function takes in a pointer, and then sets bar[0] to that memory address. In your example code, you pass it the address of array, which is an automatic (stack) variable. The destructor then attempts to delete[] bar[0], which points to a stack variable. This is completely undefined behavior, and the reason your program is crashing. You can't delete[] a stack array. You can only delete[] an array which was allocated using new[].
Also, the myfunc function is always going to leak memory, because bar[0] points to a heap-allocated array. When you set bar to a different memory address without first delete[]ing the previous address, you are leaking memory.

The problem is calling myfunc. In that function, you are replacing a pointer (bar[0]) that your class thinks it owns. Your obj destructor will then consequently try to run delete[] on your array[] in main, which probably causes your crash and leaves your original bar[0] dangling.

Related

How to release the memory outside of a function if I forgot to release the memory before the function returns

my question can be briefly shown as the following example.
void func(int n){
char *p = (char*)malloc(n);
// some codes
memset(p,0,sizeof(name));
// free(p); // Commenting this line represents that I forget to release the allocated memory.
}
int main(){
// some codes
for (int i; i < Nl; i++){
func(100);
// How can I release the allocated memory of p outside of the func?
}
}
I whish to release the allocated memory, which is allocated in a function, outside of this function.
Thank you.
The pointer in question is not returned from the function in any way, so if you don't free it in the function then the memory is leaked. You would need to modify the function to either assign the pointer to a global, return it from the function, or assign it to a dereferenced pointer passed to the function.
If your goal is to find and fix memory leaks in your program, there are tools such as valgrind which can help you with that.
To solve the problem it's better to use std::unique_ptr. If you use smart pointer it will be released whenever it's not required anymore.
Foe example :
void my_func()
{
std::unique_ptr<int> valuePtr(new int(15));
int x = 45;
// ...
if (x == 45)
return; // no memory leak anymore!
// ...
}
You can check the link to study more :
https://en.cppreference.com/book/intro/smart_pointers
Two solutions in C
a) use VLA
void foo(int n) {
char p[n];
// use p
// no need to free, p automatically releases its memory
}
b) return the pointer to the caller
char *foo(int n) {
char *p = malloc(n);
// use p
return p;
}
int main(void) {
char *bar = foo(100);
free(bar);
}
If I understand you correctly, you are struggling with the basic concept of memory management.
Looking at your code you are malloc, which is a core C memory management aspect, although you tagged the question as C and C++. I can go into depth on why there ain't a thing like C/C++, though it's better explained here: https://cor3ntin.github.io/posts/c/
One of the elements C and C++ programmers disagree is the use of malloc, which is standard in C and and only used in exceptional cases in C++.
If we look from a C++ standpoint, I'd argue you should be learning it with a recent version. Here the answer is simple: use std::make_unique:
auto p = std::make_unique<char[]>(n);
Or in this case as you are trying to do something with strings, just use std::string. Trust me, doing so will prevent a lot of grief. Let me also remark that you often don't need memory allocations, more about that can be found here: https://stackoverflow.com/a/53898150/2466431
If you however ain't programming C++, you can use malloc. Here it is important to understand that every pointer returned by malloc ends up as an argument for free. (Exceptions on this ain't for beginners)
After you call free, you can't use what the pointer points to, not the value stored in the pointer. Calling free twice for the same pointer is also an issue.
Hence, unlike in the C++ code where the memory gets freed when no longer used. You need to keep detailed attention for this and call free.
In your function, uncommenting the free is the correct solution.
If you have the intention to let the data outlive the function call, you should be returning the pointer to the caller, this is than responsible for the ownership:
char * func(int n){
char *p = (char*)malloc(n);
// some codes
memset(p,0,sizeof(name));
return p;
}
int main(){
// some codes
for (int i; i < Nl; i++){
char *s = func(100);
free(s);
}
}
Let me show the same with the previously mentioned C++:
#include <memory>
std::unique_ptr<char[]> func(int n){
auto p = std::make_unique<char[]>(n);
// some codes
return p;
}
int main(){
// some codes
for (int i; i < Nl; i++){
auto s = func(100);
}
}
Or using std::string
#include <string>
std::string func(int n){
auto p = std::string(n, '\0');
// some codes
return p;
}
int main(){
// some codes
for (int i; i < Nl; i++){
auto s = func(100);
}
}

confusion with passing arrays by reference using pointers

I just asked a question several hours ago, and I have been utterly confused with something pointed out in the answers (arrays using pointers in c++: segmentation fault when accessing the returned array). Some people have been responding a bit negatively to my newb questions, so I went over my book about pointers, which did not help me much. So, here I go again.
In the previous question, I had a function void builder(int aSize1, int aSize2, int aSize3, int*** frequencies) that I thought would dynamically allocate memory for the 3d array passed in for the int*** frequencies parameter and initialize it. However, I was told that only a copy would be passed into the function and I would be allocating and initializing just for the copy not the original. Hence, they have advised me to use a reference instead, rendering the function prototype as void builder(int aSize1, int aSize2, int aSize3, int***& frequencies).
However, I recalled that just yesterday when I first stumbled upon this concept of pass by reference using pointers, one would be able to manipulate the data of the pointer as well. To wit,
void change_what_this_points_to( int* a )
{
*a = 42;
}
this function does change the value of a pointer that is fed into the function.
So, my question is, why does the former pass in a copy while the latter passes the real deal? I do not see much difference between the two functions, aside from the fact that one has more asterisks.
Any help would be appreciated. Thanks!
While the other answer says it perfectly I just thought I'd add my two cents just in case it helps. Think of a pointer as just an address in memory. You pass that address into a function, and the function writes something in there. Then after the function is called you can look in that same location in memory and see what value is there.
So let's assume you have the following code:
void SetValue(int *a){ *a = 10;}
void DoWork()
{
int a;
SetValue(&a);
}
The SetValue function takes as a parameter a pointer to an int, or as we'll think of it, an address in memory where an int is stored. The function then simply writes the number 10 to the passed in address.
The method DoWork then creates the memory for an int and passes the address of that memory to the function. So by the time DoWork returns the memory where "a" is stored has the value 10. Sounds like you have this already from your question but wanted to start here just in case.
Now let's pretend you want a function to allocate memory for you. What you are really asking the function to do is to allocate memory and tell me where that memory is. So you could do that with a pointer return value, i.e.
int* AllocateMemoryForMe()
{
return new int(); //Creates memory for an int, let's pretend it's at location 0x100
}
void DoWork()
{
int* a = NULL; // a has a value of 0x00
a = AllocateMemoryForMe(); //a will now have the value of 0x100
*a = 10; //We now write 10 to memory location 0x100
}
Or you could do this using a pointer. If you do this, what you actually have to do is pass into the function a location in memory to write the address of the allocated memory into, so a pointer to a pointer. So when the function returns you can look into this address and see what the address of newly created memory is. So for example:
void AllocateMemoryForMe(int** x)
{
*x = new int(); //allocates memory for an int, let's pretend it's at memory location 0x200
}
void DoWork()
{
int** a = new int*(); //Creates memory for an int pointer. Let's pretend it allocates memory at location 0x100.
AllocateMemoryForMe(a); //pass memory location 0x100 to the function.
//Right now the address of a is still 0x100 but the data at the memory location is 0x200. This is the address of the int we want to write to.
**a = 10; //This will now write 10 to the memory location allocated by the AllocateMemoryForMe() function.
}
This function
void change_what_this_points_to( int* a )
{
*a = 42;
}
does not change the pointer itself. It changes the integer object pointed to by the pointer.
If you want to change the pointer itself you should write the function either the following way
void change_what_this_points_to( int * &a )
{
a = new int( 42 );
}
or the following way
void change_what_this_points_to( int **a )
{
*a = new int( 42 );
}
Thus returning to your function you should declare it either like
void builder(int aSize1, int aSize2, int aSize3, int*** &frequencies);
or like
void builder(int aSize1, int aSize2, int aSize3, int**** frequencies);

delete[] and delete seems to behave alike

here if I use delete or delete[] the output is still 70. Can I know why?
#include<iostream>
using namespace std;
int main()
{
int* c = new int[100];
for(int i=0; i<98; i++)
{
c[i] = i;
}
cout<<c[70]<<endl;
delete[] c;
or
delete c;
cout<<c[70]<<endl; //outputs 70 even after delete[] or delete
return 0;
}
Accessing deleted memory is undefined behavior. Deleting with the wrong delete is also UB. Any further discussion is pointless in the sense that you cannot reliably expect any outcome.
In many cases, UB will just do the "correct" thing, but you need to be aware that this is completely "by chance" and could change with another compiler, another version of the same compiler, the weather... To get correct code, you need to avoid all cases of UB, even those that seemingly work.
Using new will just allocate some memory to your program and return a pointer pointing at the said memory address, reserving as much memory as needed for the datatype. When you use delete later, it "frees" the memory, but doesn't delete it's content. If you had an int with the value 70 stored at that address, it will still contain 70, until another application wants some memory, gets said address and puts another value in there.
If you use new to allocate memory for an array, you will reserve following blocks of memory until there are enough blocks for your specified array length.
Let's say you do the following:
int main() {
int* array = new int[10]; // array now points to the first block of the allocated memory
delete array; // since array points to the first block of the array, it will only free that block, but nothing else, causing a memory leak
delete[] array; // will free all memory allocated by the previous new
// Note that you should never free allocated memory twice, like in this code sample. Using delete on already freed memory is undefined behaviour!
]
Always use delete for single variables and delete[] for arrays.
A demonstration of your problem:
int main() {
int* c = new int[10]; // We allocate memory for an array of 10 ints
c[0] = 1; // We set the value of the first int inside the array to 1
delete[] c;
/*
* We free the previously allocated memory.
* Note that this does not delete the CONTENT of the memory!
* c does still point towards the first block of the array!
*/
std::cout << c[0];
/*
* Firstly, this is undefined behaviour (Accessing deallocated memory).
* However, this will output 1,
* unless some other process allocated the memory at the address
* and filled it with another value already. (Very unlikely)
*/
return 0;
}
If you want to delete / overwrite the content of the deleted memory, you can use std::memset.
Example:
#include <cstring>
int main() {
std::size_t length = 10;
int* c = new int[length];
c[0] = 1;
std::cout << c[0] << std::endl; // Will output 1
std::memset( c, 0, length ); // Fill the memory with 0 bytes
delete[] c; // Now we free the array's memory
std::cout << c[0] << std::endl; // Will output 0
}
As others pointed its undefined behaviour and anything can happen.
These can be easily caught with the help of tools like valgrind.

How to make it so the user can't delete a dynamic array?

In writing a response, I wrote some code that challenged my assumptions on how const pointers work. I had assumed const pointers could not be deleted by the delete function, but as you'll see from the code below, that isn't the case:
#include <new>
#include <string.h>
class TestA
{
private:
char *Array;
public:
TestA(){Array = NULL; Array = new (std::nothrow) char[20]; if(Array != NULL){ strcpy(Array,"Input data"); } }
~TestA(){if(Array != NULL){ delete [] Array;} }
char * const GetArray(){ return Array; }
};
int main()
{
TestA Temp;
printf("%s\n",Temp.GetArray());
Temp.GetArray()[0] = ' '; //You can still modify the chars in the array, user has access
Temp.GetArray()[1] = ' ';
printf("%s\n",Temp.GetArray());
//Temp.GetArray() = NULL //This doesn't work
delete [] Temp.GetArray(); //This works?! How do I prevent this?
}
My question is, how do I pass the user access to a pointer (so they can use it like a char array), whilst making it so that the delete function cannot delete it, by preferably throwing some sort of complaint or exception?
If your users are using delete[] on pointers they didn't get from new[], hit them upside the head with a clue bat.
There are so many reasons a pointer can be dereferenced but mustn't be passed to delete:
Someone else will delete it.
It's not the beginning of the block.
It came from malloc or some other non-new allocator.
It has static, not dynamic lifetime.
If has automatic lifetime.
Some of these will manifest in exceptions at runtime. Others will cause crashes at some later time. All are "undefined behavior" according to the standard.
The assumption should be that a pointer cannot be used as the argument to delete, unless explicitly stated otherwise.
If entry-level programmers are making this mistake, educate them. If "experienced" developers are doing it, fire them for lying on their resume.
If you just want it to hurt when they do that, allocate the array one larger than necessary, and return Array + 1;. Now everything will blow up if they try to use delete[].
The practical use is that it's (more) likely to make the program crash inside the bogus call to delete, with the offending function still on the call stack. Where the original will probably continue running for a while, and finally crash in innocent code. So this helps you catch stupid users.
delete [] Temp.GetArray(); //This works?! How do I prevent this?
As long as, it returns char* or some other pointer type, you cannot prevent it; it doesn't matter if the expression in delete statement is const, because all of the following are perfectly valid in C++:
char *pc = f();
delete [] pc; //ok
const char *pc = g();
delete [] pc; //ok
char * const pc = h();
delete [] pc; //ok
const char * const pc = k();
delete [] pc; //ok
However, if you change this :
char *Array;
to this
std::vector<char> Array;
And then you could achieve what you want, by returning it as:
std::vector<char> & GetArray() { return Array; }
The bottomline is :
In C++, the default choice for dynamic array should be std::vector<T> unless you've a very strong reason not to use it.
Your const is doing no effect, you are returning a const pointer, not a pointer to const char, which is what you want. Also see Nawaz recommendation on using vectors instead.
The most you can really do is to return something that is not an acceptable operand for delete. This can be an RAII object (like std::vector or std::array) or it can be a reference (depending on your situation, either could be appropriate).
[Un]fortunately, C++ lets the programmer do all sorts of sneaky things.
You cannot block stupidity entirely, but you can stifle it a tad by using an access mechanism instead of returning the actual array pointer.
char& operator[](size_t index) { return Array[index]; }
This does not address the ability to treat it like a char array, but as has been pointed out, if you reveal that pointer, (bad) programmers a free to run delete on it all they want.

Scope, arrays, and the heap

So, I have this array. It needs to be accessed outside the scope of this function. I have been slapping a pointer to it into a pair which gets put into a deque. But once I'm outside the scope, the local stack is gone, the array is invalid, and I've just got a useless pointer, right?
So I've trying to put this array onto the scope-transcending heap, where it will remain until I delete it at a later time. But I'm having issues getting this working. Right now g++ is coughing up errors about invalid conversion from 'int' to 'int*'.
void randomFunction(int x, int y, int width, int height)
{
int **blah[4] = {x, y, width, height};
std::pair <foobar*, int* > tempPair (foobar1, blah);
randomDeque.push_front(tempPair);
}
I've also tried initializing it like this:
int *blah[4] = new int[4];
...and it says that the array must be initialized with a brace-enclosed initializer.
I'm really not used to working with pointers. What am I doing wrong?
There are two problems. First, indeed, you are confused about pointers/arrays:
int a[4]; // this is an array of 4 integers, a is the name of the array
int *a[4]; // This is an array of 4 *pointers* to int
So your declaration:
int **blah[4];
Define an array of 4 pointers to pointers array. Maybe you are confused by the following fact (I know I was when I learned C). If you declare a variable:
int *a;
This is a declaration of a pointer to an integer. But if you have a variable a which is a pointer, you get the thing it points to (an integer here) by using *a:
*a = 1; // a is a pointer (i.e. an address), *a is the value pointed to by a.
So * in declaration is used to declare pointer, but * in statements is used to deference value.
But your second problem has nothing to do with pointer per-se. It is about ressource-management (memory being one, but file, locks being others). Anything allocated on the stack does not exist anymore when it is out of scope. In pure C, you only really have one solution: allocating on the heap with malloc, and making sure to free afterwards. So you would do something like:
// foo is a struct
foo *init_foo()
{
foo* tmp;
tmp = malloc(sizeof(*tmp));
// initialize tmp
return tmp;
}
And then, you will clean it with another function:
foo *a;
a = init_foo();
// do stuff
clean_foo(a);
Example: the FILE* handle and fopen/fclose (in addition to allocating stuff, there are some things related to the OS to handle the file). Another solution is to use alloca, which is not standard C, but is supported by many toolchains.
In C++, you can use smart pointers, which use for example reference counting to do resources management. I am less familiar with C++, and I am sure people will jump in on that part. The idea with reference counting is that it still gives some of the advantages of auto pointers (you don't have to call delete by yourself, which is extremely error-prone for non trivial projects), but without being purely scope-based. One reference counting-based smart pointer is shared_ptr in boost.
The whole concept looks strange to me. If you declare array on the stack, it will not exist outside the scope of your function. If you allocate it using 'new' - make sure you 'delete' it sometime, otherwise it's memory leak!
The correct code with 'new' is:
int *blah = new int[4];
...
// don't forget to:
delete [] blah;
I'm not sure if I got right what you want to do, but in case you want to return a reference to an int array which will be valid after randomFunction returns, a good way to do it is with Boost:
#include <boost/shared_ptr.hpp>
#include <vector>
boost::shared_ptr<std::vector<int> > randomFunction(int x, int y, int width, int height)
{
boost::shared_ptr<std::vector<int> > blahPtr(new std::vector<int>(4));
(*blahPtr)[0] = x;
(*blahPtr)[1] = y;
(*blahPtr)[2] = width;
(*blahPtr)[3] = height;
return blahPtr;
}
You don't have to remember about deleteing blahPtr -- when all copies of it go out of scope, Boost will delete your std::vector object automatically, and C++ standard library will delete the underlying array.
It looks like you want a 4x4 array, in which case you should create it like so (untested code from the top of my head):
int **blah = new int* [4];
for(int i = 0; i < 4; ++i)
{
*blah[i] = new int[4];
}
Alternatively you can create a 1D array and treat it like a 2D array:
int *blah = new int[16];
#define ELEM(x,y) w*4+h
blah[ELEM(1,1)] = 123;