First Steps in Programming - Defining Constants
(Page 8 of 13 )
Although you defined Pi as a variable in the previous example, it’s really a constant value that you don’t want to change. The value of π is always a fixed number. The only question is how many digits precision you use in its specification. It would be nice to make sure its value stayed fixed in a program so it couldn’t be changed by mistake.
You actually have a couple of ways in which you can approach this. The first is to define Pi as a symbol that’s to be replaced in the program by its value during compilation. In this case, Pi isn’t a variable at all, but more a sort of alias for the value it represents. Let’s try that out.
Try It Out: Defining a Constant
Let’s look at specifying PI as an alias for its value:
/* Program 2.9 More round tables */
#include <stdio.h>
#define PI 3.14159f /* Definition of the symbol PI */
void main()
{
float radius = 0.0f;
float diameter = 0.0f;
float circumference = 0.0f;
float area = 0.0f;
printf("Input the diameter of a table:");
scanf("%f", &diameter);
radius = diameter/2.0f;
circumference = 2.0f*PI*radius;
area = PI*radius*radius;
printf("\nThe circumference is %.2f", circumference);
printf("\nThe area is %.2f", area);
}
This produces exactly the same output as the previous example.
HOW IT WORKS
After the comment and the #include directive for the header file, you have a preprocessing directive:
#definePI 3.14159f /* Definition of the symbol PI */
You’ve now defined PI as a symbol that is to be replaced in the code by 3.14159f. You use PI rather than Pi, as it’s a common convention in C to write identifiers that appear in a #define statement in capital letters. Wherever you reference PI within an expression in the program, the compiler will substitute the value you’ve specified for it in the #definedirective. All the substitutions will be made before compiling the program. When the program is ready to be compiled, it will no longer contain references toPI, as all occurrences will have been replaced by the sequence of characters that you’ve specified in the #define directive. This all happens internally while your program is processed by the compiler. Your source program will not be changed: it will still contain the symbol PI.
The second possibility is to define Pi as a variable, but to tell the compiler that its value is fixed and must not be changed. You can fix the value of any variable by prefixing the type name with the keyword const when you declare the variable, for example:
const float Pi = 3.14159f; /* Defines the value of Pi as
fixed */
Adding the keyword const in the declaration for Pi will cause the compiler to check that the code doesn’t attempt to change its value. Any code that does so will be flagged as an error and the compilation will fail. Let’s see a working example of this.
Try It Out: Defining a Variable with a Fixed Value
You’ll try using a constant in a variation of the previous example but shorten the code a little:
/* Program 2.10 Round tables again but shorter */
#include <stdio.h>
void main()
{
float diameter = 0.0f; /* The diameter of a table */
float radius = 0.0f; /* The radius of a table */
const float Pi = 3.14159f; /* Defines the value of Pi as
fixed */
printf("Input the diameter of the table:");
scanf("%f", &diameter);
float radius = diameter/2.0f;
printf("\nThe circumference is %.2f", 2.0f*Pi*radius);
printf("\nThe area is %.2f", Pi*radius*radius);
}
HOW IT WORKS
Following the declaration for the variable radius, you have this statement:
const float Pi = 3.14159f; /* Defines the value of
Pi as fixed */
This declares the variable Pi and defines a value for it; Pi is still a variable here, but the initial value you’ve given it can’t be changed. Theconstmodifier achieves this effect. It can be applied to any statement declaring a variable of any type to fix the value of that variable. Of course, the value must appear in the declaration in the same way as shown here: following an=sign after the variable name. The compiler will check your code for attempts to change variables that you’ve declared as const, and if it discovers that you’ve attempted to change a const variable it will complain. There are ways to trick the compiler to change const variables, but this defeats the whole point of using constin the first place.
The next two statements produce the output from the program:
printf("\nThe circumference is %.2f", 2.0f*Pi*radius);
printf("\nThe area is %.2f", Pi*radius*radius);
In this example, you’ve done away with the variables storing the circumference and area of the circle. The expressions for these now appear as arguments in the printf() statements where they’re evaluated, and their values are passed directly to the function.
As you’ve seen before, the value that you pass to a function can be the result of evaluating an expression rather than the value of a particular variable. The compiler will create a temporary variable to hold the value and that will be passed to the function. The temporary variable is subsequently discarded. This is fine, as long as you don’t want to use these values elsewhere.
Choosing the Correct Type for the Job You have to be careful when doing calculations as to the type of variable that you’re using. If you use the wrong type, then you may find that errors creep into your programs that can be hard to detect. This is best shown with an example.
Try It Out: The Right Types of Variables
Here’s an example of how things can go horribly wrong if you choose an unsuitable type for your variables:
/* Program 2.11 Choosing the correct type for the job 1*/ #include <stdio.h>
void main()
{
const float Revenue_per_150 = 4.5f;
short JanSold = 23500; /* Stock sold in January */
short FebSold = 19300; /* Stock sold in February */
short MarSold = 21600; /* Stock sold in March */
float RevQuarter = 0.0f; /* Sales for the quarter */
short QuarterSold = JanSold+FebSold+MarSold; /* Calculate
quarterly total */
/* Output monthly sales and total for the quarter */
printf("\nStock sold in\n Jan: %d\n Feb: %d\n Mar: %d",
JanSold,FebSold,MarSold);
printf("\nTotal stock sold in first quarter: %
d",QuarterSold);
/* Calculate the total revenue for the quarter and output
it */
RevQuarter = QuarterSold/150*Revenue_Per_150;
printf("\nSales revenue this quarter is:
$%.2f\n",RevQuarter);
}
These are fairly simple calculations, and you can see that the total stock sold in the quarter should be 64400. This is just the sum of each of the monthly totals, but if you run the program, the output you get is this:
=======================================================
Stock sold in
Jan: 23500
Feb: 19300
Mar: 21600
Total stock sold in first quarter: -1136
Sales revenue this quarter is:$-31.50
=======================================================
Obviously, all is not right here. It doesn’t take a genius or an accountant to tell you that adding three big, positive numbers together shouldn’t give a negative result!
HOW IT WORKS
First you define a constant that will be used in the calculation:
const Revenue_per_150 = 4.5f;
This defines the revenue obtained for every 150 items sold. There’s nothing wrong with that.
Next, you declare four variables and assign initial values to them:
short JanSold = 23500; /* Stock sold in January */
short FebSold = 19300; /* Stock sold in February */
short MarSold = 21600; /* Stock sold in March */
float RevQuarter = 0.0f; /* Sales for the quarter */
The first three variables are of type short, which is quite adequate to store the initial value. The RevQuarter variable is of type float because you want two decimal places for the quarterly revenue.
The next statement declares the variable QuarterSold and stores the sum of the sales for each of the months:
short QuarterSold = JanSold+FebSold+MarSold; /* Calculate
quarterly total */
Note that you’re initializing this variable with the result of an expression. This is possible only because the values of these variables are known to the compiler, so this represents what is known as a constant expression. If any of the values in the expression were determined during execution of the program—from a calculation involving a value that was read in, for instance—then this wouldn’t compile. The compiler can only use initial values that are explicit or are produced by an expression that the compiler can evaluate.
In fact, the cause of the erroneous results is in the declaration of the QuarterSold variable. You’ve declared it to be of type short and given it the initial value of the sum of the three monthly figures. You know that their sum is 64400 and that the program outputs a negative number. The error must therefore be in this statement.
The problem arises because you’ve tried to store a number that’s too large for type short. If you remember, the maximum value that a short variable can hold is 32,767. The computer can’t interpret the value of QuarterSold correctly and happens to give a negative result. The solution to your problem is to use a variable of type long that will allow you to store much larger numbers.
SOLVING THE PROBLEM
Try changing the program and running it again. You need to change only two lines in the body of the function main(). The new and improved program is as follows:
/* Program 2.12 Choosing the correct type for the job 2 */ #include <stdio.h>
void main()
{
const float Revenue_Per_150 = 4.5f;
short JanSold =23500; /* Stock sold in January */
short FebSold =19300; /* Stock sold in February
*/
short MarSold =21600; /* Stock sold in March */
float RevQuarter = 0.0f; /* Sales for the quarter */
long QuarterSold = JanSold+FebSold+MarSold; /* Calculate
quarterly total */
/* Output monthly sales and total for the quarter */
printf("Stock sold in\n Jan: %d\n Feb: %d\n Mar: %d\n",
JanSold,FebSold,MarSold);
printf("Total stock sold in first quarter: %
ld\n",QuarterSold);
/* Calculate the total revenue for the quarter and
output it */
RevQuarter = QuarterSold/150*Revenue_Per_150;
printf("Sales revenue this quarter is:$
%.2f\n",RevQuarter);
}
When you run this program, the output is more satisfactory:
=======================================================
Stock sold in
Jan: 23500
Feb: 19300
Mar: 21600
Total stock sold in first quarter: 64400
Sales revenue this quarter is: $1930.50
=======================================================
The stock sold in the quarter is correct, and you have a reasonable result for revenue. Notice that you use %ld to output the total stock sold. This is to tell the compiler that it is to use a long conversion for the output of this value. Just to check the program, calculate the result of the revenue yourself with a calculator.
The result you should get is, in fact, $1,932. Somewhere you’ve lost a dollar and a half! Not such a great amount, but try saying that to an accountant! You need to find the lost $1.50. Consider what’s happening when you calculate the value for revenue in the program:
RevQuarter = QuarterSold/150*Revenue_Per_150;
Here you’re assigning a value to RevQuarter. The value is the result of the expression on the right of the=sign. The result of the expression will be calculated, step by step, according to the precedence rules you’ve already looked at in this chapter. Here you have quite a simple expression that’s calculated from left to right, as division and multiplication have the same priority. Let’s work through it:
QuarterSold/150 is calculated as 64400/150, which should produce the result
429.333.
This is where your problem arises. QuarterSold is an integer and so the computer truncates the result of the division to an integer, ignoring the .333. This means that when the next part of the calculation is evaluated, the result will be slightly off:
429*Revenue_Per_150 is calculated as 429 * 4.5 which is 1930.50.
You now know where the error has occurred, but what can you do about it? You could change all of your variables to floating-point types, but that would defeat the purpose of using integers in the first place. The numbers entered really are integers, so you’d like to store them as such. Is there an easy solution to this? In this case there is. You can rewrite the statement as follows:
RevQuarter = Revenue_Per_150*QuarterSold/150;
Now the multiplication will occur first, and because of the way arithmetic with mixed operands works, the result will be of type float. The compiler will automatically arrange for the integer operand to be converted to floating-point.
When you then divide by 150, that operation will execute with float values too, with 150 being converted to 150f. The net effect is that the result will now be correct.
However, there’s more to it than that. Not only do you need to understand more about what happens with arithmetic between operands of different types, but also you need to understand how you can control conversions from one type to another. In C you have the ability to explicitly convert a value of one type to another type. This process is called casting.
This article is excerpted from Beginning C by Ivor Horton (Apress, 2004; ISBN 1590592530). Check it out at your favorite bookstore today. Buy this book now. |
Next: Type Casting in Arithmetic Expressions >>
More Code Examples Articles
More By Apress Publishing