The situation is:
int main ()
{
int *p1 = new int[50];
int *p2 = p1;
...
When I want to delete my array I do:
delete[] p1;
Can I do it also with this:
delete[] p2;
?
Both pointers are pointing to the same memory, so you can use either one when you delete[]. But only do it once, deleting already deleted memory is undefined behavior. So if you do delete[] p1; then you can't do delete[] p2; as well, it's one or the other.
If not to delve into the details the definition of the delete operator looks the following way
delete expression
delete [ ] expression
As you can see it uses an expression (more precisely a cast expression). For example you could write
int *p1 = new int[50];
int *p2 = p1 + 50;
delete [] ( p2 - 50 );
(Notice that you have to enclose in parentheses expression p2 - 50.)
The expression is evaluated and its values is used as the address of the memory being deleted.
After deleting the memory you may not access it. Otherwise the bahaviour of the program will be undefined.
Since p2 points to the same block of memory that was allocated by p1 then yes, p2 can be used to erase that block of memory.
You can verify this by running the following code...
#include <iostream>
using namespace std;
int main()
{
int* p1 = new int[10];
int* p2 = nullptr;
for (int i = 0; i < 10; i++) {
p1[i] = i * i;
}
// 1st run
for (int i = 0; i < 10; i++) {
cout << p1[i] << " ";
}
cout << endl;
p2 = p1;
if (p2 != nullptr) {
delete p2;
}
// 2nd run;
for (int i = 0; i < 10; i++) {
cout << p1[i] << " ";
}
p1 = nullptr;
p2 = nullptr;
return 0;
}
The 2nd run through the p1 array shows that the content of that array was deleted by the delete p2 operation which was put in an if statement for safety.
The two pointers can be put to rest, once their use is over, by equating them to nullptr keyword.
Related
int main()
{
int *dizi = new int[3];
int *ptr = new int;
*dizi = 1;
*(dizi + 1) = 2;
*(dizi + 2) = 3;
ptr = (dizi + 2);
delete ptr;
for (int i = 0; i < 2; i++)
{
cout << *(dizi + i) << endl;
}
delete[] dizi;
}
I want to return the dizi[2] value but I can't, it just crashes how can I do this, can you give me an example?
Trying to delete ptr is the same as trying to delete dizi[2] as you can read in the comment section delete must be used in an address returned by new. The behavior of your program is undefined.
You also have a memory leak, the memory allocated and assigned to ptr will be inaccessible when you reassign ptr.
If you want to assing the value of dizi + 2 to ptr you would need:
//...
int *ptr = new int;
*ptr = dizi[2]; // or *(dizi + 2);
std::cout << *ptr; // use it
delete ptr; // delete if after use
//...
If, on the ther hand, your intention is to assing dizi + 2 (or &dizi[2]) to ptr, no memory allocation is needed for ptr you can just make the assignment directly:
//...
int *ptr = dizi + 2;
std::cout << *ptr;
//...
Note that, in this case, after the array deletion, ptr becomes dangling, you can no longer use it while it's pointing to dizi + 2.
Getting the sound of an error (or may be exception), but not a pop-up window of it, so can't understand what's wrong. After debugger usage, realized that the error comes from the destructor. So i'm getting the result "August" but the program don't stop working after that. Assume that the problem is in releasing memory. Thanks in advance.
#include <iostream>
using namespace std;
class B_class {
char *p;
public:
void put_author(char *p) {
this->p = new char[strlen(p)];
for (int i = 0; i < strlen(p) + 1; i++)
*(this->p + i) = *(p + i);
}
void show_author() {
for (int i = 0; i < strlen(p) + 1; i++)
cout << *(p + i);
cout << endl;
}
~B_class() {
if (*p) {
delete[] p;
p = nullptr;
}
}
};
int main() {
B_class B;
B.put_author("August");
B.show_author();
return 0;
}
this->p = new char[strlen(p)];
You've allocated strlen(p) characters.
for (int i = 0; i < strlen(p) + 1; i++)
*(this->p + i) = *(p + i);
You write strlen(p) + 1 characters into the array. That's one more than the length of the allocated array. The behaviour of accessing an array outside of its bound is undefined.
You can fix this by allocating sufficiently large buffer.
If you created an instance of B_class, but never call put_author, you'd be calling delete[] p on an uninitialized pointer. The behaviour would be undefined.
You can fix this by initializing the p member in a constructor. Either to nullptr, or some buffer allocated using new[].
if (*p) {
delete[] p;
You only delete p if it isn't an empty string. So, if you did B.put_author("");, the memory would leak.
You can fix this by removing the if.
You happen to not do this in your example, but if you made any copies of B_class instances, the destructors of those instances would attempt to delete the same buffer, which would result in undefined behaviour.
You can fix this by following the rule of zero / three / five. The conventional approach would be to use std::string and get rid of your destructor.
This is my simple program that has two functions, one is to create a series of Fibonacci then add it to an array. Another one is used to deallocate the array, but it doesn't work. Can someone help me?
int **createFibArray(int n){
int **arr = new int*[n];
int fnum1 = 1,fnum2=1,fnum;
// n== 1
if(n == 1){
arr[0] = new int;
*arr[0] = 1;
return arr;
}
// n>= 2
arr[0] = new int;
arr[1] = new int;
*arr[0] = 1;
*arr[1] = 1;
// fib calculator
for(int i=2; i<n; i++){
fnum = fnum1 + fnum2;
fnum1 = fnum2;
fnum2 = fnum;
arr[i] = new int;
*arr[i] = fnum;
}
return arr;
}
//This function takes an array pointer, and deallocates memory
void removeArray(int head[]){
delete [] head;
head = nullptr;
}
int main(){
int **head = createFibArray(10);
for(int i=0;i<10;i++){
cout << *head[i] << endl;
}
cout << "------" << endl;
removeArray(*head);
for(int i=0;i<10;i++){
cout << *head[i] << endl;
}
return 0;
}
You need to strongly consider returning an array of integers rather than an array of integer pointers. If you insist on using a raw pointer rather than an STL container:
int **createFibArray(int n)
Should be
int *createFibArray(int n)
And this:
int **arr = new int*[n];
will be this:
int *arr = new int[n];
Then you can remove the * from nearly every place you use it, and the delete function can remain pretty much unchanged. You will change the call to the delete function:
removeArray(*head);
becomes:
removeArray(head);
However, setting the value to nullptr in the function is worthless. either do so after the call to removeArray or omit it entirely if you are certain it will never be reused after being deleted.
Which brings us to the last part of your main function. Dereferencing a pointer after you have deleted it (or attempted to delete it in this case) is undefined behavior.
Ok so I am going to lay out two programs. Both are dynamic arrays using pointers and the new operator. But one doesn't seem to like the delete operator.
#include <iostream>
int main()
{
int *p;
p = new int[5];
for (int i = 0; i < 5; i++)
{
p[i] = 25 + (i * 10);
std::cout << p[i] << " ";
}
std::cout << std::endl;
delete [] p;
p = NULL;
return 0;
}
That's the first program. It likes the delete operator just fine. Now the program that dislikes the delete operator:
#include <iostream>
int main()
{
int x;
int *p;
p = new int[5];
*p = 4;
for (int i = 0; i < 5; i++)
{
std::cout << *p << " ";
x = *p;
p++;
*p = x + 1;
}
std::cout << std::endl;
delete [] p;
p = NULL;
return 0;
}
This program compiles just fine. But during execution, it throws an error - free(): invalid pointer: 0xfdb038 .. or whatever the memory address is for that particular execution. So, the question is:
Why can't the delete operator be used in the second case?
I don't want to have memory leak; I don't want the pointer to be dangling.
If I just say p = NULL;, then p = 0, but I believe the pointer is still dangling?, but I'm not sure. Thanks in advance.
Look at this loop in the second piece of code:
for (int i = 0; i < 5; i++)
{
std::cout << *p << " ";
x = *p;
p++;
*p = x + 1; // <--- Here
}
Notice that in this line, you write to the memory address currently pointed at by p. Since you always increment p and then write to it, you end up writing off past the end of the region that you allocated for p. (If we imagine pOrig as a pointer to where p initially points, then this writes to pOrig[1], pOrig[2], pOrig[3], pOrig[4], and pOrig[5], and that last write is past the end of the region). This results in undefined behavior, meaning that literally anything can happen. This is Bad News.
Additionally, delete[] assumes that you are passing in a pointer to the very first element of the array that you allocated. Since you've incremented p so many times in that loop, you're trying to delete[] a pointer that wasn't at the base of the allocated array, hence the issue.
To fix this, don't write to p after incrementing it, and store a pointer to the original array allocated with new[] so that you can free that rather than the modified pointer p.
You have to delete the pointer that you got from new. However, in your second code you did p++ which changed the pointer. Therefore you tried to delete a pointer you didn't get from new and delete crashes.
To fix this type of error never use new. Instead use std::vector<int> p;. Since you never need new you cannot forget a delete.
Problem is changing p in p++.
You should always store (to delete) original pointer. Like this:
#include <iostream>
int main()
{
int *original = new int[5];
int *p = original;
for (int i = 0; i < 5; i++)
{
std::cout << *p << " ";
int x = *p;
p++;
*p = x + 1;
}
std::cout << std::endl;
delete [] original;
return 0;
}
I am trying to create a class analogous to the built-in vector class in C++. I have tried to follow all the instructions in Walter Savitche's textbook, but just can't get it to work properly.
The code was written using the Code::Blocks IDE and compiled using the gcc compiler.
The thing I think I'm missing is the relationship between array parameters and a pointer that points to an array.
This is what I understand about normal variables:
int *p1, *p2, *p3, *p4, a;
a = 5; // variable of type int with value 5
p1 = &a; // p1 now points to the value 5
p2 = p1; // p2 now also points to the value of a
p3 = new int; // p3 points to an anonamous variable of type int with undefined value
*p3 = *p1 // value of variable changed to the value of a, namely 5, but doesn't point to a
p4 = new int; // p4 points to an anonamous variable of type int with undefined value
*p4 = 5; // value of variable changed to 5
p4 = p1 // p4 now also points to the value of a
This is what I essentially don't understand about arrays and pointers that point to arrays
int *p1, *p2, *p3, *p4, a[3] = {4, 5, 6}; // a points to the first indexed element of the array, namely 4
p1 = a; // p1 points to the exactly the same thing as a
p2 = new int[3]; // p2 points to an array of base type int with undefined values
p2[0] = 8; // is this the correct usage? is p2 "dereferenced"
p2[1] = 9;
p2[2] = 10;
p2[2] = p1[2]; // again is this correct? is the third element of the array pointed to by p2 now equal to 6?
*p3 = a // what does this mean?
p4 = new int[4]; // p4 points to an array of base type int with undefined values
p4[0] = p2[0];
p4[1] = p2[1];
p4[2] = p2[2];
p4[3] = 3
p2 = p4 // p2 now points to p4, but what happens to the array p2 was pointing to?
delete [] p2; // does this destroy the pointer and the array it is pointing to or just one or the other?
For completeness sake my class is defined as follows:
class VectorDouble
{
public:
// constructors
VectorDouble(); // default constructor
VectorDouble(int init_count); // user specified
VectorDouble(const VectorDouble& vd_object); // copy constructor
// destructor
~VectorDouble();
// accessors
int capacity_vd(); // get max_count
int size_vd(); // get amt_count
double value_at(int index); // get value of "value" at index i
// mutators
void push_back_vd(double put_at_end); // insert new element at end of "value"
void reserve_vd(int incr_capacity); // set max_count
void resize_vd(int incr_size); // set amt_count
void change_value_at(double d, int index); // set value of "value" at index i
// overloaded =
void operator =(const VectorDouble& vd_object_rhs);
// other
friend bool operator ==(VectorDouble vd_object1, VectorDouble vd_object2);
private:
double *value; // pointer that points to array of type double
int max_count; // the memory allocated to the array
int amt_count; // the amount of memory in use
};
And the troublesome function is:
void VectorDouble::push_back_vd(double put_at_end)
{
double *temp;
if(amt_count == max_count)
max_count += 1;
temp = new double[max_count];
for(int i = 0; i < amt_count; i++)
temp[i] = value[i];
amt_count += 1;
temp[amt_count] = put_at_end;
value = temp;
}
The member function just seems to insert 0.0 instead of the user input, I have no idea why...
In main:
VectorDouble vec1(10);
double dd;
cout << "Enter 3 doubles to vec1:\n";
for(int i = 0; i < 3; i++)
{
cout << i << ": ";
cin >> dd;
vec1.push_back_vd(dd);
}
cout << "The variables you entered were:\n";
for(int i = 0; i < 3; i++)
cout << i << ": " << vec1.value_at(i) << endl;
I enter:
12.5
16.8
15.2
I get back:
0
0
0
I fixed it! Only problem is that the mistake was exceedinly simple. Sorry to waste everybodies time, but thanks to all, I did learn quite a lot!
The mistake was my placement of amt_count += 1;, I'm used to arrays indexed from 1 not zero (I have done a lot of coding in the R language). The corrected code with the memoery leak taken care of is:
void VectorDouble::push_back_vd(double put_at_end)
{
double *temp;
if(amt_count == max_count)
max_count += 1;
temp = new double[max_count];
for(int i = 0; i < amt_count; i++)
temp[i] = value[i];
temp[amt_count] = put_at_end;
amt_count += 1;
delete [] value;
value = temp;
}
This is what I understand about normal variables
All correct, with the caveat that I'd avoid the terminology "points to the value x"; you're pointing to the object, which in turn has value x.
This is what I essentially don't understand about arrays and pointers that point to arrays
You're confusing pointers with arrays. In int a[3], a is an array. It is not a pointer. It is an array.
*p3 = a isn't valid, so it means nothing.
p2 now points to p4, but what happens to the array p2 was pointing to?
You've leaked it.
// does this destroy the pointer and the array it is pointing to or just one or the other?
It destroys the thing you new'd, that the pointer is pointing to. i.e. the array
Otherwise all correct.
As for your vector implementation, the main problem is that temp[amt_count] is an overflow because you've already incremented amt_count. Also, vector implementations typically grow exponentially rather than on-demand. Finally, you're leaking the previous storage.
Using different terminology might help you:
A pointer is just an ordinary variable. Instead of holding an integer, a float, a double, etc., it holds a memory address. Consider the following:
int* p = nullptr; // p has the value "nullptr" or null memory address
int i = 5; // i has value 5
p = &i; // p now has the value of the address of i
The ampersand gets the address of a variable.
An asterisk dereferences a pointer; that is it will get the value stored in the memory address the pointer holds:
cout << *p << endl; // Prints whatever is stored in the memory address of i; 5
As for your vector implementation, try moving this line amt_count += 1; to below this line:
temp[amt_count] = put_at_end;, as you're trying to access beyond the end of your array.
Most of your understanding is correct. But...
a[3] = {4, 5, 6}; // a points to the first indexed element of the array, namely 4
Although arrays and pointers can be indexed and treated in a similar fashion, they are different, and their differences can lead to some sneaky bugs; so be careful with this statement.
*p3 = a // what does this mean?
This is invalid. Your types don't match: *p3 is an integer, a is an array.
p2 = p4 // p2 now points to p4, but what happens to the array p2 was pointing to?
The array p2 was pointing to is now leaked memory. This is bad.
delete [] p2; // does this destroy the pointer and the array it is pointing to or just one or the other?
The value of the pointer does not change. However, the memory it points to is deallocated, so dereferencing it will give you undefined results. It's best to set p2 = nullptr; after deleting it.
This answer might help with your understanding of arrays and accessing their elements.
"p2 now points to p4, but what happens to the array p2 was pointing to?"
It is 'leaked', this means its still allocated but there is no way to reach it anymore. If you keep doing this is the same program your memory size will keep growing
Other languages (Java, c#,...) have 'garbage collectors' that detect when this happens and will free the memory automatically
C++ solution to this problem is to never user naked arrays and pointers. Instead you use std::vector and std::shared_ptr; these will clean up for you
Your function is really wrong...
void VectorDouble::push_back_vd(double put_at_end)
{
double *temp;
if(amt_count == max_count)
max_count += 1;
temp = new double[max_count];
for(int i = 0; i < amt_count; i++)
temp[i] = value[i];
amt_count += 1;
temp[amt_count] = put_at_end;
value = temp;
}
Notice that in each call you allocate new array (even if there's still space), copy everything in it and leak memory (old array)...
Here is a slightly corrected version, but it's not guaranteed to be completely OK (;
void VectorDouble::push_back_vd(double put_at_end)
{
if(amt_count == max_count)
{
max_count += 1;
double *temp = new double[max_count];
for(int i = 0; i < amt_count; i++)
temp[i] = value[i];
delete[] value;
value = temp;
}
value[amt_count] = put_at_end;
amt_count += 1;
}