Trying to ignore all whitespace up to the first character (desperately needing a simple nudge) - c++

I'll be flat out honest, this is a small snippet of code I need to finish my homework assignment. I know the community is very suspicious of helping students, but I've been racking my head against the wall for the past 5 hours and literally have accomplished nothing on this assignment. I've never asked for help on any assignments, but none have given me this much trouble.
All I'm having trouble with is getting the program to strip the leading whitespace out. I think I can handle the rest. I'm not asking for a solution to my overall assignment, just a nudge on this one particular section.
I'll post the full assignment text here, but I am NOT posting it to try to get a full solution, I'm only posting it so others can see the conditions I have to work with.
"This homework will give you more practice in writing functions and also how numbers are read into a variable. You need to write a function that will read an unsigned integer into a variable of type unsigned short int. This will have a maximum value of 65535, and the function needs to take care of illegal numbers. You can not use "cin >>", inside the function.
The rules for numeric input are basically as follows:
1) skip all leading white spaces
2) first character found must be numeric else an error will occur
3) numeric characters are then processed one at a time and combine with number
4) processing stops when non-numeric found
We will follow these rules and also add error handling and overflow. If an illegal entry is made before a numeric than an error code of "1" will be sent back, if overflow occurs, that is number bigger then 65535, then error code of "2" will be sent back. If no error then "0" is sent back.
Make sure the main function will continue to loop until the user enters a “n” or “N” for NO, the main should test the error code returned from the function called “ReadInt” and display appropriate error messages or display the number if there is no error. Take care in designing the “ReadInt” function, it should be value returning and have a reference parameter. The function needs to process one character at a time from the input buffer and deal with it in a correct fashion. Once the number has been read in, then make sure the input buffer is empty, otherwise the loop in main may not work correct. I know this is not how the extraction works, but lets do it this way.
You do not need to turn in an algorithm with this assignment, but I would advise you to write one. And the debugger may prove helpful as well. You are basically rewriting the extraction operator as it works on integers."
A majority of my code won't make sense as I've been deleting things and adding things like crazy to try everything I can think of.
#include <iostream>
#include <CTYPE.h>
using namespace std;
int ReadInt (unsigned short int &UserIn);
int main()
{
int Error;
unsigned short int UserInput;
char RepeatProgram;
do
{
Error=ReadInt(UserInput);
if (Error==0)
cout << "Number is " << UserInput << endl;
else if (Error==1)
cout << "Illegal Data Entry\n";
else if (Error==2)
cout << "Numerical overflow, number too big\n";
cout << "Continue? n/N to quit: ";
cin >> RepeatProgram;
cout << endl;
} while (RepeatProgram!='N' && RepeatProgram!='n');
}
int ReadInt (unsigned short int &UserIn)
{
int Err=0;
char TemporaryStorage;
long int FinalNumber=0;
cout << "Enter a number: ";
//cin.ignore(1000, !' '); this didn't work
cin.get(TemporaryStorage);
cout << TemporaryStorage;//I'm only displaying this while I test my ideas to see if they are working or not, before I move onto the the next step
cout << endl;
return Err;
}
I really appreciate any help I may get and hope I don't give the impression that I'm looking for a full free solution to the whole problem. I want to do this on my own, I'm just lot on this beginning.

