C: Scanf in while loop executes only once - c

I am trying something simple in C, a program to get the exchange and do some conversions.
To make sure scanf gets the right type I placed it into a while loop, which continues to ask for input until a number is inserted.
If I enter a character instead of a number it does not ask again for an input.
exRate = 0;
scanfRes = 0;
while(exRate <= 0){
printf("Enter the exchange rate:");
while(scanfRes != 1){
scanfRes = scanf(" %f", &exRate);
}
if(scanfRes == 1 && exRate > 0){
break;
}
printf("Exchange rate must be positive.\n");
}
UPDATE: As this is a course assignment, I was not supposed to use anything outside of the taught material. When I asked the academic staff about handling unexpected input, I got an answer that this is a scenario I am not supposed to take into consideration.
The answers and help in the comments is all useful and I added 1 to all useful suggestions. The staff answer makes this question no longer needed.

Change handling of scanf() result.
If the input is not as expected, either the offending input data needs to be read or EOF should be handled.
for (;;) {
printf("Enter the exchange rate:");
scanfRes = scanf("%f", &exRate);
if (scanfRes == 0) {
printf("Exchange rate must be numeric.\n");
// somehow deal with non-numeric input, here just 1 char read & tossed
// or maybe read until end-of-line
fgetc(stdin);
} else if (scanfRes == EOF) {
// Handle EOF somehow
return;
} exRate > 0){
break;
}
printf("Exchange rate must be positive.\n");
}
Note: the " " in " %f" is not needed. "%f" will consume leading white-space.

Related

Nested if statement in C - why doesn't it evaluate the last else if?

The following code does not execute the last else if statement when you assign to choice value 3.
#include<stdio.h>
#include<stdlib.h>
int main() {
puts("Specify with a number what is that you want to do.");
puts("1. Restore wallet from seed.");
puts("2. Generate a view only wallet.");
puts("3. Get guidance on the usage from within monero-wallet-cli.");
unsigned char choice;
choice = getchar();
if ( choice == '1' ) {
system("nice -19 ~/monero-x86_64-linux-gnu-v0.17.2.0/monero-wallet-cli --testnet --restore-deterministic-wallet");
exit(0);
}
else if ( choice == '2' ) {
system("nice -19 ~/monero-x86_64-linux-gnu-v0.17.2.0/monero-wallet-cli --testnet --generate-from-view-key wallet-view-only");
exit(0);
}
else if ( choice == '3' ) {
puts("Specify with a number what is that you want to do.");
puts("1. Get guidance in my addresses and UTXOs");
puts("2. Pay");
puts("3. Get guidance on mining.");
unsigned char choicetwo = getchar();
if ( choicetwo == '1' ) {
printf("Use \033address all\033 to get all your addresses that have any balance, or that you have generated at this session.");
printf("Use \033balance\033 to get your balance");
printf("Use \033show_transfers\033 to get ");
printf("Use \033show_transfers\033 out to get ");
printf("Use \033show_transfers in\033 to get your balance");
}
}
return 0;
}
I get the following output When I enter 3:
Specify with a number what is that you want to do.
1. Restore wallet from seed.
2. Generate a view only wallet.
3. Get guidance on the usage from within monero-wallet-cli.
3
Specify with a number what is that you want to do.
1. Get guidance in my addresses and UTXOs
2. Pay
3. Get guidance on mining.
I'm really blocked, something is missing and I have no clue why it does not proceed to take the input from the user for the second time.
When you enter "3" for the first input, you're actually inputting two characters: the character '3' and a newline. The first getchar function reads "3" from the input stream, and the second one reads the newline.
After accepting the first input, you'll want to call getchar in a loop until you read a newline to clear the input buffer.
choice = getchar();
while (getchar() != '\n');

How to add few indata parameters using gets(tmp)?

