First day at C++ - c++

I need to ask for the user's Initials and have it return their input. If they input any int I need it to loop back and ask them again.
int main()
{
// Program 1-1
std::cout<<"Hello, can you please enter your initials?\n";
char initials[50];
std::cin.getline(initials, 50);
while (std::cin != int)
{
std::cout << "Thank you. " << initials << std::endl;
}
else (std::cin.fail())
{
std::cin.clear();
}
}

#include <cctype>
#include <iostream>
#include <string>
int main() {
std::string tmp;
bool bogusInput;
do {
std::cout << "Initials: ";
std::getline(std::cin, tmp);
bogusInput = false;
for (auto i : tmp) {
if (std::isdigit(i)) {
bogusInput = true;
break;
}
}
if (bogusInput) {
std::cout << "Are you Elon's son? Please enter letters only.\n";
}
} while (bogusInput);
std::cout << "Thank you, " << tmp << ".\n";
return 0;
}
This code does the job you describe. I chose a do/while loop since I always need to get initials at least one time.
The variable bogusInput is a flag that I use to know if something hasn't worked out properly. It is declared outside of the loop for the sake of the while condition. It is always reset before performing the check, this allows the case of multiple attempts to work.
Finally, "valid" input gets us out of the loop and we say thank you and end.

Related

Having trouble with std::string::compare() return values in c++

Relatively new to c++.
Having trouble understanding an issue I am having with the compare() function returning 1 instead of 0.
I have a program which reads a text file containing an arbitrary number of questions and answers for a quiz. It is formatted as such:
Q: How many days in a week?
A: seven
I have three files, main.cpp, Quiz.cpp, and Quiz.h:
main.cpp:
#include <iostream>
#include <vector>
#include <fstream>
#include <algorithm>
#include <ctime>
#include <cstdlib>
#include "Quiz.h"
using namespace std;
int main(int argc, char* argv[]){
srand(unsigned(time(0)));
vector<Quiz> quizVector;
ifstream inputQuiz;
inputQuiz.open(argv[1]);
string q, a;
int questionCount = 0;
if(inputQuiz.is_open()){
getline(inputQuiz, q);
getline(inputQuiz, a);
while(!inputQuiz.eof()){
Quiz *instance = new Quiz(q, a);
quizVector.push_back(*instance);
questionCount++;
getline(inputQuiz, q);
getline(inputQuiz, a);
}
}
random_shuffle(quizVector.begin(), quizVector.end());
string userInput;
for(int i = 0; i < questionCount; i++){
cout << quizVector[i].getQuestion() << endl;
cout << "A: ";
getline(cin, userInput);
if(quizVector[i].getAnswer().compare("A: " + userInput) == 0){
cout << "Correct." << endl;
}
else{
cout << "Incorrect." << endl;
}
}
return 0;
}
Quiz.cpp:
#include <string>
#include "Quiz.h"
int Quiz::score = 0;
std::string Quiz::getQuestion(){
return question;
}
std::string Quiz::getAnswer(){
return answer;
}
Quiz.h:
#ifndef QUIZ_H
#define QUIZ_H
class Quiz{
private:
std::string question {""};
std::string answer {""};
public:
Quiz() = default;
Quiz(std::string q, std::string a) : question {q}, answer {a} {}
std::string getQuestion();
std::string getAnswer();
};
#endif
My problem lies within main.cpp:
for(int i = 0; i < questionCount; i++){
cout << quizVector[i].getQuestion() << endl;
cout << "A: ";
getline(cin, userInput);
if(quizVector[i].getAnswer().compare("A: " + userInput) == 0){
cout << "Correct." << endl;
}
else{
cout << "Incorrect." << endl;
}
}
When I input the correct answer corresponding to each question, compare() does not return 0, but consistently returns 1. There are no leading or trailing spaces at the start or ends of each line in the text file. Am I misunderstanding how getline() or compare() works? Is it something else? Any help is appreciated!
I see a number of problems with this code:
std::random_shuffle() is deprecated in C++14 and removed in C++17, use std::shuffle() instead.
you are not validating that argv contains an input parameter before using it.
Your use of eof() in the while loop is wrong. For instance, if the last question/answer pair in the file is terminated by EOF instead of a line break, getline() will still return the question/answer to you, but it will also set the eofbit flag on the stream, which will cause eof() to return true and thus you will skip saving the last pair into the vector. The stream is not technically in a failed state yet in this situation (see the diagram at https://en.cppreference.com/w/cpp/io/basic_ios/eof), so you shouldn't skip the last pair if it terminates with EOF rather than a line break.
Your while loop is leaking memory.
you don't need questionCount at all, use quizVector.size() instead. Or better, a range-for loop.
you don't really need to use compare() at all, you can use operator== instead. But, if you do use compare(), you should take into account that it is case-sensitive (as is operator==). You should also take advantage of the fact that compare() lets you specify an index to start comparing from, so you can ignore the A: prefix in the stored answer (alternatively, you could just strip off the Q: and A: prefixes when storing the question/answer in Quiz's constructor). Otherwise, you can use your compiler's strcmpi() function instead (if it offers one).
Try something more like this instead:
#include <iostream>
#include <vector>
#include <fstream>
#include <algorithm>
#include <random>
#include <cctype>
#include "Quiz.h"
using namespace std;
string toLowercase(string s) {
transform(s.begin(), s.end(), s.begin(),
[](unsigned char c){ return tolower(c); }
);
return s;
}
int main(int argc, char* argv[]){
if (argc < 2){
cerr << "Please specify a file to open!" << endl;
return 0;
}
ifstream inputQuiz(argv[1]);
if (!inputQuiz.is_open()) {
cerr << "Can't open the file!" << endl;
return 0;
}
vector<Quiz> quizVector;
string q, a, userInput;
while (getline(inputQuiz, q) && getline(inputQuiz, a)) {
quizVector.emplace_back(q, a);
}
random_device rd;
mt19937 g(rd());
shuffle(quizVector.begin(), quizVector.end(), g);
for(auto &quiz : quizVector){
cout << quiz.getQuestion() << endl;
cout << "A: ";
getline(cin, userInput);
userInput = toLowercase(userInput);
a = toLowercase(quiz.getAnswer());
if (a == ("a: " + userInput)) {
// or:
// if (a.compare(2, string::npos, userInput) == 0) {
// or, if you strip off "A:" beforehand:
// if (a == userInput) {
cout << "Correct." << endl;
}
else {
cout << "Incorrect." << endl;
}
}
return 0;
}

