C++ Help, Please. Thank You.

Flint • Nov 21, 2010 10:20 pm
This program is supposed to check that a password is at least 6 characters AND contains at least one digit. What I never was able to figure out is how to check for BOTH conditions. Since I have them in two functions, once one is satisfied, it drops to the next one and forgets about the other. I didn't know how to get "back" to the previous condition, so I copy/pasted the code in an if/else statement! The if statement was originally supposed to print the "Thank you that is a valid password" but it didn't print, so I put it in again at the bottom.

However, if you put in a correct password at the first prompt, the if statement prints. In the version I am turning in, I told it to print an endl; (it just skips a line).

See how the "Please enter a password: ";s are numbered 1 through 4? if you get down to "Please enter a password4: "; and enter 123 it accepts this as valid. It still does not check "also" for length.

I don't know how to validate a string of input for two separate conditions. The problem is, when it fails I need it to tell the user why it failed, so I can't just lump them together.

I am going cross-eyed. Can anybody tell me what my ignorant mistake is?

There are no examples of this in my textbook...

//This program prompts the user to enter a password,
//and then checks the password against (a) and (b)
//conditions to determine if it is valid. Whenever
//the password fails a checkpoint, the reason is given
//and the user is prompted to enter another password.
//When a correct password is given, the user is informed
//and the program exits anfter the enter key is pressed.

#include<iostream>
#include<cstring>
#include<cctype>
using namespace std;

//Function checks the password for length. (a)
bool passLength(char[]);

//Function checks the password for a digit. (b)
bool containDigit(char[]);

int main()
{
const int SIZE = 21;
char password[SIZE];

cout << "Please enter a password: ";
cin.getline(password, SIZE);

while (!passLength(password)) //(a) called
{
cout << "Passwords must be at least 6 characters long" << endl;
cout << "Please enter a password1: ";
cin.getline(password, SIZE);
(passLength(password)); //(a) called again
}

while (!containDigit(password)) //(b) called
{
cout << "Passwords must include at least on digit (1-9)" << endl;
cout << "Please enter a password2: ";
cin.getline(password, SIZE);
(containDigit(password)); //(b) called again
}

if ((passLength(password)) && (containDigit(password)))
{
cout << "Clearly, I have no idea what I'm doing here..." << endl;
cout << "I copy/pasted the previous code, to check it again. lol." << endl;
cout << "I never really figured out how to check for BOTH conditions."<< endl;
}
else
{
while (!passLength(password)) //(a) called
{
cout << "Passwords must be at least 6 characters long" << endl;
cout << "Please enter a password3: ";
cin.getline(password, SIZE);
(passLength(password)); //(a) called again
}

while (!containDigit(password)) //(b) called
{
cout << "Passwords must include at least on digit (1-9)" << endl;
cout << "Please enter a password4: ";
cin.getline(password, SIZE);
(containDigit(password)); //(b) called again
}
}

cout << "Thank you that is a valid password" << endl;

//Keep the window open until Enter key is pressed.
cout << "\nPress Enter to close window..." << endl;
std::cin.get();

return 0;
}

bool passLength(char password[]) //(a) function
{
int lengthPass = 6;
int length = strlen(password);

if (lengthPass <= length)
return true;
else return false;
}


bool containDigit(char password[]) //(b) function
{
int index = 0;
int length = strlen(password);

for (index = 0; index < length; index++ )
{
if (isdigit(password[index]))
return true;
}
return false;

}


I am a total n00b at programming, this is programming fundamentals 1. Please take pity on me. This is due on Nov. 23rd.
Flint • Nov 21, 2010 10:30 pm
This illustrates my dilemma:

Please enter a password: abc
Passwords must be at least 6 characters long
Please enter a password: abcdef
Passwords must include at least on digit (1-9)
Please enter a password: 123
Passwords must be at least 6 characters long
Please enter a password: abcdef
Passwords must include at least on digit (1-9)
Please enter a password: 123
Thank you that is a valid password

Press Enter to close window...


I know how to evaluate for one or the other, but not both. I could repeat my "hack" ad infinitum, but it would always, eventually let you enter 123 and have it accpeted as valid.
Pete Zicato • Nov 22, 2010 12:16 am
What you want to do is to check the minimum number of times.


bool oklength = PassLength(password);
bool okdigit = containDigit(password);

