struct item
{
unsigned int a, b, c;
};
item* items[10];
delete items[5];
items[5] = NULL;
The above code works
But the below method is not working
int * arr1[30];
delete (arr1+5);
I am a beginner, Please tell me why I am able to delete in case of structure pointer but not in case of int
pointer
You're seemingly misunderstanding what delete is for: it's purely and simply to release memory allocated by new, not to 'delete' elements of arrays.
So you might use it like this:
int *p = new int;
//...
delete p;
When you allocate arrays, you must instead use delete[], like this:
int *q = new int[23];
//...
delete [] q;
But at no point should you try and delete something that hasn't been new'ed, or use the non-matching version of delete, e.g. delete [] p; or delete q; above.
If what you really want is some sort of 'array' from which you can remove elements, try this:
#include <vector>
struct item
{
unsigned int a, b, c;
};
int main()
{
std::vector<item> items(10);
items[5].a = 23;
items.erase(items.begin() + 5);
return 0;
}
Are you allocating heap memory anywhere? You are not doing so in the code above. You are lucky that the first delete does not crash.
When using the (arr1+5) approach, you are passing the memory address of the array slot itself at index 5, not the int* that the slot contains. To delete the int* that is contained in the slot at index 5, you have to dereference the pointer value, eg:
delete *(arr1+5);
Related
void foo(int i)
{
char* p = new char[10];
if (i)
{
p = 0;
}
delete[] p;
}
In the above code snippet, p resource was referenced to zero. Will this create a memory leak in my code?
Yes it leaks in case i != 0.
Your variable p points to some address in memory and by doing p = 0; you erase that pointer. So the instruction delete[] p; will work for a nullptr pointer and you'll not free the allocated memory.
For this type of problems we use smart pointers (unique_ptr, shared_ptr, ...) and STL containers and objects like std::string, std::vector<char>, std::list<char> and so on.
So, in your case you have to change code to something like that
{
char* p = new char[10];
if (i)
{
if (p) {
delete[] p;
p = 0;
}
}
if (p) {
delete[] p;
p = 0;
}
}
Inside your function foo, you are setting the value of the pointer p, which actually is a pointer to the beginning of your dynamic array, to 0 if i is non-zero:
if(i)
{
p = 0;
}
Therefore, when i is non-zero, p no longer points to the start of your array and the delete command will fail to deallocate the array that you create inside the function.
So yes, when i is non-zero, your function will leak memory. I wouldn't change p if I were you. Keep that unchanged until the end so that you call delete [] on it and deallocate the array.
Alternatively, consider using a std::vector instead:
std::vector<char> vec(10);
This does something equivalent except it will take care of the memory allocation/deallocation for you automatically.
I'm getting this error when I try to compile my code.
I dont have any *(pointers) and can't understand why im getting this.
Im working now with template. You can check my code too see:
#include <iostream>
#include <cstdlib>
#include <stdlib.h>
#include <conio.h>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <algorithm>
using namespace std;
template <class T>
class Set
{
public:
T **p;
int n;
Set(){
};
Set(int n)
{
this->n = n;
p = new T*[n];
}
~Set()
{
if(p) delete []p;
}
void setValues(T k,int l)
{
p = k;
n = l;
}
void add(T k)
{
T p1;
p1 = p;
p = new T[n+1];
p = p1;
p[n+1] = k;
n++;
}
void remove(T k)
{
T p1;
int l =0;
p1 = p;
p = new T[n-1];
for(int i=0;i<n;i++)
if(p1[i]!=k)
{
p[l] = p1[i];
l++;
n--;
}
}
void operator+(Set s)
{
for(int i=0;i<n;i++)
p[i]+=s.p[i];
}
void operator-(Set s)
{
for(int i=0;i<n;i++)
p[i]-=s.p[i];
}
void operator*(Set s)
{
for(int i=0;i<n;i++)
p[i]*=s.p[i];
}
void show()
{
for(int i=0;i<n;i++)
cout<<p[i]<<" | ";
}
};
int main()
{
Set<int> s1,s2;
int arr[]={0,2,3,4,3,6};
int n=6;
float arr2[]={0.5,12.1,1.7,23.15};
char arr3[]={'a','h','m','k','c','e'};
s1.setValues(arr,n); // <------------- here is error;
s1.show();
}
I'm getting error on this line s1.setValues(arr,n);
This is setValues() method:
void setValues(T k,int l)
{
p = k;
n = l;
}
I had tried to avoid the error by using & like that: s1.setValues(arr,&n)
and s1.setValues(arr,*n)
Also I tried to change it in method: void setValues(T k,int &l) and void setValues(T k,int *l)
in class: public:
T **p;
int *n; and public:
T **p;
int &n;
In my first version I have tried to use: s1.setValues(arr,6) where 6 is the length of the array. But I was also getting the error;
Edit: I had misread the type of p, and also apparently read the error backwards.
The class is intantiated with T as int. All arrays decay to pointers, so arr is of type int*. This means you cannot pass it in as the first argument of setValues.
void setValues(T k, int l);
...
s1.setValues(arr, n); //arr is type int*, but k is of type int.
I'm afraid I don't understand what your code is doing well enough to suggest how you might want to fix it, but this is why the compiler is emitting that error.
Preliminary remark: since you do not use std::set I suppose this is an exercise, and that you are not allowed to use std::vector which would considerably facilitate the management of p
The problem(s)
There are some contradictions in this code, and some more errors that do not appear yet because the corresponding template member function is not used:
The member T** p is defined as a pointer to pointer of T
In the constructor you allocate an array of pointers to T, which will give you indeed a pointer to pointers of T.
But in add() and remove() you try to reallocate p's with an array of T, which will give you a T* instead of T**. In addition you clearly want to add or remove a value and not a pointer.
But in set value, it is not clear if you want to set a single value (which the T k in the signature suggests) or if you want to set all the values from an array (which the length argumen int l suggests). Given the name of the function has Values in plural, I will assume the second alternative.
Solution Step 1: Get it to compile. But it won't really work
You need to correct:
T *p;
and adapt the constructor accordingly with p = new T[n];
auto p1 = p;
You then need to change your function definition to:
void setValues(T k[],int l) // option 1
void setValues(T *k,int l) // or option 2
The good news is that the code will then compile
The bad news is that it will not do what you want. Furthermore the code of the function and some other problems will cause UB (meaning that a lot of bad things can happen, including memory corruption, crash, etc...).
Solution Step 2: assignment of arrays, pointers and the rule of 3
This code does not what you expect it to do:
void setValues(T *k, int l)
{
p = k; // OUCH !!!!!! pointer copy and not copy of the array elements
n = l;
}
Currently, you do not copy the elements of an array, but you replace a pointer. This has following consequences:
first you will leak memory, since the pointer to the allocated memory is lost and will never be freed.
second, you will make this pointer point to an array that was not allocated with new[], which might hurt you badly when you later delete[] this pointer.
third: the array to which your class points might get deleted by the owner of the array, in which case you'd use a dangling pointer.
So you need to adapt your code as follows:
void setValues(T k[],int l) // change signature
{
if (n!=l) { // if the size is the same, we'll reuse p, if not:
delete[] p; // avoid the memory to leek
p= new T[l]; // start with a fresh memory
n = l; // define new length
}
for (int i=0; i<l; i++)
p[i]=k[i]; // copy array elements one by one
}
Another important problem is the rule of 3. This is not a problem with your current main() but quickly will become: if you work with pointers in a constructor or a destructor, you should define a copy construtor and an assignement operator. If you don't, you risk to end with shallow copies of your Set (2 different object but using the same pointer).
Solution Step 3: get rid of the remaining issues
First, your default constructor leaves p and n unitialized. They could be random value, which might cause the destructor to try to delete something that was not allocated. And the same for anny other function that assumes that things that assumed the member values would be consistend. So:
Set(){
p=nullptr;
n=0;
};
Then you have similar problems in add(), that you had in setValues() with the pointer assignment. IN addition you go out of bounds, even after the realocation: the last element of an array p with n+1 element is p[n] and not p[n+1]. I let you as an exercise to improve it.
Online demo
How do I delete this allocated pointer?
int (*foo)[4] = new int[100][4];
Is it just :
delete[] foo;
As you have allocated an array you have to use operator delete[]
delete []foo;
That it would be more clear you can rewrite the code snippet the following way
typedef int T[4];
T *foo = new T[100];
delete []foo;
I have a pointer to a class, that have a pointer to a multidimensional array but I can't seem to delete it from memory when I need to or set it to NULL.
#define X 10
#define Y 10
struct TestClass
{
public:
int *pArray[X][Y];
};
// different tries, none working:
delete Pointer_To_TestClass->pArray[0][0];
delete[] Pointer_To_TestClass->pArray[0][0]
// or by simply:
Pointer_To_TestClass->pArray[0][0] = NULL;
I know the array has data because I can see the results on screen.
Also check if it's NULL already, then doesn't try to delete it.
Since I want to delete a pointer in another pointer - is this a special circumstance that works differently? Like it deletes the first pointer holding the other pointer instead of the pointer inside the pointer (pArray is the second pointer, Pointer_To_Testclass is the first pointer)
UPDATE/EXPLANATION
I want to be able to delete pArray[0][0] while pArray[0][1] still exists and if [0][0] doesn't exist it should be equal to NULL. Most because I want to access this array by [X][Y] values for easy access. If [0][0] is a pointer, it should be NULL when deleted so I can check if it is NULL.
Anyone has any ideas?
If you want a 2D array of pointers to <whatever>, create a class to handle that, then put an instance of it in your TestClass. As far as how to do that, I'd generally use something on this order:
template <class T>
class matrix2d {
std::vector<T> data;
size_t cols;
size_t rows;
public:
matrix2d(size_t y, size_t x) : cols(x), rows(y), data(x*y) {}
T &operator()(size_t y, size_t x) {
assert(x<=cols);
assert(y<=rows);
return data[y*cols+x];
}
T operator()(size_t y, size_t x) const {
assert(x<=cols);
assert(y<=rows);
return data[y*cols+x];
}
};
class TestClass {
matrix2d<int *> array(10, 10);
public:
// ...
};
Given that you're storing pointers, however, you might want to consider using Boost ptr_vector instead of std::vector.
#define X 10
#define Y 10
struct TestClass
{
public:
TestClass()
{
// Must initialize pArray to point to real int's otherwise pArray
// will have bogus pointers.
for (size_t y = 0; y < Y; ++y)
{
for (size_t x = 0; x < X; ++x)
{
pArray[x][y] = new int;
}
}
}
int *pArray[X][Y];
};
int main()
{
TestClass *Pointer_To_TestClass = new TestClass;
delete Pointer_To_TestClass->pArray[0][0];
Pointer_To_TestClass->pArray[0][0] = 0;
return 0;
}
Depends on your allocation of pArray[i][j]. If it's something like pArray[i][j] = new int; then call delete Pointer_To_TestClass->pArray[0][0];. If it's something like pArray[i][j] = new int[10] then use your second option, delete[] Pointer_To_TestClass->pArray[0][0];. I'd also highly recommend immediately following the delete with setting it to NULL and proceeding it with the check for NULL.
The third one did not compile for me delete[][] Pointer_To_TestClass->pArray[0][0]; I got the error
Line 34: error: expected primary-expression before '[' token
compilation terminated due to -Wfatal-errors.
Also, I'd highly recommend having those deletes in the destructor. Other places may be fine as well.
You may find the typedef of int* to be helpful for readability understanding you have a two-dimensional array of int*.
If you've dynamically created an array, then delete it with delete[]. You have to give delete[] a pointer to the start of the array, however, not an element of the array!
If you want the elements to be deletable, then they have to be dynamically allocated separately.
So you have to have a multi-dimensional array of pointers;
int *(*pArray)[X][Y];
Then dynamically assign each one, which yes is a pain.
It is interesting, however, that you are even attempting to do this, why do you want to delete single elements?
Consider this code:
using namespace std;
int* get()
{
unique_ptr<int> p (new int[4]);
return p.get();
}
int main(int argc, char **argv)
{
int *arr1=get();
int* arr2=get();
for(int i=0;i<4;i++)
{
arr1[i]=i;
arr2[i]=i*2;
}
for(int i=0;i<4;i++)
cout << arr1[i];
return 0;
}
arr1 and arr2 point to the same area of memory.
So they share the same values.
I don't understand why, when I call arr2=get() :
unique_ptr<int> p (new int[4]);
This object shouldn't be created again? It isn't deleted because still reachable by arr1.
How to get two arrays of different memory areas?
I am fairly sure you are playing with undefined behavior which is bad.
the data being pointed to was destroyed when the unique pointer was destroyed, the fact the values are the same, and the same slot was chosen is luck.
for pointers to array type use a vector
std::vector<int> get()
{
return std::vector<int>(4);
}
int main()
{
std::vector<int> arr1=get();
std::vector<int> arr2=get();
return 0;
}
for normal single value pointers then you can return a unique_ptr;
std::unique_ptr<int> get(){
return std::unique_ptr<int>(new int(0));
}
:::
std::unique_ptr<int> ptr=get();
There are a memory leak in such kind of usage of smart pointers. unique_ptr will use operator delete in order to free the allocated memory, but you need delete []. Also the return value of get function will be an invalid ptr because the unique_ptr will free the allocated area. If you need dynamically allocated arrays then use std::vector.