Comparing strings in this instances work differently, any reason?

Can someone help me with this, please? The block of code in the green box works fine, but the one in red works but not really. It's checking if the emails have both "#gmail.com" and "#yahoo.com". I want it to check both emails so that if they both contain only one "#gmail.com" or "#yahoo.com", it will exit the loop. Thank you!
#include <iostream>
using namespace std;
int main()
{
string emailOne_, emailTwo_;
bool valid = true;
do
{
cout << "Email: ";
cin >> emailOne_;
cout << "Re-enter email: ";
cin >> emailTwo_;
if (emailOne_.compare(emailTwo_) != 0)
{
valid = false;
cerr << "\t[*] ERROR: EMAILS DO NOT MATCH\n\n";
}
else
{
valid = true;
}
string myArray[] = { "#gmail.com", "#yahoo.com" };
int arrSize = sizeof(myArray) / sizeof(myArray[0]);
for (int i = 0; i < arrSize; i++)
{
auto found = emailOne_.find(myArray[i]);
if (found == string::npos)
{
valid = false;
cerr << "\t[*] ERROR: EMAILS MUST HAVE #gmail.com or #yahoo.com\n\n";
break;
}
else
{
valid = true;
}
}
} while (valid == false);
return 0;
}
You have some issues in the code
auto found = emailOne_.find(myArray[i]); will find the #gmail.com even if the entered email address is foo#gmail.com.uk, which is probably not what you want.
If the first entry in myArray doesn't match, you break out and don't test the next.
If the first entry is a match, you don't break out, so you go on and try the next string in myArray which will of course not match - and then you break out.
It's therefore currently impossible to get a valid match. By breaking out only when a valid match is found, you should be able to get the correct result.
Example with some suggested simplifications:
#include <iostream>
#include <string>
int main() {
const std::string myArray[] = {"#gmail.com", "#yahoo.com"};
std::string emailOne_;
for(;;) {
std::string emailTwo_;
std::cout << "Email: ";
std::cin >> emailOne_;
std::cout << "Re-enter email: ";
std::cin >> emailTwo_;
// simplify comparisons:
if(emailOne_ != emailTwo_) {
std::cerr << "\t[*] ERROR: EMAILS DO NOT MATCH\n\n";
continue; // back to entering email
}
bool valid = false;
// Use range-based for loops to simplify looping over arrays:
for(const std::string& end : myArray) {
// check if the end of emailOne_ is equal to `end` by comparing
// a substring of emailOne_ with the same length as end, with end:
if(emailOne_.size() > end.size() && // must be long enough
emailOne_.substr(emailOne_.size() - end.size()) == end)
{
valid = true;
break;
}
}
// check the valid state after the loop:
if(!valid) {
std::cerr << "\t[*] ERROR: EMAILS MUST HAVE #gmail.com or #yahoo.com\n";
} else {
break; // a valid email address was found.
}
}
std::cout << emailOne_ << " is a valid address\n";
}

