Beginner C++ programmer, confused over dynamic arrays - c++

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;
}

Related

creating pointer arrays in c++ with help of new keyword

What's the meaning of the code below?
int **matrix = new int*[n]
What's the difference here between matrix and int*[n]?
It is an array of 'n' pointers, for which memory can be allocated and initialized in loop.
If n is 3, it is an array of 3 elements and each is pointer to int, can point to set of array of integer values like below.
matrix[0] -> Ox001 points to array of int [ 1 2 3 4]
matrix[1] -> Ox017 [ 5 6 7 8]
matrix[2] -> Ox024 [ 9 10 11 12]
Sample code like this
int **m = new int*[3];
for(auto i=0; i < 3; i++)
{
m[i] = new int[3];
for(auto j=0; j < 3; j++)
m[i][j] = 0;
}
for(auto i=0; i < 3; i++)
{
m[i] = new int[3];
for(auto j=0; j < 3; j++)
cout << m[i][j];
cout << "\n";
}
for instance there is cricket team and you need
Since you have Cricket* team;, this indicates you have one of two possible
situations:
1) a pointer to a single CricketPlayer (or any derived) type
2) a pointer to an array of CricketPlayer (but not derived) types.
What you want is a pointer to an array of CricketPlayer or derived types. So you
need the **.
You'll also need to allocate each team member individually and assign them to the array:
// 5 players on this team
CricketPlayer** team = new CricketPlayer*[5];
// first one is a bowler
team[0] = new Bowler();
// second one is a hitter
team[1] = new Hitter();
// etc
// then to deallocate memory
delete team[0];
delete team[1];
delete[] team;
In your query,
It can be understood as
int *matrix[]=new int*[n];
SO there are n pointers pointing to n places.
Because
int *foo;
foo=new int[5];
will also create 5 consecutive places but it is the same pointer.
In our case it is array of pointers
You need to notice some thing as follows:
int *p means that p is a pointer that points to an int variable or points to an array of int variables.
int* *p means that p is a pointer that points to an int* variable or points to an array of int* variables.
new int[5] is an array of 5 int variables.
new int*[5] is an array of 5 int* variables.
In this case, matrix is the second type so it can point to an array of int* variables so the statement:int **matrix = new int*[n] is legal
It means that you have declared a double pointer(of type int) called matrix and allocated an array of n int* pointers. Now you can use matrix[i] as an int* pointer (0 <= i < n). Later you might want to allocate memory to individual pointers as well like matrix[i] = new int[size];(size is an int or more appropriately size_t)
matrix is an object of type int **. This type is a pointer to pointer to int.
On the other hand, int * is a type, a pointer to int.
The expression:
new int*[n]
creates n adjacent objects of type int * somewhere in memory and returns a pointer to the first of them. In other words, it allocates and constructs n pointers to int; and returns a pointer to the first. Since the first (and each of them) are int *, the pointer pointing to the first is, in turn, of type int **.
It would be absolutely clear if you remember the operator associativity and precedence.
Going by that int *[n] will be interpreted by compiler : as array of " n pointer to integers".(as [ ] has greater precedence than *, so for easy understanding, compiler interprets it that way.).
Now comming to other side int ** matrix is pointer to pointer.
When you created an array of pointer,you basically have the address of the first location ,here first location stores an pointer to integer.
So,when you are storing the address of the first address of such array you will need pointer to a pointer to point the whole array.
//code for passing matrix as pointer and returning as a pointer
int ** update(int ** mat)
{
mat[0][1]=3;
return mat;
}
int main()
{ int k=4;
int **mat = new int*[k];
for(auto i=0; i < k; i++)
{
mat[i] = new int[k];
for(int j=0;j<k;j++)
{
if(i==j)
mat[i][j]=1;
else
mat[i][j]=0;
}
}
mat=update(mat);
for(auto i=0; i < k; i++)
{
for(auto j=0; j < k; j++)
cout << mat[i][j];
cout << "\n";
}
return 0;
}

How do I properly reference this pointer multiple times?

This is my function to find the union of 2 set arrays located by a void pointer which I have issues running the first part to copy Set A into the union Set before doing comparisons with Set B
Right now the output of this code produces example
Set A = {1,5,7,8}
Union Set = {8,8,8,8} Copies last element of Set A 4 times
as the last loop causes the temp pointer to point at 8.
Do I have to create a new int pointer for each loop or is there a better way of going around this
// Note I cannot use vectors or sorting methods as it isnt in my learning scope yet so i'll have to stick to the primitive comparison way
//Definitions
// VoidPtr is Void*
// aSet is (VoidPtr *a = new VoidPtr[MAX])
// getElementI(aSet[i]) Returns an integer value at that position of the pointer
void findUnion(VoidPtr * aSet,VoidPtr * bSet,VoidPtr * unionSet,int sizea,int sizeb,int &sizec)
{
int* temp;
VoidPtr vp;
int notEqual = 0;
// Copy set a into set c
for(int i =0; i < sizea; i++)
{
*temp = getElementI(aSet[i]);
vp = temp;
unionSet[i] = vp;
}
}
int* temp;
Here temp is an uninitiaised pointer
*temp = getElementI(aSet[i]);
Here temp is being dereferenced. Dereferencing uninitialised pointers results in a program crash (at best) and all sorts of weird behaviour (at worst).
I'm finding it quite hard to understand what you really need to do, but allocating a new int pointer every time round the loop sounds reasonable. Like this
for(int i =0; i < sizea; i++)
{
int *temp = new int (getElementI(aSet[i]));
unionSet[i] = temp;
}
But I am guessing.

