Accessing and changing local variable inside while loop C# [closed] - c#

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
I am currently trying to define two integer variables by user input. If the user inputs an integer which is not contained in the defined range, the user will be asked to input again, until the user inputs an accepted value.
static void Main(string[] args)
{
int a;
int b;
bool isAValid = false;
bool isBValid = false;
while (isAValid == false)
{
Console.Write("Input number from 2 to 20: ");
isAValid = true;
a = Convert.ToInt16(Console.ReadLine());
if (a < 2 || a > 20)
{
isAValid = false;
}
}
while (isBValid == false)
{
Console.Write("Input number from 2 to 20: ");
isBValid = true;
b = Convert.ToInt16(Console.ReadLine());
if (b < 2 || b > 20)
{
isBValid = false;
}
}
}
What I am trying to accomplish, is saving the user input as a and b respectively, so the local variable value is defined as the user input value. However, when I try to access the local variable after the last while loop is broken, I get the "Use of unassigned local variable a (or b)".
Any ideas how I can define the variables, while still having the input prompt loop?

It's funny that the compiler cannot see that the while loops are always entered, and a and b are always initialized.
Update: Eric Lippert commented that for the purpose of flow control analysis all expressions involving variables are considered possibly true or false; even expressions like x*0 == 0.
We see that the while condition is always true, partly because we know this little logic pattern for input. We know what the loop is about. The compiler doesn't. It sees an arbitrary condition and can't be bothered to prove that it is always true. It simply considers all expressions with variables non-constant.
One way to fix this is to express the logic of the program better in the language. Such a pattern is not uncommon: "Repeat something until a condition is satisfied". In particular, do it at least once in any case. There is a language construct for that in all C family languages: The do/while loop. Rewriting the loop for a gives
do
{
Console.Write("Input number from 2 to 20: ");
isAValid = true;
a = Convert.ToInt16(Console.ReadLine());
if (a < 2 || a > 20)
{
isAValid = false;
}
} while (isAValid == false);
Now I can access a after the loop; the compiler recognizes that the assignment will be guaranteed. The same should work for b.
This also enables us to write less cluttered code. The ancillary variable isAValid is needed only because of the "artificial" test when the while loop is first entered. The test is artificial because we do not have any input yet and hence cannot really test anything. If we indeed test only after the input, so that test data is available, we can put the test right into the condition. It boils down to
do
{
Console.Write("Input number from 2 to 20: ");
a = Convert.ToInt16(Console.ReadLine());
} while (a < 2 || a > 20);

To fix your error, declare this:
int a = 0;
int b = 0;
Instead of:
int a;
int b;
This will initialized your local variables and will fix your error message.

Related

