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;
}
Related
I'm learning c++ using the book:Programming Principles and Practice using C++ by Bjarne Stroustrup.
In Chapter 19, exercise 1
implement strdup() functions which will copy a c strings into another using only de-referencing method (not subscripting).
My copying doesn't print anything I've been look for answers for days.
Please anyone can help me?
Below is the entire code:-
#include <iostream>
using namespace std;
char* strdup(const char* q) {
// count the size
int n {0};
while(q[n]) {
++n;
}
// allocate memory
char* p = new char[n+1];
// copy q into p
while(*q) {
*p++ = *q++;
}
// terminator at the end
p[n] = 0;
return p;
}
int main()
{
const char* p = "welcome";
cout << "p:" << p << endl;
const char* q = strdup(p);
cout << "q:" << q << endl;
// check to see if q get new address
cout << "&p:" << &p << endl;
cout << "&q:" << &q << endl;
return 0;
}
using only de-referencing method (not subscripting)
So this is already wrong, because is uses the subscript operator []:
// count the size
int n {0};
while(q[n]) {
++n;
}
I just don't know how to turn the pointer back to the first char.
Well, there are two basic approaches:
stop damaging your original pointer in the first place. You can introduce new variables, remember?
char* p_begin = new char[n+1];
char* p_end = p_begin + n + 1; // copy the terminator too
for (char *tmp = p_begin; tmp != p_end; *tmp++ = *q++) ;
return p_begin;
you know exactly how far to move p to get back to the original value, because you already calculated how long the string is!
while(*q) {
*p++ = *q++;
}
*p = 0; // you already moved p and aren't supposed to be subscripting anyway
return p - n;
Finally, you can get the size without subscripting using exactly the same technique: either you use a temporary variable to find the terminator, or if you advance q as you go, then subtract n from it again at the end.
Oh, and if you're having trouble visualizing the values of all your variables - learn to use a debugger (or just add lots of print statements). You need to understand how your state changes over time, and watching it is much more helpful than just observing the result of a black box and trying to guess what happened inside.
Replace this:
while(*q) {
*p++ = *q++;
}
..with this:
for (int i = 0; i < n; i++) {
p[i] = q[i];
}
Problem solved.
Just a question about deallocation through a double pointer.
Would the following basic example be correct?
#include <iostream>
int main()
{
int **d = { new int*[3] };
int * p = { new int[100] } ;
p[0] = 300;
int *x = new int(1);
d[0] = p;
d[1] = x;
// pointer in d[0] is a pointer to an array
// so use this:
delete[] d[0];
// pointer in d[1] is not a pointer to an array
// so use this:
delete d[1];
std::cout << p[0] << " " << x << '\n';
}
You (try to) access p[0] after your delete[] d[0]; call, and d[0] has the p address as its value, so that delete[] call frees the p memory. This means your cout statement is undefined behaviour (when I run it, I get a 'random' value for p[0]).
Move the cout line to before the delete[] d[0] call, and you'll see the value of 300.
Also, you never free the d array! Add this line to near the end of your main: delete[] d;.
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.
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.