while (!okLength || !okDigit)
{
if (!okLength)
// err MSG

if (!okDigit)
// err MSG

// get password again


oklength = PassLength(password);
okdigit = containDigit(password);

}
Flint • Nov 22, 2010 11:16 am
Thank you. I came to more or less the same conclusion.

All last night, I was dreaming in flowcharts. I was continuously, acutely aware that the subject of each dream was being passed as a parameter to the dream function. For a nice dose of recursion, I think the only dream I had was the one in which the above happened.

When I woke up this morning I was thinking this:

//bool function (a) checks password length
//bool function (b) checks if password contains digit

get password

while ( ((a) not true) OR ((b) not true) )

{

if ((a) not true)
&#8220;Error message&#8221;
get password

if ((b) not true)
&#8220;Error message&#8221;
get password


}

&#8220;That is a valid password&#8221;


That should work, right?
Lamplighter • Nov 22, 2010 11:30 am
Don't you need a way out of the loop if the User wants to "Cancel".
Pete Zicato • Nov 22, 2010 12:29 pm
Flint;695585 wrote:

That should work, right?

No. Step through the code and ask yourself what would happen if the password were too short and had no digit.

@Lamplighter - yes in a real world program. Flint didn't mention it as part of the exercise.
Flint • Nov 22, 2010 3:16 pm
Pete Zicato;695598 wrote:
No. Step through the code and ask yourself what would happen if the password were too short and had no digit.


I should explain, the condition of the while loop would be written as:

while ((!passLength(password)) || (!containDigit(password)))


...so it actually calls both functions, and should execute the loop if either one (or both) is false.

Once inside the loop, it should keep prompting and re-executing the loop until "false OR false" is false.
...

If I step through using "abc" as the input (too short and has no digit), it would say too short and get a new password. Then evaluate for digits. Then evaluate the loop again. Right?
Happy Monkey • Nov 22, 2010 3:47 pm
I think yours would return a valid password, but [edit][strike]it won't tell them what's wrong if they enter a short password twice in a row[/strike] it's not as concise as it could be.

[code]
bool passLength(string) // just print error, and return true/false. Don't read a new pw
bool containDigit(string) // just print error, and return true/false. Don't read a new pw

string getPW()
{
string pw = read line;
while (( ! passlength(pw) ) || ( ! containDigit(pw) ))
{
pw = read line;
}
return pw;
}
[/code]
Flint • Nov 22, 2010 3:56 pm
Oh, I see. Put the error message in the function. Well, yes, they always go together.



Thank you, all. For your help here I will send you a singing telegram from a juggling midget hooker on a unicycle, and/or make a modest donation to the Cellar tip jar. My choice.
Flint • Nov 22, 2010 9:13 pm
Still haven't got it quite worked out, but I see that what I turned in has been graded and I got a 100. So... no rush, but I'm still going to keep at this until it works exactly right every time, under every circumstance.
Flint • Nov 23, 2010 1:00 am
Okay, now THIS version works right, every time, under every condition.

#include<iostream>
#include<cstring>
#include<cctype>
using namespace std;

//Function checks the password for length. (a)
bool passLength(char[]);

//Function checks the password for a digit. (b)
bool containDigit(char[]);

int main()
{
const int SIZE = 21;
char password[SIZE];

cout << "Please enter a password: ";
cin.getline(password, SIZE);

while ((!passLength(password)) || (!containDigit(password)))
{
if (!passLength(password))
{
cout << "Passwords must be at least 6 characters long" << endl;
cout << "Please enter a password1: ";
cin.getline(password, SIZE);
(passLength(password)); //(a)
}

if (!containDigit(password))
{
cout << "Passwords must include at least on digit (1-9)" << endl;
cout << "Please enter a password2: ";
cin.getline(password, SIZE);
(containDigit(password)); //(b)
}
}

cout << "Thank you that is a valid password" << endl;


//Keep the window open until Enter key is pressed.
cout << "\nPress Enter to close window..." << endl;
std::cin.get();

return 0;
}

bool passLength(char password[]) //(a)
{
int lengthPass = 6;
int length = strlen(password);

if (lengthPass <= length)
return true;
else return false;
}


bool containDigit(char password[]) //(b)
{
int index = 0;
int length = strlen(password);

for (index = 0; index < length; index++ )
{
if (isdigit(password[index]))
return true;
}
return false;

}


