Invalid array assignment? - c++

When I run the code below I get the error : invalid array assignment on lines 14 and 26. I am fairly new (1 week) to c++ so I am a bit confused. I searched and could not find an answer to solve my problem.
#include <iostream>
int main()
{
using namespace std;
char usrname[5];
char psswrd[9];
cout << "Please enter your username:";
cin >> usrname;
if (usrname = "User")
{
cout << "Username correct!";
}
else
{
cout << "Username incorrect!";
}
cout << "Please enter your password:";
cin >> psswrd;
if (psswrd = "password")
{
cout << "The password is correct! Access granted.";
}
else
{
cout << "The password is incorrect! Access denied.";
}
return 0;
}

You can't assign arrays, and
usrname = "User"
does just that. Don't.
You meant
usrname == "User"
which is a comparison, but won't compare your strings. It just compares pointers.
Use std::string instead of char arrays or pointers and compare with ==:
#include <string>
//...
std::string usrname;
cin << usrname;
if (usrname == "User")
// ^^
// note == instead of =
Side question - what's the point of shortening "username" to "usrname"... you're saving a single character...

you need to use strcmp or similar.
if (!strcmp(usrname, "User"))
{
cout << "Username correct!";
}
what you are doing is assigning a value not comparing values.

Related

C++ program stuck in an infinite loop

