C, looping exit condition [duplicate] - c

This question already has answers here:
Why does scanf get stuck in an infinite loop on invalid input? [duplicate]
(2 answers)
Closed 8 years ago.
This is a bit of a long post so bear with me. The gist of what I am trying to do is get some user input at the beginning of a loop, do some things depending on that input and possibly repeat. Simple enough right? Here is what I have.
void displayMain(Album albums[], int num_albums){
int break_condition = 1;
int user_choice;
//keep looping until we decide to quit
while (break_condition){
user_choice = displayMenu();
switch(user_choice){
case 0 :
return; //does this need to be return 0 or can it just be return (or is it the same thing?)
case 1 :
displayAlbums(albums, num_albums);
break;
case 2 :
printf("display tracks\n");
break;
default :
printf("Invalid choice!\n\n");
break;
}
}
return;
}
The function displayMenu() basically grabs some user input and returns an int.
int displayMenu(void){
printf("Display Menu\n1. Display all albums\n2. Display the tracks in an album\n0. Return to the mainmenu\nPlease enter the choice:\n");
//grab and return the choice
int choice;
scanf("%d", &choice);
return choice;
}
So when I finally run all of this code, if I enter a "bad" choice, ie: one that takes the default path in the switch statement, the code enters an infinite loop. Repeating the contents
Display Menu
1. Display all albums
2. Display the tracks in an album
0. Return to the main menu
Please enter the choice:
Invalid choice!
I am pretty much a newb at C, so I believe I know why this is. user_choice is not ever being reset, even though the function displayMenu is clearly being called (because of the infinite loop output)
Why isn't displayMenu asking the user for input anymore after one instance of "bad" input is entered? Is it because it isn't an integer? When I tried debugging and printing out user_choice, it was some large number, so likely a register or something like that.
Please help, as I said, I suck at C, so an experienced C programmer could probably lend a hand :)

Running your code in Visual Studio 2012 (in the Cygwin Terminal executing it as a .c extension that I also tested , it works just fine) the only error that I got was that I should use the safe version of scanf( scanf_s ) instead.
If you don't want doing that the whole time when you already have declared more than one scanf in your code and the specific error pops up, you could add to your preprocessor definitions the _CRT_NO_SECURE_WARNINGS sentence . Still, I don't know the exact implications of using
the scanf_s over scanf and the opposite and how it affects the input of a program.
[ Right Click on your project--> Properties--> C/C++ -->Preprocessor Definitions and you add the sentence . ]
All the above I guess only apply if your IDE is Visual Studio and that is your case.
As for the return statement in case 0. This will force the loop to terminate and thus, it will exit the function . You can use the break statement to end processing of a particular case within the switch statement and to branch to the end of the switch instead, so the loop can be continued and display your menu again.
Returning a 0 value type will not match your function type ( as long as you have it declared as void ).

Related

why is my If condition not working? ( C language)