Check user input by each char if exists in char array [duplicate]

I want to write a function that determines if all the letters of an inputted word are contained in another string of acceptable letters.
bool ContainsOnly(std::string inputtedWord, std::string acceptableLetters)
{
// ... how do I write this?
}
Here's my testing framework:
bool Tester(std::string inputtedWord, std::string acceptableLetters)
{
if (ContainsOnly(inputtedWord, acceptableLetters)) {
std::cout << "Good!" << std::endl;
return true;
}
else {
std::cout << "No good!" << std::endl;
return false;
}
}
int main()
{
std::string acceptableLetters;
std::string inputtedWord;
std::cout << "Please input the acceptable letters in your words: " << std::endl;
std::cin >> acceptableLetters;
while (inputtedWord != "STOP")
{
std::cout << "Please input the word you would like to test: (type STOP to end testing): " << std::endl;
std::cin >> inputtedWord;
Tester(inputtedWord, acceptableLetters);
}
return 0;
}
I want the following output:
Please input the acceptable letters in your words: CODING
Please input the word you would like to test: (type STOP to end testing): COIN
Good!
Please input the word you would like to test: (type STOP to end testing): COP
No good!
You can use find_first_not_of like this:
bool ContainsOnly(std::string inputtedWord, std::string acceptableLetters)
{
return inputtedWord.find_first_not_of(acceptableLetters) == std::string::npos;
}
Here's a demo.
Put all the acceptable characters to std::set.
Judge if all characters in the strings are in the set via std::all_of.
#include <set>
#include <algorithm>
bool ContainsOnly(std::string inputtedWord, std::string acceptableLetters)
{
std::set<char> okSet(acceptableLetters.begin(), acceptableLetters.end());
return std::all_of(inputtedWord.begin(), inputtedWord.end(),
[&okSet](char c)
{
return okSet.find(c) != okSet.end();
});
}

Function must return a value