Please note that I am a complete beginner at C++. I'm trying to write a simple program for an ATM and I have to account for all errors. User may use only integers for input so I need to check if input value is indeed an integer, and my program (this one is shortened) works for the most part.
The problem arises when I try to input a string value instead of an integer while choosing an operation. It works with invalid value integers, but with strings it creates an infinite loop until it eventually stops (unless I add system("cls"), then it doesn't even stop), when it should output the same result as it does for invalid integers:
Invalid choice of operation.
Please select an operation:
1 - Balance inquiry
7 - Return card
Enter your choice and press return:
Here is my code:
#include <iostream>
#include <string>
using namespace std;
bool isNumber(string s) //function to determine if input value is int
{
for (int i = 0; i < s.length(); i++)
if (isdigit(s[i]) == false)
return false;
return true;
}
int ReturnCard() //function to determine whether to continue running or end program
{
string rtrn;
cout << "\nDo you wish to continue? \n1 - Yes \n2 - No, return card" << endl;
cin >> rtrn;
if (rtrn == "1" and isNumber(rtrn)) { return false; }
else if (rtrn == "2" and isNumber(rtrn)) { return true; }
else {cout << "Invalid choice." << endl; ReturnCard(); };
return 0;
}
int menu() //function for operation choice and execution
{
int choice;
do
{
cout << "\nPlease select an operation:\n" << endl
<< " 1 - Balance inquiry\n"
<< " 7 - Return card\n"
<< "\nEnter your choice and press return: ";
int balance = 512;
cin >> choice;
if (choice == 1 and isNumber(to_string(choice))) { cout << "Your balance is $" << balance; "\n\n"; }
else if (choice == 7 and isNumber(to_string(choice))) { cout << "Please wait...\nHave a good day." << endl; return 0; }
else { cout << "Invalid choice of operation."; menu(); }
} while (ReturnCard()==false);
cout << "Please wait...\nHave a good day." << endl;
return 0;
}
int main()
{
string choice;
cout << "Insert debit card to get started." << endl;
menu();
return 0;
}
I've tried every possible solution I know, but nothing seems to work.
***There is a different bug, which is that when I get to the "Do you wish to continue?" part and input any invalid value and follow it up with 2 (which is supposed to end the program) after it asks again, it outputs the result for 1 (continue running - menu etc.). I have already emailed my teacher about this and this is not my main question, but I would appreciate any help.
Thank you!
There are a few things mixed up in your code. Always try to compile your code with maximum warnings turned on, e.g., for GCC add at least the -Wall flag.
Then your compiler would warn you of some of the mistakes you made.
First, it seems like you are confusing string choice and int choice. Two different variables in different scopes. The string one is unused and completely redundant. You can delete it and nothing will change.
In menu, you say cin >> choice;, where choice is of type int. The stream operator >> works like this: It will try to read as many characters as it can, such that the characters match the requested type. So this will only read ints.
Then you convert your valid int into a string and call isNumber() - which will alway return true.
So if you wish to read any line of text and handle it, you can use getline():
string inp;
std::getline(std::cin, inp);
if (!isNumber(inp)) {
std::cout << "ERROR\n";
return 1;
}
int choice = std::stoi(inp); // May throw an exception if invalid range
See stoi
Your isNumber() implementation could look like this:
#include <algorithm>
bool is_number(const string &inp) {
return std::all_of(inp.cbegin(), inp.cend(),
[](unsigned char c){ return std::isdigit(c); });
}
If you are into that functional style, like I am ;)
EDIT:
Btw., another bug which the compiler warns about: cout << "Your balance is $" << balance; "\n\n"; - the newlines are separated by ;, so it's a new statement and this does nothing. You probably wanted the << operator instead.
Recursive call bug:
In { cout << "Invalid choice of operation."; menu(); } and same for ReturnCard(), the function calls itself (recursion).
This is not at all what you want! This will start the function over, but once that call has ended, you continue where that call happened.
What you want in menu() is to start the loop over. You can do that with the continue keyword.
You want the same for ReturnCard(). But you need a loop there.
And now, that I read that code, you don't even need to convert the input to an integer. All you do is compare it. So you can simply do:
string inp;
std::getline(std::cin, inp);
if (inp == "1" || inp == "2") {
// good
} else {
// Invalid
}
Unless that is part of your task.
It is always good to save console input in a string variable instead of another
type, e.g. int or double. This avoids trouble with input errors, e.g. if
characters instead of numbers are given by the program user. Afterwards the
string variable could by analyzed for further actions.
Therefore I changed the type of choice from int to string and adopted the
downstream code to it.
Please try the following program and consider my adaptations which are
written as comments starting with tag //CKE:. Thanks.
#include <iostream>
#include <string>
using namespace std;
bool isNumber(const string& s) //function to determine if input value is int
{
for (size_t i = 0; i < s.length(); i++) //CKE: keep same variable type, e.g. unsigned
if (isdigit(s[i]) == false)
return false;
return true;
}
bool ReturnCard() //function to determine whether to continue running or end program
{
string rtrn;
cout << "\nDo you wish to continue? \n1 - Yes \n2 - No, return card" << endl;
cin >> rtrn;
if (rtrn == "1" and isNumber(rtrn)) { return false; }
if (rtrn == "2" and isNumber(rtrn)) { return true; } //CKE: remove redundant else
cout << "Invalid choice." << endl; ReturnCard(); //CKE: remove redundant else + semicolon
return false;
}
int menu() //function for operation choice and execution
{
string choice; //CKE: change variable type here from int to string
do
{
cout << "\nPlease select an operation:\n" << endl
<< " 1 - Balance inquiry\n"
<< " 7 - Return card\n"
<< "\nEnter your choice and press return: ";
int balance = 512;
cin >> choice;
if (choice == "1" and isNumber(choice)) { cout << "Your balance is $" << balance << "\n\n"; } //CKE: semicolon replaced by output stream operator
else if (choice == "7" and isNumber(choice)) { cout << "Please wait...\nHave a good day." << endl; return 0; }
else { cout << "Invalid choice of operation."; } //CKE: remove recursion here as it isn't required
} while (!ReturnCard()); //CKE: negate result of ReturnCard function
cout << "Please wait...\nHave a good day." << endl;
return 0;
}
int main()
{
string choice;
cout << "Insert debit card to get started." << endl;
menu();
return 0;
}

I'm comparing two variables with the same value but it says they're different