There is a better way of avoiding null inputs in Console.ReadLine instead of if statements [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
Everthing if fine with the code by now but there is a better method to avoid null inputs in Console.ReadLine, I already have tried if statement but the code end up looking like a mess.
class ColocarMoedas
{
public static void Colocar(MaquinaUsuario user)
{
int m1, m5, m10, m25, m50;
Console.Clear();
Console.WriteLine("/////////////////////////MOEDAS////////////////////////////");
Console.Write("1 Centavo: ");
m1 = int.Parse(Console.ReadLine());
Console.Write("5 Centavo: ");
m5 = int.Parse(Console.ReadLine());
Console.Write("10 Centavo: ");
m10 = int.Parse(Console.ReadLine());
Console.Write("25 Centavo: ");
m25 = int.Parse(Console.ReadLine());
Console.Write("50 Centavo: ");
m50 = int.Parse(Console.ReadLine());
user.Adicionar(m1, m5, m10, m25, m50);
Console.Clear();
}
}
There is a better way of avoiding null inputs in Console.ReadLine
instead of if statements
The answer is yes.
Though it's worth noting, there are more things that can go wrong with user input than just null. In fact null is pretty rare, it's everything else you need to worry about.
The most idiomatic way to validate user numeric input is with TryParse style methods, which return a bool when the value can't be parsed and returns a value through an out parameter when true.
Int32.TryParse Method
Converts the string representation of a number to its 32-bit signed
integer equivalent. A return value indicates whether the operation
succeeded.
You can take it a step further by using a validation loop
int m1 = 0;
while (!int.TryParse(Console.ReadLine(), out m1))
Console.WriteLine("You hard one job! Now try again");
Essentially the above says, while the number can't be converted to an integer, which includes typos, empty input, and Ctrl+c (null), write a message.

C# How to make use of return true/false from a method (outside of loop) called from within a while loop

I am trying to write a program that lets me enter a list of names with their respective film rating into an array (Would do a list but the course material wants me to use array). Before I add the names to the array I want to make sure that a valid rating has been entered.
I am currently using a for statement that cycles through he array length and lets the user enter each movie to the list that way. This happens in a while loop to make them re-enter the name if the rating is invalid before the name is committed to Array. I check the names by calling a method with a temporary string assigned with the current entered name and rating which will do some conditional checks and return either false or true depending on the outcome. But the way I am doing it is not working at all..
Problem is that I have no idea how to make practical use of the bool statement my method returns:
string[] filmNames = new string[ArrayLength];
for (int i = 0; i < filmNames.Length; i = i + 1)
{
bool ratingFail = true;
int displayNumber = i + 1;
while (ratingFail)
{
Console.Write($"> Enter the Name and Rating of film number {displayNumber} of {ArrayLength}: ");
string checkRating = Console.ReadLine();
CheckRating(checkRating); // currently just does "return false;" for testing purposes
if (true) // this statement is clearly not effected by whatever the return value is from above method. Why? What to do?
{
ratingFail = true;
}
else
{
filmNames[i] = checkRating; // this bit is marked as unreachable, which is is.
ratingFail = false;
}
}
}
my test method:
public static bool CheckRating(string checkRating)
{
return false;
}
I am VERY (a week) new to programming and C# so please keep in mind when answering that I may not understand particular lingo referring to programming terms outside of the scope of what you can see here within, but I will Google and research to the best of my abilities if there is no way to simplify what you want to say. Thank you for your time and effort.
if (true) // this statement is clearly not effected by whatever the return value is from above method. Why? What to do?
{
ratingFail = true;
}
This will always be true, because you're creating a variable that is always true. You want this:
ratingFail = CheckRating(checkRating)
if (!ratingFail) {
The rating is valid, do stuff here.
}
If ratingFail is true, the loop will continue.
This assumes that CheckRating returns true if the input is invalid, and false if it is valid. The variable naming here is pretty confusing, and I recommend you refactor.
I would do it this way, assuming CheckRating returns true if valid:
for (int i = 0; i < filmNames.Length; i = i + 1)
{
bool ratingValid; // Defaults to false
int displayNumber = i + 1;
while (!ratingValid)
{
Console.Write($"> Blablabla: ");
string input = Console.ReadLine();
ratingValid = CheckRating(input);
}
// Do stuff if rating is valid here. If you got here, rating is valid.
}
// edit by iluvpancakes //
I decided to add a comment made by #Sinatr since that was the (version of the) solution I personally ended up using:
if(CheckRating(checkRating))
{
[do stuff and things]
}
bool ret = CheckRating(checkRating); // currently just does "return false;" for testing purposes
if (ret)
{
[...]
}
Or, like Sinatr's comment:
if(CheckRating(checkRating))
{
[...]
}

C# goto user input

I am making an OS with Cosmos and want to use goto to go to the user input but I am getting the error
No such label 'input' within the scope of the goto statement
'input' is a variable in which the user has inputted.
I can understand why this is happening but how do I fix it?
You cannot user variables as scope identifier for goto statement.. you have to use label identifier within scope (namespace) indicating it by ":" ..
for example
using System;
class Program
{
static void Main()
{
Console.WriteLine(M());
}
static int M()
{
int dummy = 0;
for (int a = 0; a < 10; a++)
{
for (int y = 0; y < 10; y++) // Run until condition.
{
for (int x = 0; x < 10; x++) // Run until condition.
{
if (x == 5 &&
y == 5)
{
goto Outer;
}
}
dummy++;
}
Outer:
continue;
}
return dummy;
}
}
method M contains three nested loops. The first loop iterates through numbers [0, 9], as do the two inner loops. But in the third loop, a condition is checked that causes the loop to exit using the break keyword.
For
Break
The code increments the dummy variable after each completion of the inner loop. If the inner loop is exited early, this variable should be left alone. With the goto statement, it is not incremented.
Result:
The value 50 is printed to the console. The int is incremented 10 x 5 times.
However:
If the goto was a break, the result would be 10 x 10 times, or a total of 100.
Hope this Help.. :)
I am making an OS with Cosmos
For getting any remotely useful answers, I think you will have to give some information about the scope of the OS. Are you only fiddling around with COSMOS a bit, or do you have some special use-case you want to serve with a custom COSMOS OS?
and want to use goto to go to the user input
Especially in the latter case (specialized OS) you should clearly refrain from using GOTO, unless you have a very good reason to do so (and in my humble opinion there is no such thing as a really good reason to use GOTO). There are viable alternatives to GOTOs in modern programming languages and you should re-think your design, algorithm, whatsoever.
To answer your question. Here is an example that produces the very error message you are experiencing
private void FirstMethod()
{
goto MyLabel;
}
private void SecondMethod()
{
MyLabel:
return;
}
I have defined a label in Method. Anyway, from Main you cannot simply jump from main to another method, since the compiler would not know where to return to, after the method has finished, since no data would have been pushed to the call stack on GOTO (please see the Wikipedia page about the call stack for further information).
The following, anyway, would work, since the label and the GOTO live within the same scope
void MyMethod()
{
goto MyLabel;
// do something
MyLabel:
return;
}