I'm making a train scheduling program. In my If condition, I only want to accept 10 train ids between 100 and 200. My program is running on command prompt but my If condition is totally ignored. How should I fix this so that my program will accept ids between 100 and 200 and request the user to enter the train id again if it's not obeying the condition?
My Code:
#include <stdio.h>
#include <stdlib.h>
typedef struct {
int train_id;
int train_time;
} TrainDetails;
void enterID(TrainDetails array[10]);
int main()
{
TrainDetails array[10];
enterID(array);
return 0;
}
void enterID(TrainDetails array[10])
{
int count = 1;
int enter_Tid;
while(count < 11)
{
printf("Enter Train ID :\n");
scanf("%d",&enter_Tid);
if(enter_Tid>100 && enter_Tid<200)
{
array[count].train_id = enter_Tid;
}
count++;
}
}
you should implement a slightly different approach (it was posted on a different post. Not the same thing but a similar structure that you can use: how to use a while loop to keep asking for input until the input is correct (C)?).
These are basic control flow structures, so I suggest reading a good beginners book on the basics of programming.
int tid = -1;
while (true){
printf("input an integer value: ");
scanf("%d",&tid);
if (tid > 100 && tid < 200 ){
printf("successfully read an item");
break;
} else {
printf("Invalid tid. Retry.");
}
}
If you don't want to use the break statement you can use this kind of basic control flow:
do {
printf("input an integer value: ");
scanf("%d",&tid);
} while (tid < 100 || tid > 200);
These should be inside a bigger loop where you decide how many of these train IDs you need.
Your program does not produce any output besides the "Enter Train ID" prompts, so the only way I can imagine for you to have concluded that your if condition is being ignored is by counting the number of prompts emitted before the program terminates. Seeing only ten total even in the event that you enter an out-of-range train id, you assume that the if condition that you are using to validate the inputs has been ignored.
But that depends on an aspirational expectation of how your program will behave, not a reasonable expectation of the code you actually presented. Consider, what work is performed by the code inside the if statement's body? Only one thing: assigning the entered ID to a train. So if the user enters an invalid ID then that will not happen, but everything else in the loop body still will. In particular, count is incremented at the end of the loop regardless of whether the input was valid.
You would have had more of a clue about what is going on if you had provided more feedback to the user. It is very unfriendly to reject an input without giving any notice that you have done so or any way for the user to recognize it. At least two reasonable feedback mechanisms could be easily integrated:
Update the prompt to tell the user for which train an ID is being requested:
printf("Enter the ID for Train %d :\n", count);
Add an else block to your validation test that, when executed, prints a message explaining that the ID was rejected.
I would probably do both, but the latter is the one that would make it clear that your if condition itself is working as expected. The former would help you recognize that the loop requests an ID only once for each train, regardless of whether a valid one is provided. It stores only valid IDs, but it never prompts for a replacement ID for an invalid one.

How to track amount of inputs that have been inputted by a user? C Program

EDIT: I am so sorry for the inconvenience but I had to take out the original code that I had used to submit this question. I will reupload my old code and the new code later! But the answer that is still up was very helpful in understanding how to track the number of inputs that are inputted by a user using a do ... while loop.
For this assignment, we were supposed to create a random guessing game where user inputs a number between 1 and 100 and has 3 functions (int getRandomNumber(void), int check4Win(int,int) and void printResults(int)). getRandomNumber was just made to create the random number, check4Win was just to tell the user if their guess is too high, too low, or correct and for printResults we are supposed to rank the user based on how many guesses they inputted. My issue is with printResults and what goes in main to actually keep track of how many guesses the user inputted. I was able to get the entire code to work but my main issue is being able to keep track of the number of inputs because what I have now is printing out the first input rather than the number of inputs. I will include my entire code but the main issue is printResults. The rest of them seem fine but if you think there is an issue somewhere else please let me know! I know that I used a switch statement inside the for statement in main and I am about 99.9% sure that is wrong I just couldn't figure out what else to do. Also, the formatting is off a bit here but that's just so that the code can stay together its formatted fine on my compiler! I am also fairly new to so I will take all criticism.
Thank you!
Here is a very simple example of how to count "guesses" until success. You can extend as you see fit, whether that is to move stuff into functions, add "maximum guesses" logic, use proper input handling (this will break if you input a non-integer, like hello).
int randNum = getRandomNumber();
int guessNum = 0;
int guessCount = 0;
do {
printf("Guess #%d: ", guessCount + 1);
scanf("%d", &guessNum);
// validate
if (guessNum < 1 || guessNum > 100)
{
printf("Invalid guess\n");
continue;
}
++guessCount;
// check
if (guessNum < randNum)
printf("Too low\n");
else if (guessNum > randNum)
printf("Too high\n");
} while(guessNum != randNum);
printf("Total guesses: %d\n", guessCount);
My advice is you manage input in one place. I couldn't stomach the way you're doing input in main, but then the "check4win" function tries to input values too. A function should do what its name implies. That function "checks" something, so one would expect that it returns some kind of value that indicates the result of "checking". That's all it should do. Since it's called "check4Win", I would expect it returns true if the guess "wins" and false otherwise.

