Is there a way to 'reset' a functions variables? - c++

I recently made a function to compare an array of numbers to a single value which returns the closest value to the single value out of the array. This works perfectly well when you only use it only once but if I use it again in another instance of the code, It returns an unexpected value (usually the previous single value used before). Here is the function that I am using:
double closestval (double num1, int amountofnums, double *comps){
double storagecomps[amountofnums];
for (int i = 0; i < amountofnums; i++){
storagecomps[i] = {comps[i]};
/* Storing the array of numbers for later as I will be changing them */
}
double smallval = 0.0001; /* tiny value used to increment/decrement
values in the array to the comparison variable.*/
int_fast64_t compi [amountofnums]; /* this variable keeps track of how many times it needs to decrement/increment the values in the array to approach the variable*/
for (int i = 0; i < amountofnums; i++){
compi[i] = 0;
}
for (int i = 0; i <= amountofnums; i++){
while (comps[i] > num1){
comps[i] -= smallval;
compi[i]++;
}
while (comps[i] < num1){
comps[i] += smallval;
compi[i]++;
}
double recholder[3] = {10000000, 0,};
// This area finds the
for (int i = 0; i < amountofnums; i++){
if (compi[i] < recholder[0]){
recholder[0] = compi[i];
recholder [1] = i;
recholder[2] = storagecomps[i]; /* if the amount of iterations to approach the single variable is less than the previous record holder, it becomes the new one.
*/
}
}
return recholder[2];
}
I am relatively sure this is because (in one way or another) the variables in the function are not being redefined properly or at all. Much thanks if you can show me where I've gone wrong!

The problem isn't resetting the variables. The problem is that you are modifying the arguments passed to the function.
To prevent modifications you should use the const keyword:
double closestval (double num1, int amountofnums, const double *comps){
and then fix the errors the compilers throws at you.
If you do want to modify the comps inside the functions but not have it affect the values outside the functions then you should usestd::vector so you can pass them by value and the compiler will copy them:
double closestval (double num1, int amountofnums, std::vector<double> comps){
You should really do that anyway as you should forget all about C-style arrays till you are an expert.

Related

How would I overload the + operator for this bigint class which uses arrays? C++

I am currently taking an online data structures course using C++ and I'm working on a personal project to help me better understand the basics. The project I'm working on is an implementation of a bigint class, a class that supports storing and calculation of arbitrary-precision integers using arrays and not vectors or strings. I am struggling with the implementation of the major arithmetic operators.
The numbers are stored in the array from least to most significant digit (201 would be stored as {1,0,2}) and the calculations are performed in this order as well.
I have found some material relating to this but the vast majority use vectors/strings and did not help me much. A couple of other resources, such as this and this did help, but did not work when I tried to implement them in my code. For example, this code to implement the addition operator does not work and I either get a bad_alloc exception or the answer is just way wrong, but I can't seem to figure out why or how to solve it and I've been at it for days now:
bigint& operator+(const bigint& lhs, const bigint& rhs){
bool minus_sign = rhs.is_negative();
size_t amt_used = 0; // to keep track of items in the array
// initial size and size of resulting array
// set initial size to the size of the larger array
// set result_size to ini size plus one in case of carry
size_t ini_size = lhs.get_digit_count() > rhs.get_digit_count() ?
lhs.get_digit_count() : rhs.get_digit_count();
const size_t INITIAL_SIZE = ini_size;
const size_t RESULT_SIZE = INITIAL_SIZE+1;
uint8_t temp[RESULT_SIZE], // temporary array
result_arr[RESULT_SIZE],
lhs_arr[INITIAL_SIZE], rhs_arr[INITIAL_SIZE]; // new arrays for lhs/rhs of the same size to avoid overflow if one is smaller
//assign corresponding values to the new arrays
for (size_t i = 0; i < lhs.get_digit_count(); i++){
lhs_arr[i] = lhs.get_digit(i);
}
for (size_t i = 0; i < rhs.get_digit_count(); i++){
rhs_arr[i] = rhs.get_digit(i);
}
// perform addition
int carry = 0; //carry variable
size_t j = 0;
for ( ; j < INITIAL_SIZE; j++){
uint8_t sum = lhs_arr[j] + rhs_arr[j] + carry;
if (sum > 9){
result_arr[j] = sum - 10;
carry = 1;
amt_used++;
}
else{
result_arr[j] = sum;
carry = 0;
amt_used++;
}
}
if (carry == 1){
result_arr[j] = 1;
amt_used++;
}
// flip the array to most sig to least sig, since the constructor performs a switch to least-most sig.
size_t decrement_index = amt_used - 1;
for (int i = 0; i < RESULT_SIZE; i++){
temp[i] = result_arr[decrement_index];
decrement_index--;
}
for (int i = 0; i < RESULT_SIZE; i++){
result_arr[i] = temp[i];
}
// create new bigint using the just-flipped array and return it
bigint result(result_arr, amt_used, minus_sign);
return result;
}
Here's the error I get: Thread 1: EXC_BAD_ACCESS (code=1, address=0x5)
Either that or I get a really large number when I'm just adding 8700 + 2100
There are several issues with this code.
The use of the VLA extension (for temp etc) is not standard C++. These stack based arrays are not initialized, so they will contain random data. When you fill these arrays with data, you are not assigning to every element. This results in the garbage results when, for example, the left number is shorter than the right (so that several elements of lhs_arr have garbage data in them). These bad values will then be used in the addition array. Using std::vector would be standard compliant and result in the vector elements all being initialized to something appropriate (like 0). This could be where your "really large number" comes from.
When you "flip the array", decrement_index can be negative if not all of the result slots were used. This could be a cause of you EXC_BAD_ACCESS crashes.
Returning a reference to a local variable results in Undefined Behavior, since that local will be destroyed when the function returns resulting in a dangling reference. This could be a cause of either of your stated problems.
Your handling of negative numbers is completely wrong, since you don't really handle them at all.

What is the correct syntax for accessing a class member function for a pointer-to-class object contained within an array?

I have the following function, stdDev, which accepts an array of pointers to objects of the Student class. Student class has a member function getScores(), which returns a student's score as a double.
Here is the code below:
double stdDev(Student array[], int SIZE) {
double sum, std_sum, mean, std_mean = 0;
double *std_scores = NULL;
std_scores = new double[SIZE];
for (int i = 0; i < SIZE; i++) {
sum += array[i]->getScore;
}
mean = sum / SIZE;
for (int i = 0; i < SIZE; i++) {
std_scores[i] = pow((array[i]->getScore - mean), 2);
std_sum += std_scores[i];
}
std_mean = std_sum / SIZE;
return sqrt(std_mean);
}
On lines 8 and 13 in the above code, I get the following errors:
expression must have pointer type
and
'*': illegal operation on bound member function expression
I'm new to pointer syntax with C++. Any assistance is appreciated.
The short answer to your question is:
sum += answer[i].getScore;
Except that you need to call the function (not just refer to it), so it should be:
sum += answer[i].getScore();
Other problems:
You don't initialize sum to zero.
You leak std_scores. In reverse order of preference:
Delete it with delete [] std_scores at the end of your function.
Declare it as `std::vector std_scores(SIZE);
Don't use an array at all. Just use double score2 = pow((array[i].getScore() - mean), 2);
Finally points:
C++ is not C89 - you should delay declaring your variables until you can give them a value. std_scores is a particularly glaring example of that - you initialize to NULL and then immediately assign a new value. Apart from sum and std_sum (and i) you don't need any non-const variables.
The code would be nicer with std::accumulate
There are better algorithms for calculating mean and standard deviation that are more numerically stable.

Vector push_back in while and for loops returns SIGABRT signal (signal 6) (C++)

I'm making a C++ game which requires me to initialize 36 numbers into a vector. You can't initialize a vector with an initializer list, so I've created a while loop to initialize it faster. I want to make it push back 4 of each number from 2 to 10, so I'm using an int named fourth to check if the number of the loop is a multiple of 4. If it is, it changes the number pushed back to the next number up. When I run it, though, I get SIGABRT. It must be a problem with fourth, though, because when I took it out, it didn't give the signal.
Here's the program:
for (int i; i < 36;) {
int fourth = 0;
fourth++;
fourth%=4;
vec.push_back(i);
if (fourth == 0) {
i++;
}
}
Please help!
You do not initialize i. Use for (int i = 0; i<36;). Also, a new variable forth is allocated on each iteration of the loop body. Thus the test fourth==0 will always yield false.
I want to make it push back 4 of each number from 2 to 10
I would use the most straight forward approach:
for (int value = 2; value <= 10; ++value)
{
for (int count = 0; count < 4; ++count)
{
vec.push_back(value);
}
}
The only optimization I would do is making sure that the capacity of the vector is sufficient before entering the loop. I would leave other optimizations to the compiler. My guess is, what you gain by omitting the inner loop, you lose by frequent modulo division.
You did not initialize i, and you are resetting fourth in every iteration. Also, with your for loop condition, I do not think it will do what you want.
I think this should work:
int fourth = 0;
for (int i = 2; i<=10;) {
fourth++;
fourth%=4;
vec.push_back(i);
if (fourth==0) {
i++;
}
}
I've been able to create a static array declaration and pass that array into the vector at initialization without issue. Pretty clean too:
const int initialValues[36] = {0,1,2...,35};
std::vector foo(initialValues);
Works with constants, but haven't tried it with non const arrays.

c++ type error message from compiler, what does it mean?

I'm using g++ on fedora linux 13.
I'm just practicing some exercises from my c++ textbook
and can't get this one program to compile. Here is the code:
double *MovieData::calcMed() {
double medianValue;
double *medValPtr = &medianValue;
*medValPtr = (sortArray[numStudents-1] / 2);
return medValPtr;
}
Here is the class declaration:
class MovieData
{
private:
int *students; // students points to int, will be dynamically allocated an array of integers.
int **sortArray; // A pointer that is pointing to an array of pointers.
double average; // Average movies seen by students.
double *median; // Median value of movies seen by students.
int *mode; // Mode value, or most frequent number of movies seen by students.
int numStudents; // Number of students in sample.
int totalMovies; // Total number of movies seen by all students in the sample.
double calcAvg(); // Method which calculates the average number of movies seen.
double *calcMed(); // Method that calculates the mean value of data.
int *calcMode(); // Method that calculates the mode of the data.
int calcTotalMovies(); // Method that calculates the total amount of movies seen.
void selectSort(); // Sort the Data using selection sort algorithm.
public:
MovieData(int num, int movies[]); // constructor
~MovieData(); // destructor
double getAvg() { return average; } // returns the average
double *getMed() { return median; } // returns the mean
int *getMode() { return mode; } // returns the mode
int getNumStudents() { return numStudents; } // returns the number of students in sample
};
Here is my constructor and destructor and selectSort():
MovieData::MovieData(int num, int movies[]) {
numStudents = num;
// Now I will allocate memory for student and sortArray:
if(num > 0) {
students = new int[num];
sortArray = new int*[num];
// The arrays will now be initialized:
for(int index = 0;index < numStudents;index++) {
students[index] = movies[index];
sortArray[index] = &students[index];
}
selectSort(); // sort the elements of sortArray[] that point to the elements of students.
totalMovies = calcTotalMovies();
average = calcAvg();
median = calcMed();
mode = calcMode();
}
}
// Destructor:
// Delete the memory allocated in the constructor.
MovieData::~MovieData() {
if(numStudents > 0) {
delete [] students;
students = 0;
delete [] sortArray;
sortArray = 0;
}
}
// selectSort()
// performs selection sort algorithm on sortArray[],
// an array of pointers. Sorted on the values its
// elements point to.
void MovieData::selectSort() {
int scan, minIndex;
int *minElement;
for(scan = 0;scan < (numStudents - 1);scan++) {
minIndex = scan;
minElement = sortArray[scan];
for(int index = 0;index < numStudents;index++) {
if(*(sortArray[index]) < *minElement) {
minElement = sortArray[index];
minIndex = index;
}
}
sortArray[minIndex] = sortArray[scan];
sortArray[scan] = minElement;
}
}
The compiler is giving this error:
moviedata.cpp: In memberfunction
'double * MovieData::calcMed()':
moviedata.cpp:82: error: invalid
operands of types 'int*' and 'double'
to binary 'operator/'
I'm not sure what to make of this error, i've tried static casting the types with no luck, what does this error message mean?
you are trying to divide a pointer by a double, which the compiler is saying it does not know how todo.
sortArray is probably defined by
int ** sortArray;
its also worth noting you are returning a pointer to a stack variable, who's value will be undefined as soon as you return out of the function.
sortArray[numStudents - 1] is a pointer to int, which can't be on the left side of a division (when you remember pointers are addresses, this makes sense). If you post more of your code, we can help you correct it.
Perhaps you want something like:
int *MovieData::calcMed() {
return sortArray[(numStudents - 1) / 2];
}
This returns the middle element in your array, which should be a pointer to the middle student. I'm not clear why you're sorting lists of pointers (not the actual values), or why you're returning a pointer here. The return value + 1 will be a pointer to the next value in students, which is not the next greater value numerically. So you might as well return the actual student (int from students). If you do this, you can also average the two middle elements when the count is even (this rule is part of the typical median algorithm).
Note that I changed the return type to int *, the type of sortArray's elements. Also, your comment is incorrect. This is the median, not the mean.
Also, your selection sort is wrong. The inner loop should start at scan + 1.
Your code shows a lack of understanding of pointers. You need to do more reading and practice on simpler examples.
More specifically:
double medianValue; creates a double variable. What for? You're apparently going to return a double * and returning a pointer to a local variable is always wrong, because local variables are "recycled" when their function ends.
double *medValPtr = &medianValue; creates a pointer called medValPtr and sets it to the location of medianValue. Well.
Due to the current contents of medValPtr, *medValPtr = (sortArray[numStudents-1] / 2); has the same effect as typing medianValue = (sortArray[numStudents-1] / 2); (supposing it were to compile at all).
Which it doesn't because sortArray[numStudents-1] is, at a guess, the last item in the array sortArray but happens to be a pointer to something else. You can't divide a pointer (numerically you can, but C++ disallows it's always wrong).
Finally you return medValPtr; which is wrong because medValPtr is pointing to a local variable.
You probably want something like:
int *MovieData::calcMed() {
return sortArray[numStudents/2];
}

Template Sort In C++

Hey all, I'm trying to write a sort function but am having trouble figuring out how to initialize a value, and making this function work as a generic template. The sort works by:
Find a pair =(ii,jj)= with a minimum value = ii+jj = such at A[ii]>A[jj]
If such a pair exists, then
swap A[ii] and A[jj] else
break;
The function I have written is as follows:
template <typename T>
void sort(T *A, int size)
{
T min =453;
T temp=0;
bool swapper = false;
int index1 = 0, index2 = 0;
for (int ii = 0; ii < size-1; ii++){
for (int jj = ii + 1; jj < size; jj++){
if((min >= (A[ii]+A[jj])) && (A[ii] > A[jj])){
min = (A[ii]+A[jj]);
index1 = ii;
index2 = jj;
swapper = true;
}
}
}
if (!swapper)
return;
else
{
temp = A[index1];
A[index1] = A[index2];
A[index2] = temp;
sort(A,size);
}
}
This function will successfully sort an array of integers, but not an array of chars. I do not know how to properly initialize the min value for the start of the comparison. I tried initializing the value by simply adding the first two elements of the array together (min = A[0] + A[1]), but it looks to me like for this algorithm it will fail. I know this is sort of a strange type of sort, but it is practice for a test, so thanks for any input.
most likely reason it fails, is because char = 453 does not produce 453 but rather different number, depending what char is (signed versus unsigned). your immediate solution would be to use numerical_limits, http://www.cplusplus.com/reference/std/limits/numeric_limits/
you may also need to think about design, because char has small range, you are likely to overflow often when adding two chars.
The maximum value of any type is std::numeric_limits<T>::max(). It's defined in <limits>.
Also, consider a redesign. This is not a good algorithm. And I would make sure I knew what I was doing before calling my sort function recursively.
I haven't put too much time reading your algorithm, but as an alternative to std::numeric_limits, you can use the initial element in your array as the initial minimum value. Then you don't have to worry about what happens if you call the function with a class that doesn't specialize std::numeric_limits, and thus can't report a maximum value.