Well, I was asked to do a little job with SHA-256. I have to receive a user name and a password from the user (in console), change the password to a SHA-256 hash value and close the file (binary file). Then I have to read it again, getting its data and comparing it with new user inputs, checking if they are the same or not. A simple log-in system using SHA-256 hashing. The thing is, I write a random user name and password, but when I try to compare them later in the second step, it fails. The SHA-256 part comes straight out of the original code, it wasn't the point of this assignation.
I tried changing all my char arrays to strings, used, strcpy, strcpy_s and strncpy (just in case) and more, but it doesn't seem to work. Most of the codecomes directly from SHA-256 (my teacher sent it), but I'll put it here nonetheless
I'm putting the entire code in pastebin (it's kind of long): https://pastebin.com/W9jxsbK6
I don't know how to edit correctly in this text box, so please use the paste bin link.
struct Credentials {
char user[10];
char password[256];};
int main() {
Credentials c;
char user2[10];
char password2[256];
string test;
fstream file;
int opc;
do{
cout << "Menu:" << endl;
cout << "1.Create new user and password" << endl;
cout << "2.Validate user and password" << endl;
cin >> opc;
switch(opc){
case 1:
cout << "Type the user name" << endl;
cin >> user2;
strcpy_s(c.user, sizeof user2, user2);
cout << "Type the password" << endl;
cin >> password2;
test = SHA256::digestString(password2).toHex();
strcpy_s(c.password, sizeof test, test.c_str());
file.open("credentials.dat",ios::out|ios::binary);
if(!archivo){
cout<<"Error...\n";
return -1;
}
file.write((char*)&c,sizeof(c));
file.close();
break;
case 2:
cout << "Type user name" << endl;
cin >> user2;
cout << "Type password" << endl;
cin >> password2;
file.open("credentials.dat",ios::in|ios::binary);
if(!file){
cout<<"Error...\n";
return -1;
}
if(file.read((char*)&c,sizeof(Credentials))){
if(c.user == user2 && SHA256::digestString(password2).toHex() == c.password){
cout << endl << endl << "User validated" << endl;
}else{
cout << endl << endl << "Error" << endl;
}
}
}
} while (opc > 0 && opc < 3);
cin.ignore();
return 0;
}
if (c.user == user2)
Since user2 is a character array, and Credentials::user is also a character array, that line is not how you compare two character arrays. What that line does is compare two pointers, not contents of arrays.
The function to use is strcmp, or if you want to compare specifically N characters, the function is strncmp.
#include <cstring>
//...
if ( strcmp(c.user, user2) == 0)
{
// strings are equal
}
Now, if c.user and/or user2 were std::string, then using == to compare would have worked. That's why using std::string is much more intuitive than using char arrays in this respect -- operations such as == actually work as expected.

Elegant C++ Code: How to write more efficient code using while loops and conditional statements

