Why is my C program to do simple depreciation not working? - c

I am trying to write a program in C to calculate a salvage value after depreciation of something. However, in when I run this:
int main(int argc, char* argv){
printf("enter the purchase price, years of service, annual depreciation:\n");
double purchasePrice, yearsOfService, annualDep;
scanf("%d %d %d", &purchasePrice, &yearsOfService, &annualDep);
printf("purchase price is %d dollars\n", purchasePrice);
printf("years of service is %d years\n", yearsOfService);
printf("annual depreciation is %d dollars\n", annualDep);
double salvageValue = purchasePrice - (yearsOfService * annualDep);
printf("The salvage value of the item is %d", salvageValue);
return 0;
}
it prints out the purchasePrice instead of what the salvageValue should be. What is going on?

Replace your scanf call with:
scanf("%lf %lf %lf", &purchasePrice, &yearsOfService, &annualDep);
scanf requires that all passed pointers match the types of the conversion specifiers (and vice versa). You're passing pointers to doubles, and the correct conversion specifier is %lf.
From the scanf manpage:
l indicates either that the conversion will be one of d, i, o, u, x, X, or n and the next pointer is a pointer to a long int or unsigned long int (rather than int), or that the conversion will be one of e, f, or g and the next pointer is a pointer to double (rather than float). Specifying two l characters is equivalent to L. If used with %c or %s, the corresponding parameter is considered as a pointer to a wide character or wide-character string respectively.
(emphasis mine)

Related

Why in C does taking input using int format to a char change the value of another char variable?

I took input in %d format into a character using scanf() because I didn't want more than 8 bits. But doing so changed the value of another char variable.
Code:
#include <stdio.h>
int main() {
char a;
char b;
printf("Enter a: ");
scanf("%c", &a);
printf("a = %c\n", a);
printf("Enter b: ");
scanf("%d", &b);
printf("\na = %d\n", a);
printf("b = %d\n", b);
}
Output:
Enter a: c
a = c
Enter b: 56
a = 0
b = 56
Screenshot
scanf reads data from stdin and stores them according to the parameter format into the locations pointed by the additional arguments.
scanf("%d", &b);
With %d you are storing an integer into the char variable that can not hold an integer.
the Variable now grows into the other variable in stack above it.
if you compile with the flag "-fstack-protector-all" you should get the
*** stack smashing detected *** error on execution.
The formatting directives in a scanf format string indicate not just how to match the input, but also the type of the corresponding variable in which the resulting value is to be stored. If you pass a pointer to an object of a different type than the corresponding directive expects then you reap undefined behavior.
That's true even for a simple signedness mismatch, but in your case you have a size mismatch. For a %d directive without a size modifier, scanf expects to write the scanned integer value in an object of type [signed] int. If the pointer you pass instead points to a char, and if, as is the case in most implementations, int is larger than char, then it is particularly likely that the resulting undefined behavior manifests in unwanted ways, such as by producing changes in the values of other variables.
If you want to scan a number as a char-sized integer, then you should
Declare the variable as either signed char or unsigned char, not default char, and
Use the correct conversion specifier and size modifier for the chosen data type.
For example,
unsigned char b;
scanf("%hhu", &b);
%u is the format directive for an unsigned integer, and the hh modifier instructs scanf that the destination variable is the size of a char / signed char / unsigned char.
If you want a signed integer then it would be similar, but with the %d formatting directive:
signed char b;
scanf("%hhd", &b);
As a matter of style, do not use default char for numeric data, even if you are confident that the range of values you need to support is a subset of the intersection of the ranges of signed char and unsigned char. Especially so if you plan to use it with formatted I/O functions, because it is implementation-specific whether %hhd or %hhu is the correct directive for a default char.
I agree with the side effect you indicated. This happens when the compiler loads variables in memory one after the other. For example, I examined the change in variable a when a sufficiently large number is typed in variable b. I changed the code as follows.
#include <stdio.h>
#include <stdlib.h>
int main( void )
{
char a, b;
printf( "Address (a): %p\tAddress(b): %p\n", &a, &b);
printf( "Enter the values (a, b): " );
scanf( "%c, %d", &a, &b);
printf( "Value (a): %d\tValue (b): %d\n", a, b);
return EXIT_SUCCESS;
}
Then, when I tested the code, I realized the consequences of this side effect.
The tested code is interpreted in the image below.

scanf("%f", &weight) and scanf("%f", weight) How to determine when to add prefix &

