I can not seem to figure out why the get_password function call will always return qwert no matter what string I pass into the function. My problem is that I can not see what is going wrong with the string comparison in this function.
string get(string askfor, int numchars, string input)
{
cout << askfor << "(" << numchars << " characters): ";
cin >> input;
return input;
}
string get_password(string name)
{
string pwd;
if (name == "botting"){
pwd = "123456";
}
else if (name == "ernesto") {
pwd = "765432";
}
else if (name == "tong") {
pwd = "234567";
}
else {
pwd = "qwert";
}
return pwd;
}
int main()
{
string name;
string pwd;
string passwd;
cout << "Address of name =" << &name << "\n";
cout << "Address of pwd =" << &pwd << "\n";
cout << "Address of passwd =" << &passwd << "\n";
bool authenticated = false;
while (!authenticated)
{
// call one
string name1 = get("Name", 7, name);
cout << "call one returned: " << name1 << endl;
// call two
string pass1 = get_password(name);
cout << "call two returned: " << pass1 << endl;
//call three
string pass2 = get("Password", 7, passwd);
cout << "call three returned: " << pass2 << endl;
// compare the two passwords
authenticated = false;
if (pass1 == pass2) {
cout << "Welcome " << name << "\n";
authenticated = true;
}
else {
cout << "Please try again\n";
}
}
return 0;
}
pass name1 to the second call:
// call one
string name1 = get("Name", 7, name);
cout << "call one returned: " << name1 << endl;
// call two
string pass1 = get_password(name1); // change this variable
cout << "call two returned: " << pass1 << endl;
the get() returns the name to name1 string and does not update name variable itself, because of this name remains empty string.
That's because you never assign name anything. It is initialized as "", and that never changes. Since that matches none of the cases in get_password, it always falls into the else case, which yields "qwert".
I think the issue is that your get function would be better written like:
string get(string askfor, int numchars)
{
string input; // input shouldn't be an argument
cout << askfor<<"("<<numchars<<" characters): ";
cin >> input;
return input;
}
And you can use the result of that to assign into name:
name = get("Name", 7);
You just need to pass by reference rather than value.
string get(string askfor, int numchars, string &input)
{
cout << askfor << "(" << numchars << " characters): ";
cin >> input;
return input;
}
Related
I am hitting a bit of a roadblock and don't know what to do. I am attempting to write a program that creates an account with username and password and stores it to a text file. However, while using the program and inputting the username and password data, the program crashes as it moves to the encryption function. Thank you for your time.
bool processNewAccount (string username, string password)
{
ofstream outFile;
string outFileName = "creds.txt";
outFile.open(outFileName.c_str(), fstream::app);
if (!outFile)
return false;
outFile << username << ":" << password << endl;
outFile.close();
return true;
}
void encrypt(string& s, int key)
{
for (int i = 0; i < s.length(); i++)
{
s[i] = (s[i] + key) % 127;
if (s[i] < 33)
{
s[i] = s[i] + 33;
}
}
}
string createAccount()
{
string firstName;
string lastName;
cout << "Creating an Account:" << endl;
cout << "First Name: ";
cin >> firstName;
cout << "Last Name: ";
cin >> lastName;
cout << endl;
string username;
if (lastName.length() <5)
{
for (int i = 0; username.length() <5; i++)
username = lastName + firstName.substr(0,i);
}
else
username = lastName.substr(0,4) + firstName.at(0);
for (int i = 0; i < 5; i++)
username.at(i) = tolower(username[i]);
}
string createPass ()
{
string password1;
string password2;
cout << "Create a Password that:" << endl << endl << "-Is at least 10 characters" << endl << "-Contains no spaces" << endl << endl << "Password: ";
cin >> password1;
if (password1.length() < 10)
{
cout << "Password is not secure enough" << endl;
cout << "Enter a password at least 10 characters: " << endl << endl;
createPass();
}
if (password1.length() >= 10)
cout << "Confirm Password: ";
cin >> password2;
if (password2 != password1)
{
cout << "Passwords do not match!" << endl << endl;
createPass();
}
}
int main()
{
string user;
string pass;
char menuOption;
do
{
printMenu();
cin >> menuOption;
switch (menuOption)
{
case '1': login();
break;
case '2':
user = createAccount();
pass = createPass();
encrypt(pass, 13);
processNewAccount (user, pass);
cout << "Welcome " << "Username: " << user << endl << "Email: " << user << "#student.edu" << endl;
break;
case '3': break;
default : cout << "\nInvalid entry. Please choose from the menu.|n";
break;
}
}
while (menuOption != 3);
cout << "\n Goodbye.\n\n";
return 0;
}
Here's a better version of createPass. It actually returns the password, and also uses a loop to avoid the recursive calls that you make.
string createPass ()
{
string password1;
bool password_ok = false;
do
{
cout << "Create a Password that:" << endl << endl << "-Is at least 10 characters" << endl << "-Contains no spaces" << endl << endl << "Password: ";
cin >> password1;
if (password1.length() < 10)
{
cout << "Password is not secure enough" << endl;
cout << "Enter a password at least 10 characters: " << endl << endl;
}
else
{
cout << "Confirm Password: ";
string password2;
cin >> password2;
if (password2 != password1)
{
cout << "Passwords do not match!" << endl << endl;
}
else
{
password_ok = true;
}
}
}
while (!password_ok);
return password1;
}
And as Lightness Races in Orbit points out you need to fix createAccount in a similar way.
Untested code of course.
Neither createAccount() nor createPass() returns a value, despite having a non-void return type. This means your program has undefined behaviour. Likely the stack is in "a bit of a way" after calling those functions, resulting in the crash you've observed. Your compiler should have warned you about this: heed your compiler's warnings, then you'll know what to do.
Ensure that you have a return statement so that you can pass your functions' results back to the caller. These statements might look like this:
std::string createAccount()
{
// ...
return username;
}
std::string createPass()
{
// ...
return password1;
}
In the case of createPass(), you'll also have to change your recursive calls:
if (password1.length() < 10) {
cout << "Password is not secure enough" << endl;
cout << "Enter a password at least 10 characters: " << endl << endl;
return createPass();
}
// ...
if (password2 != password1) {
cout << "Passwords do not match!" << endl << endl;
return createPass();
}
… but I agree with John that you'd be better off replacing this recursion with a nice loop.
everyone. This is my first time using classes in C++. The instructions in the assignment I'm working on seemed a little ambiguous to me, so I'm including them in case someone more experienced thinks I'm not following them properly in my code.
Anyway, I wrote my program, and it works and creates the output I want based on my perception of the assignment. However, when I run it, an error also pops up that says "Invalid Null Pointer." I've done some research but I can't seem to figure out why this is.
Can someone help me fix my code and help a student understand what they did wrong? Thanks! :)
Assignment
Write a Person class that contains the following fields and methods:
• First Name
• Last Name
• ID Number
• Necessary constructors
•
Methods to return last name, first name, full name, and ID number
•
Methods to print last name, first name, and ID number
Write a main program to test your class.
My Program
#include <iostream>
#include <string>
using namespace std;
class Person {
private:
string FirstName;
string LastName;
string FullName;
int IDNumber;
public:
void SetFirstName(string);
void SetLastName(string);
void SetIDNumber(int);
string SetFullName(string first, string last);
string GetFirstName();
string GetLastName();
string Method1();
string Method2();
int GetIDNumber();
};
void Person::SetFirstName(string first) {
FirstName = first;
}
void Person::SetLastName(string last) {
LastName = last;
}
void Person::SetIDNumber(int ID) {
IDNumber = ID;
}
string Person::SetFullName(string first, string last) {
FullName = string(first + " " + last);
return FullName;
}
string Person::GetFirstName() {
return FirstName;
}
string Person::GetLastName() {
return LastName;
}
int Person::GetIDNumber() {
return IDNumber;
}
string Person::Method1() {
cout << "LAST NAME: " << LastName << endl;
cout << "FIRST NAME: " << FirstName << endl;
cout << "FULL NAME: " << FullName << endl;
cout << "ID NUMBER: " << IDNumber << endl;
return 0;
}
string Person::Method2() {
cout << "LAST NAME: " << LastName << endl;
cout << "FIRST NAME: " << FirstName << endl;;
cout << "ID NUMBER: " << IDNumber << endl;
return 0;
}
int main() {
string firstname, lastname;
int id;
char command;
Person Person;
cout << "What is the subject's first name? For example: Bob Smith" << endl;
cin >> firstname >> lastname;
cout << "What is " << firstname << " " << lastname << "'s ID number?" << endl;
cin >> id;
Person.SetFirstName(firstname);
Person.SetLastName(lastname);
string fullname = Person.SetFullName(firstname, lastname);
Person.SetIDNumber(id);
cout << "COMMANDS:" << endl;
cout << "f : Returns first name." << endl << "l : Returns last name." << endl << "i : returns ID number." << endl << "n : returns full name." << endl;
cout << "1 : Returns last name, first name, full name, and ID number." << endl;
cout << "2 : Returns last name, first name, and ID number." << endl << endl;
cout << "Please input the letter of your command: ";
cin >> command;
switch (command) {
case 'f':
case 'F':
cout << "FIRST NAME: " << Person.GetFirstName() << endl;;
break;
case 'l':
case 'L':
cout << "LAST NAME: " << Person.GetLastName() << endl;
break;
case 'i':
case 'I':
cout << "ID NUMBER: " << Person.GetIDNumber() << endl;
break;
case 'n':
case 'N':
cout << "FULL NAME: " << fullname << endl;
break;
case '1':
Person.Method1();
cout << endl;
break;
case '2':
Person.Method2();
cout << endl;
break;
default:
cout << "That is not a valid command." << endl;
}
}
string Person::Method1() {
// ...
return 0;
}
There's your problem.
Your method returns a std::string. 0, in this context, is treated as a NULL pointer, and your code blows up attempting to convert a NULL pointer into a string.
P.S. If you used a debugger to step through your code, a line at a time, you would've been able to figure it out yourself, instead of asking strangers on stackoverflow.com for help. Learning how to use a debugger is a required skill for every C++ developer.
The explanation:
Working with two input streams streams, both use getline() to capture the user input. The first getline() is called in the userStringPrompt() function:
string userStringPrompt()
{
string userString;
cout << "Enter a string: ";
getline(cin, userString);
return userString;
}
That sets a string that the program will use later to perform functions, like count its consonants, its vowels, etc.
The second input is used in the menu selection (choose what function/method to perform on the above string):
string userMenuPrompt()
{
string userString;
getline(cin, userString);
return userString;
}
This takes in a user input: A, B, C, D, E and performs an action. For example, if a user inputs into the first input stream:
Hello
and then enter "A" in the second input stream, it should count the vowels in hello, then return the number from the calculation, e.g. 2
The issue:
The program functions correctly when the input in userStringPrompt is without spaces. For example, Hello works, but Hello World would break the application and cause a force close. I'm not sure why, since I am capturing the stream with getline(cin, string).
The entire code:
#include <string>
#include <iostream>
using namespace std;
string userStringPrompt();
string userMenuPrompt();
void showMenu();
int countConsonants(string *ptr);
int countVowels(string *ptr);
int countConsonantsVowels(string *ptr);
int main()
{
string userInput = "";
string userString;
bool userStringSet = false;
while (userInput != "e") {
if (!userStringSet) {
userString = userStringPrompt();
userStringSet = true;
}
showMenu();
userInput = userMenuPrompt();
string *pointerVariable = &userString;
if (userInput == "a") {
cout << endl;
cout << "Vowel count in \"" << userString << "\": " << countVowels(pointerVariable) << endl;
cout << endl;
break;
}
if (userInput == "b") {
cout << endl;
cout << "Consonants count in \"" << userString << "\": " << countConsonants(pointerVariable) << endl;
cout << endl;
break;
}
if (userInput == "c") {
cout << endl;
cout << "Vowel count in \"" << userString << "\": " << countVowels(pointerVariable) << endl;
cout << "Consonants count in \"" << userString << "\": " << countConsonants(pointerVariable) << endl;
cout << endl;
break;
}
if (userInput == "d") {
userStringSet = false;
break;
}
}
return 0;
}
int countConsonants(string *ptr) {
string getVar = *ptr;
int stringSize = getVar.length();
int vowelCount = countVowels(ptr);
int totalConsonants = stringSize - vowelCount;
return totalConsonants;
}
int countVowels(string *ptr) {
int vowelsToCount = 0;
string stringVar = *ptr;
for (int i = 0; i < stringVar.length(); i++){
if (tolower(stringVar[i]) == 'a' || tolower(stringVar[i]) == 'e' || tolower(stringVar[i]) == 'i' || tolower(stringVar[i]) == 'o' || tolower(stringVar[i]) == 'u') {
vowelsToCount++;
}
}
return vowelsToCount;
}
int countConsonantsVowels(string *ptr) {
int count = countConsonants(ptr);
count += countVowels(ptr);
return count;
}
string userStringPrompt()
{
string userString;
cout << "Enter a string: ";
getline(cin, userString);
return userString;
}
string userMenuPrompt()
{
string userString;
getline(cin, userString);
return userString;
}
void showMenu() {
cout << "A) Count the number of vowels in the stream" << endl;
cout << "B) Count the number of consonants in the stream" << endl;
cout << "C) Count both the vowels and consonants in the stream" << endl;
cout << "D) Enter another string" << endl;
cout << "E) Exit the program" << endl;
}
Any guidance/hints would be greatly appreciated. I'm absolutely confused.
I guess your program is not crushing, it's just normally exits.
The program '[8776] Chapter10.exe' has exited with code 0 (0x0).
which is ok, no error code returned.
When you run your program it asks for input, do its work and because there is no more work for it - exits. To see the output you can do one of the following:
Try to run it with Ctrl + F5 in VS, it will add pause command to the end.
Another way to run it is to open command line and run it from there.
Also in your case I guess the problem is in break statements. When you choose what to do with the string you break your loop (which should run while user enters e). Remove all breaks and it will be fine.
im taking in rooms from a text file and trying to use the information in variables so i after i take the info in i add it to a linkedList, search for the room that i want by the room id and then use setRoomName = to the room it finds name. But this isnt working... Can anyone see the problem ?
Here is my code:
#include "Rooms.h"
#include "DoublyLinkedList.h"
#include <string>
using namespace std;
DoublyLinkedList<Rooms> roomsList;
DoublyLinkedListIterator<Rooms> itr = roomsList.getIterator();
Rooms :: Rooms()
{
this->roomID = 0;
this->roomName = "";
this->roomExits = "";
}
Rooms :: Rooms(int roomID,string roomName,string roomExits)
{
this->roomID = roomID;
this->roomName = roomName;
this->roomExits = roomExits;
}
int Rooms :: getRoomID()
{
return roomID;
}
void Rooms :: setRoomID(int roomID)
{
this->roomID = roomID;
}
string Rooms :: getRoomName()
{
return roomName;
}
void Rooms ::setRoomName(string roomName)
{
this->roomName = roomName;
}
string Rooms :: getRoomExits()
{
return roomExits;
}
void Rooms :: setRoomExits(string roomExits)
{
this->roomExits = roomExits;
}
void Rooms :: loadRooms()
{
string fileName = "Rooms\\Rooms.txt";
ifstream infile(fileName);
string garbage;
int loadRoomID;
string loadRoomName1;
string loadRoomName2;
string loadRoomExits;
while(infile >>garbage >> garbage >> loadRoomID >> garbage >>
garbage >> garbage >> loadRoomName1 >> loadRoomName2 >> garbage
>> garbage >> loadRoomExits)
{
cout << "Room ID: \t\t"<< loadRoomID << "\n";
cout << "Room Name: \t\t"<< loadRoomName1 <<" " << loadRoomName2 << "\n";
cout << "Room Exits: \t\t" << loadRoomExits <<"\n";
string loadRoomName = loadRoomName1 + loadRoomName2;
Rooms r1 (loadRoomID,loadRoomName,loadRoomExits);
roomsList.Append(r1);
}
}
void Rooms :: printRooms()
{
int index = 0;
//Loop through the iterator.
for(itr.Start();itr.Valid();itr.Forth())
{
index++;
cout << "------------------Rooms------------------\n";
cout << "--------------------------------\n";
cout << "Position:\t\t" << index << "\n";
cout << "--------------------------------\n";
cout << "Room ID:\t\t" << itr.Item().getRoomID() << "\n";
cout << "Room Name:\t\t" << itr.Item().getRoomName() << "\n";
cout << "Room Exits:\t\t" << itr.Item().getRoomExits() << "\n";
cout << "------------------------------------------\n";
}
cout << "Rooms: \t\t" << roomsList.getCount() << "\n";
}
string Rooms :: searchByRoomID(int searchByID)
{
//Loop through the Iterator.
for (itr.Start(); itr.Valid(); itr.Forth())
{
//If the object entered has the same first name as the one in the loop.
if (itr.Item().getRoomID() == searchByID)
{
//Print out the details from the list.
cout << "------------------------------------------\n";
cout << "Room ID:\t\t" << itr.Item().getRoomID() << "\n";
cout << "Room Name:\t\t" << itr.Item().getRoomName() << "\n";
cout << "Room Exits:\t\t" << itr.Item().getRoomExits() << "\n";
cout << "------------------------------------------\n";
setRoomID(itr.Item().getRoomID());
setRoomName(itr.Item().getRoomName());
setRoomExits(itr.Item().getRoomExits());
cout << getRoomID();
cout << getRoomName();
cout << getRoomExits();
}
}
return getRoomName();
}
Any help would be greatly appreciated.
Mistake which I found is you are finding a room By id and then you are Setting id,name,exits as same which you found. So how can you find a change
setRoomID(itr.Item().getRoomID());
setRoomName(itr.Item().getRoomName());
setRoomExits(itr.Item().getRoomExits());
Instead of this you should give some other value which you need to set for Exmple
setRoomID(789);
setRoomName("Room ");
setRoomExits("yes");
Here the found room's id,name,exits sets to 789,"Room ","Yes" respectivly
I've tried to write a simple database program. The problem is that ofstream does NOT want to make a new file.
Here's an extract from the offending code.
void newd()
{
string name, extension, location, fname;
cout << "Input the filename for the new database (no extension, and no backslashes)." << endl << "> ";
getline(cin, name);
cout << endl << "The extension (no dot). If no extension is added, the default is .cla ." << endl << "> ";
getline(cin, extension);
cout << endl << "The full directory (double backslashes). Enter q to quit." << endl << "Also, just fyi, this will overwrite any files that are already there." << endl << "> ";
getline(cin, location);
cout << endl;
if (extension == "")
{
extension = "cla";
}
if (location == "q")
{
}
else
{
fname = location + name + "." + extension;
cout << fname << endl;
ofstream writeDB(fname);
int n = 1; //setting a throwaway inteher
string tmpField, tmpEntry; //temp variable for newest field, entry
for(;;)
{
cout << "Input the name of the " << n << "th field. If you don't want any more, press enter." << endl;
getline(cin, tmpField);
if (tmpField == "")
{
break;
}
n++;
writeDB << tmpField << ": |";
int j = 1; //another one
for (;;)
{
cout << "Enter the name of the " << j++ << "th entry for " << tmpField << "." << endl << "If you don't want any more, press enter." << endl;
getline(cin, tmpEntry);
if (tmpEntry == "")
{
break;
}
writeDB << " " << tmpEntry << " |";
}
writeDB << "¬";
}
cout << "Finished writing database. If you want to edit it, open it." << endl;
}
}
EDIT: OK, just tried
#include <fstream>
using namespace std;
int main()
{
ofstream writeDB ("C:\\test.cla");
writeDB << "test";
writeDB.close();
return 0;
}
and that didn't work, so it is access permission problems.
ofstream writeDB(fname); //-> replace fname with fname.c_str()
If you lookup the documentation of the ofstream constructor, you will see something like:
explicit ofstream ( const char * filename, ios_base::openmode mode = ios_base::out );
The second argument is optional, but the first one is a const char*, and not a string. To solve this problem the most simple way is to convert your string to something called a C-string (char*, which is basically an array of chars); to do that just use c_str() (it«s part of the library).
Other than that, you could just place the information directly on a C-str, and then pass it normally to the ofstream constructor.