Now, I agree it could be more concise. Since this is the first lesson I had to actually stop and think about, I feel like I want to keep working on it. Keep in mind, I already got a 100 on this. Now, it's just for the principle.
Flint • Nov 23, 2010 1:18 am
This is somewhat better, as far as a more streamlined main function...
#include<iostream>
#include<cstring>
#include<cctype>
using namespace std;

//Function checks the password for length. (a)
bool passLength(char[]);

//Function checks the password for a digit. (b)
bool containDigit(char[]);

const int SIZE = 21;
char password[SIZE];

int main()
{
cout << "Please enter a password: ";
cin.getline(password, SIZE);

while ((!passLength(password)) || (!containDigit(password)))
{
if (!passLength(password))
(passLength(password)); //(a)

if (!containDigit(password))
(containDigit(password)); //(b)
}

cout << "Thank you that is a valid password" << endl;


//Keep the window open until Enter key is pressed.
cout << "\nPress Enter to close window..." << endl;
std::cin.get();

return 0;
}


bool passLength(char password[]) //(a)
{
int lengthPass = 6;
int length = strlen(password);

if (lengthPass <= length)
return true;
else
{
cout << "Passwords must be at least 6 characters long" << endl;
cout << "Please enter a password: ";
cin.getline(password, SIZE);
return false;
}
}

bool containDigit(char password[]) //(b)
{
int index = 0;
int length = strlen(password);

for (index = 0; index < length; index++ )
{
if (isdigit(password[index]))
return true;
}
cout << "Passwords must include at least on digit (1-9)" << endl;
cout << "Please enter a password: ";
cin.getline(password, SIZE);
return false;
}
Happy Monkey • Nov 23, 2010 11:01 am
You are reading new passwords all over the place. What if the password you read in passLength() is good? You return false anyway and ask for a new one at the next step.

You should only do one getline() per loop.
Flint • Nov 23, 2010 12:34 pm
HM wrote:
You are reading new passwords all over the place.
...
You should only do one getline() per loop.


I understand what you're saying, but the program has to do this:

Please enter a password: pass6

Passwords must be at least 6 characters long


Please enter a password: TarrantNW

Passwords must include at least one digit (1-9)


Please enter a password: Tccd03

Thank you that is a valid password


HM wrote:
What if the password you read in passLength() is good? You return false anyway and ask for a new one at the next step.
If the password I read in passLength is good (true for both conditions) then it is not false for containDigit. containDigit only runs on the condition of containDigit being false. If it is true, containDigit is not called, and the while condition of the loop exits to main function.
Happy Monkey • Nov 23, 2010 1:21 pm
I think I was wrong about the bad behavior again; it should work. But it is very complicated. The test functions can return false when the password has been changed to a good one. The structure of the while loop corrects for it, but the behavior of the functions is not what one would expect.

The snippet I posted would give the same behavior, but is much simpler.

This would allow the error reporting to be in the loop, and only calls each test once:
[code]
bool passLength(string) // just return true/false. Don't read a new pw or print error
bool containDigit(string) // just return true/false. Don't read a new pw or print error

