C++ variable appears to have different values in different functions - c++

This is a simplified and more informative version of a question that has now been deleted.
BACKGROUND
I am currently trying to familiarize myself with basic C++ programming and decided to make a game of hangman. However, I noticed that an integer variable called preset_count—which is meant to count how many letters have been pre-guessed by the game— always returns a value of 0 in the main() function whereas in other functions, it has a value of 2 (or anything greater than 0).
What I am trying to accomplish here is that the program will automatically fill in the vowels of the word the player is trying to guess. Depending on how many vowels are filled in, the score the player gets when guessing a character right increases.
For example, the player is trying to guess the word "eraser," so the hangman program will print out
"e _ a _ e _ " they will gain 334 points if they guess correctly.
In a word like "circle," though (which will be printed as "_ i _ _ _ e ") the player will gain 250 points per guess because of the fact that the player has to guess 4 characters instead of 3.
THE ISSUE AND CODE
In order to accomplish this, I added code meant to count how many vowels have been filled in by the game in a special function.
The code below is a simplified version of the one in the actual hangman program that re-creates the issue I have with the program. See, the game outputs a different value of the preset_count value in each function.
Essentially, the main() function has a
cout << "preset_count in main(): " << preset_count;
//This line of code prints out 0. However, the variant of this in find_preset():
cout << "preset_count in find_preset(): " << preset_count;
//Which, on the other hand, prints out 3.
Is there any reason behind these contradictory variable reports? Is there any way to solve this?
#include <iostream>
using namespace std;
void find_preset (int, const string, string); //Prototyping for find_preset()
int main() {
int preset_count = 0; //Amount of times a character in PRESET_LETTERS appears in the word variable.
const string PRESET_LETTERS = "AEIOUaeiou"; //The letters the program is looking out for.
string word = "eraser"; //The word being analyzed.
cout << "\nmain(): main() executed, variables declared, about to execute find_preset() function.";
find_preset(preset_count, PRESET_LETTERS, word); //find_preset() function; finds how many PRESET_LETTERS characters are in word.
cout << "\nmain(): find_preset() finished executing.\n"; //Announces that find_preset() function finished executing.
cout << "\n\nDEBUG word: " << word << endl; //Report on the set word value.
cout << "DEBUG preset_count in main(): " << preset_count << endl << endl; //Report on preset_count's value in main().
//This is where my issue takes place in. This reports a value whereas in find_preset(), the value of preset_count is 2.
return 0;
}
//find_preset() function; finds how many PRESET_LETTERS characters are in word.
void find_preset(int preset_count, const string PRESET_LETTERS, string word) {
int word_index = 0; //How many characters of word that find_preset() has gone through.
cout << "\nfind_preset() executed, now counting amount of instances of PRESET_LETTERS in word.";
//While word_index is less than the size of word. While the entire word variables hasn't been scanned yet.
while (word_index < word.size()) {
//If a PRESET_LETTERS character is found in word.
if(word.find(PRESET_LETTERS)) {
preset_count++; //preset_count increased by 1.
cout << "\nfind_preset(): preset_index and preset_count increased by 1."; //Reports preset_count++; has been executed.
}
word_index++; //Word index increased by 1.
cout << "\nfind_preset(): word_index increased by 1."; //Reports that word_index++; has been executed.
}
cout << "\nfind_preset(): while (word_index < word.size()) finished executing, now printing debug menu for find_preset().\n";
//Reports that the while loop has finished executing.
cout << "\n\nDEBUG: preset_count in find_preset(): " << preset_count; //Report on preset_count's value in find_preset().
//This is also where my issue takes place in. This reports that preset_count's value is 2 whereas in main, it reports 0.
cout << "\nDEBUG: word_index value: " << word_index << endl << endl; //Report on word_index's value.
}