I read the following codes:
//talkback.c -- nosy, informative program
#include <stdio.h>
#include <string.h> //for strlen() prototype
#define DENSITY 62.4 //human density in lbs per cu ft
int main() {
float weight, volume;
int size, letters;
char name[40]; //name is an array of 40 characters
printf("Hi! What's your first name?\n");
scanf("%s", name);
printf("%s, what's your weight in pounds?\n", name);
scanf("%f", &weight);
size = sizeof name;
letters = strlen(name);
volume = weight / DENSITY;
printf("Well, %s, your volumn is %2.2f cubit feet.\n", name, volume);
printf("Also, your first name has %d letters, \n", letters);
printf("and we have %d bytes to store it.\n", size);
}
Run it and output:
In [13]: !./a.out
Hi! What's your first name?
Hery
Hery, what's your weight in pounds?
100
Well, Hery, your volumn is 1.60 cubit feet.
Also, your first name has 4 letters,
and we have 40 bytes to store it.
I noticed that scanf("%s", name); and scanf("%f", &weight); , the second has a prefix & ahead of weight.
How could I distinguish which situation to add the prefix or not?
scanf() stands for scan formatted string. Now while scanning input from a standard input stream, scanf() needs to put that input data into somewhere. To store the formatted input data, scanf() needs to know the memory location of a variable of the same data type.
That is why scanf() needs a pointer (a pointer in C stores memory location of a variable or an expression) to store input. The address-of operator (&) preceeding a variable i.e. &var Indicates the memory location of variable 'var'.
int var;
scanf("%d",&var);
char str[20];
scanf("%s",str);
For the second example, we do not need the address-of operator because C treats array name variable as a pointer.
printf() is the reverse function of scanf(). It prints the formatted string to the standard output. Printf doesn't need any memory location to print the output, it only needs the variable to get the data and formats it according to the format specifier.
printf("%c in ASCII is %d",65,65);
The output will be: A in ASCII is 65
Because when you are accepting strings(ie; character arrays) you don't need & in front of the variable name. This is because, scanf() expects address of the variable. For normal variables the variable name represents its value, whereas the for an array the array name is a pointer pointing to the first element of the array. So when you say weight the address of the first element in the array gets substituted and you don't need to use &.
I recommend to start from scanf c rerefence and pay attention to type. E.g. %f means type of argument float* - pointer to float. So you can use only pointer, i.e. address, and there are several way to provide address:
if you have just variable (float a;) you should use & operator applied for variable name;
if you have pointer (float * ptr; or float arr[10];) you can use ptr, or arr, or (arr+4), etc. (all of this have type float *), as well as you can use &arr[4] (here arr[4] is of type float, but &arr[4] is of type float *)
Note: before using float * ptr; in scanf pointer should be initialized with valid address, e.g. ptr = (float*)malloc(sizeof(float));
How about a simply example "when to add prefix &"?
scanf("%f", ...) expects a a following float *.
With float weight, weight is not a float *, but &weight is a float *.
float weight;
scanf("%f", &weight); // & needed
With float *p, p is a float *.
float weight;
float *p = &weight
scanf("%f", p); // no &
Tip: insure your compiler has all its warnings are enabled. A well enabled compiler will report a scanf() specifier and argument mis-match.

Double, Integer, Long double

I apologies in advance if there is a stupid error in this code, but I can't seem to trouble shoot it. My problem is this, I compile with GCC-8 (installed on Mac via home-brew), then execute in the terminal. When using int do define variables s & a, I get zeros as output using the print statements below. If I declare s & a variables as double I still get zeros for the first two print statements, and 1024 for the last print statement. I'm just lost as to what is going on. Appreciate any help!
/* square code */
#include <stdio.h>
int main() {
int s, a;
printf("enter the length of your square \n");
scanf("%f", &s);
a= s * s;
printf("the area of your square is %f cm using f placeholder \n", a);
printf("the area of your square is %lf cm uning fl placeholder\n", a);
printf("the area of your square is %d cm using d placeholder \n", a);
return(0);
}
int s;
scanf("%f", &s);
If s is an int then you need to scan it in like an int using "%d" instead of "%f". What you are doing is undefined behavior, both in scanf() and printf(). An integer needs to be scanned and printed as an integer.
I think the misunderstanding is that you treat the conversion specifiers %d and %f as defining only the output formatting, regardless of the type of value passed.
Actually each conversion specifier is tightly coupled with a particular type of argument it will accept; For example, %d is defined for integral types only, and all other types like floating point or string used together with %d will yield undefined behaviour (cf, for example, cpp-reference of printf for a more detailed explanation).
So double f=1.2;printf("%d",f) will not format a floating point value 1.2 as integral (someone might expect 1 being the output); It rather yields undefined behaviour, having any output (even no output), a crash, a... whatever.
Same applies to scanf-format specifiers, of course.
So if data type is int, use %d; if data type is double, use %f.
In your code you use s as an int, and when you use scanf you are using %f instead of %d. That's the reason why you are getting the first two outputs as a zero.
As for the third output, you will get the expected value, because in that case you are correctly using %d. See the code below:
int s;
printf("enter the value");
scanf("%d", &s);
printf("the area of square is=", s*s);
Hey guys thanks so much for the help. Before checking back this morning I tried one more thing, and alas it was a stupid error.
When declaring "double s,a", I realized my scanf() function was using scanf("%f",s) as opposed to the correct scanf("%lf", s)".
Also thanks for the help for use of %d when using "int s,a".

