I'm working on a small project right now that allows a user to choose an array editing function from a switch statement. Unfortunately, I coded it poorly (I can't make the switch menu its own function at this point, it is part of main().) I only bring this up to prevent suggestions involving calling a menu function. I also cannot use main() recursion because I take user input for the array and do not want to replace the existing values.
The code below is supposed to take user input to decide whether to exit the program or to re-open the selection screen and
char restart = 'y';
do {
printf("Would you like to try a different function? (Y/N): ");
restart = getchar();
restart = getchar();
system("clear");
goto START; // "START" is the label for my main selection screen function.
} while ( restart == 'Y' || restart == 'y');
system("clear");
printf("Okay, thank you!\n\n");
for (i = 3; i > 0; i++) {
printf("Exiting in %d seconds...", &i);
sleep(1);
}
(At the end of main() I included an exit function.)
I have two questions:
How can I detect if the user inputs an invalid character? (Not n, N, y, Y) I was initially going to build this with if-else statements, but realized that was ineffective. However, now I no longer know how to work with the do-while loop to detect these inputs.
This code simply doesn't work. What'd I do wrong? When inputting y or Y, the loop never exits. Should I embed the do-while loop in a while loop utilizing breaks?
My only theories right now (as a baby C programmer) are that labels don't work with this method or that I have no real way to break from the loop.
Thank you!
The code is taken from an exam question which I did not know the answer for:
int c = 0;
while (c < 5)
{
if (c == 2)
{
continue;
}
printf ("data %d", ++c);
}
I know that it prints nothing, but I would like to know why?
Any help would be appreciated.
By default, on POSIX systems, stdout is a buffered stream which will only flush when it hits a line feed or when it's explicitly asked to flush using fflush(stdout);
Add fflush(stdout); after the printf() call and then your program should output:
data 1data 2
After that, your program will be stuck in an infinite loop, because the condition in your while statement will always be evaluated to true.
There are some buffering issues. If you add fflush(stdout) after the printf, you get data 1data 2. It doesn't go further than data2 because once c is equal to 2, it will keep hitting the if case and skipping the increment. Try the following and you will get data 1data 2:
int c = 0;
while (c < 5)
{
if (c == 2)
{
continue;
}
printf ("data %d", ++c);
fflush(stdout);
}
Once c == 2 is true, then you will stay in the loop and keep hitting the if statement. So you'll never increment once c is set to 2.
int c = 2;
if(c == 2) {
continue;
}
printf("%d", c); // this will never get hit once c is 2 since continue will
//make the program jump to the next iteration of the loop.
//Also by not flushing after the print, you aren't clearing the buffer and are then not accepting the next print.
You don't need to fflush(stdout) if the infinite loop is fixed though.
I am a beginner in C programming and I'm trying to do basic stuff. I'm trying to create a simple menu using a switch statement like this:
int disp(){
int check;
while(check!=1){
int choose;
printf("1 \n");
printf("5quit\n");
scanf("%d", &choose);
switch(choose)
{
case 1:func1();
break;
case 5: check = 1;
break;
default:
printf("wrong input");
}
return 0;
}
}
However, when either default or case 1 happen, I want to make it still loop the menu until a good input is made. For example, if I enter random stuff like "asdf", the program should say "wrong input" and then display the menu again and wait for user input. And if user enters "1", the program will run func1 and then go back to the menu and wait for the user to input a choice.
Currently, when a wrong input happens it just shuts down the program instead of displaying the menu again, and I don't know how to solve that.
Your return 0 statement is inside of your while loop. Move it down one line, outside of the loop.
This is one reason why proper indentation is important.
At this point, entering in non-numeric input results in an infinite loop because scanf isn't reading in anything. To remedy this, you call getchar in a loop after calling scanf to flush the buffer:
int c;
scanf(" %d", &choose);
while ((c=getchar()) != EOF && c != '\n');
This is correct and close to what you want
// Use a proper formatting standard to improve readability
int disp() {
int check = 0; // Initialize the loop variable
while (check != 1) {
int choose;
printf("1 \n");
printf("5quit\n");
scanf("%d\n", &choose); // Ask the scanf to swallow the newline
switch(choose) {
case 1:
func1();
break;
case 5:
check = 1;
break;
default:
printf("wrong input");
}
}
return 0; // Pull the statement out of the loop
}
EDIT: Since you are providing invalid input intentionally, it's better to check the return value of scanf to avoid errors.
I've been introduced to C this year as part of my degree, during which I have to write simple programs and test them to be idiot-proof by running them over and over again, putting nonsense variables in, etc. and I had an idea to write a program with the ability to restart itself without having to run the program again.
I've tried writing a program to perform this function (which turned out to be harder than I first thought) and I now have it working, albeit using a goto function that are frowned upon. Now the only problem I have is a while loop to check for nonsense input, that seems determined to run at least once ignoring a prompt for a valid input.
Please could someone give me an idea why this is happening? (My compiler is Dev-C++ 4.9.9.2)
int main (void)
{
mainprogram:
printf("\nPROGRAM START\n");
//code copied from an exam, to check that the program performs a function
//when ran through again
int i,j,k;
printf("Please enter 7:");
scanf("%d",&i);
printf("Please enter 4:");
scanf("%d",&j);
printf("Please enter 0:");
scanf("%d",&k);
//this is to check that the program will take input when it is restarted
do {
switch (i%j) {
case 3:
i--;
k*=i;
break;
case 2:
i--;
k+=i;
default:
i--;
k++;
break;
}
printf("i is %d k is %d\n",i,k);
} while (i>0);
//end of copied code
char prompt='y';
printf("\nRestart program?");
scanf("%c",&prompt);
while (prompt != 'y' && prompt != 'Y' && prompt != 'n' && prompt != 'N')
{
//this is the problem section, when entering nonsense input, the error messages
//display twice before pausing for input, and when restarted, the program does
//run again but displays the error messages once before pausing for input
printf("\nERROR: INVALID INPUT");
printf("\n\nRestart program?");
prompt='y';
scanf("%c",&prompt);
}
if (prompt == 'y' || prompt == 'Y')
{
goto mainprogram;
}
//
return 0;
}
while(1){ //parent
printf("\n\nRun program?");
scanf("%c",&prompt);
if (prompt == 'n' || prompt == `N`)
{
printf("\nEXITINT")
return 0;
}
int i,j,k;
printf("Please enter 7:");
scanf("%d",&i);
printf("Please enter 4:");
scanf("%d",&j);
printf("Please enter 0:");
scanf("%d",&k);
switch (i%j)
{
case 3:
i--;
k*=i;
break;
case 2:
i--;
k+=i;
break;
default:
i--;
k++;
break;
}
printf("i is %d k is %d\n",i,k);
} //end while parent
//end of copied code
There are a couple of ways one could restart a program, or more generally loop over some code. Of course, all of that can be done with gotos, but that makes the code hard to understand, so C has equivalent structures for dealing with the most common patterns:
execute code if and as long as condition holds
while (condition)
{
/* code */
}
This means before executing the code, the condition is checked. If the condition holds (its value is non-zero), the code is executed and then looped back to the top. This is equivalent to:
top_of_while:
if (!condition)
goto done;
/* code */
goto top_of_while:
done:
execute code and redo while condition holds
do
{
/* code */
} while (condition)
This means execute code first and then check for a condition. If the condition holds, executed the code again. This is equivalent to:
top_of_do_while:
/* code */
if (condition)
goto top_of_do_while;
iteration
for (initialization; condition; iteration)
{
/* code */
}
This is a kind of while loop that happens a lot, in which there is an initialization, followed by a while loop, which on the bottom changes a variable to form some sort of iteration. This is equivalent to:
initialization;
while (condition)
{
/* code */
iteration;
}
To restart a program, most likely you want the do-while loop, since for sure you know that the program has to execute once. However, by properly initialization the condition variable of a while loop, you can also ensure that the loop is always entered the first time. It's a matter of style and your liking.
Where to actually use goto
Many people would tell you to never use goto. This roots from the fact that overuse of goto had led to a great number of overly complicated programs, the so-called spaghetti code. The reason is that it's hard to build a mental model of a program where the execution can jump around to any other part.
However, gotos are actually very useful in C, without which error-handling becomes a huge pain in the ... neck. This useful usage of goto is for handling errors and cleanup, which are always in the bottom of the function. An example would be:
int *read_nums(int n)
{
int *array, i;
array = malloc(n * sizeof *array);
if (array == NULL)
goto exit_no_mem;
for (i = 0; i < n; ++i)
if (scanf("%d", &array[i]) != 1)
goto exit_bad_input;
return array;
exit_bad_input:
free(array);
exit_no_mem:
return NULL;
}
This way, the code is not cluttered (much) with error handling and cleanup is done very nicely based on how far the function has executed.
I just reformatted your code and indeed # herohuyongtao is right, the break; for case 2 has moved at the end of default which is not useful there.
But there's something really shocking in your code, is that you use a goto. Just remember that rule: WHENEVER YOU USE GOTO, THERE'S A BETTER WAY TO DO IT!
#include <stdio.h>
short int read_input (void) {
printf("\nPROGRAM START\n");
//code copied from an exam, to check that the program performs a function
//when ran through again
int i,j,k;
printf("Please enter 7:");
scanf("%d",&i);
printf("Please enter 4:");
scanf("%d",&j);
printf("Please enter 0:");
scanf("%d",&k);
//this is to check that the program will take input when it is restarted
do {
switch (i%j) {
case 3:
i--;
k*=i;
break;
case 2:
i--;
k+=i;
break; // break at the right spot
default:
i--;
k++;
}
printf("i is %d k is %d\n",i,k);
} while (i>0);
// getchar(); // could be inserted here (discards one char)
// fflush(stdin); // could also do the job (discards all remaining chars in buffer)
char prompt='y';
// here the design choice is to let the user input whatever
// and not updated the output until the right character is given
// which will hide how many wrong chars has been previously in the buffer.
printf("\nRestart program? ");
do {
prompt = getchar();
} while (prompt != 'y' && prompt != 'Y' && prompt != 'n' && prompt != 'N');
if (prompt == 'y' || prompt == 'Y')
return 1;
return 0;
}
int main() {
while (read_input() == 1);
return 0;
}
Now that the code is clean, for your exact problem, you will get into a carriage return problem. Basically, what you do is get input until \n is hit, but when you hit carriage return, you actually send CR + LF. So there's one character that never gets read in the input buffer, that you need to discard.
So you should first read that SO question that sums up very well your problem, and you can either:
add a lone getchar(); just after your //end of copied code comment,
or a fflush(stdin) can do the job (cf the SO Question to learn more about it) but has been designed about flushing output buffers, not input ones,
add a fseek(stdin,0,SEEK_END); which is a bit dirty (and non-portable) but works,
or change your conditions and your use of scanf to take into account that you're actually having more chars in the buffer.
In the code I gave you, I chose the most simplistic solution, which is to discard any wrong input without printing anything.
Build succeeds. If I open the output window, it reads:
Program ended with exit code: 0
But my program is such that this shouldn't be possible, without first having taken user input, done some stuff, and taken another user input, all in int main().
The first thing int main() does is loop through taking input for p, until the input is one (of two) desired options. So there's no way it should be able to exit immediately - it initialises p=0 and doesn't exit a while loop until p is 1 or 2.
Is there some hidden error that has allowed the build to succeed without it actually.. succeeding?
int main(){
//vars
while (TRUE){
//play computer or human?
while (!(p == 1 || p == 2)) {
printf("Single player or two player? (1/2): ");
scanf("%d", &p);
}
if (p==1) {
//play computer
}
else {
//snip
}
printf("%s won the game! Play again?", winner);
scanf("%s", playagain);
if (strncmp(playagain,"no",2)==0){
break;
}
}
return 0;
}
Print out what uppercase TRUE is defined as. I have seen some ambitious but inexperienced folks do weird things with it. You might not even be getting into your main while loop.
printf("TRUE is %d\n",TRUE);
If this is nonzero, then your problem is elsewhere.