I am trying to make a text based RPG and i'm fairly new to c++. I understand that I need to return a value, but when I try and return CharacterName or CharacterRace it comes up with unresolved externals errors. I'd really appreciate the help guys, thanks :)
CharacterCreation.h
#include <string>
#include <iostream>
void petc(), ConsoleClear(), petc(), EnterClear();
std::string CharacterName, CharacterRace;
Main.cpp
#include <iostream>
#include <limits>
#include <string>
#include <string.h>
#include "CharacterCreation.h"
std::string CharacterCreation();
int main()
{
CharacterCreation();
}
std::string CharacterCreation(int RaceChoice, int RaceChoiceLoop)
{
RaceChoiceLoop = 0;
std::cout << "Welcome to the character creation V 1.0.0" << std::endl;
EnterClear();
std::cout << "Choose a name: ";
std::cin >> CharacterName;
std::cout << CharacterName << std::endl;
EnterClear();
while (RaceChoiceLoop == 0)
{
std::cout << "(1) Human - Human's race perks: + 5 to Magic | + 1 to Sword Skill" << std::endl;
std::cout << "(2) Elf - Elve's race perks: + 5 to Archery | + 1 to Magic" << std::endl;
std::cout << "(3) Dwarf - Dwarven race perks: + 5 to Strength | + 1 to Archery" << std::endl;
std::cout << "Choose a race, " << CharacterName << ": ";
std::cin >> RaceChoice;
if (RaceChoice == 1)
{
RaceChoiceLoop = 1;
CharacterRace = "Human";
}
else if (RaceChoice == 2)
{
RaceChoiceLoop = 1;
CharacterRace = "Elf";
}
else if (RaceChoice == 3)
{
RaceChoiceLoop = 1;
CharacterRace = "Dwarf";
}
else
{
std::cout << "Invalid Option";
EnterClear();
RaceChoiceLoop = 0;
}
}
}
void petc()
{
std::cout << "Press Enter To Continue...";
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
void EnterClear()
{
std::cout << "Press Enter To Continue...";
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
system("cls");
}
void ConsoleClear()
{
system("cls");
}
A declared std::string function should return a string and this is not the same as printing it on the screen, use return "something" inside the function otherwise declare it void.
The "unresolved externals" message isn't directly caused by your returning a value.
It's a linker error, and only occurs because compilation succeeded.
The cause is that you're declaring, and calling, this parameter-less function:
std::string CharacterCreation();
but you're defining this function with two parameters:
std::string CharacterCreation(int RaceChoice, int RaceChoiceLoop)
The declaration and the definition must match.
From the looks of it, you don't actually want the parameters and should use local variables instead:
std::string CharacterCreation()
{
int RaceChoice = 0;
int RaceChoiceLoop = 0;
// ...
Problem is that the function CharacterCreation() (taking no arguments) is never defined, and thus the linker cannot find it.
Try substituting in the following:
std::string CharacterCreation(int, int);
int main()
{
CharacterCreation(1,1);
}
This will call the CharacterCreation function you have implemented below the main function. Doing this I can compile (and link) your code :)
As I have pointed in my comment before, your CharacterCreation method does not return any value, although you have defined a string as an expected one.
What you most likely want to do is either change CharacterCreation signature to:
void CharacterCreation(int RaceChoice, int RaceChoiceLoop)
and keep the current implementation
or pack all your console output in a string and return it at the end of the method.
Then in main()
string result = CharacterCreation();
can retrieve this value and you can print it in main

String not getting passed into class function

class Message {
public:
void changeSubject(string);
string getSubject();
private:
string subject;
};
void Message::changeSubject (string subjecto) //change subject{
subject = subjecto;
}
string Message::getSubject () //return subject {
return subject;
}
int main ()
{
Message person;
string aboutwhat;
cout << "Enter subject" << endl;
getline(cin, aboutwhat);
person.changeSubject(aboutwhat);
cout << person.getSubject();
return 0;
}
Above isn't the full code. The problem right now is that it prints "Enter Subject" and ends the program. Why am I not prompted to cin?
Your code as posted has several issues and doesn't compile. The following works for me
// Include al necessary headers:
#include <iostream>
#include <string>
// Either qualify the namespace of `std::string`, `std::cin`, etc
// or place a using statement like follows
using namespace std;
class Message {
public:
void changeSubject(string);
string getSubject();
private:
string subject;
};
void Message::changeSubject (string subjecto) //change subject
{ // <<< You have hidden the opening brace after the comment above
subject = subjecto;
}
string Message::getSubject () //return subject
{ // <<< You have hidden the opening brace after the comment above
return subject;
}
int main ()
{
Message person;
string aboutwhat;
cout << "Enter subject" << endl;
getline(cin, aboutwhat);
person.changeSubject(aboutwhat);
cout << person.getSubject();
return 0;
}
See the working sample here please.
Since you have stated in your question, "This isn't the full code", I'd suspect you have some error in the other parts that weren't shown.
"Why am I not prompted to cin?"
One likely possibility is you have had other inputs on cin before, that were invalid and cin got into fail() state.
To prevent this, you can put a cin.clear(); statement before the getline() call.
If you take inputs like e.g. numbers, you should check for validity like this
int x;
do {
cout << "Enter a number please: "
if(cin >> x) {
break;
}
cout << "Not a valid number, try again." << endl;
cin.clear();
} while(true);
Since your code above looks correct.
I would suggest you first get the prompting working first.
Then add back more code later.
I just tested the following in my own environment
#include <iostream>
#include <string>
main ()
{
std::string aboutwhat;
std::cout << "Enter subject" << std::endl;
std::getline (std::cin,aboutwhat);
std::cout << "Subject: " << aboutwhat << std::endl;
return 0;
}