C++ pass by reference not changing value - c++

Below is the first part of a function meant to analyze a Tic-Tac-Toe board.
The aboutToWin() function returns true if a player is "about to win," ie has two in a row. The board is represented such that if player 1 has made a move in that square, the value in the 3x3 matrix will be 1. Player 2 will be -1. If no one has made a move, it will be 0.
The part that I put in this question is the first part, which checks the negative diagonal (ie positions 1, 5, and 9 on the board).
bool aboutToWin(int squares[3][3], int& position, bool p1)
{
// The value you are looking for is 2 for p1 and -2 for p2
int check = 2;
if (!p1)
{
check = -2;
}
// Check negative diagonal
int sum = 0;
// Go through negative diagonal
for (int i = 0; i < 3; i++)
{
sum += squares[i][i];
// Saves the position of the last checked 0 square
// If check passes, this will be the winning square
// If not, it will get handled and overwritten
if (squares[i][i] == 0)
{
// Calculates position from i
position = 1 + (4 * i);
std::cout << "\nPosition: " << position << "\n";
}
}
// If this diagonal added to check, stop the function and return now
if (sum == check)
return true;
...
}
This is the code that I'm running from the main() function to test this functionality:
int p;
std::cout << p;
int a3[3][3] = {{1, 0, 1},
{0, 0, 0},
{0, 0, 1}};
std::cout << "\nShould be 1, 5: " << aboutToWin(a3, p, true) << ", " << p;
The output is the following:
0
Position: 5
Should be true, 5: 1, 0
Why is this? I can see that the value gets changed during the function, but it doesn't transfer out of the function.

The problem with using:
std::cout << "\nShould be 1, 5: " << aboutToWin(a3, p, true) << ", " << p;
is that the order of the evaluation of the arguments is not defined unless you use C++17.
It looks like p is evaluated first in your setup before the call to aboutToWin.
Separate the calls.
auto ret = aboutToWin(a3, p, true);
std::cout << "\nShould be 1, 5: " << ret << ", " << p;

Related

Displaying an equation in C++

I’m writing a formula to solve for the roots of a quadratic in C++. My output should begin with the equation such as
3x^2 +2x -3
Everything in my program is correct except for this part. My output has all plus signs followed by the coefficient. How can I get it to display minus (-) signs instead of + when a coefficient is negative? Any help is appreciated thanks!
Example code:
std::cout << a << “x^2” << “+” << b<< “x”
If b is negative it prints ax^2 + -3x but I need it to display ax^2 - 3x
std::cout << a << "x^2" << b >= 0? "+" : "" << b<< "x";
Use ternary operator to make sure "+" is only there when b is not negative.
Your problem with something like:
std::cout << a << "x^2" << "+" << b << "x";
is that you are always outputting a + followed by the b value, be it positive or negative (or zero for that matter). Consider a = 7, b = -42:
7x^2+-42x
As you've seen, these won't look nice for negative numbers. You could get rid of the + but then it would look bad for positive numbers. Consider a = 7, b = 42:
7x^242x
The following code shows a slightly different approach, where the coefficients are checked for sign and then the output is adjusted properly. It also handles arbitrary powers, though only down to zero, allows you to decide whether to print zero coefficients or not, and spaces the terms nicely:
#include <iostream>
#include <vector>
void outputEquation(const std::vector<int> &vec, bool showZeros = false) {
// Power counts down, first is to change
// formatting of first term.
auto power = vec.size() - 1;
auto first = true;
// Handle each coefficient.
for (const auto coeff: vec) {
// Select whether zero coefficients are shown.
if (coeff != 0 || showZeros) {
// Leading space on all but first term.
if (! first) std::cout << " ";
// Intelligently handle negative/non-negative.
if (coeff >= 0) {
// No leading '+' on first term,
// only print coefficient if not 1.
if (! first) std::cout << "+ ";
if (coeff != 1) std::cout << coeff;
} else {
// Output sign for negative, with space after
// if not first term. Then output |coeff|
// unless 1.
std::cout << "-";
if (! first) std::cout << " ";
if (coeff != -1) std::cout << -coeff;
}
// Output power, taking into account "x^1"
// and "x^0", which become "x" and "".
if (power > 1) {
std::cout << "x^" << power;
} else if (power == 1) {
std::cout << "x";
}
// First term done, adjust future behaviour.
first = false;
}
// Decrease power for next element.
--power;
}
// If no terms were output, just give 0.
if (first) {
std::cout << '0';
}
std::cout << '\n';
}
void outputEquation(int a, int b, int c, bool showZeros = false) {
// Just make a vector and call function above.
outputEquation({a, b, c}, showZeros);
}
// Test harness, adapt as necessary.
int main() {
outputEquation({ -4, 3, -2, 1, -1, 0, 4 });
outputEquation({ });
outputEquation({ 4 });
outputEquation({ 0 });
outputEquation({ 0, 1, 2 });
outputEquation({ 0, 0, 0, 0, 99, 0, 0, 0, 0 });
outputEquation({ 0, 0, 0, 0, 99, 0, 0, 0, 0 }, true);
outputEquation(1, 2, 3);
}
The first overloaded function is a general purpose one which you can augment with the second overload, meant specifically for quadratics. This outputs:
-4x^6 + 3x^5 - 2x^4 + x^3 - x^2 + 4
0
4
0
x + 2
9x^4
0x^8 + 0x^7 + 0x^6 + 0x^5 + 99x^4 + 0x^3 + 0x^2 + 0x + 0
x^2 + 2x + 3
but you can adjust the parameters for other possibilities.