string getPW()
{
string password;
bool ok=false;
while ( ! ok )
{
cout << "Please enter a password: ";
cin.getline(password, SIZE);

if (! passlength(password)
{
cout << "Passwords must be at least 6 characters long" << endl;
}
else if ( ! containDigit(password) )
{
cout << "Passwords must include at least on digit (1-9)" << endl;
}
else
{
ok=true;
}
}
return password;
}
[/code]
Flint • Nov 23, 2010 3:50 pm
HM wrote:
The test functions can return false when the password has been changed to a good one.
If it is a good password the function cannot return false.

HM wrote:
The structure of the while loop corrects for it, but the behavior of the functions is not what one would expect.


No, man. The if condition corrects for it by not calling the function unless it is false. The while loop doesn't correct the behavior, the while loop just exits the loop before the next iteration.



In a nutshell, this is how I check for two conditions:
while !(a) or !(b)
{
if !(a)
call (a)

if !(b)
call (b)
}


This will repeat until the conditions are met. It will also exit immediately when the conditions ARE met.
tw • Nov 23, 2010 7:35 pm
Flint;695818 wrote:
while !(a) or !(b)
{
if !(a)
call (a)

if !(b)
call (b)
}


Only reading the summary code: Are (a) and (b) a function or method? Or are each a property?

If (a) or (b) are functions: when a bad user name is entered in
while ( !(a) ....
That causes the while loop to drop to an 'If' condition. Then another
(a) function is executed.

Then the while loop again again executes (a) again:
while ( !(a) or !(b) )
Everytime (a) and (b) are executed - an new entry occurs. IOW what happened in "call (a)" gets replaced by another execution of "while ( !(a) ..."


To work, the code should read something like this:


do
{call (a)
if ((a).result == good)
{call (b)}
}
loop until ( (a).result == good and (b).result == good )


(a).result and (b).result are properties.
call(a) and call(b) are methods.

Summary code many not accurately reflect what your actual code does. But the difference between an executed function call(a) and its resulting property (a).result should be clearer. As I read the original summary code, everytime (a) is executed, a previous user name (good or bad) is erased and a new username is entered.
Flint • Nov 23, 2010 10:20 pm
@tw: (a) and (b) are bool functions. while !(a) does not cause if !(a) to drop. while !(a) OR !(b) simply makes the decision to enter the loop or not.

tw wrote:
Everytime (a) and (b) are executed - an new entry occurs.
Correct. That is what makes this work. The loop continuously evaluates, "falling through" true conditions and "catching" on false conditions. false conditions always prompt for a new password and immediately reevaluate the same condition. The loop continues to evaluate until it is able to "fall through" completely (exit the loop).

Here is the program running:

Please enter a password: a
Passwords must be at least 6 characters long
Please enter a password: abc
Passwords must be at least 6 characters long
Please enter a password: abcdef
Passwords must include at least on digit (1-9)
Please enter a password: 123
Passwords must be at least 6 characters long
Please enter a password: abcdef
Passwords must include at least on digit (1-9)
Please enter a password: a1
Passwords must be at least 6 characters long
Please enter a password: abc123
Thank you that is a valid password

Press Enter to close window...


Here is the code:

[CODE]#include<iostream>
#include<cstring>
#include<cctype>
using namespace std;

//Function checks the password for length. (a)
bool passLength(char[]);

//Function checks the password for a digit. (b)
bool containDigit(char[]);

const int SIZE = 21;
char password[SIZE];

int main()
{
cout << "Please enter a password: ";
cin.getline(password, SIZE);

while ((!passLength(password)) || (!containDigit(password)))
{
if (!passLength(password))
(passLength(password)); //(a)

if (!containDigit(password))
(containDigit(password)); //(b)
}

cout << "Thank you that is a valid password" << endl;


//Keep the window open until Enter key is pressed.
cout << "\nPress Enter to close window..." << endl;
std::cin.get();

return 0;
}

bool passLength(char password[]) //(a)
{
int lengthPass = 6;
int length = strlen(password);

if (lengthPass <= length)
return true;
else
{
cout << "Passwords must be at least 6 characters long" << endl;
cout << "Please enter a password: ";
cin.getline(password, SIZE);
return false;
}
}


bool containDigit(char password[]) //(b)
{
int index = 0;
int length = strlen(password);

for (index = 0; index < length; index++ )
{
if (isdigit(password[index]))
return true;
}
cout << "Passwords must include at least on digit (1-9)" << endl;
cout << "Please enter a password: ";
cin.getline(password, SIZE);
return false;

}[/CODE]
Happy Monkey • Nov 23, 2010 10:28 pm
Flint;695818 wrote:
If it is a good password the function cannot return false.
If the password going in is bad, abd the password entered in the function is good, then the function returns false, even though the password is good.
No, man. The if condition corrects for it by not calling the function unless it is false.
It calls it no matter what. If that first call returns false, it calls the function a second time (third if you count the loop test).

Every time you call if (!a()), you are calling a().

The while loop doesn't correct the behavior, the while loop just exits the loop before the next iteration.
While giving the user two more chances to change the password.
Flint • Nov 23, 2010 10:54 pm
HM wrote:
Every time you call if (!a()), you are calling a().
Perhaps, but this is not the behavior I see while using Visual C++ 2010 Express.

Please enter a password: abc
Passwords must be at least 6 characters long
Please enter a password: abc123
Thank you that is a valid password

Press Enter to close window...


Another example:

Please enter a password: abc
Passwords must be at least 6 characters long
Please enter a password: abcdef
Passwords must include at least on digit (1-9)
Please enter a password: 123
Passwords must be at least 6 characters long
Please enter a password: abcdef
Passwords must include at least on digit (1-9)
Please enter a password: abc123
Thank you that is a valid password

Press Enter to close window...
Flint • Nov 23, 2010 11:51 pm
Happy Monkey;695873 wrote:
If the password going in is bad, abd the password entered in the function is good, then the function returns false, even though the password is good.
I'm interested to know why you think this is; as I cannot conceive of a logic where this makes sense. Aside from the fact that this isn't what happens. I'm just interested to hear your reasoning.
Flint • Nov 24, 2010 12:09 am
Happy Monkey's suggested code from post #15 also works.

Using the else condition to exit the loop, otherwise prompting for the password at the top of the loop. This is more concise.

Please enter a password: abc
Passwords must be at least 6 characters long
Please enter a password: abcdef
Passwords must include at least on digit (1-9)
Please enter a password: 123
Passwords must be at least 6 characters long
Please enter a password: abcdef
Passwords must include at least on digit (1-9)
Please enter a password: abc123
Thank you that is a valid password

Press Enter to close window...


[CODE]#include<iostream>
#include<cstring>
#include<cctype>
using namespace std;

//Function checks the password for length. (a)
bool passLength(char[]);

//Function checks the password for a digit. (b)
bool containDigit(char[]);

const int SIZE = 21;
char password[SIZE];

int main()
{
bool ok=false;
while ( ! ok )
{
cout << "Please enter a password: ";
cin.getline(password, SIZE);

if (! passLength(password))
{
cout << "Passwords must be at least 6 characters long" << endl;
}
else if ( ! containDigit(password) )
{
cout << "Passwords must include at least on digit (1-9)" << endl;
}
else
{
ok=true;
}
}


cout << "Thank you that is a valid password" << endl;


//Keep the window open until Enter key is pressed.
cout << "\nPress Enter to close window..." << endl;
std::cin.get();

return 0;
}

bool passLength(char password[]) //(a)
{
int lengthPass = 6;
int length = strlen(password);

if (lengthPass <= length)
return true;
else
{
return false;
}
}


bool containDigit(char password[]) //(b)
{
int index = 0;
int length = strlen(password);

for (index = 0; index < length; index++ )
{
if (isdigit(password[index]))
return true;
}
return false;

}[/CODE]
Perry Winkle • Nov 24, 2010 12:14 am
Flint;695877 wrote:
Perhaps, but this is not the behavior I see while using Visual C++ 2010 Express.


Maybe you're getting confused output because you're not flushing the output stream (i.e., flush(cout);). Another, but less likely, answer might be that the function call is getting optimized away.

Either way you should at least store the values of a and b each time through the loop.
Flint • Nov 24, 2010 12:21 am
The question is whether evaluating a bool function (for true or false) is the same as "calling" the function and executing the internal code of the function which is conditional on it being true or false. And the answer I am getting is that this is not the same, because my program runs and works.

This code only "calls" passLength IF passLength is false.
[CODE]if (!passLength(password))
(passLength(password));[/CODE]
If it is false, this gives it another chance to be true. Repeat.

Unlike the solutions graciously suggested by Pete Zicato and Happy Monkey, in my code I do not require a superfluous bool variable. I use the bool function to evaluate itself. Maybe this is "wrong" but it works.
Happy Monkey • Nov 24, 2010 1:41 am
Flint;695891 wrote:
I'm interested to know why you think this is; as I cannot conceive of a logic where this makes sense. Aside from the fact that this isn't what happens. I'm just interested to hear your reasoning.


Say you call containDigit("abc")
[code]
int index = 0;
int length = strlen(password);

for (index = 0; index < length; index++ )
{
if (isdigit(password[index]))
return true;
}
[/code]
It gets through these steps, and gets here:
[code]
cout << "Passwords must include at least on digit (1-9)" << endl;
cout << "Please enter a password: ";
cin.getline(password, SIZE);
[/code]
The user enters "abc1".
And then:
[code]
return false;
[/code]
The password is now "abc1", and containDigit() returned false.

You don't see the problem in your execution because your while loop corrects for the behavior of the test functions. But if you tested the functions individually, you would see it.

Flint;695897 wrote:

This code only "calls" passLength IF passLength is false.

What exactly do you mean by "IF passLength is false"? A function can only be false if it is called and executed.

Unlike the solutions graciously suggested by Pete Zicato and Happy Monkey, in my code I do not require a superfluous bool variable. I use the bool function to evaluate itself. Maybe this is "wrong" but it works.

My first suggestion also doesn't need the bool, without the side effects in the test functions.
Flint • Nov 24, 2010 10:05 am
When I call containDigit("abc")...

Please enter a password: abcdef
Passwords must include at least on digit (1-9)
Please enter a password: abc
Passwords must be at least 6 characters long
Please enter a password: abc123
Thank you that is a valid password

Press Enter to close window...


If a condition is met, he loop "toggles" to the next false condition. If you DON'T meet the condition, you are stuck at that point until it is met (calling that same bool function with your input). Once you enter the correct input, the loop falls through to evaluate the next condition. Repeat. No matter what you input into my program, you can't make it break, and you can't make it behave wrongly. It works with 100% accuracy.

Again, the while function simply decides whether to enter the loop or not at each iteration.

A function can only be false if it is called and executed.
That seems to make sense, but running my program suggests otherwise.

I find it hard to argue with the fact that what I've done works. Because it works.

You don't see the problem in your execution because your while loop corrects for the behavior of the test functions. But if you tested the functions individually, you would see it.
I am interested to test this, but not right now, as I am about to leave to go to our cabin in the country where we have no internet and no cell phone service! Thanks for your thoughts and conversation on this--I am new to this and it really helps me to bounce ideas off of people such as yourself that I trust are logical. :::checking out:::
Perry Winkle • Nov 24, 2010 2:43 pm
Flint;695936 wrote:

I find it hard to argue with the fact that what I've done works. Because it works.


Your solution is perfectly acceptable for a classroom assignment. But you might get your ass kicked in a code review for settling for "it works."

In the real world, you want functions to have as few side-effects as possible. Ideally, a function would have no side-effect other than its return value. Some languages even ENFORCE this restriction.

Your solution depends on side effects. This makes it harder to reason about how and why it works. Happy Monkey's does not depend on side effects, and is easier to grok.

(I hope this post doesn't come off as critical. I'm just trying to add a little more to think about.)
fo0hzy • Nov 24, 2010 9:17 pm
Perry Winkle;695969 wrote:
Your solution is perfectly acceptable for a classroom assignment. But you might get your ass kicked in a code review for settling for "it works."

In the real world, you want functions to have as few side-effects as possible. Ideally, a function would have no side-effect other than its return value. Some languages even ENFORCE this restriction.

Your solution depends on side effects. This makes it harder to reason about how and why it works. Happy Monkey's does not depend on side effects, and is easier to grok.

(I hope this post doesn't come off as critical. I'm just trying to add a little more to think about.)


Nerds.
Flint • Nov 28, 2010 8:47 pm
Perry Winkle;695969 wrote:
Your solution depends on side effects.
This is, of course, semantics, but no, it doesn't.

I had a solution to design: how to test for two conditions.

I figured, while either one is false, correct that one.

while !(a) or !(b)
{
if !(a)
call (a)

if !(b)
call (b)
}



What could be simpler, or easier to understand?

Let's say I am leaving the house. Did I lock the door (a)? Did I turn off the lights (b)? While either one is false: if (a) is false I lock the door, if (b) is false I turn off the lights. When neither one is false I am done. This is common sense.

I understand that if I were doing this in the "real world" things would be more involved and this might cease to be feasible for a variety of reasons that I have yet to consider, but in essence, this is my conception of how loops work and what they are supposed to (are DESIGNED to) do.

What I don't understand is why you guys find what I did confusing. I used regular, human logic.

In the real world, you want functions to have as few side-effects as possible. Ideally, a function would have no side-effect other than its return value. Some languages even ENFORCE this restriction.
What are the undesirable "side effects" of my functions??? My functions didn't do anything but return a value until I moved some parts of main function into them so you guys could understand the elegant simplicity of my while/if/if loop.

I could put it back this way:

[CODE]while ((!passLength(password)) || (!containDigit(password)))
{
if (!passLength(password))
{
cout << "Passwords must be at least 6 characters long" << endl;
cout << "Please enter a password1: ";
cin.getline(password, SIZE);
(passLength(password)); //(a)
}

if (!containDigit(password))
{
cout << "Passwords must include at least on digit (1-9)" << endl;
cout << "Please enter a password2: ";
cin.getline(password, SIZE);
(containDigit(password)); //(b)
}
}[/CODE]

Does that help you to understand that I designed it this way on purpose? This is not accidental, there are no "side effects" ...
Happy Monkey • Nov 29, 2010 11:59 am
Flint;696889 wrote:
This is, of course, semantics, but no, it doesn't.

I had a solution to design: how to test for two conditions.

I figured, while either one is false, correct that one.


What could be simpler, or easier to understand?


while !(a) or !(b)
{
if !(a)
call (a)

if !(b)
call (b)
}


You could remove both if statements altogether. With the side effects that a() and b() have, this code would be equivalent:

while !(a) or !(b)
{
}


This is because !(a) is actually calling a(). If the test fails, then the password is changed (the side effect in question). This loop will run until the password makes it through both tests without being changed.


What I don't understand is why you guys find what I did confusing. I used regular, human logic.
A big one is that you seem to think that the a's are different in:
if (!a)
call a()
They are the same. Whatever is done in one will be done in the other.
What are the undesirable "side effects" of my functions??? My functions didn't do anything but return a value until I moved some parts of main function into them so you guys could understand the elegant simplicity of my while/if/if loop.

I could put it back this way:

[code]while ((!passLength(password)) || (!containDigit(password)))
{
if (!passLength(password))
{
cout << "Passwords must be at least 6 characters long" << endl;
cout << "Please enter a password1: ";
cin.getline(password, SIZE);
[strike](passLength(password)); //(a)[/strike]
}

if (!containDigit(password))
{
cout << "Passwords must include at least on digit (1-9)" << endl;
cout << "Please enter a password2: ";
cin.getline(password, SIZE);
[strike](containDigit(password)); //(b)[/strike]
}
}[/code]

Does that help you to understand that I designed it this way on purpose? This is not accidental, there are no "side effects" ...

(assuming there is no longer a getline in the tests, the lines I crossed out can be removed)
That is completely different. The tests no longer can change the password. That is logically a good program, though it could be more efficient.

Moving the parts of main() into the tests did not result in an equivalent program. You could not with this programn (as I did above with the other one) remove the entire contents of the while loop and have an equivalent program.
Flint • Nov 29, 2010 1:52 pm
This is because !(a) is actually calling a().


No. It isn't. It is crucial for you to realize that this is where you are wrong.

!(a) where (a) is a bool function evaluates true or false, it doesn't literally execute the function.



Really, it doesn't. It doesn't do that.



Really.
Happy Monkey • Nov 29, 2010 2:56 pm
You are wrong. The 'true' or 'false' that a() evaluates to is the one that is returned in the body of the function as it executes. I don't know where you think that value comes from if it doesn't come from the execution of the function.

Try this:

Add a second parameter to a() and b(), and pass in a unique value to each call. At the beginning of a() and b(), print out that value.


bool a(pw, x)
{
cout << "a " << pw << " " << x << endl;
...
}

bool b(pw, x)
{
cout << "b " << pw << " " << x << endl;
...
}

while !(a(pw,1)) or !(b(pw,2))
{
if !(a(pw,3))
call (a(pw,4))

if !(b(pw,5))
call (b(pw,6))
}


If you keep entering short, numberless passwords then you will see all six.
Flint • Nov 29, 2010 3:57 pm
Everything that you've said was supposed to happen (posts #8, 13, 15, 19, 25) doesn't happen. I don't see how showing you another example that doesn't happen will be more convincing than the overwhelming evidence I've already presented.
Happy Monkey • Nov 29, 2010 6:51 pm
It will happen.

I withdrew my predictions from 8 and 13 already.

I don't think you've tested whether the things I've said were supposed to happen in 15, 19, and 25 are happening. They wouldn't affect what you see in your normal execution, just what is happening behind the scenes. As I said, the while loop is correcting for the strange behavior of the functions, and it seems to me that all of the overwhelming evidence you have presented includes the while loop.

If you test the functions alone, not in a while loop, you can see the side effects:

main()
{
cin.getline(pw)
if (a(pw))
cout << "a returned true, pw is now " << pw << endl;
else
cout << "a returned false, pw is now " << pw << endl;
}

If you enter a bad password, it will ask for another. If you enter another one, it will return false, even if the second one was good.