getchar() doesn't actually take input from user - c++

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');

Related

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

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
}
}

Compare strings using ==

Code, as shown below, can be complied.
Problem: It always says "Invalid Employee id" even when I enter the correct employee id.
Please tell me why and how to do this correctly.
#include <iostream>
#include <iomanip>
using namespace std;
char select, js;
char empid[4];
double bSalary, bonus, tot=0.0;
int main()
{
do
{
cout<<"Employee id: ";
cin>>empid;
if(empid=="M001" || empid=="A004" || empid == "M002") //these are employee ids
{
cout<<"Job Status: ";
cin>>js;
if(js=='P' || js=='C')
{
cout<<"Basic Salary: ";
cin>>bSalary;
if(bSalary>75000 && js=='P')
{
bonus = bSalary*(20.0/100.0);
tot = tot + bonus + bSalary;
}
else if(bSalary>75000 && js=='C')
{
bonus = bSalary*(15.0/100.0);
tot = tot + bonus + bSalary;
}
else
tot = tot+bonus+bSalary;
}
else
cout<<"Invalid Job Status"<<endl;
}
else
cout<<"Invalid Employee no"<<endl;
cout<<"Do you want to continue: ";
cin>>select;
cout<<endl;
}while(select=='y'||select=='Y');
cout<<"Total cost: "<<setprecision(2)<<setiosflags(ios::fixed)<<tot<<endl;
return 0;
}
Note: It is going to the else clause all the time.
It's this:
char empid[4];
This is too small as there's no room for a NUL terminator after the id. You could just change it to 5, but then if someone deliberately or accidentally typed a longer string your program may crash (it's called a buffer overrun, and in some situations can allow whoever provides input to hack the account running the program).
Further, == doesn't work for character arrays: you have to use e.g.:
if (strcmp(empid, "M001") == 0 || strcmp(empid, "A004") == 0 || ...
You would be much better off using a std::string, which will grow to accommodate the actual input (including a NUL terminator though that's not counted in a string's .size()), and works intuitively with ==.
Separately, your...
tot = tot+bonus+bSalary;
...is broken, as bonus may be uninitialised you mustn't read from it in an expression. You can simply remove bonus from the addition above, if it's meant to be 0 for the relevant employees.
You can't compare C strings with == or !=. As you can see that empid here is just a pointer so == will compare the base addresses of those strings not the strings themselves.
You need to use strcmp and include
#include <cstring>
.
.
.
if(strcmp(empid,"M001")==0 || ...)
Empid is not a string. C++ doesn't have a built-in == overload to compare char arrays.
You can make your own == operator. But don't bother. Declare empid as a string and watch magic happen.
string empid;
Changing the size of the char array to take care of NULL char will not work here.
char empid[5]
"==" operator do not work properly with char arrays. please change the condition to below:
if (0 == (strcmp(empid, "M001")) || (0 == (strcmp(empid, "A004"))) || (0 ==
(strcmp(empid, "M002"))))
EDIT:people above has already answered your question. My answer is redundant now.

Inexistent double decrement?

I was writing a little game, where there is an hidden word, and the user must guess, char to char, what word is.
While coding this I got stucked in something that I don't understeand where and how it happens.
while(true)
{
if(Hue == 0)
Try -= 1;
if(Hue == 1)
Hue = 0;
GotoXY(0, 3);
printf("Inserisci una lettera maiuscola\n>");
GotoXY(1, 4);
scanf("%c", &Key);
GotoXY(0, 4);
printf(" ");
GotoXY(0, 6);
printf("Numero di tentativi rimasti: %d ", Try);
for(unsigned short Iterator = 1; Iterator < Length - 1; ++Iterator)
if(Key == UserString[Iterator])
{
for(unsigned short SecIterator = Iterator; SecIterator < Length - 1; ++SecIterator)
{
if(Key == UserString[SecIterator])
{
GotoXY(SecIterator, 1);
printf("%c", Key);
}
}
Hue = 1;
break;
}
}
Hue is a simple control variable to check if the key was in the word.
If it's still 0 then the key wasn't in the word, so the Try decrements it self and so on.
But what happen is that Hue, either is 0 or 1 causes the decrement of Try, and the thing even more stange is that Try decrement twice when is 0, evenly in the code isn't written nothing like that.
Thanks for the help.
It seems the confusion is mostly due to the double decrement: well, you are reading chars and most likely you hit return making two chars available: the entered character and the '\n' from the return. Since apparently neither character matches you get two decrements.
Just for a bit of explanation: when using the formatted input using std::cin >> Key leading whitespace is skipped. When using scanf("%c", &c) each character is extracted. I think you can have scanf() skip leading spaces using
if (1 == scanf(" %c", &c)) {
// process the input
}
Note the extra space in front of the '%c'. To debug issues like this it is generally a good idea to print what was read. ...and, of course, you always need to verify that the read was actually successful.

C++ fastest cin for reading stdin?

I've profiled a computationally-heavy C++ program on Linux using cachegrind. Surprisingly, it turns out the bottleneck of my program is not in any sorting or computational method ... it's in reading the input.
Here is a screenshot of cachegrind, in case I'm mis-interpreting the profiler results (see scanf()):
I hope I'm right in saying that scanf() is taking 80.92% of my running time.
I read input using cin >> int_variable_here, like so:
std::ios_base::sync_with_stdio (false); // Supposedly makes I/O faster
cin >> NumberOfCities;
cin >> NumberOfOldRoads;
Roads = new Road[NumberOfOldRoads];
for (int i = 0; i < NumberOfOldRoads; i++)
{
int cityA, cityB, length;
cin >> cityA;
//scanf("%d", &cityA); // scanf() and cin are both too slow
cin >> cityB;
//scanf("%d", &cityB);
cin >> length;
//scanf("%d", &length);
Roads[i] = Road(cityA, cityB, length);
}
If you don't spot any issues with this input reading code, could you please recommend a faster way to read input? I'm thinking of trying getline() (working on it while I wait for responses). My guess is getline() may run faster because it has to do less conversion and it parses the stream a less total number of times (just my guess, though I'd have to parse the strings as integers eventually too).
What I mean by "too slow" is, this is part of a larger homework assignment that gets timed out after a certain period of time (I believe it is 90 seconds). I'm pretty confident the bottleneck is here because I purposely commented out a major portion of the rest of my program and it still timed out. I don't know what test cases the instructor runs through my program, but it must be a huge input file. So, what can I use to read input fastest?
The input format is strict: 3 integers separated by one space for each line, for many lines:
Sample Input:
7 8 3
7 9 2
8 9 1
0 1 28
0 5 10
1 2 16
I need to make a Road out of the integers in each line.
Also please not that input is redirected to my program to the standard input (myprogram < whatever_test_case.txt). I'm not reading a specific file. I just read from cin.
Update
Using Slava's method:
Input reading seems to be taking less time, but its still timing out (may not be due to input reading anymore). Slava's method is implemented in the Road() ctor (2 down from main). So now it takes 22% of the time as opposed to 80%. I'm thinking of optimizing SortRoadsComparator() as it's called 26,000,000 times.
Comparator Code:
// The complexity is sort of required for the whole min() max(), based off assignment instructions
bool SortRoadsComparator(const Road& a, const Road& b)
{
if (a.Length > b.Length)
return false;
else if (b.Length > a.Length)
return true;
else
{
// Non-determinism case
return ( (min(a.CityA, a.CityB) < min(b.CityA, b.CityB)) ||
(
(min(a.CityA, a.CityB) == min(b.CityA, b.CityB)) && max(a.CityA, a.CityB) < max(b.CityA, b.CityB)
)
);
}
}
Using enhzflep's method
Considering solved
I'm going to consider this problem solved because the bottleneck is no longer in reading input. Slava's method was the fastest for me.
Streams pretty well know to be very slow. It is not a big surprise though - they need to handle localizations, conditions etc. One possible solution would be to read file line by line by std::getline( std:::cin, str ) and convert string to numbers by something like this:
std::vector<int> getNumbers( const std::string &str )
{
std::vector<int> res;
int value = 0;
bool gotValue = false;
for( int i = 0; i < str.length(); ++i ) {
if( str[i] == ' ' ) {
if( gotValue ) res.push_back( value );
value = 0;
gotValue = false;
continue;
}
value = value * 10 + str[i] - '0';
gotValue = true;
}
if( gotValue ) res.push_back( value );
return res;
}
I did not test this code, wrote it to show the idea. I assume you do not expect to get anything in input but spaces and numbers, so it does not validate the input.
To optimize sorting first of all you should check if you really need to sort whole sequence. For comparator I would write methods getMin() getMax() and store that values in object (not to calculate them all the time):
bool SortRoadsComparator(const Road& a, const Road& b)
{
if( a.Length != b.Length ) return a.Length < b.length;
if( a.getMin() != b.getMin() ) return a.getMin() < b.getMin();
return a.getMax() < b.getMax();
}
if I understood how you current comparator works correctly.
As Slava says, streams (i.e cin) are absolute pigs in terms of performance (and executable file size)
Consider the following two approaches:
start = clock();
std::ios_base::sync_with_stdio (false); // Supposedly makes I/O faster
cin >> NumberOfCities >> NumberOfOldRoads;
Roads = new Road[NumberOfOldRoads];
for (int i = 0; i < NumberOfOldRoads; i++)
{
int cityA, cityB, length;
cin >> cityA >> cityB >> length;
Roads[i] = Road(cityA, cityB, length);
}
stop = clock();
printf ("time: %d\n", stop-start);
and
start = clock();
fp = stdin;
fscanf(fp, "%d\n%d\n", &NumberOfCities, &NumberOfOldRoads);
Roads = new Road[NumberOfOldRoads];
for (int i = 0; i < NumberOfOldRoads; i++)
{
int cityA, cityB, length;
fscanf(fp, "%d %d %d\n", &cityA, &cityB, &length);
Roads[i] = Road(cityA, cityB, length);
}
stop = clock();
printf ("time: %d\n", stop-start);
Running each way 5 times (with an input file of 1,000,000 entries + the first 2 'control' lines) gives us these results:
Using cin without the direction to not sync with stdio
8291, 8501, 8720, 8918, 7164 (avg 8318.3)
Using cin with the direction to not sync with stdio
4875, 4674, 4921, 4782, 5171 (avg 4884.6)
Using fscanf
1681, 1676, 1536, 1644, 1675 (avg 1642.4)
So, clearly, one can see that the sync_with_stdio(false) direction does help. One can also see that fscanf beats the pants off each approach with cin. In fact, the fscanf approach is nearly 3 times faster than the better of the cin approaches and a whopping 5 times faster than cin when not told to avoid syncing with stdio.
inline void S( int x ) {
x=0;
while((ch<'0' || ch>'9') && ch!='-' && ch!=EOF) ch=getchar_unlocked();
if (ch=='-')
sign=-1 , ch=getchar_unlocked();
else
sign=1;
do
x = (x<<3) + (x<<1) + ch-'0';
while((ch=getchar_unlocked())>='0' && ch<='9');
x*=sign;
}
you can use this function for any type of number input, just change the paramater type.
This will run pretty faster than std scanf.
If you want to save more time best thing will be to use fread() and fwrite() but in that case you have to manipulate the input by yourself.
To save time you should use fread() to read a large chunk of data from standard input stream in one call.That will decrease the number of I/O calls hence you will see a large difference in time.

input string validation without external libraries for c++

I need to validate one input string from a user. Eventually it will need to break down into two coordinates. ie a4 c3. And once they are coordinates they need to be broken out into 4 separate ints. a=0 b=1, etc. They must also follow the following stipulations:
If an end-of-input signal is reached the program quits.
Otherwise, all non-alphanumeric characters are discarded from the input.
If what remains is the single letter 'Q'
Then the program quits.
If what remains consists of 4 characters, with one letter and one digit among the first two characters and one letter and one digit among the last two characters, and if each letter-digit pair is in the legal range for our grid
Then input is acceptable.
I have completely over-thought and ruined my function. Please let me know where I can make some corrections.
I am mainly having trouble going from one string, to four chars if and only if the data is valid. Everything else I can handle.
Here is what I have so far.
void Grid::playerMove()
{
string rawMove;
string pair1 = " ";
string pair2 = " ";
bool goodInput = false;
char maxChar = 'a';
char chary1, chary2;
int x11,x22,y11,y22;
for (int i =0; i<size; i++)
{
maxChar++;
}
while(!goodInput)
{
cout<<"What two dots would you like to connect? (Q to quit) ";
cin>>rawMove;
rawMove = reduceWords(rawMove);
if (rawMove == "Q")
{
cout<<"end game";
goodInput = false;
}
else if (rawMove.size() == 4)
{
for(int j=0;j<2;j++)
{
if (pair1[j] >='a' && pair1[j] <=maxChar)
{
chary1 = pair1[j];
}
else if(pair1[j] >=0 && pairl[j]<=size+1)
{
x1 = pair1[j];
}
}
for(int k=0;k<2;k++)
{
if (pair2[k] >='a' && pair2[k] <=maxChar)
{
chary2 = pair2[k];
}
else if(pair2[k] >=0 && pair2[k]<=size+1)
{
x2 = pair2[k];
}
}
}
if(char1 != NULL && char2 != NULL && x1 !=NULL && x2 != NULL)
{
for (int m = 0; m <= size m++)
{
if (char1 == m;)
{
x1 = m;
}
}
for (int n = 0; n <= size n++)
{
if (char2 == n)
{
x2 = n;
}
}
}
}
The end goal would be to have x1, x2, y1, and y2 with their respective values.
Keep in mind I am not allowed to have any external libraries.
It's not clear what exactly you want to achieve, but here are some pointers to get you started:
The while loop will never end because you're setting goodInput to false on quit which lets the loop continue.
The code probably does not even compile? You are missing a curly closing brace..
You are initializing pair1 and pair2 to empty strings but never change them again, so they will never contain any real information about your moves
maybe what you really want is to split up rawMove into the pair1 and pair2 substrings first?
Since this is a homework - and you're supposed to learn from those (right?) - I'm not going to give you the complete answer, but rather something like a recipe:
Use std::istream::getline(char*, std::streamsize s) to read a whole line from std::cin. Make sure you allocate a buffer large enough to hold the expected input (including the terminating null character) plus some more for invalid characters. After the call, check the failbit (input was too long) and the eofbit (hit the end-of-input) of the std::cin stream and handle those cases. Construct a std::string from the buffer if there was no error or EOF has not been reached.
Write a character-classification function (e.g. call it isAlNum(char c)) that returns true if the char argument is alpha-numeric, and false otherwise.
Combine std::string::erase(), std::remove_if(), std::not1(), std::ptr_fun() and your function isAlNum() to sanitise the input string.
Write a function that validates and parses the coordinates from the sanitised input string and call it with the sanitised input string.
Wrap the whole thing in an appropriate while() loop.
This should get you started in the right direction. Of course, if you're allowed to use C++11 features and you know how to write good regular expressions, by all means, use the <regex> header instead of doing the parsing manually.