How do I generate random numbers but not repeating and within a certain range based on user input?

Currently, I am experimenting some codes regarding/about random numbers. The problem is, when I run the program, input any number (ex. 12), I, sometimes get the correct and sometimes wrong answer. The correct answer must be any non repeating random numbers based on user input. (ex. input 5, output must be 1. seats[12]=1, 2. seats[19]=1,..., 5. seats[47]=1). I do not know what to do and yeah help me coders!
Here's the code:
#include<stdio.h>
#include<conio.h>
#include<time.h>
main()
{
int x,y,chc1A,seats[50]={};
printf("Enter a number: ");
scanf("%d",&chc1A);
srand(NULL);
for(x=0;x<chc1A;x++)
{
if(seats[rand()%50]==0)
seats[rand()%50]=1;
else
x--;
}
for(x=0,y=1;x<50;x++)
if(seats[x]==1)
{
printf("%d. seats[%d] = %d\n",y,x,seats[x]);
y++;
}
getch();
}
I do not really know what's wrong please enlighten me.
I run and coded this on Dev C++
What I want to do is: generate random numbers between 0-49 and putting it in an array seats[50]. (ex 38 then put 1 in array seats[38]). Btw this code represents passengers sitting on a bus with 50 seats. So the "1" means that the seat is occupied.
This part may cause problem.
for(x=0;x<chc1A;x++)
{
if(seats[rand()%50]==0)
seats[rand()%50]=1;
else
x--;
}
I think by
if(seats[rand()%50]==0)
seats[rand()%50]=1;
you meant to generate a random number, use that as index to seats and if seats[random_no] is 0, set seats[random_no] to 1.
But the random number in the if statement and the one in its body are different numbers.
You could use
int index = rand()%50;
if(seats[index]==0)
seats[index]=1;
Consider changing the signature of your main() function. See What are the valid signatures for C's main() function?
conio.h is not part of the standard, try to avoid its usage. Same goes for getch() as it's from conio.h.
srand() expects an unsigned int as argument and NULL is not of that type. See here.
Include stdlib.h to use srand().
And checking the return value of scanf() is a good idea. You can see if it failed or not.

Why am I getting this huge numbers in C?

