C++ Having issues reusing the same object to hold a different value - c++

Recently, I've been trying to understand why this error occurs:
BigNum num = 50;
num = 2;
When I create a BigNum with a value of 50, then try to input a value of 2 into it later, my program crashes.
These are the two constructors I use:
// constructor where operand is a long
BigNum::BigNum(long num) {
negative = num < 0;
unsigned long absNum = abs(num);
length = numberOfDigits(absNum);
data = new char[length];
for (int i = 0; absNum != 0; i++) {
data[i] = absNum % 10;
absNum /= 10;
}
}
// copy constructor
BigNum::BigNum(BigNum const& orig) {
int arrSize = orig.length;
data = new char[arrSize];
copy(orig.data, orig.data + arrSize, data);
negative = orig.negative;
length = orig.length;
}
// destructor
BigNum::~BigNum() {
delete[] data;
}
The elements in the object are:
bool negative;
int length;
char *data;
of which data holds digits for the BigNum.
However, the use of both of these constructors and destructor does not allow me to refactor the value of the object.
Could anyone shed some light on why this would be happening?
Thank you very much for your time.

Related

C++ Big Int Class - How to make an Add Function that will add both objects together and return a new one

so I'm trying to make a big int class for an assignment and include an addition function but i am having trouble with it.
So in the class we are storing two variables, an array and its size:
class HugeInteger {
private:
//pointer array to store every digit of the large number
int* digits;
//stores the lenght of the array
int length;
I need to make an add function that will take another object that we are given by input and add it with the current object and return it as a new object using our string constructor.
HugeInteger HugeInteger::add(const HugeInteger& h) {
int carry = 0;
int maxSize = length;
std::string final = "";
if (h.length > length) {
maxSize = h.length;
}
int* result = new int[maxSize];
for (int i = 0; i < maxSize; i++) {
int a = (i < length) ? digits[i] : 0;
int b = (i < h.length) ? h.digits[i] : 0;
result[i] = (a + b + carry) % 10;
carry = (a + b + carry) / 10;
}
if (carry > 0) {
maxSize++;
int* temp = new int[sizeof(result)+1];
for (int i = 0; i < sizeof(result); i++) {
temp[i] = result[i];
}
temp[sizeof(result)] = carry;
result = temp;
}
for (int i = 0; i < maxSize; i++) {
final.push_back(result[i] + '0');
}
This is what i have so far but it does not work at all if the objects have arrays of different size or even with carries. I don't know what Im doing wrong.
At the end im converting the array to a string since the only constructor we are allowed to implement is one that converts strings into the object.
Any hint or help is appreciated. I don't really get how I'm supposed to fix this when Im adding numbers one by one so for example:
363+
10
Is resulting in 463 currently which makes no sense. I tried going from right to left in the array like when adding numbers in real life but I dont know how to handle going out of limit of the smaller array.

Writing a private function to expand an array if capacity has run out

I am trying to write a class where it starts with a small array to put values in. My objective is if the number of values exceed the capacity, the array expands to fit the remaining values. For example, if I had 5 numbers, the array would expand to accommodate the fifth value.
The object actually creates an array at run time. So when I wrote the function to expand, its actually creating a new array and pointing to it.
Heres the class
class DVec // self expanding array
{
private:
//[0...n-1] are the values, [0..cap-1] exist
int n;
double* a;
int cap;
void expand(double*);
public:
DVec(); // constructs an empty DVec
void add(double v); //adds v to the end of this DVec
int size();
double pop(); // removes and returns the last value (pre: not-empty)
double get(int idx); // returns value at idx in this DVec
void set(double v, int idx); // sets this DVec at idx to be v
};
Constructor
DVec::DVec()
{
cap = 4;
a = new double[cap];
n = 0;
}
Heres the code that I'm testing it with
void DVec::add(double v)
{
a[n++] = v;
if (n == cap) { expand(a); }
}
void DVec::expand(double*)
{
double* temp = new double[n*2];
for (int i = 0; i < n; i++)
{
temp[i] = a[i];
}
*a = *temp;
}
int main()
{
DVec a; DVec* p = new DVec();
for (int i = 0; i < 6; i++)
{
a.add(i * i);
}
cout << a.get(5);
}
My problem is that it keeps bombing out if I set the for loop to i<6. Anything lower its fine.
It comes back say it threw exception:
if (!has_cctor)
cexit();
My questions is what is this? Is it because I made a pointer equal a pointer(a* = *temp)? Or am I not even in the same galaxy as the correct way to write the function?
Edit:
Thanks for all the help guys. I made changes and it all works now.
{
double* temp = new double[cap++];
for (int i = 0; i < n; i++)
{
temp[i] = a[i];
}
a = temp;
}
DVec::DVec()
{
cap = 0;
a = new double[cap];
n = 0;
}
void DVec::add(double v)
{
if (n >= cap) { expand(a); }
a[n++] = v;
}
This line looks like the problem:
*a = *temp;
I assume you meant to replace a with temp, but what you've written is equivalent to this:
a[0] = temp[0]
You should write this instead:
a = temp;
You also need to remember to delete a before overwriting it, otherwise you will have a memory leak, as well as to update cap, or you will have further problems.
I assume you are doing this as an academic exercise rather than as a solution to a real-world problem. If not, you should use std::vector, as the standard library implementers have already done all the hard work for you.

Setting constructor and destructor with *pointer array C++

I am using int *studentsAge to store a list of ages, and double *marks[2] to store a list of 2 marks per student.
Basically, I am not sure how to set my constructor and destructor.
This is my constructor...
Students::Students()
{
num = 0;
studentsAge = NULL;
marks[2] = NULL;
}
I use both pointer arrays in this function...
void Students::storeValues(int num)
{
this->num = num;
studentsAge = new int[num];
for(int i=0; i<num; i++)
{
studentsAge[i] = i;
marks[i] = new double[num]
}
}
This is my destructor...
Students::Students()
{
for(int i=0; i<num; i++)
{
delete[] marks[i];
delete[] studentAge[i];
}
delete[] marks;
delete[] studentAge
}
I am not sure if my constructor and destructor are right and I can suspect a memory leak somewhere. I am not too good with pointers, but I would appreciate it if someone could tell me where I am going wrong
It's a better design to keep each student together:
struct Student
{
int marks[2];
int age;
};
Then store a container of students:
struct Students
{
std::vector<Student> students;
void storeValues(int num);
}
Your function would look like:
void Students::storeValues(int num)
{
students.resize(num, Student()); // zero-initialized students!
for(int i=0; i<num; i++)
students[i].age = i;
}
This way you do not need to write any destructors, or any other functions in the Rule of Five, so you reduce the opportunity to make errors and avoid wasting time writing boilerplate code.
There's no reason to use your 2 element array of marks. make it easy on yourself and change it to 2 double*'s marks0 and marks1.
double* marks0;
double* marks1;
However if you want to continue on the current path, first you need to initialize marks correctly:
Students::Students()
{
num = 0;
studentsAge = NULL;
marks[0] = NULL; //clear the pointer to the first array of marks
marks[1] = NULL; //clear the pointer to the second array of marks
}
Now you need to create the marks arrays correctly:
void Students::storeValues(int num)
{
this->num = num;
studentsAge = new int[num];
marks[0] = new double[num];
marks[1] = new double[num];
for(int i=0; i<num; i++)
{
studentsAge[i] = i; //what is this doing? each student's age is the same as his/her index?
marks[0][i] = 0; //initialize the first mark for student i
marks[1][i] = 0; //initialize the second mark for student i
}
}
Finally you need to destroy the arrays correctly:
Students::~Students()
{
delete[] marks[0];
delete[] marks[1];
delete[] studentsAge;
}
I am guessing your Students class looks a bit like this as far as your main fields are concerned:
class Students
{
private:
static const int maxNumberMarks = 2; //the maximum number of marks that can be stored per student
int numStudents; // the count of the number of students
int* studentsAge; // an array of each students ages
double* marks[maxNumberMarks]; // an array of arrays to store each student mark
}
In which case your default constructor is almost right. You just needed to initialise your marks array correctly.
Students::Students()
{
num = 0;
studentsAge = NULL;
for( int markIndex = 0; markIndex < maxNumberMarks; ++markIndex )
{
marks[markIndex ] = NULL;
}
}
Your initialisation function is a bit more confused.
First off I would rename the input num arg to something like numStudents so as to not get confused with the member variable of the same name.
Secondly you need to separate the allocation of your arrays from initialising them
void Students::storeValues(int numStudents )
{
this->num = numStudents ; //store off how many students we are handling.
//allocate 3 storage arrays for each student. The age array and 2 mark arrays
studentsAge = new int[numStudents ];
for( int markIndex =0; markIndex < maxNumberMarks; ++markIndex)
{
marks[markIndex] = new double[numStudents];
}
//now init the arrays to something
for(int studentIndex=0; studentIndex < numStudents ; studentIndex++)
{
studentsAge[studentIndex] = studentIndex;
for( int markIndex =0; markIndex < maxNumberMarks; ++markIndex)
{
marks[markIndex][studentIndex] = 0.0; //zero seems a reasonable initial value.
}
}
}
Finally to get the destructor you just need to mirror the code that allocated the arrays.
~Students()
{
//delete the marks arrays
for( int markIndex =0; markIndex < maxNumberMarks; ++markIndex)
{
delete[] marks[markIndex];
marks[markIndex] = NULL;
}
//delete the ages array
delete[] studentsAge;
studentsAge = NULL;
}
As your code grows it likely you will want to store different data for each student I would recommend creating a Student class to help simplify everything.
class Student
{
private:
static const int maxNumberMarks = 2; //the maximum number of marks that can be stored per student
int age; //the age of the student
double marks[maxNumberMarks];
}
Assuming you flesh out the Student array with appropriate Default constructor this simplifies all the many allocations to just one place in the Students class
Students
{
Student* studentsArray; //dynamically allocated array of student info
int numStudents;
}
void Students::storeValues(int numStudents )
{
this->num = numStudents ;
studentsArray = new Student[numStduents];
}
~Students()
{
delete[] studentsArray;
studentsArray = NULL;
}
And if you use the std::vector in place of the allocated array you don't even need to worry about allocating and freeing that.
Short answer:
You need to write the following:
Students::Students()
{
num = 0;
studentsAge = NULL;
marks[0] = NULL;
marks[1] = NULL;
}
void Students::storeValues(int num)
{
this->num = num;
studentsAge = new int[num];
marks[0] = new int[num];
marks[1] = new int[num];
for(int i=0; i<num; i++)
{
studentsAge[i] = i; // this is where you give each student an age, are you sure you want to use i?
// here you can put grade assignments as follows:
marks[0][i] = val1; // first mark for student i
marks[1][i] = val2; // second mark for student i
}
}
Students::~Students()
{
delete[] marks[0];
delete[] marks[1];
delete[] studentsAge;
}
Long answer:
It seems that you need to understand what a pointer is and what an array is.
When you put double *marks[2] in the class declaration, it'll reserve an array of size 2 of double
pointers attached to each instance of the class. You don't need to put the [2] in the constructor.
A pointer is a variable holding the first address of a block of reserved addresses in memory. This means when you assign to a pointer, you need to give it a memory address. To write a value to the address stored in a pointer, you use the * character before the variable.
int num = 2;
int* p;
p = &num; // p will hold the address of num. Any changes to p's value will be reflected in num
p = new int; // p is assigned a new address
*p = num; // the address that p points to will hold 2 (the value in num), but if that value is changed, num will still hold 2
If you wanted to assign an array to p, you would use the new keyword. This will allocate memory
for your program to use. Don't forget to deallocate it.
size = 10;
p = new int[size];
Now you can reference the values in p by treating it as an array or pointer arithmetic,
which I won't go into now.
p[0] = 1; // the first
p[5] = 56;
The difference between a pointer and an array is array allocation and deallocation is handled by the
compiler and needs to have a fixed size at compile time. Pointer allocation and deallocation is handled by the user and its size is defined at runtime.

Segfault in custom string class

So I am trying to complete this very basic string class (MyString). Everything seemed to work, but when I uploaded it to the assignment site, it showed a segfault. The upload site uses electric fence, but it didn't give much insight as to where the fault occurred. It essentially runs through each function and returns a pass/fail/fault for it. In the case of the getline function, it returned a fault.
Also, the upload site uses valgrind which reported no errors.
EDIT: I almost forgot, when I called the function in the driver, it read from a file messages.txt, which contained one line of text: Testing this program... PLEASE WORK
Below is the getline function (as it exists in the implementation file) that appears to be the source of the fault:
// reads line from istream ... line end at newline char of choice) -- '\n' in this case
void MyString::getline(istream &inFile, char delimit)
{
int index = 0;
do
{
data[index] = inFile.get();
index ++;
if (index + 1 > capacity)
{
MyString tempStr;
delete [] tempStr.data;
tempStr.data = new char [capacity];
for (int i = 0; i <= index; i++)
{
tempStr.data[i] = data[i];
}
capacity += 5;
size = index;
delete [] data;
data = new char [capacity];
for (int i = 0; i <= size; i++)
{
data[i] = tempStr.data[i];
}
delete [] tempStr.data;
tempStr.data = NULL;
}
}
while (!inFile.eof() && data[index-1] != delimit);
if (data[index - 1] == delimit)
{
index -= 1;
if (static_cast<double>(index)/capacity < .25 && capacity > 5)
{
capacity -= 5;
char *temp = new char [capacity];
for (int i = 0; i < index; i++)
{
temp[i] = data[i];
}
delete [] data;
data = temp;
}
}
data[index] = '\0';
size = index + 1;
}
I feel like it's either something very simple I overlooked or a fundamental flaw in the way I approached this particular function. Any help is appreciated. I'm very new to programming (few weeks in) and am just trying to stay afloat -- got enrolled in CompSci 1 + 2 simultaneously.
Additionally, below is more of the implementation file -- particularly, the constructors (minus copy) and a few overloaded operators. While I could compile it on my end and concatenate class objects successfully, the upload site returned a fail when it tested "Concatenation." There wasn't any feedback as to which operator failed. I was curious what might cause that in my code. Thanks again.
#include <iostream>
#include <fstream>
#include "MyString.h"
using namespace std;
//default constructor - works
MyString::MyString()
{
capacity = 5;
size = 0;
data = new char [capacity];
}
// constructor with character string
MyString::MyString(const char *cString)
{
int index = 0;
capacity = 5;
while ( cString[index] != '\0')
{
index++;
}
size = index + 1;
while (size > capacity)
{
capacity += 5;
}
data = new char[capacity];
for (int i = 0; i < size; i++)
{
data[i] = cString[i];
}
}
// copy constructor
MyString::MyString(const MyString &aMyString)
{
capacity = aMyString.capacity;
size = aMyString.size;
data = new char [capacity];
for (int i = 0; i < size; i++)
{
data[i] = aMyString.data[i];
}
}
// overloaded += operator
void MyString::operator+=(const MyString &aMyString)
{
int tSize1 = size;
int holder = 0;
size += aMyString.size - 1;
while (size > capacity)
{
capacity += 5;
}
char *tempArr = new char [capacity];
for (int i = 0; i < (tSize1 - 1); i ++)
{
tempArr[i] = data[i];
}
for (int i = (tSize1 - 1); i < size; i++)
{
tempArr[i] = aMyString.data[holder];
holder ++;
}
delete [] data;
data = tempArr;
}
// overloaded + operator
MyString MyString::operator+(const MyString &aMyString) const
{
int holder = 0;
MyString tempS;
int tSize1 = size + aMyString.size - 1;
int tCap1 = capacity + aMyString.capacity;
if (static_cast<double>(tSize1)/tCap1 < .25 && tCap1 > 5)
{
tCap1 -= 5;
}
tempS.size = tSize1;
tempS.capacity = tCap1;
delete [] tempS.data;
tempS.data = new char [tempS.capacity];
for (int i = 0; i < (size - 1); i ++)
{
tempS.data[i] = data[i];
}
for (int i = (size - 1); i < tSize1; i++)
{
tempS.data[i] = aMyString.data[holder];
holder ++;
}
return tempS;
}
I don't know if these are all your bugs but I see two that stand out from the code:
for (int i = 0; i <= index; i++)
{
tempStr.data[i] = data[i];
}
[snip]
for (int i = 0; i <= size; i++)
{
data[i] = tempStr.data[i];
}
Both the for statements are accessing one more character than they should. If you want to process something 5 times for example in zero based indexing you check for i < 5 not i <= 5 . If I am not mistaken you have made that error in both these for loops. I believe they should be:
for (int i = 0; i < index; i++)
and
for (int i = 0; i < size; i++)
Writing memory beyond the edge of your arrays can cause problems like the segfaults.
Right away, the problem is your operator +=. It's supposed to return a reference to the object, not void.
Second, operator + should be written in terms of operator +=. Instead you wrote the whole operator + "from scratch", duplicating the code in operator +=
Here is how operator+ should be implemented:
// overloaded + operator
MyString MyString::operator+(const MyString &aMyString)
{
MyString result = *this; // copy the object
result += aMyString; // call the operator += (where the real work is done).
return result; // just return the result
}
Your operator+=, needs to be defined as this:
MyString& MyString::operator+(const MyString &aMyString)
{
// code to do work
return *this;
}
Third, you failed to implement an assignment operator. You implemented the copy constructor, but not the assignment operator. Unless you didn't post it, it has to be implemented if you want to assign one string to another.
Last, your operator+= has a flaw. It changes the value of size here:
size += aMyString.size - 1;
Then attempts to allocate memory. What if that memory allocation fails (new throws an exception)? How do you "rollback" the value of size to its original value? You can't, at least not with your implementation.
To summarize, just because you have your implementation "working" doesn't mean it really is working properly. The things I pointed out above (no assignment operator, and operator += not returning a reference, *this) are just two issues.
The problem with assignments like this is that it can give you the false sense of accomplishment, when truthfully, what you have coded has bugs you never realized, but worse, can be easily created. For example:
int main()
{
MyString s("abc");
MyString t("123");
s = t;
}
Without an assignment operator, that code fails due to a memory leak and a double deletion error.
It really takes an intermediate to advanced programmer to create yes, something that sounds simple as a "String" class properly, at least one that can pass all the tests that would make a String class usable in a real program.

C++ pointer to int in loops?

Ok, so I'm quite new to C++ and I'm sure this question is already answered somewhere, and also is quite simple, but I can't seem to find the answer....
I have a custom array class, which I am using just as an exercise to try and get the hang of how things work which is defined as follows:
Header:
class Array {
private:
// Private variables
unsigned int mCapacity;
unsigned int mLength;
void **mData;
public:
// Public constructor/destructor
Array(unsigned int initialCapacity = 10);
// Public methods
void addObject(void *obj);
void removeObject(void *obj);
void *objectAtIndex(unsigned int index);
void *operator[](unsigned int index);
int indexOfObject(void *obj);
unsigned int getSize();
};
}
Implementation:
GG::Array::Array(unsigned int initialCapacity) : mCapacity(initialCapacity) {
// Allocate a buffer that is the required size
mData = new void*[initialCapacity];
// Set the length to 0
mLength = 0;
}
void GG::Array::addObject(void *obj) {
// Check if there is space for the new object on the end of the array
if (mLength == mCapacity) {
// There is not enough space so create a large array
unsigned int newCapacity = mCapacity + 10;
void **newArray = new void*[newCapacity];
mCapacity = newCapacity;
// Copy over the data from the old array
for (unsigned int i = 0; i < mLength; i++) {
newArray[i] = mData[i];
}
// Delete the old array
delete[] mData;
// Set the new array as mData
mData = newArray;
}
// Now insert the object at the end of the array
mData[mLength] = obj;
mLength++;
}
void GG::Array::removeObject(void *obj) {
// Attempt to find the object in the array
int index = this->indexOfObject(obj);
if (index >= 0) {
// Remove the object
mData[index] = nullptr;
// Move any object after it down in the array
for (unsigned int i = index + 1; i < mLength; i++) {
mData[i - 1] = mData[i];
}
// Decrement the length of the array
mLength--;
}
}
void *GG::Array::objectAtIndex(unsigned int index) {
if (index < mLength) return mData[index];
return nullptr;
}
void *GG::Array::operator[](unsigned int index) {
return this->objectAtIndex(index);
}
int GG::Array::indexOfObject(void *obj) {
// Iterate through the array and try to find the object
for (int i = 0; i < mLength; i++) {
if (mData[i] == obj) return i;
}
return -1;
}
unsigned int GG::Array::getSize() {
return mLength;
}
I'm trying to create an array of pointers to integers, a simplified version of this is as follows:
Array array = Array();
for (int i = 0; i < 2; i++) {
int j = i + 1;
array.addObject(&j);
}
Now the problem is that the same pointer is used for j in every iteration. So after the loop:
array[0] == array[1] == array[2];
I'm sure that this is expected behaviour, but it isn't quite what I want to happen, I want an array of different pointers to different ints. If anyone could point me in the right direction here it would be greatly appreciated! :) (I'm clearly misunderstanding how to use pointers!)
P.s. Thanks everyone for your responses. I have accepted the one that solved the problem that I was having!
I'm guessing you mean:
array[i] = &j;
In which case you're storing a pointer to a temporary. On each loop repitition j is allocated in the stack address on the stack, so &j yeilds the same value. Even if you were getting back different addresses your code would cause problems down the line as you're storing a pointer to a temporary.
Also, why use a void* array. If you actually just want 3 unique integers then just do:
std::vector<int> array(3);
It's much more C++'esque and removes all manner of bugs.
First of all this does not allocate an array of pointers to int
void *array = new void*[2];
It allocates an array of pointers to void.
You may not dereference a pointer to void as type void is incomplete type, It has an empty set of values. So this code is invalid
array[i] = *j;
And moreover instead of *j shall be &j Though in this case pointers have invalid values because would point memory that was destroyed because j is a local variable.
The loop is also wrong. Instead of
for (int i = 0; i < 3; i++) {
there should be
for (int i = 0; i < 2; i++) {
What you want is the following
int **array = new int *[2];
for ( int i = 0; i < 2; i++ )
{
int j = i + 1;
array[i] = new int( j );
}
And you can output objects it points to
for ( int i = 0; i < 2; i++ )
{
std::cout << *array[i] << std::endl;
}
To delete the pointers you can use the following code snippet
for ( int i = 0; i < 2; i++ )
{
delete array[i];
}
delete []array;
EDIT: As you changed your original post then I also will append in turn my post.
Instead of
Array array = Array();
for (int i = 0; i < 2; i++) {
int j = i + 1;
array.addObject(&j);
}
there should be
Array array;
for (int i = 0; i < 2; i++) {
int j = i + 1;
array.addObject( new int( j ) );
}
Take into account that either you should define copy/move constructors and assignment operators or define them as deleted.
There are lots of problems with this code.
The declaration void* array = new void*[2] creates an array of 2 pointers-to-pointer-to-void, indexed 0 and 1. You then try to write into elements 0, 1 and 2. This is undefined behaviour
You almost certainly don't want a void pointer to an array of pointer-to-pointer-to-void. If you really want an array of pointer-to-integer, then you want int** array = new int*[2];. Or probably just int *array[2]; unless you really need the array on the heap.
j is the probably in the same place each time through the loop - it will likely be allocated in the same place on the stack - so &j is the same address each time. In any case, j will go out of scope when the loop's finished, and the address(es) will be invalid.
What are you actually trying to do? There may well be a better way.
if you simply do
int *array[10];
your array variable can decay to a pointer to the first element of the list, you can reference the i-th integer pointer just by doing:
int *myPtr = *(array + i);
which is in fact just another way to write the more common form:
int *myPtr = array[i];
void* is not the same as int*. void* represent a void pointer which is a pointer to a specific memory area without any additional interpretation or assuption about the data you are referencing to
There are some problems:
1) void *array = new void*[2]; is wrong because you want an array of pointers: void *array[2];
2)for (int i = 0; i < 3; i++) { : is wrong because your array is from 0 to 1;
3)int j = i + 1; array[i] = *j; j is an automatic variable, and the content is destroyed at each iteration. This is why you got always the same address. And also, to take the address of a variable you need to use &