I'm trying to create a simple converter that will ask a user to input data n times. The scanf() in the loop ideally should allow user to input a response in the terminal, press enter, then pass an output, then ask again....n times. But the program so far, just asks one time and never allows user to ask again.
There are many posts about scanf in loops I've seen, but I wasn't able to connect my issue with any of them.
I'm new to C, coming from Java.
#include <stdio.h>
double feet(double m);
double lbs(double g);
double f(double c);
//double askInput(int num);
int main()
{
int num, i;
i = 0;
printf("how many?\n");
scanf("%i\n", &num);
for(i = 0; i < num; i++)
{
double input = 0.0;
double output;
char unit = NULL;
printf("num to convert, units to convert?\n");
//scanf("%lf %c\n", &input, unit);
if(input == 0.0 && unit == NULL)
{
//input = askInput(num);
scanf("%lf %c\n", &input, unit);
}
//meters to feet
if(unit == 'm')
{
output = feet(input);
}
}
I've tried a number of things. I've tried using a while loop, I've tried putting scanf in a separate function and then also using if statements. I imagine I am not quite understanding how scanf works.
You have a couple issues here.
You're assigning NULL (of type void*) into a char as well as comparing these values later. Don't do this. If you want to use some sort of canary value you could instead use the character '\0' (or any other non-readily enter-able character).
You've given scanf a parameter that it expects to be a char* as a char. In order for the line scanf("%lf %c\n", &input, unit); to work as intended, you should have an ampersand in front of unit in order to pass a pointer to the local variable unit.
Giving scanf trailing whitespace requires it to read all subsequent whitespace until it can determine a block of whitespace has ended (see man 3 scanf for some more info, but note that any whitespace character in the format string is treated equivalently). In this instance having a newline on the end of your scanf calls will require them to read some amount of whitespace and then a non-whitespace character (see also the accepted answer here: white space in format string of scanf()). Just leave off the \n.
Some of your braces (namely the block for the function main) aren't closed. I'm assuming this is just a function of copying-and-pasting into SO though.
Most of this could be avoided with a stricter compilation command. If you're using gcc with the C99 standard you could try
gcc -Wall -Werror -Wextra -Wshadow -pedantic -std=c99 source_file.c.
First of all, I recommend using the _s functions instead of the regulars (for example printf_s and not printf). Second, I wrote down a version of the code that is working. I noticed that whenever I added some text to scanf_s (for example a \n) the program didn't stop but when I printed it with printf the program stopped.
FYI: For initialization, you need to put a number that the user won't enter - If the user doesn't put a value num won't store 0 but -9.2559631349317831e+61. And you should use || instead of && because you want that num and unit will store a value! :)
Here's my code:
#include <stdio.h>
#include <string.h>
int main()
{
int amount;
printf_s("How many numbers would you like to recive?\n");
scanf_s("%i", &amount);
for (int i = 0; i < amount; ++i)
{
// Initialization of all variables.
double convertedNum;
double rawNum;
char unit[3] = "";
// Getting the variables.
printf_s("Please enter the number that you\'d like to convert and the unit to
convert to.\n");
printf_s("Number: ");
scanf_s("%lf", &rawNum);
printf_s("Units (m/ft): ");
scanf_s("%s", &unit, 3);
// To make sure that we're getting right input & the wanted amount of
// numbers.
if (rawNum == -9.2559631349317831e+61 || unit == "")
{
printf_s("Please enter a number and a unit!");
--i;
}
else if (strcmp(unit, "m") == 0)
{
convertedNum = rawNum * 3.2808399;
printf_s("\n\nAfter convention, the number is %f\n", convertedNum);
}
else if (strcmp(unit, "ft") == 0)
{
convertedNum = rawNum / 3.2808399;
printf_s("\n\nAfter convention, the number is %f\n", convertedNum);
}
}
return 0;
}
Related
So I'm basically trying to make a for loop that scans the input line. The input is always one double float number and then one string. It continues scanning until the string = is reached. Each number value is stored to an array of double and each string to an array of char.
Problem is that the input line can be arbitrarily long and I don't know how to make it
The program should work as a basic calculator which reads one double float, then one operator as a string, and performs operation. If another number follows, then perform the operation with this number. If the equal sign = is reached, the program outputs the result.
int main() {
double res;
double in[10];
char *op[10][5];
int arrCheck[10];
for(int i=0; i<=5; i++) {
scanf("%lf %s ", &in[i], op[i]);
arrCheck[i] = opCheck(op[i]);
}
return 0;
}
This is the main section of my program so far. I managed to get it working and storing the data correctly. Although it always works only on predefined limit (i<=5, for instance). Is it legal to write condition like:
for(i = 0; i<'\n'; i++), or i<=?
I would expect it to continue scanning and storing the data until it reaches the equal sign =.
Try this:
for(int i = 0; (i <= 5) && (strcmp(op[i], "=") != 0); i++) {
...
}
And on your question, it is not legal to compare integers with strings. This is why string comparing functions exist.
You can also break from for loop like this:
int main()
{
double res;
double in[10];
char op[10][5];
int arrCheck[10];
for(int i=0;i<=5;i++){
scanf("%lf %s ", &in[i], op[i]);
if (strcmp(op[i], "=") == 0)
break;
arrCheck[i] = opCheck(op[i]);
}
return 0;
}
Which is even better solution than the one posted previously.
Since you are reading with scanf and the "%s" conversion-specifier, you will consume leading whitespace before each operator stored in op[n]. There is no need to call strcmp, you can simply check the first character by dereferencing the pointer, e.g.
if (scanf ("%lf %s", &in[i], op[i]) != 2 || *op[i] == '=')
break;
A short example omitting opCheck(op[i]) not included in your question, you could do something similar to:
#include <stdio.h>
int main (void) {
double in[10];
char op[10][5];
int i = 0, n;
while (i < 10) {
if (scanf ("%lf %s", &in[i], op[i]) != 2 || *op[i] == '=')
break;
i++;
}
n = ++i;
puts ("\nequation: ");
for (i = 0; i < n; i++)
printf (" %g %s", in[i], op[i]);
puts (" res");
}
(note: the use of while (i < 10) rather than a for (i = 0; i < 10; i++). You do not want to increment i in case of a matching or input failure. You only increment i after validating both conversions succeeded)
Example Use/Output
$ ./bin/eqnread
5.1 + 6 - 2 + 25 * 4 =
equation:
5.1 + 6 - 2 + 25 * 4 = res
So I'm basically trying to make a for loop that scans the input line. The input is always one double float number and then one string.
If you care about lines specifically (which are ended by \n -or by \r on some operating systems), you cannot use scanf alone, because scanf deals with all kind of space characters (including the space, the tabulation, the newline, the formfeed characters) in the same way, so ignores the specificity of end of line characters (\n and/or \r).
So the good way is to read the entire line first with fgets (or getline(3) on Linux) and later to parse that line. Be careful about very long lines, they could happen.
How would you parse that read line is a different question: manual lexing and parsing, or sscanf, or strtok or strtod, etc... come to mind.
And you did not define what a string is for you. What about spaces inside it? What about input lines that are longer than what you expect (e.g. a line of a thousand characters)? The %s for scanf would stop at the first space.
Don't forget to read carefully the documentation of every used function. Learn How to debug small programs.
Be also aware that, practically speaking, in 2019 UTF-8 is used everywhere, and that may add complications to your scheme (and to what strings are in practice).
The program should work as a basic calculator
It seems that you then should care about operator precedence. Then, recursive descent parsing comes to mind.
I'm trying to do a program with a simple game for a user to guess the number. My code is below:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define MAX 30
#define TRYING 5
void guessnumber(int, int, int *);
int main(void) {
int mytry = 1;
guessnumber(MAX, TRYING, &mytry);
if (mytry <= TRYING)
printf("Congratulations! You got it right in %d tries\n", mytry);
else
printf("Unfortunately you could not guess the number in the number of tries predefined\n");
printf("End\n");
return EXIT_SUCCESS;
}
void guessnumber(int _n, int _m, int *_mytry) {
srandom(time(NULL));
int generated = 0, mynum = 0, test = 0;
generated = rand() % (_n + 1);
printf("Welcome to \"Guess the number\" \n");
printf("A number between 0 and %d was generated\n", _n);
printf("Guess the number:\n");
while (*_mytry <= TRYING) {
test = scanf(" %d", &mynum);
if (test != 1 || mynum < 0 || mynum > MAX)
printf("ERROR: please enter a valid number \n");
else
if (mynum > generated)
printf("Wrong! The number your trying to guess is smaller\n");
else
if (mynum < generated)
printf("Wrong ! The number your trying to guess is bigger\n");
else
break;
*_mytry = *_mytry + 1;
}
}
Okay, now the program is working pretty ok except for one thing: the scanf test.
It works if I try to enter a number out of my range (negative or above my upper limit) but it fails if I for example try to enter a letter. What it does is that it prints the message of error _m times and then it prints "Unfortunately you could not guess the number in the number of tries predefined" and "End".
What am I doing wrong and how can I fix this?
In case, a character is entered, you're trying to detect it correctly
if(test!=1 ......
but you took no action to correct it.
To elaborate, once a character is inputted, it causes a matching failure. So the input is not consumed and the loop falls back to the genesis position, only the loop counter is increased. Now, the previous input being unconsumed, is fed again to the scanf() causing failure once again.
This way, the loop continues, until the loop condition is false. Also, for every hit to scanf(), as unconsumed data is already present in the input buffer, no new prompt is given.
Solution: You need to clean the input buffer of existing contents when you face a failure. You can do something like
while ((c = getchar()) != '\n' && c != EOF);
to clean the buffer off existing contents.
When you enter a letter, scanf() leaves the letter in the input stream since it does not match the %d conversion specifier. The simplest thing to do is use getchar() to remove the unwanted character:
if (test != 1) {
getchar();
}
A better solution would be to use fgets() to get a line of input, and sscanf() to parse the input:
char buffer[100];
while (*_mytry<=TRYING)
{
if (fgets(buffer, sizeof buffer, stdin) == NULL) {
fprintf(stderr, "Error in fgets()");
exit(EXIT_FAILURE);
}
test=sscanf(buffer, "%d", &mynum);
if(test!=1 || mynum<0 || mynum>MAX)
printf ("ERROR: please enter a valid number \n");
else if(mynum>generated)
printf("Wrong! The number your trying to guess is smaller\n");
else if(mynum<generated)
printf("Wrong ! The number your trying to guess is bigger\n");
else
break;
*_mytry=*_mytry+1;
}
In the above code, note that the leading space has been removed from the format string. A leading space in a format string causes scanf() to skip leading whitespaces, including newlines. This is useful when the first conversion specifier is %c, for example, because any previous input may have left a newline behind. But, the %d conversion specifier (and most other conversion specifiers) already skips leading whitespace, so it is not needed here.
Additionally, your code has srandom() instead of srand(); and the call to srand() should be made only once, and probably should be at the beginning of main(). And, identifiers with leading underscores are reserved in C, so you should change the names _m, _n, and _mytry.
So I'm trying to find the sum of an unknown amount of user-input numbers. Here's my code
int main()
{
int tmp1 = 1;
int tmp2 = 1;
int total = 0;
printf("Enter numbers for a sum: ");
tmp2 = scanf(" %d", &tmp1);
while(tmp2 > 0){
total+=tmp1;
tmp2 = scanf(" %d", &tmp1);
}
printf("total is %d", total);
return 0;
}
It gets stuck in an endless loop, and then once i hit ctrl-c to end it, it prints the correct sum. So what I'm doing wrong is how will i know when it's done scanning all the integers, and for the loop to end; since i'm not doing it correctly now
Decided to make it stop via ctrl d, and its acceptable. thanks
In your question, it is not clear how you expect your programme to understand that there won't be anymore numbers to input. Shall it be through a specific character? Or shall it just get a line of space-separated numbers and respond with a sum?
From your code, my most sensible guess is: You want it to understand that there won't be any more numbers to add, whenever it encounters a non-digital character. My guess is so, because this is almost exactly what your code does by checking the return value from scanf.
First of all, you have to change that tmp inside your loop into tmp1 because there isn't such a variable as tmp declared. edit: well, never mind
Then try running your programme, putting in any amount of white-space (space, tab or new-line) separated numbers, and then any non-digital character you like. May be a T for example, or ThoAppelsin, it won't matter. Programme won't get beyond the first character, in fact, not even beyond the first character. After that, you shall see that the numbers have been properly added together.
Since you're confused about a non-existent infinite-loop, my second guess is that you might be actually hoping it to get a single line of space-delimited numbers, and have the sum printed; and misinterpret your programme as "in infinite loop" while it merely expects further input from you, just like it does at the very beginning.
You won't get a 0 from non-redirected scanf("%d", &var);, unless you feed it with something that doesn't match to the format string to cause abnormal termination. If there's nothing left in the input stream to consume, it will just wait for more input. But say you give an 'a' to it, then all it can do is to give up and return zero, because it couldn't do a single assignment.
If you really are hoping to have a single line of numbers, then the minimal change I could offer would be something like this:
int main(void)
{
int tmp1 = 1;
char tmp2 = 0;
int total = 0;
printf("Enter numbers for a sum: ");
scanf("%d%c", &tmp1, &tmp2);
while(tmp2 == ' '){
total+=tmp1;
scanf("%d%c", &tmp1, &tmp2);
}
printf("total is %d", total);
return 0;
}
Of course, this approach has many vulnerabilities. However, if user is to input strictly a sequence like:
3 66 2 10 6
// mind the new-line
It will work fine. But if I'm allowed to change more than minimal, this is how I would do it:
#include <stdio.h>
#include <ctype.h>
#include <stdlib.h>
int main(void)
{
int LastNumber = 0;
int UpcomingCharacter = 0;
int Total = 0;
printf("Enter numbers for a sum: ");
while(scanf("%d%*[ \t]", &LastNumber) == 1)
{
Total += LastNumber;
UpcomingCharacter = getchar( );
if (!isdigit(UpcomingCharacter)) // eliminates a possible EOF return as well
break;
if (ungetch(UpcomingCharacter, stdin) != UpcomingCharacter)
{
fprintf(stderr, "%d: unexpected error with ungetch\n", __LINE__);
return EXIT_FAILURE;
}
}
printf("total is %d", Total);
return EXIT_SUCCESS;
}
Which should work fine on any whitespace-delimited sequence of numbers, excluding the new-lines of course.
I'm writing a few very small programs for my introductory C course. One of them requires me to read in double values, one number per line, and then print out basic statistics after EOF. Here is my the segment of my code that is giving me issues:
double sample[1000000];
int result;
double number;
int i = 0;
int count = 0;
double sum = 0;
double harmosum = 0;
result = scanf(" %lf \n", &number);
double min = number;
double max = number;
while(result != EOF){
sample[i] = number;
if(number < min){
min = number;
}
if(number > max){
max = number;
}
sum += number;
if(number != 0){
harmosum += (1 / number);
count++;
}
i++;
result = scanf(" %lf \n", &number);
}
After this I calculate and print some statistics based on the numbers.
My issue is, I am never making it out of the loop that scans each line. Why is this? When I press the EOF key on windows (CTRL-Z?) the console says:
^Z
Suspended
and that is it. Nothing else in the program runs. I have tried taking input from a text file but the end of the file is not detected there either. How should I fix this loop? Note I am only able to use basic scanf() no variation of the function. Thanks!
The below code is a simplification of your I/O issues.
" %lf " supplies 3 scanf() format directives: 1) white-space 2) double specifier, 3) white-space.
The first white-space directive is not needed as the %lf allows for optional leading whitespace. The 2nd white-space directive causes problems as it consumes the Enter key, waiting for additional input.
"%lf" supplies 1 scanf() format directives: double specifier
This consumes optional leading white-space, including any previous \n, then scans for and hopefully decodes a double. A \n (Enter key) following the number is left in the input buffer for the next input (the next scanf()).
Now as to why your control Z is failing. It appears your console is consuming the ^Z and performing a "suspend job". My console, instead of giving the ^Z to the program, closes the stdin input. In essence putting an EOF in stdin.
So you need to either:
1) Find your console's mechanism for closing the stdin - others have suggested ^D.
2) Use an alternative to exit your loop. I suggest result != 1 which readily occurs when non-numeric input is entered.
#include <stdio.h>
int main(int argc, char *argv[]) {
int result;
double x = 0.0;
do {
// result = scanf(" %lf ", &x); /* Your original format */
result = scanf("%lf", &x);
printf("%d %lf\n", result, x);
fflush(stdout); // Your system may not need this flush
} while (result != EOF);
}
Okay guys, after giving up on this first part of the project and debugging the other parts, I have determined that my only issue with the code above is I am trying to reference an index of an array that is out of bounds. I have also determined that the EOF key is ctrl-d, even though I have read and been told by my professor that it is ctrl-z for windows. Regardless, this should be an easy fix. Thanks so much to everyone who provided input!
#include < stdio.h >
#include < process.h >
rec();
main() {
int a, fact;
char question, n, y;
do {
printf("\nEnter any number ");
scanf("%d", & a);
fact = rec(a);
printf("Factorial value = %d\n", fact);
printf("do you want to exit.....(y/n):");
scanf("%s", & question);
}
while (question == n);
exit(0);
}
rec(int x) {
int f;
if (x == 1) return 1;
else f = x * rec(x - 1);
return f;
}
In this program I want to get factorial of the entered number, which I get. But I also want the user to say whether to exit or get the factorial of another number, which I can't do. It asks user but when I enter "n" it exits.
Where is the error?
You want
while (question == 'n');
Or
char question, n = 'n', y = 'y';
Though I find the 2nd version a little redundant.
Either way you need to change
scanf("%s"
to
scanf("%c"
To correctly read in a single char and not a string. Thanks RageD
One problem is the combination of:
char question, n, y;
scanf("%s", &question);
You are using %s to read a null-terminated string into a single character. Even if you hit 'y' and return, you'll be overwriting beyond the end of the variable. This is not good. (The good news is that "%s" skips over white space, including the newline after the number).
You either need to use "%c" in the format:
char question;
scanf(" %c", &question); // NB: The leading space is important!
or you need to use a string format and a string variable (and no &):
char question[10];
scanf("%9s", question);
If you use an array, you need to consider whether to use strcmp(), or whether to compare the first character from the input:
while (strcmp(question, "n") == 0);
while (question[0] == 'n');
You probably got told by the compiler that you'd not declared variable n so you added it. You probably need the loop to end with while (question == 'n');and then get rid of the (now) unused variablen(and the currently unused variabley`).
Note that if you use omit the space in the " %c" format string:
scanf("%c", &question);
then it will normally get the newline after the number, which won't be 'n', so your loop will exit every time, apparently without waiting for you to enter anything. You can finesse that with scanf(" %c", &question); which skips white space before reading a character.
You should test that scanf() received the input you expected each time you use it. The correct test for single item inputs is:
if (scanf(" %c", &question) != 1)
...input failed...
If you need to distinguish between EOF and conversion failure, you can capture the return from scanf():
int rc;
if ((rc = scanf(" %c", &question)) != 1)
...rc == EOF on EOF; rc == 0 on 'conversion failure'...
...a single character input can't easily fail...
...but if someone types 'a' instead of '9' when you're looking for a number...
Getting I/O right using scanf() is distressingly hard. Many experienced programmers simply don't use it; it is too hard to get right. Instead, we use fgets() or POSIX getline() to read a line of data, and then use sscanf() to parse it. There are many advantages to this, but a primary one is that the newline has been eaten so you don't run into problems with the variable question not containing the answer you expect.