I am new to c++ and trying out some stuff.
So recently I tried to create an int array on the heap and iterate it with addressation instead the standard way with [x].
Everytime I execute my code I get a heap corruption error.
I tried several things (also searched here on stackoverflow) but could not find any answers.
int* p = new int[5];
for (int i = 0; i <= 4; i++){
/*p[i] = i;
cout << p[i] << endl;*/ //This is the standard way and works
*p = i;
cout << *p << endl;
p = (p + sizeof(*p)); //iterate the pointer through the heap addresses
}
delete[] p;
The application runs and shows me the filled array values {0,1,2,3,4} but then crashes.
I get following error message:
HEAP CORRUPTION DETECTED: after CRT Block (#225) at 0x00C31B68.
CRT detected that application wrote to memory after end of heap buffer...
Thanks in advance
When you do this
p = (p + sizeof(*p));
you are taking sizeof(int) int-sized steps across the array, going beyond its bounds.
You need to take single steps:
p = (p + 1);
or
++p;
But note that after doing that, p no longer points to any place you can call delete[] on. You need to keep a pointer to the original address:
int* arr = new int[5];
int* p = arr;
....
delete[] arr;
But you have no reason to allocate the array with new in the first place.
int arr[5];
int * p = arr;
....
p = (p + sizeof(*p));
results in a jump of 4 with every iteration, as sizeof(int) is equal to 4. Hence, you are going out of bounds.
The standard way, that is :
p[i] = i;
cout << p[i] << endl;
is correct, as i increases by 1 in every iteration.
This statement
p = (p + sizeof(*p));
is wrong.
First of all you are changing the initial value of pointer p that points to the allocated memory.So this statement
delete[] p;
will be wrong for this pointer because initial value of p was changed.
Secondly expression p + sizeof(*p) means that you want to move the pointer right to sizeof( *p ) elements. If for example sizeof( *p ) is equal to 4 then after statement
p = (p + sizeof(*p));
p will point to fifth element of the array (that is with index 4).
Valid code can look the following way
int* p = new int[5];
for ( int i = 0; i < 5; i++){
*( p + i ) = i;
cout << *( p + i ) << endl;
}
delete[] p;
In pointer arithmetics an expression p + i, where p is a pointer to an array's element and i is integer, is equivalent to &(p[i]), that is a pointer to the array's element i positions after the one pointed at by p.
That's why stepping to the next element is performed by p = p+1 (or equvalently p += 1 or simply ++p).
Note however the incrementation does no checking for the array bounds – you're able to safely access the next item(s) provided they belong to the same array. If you step beyond the last item of an array you may get memory access error or just read some garbage.
See for example
http://www.tutorialspoint.com/cplusplus/cpp_pointer_arithmatic.htm
https://www.eskimo.com/~scs/cclass/notes/sx10b.html
Related
#include <iostream>
int main()
{
int v = 2;
int* arr = (int*)_malloca(v * sizeof(int));
arr[0] = 200; //shows dereferencing null ptr
std::cout << *arr;
}
I have used _malloca() to do memory allocation of dynamic array on the stack (I know vector is there, I just wanted to experiment with _malloca). I just wanted to know how it works but unlike new this gives a dereferencing warning and it is not causing runtime error here. The arr has a memory address and even takes in values and prints them. What am I missing?
The answer is given by #NateEldredge
It's a warning. _malloca can return NULL if the allocation fails, and your code doesn't test for this. It's saying it might dereference a null pointer.
So I added an if statement to check for NULL. Also, in debug mode _malloca always allocates memory in the heap. So, also check the code in release mode.
#include <iostream>
int main()
{
int v = 4;
int* arr = (int*)_malloca(v * sizeof(int));
if(arr != NULL) //a check is required if _malloca was able to allocate memory
for (int i = 0; i < v; i++)
{
arr[i] = i * 2;
std::cout << arr[i]<<"\n";
}
_freea(arr); //freeing the memory
}
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'm in a data structures course, our midterm is coming up and our practice midterm asks if each line is valid syntax:
int num = 10;
int *p, *q;
p = #
q = p; //valid
*p = q; //invalid, int* cannot be assigned to int
(*p)++; //valid
&num+1; //valid ********
p++; //valid ********
So the last two lines of code, as I understand it, add 1 to the address of the num variable.
What purpose would this have in coding?
In this case, that would lead to undefined behavior. It would address the int that follows num in memory, but there is no defined way to tell what that would be. Nonetheless, it is valid syntax.
It would make a great deal more sense if your pointer pointed to an element of an array instead of a scalar. In that case, addressing the next int is reasonable. But in both cases the syntax is valid.
A purpose this would have in coding is to write tests such as:
void f ( size_t length, int data[length] )
{
assert( 0 == length % 4 );
for ( int* p = data; p < data + length; p += 4 )
do_stuff_with_subarray( p, 4 );
return;
}
The loop condition p < data + length bounds-checks the pointer by comparing it to the address one past the end of the array. Dereferencing this address would be undefined behavior, but comparing to it is not. (In this simplistic example, though, there will be UB if do_stuff_with_subarray() ever reads past the end of an array whose length is not divisible by 4.)
In C++, following the code below:
char *p = new char();
*p = 'a';
*(p+1)= 'b';
*(p+2) ='\0';
cout<<p<<endl;
we can get the output result: ab
When I want to write the code like this:
int *p = new int();
*p = 1;
*(p+1)= 2;
cout<<p<<endl;
It gives the result, but not 12 or something start with 12
Question is why the result goes wrong when changing it from char to integer? How to realize the goal that output a list of value by using a pointer dynamic array?
This is because char * is a bit of a special case.
In the C days, char * was the only type we really had to deal with strings. C++ makes it easier to interoperate with legacy code by providing streaming operators that treat char * values specially, by streaming out each character until a null character ('\0') is encountered.
When you stream out p when it's an int * there is no special case -- you just get the raw pointer value displayed.
If you want a one-liner to display the elements in a standard container, you can combine std::copy() with std::ostream_iterator:
std::copy(std::begin(some_array),
std::end(some_array),
std::ostream_iterator<int>(std::cout));
Since your array is allocated on the heap and stored in a pointer, std::begin() and std::end() won't work for you; you'll have to provide the end iterator manually:
std::copy(p, p + 2, std::ostream_iterator<int>(std::cout));
(See a demo.)
But note that both code samples in your question are undefined behavior, because you allocate a single object of type char or int and then try to assign beyond it. You write into memory you haven't allocated. Don't do this.
To fix your cases, you need to allocate enough room for the objects you intend to store:
// Case one
char *p = new char[3];
// Case two
int *p = new int[2];
And, of course, don't forget to delete[] p in both cases -- or you could just use std::string in the first case and std::vector<int> in the second.
Ok, first of all, this is unsafe:
*(p+1)= 'b';
You only allocated one byte and now you're stomping on memory you don't own - which is undefined behavior. If you want to allocate 3 bytes, do it:
char* p = new char[3];
Secondly, this:
int* pi = new int;
cout << pi << endl;
Will print the address of the pointer. char* is special in that cout will actually print the C-style string that is pointed to, but for other types - you just get the address.
If you want to print 12, you have to dereference the pointer:
int* pi = new int(12);
cout << *pi << endl;
If you want to output 1 and 2, separately, you need an array:
int* pi = new int[2];
pi[0] = 1;
pi[1] = 2;
cout << pi[0] << ", " << pi[1] << endl;
Note that, again, *(p + 1) = 2 in your code is stomping on memory you don't own.
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;
}