Scanf_s reading wrong input

For this code below (in C)
int small_a, small_b;
printf("Please input two numbers\n");
scanf_s("%d %d", &small_a, &small_b);
printf("%d %d", &small_a, &small_b);
int test_2nd = small_a - small_b;
if (test_2nd < 0) {
printf("a is smaller %d", &small_a);
}
else {
printf("b is smaller %d", &small_b);
The values it prints when I write 4 and 2 is a huge six digit number (5504620 and 5504608 in this case) I don't understand where it goes wrong. stdio.h has been included as a header.
The problem here is in the print statement. In the code
printf("%d %d", &small_a, &small_b);
you don't need (want) to take (print) the address. Remove that &.
That said, this actually invokes undefined behavior. %d with printf() expects an argument of type int and you're essentially supplying an int *, causing the UB.
FWIW, to print an address (pointer), you need to use %p format specifier and cast the argument to void *

"static char" vs. "char" in C

To practice variable declaration, placeholders and I/O calls, I did a sample assignment in the book that I am using to study. However, I keep running into a particular problem, in that when I try to declare more than one character variable for the purpose of input, even if the compiler doesn't catch any syntax error, the program when executing will only return one character variable. This is the code in question:
#include <stdio.h>
int main()
{
double penny=0.01;
double nickel=0.05;
double dime=0.1;
double quarter=0.25;
double value_of_pennies;
double value_of_nickels;
double value_of_dimes;
double value_of_quarters;
double TOTAL;
int P;
int N;
int D;
int Q;
char a,b;
//used "static char" instead of "char", as only using the "char" type caused a formatting error where only the latter character entered in its input would appear
printf("Please enter initials> \n");
printf("First initial> \n");
scanf("%s", &a);
printf("Second initial> \n");
scanf("%s", &b);
//"%s" was used as the input placeholder for type "char"
printf("%c.%c., please enter the quantities of each type of the following coins.\n", a, b);
printf("Number of quarters> \n");
scanf("%d", &Q);
printf("Number of dimes> \n");
scanf("%d", &D);
printf("Number of nickels> \n");
scanf("%d", &N);
printf("Number of pennies> \n");
scanf("%d", &P);
printf("Okay, so you have: %d quarters, %d dimes, %d nickels, and %d pennies.\n", Q, D, N, P);
value_of_pennies=penny*P;
value_of_nickels=nickel*N;
value_of_dimes=dime*D;
value_of_quarters=quarter*Q;
TOTAL=value_of_quarters+value_of_dimes+value_of_nickels+value_of_pennies;
printf("The total value of the inserted coins is $%.2lf. Thank you.\n", TOTAL);
//total field width omitted as to not print out any leading spaces
return(0);
}
And this is the transcribed output ("a", "e", and the four "1"s are sample arbitrary input values:
Please enter initials>
First initial>
a
Second initial>
e
.e., please enter the quantities of each type of the following coins.
Number of quarters>
1
Number of dimes>
1
Number of nickels>
1
Number of pennies>
1
Okay, so you have: 1 quarters, 1 dimes, 1 nickels, and 1 pennies.
The total value of the inserted coins is $0.41. Thank you.
I entered the characters "a" and "e" as input values for the char variables "a" and "b", but only "e" had shown up. On the other hand, should I have put a "static" in the "char" variable declaration, both inputted char values will be displayed in the relevant print call.
For future reference, I would like to ask about why such a thing would occur the way that it did, and the value of the "static" word in the declaration.
(As an aside, I am aware that I could have simply made the "value_of_(insert coin here)" variables as constant macros.)
With a definition like
char a,b;
writing a statement like
scanf("%s", &a);
scanf("%s", &b);
invokes undefined behaviour. %s is not a format specifier for a char. Using wrong format specifier can and will lead to UB. You should use %c to scan a char.
To elaboreate,
%s format specifier expects a corresponding argument which is a pointer to char array. It scans multiple characters until it encounters a space (whitespace character, to be pedantic) or newline or EOF.
%c format specifier expects a corresponding argument which is a pointer to char variable. It reads only one char from the input buffer.
So, with %s, if you supply the adress of a char variable, it will try to access beyond the allocated memory region for writing the scanned data, which will invoke UB.
You may want to read some more on printf(), scanf() and format specifiers before moving forward.
You have used the wrong format specifier for char. char uses %c not %s. As far as static goes, I'm a bit confused about your question. You say in a comment that you are using static char, but I do not see any variables declared as static char.

Resources