How to redeclare already created object values in C++

I have an assignment to create a small game
Build a Text Adventure Game which takes user input and performs certain actions.
// At the start of the game the user is given the choice to choose a type of player (1, 2, 3)
// Each type of player starts with below attributes -
// Player 1 - max health = 50, damage = 10, heal = 20
// Player 2 - max health = 75, damage = 25, heal = 10
// Player 3 - max health = 100, damage = 75, heal = 20
problem is when I try to redeclare the object it doesnt change
Player player(0,0,0);
int player_no;
bool gameover=false;
std::cout<<"choose your player !!!";
std::cin>>player_no;
if(player_no==1){
Player player1(50,20,10); //value is not reflected inside while
std::cout<<player.heal; //50
std::cout<<player.health; //20
goto start;
}else if(player_no==2){
Player player(75,10,25); //value is not reflcted inside while
goto start;
}
char command;
start:
while(!gameover){
std::cout<<"what do you want ??? ";
std::cin>>command;
if(command=='D'){
std::cout<<player.health<<"\n"; //uses the default value 0
std::cout<<player.damage<<"\n"; //uses the default value 0
player.TakeDamage(player.damage); //0 is passed
}else if(command=='H') {
player.Heal(player.heal); // 0 is passed
}
How to pass the changed value inside the while ???
Tiny example to illustrate your problem:
int a = 2;
if (a == 2)
{
std::cout << "a is " << a << std::endl;
int a = 3;
std::cout << "a set to " << a << std::endl;
}
std::cout << "a is " << a << std::endl;
This prints:
a is 2
a set to 3
a is 2
Why is a not 3 in the second line? That is because the braces { ... } declare a new scope and the line int a = 3 declares a new a variable that is local to that scope only. The second we leave the if-scope the second a variable dies, and we are left with only the original which still is set to 2.
If we change it to:
int a = 2;
if (a == 2)
{
std::cout << "a is " << a << std::endl;
a = 3;
std::cout << "a set to " << a << std::endl;
}
std::cout << "a is " << a << std::endl;
Then no new a is declared, and the assignment refers to the variable in the outer scope. Now the output is:
a is 2
a set to 3
a is 3
The fix to your code is to do something like this:
Player player(0, 0, 0);
...
if (player_no == 1) {
player = Player(50, 20, 10);
...
}
There are many problem :
1) The name of the variable :
You call player on 1st line and player1 after if (player_no==1){...
2) The scope is not respected :
when you created anew Player player(75,10,25); it doesnt replace the first created Player.
I will prefer use pointer like that (there are infinite way to do it !) :
Player* pPlayer = NULL;
...
if(player_no==1){
pPlayer = new Player(50, 20, 10);
...
if(player_no==2){
pPlayer = new Player(75, 10, 25);
...
if (pPlayer != NULL) {
while(!gameover) {
if (command == 'D') {
pPlayer->Damage();
}
}
delete pPlayer;
}
Hope it helps you !

Recursively return if statement calls

I'm trying to design a program that takes an integer array as input, and then returns all combinations of values that add up to a predetermined sum. For the sake of clarity, my recursive function will return true when the total adds up to 10.
However, I also want it to return the values from the array that comprise of this total, so my definition is as follows;
If suminarray returns true, print each number from the array.
My hope was, once my base clause is reached, the recursion would unwind, and my if statements would all be evaluated, and each value would be printed from my if statement. However, all that is printed is last value from the array which made up the target total, not all the values that preceded it.
I've likely misunderstood the recursive behaviour of C++. I know how to work with recursive return calls, but logically, if the if statement can't be evaluated until the recursive function returns true or false, shouldn't they unwind, also?
#include <iostream>
bool suminarray(int *numbers, const int &size, int startPos, int total);
using namespace std;
int main()
{
int numbers[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
int startPos = 0;
int total = 0;
suminarray(numbers, 10, 0, total);
return 0;
}
bool suminarray(int *numbers, const int &size, int startPos, int total)
{
if(total == 10)
{
cout << "result. " << endl;
return true;
}
else if(total > 10)
{
return false;
}
else
{
for(int i = startPos; i < size; i++)
{
cout << " loop " << i << endl;
cout << " total" << total << endl;
if(suminarray(numbers, size, i+1, total+numbers[i]) == true)
{
cout << "Uses " << numbers[i] << endl;
}
}
}
}
Edit: correction to source code.
The immediate problem (which your compiler should be warning you about), is that you have no return statement in the final else block, which causes the function to fall off the end without returning either true or false, leading to undefined behavior. If you fix that in the most obvious way:
else
{
for(int i = startPos; i < size; i++)
{
cout << " loop " << i << endl;
cout << " total" << total << endl;
if(suminarray(numbers, size, i, total+numbers[i]) == true)
{
cout << "Uses " << numbers[i] << endl;
return true;
}
}
return false;
}
your program then works, but it only prints the FIRST set of values that add up to 10 that it finds.
That immediately shows you the problem with your approach -- each function call can only return ONCE -- you can't (easily) have it both return success AND continue to try more alternatives.
As you've already guessed, the way you're imagining the recursive function unwinding is wrong.
In your example, you want to get to a total of 10, with numbers starting at 1, and ending at 9. So, first your recursive function will make the total = 1. Then it will add another 1 to that until it gets all the way down to the tenth 1. Then it will print result, then it will unwind 1 step, and print 1.
Good so far right? Well, here's where it goes off track. At this point it doesn't unwind all the way. It still stays at 9, but this time it adds a 2 to that, fails goes back until it unwinds to a sum of 8. Now it tries 2 and works this time! Printing result, then 2.
This, as i've understood, isn't what you want. What you should be doing is make something else to hold your array of answers, and not just print them.
I know how to work with recursive return calls, but logically, if the if statement can't be evaluated until the recursive function returns true or false, shouldn't they unwind, also?
This is correct. The reason you are only seeing one print statement at the end is because only one call is returning 'true'. Therefore the 'if' statement is only true once and you only see one print statement for "Uses ".
I believe your mistake is that you didn't add a return statement after your for loop. This means the return value for your function is actually undefined. Start using the -Wall flag when you compile to make sure you don't make this mistake. Here is a version where I added a "return true;" after the 'for' loop:
#include <iostream>
bool suminarray(int *numbers, const int &size, int startPos, int total);
using namespace std;
int main()
{
int numbers[] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
int startPos = 0;
int total = 0;
suminarray(numbers, 10, startPos, total);
return 0;
}
bool suminarray(int *numbers, const int &size, int startPos, int total)
{
if(total == 10)
{
cout << "result. " << endl;
return true;
}
else if(total > 10)
{
return false;
}
else
{
for(int i = startPos; i < size; i++)
{
cout << " loop " << i << endl;
cout << " total" << total << endl;
if(suminarray(numbers, size, i, total+numbers[i]) == true)
{
cout << "Uses " << numbers[i] << endl;
}
}
}
return true;
}

Point one array value to another value of the same array - C++

Imagine I have the following code:
int* firstArray[4];
fill_n(firstArray, 4, 0);
//firstArray values are: 0, 0, 0, 0
int* secondArray[4];
fill_n(secondArray, 4, 1);
//secondArray values are: 1, 1, 1, 1
Would there be a way to link the first value of firstArray to the first value of secondArray so that if I do:
secondArray[0] = 20;
//secondArray values would be: 20, 1, 1, 1 (because I just changed it)
//firstArray values would be: 20, 0, 0, 0 (because it's pointing to the value I just changed)
As far as I've tested and researched I can't do something along those lines.
P.S.: This is to create a Samurai Sudoku (in which some chunks of numbers are shared), so when I modify a value that 2 sudokus share it would be updated in both.
You are mixing up concepts. You don't even need to declare a second array just do this:
int myarray [20];
int * mypointer;
mypointer = myarray;
// then you can use both mypointer[] myarray[] the same way to access array elements
The concept of arrays is related to that of pointers. In fact, arrays work very much like pointers to their first elements, and, actually, an array can always be implicitly converted to the pointer of the proper type.
The [] operator in arrays acts the same way as a as a de-referencing operator, but with the added ability of automatically advancing the pointer according to the data type. This is why Array[1] references the same value as *(Array+1)
however you are declaring an arrays of pointers to integers, which means that you can't "store" integer values in this array, but rather store the value of the address where the integer is located.
Additionally when you declare an array you are essentially declaring a constant pointer, so you can not "steal" it and make it pointer to another location.
Study this Code and it's output (RUN THIS CODE)
#include <iostream>
using namespace std;
void printarray (int arg[], int length) {
for (int n=0; n<length; ++n)
cout << arg[n] << ' ';
cout << '\n';
}
int main ()
{
int first[] = {5, 10, 15, 14, 13};
printarray (first,3);
// int* third[] = {1,1,1}; Not accepted because int is not int*
// storing the addresses of first as pointers in 2 different arrays
int* third[] = {first,first+2,first+3};
int* forth[] = {first,first+2,first+3};
// the memory adress where the pointers TO first is stored
cout << third << endl;
cout << forth << endl;
cout << &third << endl;
cout << &forth << endl;
// the memory adress where the pointer TO the value of first[0] is stored
cout << *third << endl;
cout << *forth << endl;
cout << third[0] << endl;
cout << forth[0] << endl;
// you are defrencing twice
cout << *third[0] << endl;
cout << *forth[0] << endl;
cout << **third << endl;
cout << **forth << endl;
// assign once
first[0] = 77;
// applys to all values
cout << first[0] << endl;
cout << *third[0] << endl;
cout << *forth[0] << endl;
// better yet declare a int* and use it same way your array
int* second;
second = first;
cout << first[0] << endl;
cout << second[0] << endl;
// again change value and the change is reflected everywhere
second[0] = 99;
cout << first[0] << endl;
cout << second[0] << endl;
cout << *third[0] << endl;
cout << *forth[0] << endl;
}
OUTPUT
5 10 15
0x786378c0b860
0x786378c0b880
0x786378c0b860
0x786378c0b880
0x786378c0b840
0x786378c0b840
0x786378c0b840
0x786378c0b840
5
5
5
5
77
77
77
77
77
99
99
99
99
Store int**s instead of int*s this way you can have each entry in the array point to the same address.
You would initialize the first element lets say as:
int *first = new int;
*first = 1;
firstArray[0] = first;
secondArray[0] = first;
Then if you write *first = 20; both arrays will be updated.
There is a problem with your question that you initialize first to 0 and then to 1. If they were the same address then setting to 1 would overwrite the setting to 0.
You question is not self coherent :
you write int* secondArray[4]; : secondArray is an array of 4 pointers to int
you write secondArray[0] = 20 : here secondArray is an array of 4 int values
Hyp 1 : arrays of 4 int values
&secondArray[1] is &secondArray[0] + 1. Full stop. That the way arrays work in C++. In that case if secondArray[0] is the same as firstArray[0] then the 2 arrays are at same address and are in fact the same array and your example becomes :
int firstArray[4];
fill_n(firstArray, 4, 0);
//firstArray values are: 0, 0, 0, 0
/* int secondArray[4]; first elements could not be related and you should have : */
int *secondArray = firstArray;
fill_n(secondArray, 4, 1);
//secondArray values are: 1, 1, 1, 1
//firstArray values are also: 1, 1, 1, 1
Hyp 2 : arrays of 4 pointers
You can have first element of both array point to same value while the three others are independent
int array[5];
int *firstArray[4];
int *secondArray[4];
firstArray[0] = &(array[0]);
for(int i=1; i<4; i++)
firstArray[i] = secondArray[i] = &(array[1]);
}
secondArray[0] = &(array[4]);
Then :
int* firstArray[4];
fill_n(firstArray, 4, 0);
//firstArray values are: 0, 0, 0, 0
int* secondArray[4];
fill_n(secondArray, 4, 1);
//secondArray values are: 1, 1, 1, 1
//firstArray values are: 1, 0, 0, 0
and
*(secondArray[0]) = 20;
//secondArray values would be: 20, 1, 1, 1 (because I just changed it)
//firstArray values would be: 20, 0, 0, 0 (because it's pointing to the value I just changed)
That is what you asked for, but it is a very unusual requirement and I'm not sure it is really what you need.

Values not written to vector

I'm trying to read pairs values from a file in the constructor of an object.
The file looks like this:
4
1 1
2 2
3 3
4 4
The first number is number of pairs to read.
In some of the lines the values seem to have been correctly written into the vector. In the next they are gone. I am totally confused
inline
BaseInterpolator::BaseInterpolator(std::string data_file_name)
{
std::ifstream in_file(data_file_name);
if (!in_file) {
std::cerr << "Can't open input file " << data_file_name << std::endl;
exit(EXIT_FAILURE);
}
size_t n;
in_file >> n;
xs_.reserve(n);
ys_.reserve(n);
size_t i = 0;
while(in_file >> xs_[i] >> ys_[i])
{
// this line prints correct values i.e. 1 1, 2 2, 3 3, 4 4
std::cout << xs_[i] << " " << ys_[i] << std::endl;
// this lines prints xs_.size() = 0
std::cout << "xs_.size() = " << xs_.size() << std::endl;
if(i + 1 < n)
i += 1;
else
break;
// this line prints 0 0, 0 0, 0 0
std::cout << xs_[i] << " " << ys_[i] << std::endl;
}
// this line prints correct values i.e. 4 4
std::cout << xs_[i] << " " << ys_[i] << std::endl;
// this lines prints xs_.size() = 0
std::cout << "xs_.size() = " << xs_.size() << std::endl;
}
The class is defined thus:
class BaseInterpolator
{
public:
~BaseInterpolator();
BaseInterpolator();
BaseInterpolator(std::vector<double> &xs, std::vector<double> &ys);
BaseInterpolator(std::string data_file_name);
virtual int interpolate(std::vector<double> &x, std::vector<double> &fx) = 0;
virtual int interpolate(std::string input_file_name,
std::string output_file_name) = 0;
protected:
std::vector<double> xs_;
std::vector<double> ys_;
};
You're experiencing undefined behaviour. It seems like it's half working, but that's twice as bad as not working at all.
The problem is this:
xs_.reserve(n);
ys_.reserve(n);
You are only reserving a size, not creating it.
Replace it by :
xs_.resize(n);
ys_.resize(n);
Now, xs[i] with i < n is actually valid.
If in doubt, use xs_.at(i) instead of xs_[i]. It performs an additional boundary check which saves you the trouble from debugging without knowing where to start.
You're using reserve(), which increases capacity (storage space), but does not increase the size of the vector (i.e. it does not add any objects into it). You should use resize() instead. This will take care of size() being 0.
You're printing the xs_[i] and ys_[i] after you increment i. It's natural those will be 0 (or perhaps a random value) - you haven't initialised them yet.
vector::reserve reserve space for further operation but don't change the size of the vector, you should use vector::resize.