C++ - fgets() ignores subsequent inputs if Enter is pressed - c++

I am trying to create an emulator for something, and in the main loop for the processor I wanted to implement a simple way to step the CPU one loop at a time (prompted by pressing Enter each loop) so I can see what instructions are being executed each step. In addition, it allows you to enter a number instead of just Enter to change the default step amount from 1 to something else (so it will skip x number of cycles and then return to 1 at a time afterwards.
The issue is that it works fine when I enter a number (skip that amount of cycles and then prompts me again each cycle), but when I just press Enter rather than entering a number I want it to default to 1 step. Instead, pressing Enter causes it to just run through the whole program without ever prompting me again. How do I make Enter == 1?
void CPU_loop()
{
...
static int step = 1;
char cmd[10];
if(step == 1)
{
if(fgets(cmd, 10, stdin) != NULL) // If you entered something other than Enter; doesn't work
{
step = std::atoi(cmd); // Set step amount to whatever you entered
}
}
else
{
--step;
}
...
}

When you press enter directly, it does not default to 1, but instead you are passing the string "\n" to std::atoi(), std::atoi() cannot be used to perform sanity check on it's input, you can use a different function for that like std::strtol() or, you can simply add
if (step == 0)
step = 1;
because when, std::atoi() takes a "\n" as input, it returns 0. Read the documentation to further understand it.
Quoting the documentation
Integer value corresponding to the contents of str on success. If the converted value falls out of range of corresponding return type, the return value is undefined. ​If no conversion can be performed, 0​ is returned.
One more thing, you could do it the c++ way using streams for input to avoid all this.

You could do:
if (fgets(cmd, 10, stdin) != NULL)
{
if (cmd[0] == '\n'){
step = 1;
}
else{
step = std::atoi(cmd); // Set step amount to whatever you entered
}
}

Related

How does this bool variable work exactly?

I am new to programming, so please forgive me if my question is too basic.
For the following code, I don't know how exactly the bool variable "more" works. It says that while loop will do the content of the loop whenever the "more" is true, but
how does the computer know that the more is true? Is it smart enough to know that "more" literally means when the user inputs additional value through keyboard? Also, does it know that a negative input is not considered "more" but only positive input is considered "more"?
Inside the while loop, it says that the more is false when the input value is 0. However, it does not logically make sense that more is false when it already goes through the while loop, which only runs when the more is true!
I learned that we will get an infinite loop when "while is always true". It seems like the while loop will always be true since more = true.
Please help me out with this question!!
vector<double> salaries;
cout << "Please enter salaries, 0 to quit:" << endl;
bool more = true;
while (more)
{
double s;
cin >> s;
if (s == 0)
more = false;
else
salaries.push_back(s);
}
(1): The computer (or the compiler) is not smart enough to connect more to a literal meaning.
(2): more can be changed inside the loop, which is what happens when you enter 0. After changing more to false, the condition in while (more) is re-evaluated. As more is now false, the loop is exited.
(3): No, more is not always true, see (2).
Ok, so point by point:
1) The compiler knows that more is true because on line 3 it says:
bool more = true;
This creates the bool more and gives it the value true.
2) more is then set to false if s is equal to zero. Although more is true at the beginning of the loop there is nothing to say it can't be changed within the loop (this is called mutability).
3) Because more gets set to false within the loop, the loop will stop executing. This will only happen if someone enters 0 for the input. If this doesn't happen you are correct, the loop will get run forever.
This is a fairly common while loop construct which allows an arbitrary number of values to be added to the vector salaries. In your question you hint that positive numbers should not be allowed, it is worth noting that there is nothing in the code enforcing this. Perhaps it would be better to change the line:
if (s == 0)
to:
if (s <= 0.0)
This way the loop will stop executing if a 0 value is entered or if a negative value is entered.
In your code snippet variable more is explicitly set two times: before the loop and inside the loop if s is equal to zero
bool more = true;
while (more)
{
//...
if (s == 0)
more = false;
//..
}
Thus when more will be set to false within the body of the loop
if (s == 0)
more = false;
the loop stops its iterations because the condition in while will not true
while (more)
Take into account that the condition above is equivalent to
while (more == true)
Though there is no great sense to write such a way because variable more is already a boolean expression.
Also take into account that according to the C++ Standard
4.12 Boolean conversions
1 A prvalue of arithmetic, unscoped enumeration, pointer, or pointer
to member type can be converted to a prvalue of type bool. A zero
value, null pointer value, or null member pointer value is converted
to false; any other value is converted to true. For
direct-initialization (8.5), a prvalue of type std::nullptr_t can be
converted to a prvalue of type bool; the resulting value is false.
You could rewrite your code snippet in other way without using variable more. For example
vector<double> salaries;
cout << "Please enter salaries, 0 to quit:" << endl;
double s;
while ( cin >> s && s != 0 )
{
salaries.push_back(s);
}
Or the condition in while could be written even like
while ( cin >> s && s )
So according to the quote of the C++ Standard if s is not equal to 0 then it is converted to bool true. As for expression cin >> s then class std::istream has explicit conversion operator that converts std::cin to boolean value if the stream is not in erroneous state.
The variable more is explicitly set to true before the loop is entered. In the loop's body, if more is set false, nothing else is executed in the loop's body afterwards. The flow of execution goes again to the beginning of the loop, where the loop's condition is evaluated. As more is false, the loop's body is not executed again.
No, the computer(compiler, more appropriate) does not know the intent behind your coding, specifics behind your variables and functions, It only working on set of instructions, which need to be syntactically correct.
in while(more) it's job is to run the loop for as long as more boolean is true and skip to next instruction when false.
while(condition),here condition is checked once for every iteration, and during the iteration, the compiler does not bother to check and skip the rest of the code upon more being false. the condition is checked only before beginning an iteration.
Absolutely, just assume while(true){set of instructions;} the condition is always true and therefore the block of code is always executed and we call this an Infinite Loop.
Well, it seems that you don't really understand the way your compiler works.
First of all, your computer is not smart or dumb, it's merely a machine and interprets whatever you give them to. So, it all comes to the way you have programmed your program. Having said that we move on:
The
while(condition) {
commands;
}
loop works basically as follows:
It checks the condition whatever that might be at the time it your
program flow enters the loop.
It continues to execute whatever commands are if and only if the previous checked condition was true.
If it wasn't true then your programs continues to execute whatever command follow your while loop.
When the execution of commands have finished it goes again to check the condition in while.
Again, if it's true it carries on with commands.
If not, then again it continues to the following your while commands.
So, to sum up, your compiler, computer or your digital friend does not check for logical flows in how you name your variables, if false does not make sense, etc. It merely checks if condition is true. That's it.
Finally an infinite loop will occur if the initial condition was true when entering the loop and when exiting the loop always continues to be true (not does not change inside the loop because it could change and also get a true values when exiting the loop).
You have some misunderstandings with how things work in C++. You can think of your program as an abstract machine. Each variable is a storage location that maintains some state. The more variable is an example of this state. You can think of the variable as a location in memory that maintains the value that you give it. The total program state is allowed to change throughout the duration of the runtime of the program.
Each assignment (the = operator) sets the state of the variable to the value on the right hand side of the assignment.
So when you say:
bool more = true;
The storage location named more is set to the value true. The storage location will remain true until you assign a new value to it.
Note that in C++ statements are evaluated sequentially. Since the values of the variables may change over time, the order of the statements matters.
Later on when you say:
while (more)
{
// ...
}
The first time that more is evaluated, it is true, but again, since more is a variable, that value may change over time.
Once you are inside the while loop, the more variable is conditionally assigned false when the variable s is equal to 0. Notice that the == is truly an equality check unlike the = operator.
if (s == 0)
more = false;
Note that you should be aware that s is of type double and the literal 0 is of type int. Fortunately for you, this will work since C++ will automatically promote the int to a double type to do the equality comparison. However, it probably makes since to use a literal 0.0 to be clear that you expect for s to be a double.
Since the value of s is dependent on the value that is read from cin, the equality condition will sometimes be true and sometimes false depending on what is entered by the user. But if more is assigned false, it when then cause the while loop to terminate on its next iteration. In other words, when you reach the close brace } the program will repeat back to the beginning of the while and try to re-evaluate more, at that point, when more is false the while loop will end.
vector<double> salaries;
cout << "Please enter salaries, 0 to quit:" << endl;
bool more = true;
while (more)
{
double s;
cin >> s;
if (s == 0)
more = false;
else
salaries.push_back(s);
}
A while loop will iterate over and over until the condition between the ()is not met. When you start the cycle you start with bool more = true; That way you're telling the while(more) loop to keep iterating while more is true. Inside the code you ask for input with cin >> s; and if the input is 0 the variable more will change to false, it will iterate again and since while(more) is awaiting for the morevariable to be true the condition won't be true and the cycle will end. If you input other value than 0 the cycle will store that value into the vector<double> salaries vector.
One way for getting the values that were stored in the vector is:
for(int i = 0; i<salaries.size(); i++){
cout<< salaries[i] << endl;
}
In which case you're telling the compiler to iterate with a variable called i starting from the value 0 until the value of i is < than the value of salaries.size(), for each iteration, i will increase and when the condition is no longer met, the cycle will end.
As a recomendation, use the std namespace for your types, it will be of help in future code to avoid bringing everything from the std namespace into your code.
std::vector<double> salaries;
std::cout << "Please enter salaries, 0 to quit:" << std::endl;
bool more = true;
while (more)
{
double s;
std::cin >> s;
if (s == 0)
more = false;
else
salaries.push_back(s);
}
and
for(int i = 0; i<salaries.size(); i++){
std::cout<< salaries[i] << std::endl;
}