Deleting dynamic array using another pointer

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.

c++ array iteration with addresses - heap corruption

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

C++: The value that the pointer is pointing to changes

I am trying to code a class that represents a set of integers. It's a homework assignment but for the life of me I cannot figure out this issue.
In the class "IntSet", I have two private variables; one is a pointer to an array the other is the size of the array. I can create objects of this class and they work as intended. But I have this function named "join" that returns an object of the IntSet class. It essentially concatenates the arrays together then uses that array to create the returning object.
Here is my code:
#include <iostream>
using namespace std;
class IntSet {
int * arrPtr;
int arrSize;
public:
//Default Constructor
IntSet() {
int arr[0];
arrPtr = arr;
arrSize = 0;
}
//Overloaded Constructor
IntSet(int arr[], int size) {
arrPtr = arr;
arrSize = size;
}
//Copy Constructor
IntSet(const IntSet &i) {
arrPtr = i.arrPtr;
arrSize = i.arrSize;
}
/*
* Returns a pointer to the first
* element in the array
*/
int* getArr() {
return arrPtr;
}
int getSize() {
return arrSize;
}
IntSet join(IntSet &setAdd) {
//Make a new array
int temp[arrSize + setAdd.getSize()];
//Add the the values from the current instance's array pointer
//to the beginning of the temp array
for (int i = 0; i < arrSize; i++) {
temp[i] = *(arrPtr + i);
}
//Add the values from the passed in object's array pointer
//to the temp array but after the previously added values
for (int i = 0; i < setAdd.getSize(); i++) {
temp[i + arrSize] = *(setAdd.getArr() + i);
}
//Create a new instance that takes the temp array pointer and the
//size of the temp array
IntSet i(temp, arrSize + setAdd.getSize());
//Showing that the instance before it passes works as expected
cout << "In join function:" << endl;
for (int j = 0; j < i.getSize(); j++) {
cout << *(i.getArr() + j) << endl;
}
//Return the object
return i;
}
};
int main() {
//Make two arrays
int arr1[2] = {2 ,4};
int arr2[3] = {5, 2, 7};
//Make two objects normally
IntSet i(arr1, 2);
IntSet j(arr2, 3);
//This object has an "array" that has arr1 and arr2 concatenated, essentially
//I use the copy constructor here but the issue still occurs if I instead use
//Inset k = i.join(j);
IntSet k(i.join(j));
//Shows the error. It is not the same values as it was before it was returned
cout << "In main function:" << endl;
for (int l = 0; l < k.getSize(); l++) {
cout << *(k.getArr() + l) << endl;
}
return 0;
}
The program compiles and the output as of now is:
In join function:
2
4
5
2
7
In main function:
10
0
-2020743083
32737
-2017308032
I don't know why but the 10 and 0 are always the same every time I recompile and run. Also, if I print out the address of the pointer rather than the value(in both the join function and the main function), I get the same memory address.
Sorry if I misuse terms, I come from a java background, so pointers and such are a little new to me. If any clarification is needed, please ask.
Thanks in advance.
int temp[arrSize + setAdd.getSize()];
This is a local array, its lifetime ends once the function returned.
IntSet i(temp, arrSize + setAdd.getSize());
Here you are constructing an IntSet with this array. In fact the constructor simply changes a member pointer to the value of temp:
IntSet(int arr[], int size) {
arrPtr = arr;
arrSize = size;
}
As a result, since the lifetime of the object that temp and consequently also i.arrPtr is pointing to ends after leaving join, you will have a wild pointer. Dereferencing this pointer later in main invokes undefined behavior.
You need to allocate the array dynamically with new[] and delete it later with delete[]. The same goes for your constructors. Also note that if you use new[] in join and delete[] in the destructor, then you also have to make sure that the copy constructor actually copies the array (create new array with new[] and copy contents). If you simply assign the pointer then both the source and destination object will point to the same array and they will also both try to delete it at deconstruction, again invoking undefined behaviour.
But since this C++, you might as well use a std::vector which does all of this for you. (or std::set if you actually want a integer set)
The quickest fix with your code is to change
int temp[arrSize + setAdd.getSize()];
into this
int * temp = new int[arrSize + setAdd.getSize()];
The thing is that you allocated temp on the stack, so when join() returns that memory is releases. By allocating memory on the heap (as per the fix) the memory is not released when join() returns.
There are other things wrong with your code -- depending on the point of the assignment. I think most of these will be fixed when you consider the implications of having memory on the heap.