int regMedicine(Medicine lakemedel[], int antalMedicine)
{
char namnMed[WORDLENGTH], tmp[WORDLENGTH], test[WORDLENGTH] = "ja";
int storlek, saldo;
while(strcmp(test, "ja") == 0)
{
printf("Ange namn: ");
gets(namnMed);
printf("Ange storlek: ");
while(tmp!=0){ ///////////////////////
gets(tmp); //////////////////////////////////////////
} ///////////////////////////////////
storlek = atoi(tmp); //atoi - converts string to int
printf("Ange saldo: ");
gets(tmp);
saldo = atoi(tmp); //atoi - converts string to int
lakemedel[antalMedicine] = createMedicine(namnMed, storlek, saldo);
antalMedicine++;
printf("Vill du fortsatta registrera (ja) eller (nej): ");
gets(test);
}
return antalMedicine;
}
I am writing a program where I use a FILE to register the medicine, size of the medicine and balance.
I wrote a function where I can take the name of medicine, size and balance. But the problem I got stuck is how to add few sizes of medicine and quit by entering "0". Any Ideas? Should I use an extra loop?
gets is an obsolete function and should never be used. Why is the gets function so dangerous that it should not be used?
while(tmp!=0) doesn't make any sense, this checks the target array address against null, which isn't what you want. Instead of this loop, make one checking the result of fgets. Examples: Removing trailing newline character from fgets() input. You can use fgets either on stdin (command line input) or directly from the FILE pointer.
Avoid atoi since it doesn't handle errors well. Instead use strtol, for example strtol(str, NULL, 10) where str is the string and 10 is decimal format (base 10).
Avoid writing source code in your native language, since C itself is based on English. It gets confusing when you have to ask for help by English-speaking programmers (such as in this site) and it also gets confusing in general for those reading the code.
I'm Swedish myself so I can read this, yet the "Swenglish" is much harder for me to read than source code written in pure English. There's also the nasty letters åäö which will eventually cause technical problems.
User messages can of course be in the native language, but that's another story.
how to add few sizes of medicine and quit by entering "0". Any Ideas? Should I use an extra loop?
Certainly, if you want to repeat entering size and balance, you'd use a loop, e. g. you could replace
printf("Ange storlek: ");
while(tmp!=0){ ///////////////////////
gets(tmp); //////////////////////////////////////////
} ///////////////////////////////////
storlek = atoi(tmp); //atoi - converts string to int
printf("Ange saldo: ");
gets(tmp);
saldo = atoi(tmp); //atoi - converts string to int
lakemedel[antalMedicine] = createMedicine(namnMed, storlek, saldo);
antalMedicine++;
with
while (printf("Ange storlek (avsluta genom att ange 0): "),
fgets(tmp, sizeof tmp, stdin) && (storlek = strtoul(tmp, NULL, 10))
)
{
printf("Ange saldo: ");
if (!fgets(tmp, sizeof tmp, stdin)) break; // leave loop on input end
saldo = strtoul(tmp, NULL, 10);
lakemedel[antalMedicine++] = createMedicine(namnMed, storlek, saldo);
}

C - segmentation fault when comparing integers

here is a part of my code. When I run my code, it's requesting an input from user and then matching it with another integer which recorded in my structure. When user input is matching, it is working correct. But when user enters a wrong input, it gives a segmentation fault. In where, I should make changes on my code?
long int userInput,endCheck; // Input from user
int flag=0; // check for match
int status;
int c; // controlling ctrl+D
int position= 999; // position of where the user input and data matched
LABEL:
printf("\n\t---------------------------------------\n");
printf("\n\nPlease enter the student ID which you want to find(3-times CTRL+D for finish):\n");
scanf("%d",&userInput);
if( (c=getchar()) == EOF){
exit(0);
}
for(i=0;i<lines,flag==0;i++){
if(index[i].id == userInput){
position=i;
flag=1;
}else{
position=999;
}
}
if(flag==0){
printf("id not found");
}
studentInfo info; // for storing the information which we will take between determined offsets
if(position!= 999){
if ( (pos = lseek(mainFile,index[position].offset , SEEK_SET)) == -1)/*going to determined offset and setting it as starting offset*/
{ perror("classlist"); return 4; }
while ( (ret= read(mainFile,&info, sizeof(info))) > 0 ){
printf("\n\nStudent ID: %d, Student Name: %s\n\n",info.id,info.name);
break;// to not take another students' informations.
}
}
flag=0;
goto LABEL;
printf("Program is terminated");
The right way to do that loop with the unwanted comma is like this. When you find the right index[i].id you can exit the loop early by using break.
for(i=0;i<lines;i++){
if(index[i].id == userInput){
position=i;
flag=1;
break;
}
}
You don't need the else branch as position is set to 999 from the outset of the code. But really you shouldn't use position in this fashion. What if you have more than 999 records? You're already using flag to identify if you've set position to a valid value. You should replace any instance of if(position!= 999) with if(flag).
Or since position is a signed int, you could use a negative value and ditch the flag.
The reason can be the fact that you are reaching an index that doesn't exist in the end of cycle, in the moment of the "if" statement with iterator "i".
Or in the last if, where you access a "position" index of the array. Check those limits.
Also, try GDB, is useful for solving this kind of problems.

Parameters inside the function

