I am taking a college level C++ course, and quite frankly nothing is really ever explained. I was given code to write, and my program works as it should. I would just like to know the purpose of certain lines.
Such as:
int i = 0;
I know I am declaring an int variable that = 0. Here my question is why the letter i? Could that be any variable name I choose?
int length = input.length();
I know I am declaring an int variable named length... but what purpose does it serve in my code?
i++
I think this ends my loop?
I have added my code for perusal. Any assistance would be greatly appreciated!
// Program takes user entered letter and matches it with the corresponding ICAO word.
//Program has been modified to use void and string methods
#include "stdafx.h"
#include "iostream"
#include "string"
using namespace std;
//Function Heading
void convert(string);
//Main Function
int main()
{
string input;
cout << " Enter a letter or word: "; // Ask the user to enter a letter or word.
cin >> input; //get input
cout << "Phonetic Version : "; //Display "Phonetic Version"
convert (input);
cout << endl;
system("pause");
}//End Main
//Function Definition
void convert(string input)
{
int i = 0; //input variable
char letters; //character variable
int length = input.length();
while (i < length) //While loop initialized
{
letters = input.at(i);
if (letters == 'a' || letters == 'A')
cout << "Alpha ";
else if (letters == 'b' || letters == 'B')
cout << "Bravo ";
else if (letters == 'c' || letters == 'C')
cout << "Charlie ";
else if (letters == 'd' || letters == 'D')
cout << "Delta ";
else if (letters == 'e' || letters == 'E')
cout << "Echo ";
else if (letters == 'f' || letters == 'F')
cout << "Foxtrot ";
else if (letters == 'g' || letters == 'G')
cout << "Golf ";
else if (letters == 'h' || letters == 'H')
cout << "Hotel ";
else if (letters == 'i' || letters == 'I')
cout << "India ";
else if (letters == 'j' || letters == 'J')
cout << "Juliet ";
else if (letters == 'k' || letters == 'K')
cout << "Kilo ";
else if (letters == 'l' || letters == 'L')
cout << "Lima ";
else if (letters == 'm' || letters == 'M')
cout << "Mike ";
else if (letters == 'n' || letters == 'N')
cout << "November ";
else if (letters == 'o' || letters == 'O')
cout << "Oscar ";
else if (letters == 'p' || letters == 'P')
cout << "Papa ";
else if (letters == 'q' || letters == 'Q')
cout << "Quebec ";
else if (letters == 'r' || letters == 'R')
cout << "Romeo ";
else if (letters == 's' || letters == 'S')
cout << "Sierra ";
else if (letters == 't' || letters == 'T')
cout << "Tango ";
else if (letters == 'u' || letters == 'U')
cout << "Uniform ";
else if (letters == 'v' || letters == 'V')
cout << "Victor ";
else if (letters == 'w' || letters == 'W')
cout << "Whiskey ";
else if (letters == 'x' || letters == 'X')
cout << "X-ray ";
else if (letters == 'y' || letters == 'Y')
cout << "Yankee ";
else if (letters == 'z' || letters == 'Z')
cout << "Zulu ";
i++;
}
}
int length = input.length();
I know I am declaring an int variable named length... but what purpose
does it serve in my code?
None.
It would serve some purpose if input's length would change later on and you'd need to remember the old length for some reason.
Since this is not the case here, your professor may think that this is some kind of "optimisation" on the grounds that repeatedly calling length() may be too slow. But this is nonsense; your computer is too fast for such micro-optimisations to have an observable effect, especially with modern compilers being much better at optimising programs than the programmers themselves.
Just remove the length variable to make the code shorter.
Here
string input;
std::string has a method called length() which returns the length of the string, in terms of bytes. Hence you are using like
int length = input.length(); /* use variable name as other than predefined method to avoid confusion */
| |
this is just this is a method of string
a int variable
int i = 0;
I know I am declaring an int variable that = 0. Here my question is why the letter i? Could that be any variable name I choose?
Yes. Variable names are arbitrary, name them however you want (within the restrictions of the language syntax, of course). Just make sure you use names that are meaningful within the context in which they are being used. Readability matters when maintaining code over time.
int length = input.length();
I know I am declaring an int variable named length... but what purpose does it serve in my code?
To make a local cached copy of the character count of the input string so your loop does not have to keep calling the string's length() method over and over. Using a few bytes of local stack space can save time and overhead of retrieving the string's length, which does not change while the loop runs.
i++
I think this ends my loop?
It increments the value of the i variable, nothing more. The loop ends when the while statement evaluates as false (when i catches up to length).
Related
basically I am having weird trouble with my while loop near the beginning of the program which checks for user validation on their choice of activity. When they choose the first activity and complete it, it works fine, but when they complete the second activity, it will go into runtime and keep requesting the user to input a valid choice, even though they haven't even gotten the chance to input a choice. Any tips?
#include <iostream>
using namespace std;
int main()
{
const int DIGITS_CHOICE = 1, IDENTIFIER_CHOICE = 2, DOUBLE_CHOICE = 3, EXIT_CHOICE = 4;
int choice;
int userNumber, storedNumber, factor = 10, digitCounter = 0, subtractor;
char ch;
do
{
cout << "\n\n\t\tPlease choose an option:\n\n"
<< "1. How many digits?\n"
<< "2. Is this a valid C++ Identifer?\n"
<< "3. Is this a double letter word?\n"
<< "4. Exit\n";
cout << endl << "Choice: ";
cin >> choice;
while (choice < DIGITS_CHOICE || choice > EXIT_CHOICE)
{
cout << endl << "Please enter a valid menu option: ";
cin >> choice;
}
if (choice != EXIT_CHOICE)
{
switch (choice)
{
case DIGITS_CHOICE:
cout << "Please enter an integer: ";
cin >> userNumber;
storedNumber = userNumber;
if (userNumber < 10)
{
digitCounter = 1;
}
else
{
while (userNumber != 0)
{
subtractor = userNumber % factor;
if (subtractor > 0)
{
userNumber = userNumber - subtractor;
factor *= 10;
digitCounter++;
}
else
{
userNumber = 0;
}
}
}
cout << storedNumber << " has " << digitCounter << " digit(s)." << endl;
factor = 10;
digitCounter = 0;
break;
case IDENTIFIER_CHOICE:
cout << "Please enter an identifier and press [Enter] immediately after. ";
cin >> ch;
if (ch >= 0 || ch <= 9 || ch <= 'a' || ch >= 'z' || ch <= 'A' || ch >= 'Z' || ch != '_')
{
if (ch >= 0 || ch <= 9)
{
cout << "Not a valid identifier." << endl;
cout << "Identifiers cannot start with a digit." << endl;
ch = '\n';
}
else
{
cout << "Not a valid identifier." << endl;
cout << "Inavlid character." << endl;
ch = '\n';
}
}
while (ch != '\n')
{
if (ch >= 'a' || ch <= 'z' || ch >= 'A' || ch <= 'Z')
{
cin.get(ch);
}
}
break;
case DOUBLE_CHOICE:
break;
}
}
} while (choice != EXIT_CHOICE);
return 0;
}
Also the program isn't complete yet. the third option has nothing and the 2nd option is almost complete. the first activity though is complete :)
Your check for valid characters is too broad, and doesn't really make sense:
if (ch >= 0 || ch <= 9 || ch <= 'a' || ch >= 'z' || ch <= 'A' || ch >= 'Z' || ch != '_')
Every possible value of ch is going to be greater than or equal to zero, so this expression is equivalent to (true || a || b || c || ... || z) and it's always going to resolve to true.
Instead, see if it's below 'A', between 'Z' and 'a' or beyond 'z' and if so, it's invalid.
Also, when checking if it's a digit, you need to check if it's ≥ '0' and ≤ '9' as characters. It's important that you compare it to the character representation of 0 and 9 because the value of the character '0' not actually 0 (it turns out it's actually 48) and likewise with '9':
if ( ch < 'A'
|| (ch > 'Z' && ch < 'a')
|| ch > 'z')
{
if (ch >= '0' && ch <= '9')
{
cout << "Not a valid identifier." << endl;
cout << "Identifiers cannot start with a digit." << endl;
ch = '\n';
}
else
{
cout << "Not a valid identifier." << endl;
cout << "Invalid character." << endl;
ch = '\n';
}
}
It's not really clear what the check after that is meant to do? Is it only meant to allow letters? That seems strange after saying "Identifiers cannot start with a digit." anyway:
if (ch >= 'a' || ch <= 'z' || ch >= 'A' || ch <= 'Z')
This has essentially the same issue where every character is going to be either above 'a' or below 'z' or both, so this will always resolve to true. Instead, use && to check for being within a range:
if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))
Hopefully that addresses your question.
The logic is not great; i is valid, but your code says it's not. It at least goes back to the menu just fine. Your code is also behaving like it will respond immediately as letters are being typed. That is not the case. It won't print anything until the user presses Enter.
It seems the issue is your variable ch being a char. If I type anything that's longer than a single character, what will happen is that the single character gets evaluated, and the remaining characters I typed remain in the input stream. It looks like you are attempting to handle that, but it's not working. I am not going to spend time delving into the why, partly because it's complex, partly because I don't know the full intricacies of istream behavior.
What I will say is that if you want to handle a multi-character input, use cin.get() everywhere and not just sometimes. You can do processing of each character, but again, nothing will go to the screen until the user presses Enter.
But here's code that appears to work:
#include <cctype> // isalpha() and isalnum()
#include <string> // ch is now a std::string
// ...
case IDENTIFIER_CHOICE:
cout << "Please enter an identifier and press [Enter] immediately after. ";
std::cin.ignore(256, '\n'); // needed because of getline behavior
std::getline(std::cin, ch);
if (!(isalpha(ch[0]) || ch[0] == '_')) {
cout << "Not valid.\n";
break;
}
for (int i = 1; i < ch.size(); ++i) {
if (!isalnum(ch[i])) {
cout << "Not valid.\n";
break;
}
}
cout << "Valid.\n";
break;
// ...
With cin, when you press Enter, that keystroke is saved in the input stream. getline() doesn't behave the way we expect because while cin will typically ignore that keystroke, getline does not. So I just tell cin to ignore an arbitrary (but sufficient in this case) amount of characters in the stream up to and including the Enter keystroke (Mac and Linux, should still behave for Windows (I think)).
This is still far from bulletproof input validation (that's impossible), but I think it suffices for what you're working on.
I am working on a project right now and when I try to run what I have below it gives me an error that says "uninitialized local variable 'userOption' used" on line 22, while (isValidOption(userOption) == true) {.
How do I fix that error? Thank you.
#include<iostream>
#include <string>
using namespace std;
char toupper(char ch) {
if (ch >= 'A'&&ch <= 'Z')
return(ch);
else
return(ch - 32);
}
bool isValidOption(char ch) {
if (ch == 'I' || ch == 'O' || ch == 'L' || ch == 'X')
return(true);
else
return(false);
}
char getMainOption() {
string UserInput;
char userOption;
while (isValidOption(userOption) == true) {
cout << "Choose One of the following options\n";
cout << "I--List Our Inventory\n";
cout << "O--Make an Order\n";
cout << "L--List all Orders made\n";
cout << "X--Exit\n";
cout << "Enter an option: ";
getline(cin, UserInput);
userOption = toupper(UserInput[0]);
if (!isValidOption(userOption)) {
cout << "Invalid String\n";
cout << "Enter an option: ";
getline(cin, UserInput);
userOption = toupper(UserInput[0]);
}
if (userOption == 'I')
cout << "Listing Our Inventory\n";
else if (userOption == 'O')
cout << "Make an order\n";
else if (userOption == 'L')
cout << "Listing all orders\n";
}
return userOption;
}
int main() {
char choice;
choice = getMainOption();
system("pause");
return 0;
}
What the error is saying that you're trying to read from userOption before you've ever written to it. If a variable is uninitialized, its memory contents will be full of junk left behind by other functions and it can easily cause bugs. In your case, you'll want to read input from the user into userOption before you do any logic on it. This can be done with a do-while loop:
char userOption; // not yet initialized
do {
...
cin >> userOption; // userOption gets initialized here on first loop run
} while (isValidOption(userOption)); // no need for == true, that's a tautology :-)
// NOTE: perhaps you want to loop while the input is INvalid, as in
// while (!isValidOption(userOption)); ?
A couply code-review comments I would additionally give are:
std::toupper already exists in <cctype>. Docs are here
return is not a function call and it's better to write return ch; than return(ch);
if (ch == 'I' || ch == 'O' || ch == 'L' || ch == 'X'){ return true; } else { return false; } is completely equivalent to the shorter return ch == 'I' || ch == 'O' || ch == 'L' || ch == 'X';
Also take a look at system(“pause”); - Why is it wrong?
Happy coding! Let me know if questions remain
#include <iostream>
using namespace std;
int main()
{
char input, letter1,letter2;
cout << "Enter a letter: ";
cin >> input;
if ( (input >= 'A' && input >= 'Z') || (input <= 'a' && input <= 'z') )
{
if ( (input >= 'A' && input >= 'X') || (input <= 'a' && input <= 'x') )
{
letter1 = input + 1;
letter2 = input + 2;
cout << "Your letter trio today is " << input << letter1 << letter2<<".\n";
}
else if ( input == 'Y' || input == 'y' )
{
letter1 = input + 1;
cout << "Your letter trio today is " << input << letter1 <<".\n";
}
else
{
cout << "Your letter trio today is " << input <<".\n";
}
}
}
if I input y, my output becomes yz{. If I input Y, my output becomes YZ[. If I input Z, my output becomes Z[. Any ideas? thanks guys
Welcome to the ASCII representation of characters! C++ standard only requires that representation of digits are contiguous, but most common implementation use ASCII. The ASCII code for Y is 0x59. 0x59+1 is 0x5A the ASCII code of Z. And just guess what is the character with ASCII code 0x5B? Yes it is [ so your output is normal...
The same, ascii code of lower case y is 0x79, and ascii code of { is 0x7B
I made a little game where the program jumbles up a word and asks for player input. However, one of the If statements are giving me an error and stopping me from compiling the program.
string isready;
cin >> isready;
if (isready == 'y' || 'Y')
Above I set up a string to be called isready, than asked the user for input. As seen above,
I wanted the if statement to activate if either y or capital y was typed in and received.
However, it just gives me the error:
invalid operands to binary expression ('string'
(aka 'basic_string, allocator >') and 'int')
Perhaps I'm missing a #include file?
#include <iostream>
#include <string>
#include <cstdlib>
#include <ctime>
#include <unistd.h>
using namespace std;
int main()
{
enum fields {WORD, HINT, NUM_FIELDS};
const int NUM_WORDS = 5;
const string WORDS[NUM_WORDS][NUM_FIELDS] = //5x2 array
{
{"wall", "Do you feel you're banging your head against something?"},
{"glasses", "These might help you see the answer."},
{"labored", "Going slowly, is it"},
{"persistent", "Keep at it."},
{"jumble", "It's what the game is all about."}
};
srand(static_cast<unsigned int>(time(0)));
int choice = rand() % NUM_WORDS;
//Choice value in array, than area in array where word and hint are
string theWord = WORDS[choice][WORD]; //word to guess
string theHint = WORDS[choice][HINT]; //hint for word
string jumble = theWord; //jumbled version of word
int length = jumble.size();
//Index1 and index2 are random locations in the string theWord
//last two lines swaps areas, ending the for function with a different
//jumble variable every time.
for (int i = 0; i < length; ++i)
{
int index1 = rand() % length;
int index2 = rand() % length;
char temp = jumble[index1];
jumble[index1] = jumble[index2];
jumble[index2] = temp;
}
cout << "\t\tWelcome to Word Jumble!\n\n";
cout << "Unscramble the letters to make a word.\n";
cout << "\n\n\nReady? (y/n)";
//I'm asking here if the player is ready
string isready;
cin >> isready;
if (isready == 'y' || 'Y')
{
cout << "Ok this is how the scoring works\n";
cout << "The length of the word you will guess is times by 5000.\n";
cout << "If you ask for a hint, your score will go down by half.\n";
cout << "If you get the wrong answer, your score will go down by 1000.";
cout << "\nOk, lets start!\n\n\n";
int counter = 3;
for(int i = 0; i < 3; ++i)
{
cout << counter << "..." << endl;
counter--;
}
sleep(1);
}
else
{
cout << "check";
}
cout << "Enter 'quit' to quit the game.\n";
cout << "Enter 'hint' for a hint.\n";
cout << "The jumble is: " << jumble;
//Score system
unsigned long int score;
int amount_of_guesses, amount_of_wrong = 0;
string guess;
cout << "\n\nYour guess: ";
cin >> guess;
while ((guess != theWord) && (guess != "quit"))
{
if (guess == "hint")
{
cout << theHint;
amount_of_guesses++;
}
else
{
cout << "Sorry, that's not it.";
amount_of_wrong++;
}
cout << "\n\nYour guess: ";
cin >> guess;
}
score = theWord.length() * 1000 -(amount_of_wrong * 1000)
/ 2 * amount_of_guesses;
if (guess == theWord)
{
cout << "\nThat's it! You guessed it!\n";
}
cout << "Your score is: " << score;
cout << "\nThanks for playing.\n";
return 0;
}
here
(isready == 'y' || 'Y')
you are trying to use operator== on std::string and char, because 'y' is char. Apart from this conditions should be in parenthesis because || has lower precedence than ==
Correct version is:
( (isready == "y") || ( isready == "Y")) // use bool operator==
(const string& lhs,
const string& rhs);
Operator || takes logical expressions on both sides:
if (isready == "y" || isready == "Y")
Note the double quotes above, because isready is a std::string. You could also change isready to char, and use character constants (i.e. 'y' and 'Y' in single quotes).
Your current expression is syntactically valid, but it will be evaluated as unconditional true, because it is interpreted as follows:
if (isready == 'y' || 'Y' != 0)
// ^^^^^^^^
// != 0 part is implicit;
// `Y` != 0 is always true, so the entire OR is also always true
Change this statement
if (isready == 'y' || 'Y')
to
if ( isready == "y" || isready == "Y")
Take into account that there are double quotes.
The problem is that there is no such operator == that can compare an object of type std::string with an object of type char. There is no such a constructor in class std::string that could convert implicitly an object of type char to an object of type std::string. However class std::string has a constructor that can convert a string literal to an object of type std:string. So the right operand that is "y" or "y" is implicitly converted to a temporary object of type std::string. As the result in the condition above two objects of type std::string are compared.
Also the condition you wrote initially is invalid even if you would use string literals instead of character literals. If for example isready == "y" was equal to false then you will get
false || "y"
In this expression string literal "y" is converted to a pointer to its first character. As this pointer is not equal to NULL then the whole expression will be true independing of the value in isready
(isready == 'y' || 'Y')
You should check for each character seperately.
((isready == "y" || (isready == "Y"))
if (isready == 'y' || 'Y')
should be
if (isready == "y" || isready == "Y")
I have been working on this all day with no luck. Its night now and don't know what to do. My assignment is to read number of vowels, number of white spaces, and number of other characters in a user inputted sentence. I know i need to use cin.get(ch) for whitespaces, but don't know how. I also need to output the sentence to a file. Heres what I have so far:
//Get data from user
cout << "Enter your sentence on one line followed by a # to end it: " << endl;
while (cin >> noskipws >> character && character != '#')
{
character = static_cast<char>(toupper(character));
if (character == 'A' || character == 'E' || character == 'I' ||
character == 'O' || character == 'U')
{
vowelCount++;
isVowel = true;
}
if (isspace(character))
{
whiteSpace++;
}
else if (isVowel == true && isspace(character))
{
otherChars++;
}
outFile << character;
}
outFile << "vowelCount: " << vowelCount << endl;
outFile << "whiteSpace: " << whiteSpace << endl;
outFile << "otherchars: " << otherChars << endl;
This line
if (character == 'A' || 'E' || 'I' || 'O' || 'U');
Is not doing what you think. It will always return true.
you need
if (character == 'A' || character == 'E' || character == 'I' || character == 'O' || character =='U')
and remove the semicolon as well at the end of that line
Here:
while (cin >> character && character != '#')
You are skipping all white space. To prevent the operator >> from skiiping white space you need to explicitly specify this with the noskipws modifier.
while(std::cin >> std::noskipws >> character && character != '#')
Alternatively the same affect can be achieved with get
while(std::cin.get(character) && character != '#')
Next you are reading more characters outside the loop condition.
cin.get(character);
You already have a value in the variable 'character'. So remove both of these. The next iteration of the loop (in the while condition) will get the next character (as it is executed before the loop is entered).
Then fix you test as Tim pointed out.
You can then add another test for white space with:
if (std::isspace(character)) // Note #include <cctype>
{ /* STUFF */ }
#include <iostream>
using namespace std;
int main()
{
char ch;
int vowel_count = 0;
int space_count = 0;
int other_count = 0;
cout << "Enter a string ends with #: " << endl;
while(1)
{
cin.get(ch);
if(ch == '#')
{
break;
}
if(ch == 'A' || ch == 'a'
|| ch == 'E' || ch == 'e'
|| ch == 'I' || ch == 'i'
|| ch == 'O' || ch == 'o'
|| ch == 'U' || ch == 'u')
{
++vowel_count;
}
else if(ch == ' ')
{
++space_count;
}
else
{
++other_count;
}
}
cout << "Vowels: " << vowel_count << endl;
cout << "White spaces: " << space_count << endl;
cout << "Other: " << other_count << endl;
return 0;
}
No arrays
You can check for whitespace the exact same way. Common whitespace characters are space (' '), and horizontal tab ('\t'). Less-common are newline ('\n'), carriage return ('\r'), form feed ('\f') and vertical tab ('\v').
You can also use isspace from ctype.h.