I'm trying to teach myself C using Kernighan's book and I'm supposed to make a graph that indicates how many letters there are in each word. I haven't got to the "plotting" part as I'm getting really weird and enormous numbers at the output. Right now I'm just trying to have the value of the first and second elements of the array "arreglo" printed.
The code is the following:
#include <stdio.h>
#define ARRAY_SIZE 100
/*#define AUX 0
#define AUX2 0*/
main()
{
int s,j,noletra,i,arreglo[ARRAY_SIZE],otros, nopalabra, c;
int a;
nopalabra=1;
while((c=getchar())!=EOF)
{
if(c==' '||c=='\t'||c=='\n')
++nopalabra;
else
++arreglo[nopalabra];
}
printf("%d",arreglo[1],arreglo[2]);
}
The reason I'm trying to know the value in the second element in the array is that the first element has the correct value. The code is supposed to add 1 to the array index which is the number of words each time a space, tab or \n is typed and to add 1 to the array element whenever something different than the previously mentioned characters is typed (Letters). Right now it´s supposed to print correctly the number of the letters of two words, the first element is correctly printed but the second is a huge number, the output is:
alan amaury
^Z
4 8257542
--------------------------------
Process exited after 7.773 seconds with return value 9
Press any key to continue . . .
The output is supposed to be 4 7. I'm using a compiler in windows so EOF should be Ctrl+Z
Any help that I could get from you will be appreciated :)
At least these problems.
int arreglo[ARRAY_SIZE]; is not initialized before its elements are incremented. This is the mostly likely cause of "Why am I getting this huge numbers" #ikegami
// int arreglo[ARRAY_SIZE];
// replace with
int arreglo[ARRAY_SIZE] = { 0 };
Code can access out of array bounds as nopalabra is not confined to 0 to 99.
#define ARRAY_SIZE 100
int arreglo[ARRAY_SIZE];
++arreglo[nopalabra]; // No access protection
printf("%d",arreglo[1],arreglo[2]); only prints arreglo[1]
Logic flow is incorrect to "make a graph that indicates how many letters there are in each word."
main() return type not coded.
Some pseudo-code as an alternative
int main(void) {
set all arreglo[] to 0
int nopalabra = 0;
part_of_word = false; // Keep track of word state
loop forever {
get a character into c
if c is a separator or EOF
if (part_of_word) {
arreglo[nopalabra]++;
part_of_word = false;
nopalabra = 0;
if (c == EOF) break loop
} else {
nopalabra++;
part_of_word = true;
}
}
print out results
}
First, try the solution answered before, changing the printf() call.
If there is still a problem try:
printf("%d %d \n",arreglo[1],arreglo[2]);
Just before the while loop, to see if the "arreglo" array is initialize to 0's or just random values.
On the side:
Your call to printf() has more parameters than covered by the format string.
So you should clean up your code to something similar to
printf("%d %d\n", arreglo[1], arreglo[2]);
Concerning the strange output:
A way of getting surprising values is using non-initialised variables.
In your case the lack of initialisation affects the array arreglo.
Make sure to initialise it, so that all counting starts on a meaningful value.
Another way of getting seemingly very high values is printing several numbers next to each other, without separating white space in between.
So the " " and the "\n" in the format string I proposed are quite relevant.
the question is: "Why am I getting this huge numbers in C?"
the answer is: you have not assigned anything to arreglo array, and since you have not initialized it, you got some random values that have been there in memory. Trust me on this, I have run your code in debugger, which I also highly recommend a a standard practice while lerning to program.
Also, this is a common mistake where the format specifier is not written:
printf("%d",arreglo[1],arreglo[2]);
See if using printf("%d","%d",arreglo[1],arreglo[2]) solves your problem.
By the way, K&R book is very old, and written at the time where there have been no other C books. There are better ways to learn C.

COINS - SPOJ TLE in File reading Method

Solving the question by Memoization without the help of Maps, I got a TLE due to the method of reading the file, which shouldn't have been the case according to me. What could be the possible reason?
Here is the code that gives AC - http://ideone.com/OX1XlD
In the above code, for scanning n, if the while(scanf("%lld",&n)!=EOF) is replaced by
scanf("%lld",&n)
while(n!=EOF){ do something
scanf("%lld",&n);
}
the same gives a TLE. I can't figure out why.
I did not check your code in the link, but from the code in the question, in case of while(scanf("%lld",&n)!=EOF), you're checking the return value of scanf() itself.
OTOH, by saying
scanf("%lld",&n)
while(n!=EOF){
you're checking the value of n, which, is a completely different case and in case of scanf() failure, is undefined behaviour, if n is not initialized earlier.
The correct and preferred method,Thanks to Mr. Weather Vane will be to check against the number of items in scanf(), like
if (1 != scanf("%lld",&n))
or,
while ( 1 == scanf("%lld",&n)) //as in this case
EOF is a corner case and is usually rare.
In response to a recent comment by OP I suggest he tries this.
#include <stdio.h>
int main(void) {
long long int n;
char instr[20];
while (1 == scanf("%lld", &n)) {
printf ("The entry was %lld\n", n);
}
printf("End of file\n");
return 0;
}
The SPOJ will test your code by feeding it input from a file. Let's say inp.txt has
1
2
3
4
You then run your code with something like (in the case of Windows console)
coins <inp.txt
and this gives me the output
The entry was 1
The entry was 2
The entry was 3
The entry was 4
End of file
If this works, and your program still exceeds the time limit, you must look at your solution algorithm, since SPOJ gives no clues as to why you have a TLE.
Of course, your submitted solution must not print those cues since the output will fail the test.

Resources