Infinite loop, program ignoring lines - c

I need a little help im sort of new to C programming. I'm having some trouble, for some reason the program won't read the line that im trying to take choice as input from the user which is causing me to have infinite loop neither the menu is printing.
Also stuff like this happen with me a lot of the time like when I copy my friends' code how it is it dosent run any loops even my teacher doesn't know why so if you can help in this too please do .
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <string.h>
int main (){
int choice ,score=0;
char name [30];
puts("Welcome to our game , Have fun !\n ");
puts("Enter your name");
scanf("%c",name);
printf("1-Start new game\t2-show recorde\n3-Help \t4-Show score\n5-Reset score \t6-Quit game");
scanf("%d",choice);
while(choice!=6){
switch(choice){
case 1 :
break;
case 2 :
break;
case 3 :
break;
case 4 :
break;
default :
puts("\n invalid input ");
break;
}//end switch
}//end while loop
}//end main

Your usage of scanfis wrong.
scanf("%c",name);
Format specifier %c is not suitable to read a string. It only reads 1 single character.
The other members of name array will be untouched and as local variables are not initialized to 0, that is not a valid nul-terminated string.
As soon as you try to print name or perform any string operations with it, this will result in undefined behaviour.
As a result, whatever you type after first character, stays in input buffer and is fetched during next read attempt.
To fix this, use format specifier %s.
When you now try to read the choice as an integer
scanf("%d",choice);
the input buffer contains remaining letters and also \n from first call, which does not match any number.
After the call choice is not modified and still contains its indetermined content (You don't initialize it)
You should always check return value of scanf to see how many parameters were read. It would show you that it didn't find any value.
Besides that, you also provide invalid parameter. You must provide the address of an integer. This is undefined behaviour.
This is the reason why you always enable warnings in your compiler. It should warn you about this error.
To fix this, use
int ret = scanf(" %d", &choice);
if (ret != 1)
// error handling, try again, etc.
Note the space in the format string to skip whitespace including \n.
Finally, you enter your loop with a "random" value in choice and never try to read again. How would you expect to leave the loop without this?
If your teacher really doesn't know why, the missing indentation might be a reason.

Related

Input buffer to get a an input, C programming

I'm in my first steps in C programming, and I came across a task I can not find a solution to.
The task is simple: taking a character from the user.
After that, you receiving a string from the user until the user types the * character.
Then print the number of times the user typed the first character.
I was able to solve the problem using char [SIZE]ת when I placed a maximum input size of 255 bytes (#define SIZE 255).
Nevertheless, my teacher tells me that although the solution is working well, this was not the purpose of the exercise, also, I can not assume a maximum string size.
He asks us to use the input buffer.
No dynamic memory allocation is used in the exercise, and only the stdio.h library is allowed.
I read a lot about the input buffer, but I still have not found the possibility to solve the exercise - how can I absorb value from the user without knowing its size?
I would be happy to receive assistance and tips on how to use the input buffer correctly.
Or more focused, how to input values (string of characters) into the input buffer, and then go over each character separately in this string and process it.
Thank You
There is no need to store all characters. Once you have read a character you can throw it away and just increase a counter. Something like this:
#include <stdio.h>
int main() {
char c, first;
int counter=0;
printf("Enter first character: ");
scanf("%c", &first);
do {
scanf("%c", &c);
if(c == first)
counter++;
} while (c != '*');
printf("You entered '%c' %d times\n", first, counter);
}
Output:
Enter first character: a
aaaaa*
5
or
Enter first character: a
aabbaa*
You entered 'a' 4 times
Note:
As been pointed out in the comments, scanf is not a good tool for this kind of stuff. I would advice against the usage of it, unless you know it is the right tool. But that's beside the point. The point here was to show you that you don't need to store the whole input buffer. If you want to look at alternate input methods (as William Pursell suggested in the comments) you could have a look at fgetc, getc, or getchar for reading single characters. fread is also a tool you should get familiar with.

Infinite loop with 'char' type input

I am learning binary search tree. Given below is the main function of a program to perform basic BST operations. The option variable chooses which operation to perform for switch
int main()
{
struct node* tree=NULL;
struct node* ptr=NULL;
struct node* ptrm=NULL;
int val;
int option;
do
{
printf("\n1.Insert Node\n2.Preorder Traversal\n3.Postorder Traversal\n4.Inorder Traversal\n5.find_smallest_element\n6.find_largest_element\n7.Delete Element\n8.Total_nodes\n9.total_external_nodes\n10.total_internal_nodes\n11.Mirror image\n12.Exit\n");
printf("\nEnter option");
scanf("%d",&option);
switch(option)
{
case 1:
printf("\nEnter value to be inserted");
scanf("%d",&val);
tree=insert_element(&tree,val);
printf("\n%d Inserted\n",val);
break;
case 2:
preorder(&tree);
break;
case 3:
postorder(&tree);
break;
case 4:
inorder(&tree);
break;
case 5:
ptr=find_smallest_element(&tree);
printf("\nSmallest element:%d",ptr->data);
break;
case 6:
ptr=find_largest_element(&tree);
printf("\nLargest element:%d",ptr->data);
break;
case 7:
printf("\nEnter value of element to be deleted");
scanf("%d",&val);
tree=delete_node(&tree,val);
break;
case 8:
printf("\nTotal nodes%d",total_nodes(&tree));
break;
case 9:
printf("\nTotal External nodes%d",total_external_nodes(&tree));
break;
case 10:
printf("\nTotal Internal nodes%d",total_internal_nodes(&tree));
break;
case 11:
ptrm=mirror_image(&tree);
}
}while(option!=12);
return 0;
Everything works fine when i give int data as input for 'option'.However, when i give a char input the program goes into infinite loop and displays option list repeatedly.
Why does this happen?
Since you used %d format specifier in the scanf() format string,
scanf("%d",&val);
will successfully assign to val only if an integer was given as the input. If a char is given instead, scanf() (which returns the number of successful assignments) will return 0 here and will leave the char in the input buffer unconsumed.
During the next iteration of the loop, this char would still be in the input buffer and scanf() would end up trying to read the same thing and will won't assign to val once again.
This will go on and on resulting in an infinite loop.
To solve this, check the value returned by scanf(). If it is not 1, clear the input buffer till the next \n (newline) like
int t;
while( (t=getchar()) != `\n` );
This will consume the old data till a \n from the input buffer.
You could then use the continue statement to skip the rest of that iteration of the loop.
Read about getchar() here.
Why does this happen?
The roots of this issue stem all the way back to how scanf indicates error codes to your code (not at all, because your code discards them), and what scanf("%d", &val) is expected to do when non-decimal input is encountered; it stops reading input, possibly returning an error code, but your code discards that and continues on merrily trying to delete the node indicated by the value which may not have been read, leading to possible use of an uninitialised variable later...
Some people take the guessing to an extreme, and think it's appropriate to use fflush(stdin) to solve this (it isn't; don't do that...). You've not gone that far, but I think it might be a good idea to start reading the manuals of the functions you're using. The scanf manual is here. Make note of that URL, and realise that you can look up other standard functions (both C99 and POSIX standard) by substituting the name of the function.
The first thing your code must do is check that return value, which your manual will document in the RETURN VALUES section; as with most standard library functions, scanf has a return value which your code should most likely contain critical logic regarding! From there, how you handle errors is your business. Perhaps it might be appropriate to use something simple yet user-unfriendly, like:
perror(scanf);
exit(EXIT_FAILURE);
You should seek the simpler solutions where possible, to avoid overcomplicating things. If your input doesn't come directly from the user, or you just want to prototype, you should use the solution above. You can always change exit(EXIT_FAILURE) to return EXIT_FAILURE; and return 0; on success, if necessary later.
If you choose to keep your program running, how much of the user input gets discarded due to the typo is up to you. By far the simplest option is to just read a single character (using getchar();)...
You could choose to discard a word of input, like so: scanf("%*s");. The * informs scanf to read and discard the input, rather than reading and assigning.
Neither of those options strike me as being particularly user-friendly. If you're going to the effort of making a user-friendly interface, you'll probably want to choose one of the following options.
Using the * assignment-suppression modifier, you can also discard a line of input, like so:
scanf("%*[^\n]");
getchar();
The getchar(); is necessary to discard the newline character, which we expect to be discarded when a line is discarded.
Using the command line arguments for your input, rather than using stdin (or other files/streams). Some surprisingly simple yet versatile menus have been produced this way, such as the ones your compiler presents to you. Your mode of input then changes to using friendlier functions such as sscanf, and developing your program not as a looping program that remains open, but as an instant program which gets executed every now and then, when necessary, to update records or what-not.
Using the graphical user interface instead of the console. Well, that one really makes the ol' noggin' flog, eh? You could use... a context menu such as the File/Edit/etc menus in Windows, or a listbox (which would be more touch-screen friendly) to prompt your user for a selection.
Suffice to say, this looks like homework, so you probably don't have the choice to design a more appropriate user interface... In this case, I suggest using the * assignment-suppression modifier as per above (the first bolded section).

How to check if a string is empty in C (nothing has worked so far)

I have to make a code that checks to see whether the Student 1's first name was blank and if it was then ask the user to input a name. However, when I use this code it doesn't display that message. When I press enter the cursor just goes to the next line until I actually type something in. I've tried this with strcmp too and nothing works.
#include <stdio.h>
#include <string.h>
{
char charStudent1FirstName[50] = "";
printf("Please enter Student 1's First name: ");
scanf("%s", &charStudent1FirstName);
if (charStudent1FirstName[0] == '\0')
{
printf("Please input Student 1's first name again: ");
scanf("%s", &charStudent1FirstName);
}
}
Here's what I changed:
Use fgets instead of scanf. This means you will actually see the blank line if that's all that's entered.
Trim the newline from the fgets result.
Use charStudent1FirstName instead of &charStudent1FirstName. You want to pass a char*, not a char**. If your compiler doesn't warn you about this, consider using a different compiler or changing your compilation settings.
Use a loop so the user is prompted to enter a name as many times as necessary until one is entered.
Complete working code:
#include <stdio.h>
#include <string.h>
int main() {
char charStudent1FirstName[50] = "";
while (charStudent1FirstName[0] == 0) {
printf("Please input Student 1's first name: ");
fgets(charStudent1FirstName, 50, stdin);
charStudent1FirstName[strcspn(charStudent1FirstName, "\n")] = 0;
}
printf("First name: %s\n", charStudent1FirstName);
}
There's nothing wrong with the way that you're checking for the empty string. Your issue is that you're using scanf, which is notoriously hard to use. scanf handles whitespace probably not in the way you expect: you want line-based input, but scanf reads a stream of tokens. scanf does not care about newlines, so in your case, it won't read anything until you type in non-whitespace and therefore will not retrieve an empty string.
Instead, you should read an entire line using fgets (or POSIX getline if available) and then parse that line (if necessary) with sscanf. (Note that fgets can leave a newline at the end of the string, so you must strip that off.)
Perhaps beating a dead horse, your usage of scanf is also unsafe because you do not limit the amount of data that it can write to charStudent1FirstName, and consequently a user could easily overflow the destination buffer. While it's possible to jump through some hoops to use scanf safely when reading strings, using fgets/getline would avoid these problems. (Additionally, using fgets/getline would make it more obvious that you should be passing charStudent1FirstName as an argument, not &charStudent1FirstName.)

Why is this loop infinitely repeating?

The purpose of this program is to count the digits in an alphanumeric input. However, I used a loop to not execute the program unless the input is alphanumeric.
This is the code:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
int main(){
int input,isanum,digitcount;
printf("\nEnter a number: ");
scanf("%d",&input);
isanum=isalnum(input);
while(isanum==0){
printf("\nIncorrect input. Try again: ");
scanf("%d",&input);
isanum=isalnum(input);
}
digitcount=0;
while(input!=0){
input=input/10;
digitcount++;
}
printf("\nNumber of digits = %d",digitcount);
return 0;
}
The problem is with the loop. It keeps looping infinitely and ignores the scanf statement and I don't know why. Am I using isalnum() incorrectly here?
You need to check the return value of scanf().
isalnum() takes a character, but you are passing an int. '1' is not the same as 1 in C.
You probably should consume an entire line each time, e.g. with fgets(), and then check if it fits your desired input format, e.g. with sscanf().
As it stands, you never consume anything, you just keep trying to read a number but there isn't one there so it fails every time. Failing to check the return value of scanf() is a contributing factor to your not noticing this.
Look at how isalnum() is defined: it expects a char *. You, however, give it an int *. The data is stored completely different there.
Besides, if you are reading in an int, you know beforehand that it will be alphanumeric, right?

why does my int while loop keeps going when i scan for a number?

I'm having a problem with a while loop. I have to enter a number which is bigger than 0 and below 81. when I use numbers like -1,0,1,2,82 it is going good and I get the expected result, but when I use a letter it keeps going through my while loop. I've used the debugger in eclipse and when I'm at the while loop amount is automatically set to '0' because of the failed scanf. Why does it keep looping when I insert a letter?
#include <stdio.h>
#include <stdlib.h>
int main(){
int amount = 0;
printf("Give a number:\n");
fflush(stdout);
scanf("%d",&amount);
while(amount <= 0 || amount >= 81){
printf("Wrong input try again.\n");
printf("Give a number:\n");
fflush(stdout);
scanf("%d",&amount);
}
return EXIT_SUCCESS;
}
You need to make sure the scanf() worked. Use the returned value to do that
if (scanf("%d", &amount) != 1) /* error */;
When it doesn't work (because eg a letter was found in input) you probably want to get rid of the cause of the error.
A better option to get input from users is to use fgets()
See this related question: scanf() is not waiting for user input
The reason is that when you press enter with a char, scanf failed and didn't eat up the char in the input feed. As a result, the next block begins having whatever you entered before.
You can check that by adding a getchar() before the scanf() inside the while loop. You'll notice that it'll repeat the while loop as many times as your line has invalid characters, then stop and wait for input. The getchar() ate one of the invalid chars in the input each time the loop ran.
It would be better not to use scanf like that, though. Take a look a this resource:
Reading a line using scanf() not good?

Resources