I have a work to do in which I have to keep a loop inside the function expecting the following parameters:
-"i" to insert
-"s" to search
-"q" to quit
How do I keep this loop? I've looked up some options and it seems to be possible using a while or a switch, but I am not sure which is the best way to read those chars (with a fscanf perhaps?). I am also not sure how to read the things after the parameter "i" as the input would be "i word 9", so after detecting the i to insert I have to read a string and an int.
Anyone has any idea how to do this? I am sorry is this seems simple, but I am new to programming.
edit: Here is what I have so far
while (loop) {
fscanf(stdin,"%c",&par);
if (strcmp(&par,"i")){
scanf("%s %d",palavra,p);
raiz = insere(raiz,&palavra,p);
}
else if (strcmp(&par,"b")){
scanf("%s",palavra);
busca(raiz,&palavra);
}
else if (strcmp(&par,"q"))
loop = 0;
}
edit 2: This is what I have now, I am having problems reading the string and integer when the parameter is i, somehow it crashes the function
while (1) {
c = getchar();
if (c == 'f')
break;
else if (c == 'i'){
fscanf(stdin,"%s",&palavra);
scanf("%d",&p);
raiz = insere(raiz,palavra,p);
}
else if (c == 'b') {
scanf("%s",palavra);
busca(raiz,palavra);
}
}
Thanks in advance!
The code you have doesn't look too bad compared to what I believe you want. You can replace the "while (loop)" with "while (1)" and then your exist code "loop = 0;" with "break;" which is a bit more standard way of doing things. Also "fscanf(stdin..." is the same as "scanf(..." ... scanf will read from stdin by default. You might want to check the docs for strcmp because it returns 0 for an exact match and I don't think that will do what you want in your 'if' statements. You should be able to use scanf to read in the values you want, is it giving you an error?
You are using 3 separated scans. That means you can't input this "i word 9", but input one command or parameter at the time separated by EOL(pressing enter).. i, enter, word, enter, 9, enter ... Then the function should actually get further in those "if"s. With those scans you also should consider printing information about expected inputs ("Choose action q/i/f")
And I would recommend using something to test those inputs.
if (scanf("%d", &p) == 0) {
printf("Wrong input");
break;
}

C: Do-While Loop Repeating Too Much!

I have a small program that which is confusing me. I am trying using a loop to take input from user. In case input is wrong, it is repeated again but if it is right, it exits.
The code snippet is:
void main()
{
char user_status; // Checks User Status q = Quiz Master and p = Participant
int valid_status = '0'; // Checks If User Status Is Valid Or Not. Used In Some Loops. 0 = Invalid, 1 = Invalid.
printf("Welcome to General Knowledge Quiz Management System.\nThis application has been designed to help you conduct a quiz or test your GK.");
do
{
user_status = '0';
printf("\n\nPlease enter your role.\nQuiz Master = \'q\'\nParticipant = \'p\'\n");
scanf("%c", &user_status);
if (user_status == 'q'|| user_status == 'Q')
{
printf("Initializing Quiz Master Segment\n\n________________________________\n");
initiate_qm();
valid_status = '1';
}
else if (user_status == 'p' || user_status == 'P')
{
printf("Initializing Participant Segment");
initiate_pa();
valid_status = '1';
}
}
while (valid_status != '1')
printf("\nProgram Will Exit Now. Press Any Key To Return To Windows.");
getch();
}
I am expecting this output:
Please Enter Your Role
Quiz Master = 'q'
Participant = 'p'
Till now, it works great. When I input q/Q/p/P, it works great. But when I input something wrong, it does not give required output.
For example, if I input "abc", I should get the above text again asking me to input q or p. But instead, I get this:
Please Enter Your Role
Quiz Master = 'q'
Participant = 'p'
Please Enter Your Role
Quiz Master = 'q'
Participant = 'p'
Please Enter Your Role
Quiz Master = 'q'
Participant = 'p'
Please Enter Your Role
Quiz Master = 'q'
Participant = 'p'
_ (I have to input here)
Now, why is it repeating 3 extra times. One interesting thing to note is that if I input something that is 2 characters long, it repeats 2 extra times and if I leave it blank(just hit return), it does not repeat extra times.
I have to use only C. I am using Visual C++ 2010 to compile.
Thanks.
Because you have given scanf three characters to process. It removes first first character the first time it calls scanf getting 'a', but still has 'bc' left in the stdin buffer.
You need to check for leftover stuff in your buffer before you look for input again. And I'd avoid flushing the stdin buffer because it's undefined behavior. (http://www.gidnetwork.com/b-57.html)
You can read the remaining characters and discard them with
do{
scanf("%c", &user_status);
}while(user_status!='\n'); //This discards all characters until you get to a newline
right after you read the character you want.
You want
do
{
} while (condition);
As your forgot the semicolon, you get:
do
{
....
}
while(condition)
do something else;
You could have noticed that just by auto-indenting your code in an editor like I did on your question.
Also when you do some scanf you should rather include the \n in the format specification.
First of all, # include <stdio.h> and use getc(stdin) to get a character. It'll help you to prevent cursor from moving and putting unnecessary characters to console.
Secondly, write the welcome message before the loop.

Resources