While function doesn't work like I want it to

Had a new problem with the while function. As easy as it sounds, I still can't wrap my head around it.
Like my last program, this one closes unexpectedly after the correct and wrong messages.
I want this to loop after entering a number, so that the program won't stop.
Thanks for the help, if any.
#include <iostream>
using namespace std;
int main()
{
int X = 0; //setting the first variable
int num; //setting the second
while (X == 0) //this should happen whenever X is equal to 0
{
cout << "Type a number bigger than 3. "; //output
X++; //This should increase X, so that the next while function can happen
}
while (X == 1) //again, since I increased x by one, (0+1=1 obviously) this should happen
{
cin >> num; //standard input
if (num > 3) //if function: if num is bigger than three, then this should happen
{
cout << "Correct! Try again!" <<endl; //output
X--; //Here I'm decreasing x by one, since it was 1 before, now it becomes 0. This should make the "while (X == 0)" part happen again, so that another number bigger than three can be entered
}
if (num <= 3) //if function: if num is lesser than or equal to 3, this should happen
{
cout << "Wrong! Try again!" <<endl; //output
X--; //This is supposed to work like the "X--;" before, repeating the code from "while (X==0)"
}
}
}
now it becomes 0. This should make the "while (X == 0)" part happen again
Nope. While loops don't magically take effect at any point during execution of the program. You only enter a while loop when you've reached it from code above. Programs are executed top-to-bottom, generally.
You would need a loop around the entire program if you want to keep going round and round. Those whiles you have now should probably be ifs.
Merge the two while loops into one, while(true).
Put each previous while body into an if state with the clause from the old while in it.
while(true) {
if (X==0) {
// the X==0- case
} else if (X==1) {
// the X==1 case
}
}
in order to end your loop, do a break;.
You have to think of C++ programs as a sequence of instructions, like a recipe. while just means a loop: you check the condition. If true, you run the body. After running the body, you check only that condition again, and run the body if true. Whenever the condition is false at the start or end of the body of the while (the {} enclosed code after it), you end the loop and proceed to the next one.
The first loop runs, finishes, then the second loop runs in your code. Once the first loop exits, you do not go back into it just because the condition becomes true.
Understanding flow control is one of the "hard" steps of learning to program, so it is ok if you find this tricky.
There are many improvements you can do your code beyond getting it working -- there is, actually, little need for X at all. But baby steps! Once you get it working, you can ponder "how could I remove the variable X?".
Before making such fundamental changes to your program, you should get it working, and save a copy of it so you can "go back" to the last working version.
You want to wrap all that code in it's own while loop:
while (true /* or something */)
{
while (X == 0) //this should happen whenever X is equal to 0
{
// ...
}
At least put your second while loop inside the first one to get it working as intended. Otherwise your program has no reason to go back again.
Nevertheless it's not a good design.

Getting stuck in an infinite loop

I had my program running smoothly, and then after commenting it and adding some final touches, it stopped working on me. The function that I am having problems with is using several objects/functions defined elsewhere, so I am just wondering if someone can affirm that my logic is correct and that the infinite loop is not a product of a syntax error. Thanks for your time, here is the problem I'm having:
If the cashier started a new order and wants to close his order, T is typed in. However, when trying to exit an order and loop back to the start of while(moreCustomers), nothing is happening. I am trying to exit the while(moreItems) loop by setting moreItems = false;, but after doing that, it gets stuck in the while(moreItems) loop and does not go back to while(moreCustomers). Does the syntax make sense, and should I be able to break the loop by setting moreItems = false;?
bool moreCustomers = true;
while (moreCustomers)
{
// get input to start new order or close register
drawInstruct("Enter N to start a new order or E to\n close the register.");
char* setFmt = "#"; // the input must be a letter
char input[7]; // char array that stores input from cashier
s.GetStr(xLeftCoord + 1, yTopCoord + 1, input, 1, setFmt, true);
for(int x = 1; x < 10; x++) // clear the input field
{
s.ClearScreenPos(x, 1);
}
if (input[0] == 'N') // if a new order is requested
{
bool moreItems = true;
while (moreItems)
{
getInput(input);
if(input[1]) // if input is not a single char
{
if (input[0] == 'M') // get the desired number of multiples for the current item and update the tape and display area accordingly
{
custTape.handleMultiples(atoi(input)); // adds multiples to tape
curVal = isUPC->price * (atoi(input)); // updates the current item price
drawDisplayArea(curVal); // updates the display area
}
else // invalid number of multiples, prompt for new multiple
{
drawInstruct("Invalid command. Please try again.");
s.Delay();
}
}
else if (input[0] == 'T') // close the order
{
drawInstruct("Order cancelled.");
s.Delay();
moreItems = false; // customer order is complete, exit loop
}
else // invalid command, get new input from the cashier
{
drawInstruct("Invalid command. Please try again.");
s.Delay();
}
}
}
else if (input[0] == 'E') // close the register
{
moreCustomers = false; // no more customers, exit the program
}
else // invalid command, get new input from the cashier
{
drawInstruct("Invalid Command. Please try again.");
s.Delay();
}
}
I can't exit else if(input[0] == 'T'), and any commands I enter in after moreItems = false; work correctly.
I'd set a breakpoint on the first moreItems = false; line to see if it is ever being hit. My guess is that it is not. You've tagged the question with Visual Studio, so if that is what you're using see this link for how to set a breakpoint:
http://msdn.microsoft.com/en-us/library/vstudio/k80ex6de%28v=vs.100%29.aspx
Basically a breakpoint causes your program to stop at that line. Also try setting a breakpoint on this line:
if (input[0] == 'N')
Run the program, press a key, and wait for the breakpoint to be hit. Then use the "Step Over" option on the Debug menu. This runs your program line by line, each time you press "Step Over" (F10 does this too, much quicker). Keep stepping to see what path of execution occurs through your code. You may also be able to hover over variables to see their values.
Theres loads on the net about debugging with visual studio, but if you master the above you'll be well away

Why can't I read all Ctrl + 'letters'

I've made a program that allows me to read all the stand-alone function keys (that I thought to test, at least) on my keyboard. I have it designed so that I can refer to any single key input as a single value. It handles Return, F1-F12, delete, backspace, arrows etc
I just thought to test modifications of input. I already made sure shift works, but now I decided to test Ctrl and Alt.
Question 1
Why does Alt not modify any of the input key codes?
Question 2
Why can I not capture certain Ctrl + combinations?
Eg. Ctrl + s; Ctrl + 1-9;
Ctrl + 2 works, but I think it might be due to having my keyboard set as UK.
This is the code I am using.
Please note, I am not necessarily asking how to capture these key combinations (unless it is a simple modification or two). I only want to know why I am unable to.
#include <iostream>
#include <conio.h>
#include <cwchar>
union wide_char
{
short Result;
char C[2];
};
int main()
{
wchar_t R;
int N;
wide_char user_input;
//Loops forever, this is only a proof of concept program proving this is possible to incorporate into a larger program
while(true)
{
user_input.C[0] = 0;
user_input.C[1] = 0;
//Loop twice, or until code causes the loop to exit
//Two times are neccessary for function keys unfortunately
for(int i = 0; i < 2; ++i)
{
//While there isn't a key pressed, loop doing nothing
while(!kbhit()){}
//Grab the next key from the buffer
//Since the loop is done, there must be at least one
user_input.C[i] = getch();
switch(user_input.C[i])
{
case 0:
case -32:
//The key pressed is a Function key because it matches one of these two cases
//This means getch() must be called twice
//Break switch, run the for loop again ++i
break;
default:
//The character obtained from getch() is from a regular key
//Or this is the second char from getch() because the for loop is on run #2
//Either way we need a wide char (16 bits / 2 Bytes)
if(user_input.C[1] != 0)
//Function keys {Arrows, F1-12, Esc}
//We now combine the bits of both chars obtained
//They must be combined Second+First else the F1-12 will be duplicate
//This is because on F1-12 getch() returns 0 thus won't affect the combination
R = user_input.Result;
else
//Regular key press
R = user_input.C[0];
//Display our unique results from each key press
N = R;
std::cout << R << " R = N " << N << std::endl;
if( R == 'a' )
std::cout << "a = " << N << std::endl;
//Manually break for loop
i = 3;
break;
}
}
//We need to reset the array in this situation
//Else regular key presses will be affected by the last function key press
}
}
This is very specific to your environment. You're using conio which is specific to DOS / Windows.
Most of the Ctrl + alpha key values are bound to characters 1 - 26, and certain others are bound to other values under 31, to map to ASCII control characters. But some, like Ctrl + S have special meaning (Ctrl + S is XOFF in ASCII), and so might get 'eaten' by your environment.
Fundamentally, the issue you're facing is the fact that getch approximates an old-school serial terminal interface. They only expose keyboard events at a "least common denominator" level, as opposed to a lower level that would allow you to distinguish modifier keys, etc. and give you a better way to deal with special keys such as function keys.
(As you've noticed, function keys, have special multi-byte sequences. Again, this is due to emulating old-school serial terminals, where the keyboard might be at the other end of a remote link.)
To get a lower-level (and therefore more direct and flexible interface) you need to use a more platform-specific library, or a richer library such as SDL. Either would give you a lower level view of the inputs from the keyboard.

getchar() doesn't actually take input from user

I am writing a flexible command-line (but not for long!) diamond-square generator in C++. I have just finished writing the user input half. However, on the very last command, input "slips" and a newline is automatically inputted to getchar(). I have taken precautions to ensure that it's not any sort of overflow, namely, fflushing both stdin, and, for good measure, stdout. The problem persists. Here is my code:
#include <stdio.h>
#include <stdlib.h>
int main () {
unsigned long seed = 0, x = 0, y = 0, initial = 0, range = 0;
int smooth = 0, fail = 1;
char flagchar1 = 'n';
printf("Welcome to my diamond-square generator! This isn't full-feature yet, so I'm just gonna have you input the variables one by one. ");
do {
printf("Please input the seed (this is a positive integer):\n");
fail = scanf("%lu", &seed);
while (fail == 0) {
printf("Try again, smartass.\n");
fail = scanf("%lu", &seed);
}
fail = 1;
printf("Now input the x, or horizontal, size of your grid:\n");
fail = scanf("%lu", &x);
while (fail == 0) {
printf("An integer. Not a string. An integer. You can do that, can't you?\n");
fail = scanf("%lu", &x);
}
fail = 1;
printf("Now input the y, or vertical, size of your grid:\n");
fail = scanf("%lu", &y);
while (fail == 0) {
printf("What was that supposed to be? An integer, please.\n");
fail = scanf("%lu", &y);
}
fail = 1;
printf("Now input about how high you'd like the grid to be (this goes from a scale of 1 to 256):\n");
fail = scanf("%lu", &initial);
while (initial == 0 || initial > 256 || fail == 0) {
printf("ahahahahaha how HIGH do you have to be just to HAVE that hieght........\n");
fail = scanf("%lu", &initial);
}
fail = 1;
printf("Now input the range of the heights on your grid (this must be equal to or less than 256):\n");
scanf("%lu", &range);
while (range >= 256 || fail == 0) {
printf("What did I say about being equal to or less than 256? Give me something reasonable to work with here.\n");
fail = scanf("%lu", &range);
}
fail = 1;
printf("Just one more variable to go! Now, I need you to input the smoothness of your grid. Smaller numbers make spikier grids. You can make this negative, but beware!\n");
fail = scanf("%d", &smooth);
while (fail == 0) {
printf("That... was not a number.\n");
fail = scanf("%d", &smooth);
}
fail = 1;
printf("\nOkay. Are these the values you want?\n Seed: %lu\n Width: %lu\n Length: %lu\n Height: %lu\n Range: %lu\n Smoothness: %d\nDo you want to keep these? Type Y/n.\n", seed, x, y, initial, range, smooth);
fflush(stdin);
fflush(stdout);
flagchar1 = getchar();
} while (flagchar1 != 'y' && flagchar1 != 'Y' && flagchar1 != '\n');
}
Here is my output, the program having ended (the program just repeats the entire do-while loop if I remove the && flagchar1 != '\n' from while()):
Welcome to my diamond-square generator! This isn't full-feature yet, so I'm just gonna have you input the variables one by one. Please input the seed (this is a positive integer):
12345678
Now input the x, or horizontal, size of your grid:
40
Now input the y, or vertical, size of your grid:
30
Now input about how high you'd like the grid to be (this goes from a scale of 1 to 256):
1288
ahahahahaha how HIGH do you have to be just to HAVE that hieght........
128
Now input the range of the heights on your grid (this must be equal to or less than 256):
30
Just one more variable to go! Now, I need you to input the smoothness of your grid. Smaller numbers make spikier grids. You can make this negative, but beware!
10
Okay. Are these the values you want?
Seed: 12345678
Width: 40
Length: 30
Height: 128
Range: 30
Smoothness: 10
Do you want to keep these? Type Y/n.
What's happening, and how do I fix it?
P.S. I know my input validation is essentially useless. Help with this is also greatly appreciated.
Make the end of your loop look like this:
// Ignore remaining characters on current line.
int ch;
while( (ch = getchar()) != EOF && ch != '\n')
;
// fetch first character on next line
flagchar1 = getchar();
} while (flagchar1 != 'y' && flagchar1 != 'Y' && flagchar1 != '\n');
You are leaving the '\n' in stdin after your last call to scanf.
You must not rely upon fflush(stdin) having any specific behavior. The result of invoking fflush on a input stream is undefined. See Using fflush(stdin)
The code is behaving exactly as you tell it to. If the user enters 'y', 'Y' or enter, one of those conditions in the while loop will be false, which causes it to exit.
What you want is:
while (flagchar1 == 'y' || flagchar1 == 'Y' || flagchar1 == '\n');
Edit: I would also delete the fflush(stdin) and replace getchar() with fgets(). That will guarantee the entire line is read without having to use fflush, which may be the issue.
I'm guessing you are on Linux? This works fine on VS in Windows. It prompts, reads from keyboard, and if examined contains the correct 'y' or 'Y' in question.
I might suggest you try changing the last scanf to:
fail = scanf("%d ", &smooth);
You could also try calling fpurge() instead of fflush(), but that's non standard, and I think the space at the end of the format string will get you what you want.
The trailing space will ask scanf to consume any extra whitespace (including newlines) in the input data. fflush() probably won't do what you want for input.
I suspect whatever system you are on is indeed leaving the carriage return in the stream and if you print flagchar1 as an int you'll get 10?
Suggestions:
Use C++ streams.
Use tolower or toupper before comparing characters.
Use std::string.
The C language, which uses fgets, gets, fflush, strcmp, has many issues in this area. The C++ language has resolved many of these issues in the std::stream classes.
Since you are not using C++ features, you should change the C++ tag to C.
Try
} while (flagchar1 != 'y' || flagchar1 != 'Y' || flagchar1 != '\n');
instead of
} while (flagchar1 != 'y' && flagchar1 != 'Y' && flagchar1 != '\n');