As a preface, I want to state that this is a question made by a student, but unlike most of their type, it is a quality question that merits a quality answer, so I'll try to do it ;). I won't try to just answer your concrete question, but also to show you other slight problems in your code.
First of all, let's analyze your code step by step. More or less like what a debugger would do. Take your time to read this carefully ;)...
#include <iostream>
#include <CTYPE.h>
Includes headers <iostream> and <ctype.h> (the uppercase works because of some flaws/design-decisions of NTFS in Windows). I'ld recommend you to change the second line to #include <cctype> instead.
using namespace std;
This is okay for any beginner/student, but don't get an habit of it! For the purposes of "purity", I would explicitly use std:: along this answer, as if this line didn't existed.
int ReadInt (unsigned short int &UserIn);
Declares a function ReadInt that takes a reference UserIn to type unsigned short int and returns an object of type int.
int main()
{
Special function main; no parameters, returns int. Begin function.
int Error;
unsigned short int UserInput;
char RepeatProgram;
Declares variables Error, UserInput, and RepeatProgram with respective types int, unsigned short int, and char.
do
{
Do-while block. Begin.
Error=ReadInt(UserInput);
Assign return value of ReadInt of type int called with argument UserInput of type int& to variable Error of type unsigned short int.
if (Error==0)
std::cout << "Number is " << UserInput << endl;
If Error is zero, then print out UserInput to standard output.
else if (Error==1)
std::cout << "Illegal Data Entry\n";
else if (Error==2)
std::cout << "Numerical overflow, number too big\n";
Otherwise, if an error occurs, report it to the user by means of std::cout.
std::cout << "Continue? n/N to quit: ";
std::cin >> RepeatProgram;
Query the user if he/she wants to continue or quit. Store the input character in RepeatProgram of type char.
std::cout << std::endl;
Redundant, unless you want to add padding, which is probably your purpose. Actually, you're better off doing std::cout << '\n', but that doesn't matters too much.
} while (RepeatProgram!='N' && RepeatProgram!='n');
Matching expression for the do-while block above. Repeat execution of the given block if RepeatProgram is neither lower- or uppercase- letter N.
}
End function main. Implicit return value is zero.
int ReadInt (unsigned short int &UserIn)
{
Function ReadInt takes a reference UserIn to unsigned short int and returns an object of type int. Begin function.
int Err=0;
char TemporaryStorage;
long int FinalNumber=0;
Declares variables Err, TemporaryStorage, and FinalNumber of respective types int, char, and long int. Variables Err and FinalNumber are initialized to 0 and 0, respectively. But, just a single thing. Didn't the assignment said that the output number be stored in a unsigned short int? So, better of this...
unsigned short int FinalNumber = 0;
Now...
std::cout << "Enter a number: ";
//std::cin.ignore(1000, !' '); this didn't work
Eh? What's this supposed to be? (Error: Aborting debugger because this makes no logic!**). I'm expecting that you just forgot the // before the comment, right? Now, what do you expect !' ' to evaluate to other than '\0'? istream::ignore(n, ch)will discard characters from the input stream until either n characters have been discarded, ch is found, or the End-Of-File is reached.
A better approach would be...
do
std::cin.get(TemporaryStorage);
while(std::isspace(TemporyStorage));
Now...
std::cin.get(TemporaryStorage);
This line can be discarded with the above approach ;).
Right. Now, where getting into the part where you obviously banged your head against all solid objects known to mankind. Let me help you a bit there. We have this situation. With the above code, TemporaryStorage will hold the first character that is not whitespace after the do-while loop. So, we have three things left. First of all, check that at least one digit is in the input, otherwise return an error. Now, while the input is made up of digits, translate characters into integers, and multiply then add to get the actual integer. Finally, and this is the most... ahem... strange part, we need to avoid any overflows.
if (!std::isdigit(TemporaryStorage)) {
Err = 1;
return Err;
}
while (std::isdigit(TemporaryStorage)) {
unsigned short int OverflowChecker = FinalNumber;
FinalNumber *= 10; // Make slot for another digit
FinalNumber += TemporaryStorage - '0'; '0' - '0' = 0, '1' - '0' = 1...
// If an unsigned overflows, it'll "wrap-around" to zero. We exploit that to detect any possible overflow
if (FinalNumber > 65535 || OverflowChecker > FinalNumber) {
Err = 2;
return Err;
}
std::cin.get(TemporaryStorage);
}
// We've got the number, yay!
UserIn = FinalNumber;
The code is self-explanatory. Please comment if you have any doubts with it.
std::cout << TemporaryStorage;//I'm only displaying this while I test my ideas to see if they are working or not, before I move onto the the next step
cout << endl;
return Err;
Should I say something here? Anyway, I already did. Just remember to take that std::couts out before showing your work ;).
}
End function ReadInt.

