I am a beginner programmer (about a week) and my simple program keeps crashing. What did I do wrong? It crashes before I even input the amount of hours. Please help.
#include <stdio.h>
#include <stdlib.h>
int hours;
float wage;
float total[2];
int main()
{
printf("How many hours have you worked this week?\n");
fgets(hours, sizeof(hours), stdin);
sscanf(hours,"%d", &wage);
if (hours < 40)
wage = 8.5;
total[0] = hours * wage;
printf("You will earn %d dollars", total[0]);
if (hours >= 40)
wage = 12.75;
total[1] = hours * wage;
printf("You will earn %d dollars", total[1]);
return 0;
}
I think the issue is here:
fgets(hours, sizeof(hours), stdin);
fgets doesn't do formatted input, so this will end up crashing in Cruel and Unusual Ways as it tries to use the integer value hours as a pointer to a buffer that should be read.
To fix this, try this:
scanf("%d", &hours);
You also have a completely unnecessary and malformed scanf on the next line:
sscanf(hours,"%d", &wage);
The syntax for scanf is
scanf(formatting-string, destinations...);
Therefore, it should probably look like this:
scanf("%f", &wage);
You should definitely crank up the warning level on your compiler; I'm amazed that this compiled without giving you a warning explaining that something fishy was going on.
There's also an issue with your formatting specifiers in the printf statements:
printf("You will earn %d dollars", total[0]);
Note that total[0] is a float, not an int, so %d is inappropriate. Try using %f instead.
Hope this helps!
hour is defined int but you are initializing it with fgets which is used for inputting strings.
Use
scanf("%d", &hours);
Also use %f instead of %d in all of your printf statements and so with sscanf otherwise your programs behavior will Undefined.
7.21.6 Formatted input/output functions
If a conversion specification is invalid, the behavior is undefined.282) If any argument is
not the correct type for the corresponding conversion specification, the behavior is
undefined.
http://www.cplusplus.com/reference/cstdio/fgets/
fgets gets a char pointer as first argument... you give a int. Thats why it crashes
fgets expects its first argument to be a pointer to the first element of an array of char, which will hold the input. For example:
char hoursBuf[4]; //room for 3 digits plus 0 terminator
if ( !fgets( hoursBuf, sizeof hoursBuf, stdin ))
{
// error on input; you really want to verify that your library calls
// succeed before moving on.
}
This will save the input as a string, or a sequence of characters; in order to perform calculations with it, you will have to convert it to an integer type using another function like strtol or sscanf.
You could avoid the conversion step by using scanf directly:
if ( scanf( "%d", &hours ) == 1 )
{
...
}
scanf will return the number of successful conversions and assignments; in the case above, it should be 1. If it's 0, then the user typed in something other than a valid integer. However, if they type in something like "12w", scanf will convert and assign the "12" to hours, return 1, and leave the w in the input stream to foul up the next input.
I prefer using strtol because it catches those cases:
char *chk; // will point to the first character not converted
int tmp = (int) strtol( hoursBuf, &chk, 10 );
if ( !isspace( *chk ) && *chk != 0 )
{
// *chk is not whitespace or 0, meaning the user typed an invalid character
fprintf( stderr, "%s is not a valid integer string\n", hoursBuf );
}
else
{
// input was good, so we assign hours:
hours = tmp;
}
I know this is a lot to take in for someone who's been programming for about a week. I/O in C can either be "simple" or "robust"; you don't get both.
Related
I need to receive from the user input that can come in 2 forms, char int float or char int, but I don't know which of them will be given. I tried this:
int main(){
char letter;
int num;
float value;
while(getchar()!=EOF){
scanf(" %c %d %f", &letter, &num, &value);
printf("%c\n", letter);
printf("%d\n", num);
printf("%f\n", value);
}
return 0;
}
The problem with this is when I give an input like this:
? 12345
g 12345 45.6
? 12345
Output given: Expected Output:
1 ?
2345 12345
0.000000 0.000000
1 g
2345 12345
45.599998 45.599998
? ?
12345 12345
45.599998 45.599998
Why is part of the number going in the place of the char and the char is ignored? Is there a way to fix this?
There are several problems here:
The missing char. When you do while(getchar()!=EOF) for the first time, you are consuming the first character in the stream, which happens to be '?'. The subsequent scanf() cannot retrieve that anymore, so it grabs the next non-whitespace character, which happens to be the '1' of the following number.
After that '1' is read, the rest of the number is parsed, providing the result 2345.
The following conversion tries to parse a float, but the next non-whitespace character is a g, so no float can be read, and the conversion fails.
You fail to check, how many conversions are successful. scanf() dutifully returns the number of successful conversions, but you ignore that.
If you had checked the return value, you would have found that the first scanf() call returns 2 because the character and the integer conversions finished successfully, but the float conversion failed.
Likewise, the second scanf() call should have returned 3, signaling that all three conversions succeeded. The last call to scanf() should return 2 again.
The gobbling up of a character in while(getchar()!=EOF) bites you again on the second line, this time it is the 'g' that's removed from the stream before the scanf() gets a chance to read it.
After the second call to scanf() successfully terminates, the '\n' character is left in the stream. Thus, the following while(getchar()!=EOF) gobbles that up, and the third scanf() call can finally correctly fetch the first character on the line ('?').
The float conversion fails again on the third input line, and the corresponding variable is left untouched, and you fail to detect this condition by ignoring the return value of scanf().
Long story short:
Each getchar() call consumes a character that cannot be read by scanf() anymore.
Any scanf() call that ignores the return value is a bug. Without checking that, you cannot know that you actually read anything.
Btw: man scanf and man getchar could have told you everything I just said. It pays off to know how to read manpages.
In this case, it's best to first retrieve the user input as char* (fgets-like) and then parse it with sscanf (not scanf, sscanf).
You will have to check the return value of sscanf in order to know wether the input user is correctly formatted.
If you need to check if there is not garbage value after the parsing (like "g 12345 45.6 garbagevalue"), you can add a %c after and check if the value have changed.
char letter;
int integerNumber;
double floatingNumber;
char end;
char *userInput = ...;
end = '\0';
if (sscanf(userInput, "%c %d %f%c", &letter, &integerNumber, &floatingNumber, &end) == 3 && end == '\0') {
// First form
} else {
end = '\0';
if (sscanf(userInput, "%c %d%c", &letter, &integerNumber, &end) == 2 && end == '\0') {
// Second form
} else {
// Error : Input not strictly "%c %d %f" or "%c %d"
}
}
Sound good to you ?
I wonder if it would be simpler to read in a block of data from the keyboard to a string from the keyboard and then analyse with sscanf as in the outline below
#define MAX_INPUT 100
char data_input[MAX_INPUT];
int finished=0, test;
char letter;
int num;
float value;
while (finished==0) {
// scanf("%s",data_input); //taken out after useful comments below
fgets(data_input,100,stdin); //replacement from comments...
// insert code using sscanf to read in data from user
test=sscanf(data_input, "%c %d %f", &letter, &num, &value);
if (test==3)
{
//success - sscanf successfully assigned 3 values...
// (ony if you have everything you need then....)
finished =1;
} else if (test==2){
// insert something to try to test if data from two data entries is ok....
// (ony if you have everything you need then....)
finished =1;
} else {
printf("problem with data entry - please type again\n");
}
}
with apologies to #Tom's because the use of sscanf was first suggested by him...
I think it's obvious I don't understand. How do you tell the computer in C to decide which is the appropriate interest rate and then calculate and display it. This is the best I could come up with and I have to hand this as an assignment tomorrow. I had not clue it would be this difficult.
#include <stdio.h>
int main (void)
{
float time;
float principal;
char response[15];
float rate1, rate2,rate3,rate4;
rate1=.04,rate2=.05,rate3=.06,rate4=.07;
float SimpleInterest1;
float SimpleInterest2;
float SimpleInterest3;
float SimpleInterest4;
SimpleInterest1=principal*time*rate1;
SimpleInterest2=principal*time*rate2;
SimpleInterest1=principal*time*rate3;
SimpleInterest2=principal*time*rate4;
printf("Please enter principal\n");
scanf ("%f",&principal);
printf ("Please enter time\n");
scanf ("%f",&time);
if (principal <= 5000)
{
printf ("%f",&SimpleInterest1);
}
printf ("Do you still want the loan?\n");
scanf ("%s",response);
return 0;
}
As it has been already said: do not forget to ask for principal value using
scanf.
Then, use if-else if-else-statements to know in which interval principal lies.
Then, inside each statement, assign interest to the right value.
Then assign time to the right value (you can scanf it if you have to) before calculating the interest.
Also, check if the interest has to be recomputed each year on the
new debt. If this is the case, then the formula should be
debt = principal * (1 + rate)^time.
You can #include <math.h> to use the pow function that computes the power of a float or a double.
Then just printf("%f", debt);.
Aparté:
Michael Overton's book "Numerical Computing with IEEE Arithmetic" pp.82-86 explains pretty well how to compute a compound interest with a stable algorithm, because the naive way to compute it using pow can involve a loss of accuracy.
First off, these two lines are probably a typo:
SimpleInterest1=principal*time*rate3;
SimpleInterest2=principal*time*rate4;
They should become this:
SimpleInterest3=principal*time*rate3;
SimpleInterest4=principal*time*rate4;
Next, if your asking about i/o (input/output), then here's a basic run through:
You use printf( char *format, ...) to output information.
You use scanf( char *format, ...) to do basic input.
Where format is one of the following (this is the basics):
%s : Argument is expected to be of type char*
%i : Argument is expected to be signed int
%f : Argument is expected to be float (use also for double in printf)
%u : Argument is expected to be unsinged int.
When you use scanf, you should check the return value and clear the input buffer, examples will follow:
void clear_buffer() {
// Note that ch is int not char, this is important
int ch;
while( (ch = getchar()) != EOF && ch != '\n');
}
int answers = 0;
float value = 0.0;
do {
// Scanf returns the recieved number of args that fit the format string
answers = scanf( "%f", &value );
clear_buffer();
if (answers == 0) {
continue;
}
} while (value > -0.1 && value < 0.1);
The above may not work as I mainly work with unsigned integers, but it should provide a good foundation at the very least.
You use if...else if....else to determine the formula to use.
Lastly, you should calculate the SimpleInterest AFTER you get a value for time and principal; the c parser cannot 'see into the future'
I am new to C, but I know C#. In C#, I could use TryParse to ensure that the user typed in the correct datatype.
Here is the basic code I have for C:
int shallowDepth;
do
{
printf ("\nEnter a depth for the shallow end between 2-5 feet: ");
scanf ("%d", &shallowDepth);
if (shallowDepth < 2 || shallowDepth > 5)
{
printf("\nThe depth of the shallow end must be between 2-5 feet.");
}
}
while (shallowDepth < 2 || shallowDepth > 5);
The problem is if I type characters, such as "asdf", the program goes crazy and repeatedly says "Enter a depth for the shallow end between 2-5 feet: ". I'm not sure why this is exactly happening, but it has to be because it expects an int and I'm passing characters.
So how do I verify that the user inputted data is of int type before trying to store it in a variable? Thanks.
This is happening because with %d scanf will refuse to touch anything that does not look like a number and leaves the text in the buffer. The next time around it will again reach the same text and so on.
I recommend that you ditch scanf for now and try something like fgets and then one of the functions in the strtoXXX family such as strtoul or strtoumax. These functions have a well-defined way of reporting errors and you can easily prompt the user for more text.
For example you could do:
char str[LENGTH];
long x;
if (!fgets(str, sizeof str, stdin)) {
/* Early EOF or error. Either way, bail. */
}
x = strtol(line, NULL, 10);
At this point you could use your number, but be aware that:
You can specify a pointer for strtol to fill and it will point to the first unacceptable character
If the result cannot be represented as a long then strtol will set errno = ERANGE. If you plan to test for this you must set errno = 0 before the strtol
If you want to use scanf you can't test it before. But you don't need too!
In your code if the user doesn't enter a number (or something that starts with a number), scanf returns 0, because it returns the number of parameters it could read.
So you need to check the return value of scanf to check if anything could be read.
Second, you need to remove everything that's still in the puffer.
You can use something like this for that:
while(getchar()!='\n');
If you want to handle files as well, you should catch EOF there, too.
int shallowDepth;
int invalid;
do {
int stat;
invalid = 0;
printf ("\nEnter a depth for the shallow end between 2-5 feet: ");
stat = scanf ("%d", &shallowDepth);
if(stat != 1){
invalid = 1;
while(getchar() != '\n');//clear stdin
} else if (shallowDepth < 2 || shallowDepth > 5){
invalid = 1;
printf("\nThe depth of the shallow end must be between 2-5 feet.");
}
}while (invalid);
I have an assignment where the user must enter four inputs, one after another. They are:
character, float, float, int.
The main issue is how to check for errors and make sure the used entered valid input?
I have finished the character section but for the floats and ints, how can I check that only numbers are entered and print an error message if letters or symbols are entered?
Thought maybe isdigit() or isaplha() but unsure how to implement their use.
NOTE I have already used scanf() for the input but not sure how to check if input is valid?
If the user is required to enter a string, two floating point numbers and an integer, use
char s[1024];
float f1, f2;
int i;
if (sscanf (buff, "%s %f %f %d", s, &f1, &f2, &i) == 4) {
/* Could scan values as expected. */
} else {
/* Input not as expected. */
}
since sscanf returns the number of successfully scanned values. For the details, see the sscanf manual page. Note that scanning an unbounded string with %s has its problems with large inputs. This may not be an issue for homework assignments, but is definitely something to be aware of in production software.
With sscanf(), you can try to parse the content of a string as some data type, like an integer (with the %d format specifier) or floating point number (with %g).
The return value of sscanf() tells you if it was successful in interpreting the text as the desired data.
You can also use %n to learn how many characters sscanf() looked at, which is handy when you want to analyze in multiple steps.
I don't know how you're getting your values right now other than you're using scanf() as you mentioned in your post. So lets say you're doing something like this:
char buf[100];
scanf("%s", buf);
to get the float/int values. If you want to use isdigit() to verify they are all digit values you can loop as such:
int i = 0;
//need to check for a . for floats
//need to check for a - for negative numbers
while(isdigit(buf[i]) || buf[i] == '.' || buf[i] == '-')
i++;
if(i == strlen(buf)) // if we made it to the end of the string
//we have all digits, do all digit code
else
//there are numbers or symbols, ask for the number again, or terminate, or whatever
I started learning C programming and in this program I am trying to get user input and then a line at a time and decide if it contains non-int characters. I've been trying this method:
scanf("%d", &n);
if (isalpha(n))
{
i = -1;
}
I googled a bit and learned the function isalpha is good way to do it. However, I'm getting a segmentation fault every time I test the fragment above with non-int characters (letters for example). Any suggestion would be appreciated.
The %d format specifier forces scanf() to only accept strings of digits. Given anything else, it will fail and leave n unfilled (and assuming you didn't initialize n before, it will be filled with garbage).
The crux of the problem is that isalpha() expects a value between 0 and 255, and has an assertion to enforce it. At least on my VC++ compiler, it causes a crash with an access violation when given an invalid value (in non-debug mode).
To solve this you just have to switch to a %c format specifier. Converting n to a char would also be advisable as that makes your intent of reading a single character clearer.
EDIT: Given your clarifications in the comments, you can leave everything as is and simply check the return value of scanf() instead of going the isalpha() route. It returns the number of values read successfully, so when it encounters a non-integer or end of file, it will return 0. E.g.:
int main() {
int n;
while (scanf("%d", &n)) {
printf("Got int: %d\n", n);
}
}
I have no idea why you're getting a seg-fault. I'd have to see more of your program.
But using "%d" for scanf will only accept integer values and you'll get "0" for n that isn't an integer and therefore isalpha(n) will always be false and i will never be set to -1.
Perhaps you aren't initializing i and therefore it is never set. If you are referencing it later, that's probably the source of your seg-fault.
Use scanf("%c", &n), like this:
int main(char** argc, int argv) {
char n = 0;
int i = 0;
scanf("%c", &n);
if (isalpha(n)) {
i = -1;
}
printf("you typed %c, i=%d", n, i);
}
Make sure you have a character buffer to store the value in. Scan it as a string, and then use isalpha():
char buffer[32];
sscanf("%32s", buffer);
// loop and check characters...
if(isalpha(buffer[i])) ....
Note the use of %32s, this is to prevent buffer overflows (32 == size of buffer)
Given that n is an integer, we can diagnose that you are reading a value into n which is not in the range 0..255 plus EOF (normally -1), so that the code for isalpha(n) is doing something like:
(_magic_array[n]&WEIRD_BITMASK)
and the value of n is causing it to access memory out of control, hence the segmentation fault.
Since scanf():
Returns the number of successful conversions, and
Stops when there is a non-integer character (not a digit or white space or sign) in the input stream,
you can use:
#include <stdio.h>
int main(void)
{
char n = 0;
while (scanf("%c", &n) == 1)
printf("you typed %d\n", n);
return 0;
}