The following code generates different characters based on choices taken by the user previously using a bool function. The user can choose whether or not to have some of the characters, such as "numbers" or "Uppercase characters".
The issue I'm having is that after I've implemented a switch/case system to fully randomize which character goes first, the choices aren't respected anymore.
Per example, the user can choose numbers off, yet sometimes numbers will still show up in the sequence. This does not occur with the switch taken off for randomization purposes (which keeps the sequence to Lowercase+Uppercase+Symbols+Numbers).
Should I be using if/else here, or is something else most likely wrong with the rest of the code?
int randomCharacter_cases;
for(int i=0; i<100; i++)
{
// If no appropriate option was selected, then the user will go back to selection:
if(StrongPass==0 && lowercase==0 && Uppercase==0 && numbers==0 && symbols==0)
{
// CODE
}
// This selects the order of each character:
randomCharacter_cases=rand()%4+1;
switch(randomCharacter_cases)
{
// Lowercase characters;
case 1:
{
if(StrongPass==1 || lowercase==1)
{
keeper.push_back((char)(rand()%(122-97+1)+97));
}
break;
}
// Uppercase characters;
case 2:
{
if(StrongPass==1 || Uppercase==1)
{
keeper.push_back((char)(rand()%(90-65+1)+65));
}
break;
}
// Symbols;
case 3:
{
if(StrongPass==1 || symbols==1)
{
keeper.push_back((char)(rand()%(64-33+1)+33));
}
break;
}
// Numbers;
case 4:
{
if(StrongPass==1 || numbers==1)
{
keeper.push_back((char)(rand()%(57-48+1)+48));
}
break;
}
}
}
EDIT: StrongPass, in this particular piece of code, is done in the case where the user doesn't wish to choose what characters he doesn't generate (for example, you may choose any of the four char. types, or you may simply say that you want an automatically generated password, which uses all four types of characters).
This is the function used to determine each individual usage:
bool yesno()
{
string inp;
cin>>inp;
if(!(inp=="Y" || inp=="y" || inp=="N" || inp=="n"))
{
cout<<"Y or N:";
yesno();
}
if(inp=="Y" || inp=="y")
return 1;
else
return 0;
}
EDIT: Usage example:
// Choices we take for each password option:
bool StrongPass,lowercase,Uppercase,symbols,numbers;
// Function for generating random numbers:
srand (time(NULL));
// Default strong options, for easy use:
cout<<"Would you like an automatic S.T.R.O.N.G. password?: ";
StrongPass=yesno();
// If you'd like a more advanced password:
if(StrongPass==0)
{
cout<<"Length of the password?: ";
cin>>length;
cout<<"Length of the password?: "<<length<<"\n";
cout<<"Include lowercase characters?: ";
lowercase=yesno();
cout<<"Include uppercase characters?: ";
Uppercase=yesno();
cout<<"Include symbols?: ";
symbols=yesno();
cout<<"Include numbers?: ";
numbers=yesno();
}
// The password itself is generated here:
int randomCharacter_cases;
for(int i=0; i<100; i++)
{
// This selects the order of each character:
randomCharacter_cases=rand()%4+1;
switch(randomCharacter_cases)
{
// Lowercase characters;
case 1:
{
if(StrongPass==1 || lowercase==1)
{
keeper.push_back((char)(rand()%(122-97+1)+97));
}
break;
}
// Uppercase characters;
case 2:
{
if(StrongPass==1 || Uppercase==1)
{
keeper.push_back((char)(rand()%(90-65+1)+65));
}
break;
}
// Symbols;
case 3:
{
if(StrongPass==1 || symbols==1)
{
keeper.push_back((char)(rand()%(64-33+1)+33));
}
break;
}
// Numbers;
case 4:
{
if(StrongPass==1 || numbers==1)
{
keeper.push_back((char)(rand()%(57-48+1)+48));
}
break;
}
}
}
Per example, the user can choose numbers off, yet sometimes numbers will still show up in the sequence.
Your symbols random generation includes numbers (48...57), so even if you switch numbers off symbols may produce numbers
To answer the question, "Should I be using if/else here" - Sure. It is perfectly acceptable to use a if/else statement within a switch case statement.
The reason you are getting numbers is because either StrongPass or numbers is equal to one. Since you haven't provided where/how/ you are assigning values to this, the best advice we can give you is as follows:
If you don't want numbers to appear, ensure that both StrongPass AND numbers is equal to 0.
[EDIT]
You're input selection function is broken. You have a recursive call that you are no longer catching the value of. Not sure how you are USING this function, though.
If the first call fails (user doesn't select valid input), the recursive call's return value IS NOT CAUGHT. The original function returns 0 no matter what. Even if the recursive call was a "successful" input.
Related
The following snippet is from an inventory system I'm working on. I keep on running into scenarios where I fell I should be able to simple run a for loop, but am stymied by the fact that in different cases I'm using different vectors/variables/etc. I run into this problem just about any time I need to work with a variable or object who's name won't be known at run-time. In this particular situation, case 1: is exactly the same as case 2: except that the vector tankInventory[] would be dpsInventory[] in case 2:
I feel I'm doing something fundamentally backwards, but I'm not clear on how to reorient my thinking about this. Any advice?
case 1:
//loop through the inventory...
for (int i = 0; i < 6; i++)
{
//looking for an empty spot
if (tankInventory[i] == -1)
{
//add the item...
tankInventory[i] = { item };
//decrement the number of items being added
number--;
//and stop the loop if you're out of items to add
if (!number)
break;
}
}
//if there are no more items to add, break;
if (!number)
break;
//but if there are more...
else
{
//switch to main inventory...
character = 0;
//and return to the top
goto returnPoint;
}
Use a function.
Just extract the common logic out into a function, and take as parameters whatever can change.
Also, it seems like you're using goto and breaking out from the switch instead of doing a loop. I'd do something like do {} while (number) or while (number) {}, depending on what you need. This way it's much easier to use a function.
You're very likely on the right track, this is how we build up the abstractions. A simple way is to define a lambda:
// you might refine the captures
auto processInventory = [&](auto& inventoryToProcess) {
//loop through the inventory...
for (int i = 0; i < 6; i++)
{
//looking for an empty spot
if (inventoryToProcess[i] == -1)
{
//add the item...
inventoryToProcess[i] = { item };
//decrement the number of items being added
number--;
//and stop the loop if you're out of items to add
if (!number)
break;
}
}
//if there are no more items to add, break;
if (!number)
break;
//but if there are more...
else
{
//switch to main inventory...
character = 0;
//and return to the top
goto returnPoint;
}}
};
switch(condition) {
case 1:
processInventory(tankInventory);
break;
case 2:
processInventory(dpsInventory);
}
if(command[i]=='H' or command[i]=='h' or command[i]=='C' or command[i]=='c'){
do something;
}
Once the logic flow goes inside this if-statement, I want to know what exactly command[i] was. Surely I can make individual comparisons again in the inside block and find out, but is there a more elegant way of knowing, say, the index of the condition that was satisfied?
If you use
if((myC=command[i]) =='H' ||
(myC=command[i]) =='h' ||
(myC=command[i]) =='C' ||
(myC=command[i]) =='c')
then the value of the successful expression will end up in myC, because evaluation in a chain of "or"s stops at the first true subexpression.
If you go one step further you can get a number value identifying the subexpression by index.
if(((myC=1), command[i]) =='H' ||
((myC=2), command[i]) =='h' ||
((myC=3), command[i]) =='C' ||
((myC=4), command[i]) =='c')
Same concept, the first successful subexpüression is the last to be evaluated and the , operator ensures that only the second part gets used for the comparison.
Another option is to assign a value. You could use switch, an if..else tower, or a function with return statements. Here is a version with function:
int classify( char command )
{
switch( command )
{
case 'H': return 1;
case 'h': return 2;
case 'C': return 3;
case 'c': return 4;
default : return 0;
}
}
void func(void)
{
int result = classify( command[i] );
if ( result )
{
// use result value here as appropriate
}
}
It would also be possible, in fact preferable, to use an enumerator instead of magic numbers.
Just do this -
if(command[i]=='H' or command[i]=='h' or command[i]=='C' or command[i]=='c'){
print command[i]; //use whatever command is appropriate for printing
do something;
}
This question already has answers here:
Function with missing return value, behavior at runtime
(4 answers)
Closed 5 years ago.
I was helping a friend with one of his C++ assignments and we found the following code snippet would throw exceptions in MSVC, but when compiling with G++, the exact same code would work fine. The exceptions were return because this function called getValue() wasn't returning anything.
string getValue(int value) {
ostringstream convert;
string rtnValue;
switch (value) {
case 11:
{
rtnValue = "J";
break;
}
case 12:
{
rtnValue = "Q";
break;
}
case 13:
{
rtnValue = "K";
break;
}
case 14:
{
rtnValue = "A";
break;
}
default:
{
//
// if the value is a a number, we assume it is 2..10
//
convert << value; // use a stream to convert the number
rtnValue = convert.str(); // into a string
if (value < 2 || value > 10)
{
rtnValue = "ERROR" + rtnValue + "ERROR";
}
}
return rtnValue;
}
}
This program turns integers into strings. For the numbers 11-14 it uses switch statement (I know this isn't the best implementation but it's an introductory class).
We found that this could easily be solved by adding another return statement at the end.
string getValue(int value) {
ostringstream convert;
string rtnValue;
switch (value) {
case 11:
{
rtnValue = "J";
break;
}
case 12:
{
rtnValue = "Q";
break;
}
case 13:
{
rtnValue = "K";
break;
}
case 14:
{
rtnValue = "A";
break;
}
default:
{
//
// if the value is a a number, we assume it is 2..10
//
convert << value; // use a stream to convert the number
rtnValue = convert.str(); // into a string
if (value < 2 || value > 10)
{
rtnValue = "ERROR" + rtnValue + "ERROR";
}
}
return rtnValue;
}
return rtnValue;
}
And this now fixes it for MSVC (and I assume G++ if I checked).
Why did that fix work? Does MSVC and G++ treat parentheses differently with respect to switch statements?
In the first example, the return rtnValue is in the wrong place, and will only ever work when the default case is hit.
In the second example, you have added the return rtnValue in the correct place (and the other can be safely removed).
As to why it worked on GCC and not on MSVC, I don't know, without the return being in the correct place, it's not valid C++ (not all paths have a return value), so you should have got a compilation error on any C++ compiler.
I would suggest the problem is actually the way the braces {} are being used, and your friend thought that the closing brace of the default case, actually closed the switch statement, but it doesn't.
Also, there is no need to have braces on any of the case statements. Braces CAN be used in this way to introduce scoping (for example, temporary variables for a particular case), but in your example, just leads to confusion.
this is the problem
default:
{
convert << value; // use a stream to convert the number
rtnValue = convert.str(); // into a string
if (value < 2 || value > 10)
{
rtnValue = "ERROR" + rtnValue + "ERROR";
}
}
return rtnValue;
}
your return statement is in the wrong block, i.e , switch block.
what happens is that, when a case is satisfied it breaks out of the switch that is why it didn't return anything (because it is now out of switch statement).
In order to fix it you have to move your return statement to out of the switch statement to the end of the function.
This correction will we equivalent to the second code that you have provided.
But even in the second code remove the inner return statement.
Return value
Your return statement in the first sample applies to the default case only since the execution of the switch block ends with a break statement in every other case.
In a non-default case, you leave the return value of your function uninitialized. MSVC does warn about that while debugging (see https://learn.microsoft.com/en-us/visualstudio/debugger/how-to-use-native-run-time-checks for details) but GCC does not. This problem might be detected during compile time but you cannot rely on that.
The return statement added to the second sample is correct. You can remove the original one which becomes superfluous.
Braces
Notice that the braces inside the switch block are not necessary and introduce confusion here. They would be only useful if you created a local variable just to be used in a single case. Anyway, the braces should be indented more than the braces of the switch block. This part
}
return rtnValue;
}
demonstrates the misleading indentation clearly. The indentation used in the second example is one of the good solutions to this problem.
I am doing some sample programs in C++. I have 100,000 single column data in a Text File. I loaded that all data into a std::vector. Now I need to check the first character of every data whether it is '#' or '%' or '$'. The data are in Sorted manner in the way of '#','$','%'. I can do programming for this like Below.
for ( i = 0; i < myArray.size(); i++)
{
if(mrarray[i][0]=='#')
{
// do some process for '#' values
}
else if(mrarray[i][0]=='$')
{
// do some process for '$' values
}
else if(mrarray[i][0]=='%')
{
// do some process for '%' values
}
}
My Question is " Is it a best way to do this ? . Is there any other way to do this program with better efficiency ? " ???
That's about as efficient as it gets, the only thing that will make it a bit faster is using a switch statement.
for ( i = 0; i < myArray.size(); i++)
{
switch(myArray[i][0]){
case '#':
// Do stuff
break;
case '$':
// Do stuff
break;
case '%':
// Do stuff
break;
}
}
I'm also assuming you're only doing this once. If you're doing it more than once with the same data, then it can be made more efficient by sorting it. If that's the case, let me know and I will update my answer.
As state in why-is-processing-a-sorted-array-faster-than-an-unsorted-array, It may be more efficient to sort your lines first (based on first character) and then process your vector.
The switch statement proposed by David would be my choice.
But as alternative, you may try an array of function pointer, something like:
using my_function_pointer = void (*)(const std::string&/*, other required stuff*/);
const my_function_pointer funs[256] = { dummy_f, dummy_f, .., f_charp, f_dollar, f_mod, dummy_f, ..};
for ( i = 0; i < myArray.size(); i++) {
funs[myArray[i][0]](myArray[i] /*, other required stuff*/);
}
And anyway, you need to benchmark your change as for any optimization.
My code is:
#include<stdio.h>
void main(void)
{
float timeLeavingTP;
int transitNumber;
float transitTime;
printf("Please enter the time leaving TP.\n");
scanf_s("%f",&timeLeavingTP);
printf("Please enter bus number.\n");
scanf_s("%d",&transitNumber);
if(timeLeavingTP==1.00)
{
if(transitNumber==27)
{
transitTime=1.56;
}
else if(transitNumber==8);
{
transitTime=1.39;
}
}
if(timeLeavingTP==6.30)
{
if(transitNumber==27)
{
transitTime=7.32;
}
else if(transitNumber==8)
{
transitTime=7.29;
}
printf("The time reached home is %f\n",transitTime);
}
}
After debugging i got
Please enter the time leaving TP
1.00
Please enter bus number
27
Please enter to continue...
My question is How do i adjust the program to make it look like the one below instead. What kind of error did i commit?
Please enter the time leaving TP
1.00
Please enter bus number
27
The time reached home is 1.56
Thanks for the help in advance!
Hi guys after including == i still got the same for my debugging? Is there something else that i did wrong?
Part 1: = vs ==
Note that:
if(timeLeavingTP=1.00)
Does not do what you expect. It assigns timeLeavingTP with 1.00.
You probably want:
if(timeLeavingTP==1.00)
Additionally, note that this error occurs 6 times in your program.
Part 2: comparing floating point numbers
Your code might work in this case, but I'm not 100% sure if it will or not. It's often difficult to directly compare 2 floating point numbers, because of the inaccuracy of storing them (for example, 0.1 is usually not representable in floating point).
Most people solve this problem in one of a few ways:
Test a range around the number.
Convert to some fixes width format. Perhaps you could store the number as an integer, knowing that it's representation is actually 0.01 * the stored number.
In this case, you could actually just store the information as strings, and compare those.
Part 3: conditionals
To write a proper conditional, it should look like:
if (condition) {
...
} else if (condition) {
...
} else if (condition) {
...
} else {
...
}
You can certainly nest conditionals as well:
if (condition) {
if (condition) {
...
} else {
...
}
} else if (condition) {
...
}
Your code, for example, messes this up when you do:
}
else(transitNumber=8);
{
transitTime=1.39;
}
Note that the else statement does not accept a conditional after it.
Part 4: excessive semicolons
Additionally, note that after the else and if statements there are no semicolons. The semicolons only appear within the braces. So this statement:
if(timeLeavingTP=6.30);
While semantically valid, does not do what you expect. You actually want to remove that semicolon.
if(timeLeavingTP == 1.00)
{
if(transitNumber == 27)
{
transitTime=1.56;
}
else if(transitNumber == 8)
{
transitTime=1.39;
}
}
else if(timeLeavingTP == 6.30)
{
if(transitNumber == 27)
{
transitTime == 7.32;
}
if(transitNumber ==8)
{
transitTime=7.29;
}
}
printf("The time reached home is %f\n",transitTime);
}
if(transitNumber=27)
{
transitTime=1.56;
}
else(transitNumber=8);
{
transitTime=1.39; //this line is executed all the time
}
This code is completly invalid!
First, you do not compare anything... transitNumber = 27 is an assignment.
Second else(transitNumber=8); again this is an assignment and it should be else if(...). Also ; at the and means that transitTime = 1.39(inside bracket) will always happen, even if transitNumber != 8
Change
if(timeLeavingTP=1.00)
to
if(timeLeavingTP==1.00)
so that you can compare timeLeavingTP correctly.