Would you be able to give me some suggestions for how I could simplify my code?
#include <iostream>
#include<fstream>
#include<string>
using namespace std;
int main() {
string current_users[5];
string new_users[5], new_user;
ifstream read;
read.open("current.txt");
for (int index = 0; index < 5; index++) {
read >> current_users[index];
}
read.close();
cout << "Enter a username: ";
cin >> new_user;
char user_choice;
int index = 0, new_index = 0;
while (index <= 5) {
if (new_user == current_users[index]) {
cout << "That username already exists."
<< " Enter a different username: ";
cin >> new_user;
index = 0;
continue;
}
if (index < 5)
index++;
else {
new_users[new_index] = new_user;
cout << "\nWelcome " << new_user << endl;
new_index++;
if (new_index < 5) {
cout << "Would you like to register another user?:"
<<"'Y' for yes or 'N' for no";
cin >> user_choice;
}
if (user_choice == 'Y' || user_choice == 'y') {
cout << "\nEnter a new username: ";
cin >> new_user;
index = 0;
}
else
break;
}
}//end of while
system("pause");
return 0;
}
This program asks a user to enter a username and checks if that username already exists. If it exists, it prompts the user to use a different username, also checking if that username already exists. If the username is unique the program welcomes the new user and asks if the user wants to register another new user (weird, but I wanted to try it). If the user wants to add another user to the "website" per say then the program runs again, checking for redundancy. I limited this program to 5 possible usernames to check and add for ease of testing. There's no errors.
The code is just chunky. I came up with this problem. I'm not in school. Can't afford it and wasn't admitted to any school where I applied. Any suggestions for online schools that offer degrees in computer science?
Here are some suggestions:
Array of Structures not parallel arrays
Use a std::vector of structures and not parallel arrays:
struct Record
{
std::string new_user;
std::string current_user;
};
std::vector<Record> database;
Processors that use a data cache like to have their elements close together. Here, new_user[0] would be next to current_user[0] in the cache.
With your parallel arrays, new_users[0] is next to current_user[4]; so the processor has to go past 4 elements to get to the first new_users element.
Loop Unrolling
You could eliminate the for loop for reading in your values:
read >> current_users[0];
read >> current_users[1];
read >> current_users[2];
read >> current_users[3];
read >> current_users[4];
This eliminates the overhead associated with a for loop.
Convert to all Lower or all Upper case before comparing
You can reduce the number of comparisons by converting to uppercase or lowercase before comparing:
if (std::toupper(user_choice) == 'Y')
Most of what you have is good. I'd wrap everything into a function and use std::find from the standard library in order to find duplicates.
template<std::size_t N, std::size_t M>
void GetUsers( std::string (&new_users)[N], std::string const (&current_users)[M] ) {
int idx = 0;
while (idx < 5) {
std::cout << "Enter a username: ";
std::string user; std::cin >> user;
if (std::find(current_users.begin(), current_users.end(), user) != current_users.end()) {
std::cout << "That username already exists.\n";
continue;
} else {
new_users[idx++] = user;
if (idx < 5) {
std::cout << "Would you like to register another user? [Y/n]: ";
if (std::tolower(std::cin.get()) == 'y') {
continue;
}
}
break;
}
}
}

Assigning the "Enter Key" value to a string [C++]

In this rather simple exercise I have to receive an user input, store said input into a string, pass the string to a function by reference and finally modify the string so that every character is "parsed" by the toupper() function.
However, should the user insert 'q' as input, the program stops saying "Bye" OR if he just presses the Enter Key, the program is supposed to say something like "Hey, this string is empty".
Now the real problem here is in the last part since my code won't manage the case where the user inputs only the Enter Key value (to be honest, even if I just text a bunch of spaces followed by the Enter Key, nothing happens)
void uppercase(std::string &);
int main(){
using namespace std;
string ex2;
cout << "Exercise 2" <<endl;
while(ex2!="Bye"){
cout << "Enter a string(q to quit): ";
cin >> ex2;
cout << "Was: " << ex2 << endl << "Now is: ";
uppercase(ex2);
}
return 0;
}
void uppercase(std::string &str){
using namespace std;
if(str[0]=='\n')
cout <<"Empty string dude!" << endl;
else{
if(str.length()==1 && str[0]=='q'){ //press 'q' to exit program
str="Bye";
cout << str;
}
else{ //uppercase
for(int i=0;i<str.length();i++){
str[i]=(toupper(str[i]));
}
cout << str <<endl;
}
}
}
I also tried the compare() function and even to compare the whole string to null (pointless, but still worth a shot) and to the string "";
Sorry for the bad interpretation of your problem, trying
if( (str.length()==1 && str[0]=='q') || str.length() == 0)
{}
May help you out of the problem

C++ how to detect whitespace