How to get value in conditional statement in c# outside of that conditional statement?

How to get value in conditional statement in c# (example in a if statement and you want the value in the if statement be used outside it ) how?
example
int a, b, c;
if (a > 3)
{
c = 20;
}
else if (b < 3)
{
c = 10;
}
//how do i get the value of c outside the conditional statement??
Console.WriteLine("{0}", c);
//it always says local variable unassigned local variable
*update supposedly my code is correct and i
ve declared a; and i want to use the value of a outside the conditional statement.
*update all i want to know is to get the value of c outside the conditional
It seems you declared a but didn't initialize it.In C# you should initialize local variables to something before the first usage. If your if statement evaluates to false then a will remain uninitialized.And even if it would evalute to true you are trying to read its value (in x++) before initializing it, so it will still be a problem. To fix that just initialize it with a default value while declaring:
int a = 0;
In this case a should be declared outside the if statement. IE
int a = 1;
if(condition){
a=a++;
}
console.WriteLine("{0}",a);
However, there are several issues with your code. Most notably, are you sure you want to be doing a=a++? This code is redundant, you should be doing just a++.
I suspect your real issue lies outside the code you shared. If you post more code I can refine my answer to help you more.
In your new code example, the problem is that you've declared variables a, b, and c but have not initialized them. An if statement might be entered and it might not be entered so any assignments done inside of an if statement might not be executed.
You need to tell the compiler what the initial values of a, b and c are before you can use them, which I think almost everyone here has already been saying. Try changing your code to this:
int a = 0, b = 0, c = 0;
if (a > 3)
{
c = 20;
}
else if (b < 3)
{
c = 10;
}
//This should print out 10
Console.WriteLine("{0}", c);
//no more compile errors will occur
Notice that a, b, and c have been given default values of 0 so in the event that the if statement is not entered, they will still be assigned a usable value.
Also, if a = 0 and b = 4 then the entire if block is skipped, leaving c untouched which is where its default value of 0 will be printed to the console.
Another option, which isn't the best thing to do in my opinion is the following
int a = 0, b = 0, c;
if (a > 3)
{
c = 20;
}
else if (b < 3)
{
c = 10;
}
else
{
c = 1;
}
Console.WriteLine("{0}", c);
This will compile even though you're not initializing the c variable because in a round about way you are; in the final else the variable is assigned 1 so there would be no case were c is not initialized.
Your problem is not c at all; your problems are a and b. You just need a bit more understanding how the compiler works.
Let's put it this way: you have...
int a, b, c;
Here, you're telling the compiler that it will use 3 variables that somewhere, eventually, will contain int values; but now they don't have nothing, they're empty (note: not 0; empty) or as known in C#, they're null.
When the compiler reaches here:
if (a > 3)
{
c = 20;
}
it says: "whoops! I need to check if a is less than 3, but before this line a is never assigned a value, it's empty, and I can't check it like that. I'll better throw an error."
Same happens with the next condition.
If, as other answers say, before the condition you assign them a value, the compiler will be able to compare and use them.
Now let's take a look at your original code:
int a;
//I'll asume you declared a the same way that the other code
if (condition)//this is true
{
a = a++;
}
//how do i get the value of a?
Console.WriteLine("{0}", a);
//it always says local variable unassigned local variable
When the compiler reaches to Console.WriteLine("{0}", a);, it says: "Hmmm... I have to print a, but it has a value only if conditionis true, but if it is false, I won't be able to print it because it'll be empty. Better throw an error now than when running!"
As you see, is all about using your variables only after you're sure that all possible ways that lead to your line of code assign a value to that variable.

