Sentinel controlled while loops C# - c#

Not Homework..So I've got a simple console program to read exam scores and prints out the average and grade. So far it's the following:
public static void Main ()
{
int sum = 0;
int count = 0;
double average = 0;
Console.WriteLine ("Enter all your exam scores one by one. When finished, enter -99");
string scores = Console.ReadLine ();
while (scores != "-99") {
sum += int.Parse (scores);
count++;
scores = Console.ReadLine ();
}
if (scores == "-99") {
average = sum / count;
if (average >= 90)
Console.WriteLine ("Your average score is {0}. This is good for a letter grade of A", average);
Console.WriteLine(....more scores etc...);
Now I want to check for invalid entries with TryParse. I thought I'd stick in another while loop before the other and change the original one like this:
Console.WriteLine ("Enter all your exam scores one by one. When finished, enter -99");
string scores = Console.ReadLine ();
while (int.TryParse(scores, out numbers) == false){
Console.WriteLine("Please enter a valid integer")
scores = Console.ReadLine();
sum += int.Parse(scores);
count++;
}
while (scores != "-99" && int.TryParse(scores, out numbers) == true) {
sum += int.Parse (scores);
count++;
scores = Console.ReadLine ();
}
if (scores == "-99") {
average = sum / count;
if (average >= 90)
Console.WriteLine ("Your average score is {0}. This is good for a letter grade of A", average); ...etc...
The problem here is that if the user enters valid entries at first and then enters an invalid one, the compiler can't get back to the first while loop to check for the invalid entry. So I tried to swap the positions of the while loops. But this has the same effect; it can't get back to the first while loop to check for valid entries after an invalid one is entered. The answer is most likely simple, but I'm stuck.

The issue you are having is that you break from the first loop when the TryParse returns true, but have no recourse to re-enter the loop. Instead you should nest your loops. The loop with the sentinel should be the outer loop, and the loop that validates and re-prompts the user should be the inner loop. Here is an example:
while(scores != "-99")
{
scores = Console.ReadLine();
while((int.TryParse(scores, out numbers) == false)
{
//validation failed, re-prompt user for better number
Console.WriteLine("Bad value, try again")
scores = Console.ReadLine()
}
//do stuff here with the valid score value
}

Related

I am new here as well as into coding ! I solved a problem but i was wondering if the same problem could be solved in different/shorter ways?

The Problem:
Imagine you are a developer and get a job in which you need to create a program for a teacher. He needs a program written in c# that calculates the average score of his students. So he wants to be able to enter each score individually and then get the final average score once he enters -1.
So the tool should check if the entry is a number and should add that to the sum. Finally once he is done entering scores, the program should write onto the console what the average score is.
The numbers entered should only be between 0 and 20. Make sure the program doesn't crash if the teacher enters an incorrect value.
Test your program thoroughly.
My solution to the problem :
static void Main(string[] args)
{
int digit = 0,sum=0,counter=0;
string x;
try
{
for (int i = 0; i <= counter; i++)
{
Console.WriteLine("Please Enter Score");
x = Console.ReadLine();
bool isParsable = Int32.TryParse(x,out digit);
if (isParsable)
{
if (digit >= 0 && digit <= 20)
{
Console.WriteLine("Valid Number");
sum += digit;
counter++;
Console.WriteLine($"Student number {counter} got {digit}");
}
else if (digit == -1)
{
Console.WriteLine($"Total sum is {sum}");
Console.WriteLine($"Total number of students is {counter}");
Console.WriteLine($"Average score of {counter} students is {sum / counter}");
break;
}
else
{
Console.WriteLine("Please enter a valid score");
}
}
Console.WriteLine("Please enter Numerical Values only");
}
}
catch (DivideByZeroException)
{
Console.WriteLine("Unable to get results");
}
}

How do I make the program request user input after inputting invalid data in C#?

I am not sure how to tackle this problem. I tried putting the do while loop in the method GetUserInput and then putting the for loop in the do while loop. It doesn't reset the question it just takes the number and adds it the numbers before it. Its a supposed to be a calculator program.
//This propgram will be used to make a calculator for the class project.
//The numbers are stored as floats as well as the result. Then displayed on console.
//V1 adds a do-while loop that repeats as long as the user wants.
//V2 adds a if and else logic for when the user input a character other than a number the program will close.
//V3 added a for-loop to increase the amount of numbers that can be considered in the calculation. It makes an array
//V4 added methods to get user input and sum the numbers
class MainClass
{
public static void Main(string[] args)
{
Console.WriteLine("Hello Ulises Sanchez");
//Define 3 floating point numbers to capture the 2 inputs and the result
//floats are used to capture a broader range of numbers
float[] userInput = new float[10];
//stores the number of inputs the user requests
int numberOfUserInputs;
//define strings to store data read and also user prompts
string inputString;
string doMorefunctions = "Add More Numbers Together - y = yes - anything else for no";
//variable to test the condition to continue with calculations
bool moreActions;
do
{
Console.Clear();
numberOfUserInputs = GetuserInput(userInput);
//adds the numbers together
Summation(userInput, numberOfUserInputs);
//reset moreAction
moreActions = false;
Console.WriteLine(doMorefunctions);
inputString = Console.ReadLine();
if (inputString == "y" || inputString == "Y")
moreActions = true;
} while (moreActions);
}
//Gets the number of user inputs and stores each in the userInput array
static int GetuserInput(float[] inputArray)
{
int numberOfInputs;
string userInputPrompt = "How many numbers do you want to enter?";
//string continueMessage = "Hit any key to continue";
string errorMessage = "Invalid Input";
string inputString;
bool TryAgain;
Array.Clear(inputArray, 0, 10);
//Gets number of inputs from user
Console.Write(userInputPrompt);
inputString = Console.ReadLine();
numberOfInputs = int.Parse(inputString);
//Get inputs
for (int i = 0; i < numberOfInputs; i++)
{
Console.Write("Enter variable number {0}: ", i + 1);
inputString = Console.ReadLine();
if (Single.TryParse(inputString, out float result))
{
//if input is valid convert to float
inputArray[i] = float.Parse(inputString);
}
else
{
TryAgain = false;
Console.WriteLine(errorMessage);
inputString = Console.ReadLine();
if (inputString == "y" || inputString == "Y") TryAgain = true;
//if input is not valid input exit program
//Console.WriteLine(continueMessage);
//Console.ReadLine();
//System.Environment.Exit(1);
}
}
return numberOfInputs;
}
//takes the user input and performs a summation calculation
static void Summation(float[] inputArray, int numberOfInputs)
{
float summationResult = 0.0f;
for (int i = 0; i < numberOfInputs; i++)
{
summationResult += inputArray[i];
}
//display result to the screen
Console.WriteLine("Summation = {0}", summationResult);
}
}
We have this concept of "don't repeat yourself" (DRY) so we look for ways to make code that repeats itself not do so. Every one of your methods repeats the print/ReadLine process for asking a question
Let's have a method that asks the user for a string:
public string Ask(string q){
Console.WriteLine(q);
return Console.ReadLine();
}
Now we can say:
string name = Ask("what is your name? ");
Suppose blank input is invalid, let's use a loop to repeat the question:
public string Ask(string q){
string a = "";
while(string.IsNullOrEmpty(a)){
Console.WriteLine(q);
a = Console.ReadLine();
}
return a;
}
If the user gives no answer, they are stuck in the loop and the question is repeated until they give a valid answer
Now let's reuse this to ask for an int:
public int AskInt(string q){
return int.Parse(Ask(q));
}
Here we reuse Ask within AskInt so we don't do the print/read thing again and we leverage the "cannot renter blank" validation we already write
This however explodes if the user enters non ints
So let's use int.TryParse and keep looping while they enter garbage that doesn't parse;
public int AskInt(string q){
bool success = false;
into a=0;
while(!success){
success = int.TryParse(Ask(q), out a);
}
return a;
}
The user can only get to the last line if they enter an int
If you also want to add range validation, for example, you can put an int min, int max into your method parameters and inside the loop do success = success && a <= && a >= min
int guess = AskInt("enter a number between 1 and 10: ", 1, 10);
The idea is to write one method that does one thing really well I.e. "ask the user for a string" and then reuse that when we write the next method that does one thing well, so we end up with two methods that do two things well. Giving the methods a sensible name allows us to package up that bit of logic they do into a few words and make out code read like a book. It doesn't need as many comments then
//ask the user what their next guess is
int guess = AskInt("enter a number between 1 and 10: ", 1, 10);
This comment isn't needed; we can easily deduce the same just by reading the code.

system.formatexception in while(true) loop

The subject is a little problem:
Write a program and continuously ask the user to enter a number or "ok" to exit. Calculate the sum of all the previously entered numbers and display it on the console.
Here is my code:
var sum = 0;
while (true)
{
Console.WriteLine("Enter a number or ok to exit:");
if (Console.ReadLine() == "ok") break;
sum += Convert.ToInt32(Console.ReadLine());
Console.WriteLine(sum);
}
When I tap ok, it terminate.
When I tap number and enter, it shows system.formatexception:The input string is not in the correct format.
I know one of the solution is
var sum = 0;
while (true)
{
Console.Write("Enter a number (or 'ok' to exit): ");
var input = Console.ReadLine();
if (input.ToLower() == "ok")
break;
sum += Convert.ToInt32(input);
}
Console.WriteLine("Sum of all numbers is: " + sum);
Maybe My code looks a little weired, But Why is my code wrong?
Reason is input will be "ok". Can not convert that into an integer.
first you have to store the first input value into other variable.
then convert that string into integer and get summation.
var sum = 0;
while (true)
{
Console.Write("Enter a number (or 'ok' to exit): ");
var input = Console.ReadLine();
int newVariable = 0;
if (input.ToLower() != "ok")
{
newVariable = Convert.ToInt32(input);
}
input = Console.ReadLine();
if (input.ToLower() == "ok"){
break;
sum += newVariable;
}
}
Console.WriteLine("Sum of all numbers is: " + sum);
If there any problem here please let me know.
Try this:
var sum = 0;
while (true)
{
Console.WriteLine("Enter a number or ok to exit:");
String ans = Console.ReadLine();
if (ans == "ok" || ans.ToLower() == "ok") break;
sum += Convert.ToInt32(ans);
Console.WriteLine(sum);
}
Here I've just store input entered by user in one variable and use that variable in further process.
In your first code you have take input two times, first one is in IF condition and second in parsing, that may cause the problem.
The correct way to do this is to use int.TryParse for your conversion from a string to a number. TryParse attempts to convert the string to a number, but if it cannot do so (for example, the string contains more than just numeric digits) it will fail gracefully instead of causing an exception. The other answers so far will all cause an unhandled FormatException if something non-numeric is entered other than "ok". By using int.TryParse you can handle the case where it's a valid number, as well as the case where it is invalid, and then alert the user. Here's an example within the context of your code:
// I prefer using concrete types for numbers like this, so if anyone else
// reads it they know the exact type and numeric limits of that type.
int sum = 0;
int enteredNumber = 0;
while (true)
{
Console.Write("Enter a number (or 'ok' to exit): ");
var consoleInput = Console.ReadLine();
if (consoleInput.ToLower() == "ok")
break;
if(int.TryParse(consoleInput, out enteredNumber))
{
sum += enteredNumber;
}
else
{
Console.WriteLine("You entered '" + consoleInput + "', which is not a number.");
}
}
Console.WriteLine("Sum of all numbers is: " + sum.ToString());
This is better because you know you have no control over the user's input other than to validate it yourself, and so it's better to speculatively convert the number and be alerted to success or failure without triggering an exception. Wrapping everything with a try/catch block is not a proper solution.
Your first code example, as rightly pointed out in the comments, reads a line, tests it for 'ok', then throws it away, reads another line, and uses that to add to the sum, which is not what you wanted.
After some quick research, I would say the most concise way to handle this in C# is probably something like your second code example. In F# I was able to come up with the following examples (one is a loop, the other uses sequences, i.e. IEnumerable<_>s) but I found no concise way to get the same with C# and LINQ…
let inputLoop () =
let rec aux sum =
match stdin.ReadLine () with
| "ok" -> sum
| s -> aux (sum + int s)
stdout.WriteLine (aux 0 |> string)
let inputSeq () =
fun _ -> stdin.ReadLine ()
|> Seq.initInfinite
|> Seq.takeWhile (fun s -> s <> "ok")
|> Seq.sumBy int
|> string
|> stdout.WriteLine
Try it :)
var sum = 0;
while (true)
{
Console.Write("Enter a number: or ok to exit : ");
String input = Console.ReadLine();
if (input == "ok" || input.ToLower() == "ok") break;
if(string.IsNullOrWhiteSpace(input))
continue;
sum += Convert.ToInt32(input);
}
Console.WriteLine("Total Result: " + sum);
Write a program and continuously ask the user to enter a number or "ok" to exit. Calculate the sum of all the previously entered numbers and display it on the console. Happy Coding
var sum = 0;
while (true)
{
Console.Write("Write number or write \"ok\" for exit: ");
var input = Console.ReadLine();
if (input.ToLower() != "ok")
{
sum += Convert.ToInt32(input);
continue;
}
break;
}
Console.WriteLine("All sum: " + sum + ".");
This is one way to do it. I'm just learning to do this!
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Enter number to know the sum or press ok to exit and display the sum");
int sum = 0;
while (true) // to run the program continously asking user input
{
Console.WriteLine("Enter Number: ");
var input = Console.ReadLine(); // takes user input
if (input.ToLower() == "ok") // compares user input to string ok
break; //if user input is ok, breaks the loop and sum is displayed
var inputInInt = Convert.ToInt32(input); // if user input is int, continues to convert it to integer
sum += inputInInt; // user input in interger is added to sum
}
Console.WriteLine("The sum of entered numbers is: " + sum);
Console.ReadLine();
}
}

C# While Loop (adding the user input to reach a target)

I need to create a program that adding the user input to reach a target, as a result, is just like below.
I have to use 'While Loop' for this,
but it is difficult for me to use while loop...
Here is my code
Console.WriteLine("Enter Target Value: 6");
int total = 0;
int target = 6;
int i;
for (i = 1; i <= 4; i++)
{
Console.Write("Enter #{0}:\t", i);
total += Convert.ToInt32(Console.ReadLine());
}
while (total == target);
Console.WriteLine("It took {0} inputs to take the sum to\t{1}",i, total);
Console.ReadLine();
Could you please help me to find the problems?
Do you know what number the user will enter? No, you do not know. So you do not know how many numbers will it take to reach the sum as well.
Pick the right tool for the job.
For Loop
A "For" Loop is used to repeat a specific block of code a known number of times.
While Loop
A "While" Loop is used to repeat a specific block of code an unknown number of times,
Given the above 2 options, your pick should be a while loop since you do NOT know how many times you will need to ask the user to enter a number to reach the sum. It may be 1 or many, many times.
In C#, there is also the do while loop, which is to be used if you know you must do something at least once and possibly more, Therefore, for your case the best option would be to use do while.
You may read more on while loop, for loop, and do while.
Here is the complete example.
static void Main(string[] args)
{
try
{
int i = 0;
int number;
int input=0;
Console.WriteLine("Enter target number ");
number = int.Parse(Console.ReadLine());
while (input != number && input < number)
{
Console.WriteLine($"Enter number {i+1}");
input += int.Parse(Console.ReadLine());
i++;
}
Console.WriteLine($"It took {i} number to make the sum {number}");
}
catch (Exception e)
{
}
Console.ReadLine();
}
Your code is perfectly operational. I hope this helps:
Console.WriteLine("Enter Target Value: 6");
int total = 0;
int target = 6;
int i = 1;
while (i <= 4)
{
Console.Write("Enter #{0}:\t", i);
total += Convert.ToInt32(Console.ReadLine());
i++;
}
while (total == target);
Console.WriteLine("It took {0} inputs to take the sum to\t{1}",i, total);
Console.ReadLine();

Finding out whether a number is a palindrome or not in C#

I am new to C# and was doing this program as an exercise. I have managed to get my program to print the reversed number of the input given by the user, but when I move onto checking whether it is a palindrome or not, it does not calculate the answer correctly. It always prints 'not a palindrome'.
After some error checking, I realized that the reason why it was doing this is because the last number that gets stored in newnum is just the last digit after being reversed and not the entire number. How can I rectify this??
My Code
int i, remainder = 0, newnum = 0;
Console.WriteLine("Enter a Number: ");
int uinput = Convert.ToInt32((Console.ReadLine()));
for (i = uinput; i > 0; i = (i / 10))
{
remainder = i % 10;
Console.Write(remainder);
newnum = remainder;
}
if (newnum == uinput)
{
Console.WriteLine("The Number {0} is a palindrome", uinput);
}
else
{
Console.WriteLine("Number is not a palidrome");
}
Console.WriteLine(uinput);
Console.WriteLine(newnum);
Console.ReadKey();
}
I also looked online at another code example, but the thing I don't understand in that is why num is being converted to boolean type in the while loop? Is that just to keep the loop running?
The Code reffered to above
int num, rem, sum = 0, temp;
//clrscr();
Console.WriteLine("\n >>>> To Find a Number is Palindrome or not <<<< ");
Console.Write("\n Enter a number: ");
num = Convert.ToInt32(Console.ReadLine());
temp = num;
while (Convert.ToBoolean(num))
{
rem = num % 10; //for getting remainder by dividing with 10
num = num / 10; //for getting quotient by dividing with 10
sum = sum * 10 + rem; /*multiplying the sum with 10 and adding
remainder*/
}
Console.WriteLine("\n The Reversed Number is: {0} \n", sum);
if (temp == sum) //checking whether the reversed number is equal to entered number
{
Console.WriteLine("\n Number is Palindrome \n\n");
}
else
{
Console.WriteLine("\n Number is not a palindrome \n\n");
}
Console.ReadLine();
Any sort of help is much appreciated!! Thank You :)
I'm not sure what you're asking, since the second snippet of code you found online should fix your issue.
Your code works, if you just change the line
newnum = remainder;
to
newnum = (newnum*10) + remainder;
The issue in your case is not the condition you used in the for loop, it's just that you're overwriting newnum with the remainder every time, so newnum is only storing the last reminder that was calculated in the loop, "forgetting" all the others it had calculated before.
To reverse the number, every time you enter the loop, you should add the last remainder you've found to the right of newnum, which is effectively equivalent to multiplying everything by 10 and adding remainder.
Try to follow it step by step with pen and paper (or with a debugger).
public bool isPalindome(int num)
{
string sNum = num.ToString();
for (int i = 0; i<sNum.Length; i++)
if (sNum[i] != sNum[sNum.Length-1-i]) return false;
return true;
}
I think that will do it... Untested!!
As dognose (and Eren) correctly assert you only need to go halfway through
public bool isPalindome(int num)
{
string sNum = num.ToString();
for (int i = 0; i < sNum.Length/2; i++)
if (sNum[i] != sNum[sNum.Length-1-i]) return false;
return true;
}
You will also need to decide what happend to negative numbers.. ie is -121 a plaindome? This method will say that it isn't...
Easiest way:
public static Boolean isPalindrom(Int32 number){
char[] n1 = number.ToString().ToCharArray();
char[] n2 = number.ToString().ToCharArray();
Array.Reverse(n2);
String s1 = new String(n1);
String s2 = new String(n2);
return (s1 == s2);
}
https://dotnetfiddle.net/HQduT5
you could also use Integers for s1 and s2 and return (s1-s2 == 0)
You have many ways of accomplish this exercise.
A. You can leave the input as string and loop it over, every iteration to check if the value of index 'i' and value of index 'len-i-1' are equals, if not false, otherwise return at the end of the loop true. (the loop should run till i < len/2)
B. You can create a new string and insert the text from end to start and then compare if the original string and result string are equals.
C. there are much more ways without using the string solutions, just with calculation..
int x;
cin<<x; //input the number
int ar[];
int i=0;
temp2=0;
while(x/10 != 0)
{
int temp=x%10;
ar[i]=temp;
x=x/10;
i++;
}
for(int j=0, j<i,j++)
{
temp2=temp2*10+ar[j];
}
if(temp2==x){cout<<"palindrome"}
else {"not palindrome"}
ok here is the logic:
we first input the number x(it can be of any length)..Next we split the number into array..the condition to do this is tha we check for the qoutient to decide whether the number is fully split..next we take the array and rejoin it and check with the input number..
Use the following code:
public boolean isPalindrom(Integer number)
{
return number.Equals(int.Parse(String.Join("", String.Join("", number.ToString().ToCharArray().Reverse().ToArray()))));
}

Categories

Resources