I am creating a program that allows users to key in their user name and password. the problem is, when the system prompts to "Enter userName:" and I hit enter key, it will print out "Name cannot contain a blank"
but if I hit a FEW spaceBars and hit enter key and make it blank field after that ,it skips to prompt the user to enter the password without printing out "Name cannot contain a blank" and prompting the user to enter the userName again.
how should I change my codes to ensure that it will still prompt the user to enter the userName again even though I hit a spacebars and hit enter? please advise. thanks
code
string userName=" ";
string password;
cout << "Enter UserName:";
while (getline(cin, userName)) {
if (userName.empty()) {
cout << "Name cannot contain a blank."<< endl;
cout << "Enter userName:";
userName = userName;
//throw errorMsg;
}
if(!userName.empty()) {
cout << "Enter Password";
}
}
Username validation is not trivial, for many reasons. You don't want to be in the business of manufacturing what you "think" the user wanted to type, while at the same time it is clear you want to avoid a potentially long validation of what is going to be invalid.
In the end, I would suspect you can simply take the prospect entry, strip all the whitespace, and if there is anything left over, submit the original entry for validation. Don't bite off the business of validating something the user may have meant to type. I.e.
"\t\t "
should be grounds for a re-prompt, while
"John Smith"
"\t WillJohnson "
"Gary"
should all be submitted verbatim, and let the chips fall where they may.
That said,
bool isValidUserName(std::string name)
{
name.erase(std::remove_if(name.begin(), name.end(),
[](char c){ return std::isspace(static_cast<unsigned char>(c));}), name.end());
return !name.empty();
}
should do that for you. A sample is below:
int main()
{
std::cout << std::boolalpha << isValidUserName("\t \t ") << std::endl;
std::cout << std::boolalpha << isValidUserName("\t Will Johnson ") << std::endl;
return 0;
}
Output
false
true
Assuming a C++11 compliant compiler your test for spaces could be using std::find_if
if (std::find_if(userName.begin(), userName.end(), isspace))
!= userName.end())
or
if (std::find_if(userName.begin(), userName.end(),
[=](char c){return isspace(c);}) != userName.end())
Notice that several characters are space-like ' ' but also '\t' (tabulation) etc...
just consider the space as a character and increment it when you find it
The logic is to check if the starting character of the username is a blank space and also the last slot of the string is not a blank space.
example :
This should be accepted = "a b".
But
this should not be " a ".
or this should not be " a".
or this should not be "a ".
if (userName[0]!=" " && userName[userName.size()]!=" "){
//accept this case and move on.
}
else{
//reject all other cases.
}
#include <iostream>
#include <vector>
using namespace std;
int main(){
string username, password;
int un = 1;
int ps = 1;
while(un){
cout<<"Username:";
getline(cin,username);
int usize = username.size();
vector <string> v ;
v.insert(v.begin(), username);
if (usize==1){
if(username==" "){
cout<<"Username can not be blank"<<endl;
}
else{
un=0;
}
}
else{
int check=0; int trim = 0;
for (int i=0; i<usize; i++){
if (username[i]!=' '){
check=1;
trim = i;
break;
}
}
if(check==1){
un=0;
}
else{
}
}
}
while(ps){
cout<<"Password:";
getline(cin,password);
int usize = password.size();
vector <string> v ;
v.insert(v.begin(), password);
if (usize==1){
if(password==" "){
cout<<"Password can not be blank"<<endl;
}
else{
ps=0;
}
}
else{
int check=0;
for (int i=0; i<usize; i++){
if (password[i]!=' '){
check=1;
break;
}
}
if(check==1){
ps=0;
}
else{
}
}
}
cout<<endl;
cout<<"----------------------------------------------"<<endl;
cout<<"Username is: "<<username<<endl;
cout<<"Password is: "<<password<<endl;
return 0;
}
Check if the string is empty if so then do the empty validation
If the string is not empty then check if it has spaces i.e find_first_not_of("\t ") if this returns number greater than 0 we know the username has leading white/tab spaces followed by zero or more characters. i.e leading spaces then the username
Its upto you to now do the validation for a good username.
#include <iostream>
#include <cstring>
using namespace std;
int main() {
string userName = " ";
string password;
cout << "Enter UserName:";
while(getline(cin, userName)) {
if(userName.empty()) {
cout << "Empty String";
} else if(userName.find_first_not_of("\t ") > 0) {
cout << "Could contain spaces followed by username or just spaces";
} else {
cout << "User Name is Valid";
}
}
return 0;
}