Use of unassigned local variable being a pain

I'm trying to make a program that finds the factors of a number. I made a fairly simple one but it always repeated the same two factors twice i.e. 1 and 2, 2 and 1. So, to fix that I tried to check if the number had been used before but it keeps saying the bool proceed is unassigned.
using System;
namespace FactorableOrNah
{
class MainClass
{
public static void Main (string[] args)
{
Console.WriteLine ("Enter a whole number to view its factors: ");
int userInput = int.Parse(Console.ReadLine ());
int[] antiDoubler = new int[userInput];
bool proceed;
Console.Clear();
for (int i = 1; i != userInput; i++) {
antiDoubler[i] = userInput / i;
for(int j = 0; j < userInput; j++) {
if (antiDoubler [j] == i)
proceed = false;
else
proceed = true;
}
if ((userInput % i) == 0 && i != 1 && proceed == true)
Console.WriteLine("{0} and {1}", i, (userInput / i));
}
}
}
}
Using uninitialized variables in C# is not allowed. The compilation error can be solved by using either:
bool proceed = false;
or
bool proceed = default(bool);
since the default value of bool is false;
However, the algorithm is too complicated and very hard to read. Just for fun. A recursive example.
static IEnumerable<int> GetFactors(int number)
{
return GetFactors(number, number);
}
static IEnumerable<int> GetFactors(int number, int check)
{
if (check > 0)
{
if (number % check == 0)
{
yield return check;
}
foreach (var f in GetFactors(number, --check))
{
yield return f;
}
}
}
UPDATE:
Local variables cannot be left uninitialized, however class members (static members and instance variables), furthermore array elements are initialized automatically by the memory manager, so they are never uniitialized.
From the specification:
A variable must be definitely assigned (ยง5.3) before its value can be
obtained. As described in the following sections, variables are either
initially assigned or initially unassigned. An initially assigned
variable has a well-defined initial value and is always considered
definitely assigned. An initially unassigned variable has no initial
value. For an initially unassigned variable to be considered
definitely assigned at a certain location, an assignment to the
variable must occur in every possible execution path leading to that
location.
For your case you have an initially unassigned variable. Thus, the variable must be set in every possible execution path. There is one possible execution path to which your variable is not defined - when userInput >= j.
This would happen if userInput is 0. Following your program manually:
The first for case will check if i != userInput. Since i = 1 this is true, thus it will continue in the for loop.
the second for case will check if j < userInput. Since j = 0 this is false, thus it will skip the for case and never set proceed
Now you have arrived to where you check proceed and it was never set. So the compiler tells you that this is not allowed.
To solve your issue, you have to decide whether to:
define a default value for proceed, for instance false and set it at declaration, i.e. bool proceed = false;.
Rewrite your logic so that you do not need the boolean, for instance like Daniel Leiszen suggests.

Categories

Resources