You can skip leading whitespace from a stream using std::ws. For example:
std::cin >> std::ws;
This use of >> just invokes the manipulator std::ws on the stream. To meet the teacher's requirements you can invoke it directly:
std::ws(std::cin);
Formatted input automatically skips whitespace. Note that should also always check whether input was successful:
if (std::cin.get(TemporaryStorage)) {
...
}

Related

Code for decrypting simple sentences made with CodeBlocks crashes without outputting a single character [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 1 year ago.
Improve this question
I am making a program that inputs the alphabetical order for encrypting a sentence to decrypt it (just replacing characters). I am required to input the number of words it has, but the method I'm using doesn't need that so I just input it and do nothing with it (it doesn't matter because an AI will be verifying only the output of the program). I think I came up with a decent algorithm, but the program keeps crashing after I enter the encrypted sentence. I tried changing a lot of things but nothing seems to solve the issue. Also, I'm sorry for any things that don't make sense in the code, I'm just a beginner. Please help me stop the program from crashing so I can submit it before the end of tomorrow.
This is my code
#include <iostream>
#include <string>
using namespace std;
int main()
{
int n, i, j;
string key, encrypted;
cin >> key;
char alphabet[]={'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z'};
cin >> n;
getline(cin>>ws, encrypted);
for (i=0;i<=encrypted.size();i++)
{
for (j=0;j<encrypted.size();j++)
{
if (encrypted[i]==key[j])
{
cout << alphabet[j];
}
else if (encrypted[i]==key[j]+32)
{
cout << alphabet[j]+32;
}
else if (encrypted[i]==' ')
{
cout << " ";
}
}
}
}
Your program has the following bugs:
First bug:
As already pointed out in the comments section, you should change the line
for (j=0;j<encrypted.size();j++)
to
for (j=0;j<key.size();j++)
Second bug:
Due to integer promotion, the expression alphabet[j]+32; will evaluate to a value of type int, not char. This means that
cout << alphabet[j]+32;
will print a number, not a character. Therefore, you must cast the result of the expression back to the data type char, like this:
cout << static_cast<char>( alphabet[j]+32 );
Third bug:
The line
cout << " ";
should only be called once per outer loop iteration, i.e. once per character in the string encrypted. However, you are calling it once per inner loop iteration, which means you are calling it several times per character. Therefore, you should remove that statement from the inner loop and put it into the outer loop.
Fourth bug:
The line
for (i=0;i<=encrypted.size();i++)
is wrong. It should be < instead of <=. Otherwise, you will also process the terminating null character of the string, which is not meaningful.

Wrong Output : counting the string

#include <iostream>
#include <cstring>
using namespace std;
int main() {
char a[10001],b[10001];
int tot,s1,s2;
cin>>tot;
while(tot!=0) {
gets(a);
gets(b);
s1= strlen(a);
s2= strlen(b);
cout<<s1<<s2<<endl;
tot--;
s1=0;
s2=0;
}
}
this is a program to find length of two strings , with cases also entered
Input :
4
abcd
xyz
abcd
bcda
aabc
acaa
Codechef
elfedcc
Expected output
43
44
44
87
but output is
04
34
44
48
Why?
As noted in the comment, the compiler is punishing you for using gets1. I wasn't going to write an actual answer, but the answers you're getting seem to be trying to cover up the problems with the code, without actually fixing anything.
First: never use gets. There's simply no way to use it safely, and no excuse for even trying. It's just a badly designed function and we'd all be better off if it had never existed.
Second, in C++ there's almost never a good reason to use arrays of char for strings. strlen is pretty much the same way. These aren't as dangerous or horrible as gets but real reasons to use them in C++ (outside of things like extremely limited embedded systems) is sufficiently rare that until you know what you're doing and why, it's probably best to forget that they even exist as well.
While you're at it, using a while loop (counting down, no less) in a case like this mostly just obfuscates the code while gaining nothing in return. For that matter, using a variable name like tot instead of (for example) total or (better) pair_count is kind of silly as well.
So, having gotten bombastic about what you shouldn't do, what would I suggest instead? First, if you're going to use stream >> var type input, try to use it consistently. If you're going to read lines instead, try to do that consistently. In this case, you can use either one, but mixing the two leads to exactly the sort of problem you're having right now. As such, it's best to avoid that whole area if you can (and you almost always can).
For this, I'd use >> throughout, use std::string to hold the strings, and a for loop to execute the fixed number of iterations:
int word_count;
std::cin >> pair_count;
for (int i=0; i<pair_count; i++) {
std::string a, b;
std::cin >> a >> b;
std::cout << a.size() << b.size() << '\n';
}
Unlike the other recommendations you've gotten, this is typesafe (scanf and company don't even try to be), safe from buffer overflows (gets never is, and while scanf and company can be, they aren't when used as the other answers have recommended). It's also shorter and simpler without adding mostly-unexplained patches to cover up the real problems in the code.
If the preceding sounds harsh, I apologize for that. Unfortunately, that's sometimes just about necessary to get the point across, and at least to me, this seems like one of those times.
1. The zeroth commandment: thou shalt not use gets. If you do, you shall surely die (but not as soon as everybody maintaining your code wishes you had).
You should really try using the standard template library for string things:
std::string a, b;
int numberToAsk = 0;
cin >> numberToAsk;
while(numberToAsk!=0) {
cin >> a >> b;
cout << a.size() << ", " << b.size() << endl;
--numberToAsk;
}
(also make sure to use std::vector in stead of plain arrays!)
Also, you can avoid needing to ask for the number of entries upfront by just checking if standard input is still ok; your program will end as soon as you end the input stream (e.g. ctrl+z or F6 on windows, or ctrl+d on linux):
while(cin >> a >> b) {
cout << a.size() << ", " << b.size() << endl;
}
cin>>tot;
This code does not consume '\n' character. So the first gets call reads line between "4" and "\n". To see it you may try input
4abcd
xyz
abcd
bcda
aabc
acaa
Codechef
elfedcc
change cin to scanf works
#include <iostream>
#include <cstring>
#include <stdio.h>
using namespace std;
int main() {
char a[10001],b[10001];
int tot,s1,s2;
scanf("%d\n",&tot);
while(tot!=0) {
gets(a);
gets(b);
s1= strlen(a);
s2= strlen(b);
cout<<s1<<s2<<endl;
tot--;
s1=0;
s2=0;
}
}
Do it this way
scanf("%d ",%t);
For taking in no. of inputs. That space avoids '\n' character that you enter after entering a number input which is taken by first string. Rest of your code can be done as it is.
You need to include cstdio header. #include<cstdio>

Validating a string to be all digits

Hi I'm having trouble validating this string to be all decimals, even if I type in 9999 it still tell me my if statement comes out false. I think it's a typo but I don't know where.
cout<<"Enter a very large number"<<endl;
cin>>In1; //inputs a string
for(int i=0; 0<In1.length();i++){ //the loop that goes thru each index
if (!(isdigit(In1[i]))){ //validates each index
//tells the user to try again
cout<<"You did not enter a valid input, please try again"<<endl;
In1="";
cin>>In1;
i=0;//starts the loop over if reached
}
}
I keep receiving the "You did not enter a valid input, please try again" regardless of whether I type it right or wrong.
for(int i=0; 0<In1.length();i++){
See what you did? Change to
for(int i=0; i<In1.length();i++)
In your loop condition you need to compare i with In1.length().
You might want to change
0<In1.length()
to
i<In1.length()
Using
#include<algorithm>
if ( std::find_not_if( in1.begin(), in1.end(), isdigit ) != in1.end() ){ ...
might have prevented this unfortunate incident, and is also quite clear on the intent. The dual _not/!= muddles it slightly but still.
There are quite a few convenience algorithms, replacing common uses for simple for- statements. Most of them are on the form
do_this( where_to_start, where_to_end, do_this_operation )
There is usually nothing special or dramatic with these function, they apply the operation to each element in the start-end sequence.
You have find, count, copy, and generate to mention a few. Their purpose is to clarify the intent of your for-statement. You can find a complete list at http://en.cppreference.com/w/cpp/algorithm
You will almost certainly find that, over time, you become more adept at seperating different parts of code into the functionality that they each provide. Making debugging and later modification considerably easier.
It also makes, as Captain Giraffe points out, the intent of the code considerably more clear - something that can only make reading the code easier & quicker.
I've not used std::find_not_if, opting instead to use the method that you've chosen (based on the assumption that the important thing is knowing how to get the right answer, as opposed to simply supplying the right answer - well, that and me not knowing of find_not_if's existence :grin:) You'll see that I've chucked it into it's own function, which I call from main. The function also only performs a single task - that of checking the validity of the string. Any attempt to prompt the user for this text, re-prompt in the case of error and finally, take action on the correct input is the sole responsibility of the code that calls isValidNumericalString - there's no reason you couldn't throw those functions into their own functions, as opposed to having a single, large body of main.
#include <iostream>
using namespace std;
// returns true if all characters in string are numerical (0-9)
bool isValidNumericalString(string inputString)
{
int i, n = inputString.length();
for (i=0; i<n; i++)
if ( !isdigit(inputString[i]) )
return false;
return true;
}
int main()
{
string In1;
cout << "Enter a very large number (digits 0-9 only. 10e1 is unacceptable): ";
cin >> In1;
while (!isValidNumericalString(In1))
{
cout << "You did not enter a valid input, please try again :p" << endl;
cout << "Enter a very large number (digits 0-9 only. 10e1 is unacceptable): ";
cin >> In1;
}
cout << "Congratulations - '" << In1 << "' is a valid string representation of a number" << endl;
return 0;
}

Using C++ code in VIsual C++, no errors but some part of the code is just ignored

I'm an absolute beginner to programming and i'm just doing some exercises exercises for the beginning.
First of all, i'm using Visual C++ 2010 to compile C-Code. I just create a new project and choose an empty console application. After that, I create a ressource file named test.c and change in the file properties the elementype to C/C++ Compiler and compile as C++ Code, so that i can use #include <iostream> for the std::cin.get() command. Now the code:
#include <stdio.h>
#include <iostream>
int main()
{
int number1, number2;
int sum;
puts("Enter number 1 please:");
scanf_s("%d",&number1);
puts("Enter number 2 please:");
scanf_s("%d",&number2);
std::cin.get();
std::cin.get(); //(1)
sum = number1 + number2;
printf("The average is %f\n", sum/2);
return 0;
}
Now my problem ist that the "std::cin.get()" command is just ignored. Afer typing in the two numbers the program just stops and the console window closes.
Any idea where the problem is?
I have another question please.
Since my problem with holding the console open is solved (1), now my printf() gives me just zeros as output. I want to have a float number as output but no matter what i type in as number1 and number2 i always get "0.000000".
Since i'm still working on my little program to verify the input before it is accepted, i have another question please.
I want to use the following code just to check the input.
#include <stdio.h>
#include <iostream>
#include <ctype.h>
int main()
{
int number1, number2;
int sum;
puts("Enter number 1 please:");
scanf_s("%d",&number1);
if (isdigit(number1))
{
puts("Enter number 2 please:");
scanf_s("%d",&number2);
}
else
{
puts("Your input is not correct. Enter a number please.");
}
std::cin.get();
std::cin.get();
/*
sum = number1 + number2;
printf("The average is %f\n", sum/2); */
return 0;
}
Well it doensn't work. I type in a digit and my response is "Your input is not...". I have used the search and found the following: Check if User Inputs a Letter or Number in C. Unfortunately the suggestions doesn't help me.
It's not ignored. When you type your second number, then hit enter, it puts your number plus a newline character in the input stream. scanf removes the number, but leaves the newline character alone. When you call cin.get(), since there's a character in the stream, it doesn't wait for your input.
PigBen has already given you a good explanation of where you err. However, I have some additonla points to make about your program which won't fit into a comment:
You are mixing C and C++ input. Why? What's wrong with std::cin >> number1?
When you change number1 to double, you need to remember to change the formatting string in scanf(), too, while with IO streams the compiler will figure out everything for you. With streams and C++' strings, containers and other data structures, it's much harder to do something that compiles, but invokes the dreaded Undefined Behavior at run-time.
Also note that you do not check whether your inputting operations succeed. What happens if I invoke your program, and instead of passing it numbers, I enter non-digits? Never use input from users, files, or other externals sources unverified.
With IO streams, the input operator >> returns (a reference to) the stream, and you can use streams as if they were booleans, so you can do
if(std::cin >> number1)
// input succeeded
or
if( !(std::cin >> number2) ) // note the negation operator !
// input error
to check.
Streams enter a bad state internally after input/output errors. Any further IO operations will fail on a stream that had encountered an error. Therefore, if you want, you can delay input verification until all input operations are done:
std::cout << "Enter number 1 please:";
std::cin >> number1;
std::cout << "Enter number 2 please:";
std::cin >> number2;
if(!std::cin)
// input error
However, remember to always verify input before you first use it.
Note that I didn't check the output for errors. That's because it's hard to imagine something going wrong with output to the console. (And what would you do about it? Print an error message?) However, if you write into a file, remember to check output, too. It's easy for a file operation to go wrong.
In answer to your modified question it is because you are using ints for division. Change int sum to float sum and everything should be fine.
To answer your modified question: you're using the %f printf() format with an int, and that doesn't work. If you want to print out floating-point, you need to pass a double. You could print out (double)sum / 2 or even sum / 2.0, both of which yield doubles. (No, a float doesn't work the same for a variadic function like printf().) As it is, you're passing what is probably a four-byte type and telling printf() to treat it as an eight-byte type of different format, so it's no wonder you're not getting the expected results.
Alternately, you could switch to C++ iostreams, which save you the problem of matching types and knowing the default promotions. You'd still get an integer from sum/2, and that would drop any one-half, but it would be the right result.

Trying to use a while statement to validate user input C++

I am new to C++ and am in a class. I am trying to finish the first project and so far I have everything working correctly, however, I need the user to input a number to select their level, and would like to validate that it is a number, and that the number isn't too large.
while(levelChoose > 10 || isalpha(levelChoose))
{
cout << "That is not a valid level" << endl;
cout << "Choose another level:";
cin >> levelChoose;
}
That is the loop I made, and it sometimes works. If I type in 11 it prints the error, and lets me choose another level. However if the number is large, or is any alpha character it floods the screen with the couts, and the loop won't end, and I have to force exit. Why does it sometimes stop at the cin and wait for user input, and sometimes not? Thanks for the help!
This is an annoying problem with cin (and istreams in general). cin is type safe so if you give it the wrong type it will fail. As you said a really large number or non-number input it gets stuck in an infinite loop. This is because those are incompatible with whatever type levelChoose may be. cin fails but the buffer is still filled with what you typed so cin keeps trying to read it. You end up in an infinite loop.
To fix this, you need to clear the fail bit and ignore all the characters in the buffer. The code below should do this (although I haven't tested it):
while(levelChoose > 10 || isalpha(levelChoose))
{
cout << "That is not a valid level" << endl;
cout << "Choose another level:";
if(!(cin >> levelChoose))
{
cin.clear();
cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
}
}
Edit: numeric_limits<> is located in the limits include:
#include<limits>
From your description, it seems likely (nearly certain) that levelChose is some sort of numeric type, probably an integer.
When you use operator>> to read a number, anything that couldn't be part of a number (e.g., most letters) will be left in the input buffer. What's happening is that you're trying to read the number, it's failing and leaving the non-digit in the buffer, printing out an error message, then trying to read exactly the same non-digit from the buffer again.
Generally, when an input like this fails, you want to do something like ignoring everything in the input buffer up to the next new-line.
levelChoose appears to be an integer type of some form (int, long, whatever).
It's not valid to input a character into an integer directly like that. The input fails, but leaves the character in the incoming buffer, so it's still there when the loop comes around again.
Here's a related question: Good input validation loop using cin - C++
I suspect the part while(levelChoose > 10..... This does not restrict level to less than 10 (assuming greater than 10 is a large number in your context). Instead it probably should be while(levelChoose < 10...
To check that an expression is not too large, the following could be a possibility to validate (brain compiled code!!)
const unsigned int MAX = 1000;
unsigned int x;
cin >> x;
while(x < MAX){}