The arguments in C++ are copies of what are passed by default. Therefore, modifications of arguments in callee functions won't affect what are passed in caller. You should add & to make the arguments to references if you want to have functions modify what are passed.
Both declaration and definition should be modified.
void find_preset (int&, const string, string); //Prototyping for find_preset()
void find_preset (int& preset_count, const string PRESET_LETTERS, string word) //find_preset() function; finds how many PRESET_LETTERS characters are in word.
{

Related

Putting spaces before two cout statement iterations that is displayed via a recursive function

Essentially I am making some recursive calls where it increments and decrements a number that is displayed via cout statements. There are two cout statement iterations(so four of one cout statement, and four of the other) that display this. The first one increments the number from 1 to 4, and the second one decrements the number from 4 to 1. What I want to happen is for each cout statement, depending on the number, I want that many spaces before that specific cout function, except that value minus one. The difference between the first and second cout function is that the second cout function will also print out ALSO(will make sense later when I show my intended output.)
So this is the intended output of the cout functions(the stuff in parentheses is not meant to be taken literally. I was unable to just put spaces behind them because it wouldn't show for some reason. The first and last sentences of the output should have zero spaces behind it.):
This was written by call number 1.
(one space here)This was written by call number 2.
(two spaces here)This was written by call number 3.
(three spaces here)This was written by call number 4.
(three spaces here)This ALSO was written by call number 4.
(two spaces here)This ALSO was written by call number 3.
(one space here)This ALSO was written by call number 2.
This ALSO was written by call number 1.
Here is my code that accomplishes all this EXCEPT the spaces(There should be iostream with the angled brackets surrounding it after include, but it refuses to show for some reason.):
#include <iostream>
using namespace std;
void Waswritten(int numwrite);
int main()
{
Waswritten(4);
return 0;
}
void Waswritten(int numwrite)
{
static int count = 0;
if (!numwrite)
return;
cout << "This was written by call number " << ++count << "." << endl;
Waswritten(numwrite - 1);
cout << "This ALSO was written by call number " << count-- << "." << endl;
}
Call this method from Waswritten
void writeSpaces(int spaceCount){
for(int i=0;i<spaceCount;i++){
cout<<" ";
}
}
before each cout
writeSpaces(count);

How do I extract characters in a specific position from an input string?

For my homework project I'm expected to create a program that asks the user their favorite city and which character they would like to display. The user inputs a number representing the position of the character within the city they would like to display, and the program is supposed to display the letter at this position.
We have not yet learned how to extract characters from a string, but this part of our project is supposed to show that we can properly google to find solutions for our coding. I have found a void function that would extract the character from a specific position for me, but am entirely lost on how to use it. I've tried several different methods and typed out every way I could possibly think to implement this function and it has not worked.
I've tried copying the example code I found online exactly as is (first example found at this address: https://www.geeksforgeeks.org/string-at-in-cpp/) but even the example would not run in visual studio 2017.
#include <iostream>
#include <string>
using namespace std;
void at(string);
int main()
{
//variables for favorite city & display character
string favCity;
int dispChar;
//asking user for favorite city
cout << "Input your favorite city: ";
cin >> favCity;
cout << "Which character would you like to display: ";
cin >> dispChar;
cout << endl << endl;
cout << "The user entered: " << favCity << endl;
cout << "The character at position " << dispChar << " is: " << at();
}
The expected result is that the computer will display "The character at position (dispChar) is: (whatever letter is at the user input position dispChar)"
EX: "The character at position 2 is: e //If the user input the city Detroit
I get the error that at is undefined, when I tried using str.at(); I would get str is undefined, etc.
There is no need of using an external function in order to extract a character from a string by its index. std::string itself implements an std::string::at function and also overloaded [] operator.
So two ways for doing that:
1.
cout << "The character at position " << dispChar << " is: " << favCity.at(dispChar);
2.
cout << "The character at position " << dispChar << " is: " << favCity[dispChar];
std::string::at can be used to extract characters by characters from a given string.
char& string::at (size_type idx)
string::at function returns the character at the specific position(idx). You can directly use string::at as you have included class.Learn More Here
So, in your solution you declared void at(string); therefore you need to define it too.
I have made some changes in your code I think that should do it.
#include <string>
using namespace std;
void extract_char(string str, int pos)
{
cout<<str.at(pos);
}
int main(void)
{
int dispChar;
string favCity;
cout<<"Input your favorite city: ";
cin>>favCity;
cout<<"Which position would you like to extract the character from(0 to size of city): ";
cin>>dispChar;
cout<<endl<<endl;
cout<<"The user entered: "<<favCity<<endl;
extract_char(favCity, dispChar-1);
/*
OR
cout<<"The character at position "<<dispChar<<" is: "<<favCity.at(dispChar-1);
*/
return 0;
}

How to understand C++ function/data structs?

'strToDouble' was not declared in this scope Lab1-3.cpp /Lab1-3/src line 65 C/C++ Problem
The first problem, as #SoronelHaetir pointed out, is that you were trying to assign title to variable which can only hold one character. Instead, you should use char array, char pointer, or even string object to contain your multi-letter value. In my code example below, I used char array with fixed size of 25, to store the title. Beware that you can store only up to 24 characters in it, because char arrays need special character which will denote the end of char array. Otherwise it would end up writing junk after your desired value. That special character is null-terminating character which is written like '\0'.
Using return; statement in your void displayBid(Info itemOne); function was completely unnecesary. While you can use return; to stop function from executing, you placed it at the end of function which was just about to end itself in normal way, but you forced it with no reason. Besides, you do not need any return; statements for functions which return void – nothing.
Then, fund and bidAmount are representing money value, which may or may not be of integer value, so you should consider float or double data types to store money value.
Next thing is your function Info getBid();. First, I have to say that naming may be a bit confusing. If you read the name of that function without seeing its actual code, how would you understand what it may do? For me, it sounded like it is about to get me information about a bid, while actually it is setting it up. Second, you could simplify code for entering values, in the way I did it in my code example. The way you tried to use different techniques for getting values from user input was a bit wrong. getline is member function which is used with istream objects. Your istream object is cin. In order to access that member function you shall write it as cin.getline(to be discussed);. That function only works with characters. Its first parameter accepts pointer to the first character (address of the first character) in sequence of characters.
Second parameter is of integer data type and specifies how much characters you want to be extracted from your input and stored in an argument which is in place of the first parameter. Beware not to write, for example, 25, because in char array you have to leave one place for '\0' character, which is automatically placed where it needs to be. getline member function has also default delimiter '\n', which denotes new line. It means that you can enter less characters than function can extract, because extraction will stop as soon as it reads that delimiter value from user input. Although, if you want your specific delimiter, getline member function has its overloaded version which third parameter is one where you enter desired delimiter as an argument. (Overloaded functions are basically functions with the same name, but different parameters. They provide same functionality with different implementation.)
Even if you had set up values for a bid, you never returned it from function. You correctly said that its return value is Info, but you did not return it. Actually, you again exited just before its normal exit. Instead, you should have written return itemOne; In my code example, I passed the variable created in int main(); function by reference, which means it is not a copy as usually, so I do not have to return it and assign to another variable of the same type to appropriately apply desired changes.
Finally, in the int main(); function, you could just declare int choice, without initializing it and use do-while loop in the way I did it. Also, switch statement provides defining what will happen if none of the cases are true, in the way that after all cases you write default:, and below it whatever you want to happen. In your code example, your function will continue executing even if user enters anything but 1, 2 except for 9 defined to stop its execution. In my code example, whatever user enters besides 1 and 2, including zero, function will exit. Well, except for new line.
And, let us discuss again the naming. Your data structure name has to directly imply what it is. Info does not do that. That name would actually be more appropriate for your void displayBid(Info itemOne); function to be called. In my code example, I renamed it to Bid.
#include <iostream>
using namespace std;
struct Bid
{
char title[25];
int vehicleID;
double fund;
double bidAmount;
};
void GetBid(Bid item)
{
cout << "Title: " << item.title << endl;
cout << "Fund: " << item.fund << endl;
cout << "Vehicle: " << item.vehicleID << endl;
cout << "Bid Amount: " << item.bidAmount << endl;
}
void SetBid(Bid & item)
{
cout << "Enter title: ";
cin >> item.title;
cout << "Enter fund: ";
cin >> item.fund;
cout << "Enter vehicle ID: ";
cin >> item.vehicleID;
cout << "Enter amount: ";
cin >> item.bidAmount;
}
int main()
{
Bid item;
int choice;
do {
cout << "Menu:" << endl;
cout << " 1. Enter Bid" << endl;
cout << " 2. Display Bid" << endl;
cout << " 0. Exit" << endl;
cout << "Enter choice: ";
cin >> choice;
switch (choice)
{
case 1:
SetBid(item);
break;
case 2:
GetBid(item);
break;
default:
choice = 0;
cout << "Goodbye." << endl;
break;
}
} while (choice != 0);
return 0;
}
The first (and biggest) problem is:
char title;
This allows you to store only a single character rather than an entire name (prefer std::string to char arrays).

Program throwing exception

I am writing a program that allows the user to enter a sentence which then gets stored in a string and then the program will remove any full stops in the sentence and then create a list of each individual word in the string before outputting that list to the console.
the program is working perfectly as long as there is only 1 full stop in the sentence but if there are any more than that it throws this exception:
Unhandled exception at at 0x7696B727 in Project6.exe: Microsoft C++ exception: std::out_of_range at memory location 0x0022F8B8.
and then if I continue to run it it throws:
Run-Time Check Failure #0 - The value of ESP was not properly saved across a function call. This is usually a result of calling a function declared with one calling convention with a function pointer declared with a different calling convention.
any suggestions? (and before anyone asks, i know you usually only have 1 full stop in a sentence but i need to do it with more than 1 as part of testing.
here is the code:
#include <iostream>
#include <string>
using namespace std
string sSentence; // sets up a string variable called sSentence
int i = 0;
void RemoveFullStop()
{
while(sSentence.find (".") != string::npos) // the program runs this loop until it cannot find any more full stops in the string
{
i = sSentence.find("." , i); // find the next full stop in the string and get the character count of the space and place it in the variable i
sSentence.replace(i,1,""); // remove the full stop
}
}
void ListWords()
{
while(sSentence.find (" ") != string::npos) // the program runs this loop until it cannot find any more spaces in the string
{
i = sSentence.find(" " , i); // find the next space in the string and get the character count of the space and place it in the variable i
// cout << i << endl; // output the contents of iWordSpace to the console (used for debugging - no longer used)
sSentence.replace(i,1,"\n");
// cout << sSentence << endl; // output the contents of iWordSpace to the console (used for debugging - no longer used)
}
}
int main()
{
getline(cin, sSentence); // get user input and store it in sSentence (using the getline function so the .find operation works correctly)
RemoveFullStop(); // calls the RemoveFullStop void function that removes all full stops from the string
ListWords(); // calls the ListWords void function that splits the string into a list of words
cout << endl; // formatting line
cout << "The words that were in the sentence were:" << endl;
cout << endl; // formatting line
cout << sSentence << endl;
cout << endl; // formatting line
system("pause");
return 0;
}
The problem is that you keep re-using i, in both RemoveFullStop and ListWords.
i only ever increases, and so eventually it can get past the end of the string.
You really shouldn't need a global i variable at all, to do this task.
The reason this happens is that when sSentence.find(" " , i) in ListWords runs, i's value is not 0 because it was already defined in RemoveFullStop(). To fix this, first remove int i = 0;, then add it to RemoveFullStop() and ListWords()
Also, while this is just a style thing and won't effect your codes ability to run, I wouldn't call this variable i as i,j,k usually imply counters. Call this variable something more appropriately descriptive.
Here is the relevant code as it should be.
using namespace std
string sSentence;
void RemoveFullStop()
{
int charPlace = 0;
while(sSentence.find (".") != string::npos)
{
charPlace = sSentence.find("." , charPlace);
sSentence.replace(charPlace,1,"");
}
}
void ListWords()
{
int charPlace = 0;
while(sSentence.find (" ") != string::npos)
{
charPlace = sSentence.find(" " , charPlace);
sSentence.replace(charPlace,1,"\n");
}
}

How to convert vector to string and convert back to vector

----------------- EDIT -----------------------
Based on juanchopanza's comment : I edit the title
Based on jrok's comment : I'm using ofstream to write, and ifstream to read.
I'm writing 2 programs, first program do the following tasks :
Has a vector of integers
convert it into array of string
write it in a file
The code of the first program :
vector<int> v = {10, 200, 3000, 40000};
int i;
stringstream sw;
string stringword;
cout << "Original vector = ";
for (i=0;i<v.size();i++)
{
cout << v.at(i) << " " ;
}
cout << endl;
for (i=0;i<v.size();i++)
{
sw << v[i];
}
stringword = sw.str();
cout << "Vector in array of string : "<< stringword << endl;
ofstream myfile;
myfile.open ("writtentext");
myfile << stringword;
myfile.close();
The output of the first program :
Original vector : 10 200 3000 40000
Vector in string : 10200300040000
Writing to File .....
second program will do the following tasks :
read the file
convert the array of string back into original vector
----------------- EDIT -----------------------
Now the writing and reading is fine, thanks to Shark and Jrok,I am using a comma as a separator. The output of first program :
Vector in string : 10,200,3000,40000,
Then I wrote the rest of 2nd program :
string stringword;
ifstream myfile;
myfile.open ("writtentext");
getline (myfile,stringword);
cout << "Read From File = " << stringword << endl;
cout << "Convert back to vector = " ;
for (int i=0;i<stringword.length();i++)
{
if (stringword.find(','))
{
int value;
istringstream (stringword) >> value;
v.push_back(value);
stringword.erase(0, stringword.find(','));
}
}
for (int j=0;j<v.size();i++)
{
cout << v.at(i) << " " ;
}
But it can only convert and push back the first element, the rest is erased. Here is the output :
Read From File = 10,200,3000,40000,
Convert back to vector = 10
What did I do wrong? Thanks
The easiest thing would be to insert a space character as a separator when you're writing, as that's the default separator for operator>>
sw << v[i] << ' ';
Now you can read back into an int variable directly, formatted stream input will do the conversion for you automatically. Use vector's push_back method to add values to it as you go.
Yes, this question is over a year old, and probably completely irrelevant to the original asker, but Google led me here so it might lead others here too.
When posting, please post a complete minimal working example, having to add #include and main and stuff is time better spent helping. It's also important because of your very problem.
Why your second code isn't working is all in this block
for (int i=0;i<stringword.length();i++)
{
if (stringword.find(','))
{
int value;
istringstream (stringword) >> value;
v.push_back(value);
stringword.erase(0, stringword.find(','));
}
}
istringstream (stringword) >> value interprets the data up to the comma as an integer, the first value, which is then stored.
stringword.find(',') gets you the 0-indexed position of the comma. A return value of 0 means that the character is the first character in the string, it does not tell you whether there is a comma in the string. In that case, the return value would be string::npos.
stringword.erase deletes that many characters from the start of the string. In this case, it deletes 10, making stringword ,200,3000,40000. This means that in the next iteration stringword.find(',') returns 0.
if (stringword.find(',')) does not behave as wished. if(0) casts the integer to a bool, where 0 is false and everything else is true. Therefore, it never enters the if-block again, as the next iterations will keep checking against this unchanged string.
And besides all that there's this:
for (int j=0;j<v.size();i++)
{
cout << v.at(i) << " " ;
}
it uses i. That was declared in a for loop, in a different scope.
The code you gave simply doesn't compile, even with the added main and includes. Heck, v isn't even defined in the second program.
It is however not enough, as the for condition stringword.length() is recalculated every loop. In this specific instance it works, because your integers get an extra digit each time, but let's say your input file is 1,2,3,4,:
The loop executes normally three times
The fourth time, stringword is 4, stringword.length() returns 2, but i is already valued 3, so i<stringword.length() is invalid, and the loop exits.
If you want to use the string's length as a condition, but edit the string during processing, store the value before editing. Even if you don't edit the string, this means less calls to length().
If you save length beforehand, in this new scenario that would be 8. However, after 4 loops string is already empty, and it executes the for loop some more times with no effect.
Instead, as we are editing the string to become empty, check for that.
All this together makes for radically different code altogether to make this work:
while (!stringword.empty())
{
int value;
istringstream (stringword) >> value;
v.push_back(value);
stringword.erase(0, stringword.find(',')+1);
}
for (int i = 0; i < v.size(); i++)
{
cout << v.at(i) << " " ;
}
A different way to solve this would have been to not try to find from the start, but from index i onwards, leaving a string of commas. But why stick to messy stuff if you can just do this.
And that's about it.