Login

First Steps in Programming

This article will show you how to write programs that can access and and manipulate data, and work with different data values each time you use them. It is excerpted from the book Beginning C by Ivor Horton (Apress, 2004; ISBN 1590592530).

BY NOW YOU’RE PROBABLY EAGER to create programs that allow your computer to really interact with the outside world. You don’t just want programs that work as glorified typewriters, displaying fixed information that you included in the program code, and indeed there’s a whole world of programming that goes beyond that.

Ideally, you want to be able to enter data from the keyboard and have the program squirrel it away somewhere. This would make the program much more versatile. Your program would be able to access and manipulate this data, and it would be able to work with different data values each time you executed it. This idea of entering different information each time you run a program is key to the whole enterprise of programming. A place to store an item of data that varies in a program is, not altogether surprisingly, called a variable, and that is what this chapter covers.

This is quite a long chapter, and it covers a lot of ground. By the time you reach the end of it, you’ll be able to write some really useful programs.

In this chapter you’ll learn

How memory is used and what variables are

How you can calculate in C

What different types of variables there are and what you use them for

What casting is and when you need to use it

How to write a program that calculates the height of a tree—any tree

Memory in Your Computer

First let’s look at how the computer stores the data that’s processed in your program. To understand this, you need to know a little bit about memory in your computer, so before you go into your first program, let’s take a quick tour of your computer’s memory.

The instructions that make up your program, and the data that it acts upon, have to be stored somewhere while your computer is executing that program. When your program is running, this storage place is the machine’s memory. It’s also referred to as main memory, or the random access memory (RAM) of the machine.

Your computer also contains another kind of memory called read-only memory (ROM). As its name suggests, you can’t change ROM; you can only read its contents or have your machine execute instructions contained within it. The information contained in ROM was put there when the machine was manufactured. This information is mainly programs that control the operation of the various devices attached to your computer, such as the display, the hard disk drive, the keyboard, and the floppy disk drive. On a PC, these programs are called the basic input/output system (BIOS) of your computer. I don’t need to refer to the BIOS in detail in this book. The interesting memory for your purposes is RAM: this is where your programs and data are stored when they execute. So let’s understand a bit more about it.

You can think of your computer’s RAM as an ordered sequence of boxes. Each of these boxes is in one of two states: either the box is full when it represents 1 or the box is empty when it represents 0. Therefore, each box represents one binary digit, either 0 or 1. The computer sometimes thinks of these in terms of true and false: 1 is true and 0 is false. Each of these boxes is called a bit, which is a contraction of “binary digit.”

NOTE If you can’t remember or have never learned about binary numbers, and you want to find out a little bit more, you’ll find more detail in Appendix A. However, you needn’t worry about these details if they don’t appeal to you. The important point here is that the computer can only deal with 1s and 0s—it can’t deal with decimal numbers directly. All the data that your program works with, including the program instructions themselves, will consist of binary numbers internally.

For convenience, the boxes or bits in your computer are grouped into sets of eight, and each set of eight bits is called a byte. To allow you to refer to the contents of a particular byte, each byte has been labeled with a number, starting from 0 for the first byte, 1 for the second byte, and going up to whatever number of bytes you have in your computer’s memory. This label for a byte is called its address. Thus, each byte will have an address that’s different from that of all the other bytes in memory. Just as a street address identifies a particular house uniquely by its house number, the address of a byte uniquely references that byte in your computer’s memory.

To summarize, you have your memory building blocks (called bits) that are in groups of eight (called bytes). A bit can only be either 1 or 0. This is illustrated in Figure 2-1.

Figure 2-1.Bytes in memory

Memory is often expressed in terms of so many kilobytes, megabytes, or even gigabytes. Here’s what those words mean:

1 kilobyte (or 1KB) is 1,024 bytes.

1 megabyte (or 1MB) is 1,024 kilobytes, which is 1,048,576 bytes.

1 gigabyte (or 1GB) is 1,024 megabytes, which is 1,073,741,841 bytes.

You might be wondering why you don’t work with simpler, more rounded numbers, such as a thousand, or a million, or a billion. The reason is that there are 1,024 numbers from 0 to 1,023, and 1,023 happens to be 10 bits that are all 1 in binary: 11 1111 1111, which is a very convenient binary value. So while 1,000 is a very convenient decimal value, it’s actually rather inconvenient in a binary machine—it’s 11 1110 1000, which is not exactly neat and tidy. The kilobyte (1,024 bytes) is therefore defined in a manner that’s convenient for your computer, rather than for you. Similarly, for a megabyte, you need 20 bits, and for a gigabyte, you need 30 bits. One point of confusion can arise here, particularly with disk drive capacities. Disk drive manufacturers often refer to a disk as having a capacity of 537 megabytes or 18.3 gigabytes, when they really mean 537 million bytes and 18.3 billion bytes. Of course, 537 million bytes is only 512 megabytes and 18.3 billion bytes is only 17 gigabytes.

Now that you know a bit about bytes, let’s see how you can use this memory in your programs.

What Is a Variable?

A variable is a specific piece of memory in your computer that consists of one or more contiguous bytes. Every variable has a name, and you can use that name to refer to that place in memory to retrieve what it contains or store a new data value there.

Let’s start with a program that displays your salary using the printf()function that you saw in Chapter 1. Assuming your salary is $10,000, you can already write that program very easily:

/* Program 2.1 What is a Variable? */#include <stdio.h>void main(){printf(“My salary is $10000″);}

I’m sure you don’t need any more explanation about how this works; it’s almost identical to the programs you developed in Chapter 1. So how can you modify this program to allow you to customize the message depending on a value stored in memory? There are, as ever, several ways of doing this. What they all have in common, though, is that they use a variable.

In this case, you could allocate a piece of memory that you could call, say, salary, and store the value 10000 in it. When you want to display your salary, you could use the name you’ve given to the variable, which is salary, and the value that’s stored in it (10000) would be displayed. Wherever you use a variable name in a program, the computer accesses the value that’s stored there. You can access a variable however many times you need to in your program. And when your salary changes, you can simply change the value stored in the variable salary and the whole program will carry on working with the new value. Of course, all these values will be stored as binary numbers inside the computer.

You can have as many variables as you like in a program. The value that each variable contains, at any point during the execution of that program, is determined by the instructions contained in your program. The value of a variable isn’t fixed, and it can change as many times as you need it to throughout a program.

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.

{mospagebreak title=Variables That Store Numbers}

There are several different types of variables, and each type of variable is used for storing a particular kind of data. You’ll start by looking at variables that you can use to store numbers. There are actually several ways in which you can store numbers in your program, so let’s start with the simplest.

Integer Variables

Let’s look first at variables that store integers. An integer is any whole number without a decimal point. Examples of integers are as follows:

1 10,999,000,000 –1

You’ll recognize these values as integers, but what I’ve written here isn’t quite correct so far as your program is concerned. You can’t include commas in an integer, so the second value would actually be written in a program as 10999000000.

Here are some examples of numbers that are not integers:

1.234 999.9 2.0 –0.0005

Normally, 2.0 would be described as an integer because it’s a whole number, but as far as your computer is concerned it isn’t because it contains a decimal point. For your program, you must write the integer 2 as 2 with no decimal point. Integers are always written in a C program without a decimal point; if there’s a decimal point, it isn’t recognized an integer. Before I discuss variables in more detail (and believe me, there’s a lot more detail!), let’s look at a simple variable in action in a program, just so you can get a feel for how they’re used.

Try It Out: Using a Variable

Let’s go back to your salary. You can try writing the previous program using a variable:

The first three lines are exactly the same as in all the previous programs. Let’s look at the new stuff.

The statement that identifies the memory that you’re using to store your salary is as follows:

int salary; /* Declare a variable called salary */

This is called a variable declaration because it declares the name of the variable. The name, in this program, is salary.

CAUTION Notice that the variable declaration ends with a semicolon. If you omit the semicolon, your program will generate an error when you compile it.

The variable declaration also specifies the type of data that the variable will store. You’ve used the keyword int to specify that the variable, salary, will be used to store an integer value. The keyword int precedes the name of the variable. As you’ll see later, declarations for variables that store other kinds of data consist of another keyword specifying a data type followed by a variable name in a similar manner.

NOTE Remember, keywords are special C words that mean something specific to the compiler. You must not use them as variable names or your compiler will get confused.

The next statement is

salary = 10000;

This is a simple arithmetic assignment statement. It takes the value to the right of the equal sign and stores it in the variable on the left of the equal sign.

Here you’re declaring that the variable salary will have the value 10000. You’re storing the value on the right (10000) in the variable on the left (salary). The = symbol is called the assignment operator because it assigns the value on the right to the variable on the left.

You then have the familiar printf() statement, but it’s a little different from how you’ve seen it in action before:

printf(“My salary is %d.”, salary);

There are now two arguments inside the parentheses, separated by a comma. An argument is an item of data that’s passed to a function. In this program statement, the two arguments to the printf() function are as follows:

Argument 1is a control string, so called because it controls how the output specified by the following argument (or arguments) is to be presented. This is the character string between the double quotes.

Argument 2 is the variable salary. How this variable will be displayed is determined by the first argument—the control string.

The control string is fairly similar to the previous example in that it contains some text to be displayed. However, if you look carefully, you’ll see %d embedded in it. This is called a conversion specifier for the variable.

NOTE Conversion specifiers always start with a%character. Because a %in a control string always indicates the start of a conversion specifier, if you want to output a % character you must use the sequence %%.

Conversion specifiers determine how variables are displayed on the screen. In this case, you use a d, which is a decimal specifier that applies to integer values (whole numbers). It just means that the second argument, salary, will be interpreted and output as a decimal (base 10) number.

Both of these variables are declared as type int so they both store integer values. Notice that they’ve been declared in separate statements. Because they’re both of the same type, you could have saved a line of code and declared them together like this:

int brothers, brides;

When you declare several variables in one statement, the variable names following the data type are separated by commas, and the whole line ends with a semicolon. This can be a convenient format, although there’s a downside in that it isn’t so obvious what each variable is for, because if they appear on a single line you can’t add individual comments to describe each variable. However, you could write this single statement spread over two lines:

By spreading the statement out over two lines, you’re able to put the comments back in. The comments will be ignored by the compiler, so it’s still the exact equivalent of the original statement without the comments. Of course, you might as well write it as two statements.

Note that the declarations appear at the beginning of the executable code for the function. You should put all the declarations for variables that you intend to use at the beginning.

The next two statements initialize each of the variables with the same value, 7:

Note that the statements that declared these variables precede these statements. If one or the other of the declarations were missing or appeared later in the code, the program wouldn’t compile.

In the next statement is a control string that will display a line of text. Within this text, the %d conversion specifiers will be replaced by the values currently stored in the variables that appear as the second and third arguments to the printf() function call—in this case, brides and brothers:

printf(“%d brides for %d brothers”, brides, brothers);

The conversion specifiers are replaced in order by the values of the variables that appear as the second and subsequent arguments to the printf() function, so the value of brides corresponds to the first specifier, and the value of brothers corresponds to the second. This would be clearer if you changed the statements that set the values of the variables as follows:

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.

{mospagebreak title=Naming Variables}

The name that you give to a variable, conveniently referred to as a variable name, can be defined with some flexibility. A variable name is a string of one or more letters, digits, and underscore characters (_) that begins with a letter (incidentally, the underscore character counts as a letter). Examples of good variable names are as follows:

Radius diameter Auntie_May Knotted_Wool D666

Because a name can’t begin with a digit, 8_Ball and 6_pack aren’t legal names. A variable name can’t include any other characters besides letters, underscores, and digits, so Hash! and Mary-Lou aren’t allowed as names. This last example is a common mistake, but Mary_Lou would be quite acceptable. Because spaces aren’t allowed in a name, Mary Lou would be interpreted as two variable names, Mary and Lou. Variables starting with one or two underscore characters are often used in the header files, so don’t use the underscore as the first letter when naming your variables; otherwise, you run the risk of your name clashing with the name of a variable used in the standard library. For example, names such as_this and_that are best avoided.

Although you can call variables whatever you want within the preceding constraints, it’s worth calling them something that gives you a clue to what they contain. Assigning the name x to a variable that stores a salary isn’t very helpful. It would be far better to call it salary and leave no one in any doubt as to what it is.

CAUTION The number of characters that you can have in a variable name will depend upon your compiler. Up to 31 characters are generally supported, so you can always use names up to this length without any problems. I suggest that you don’t make your variable names longer than this anyway, as they become cumbersome and make the code harder to follow. Some compilers will just truncate names that are too long.

Another very important point to remember when naming your variables is that C is case sensitive, which means that the names Democrat and democrat are completely different. You can demonstrate this by changing the printf() statement so that one of the variable names starts with a capital letter, as follows:

You’ll get an error message when you try to compile this version of the program. The compiler interprets the two variable names brides and Brides as different, so it doesn’t understand what Brides refers to. This is a common error. As I’ve said before, punctuation and spelling mistakes are one of the main causes of trivial errors.

Using Variables

You now know how to name and declare your variables, but so far this hasn’t been much more useful than anything you learned in Chapter 1. Let’s try another program in which you’ll use the values in the variables before you produce the output.

Try It Out: Doing a Simple Calculation

This program does a simple calculation using the values of the variables:

/* Program 2.4 Simple calculations */#include <stdio.h>void main(){ int Total_Pets; /* The total number of pets */ int Cats; /* The number of cats as pets */ int Dogs; /* The number of dogs as pets */ int Ponies; /* The number of ponies as pets */ int Others; /* The number of other pets */ /* Set the number of each kind of pet */ Cats = 2; Dogs = 1; Ponies = 1; Others = 46; /* Calculate the total number of pets */ Total_Pets = Cats + Dogs + Ponies + Others; printf(“We have %d pets in total”, Total_Pets); /* Output the result */}

This example produces the output

=======================================================We have 50 pets in total =======================================================

HOW IT WORKS

As in the previous examples, all the statements between the braces are indented by the same amount. This makes it clear that all these statements belong together. You should always organize your programs the way you see here: indent a group of statements that lie between an opening and closing brace by the same amount. It makes your programs much easier to read.

You first define five variables of type int:

int Total_Pets; /* The total number of pets */ int Cats; /* The number of cats as pets */ int Dogs; /* The number of dogs as pets */ int Ponies; /* The number of ponies as pets */ int Others; /* The number of other pets */

Because each of these variables will be used to store a count of a number of animals, it’s definitely going to be a whole number. As you can see, they’re all declared as type int.

Note that you could have declared all five variables in a single statement and included the comments, as follows:

int Total_Pets, /* The total number of pets */ Cats, /* The number of cats as pets */ Dogs, /* The number of dogs as pets */ Ponies, /* The number of ponies as pets */ Others; /* The number of other pets */

The statement is spread over several lines so that you can add the comments in an orderly fashion. Notice that there are commas separating each of the variable names. Because the comments are ignored by the compiler, this is exactly the same as the following statement:

int Total_Pets, Cats, Dogs, Ponies, Others;

You can spread C statements over as many lines as you want. The semicolon determines the end of the statement, not the end of the line.

Now back to the program. The variables are given specific values in these four assignment statements:

Cats = 2; Dogs = 1; Ponies = 1; Others = 46;

At this point the variable Total_Pets doesn’t have an explicit value set. It will get its value as a result of the calculation using the other variables:

Total_Pets = Cats + Dogs + Ponies + Others;

In this arithmetic statement, you calculate the sum of all your pets on the right of the assignment operator by adding the values of each of the variables together. This total value is then stored in the variable Total_Pets that appears on the left of the assignment operator. The new value replaces any old value that was stored in the variable Total_Pets.

The printf() statement shows the result of the calculation by displaying the value of Total_Pets:

printf(“We have %d pets in total”, Total_Pets);

Try changing the numbers of some of the types of animals, or maybe add some more of your own. Remember to declare them, initialize their value, and include them in the Total_Pets statement.

Initializing Variables

In the previous example, you declared each variable with a statement such as this:

int Cats; /* The number of cats as pets */

You set the value of the variable Cats using this statement:

Cats = 2;

This sets the value of the variable Cats to 2.

So what was the value before this statement was executed? Well, it could be anything. The first statement creates the variable called Cats, but its value will be whatever was left in memory from the last program that used this bit of memory. The assignment statement that appeared later set the value to 2, but it would be much better to initialize the variable when you declare it. You can do this with the following statement:

int Cats = 2; /* The number of cats as pets */

This statement declares the variable Cats as type intand sets its initial value to 2.

Initializing variables as you declare them is a very good idea in general. It avoids any doubt about what the initial values are, and if the program doesn’t work as it should, it can help you track down the errors. Avoiding leaving spurious values for variables when you create them also reduces the chances of your computer crashing when things do go wrong. Inadvertently working with junk values can cause all kinds of problems. From now on, you’ll always initialize variables in the examples, even if it’s just to 0.

Arithmetic Statements

The previous program was the first one that really did something. It was very simple— just adding a few numbers—but it was a significant step forward. This was an elementary example of using an arithmetic statement to perform a calculation. Now let’s look at some more sophisticated calculations that you can do.

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.

{mospagebreak title=Basic Arithmetic Operations}

In C, an arithmetic statement is of the following form:

Variable_Name = Arithmetic_Expression;

The arithmetic expression on the right of the=operator specifies a calculation using values stored in variables and/or explicit numbers that are combined using arithmetic operators such as addition (+), subtraction (-), multiplication (*), and division (/). There are also other operators, as you’ll see.

In the previous example, the arithmetic statement was

Total_Pets = Cats + Dogs + Ponies + Others;

The effect of this statement is to calculate the value of the arithmetic expression to the right of the=and store that value in the variable specified on the left.

In C, the=symbol defines an action. It doesn’t specify that the two sides are equal, as it does in mathematics. It specifies that the value resulting from the expression on the right is to be stored in the variable on the left. This means that you could have

Total_Pets = Total_Pets + 2;

This would be ridiculous as a mathematical equation, but in programming it’s fine. Let’s look at it in context. Imagine you’d rewritten the last part of the program to include the preceding statement. Here’s a fragment of the program as it would appear with the statement added:

After executing the first statement here, Total_Pets contains the value 50. Then, in the second line, you add 2 to that value and store the result back in the variable Total_Pets. The final total that will be displayed is therefore 52.

NOTE In assignment operations, the expression on the right side of the=sign is evaluated first, and the result is then stored in the variable on the left. The new value replaces the value that was previously contained in the variable to the left of the assignment operator.

Any expression that results in a numeric value is described as an arithmetic expression. The following are all arithmetic expressions:

3 1+2 Total_Pets Cats + Dogs – Ponies

Evaluating any of these expressions produces a single numeric value. In a moment, you’ll take a closer look at how an expression is made up, and you’ll look into the rules governing its evaluation. First, though, you’ll try some simple examples using the basic arithmetic operators that you have at your disposal. Table 2-1 shows these operators.

Table 2-1. Basic Arithmetic Operators

Operator

Action

+

Addition

-

Subtraction

*

Multiplication

/

Division

%

Modulus

You may not have come across the modulus operator before. It just calculates the remainder after dividing the value of the expression on the left of the operator by the value of the expression on the right. For this reason it’s sometimes referred to as the remainder operator. The expression 12%5 would produce 2, because 12 divided by 5 leaves a remainder of 2. You’ll look at this in more detail shortly. All these operators work as you’d expect with the exception of division, which has a slight aberration from the norm when applied to integers, as you’ll see. Let’s try some more arithmetic operations.

Try It Out: Subtraction and Multiplication

Let’s look at a food-based program that demonstrates subtraction and multiplication:

I couldn’t fit the statement in the space available, so after the comma following the first argument to printf(), I put the rest of the statement on a new line. You can spread statements out like this to make them easier to read or fit within a given width on the screen.

Note that you could not split the string that is the first argument in this way. An explicit newline character isn’t allowed in the middle of a string. When you need to split a string over two or more lines, each segment of the string on a line must have its own pair of double quotes delimiting it. For example, you could write the previous statement as follows:

Where there are two or more strings immediately following one another like this, the compiler will join them together to form a single string.

You display the values stored in eaten and cookies using the conversion specifier,%d, for integer values. The value of eaten will replace the first %d in the output string, and the value of cookies will replace the second. The string will be displayed starting on a new line because of the n at the beginning.

The next statement sets the variable eaten to a new value:

eaten = 3; /* New value for cookies to be eaten */

The new value, 3, replaces the previous value stored in eaten, which was 2. You then go through the same sequence of operations as you did before:

Here the second argument to the printf() function is an arithmetic expression rather than just a variable. The compiler will arrange for the result of the expression total_eaten*cookie_calories to be stored in a temporary variable, and that value will be passed as the second argument to the printf() function. You can always use an expression for an argument to a function as long as it evaluates to a result of the required type.

Easy, isn’t it? Let’s take a look at division and the modulus operator.

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.

{mospagebreak title=Try It Out: Division and the Modulus Operator}

Suppose you have a jar of 45 cookies and a group of 7 children. You’ll share out the cookies equally among the children and work out how many each child has. Then you’ll work out how many cookies are left over.

/* Program 2.6 Cookies and kids */ #include <stdio.h> void main() { int cookies = 45; /* Number of cookies in the jar */ int children = 7; /* Number of children */ int cookies_per_child = 0; /* Number of cookies per child */ int cookies_left_over = 0; /* Number of cookies left over */ /* Calculate how many cookies each child gets when they are divided up */ cookies_per_child = cookies/children; /* Number of cookies per child */ printf(“You have %d children and %d cookies”, children, cookies); printf(“nGive each childcookies.”,cookies_per_child); /* Calculate how many cookies are left over */ cookies_left_over = cookies%children; printf(“nThere are %d cookies left over.n”, cookies_left_over); }

When you run this program you’ll get this output:

======================================================You have 7 children and 45 cookiesGive each child 6 cookies.There are 3 cookies left over.============================================================

HOW IT WORKS

Let’s go through this program step by step. Four integer variables, cookies, children, cookies_per_child, and cookies_left_over, are declared and initialized with the following statements:

int cookies = 45; /* Number of cookies in the jar */int children = 7; /* Number of children */int cookies_per_child = 0; /* Number of cookies per child */int cookies_left_over = 0; /* Number of cookies left over */

The number of cookies is divided by the number of children by using the division operator / to produce the number of cookies given to each child:

cookies_per_child = cookies/children; /* Number of cookies per child */

The next two statements output what is happening, including the value stored in cookies_per_child:

You can see from the output that cookies_per_child has the value 6. This is because the division operator always produces an integer result when the operands are integers. The result of dividing 45 by 7 is 6, with a remainder of 3.

You calculate the remainder in the next statement by using the modulus operator:

cookies_left_over = cookies%children;

The expression to the right of the assignment operator calculates the remainder that results when the value of cookies is divided by the value of children.

Finally, you output the reminder in the last statement:

printf(“nThere are %d cookies left over.n”, cookies_left_over);

More on Division with Integers

Let’s look at the result of using the division and modulus operators where one or the other of the operands is negative. With division, if the operands have different signs, the result will be negative. Thus, the expression–45/7 produces the same result as the expression 45/–7, which is –6. If the operands in a division are of the same sign, then the result is positive. Thus, 45/7 produces the same result as –45/–7, which is 6.

With the modulus operator, the sign of the result is always the same as the sign of the left operand. Thus, 45%–7 results in the value 3, whereas –45%7 results in the value –3.

Unary Operators

The operators that you’ve dealt with so far have been binary operators. These operators are called binary operators because they operate on two data items. Incidentally, the items of data that an operator applies to are called operands. For example, the multiplication is a binary operator because it has two operands and the effect is to multiply one operand value by the other. However, there are some operators that are unary, meaning that they need only one operand. You’ll see more examples later, but for now you’ll just take a look at the single most common unary operator.

The Unary Minus Operator

You’ll find the unary operator very useful in more complicated programs. It makes whatever is positive negative, and vice versa. You might not immediately realize when you would use this, but think about keeping track of your bank account. Say you have $200 in the bank. You record what happens to this money in a book with two columns, one for money that you pay out and another for money that you receive. One column is your expenditure (negative) and the other is your revenue (positive).

You decide to buy a CD for $50 and a book for $25. If all goes well, when you compare the initial value in the bank and subtract the expenditure ($75), you should end up with what’s left. Table 2-2 shows how these entries could typically be recorded.

If these numbers were stored in variables, you could enter both the revenue and expenditure as positive values and only make the number negative when you wanted to calculate how much was left. You could do this by simply placing a minus sign (-) in front of the variable name.

To output the amount you had spent as a negative value, you could write

The minus sign will remind you that you’ve spent this money rather than gained it. Note that the expression-expenditure doesn’t change the value stored in expenditure— it’s still 75. The value of the expressionis –75.

The unary minus operator in the expression-expenditure specifies an action. Instructions must be executed in your program to evaluate this. This is subtly different from when you use the minus operator when you write a negative number such as –75 or –1.25. In this case, the minus doesn’t result in an action and no instructions need to be executed when your program is running. It simply instructs the compiler to create the appropriate negative constant in your program.

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.

{mospagebreak title=Variables and Memory}

So far you’ve only looked at integer variables without considering how much space they take up in memory. Each time you declare a variable, the computer allocates a space in memory big enough to store that particular type of variable. Every variable of a particular type will always occupy the same amount of memory—the same number of bytes—but different types of variables require different amounts of memory to be allocated.

NOTE The amount of memory occupied by variables of a given type will always be the same on a particular machine. However, in some instances a variable of a given type on one computer may occupy more memory than it does on another.

You saw at the beginning of this chapter how your computer’s memory is organized into bytes. Each variable will occupy some number of bytes in memory, so how many bytes are needed to store an integer? Well, 1 byte can store an integer value from –128 to +127. This would be enough for the integer values that you’ve seen so far, but what if you wanted to store a count of the average number of stitches in a pair of knee-length socks? One byte wouldn’t be anywhere near enough. Consequently, not only do you have variables of different types in C that store different types of numbers, one of which happens to be integers, but you also have several varieties of integer variables to provide for different ranges of integers to be stored.

As I describe each type of variable in the following sections, I’ll include a table containing the range of values that can be stored and the memory the variable will occupy. I’ll summarize all these in a complete table of all the variable types at the end of this chapter.

Integer Variable Types

You have three basic flavors of integer variables that you can declare. Each type is specified by a different keyword, as shown in Table 2-3.

Table 2-3. Keywords for Integer Variable Types

Keyword

Number of Bytes

Range of Values

int

2 or 4 (depending on

–32,768 to +32,767 or –2,147,438,648 to

your computer)

+2,147,438,647

short

2

–32,768 to +32,767

long

4

–2,147,438,648 to +2,147,438,647

The types short and long are really abbreviations for types short int and long int, but they’re almost always written in their abbreviated forms. Table 2-3 reflects the typical size of each type of integer variable, although the amount of memory occupied by variables of these types depends on the particular compiler you’re using. The only specific requirement is that type long won’t occupy less memory than type int, and type int won’t occupy less memory than type short. Outside of that, the compiler-writer has complete freedom to make the best use of the hardware arithmetic capabilities of the machine on which the compiler is executing.

Variables of type int should have the size most suited to the computer on which the code is executing. For example, consider the following statement:

int cookies = 0;

This statement declares a variable that will occupy 2 bytes on some machines and 4 bytes on others. You may also find that two different compilers on the same machine implement type int with different sizes. This variation may seem a little strange, but the int type is intended to correspond to the size of integer that the computer has been designed to deal with most efficiently, and this can vary not only between different types of machine, but also with the same machine architecture as the chip technology evolves over time. Ultimately, it’s the compiler that determines what you get. Although at one time many C compilers for the PC created int variables as 2 bytes, with more recent C compilers on a PC, variables of type int occupy 4 bytes. This is because all modern processors move data around at least 4 bytes at a time. If your compiler is of an older vintage, it may still use 2 bytes for type int, even though 4 bytes would now be better on the hardware you’re using.

NOTE The sizes of all these types are compiler dependent. The ANSI standard for the C language requires only that the size of shortvariables should be less than or equal to the size of type int, which in turn should be less than or equal to the size of type long.

If you use type short, you’ll probably get 2-byte variables. The previous declaration could have been written as follows:

short cookies = 0;

Because the keyword short is actually an abbreviation for short int, you could write this as follows:

short int cookies = 0;

This is exactly the same as the previous statement. When you write just short in a variable declaration, the int is implied. Most people prefer to use this form—it’s perfectly clear and it saves a bit of typing.

NOTE Even though type shortand type intmay occupy the same amount of memory on some machines, they’re still different types.

If you need integers with a bigger range—to store the average number of hamburgers sold in one day, for instance—you can use the keyword long:

long Big_Number;

Type long defines an integer variable with a length of 4 bytes, which provides for a range of values from –2,147,438,648 to +2,147,438,647. As noted earlier, you can write long int if you wish instead of long, because it amounts to the same thing.

Integer Constants

Because you can have different kinds of integer variables, you might expect to have different kinds of integer constants, and you do. If you just write an integer value 100, for example, this will be of type int. If you want to make sure it is type long, you must append an upper- or lowercase letter L to the numeric value. So the integer 100 as a long value is written 100L. Although it’s perfectly legal, a lowercase letter l is best avoided because it’s easily confused with the digit 1.

To declare and initialize the variable Big_Number, you could write this:

long Big_Number = 1287600L;

An integer value will also be type long if it’s outside the range of type int. Thus, if your compiler implementation uses 2 bytes to store type int values, the values 1000000 and 33000 will be of type long by default, because they won’t fit into 2 bytes.

You write negative integer constants with a minus sign, for example:

int decrease = -4;long below_sea_level = -100000L;

You can also write integer values in hexadecimal form—that is, to base 16. The digits in a hexadecimal number are the equivalent of decimal values 0 to 15, and they’re represented by 0 through 9 and A through F (or a through f). Because there needs to be a way to distinguish between 9910and 9916, hexadecimal numbers are written with the prefix 0x or 0X. You would therefore write 9916in your program as 0x99 or as 0X99.

Hexadecimal constants are most often used to specify bit patterns because each hexadecimal digit corresponds to 4 binary bits. The bitwise operators that you’ll see in the next chapter are usually used with hexadecimal constants that define masks. If you’re unfamiliar with hexadecimal numbers, you can find a detailed discussion of them in Appendix A.

Floating-Point Values

Floating-point variables are used to store floating-point numbers. Floating-point numbers hold values that are written with a decimal point, so you can represent fractional as well as integral values. The following are examples of floating-point values:

1.6 0.00008 7655.899

Because of the way floating-point numbers are represented, they hold only a fixed number of decimal digits; however, they can represent a very wide range of values— much wider than integer types. Floating-point numbers are often expressed as a decimal value multiplied by some power of 10. For example, each of the previous examples of floating-point numbers could be expressed as shown in Table 2-4.

Table 2-4. Expressing Floating-Point Numbers

Value

With an Exponent

Can Also Be Written in C As

1.6

0.16✕101

0.16E1

0.00008

0.8✕10-4

0.8E4

7655.899

0.7655899✕104

0.7655899E4

The center column shows how the numbers in the left column could be represented with an exponent. This isn’t how you write them in C; it’s just an alternative way of representing the same value designed to link to the right column. The right column shows how the representation in the center column would be expressed in C. The E in each of the numbers is for exponent, and you could equally well use a lowercase e. Of course, you can write each of these numbers in your program without an exponent, just as they appear in the left column, but for very large or very small numbers, the exponent form is useful. I’m sure you’d rather write 0.5E-15 than 0.0000000000000005, wouldn’t you?

Floating-Point Variables

There are three different types of floating-point variables, as shown in Table 2-5.

Table 2-5. Floating-Point Variable Types

Number

Keyword

of Bytes

Range of Values

float

4

±3.4E38 (7 decimal digits precision)

double

8

±1.7E308 (15 decimal digits precision)

long double

10

±1.2E4932 (19 decimal digits precision)

These are typical values for the number of bytes occupied and the ranges of values that are supported. Like the integer types, the memory occupied and the range of values are dependent on the machine and the compiler. The type long double is sometimes exactly the same as type double with some compilers. Note that the number of decimal digits of precision is only an approximation because floating-point values will be stored internally in binary form.

A floating-point variable is declared in a similar way to an integer variable. You just use the keyword for the floating-point type that you want to use:

float Radius;double Biggest;

If you need to store numbers with up to seven digits of accuracy (a range of 10-38to+38), then you should use variables of type float. Values of type float are known as single precision floating-point numbers. This type will occupy 4 bytes in memory, as you can see from the table. Using variables of type double will allow you to store double precision floating-point values. Each variable of type double will occupy 8 bytes in memory and give you 15-digit precision with a range of 10-308to 10+308. Variables of type double suffice for the majority of requirements, but some specialized applications require even more accuracy and range. The long double type provides the exceptional range and precision shown in the table.

To write a constant of type float, you append an f to the number to distinguish it from type double. You could have initialized the last two variables with these statements:

float Radius = 2.5f;double Biggest = 123E30;

The variable Radius has the initial value 2.5, and the variable Biggest is initialized to the number that corresponds to 123 followed by 30 zeroes. Any number that you write containing a decimal point is of type double unless you append the F to make it type float. When you specify an exponent value with E or e, the constant need not contain a decimal point. For instance, 1E3f is of type float and 3E8 is of type double.

To specify a long double constant, you need to append an upper- or lowercase letter L to the number, for example:

long double huge = 1234567.89123L;

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.

{mospagebreak title=Division Using Floating-Point Values}

As you’ve seen, division operations with integer operands always produce an integer result. Unless the left operand of a division is an exact multiple of the right operand, the result will be inherently inaccurate. Of course, the way integer division works is an advantage if you’re distributing cookies to children, but it isn’t particularly useful when you want to cut a 10-foot plank into four equal pieces. This is a job for floating-point values.

Division operations with floating-point values will give you an exact result—at least, a result that is as exact as it can be with a fixed number of digits of precision. The next example illustrates how division operations work with variables of type float.

Try It Out: Division with Values of Type float

Here’s a simple example that just divides one floating-point value by another and displays the result:

You use the format specifier %f to display floating-point values. In general, the format specifier that you use must correspond to the type of value that you’re outputting. If you output a value of type float with the specifier %d that’s intended for use with integer values, you’ll get rubbish. This is because the float value will be interpreted as an integer, which it isn’t. Similarly, if you use %f with a value of an integer type, then you’ll also get rubbish as output.

More on Format Specifiers

In the last example, you got a lot of decimal places in the output that you really didn’t need. You may be good with a rule and a saw, but you aren’t going to be able to cut the plank with a length of 2.500000 feet rather than 2.500001 feet. You can specify the number of places that you want to see after the decimal point in the format specifier. To obtain the output to two decimal places, you would write the format specifier as %.2f. To get three decimal places, you would write %.3f.

You can change the printf() statement in the last example so that it will produce more suitable output:

The first format specification corresponds to the plank_length variable and will produce output with two decimal places. The second specification will produce no decimal places—this makes sense here because the piece_count value is a whole number. The last specification is the same as the first. Thus, if you run the example with this version of the last statement, the output will be

=======================================================A plank 10.00 feet long can be cut into 4 pieces 2.50 feet long.=======================================================This is much more appropriate and looks a lot better.

The field width for the output has been determined by default. The printf() function works out how many character positions will be required for a value, given the number of decimal places you specify. However, you may want to decide the field width yourself. This will be the case if you want to output a column of values so they line up. If you let the printf() function work out the field width, you’re likely to get a ragged column of output. A more general form of the format specifier for floating-point values can be written like this:

%[width][.precision]f

The square brackets here aren’t part of the specification. They enclose bits of the specification that are optional, so you can omit either the width or the.precision, or both. The width value is an integer specifying the total number of characters in the output: the field width. The precision value is an integer specifying the number of decimal places that are to appear after the decimal point.

You could rewrite printf() from the last example to specify the field width as well as the number of digits you want after the decimal point, for example:

I changed the text a little to get it to fit across the page here. The first value now will have a field width of 8 and two decimal places after the decimal point. The second value, which is the count of the number of pieces, will have a field width of 5 characters and no decimal places. The third value will be presented in a field width of 6 with two decimal places.

When you specify the field width, the value will be right-aligned by default. If you want the value to be left-aligned in the field, you just put a minus sign following the %. For instance, the specification %-10.4f will output a floating-point value left-aligned in a field width of 10 characters with four digits following the decimal point.

Note that you can specify a field width and the alignment in the field with a specification for outputting an integer value. For example, %-15d specifies an integer value will be presented left-aligned in a field width of 15 characters.

There’s more to format specifiers than I’ve introduced here, and you’ll learn more about them later. Try some variations out using the previous example. In particular, see what happens when the field width is too small for the value.

More Complex Expressions

You know that arithmetic can get a lot more complicated than just dividing a couple of numbers. In fact, if that was all you were trying to do, then you may as well use paper and pencil. Now that you have the tools of addition, subtraction, multiplication, and division at your disposal, you can start to do some really heavy calculations.

For these more complicated calculations, you’ll need more control over the sequence of operations when an expression is evaluated. Parentheses provide you with this capability. They can also help to make expressions clearer when they’re getting intricate.

Parentheses in Arithmetic Expressions

You can use parentheses in arithmetic expressions, and they work much as you’d expect. Subexpressions contained within parentheses are evaluated in sequence from the innermost pair of parentheses to the outermost, with the normal rules that you’re used to for operator precedence, where multiplication and division happen before addition or subtraction. Therefore, the expression 2 * (3 + 3 * (5 + 4)) evaluates to 60. You start with the expression 5 + 4, which produces 9. Then you multiply that by 3, which gives 27. Then you add 3 to that total (giving 30) and multiply the whole lot by 2.

You can also insert spaces to separate operands from operators to make your arithmetic statements more readable. If you’re not quite sure of how an expression will be evaluated according to the precedence rules, you can always put in some parentheses to make sure it produces the result you want.

Try It Out: Arithmetic in Action

This time you’ll have a go at calculating the circumference and area of a circular table from an input value for its diameter radius. You may remember from elementary math the equations to calculate the area and circumference of a circle using π or pi (circumference = 2πr and area = πr2, whereris the radius). If you don’t, then don’t worry. This isn’t a math book, so just look at how the program works.

You declare and initialize five variables, where Pi has its usual value. Note how all the initial values have an f at the end because you’re initializing values of type float. Without the f the values would be of type double. They would still work here, but you would be introducing some unnecessary conversion that the compiler would have to arrange, from type double to type float.

The following statement outputs a prompt for input from the keyboard:

printf(“Input the diameter of the table:”);

The next statement deals with reading the value for the diameter of the table. You use a new standard library function, the scanf()function, to do this:

scanf(“%f”, &diameter); /* Read the diameter from the keyboard */

The scanf() function is another function that requires the stdio.h header file to be included. This function handles input from the keyboard. In effect it takes what you enter through the keyboard and interprets it as specified by the first argument, which is a control string between double quotes. In this case the control string is “%f” because you’re reading a value of type float. It stores the result in the variable specified by the second argument, diameter in this instance. The first argument is a control string similar to what you’ve used with the printf() function, except that here it controls input rather than output.

You’ve undoubtedly noticed something new here: the & preceding the variable name diameter. This is called the address of operator, and it’s needed to allow the scanf() function to store the value that is read in your variable, diameter. The reason for this is bound up with the way argument values are passed to a function. For the moment, I won’t go into a more detailed explanation of this; you’ll see more on this in Chapter 11. The only thing to remember is to use the address of operator (the & sign) before a variable when you’re using the scanf()function, and not to use it when you use the printf() function.

You’ll see a lot more on how scanf() works later in the book, but for now the basic set of format specifiers you can use for reading data of various types are as follows:

To read a value of type short %hdTo read a value of type int %dTo read a value of type long %ldTo read a value of type float %f or %eTo read a value of type double %lf or %le

In the %ld and %lf format specifiers, l is a lowercase L. Don’t forget, you must always prefix the name of the variable that’s receiving the input value with &. Also, if you use the wrong format specifier—if you read a value into a variable of type float with %d, for instance—the data value in your variable won’t be correct, but you’ll get no indication that a junk value has been stored.

Next, you have three statements that calculate the results you’re interested in:

The first statement calculates the radius as half of the value of the diameter that was entered. The second statement computes the circumference of the table, using the value that was calculated for the radius. The third statement calculates the area. Note that if you forget the f in 2.0f, you’ll probably get a warning message from your compiler. This is because without the f, the constant is of type double, and you would be mixing different types in the same expression. You’ll see more about this later.

The next two statements output the values you’ve calculated:

printf(“nThe circumference is %.2f”, circumference); printf(“nThe area is %.2fn”, area);

These two printf() statements output the values of the variables circumference and area using the format specifier %.2f. As you’ve already seen, in both statements the format control string contains text to be displayed, as well as a format specifier for the variable to be output. The format specification outputs the values with two decimal places after the point. The default field width will be sufficient in each case to accommodate the value that is to be displayed.

Of course, you can run this program and enter whatever values you want for the diameter. You could experiment with different forms of floating-point input here, and you could try entering something like 1E1f, for example.

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.

{mospagebreak title=Defining Constants}

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.

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:

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:

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 inJan: 23500Feb: 19300Mar: 21600Total stock sold in first quarter: -1136Sales 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:

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 inn Jan: %dn Feb: %dn Mar: %dn”, JanSold,FebSold,MarSold); printf(“Total stock sold in first quarter: % ldn”,QuarterSold); /* Calculate the total revenue for the quarter and output it */ RevQuarter = QuarterSold/150*Revenue_Per_150; printf(“Sales revenue this quarter is:$ %.2fn”,RevQuarter);}

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.

{mospagebreak title=Type Casting in Arithmetic Expressions}

Let’s look at the original expression to calculate the quarterly revenue again and see how you can control what goes on so that you end up with the correct result:

RevQuarter = QuarterSold/150*Revenue_Per_150;

You know that if the result is to be correct, this statement has to be amended so that the expression is calculated in floating-point form. If you cast the value of Quarter-Sold to type float, then the expression will be evaluated as floating-point and your problem will be solved. To convert the value of a variable to another type, you place the type that you want to cast the value to in parentheses in front of the variable. The statement to calculate the result correctly will thus be

RevQuarter = (float)QuarterSold/150.0f*Revenue_Per_150;

This is exactly what you require. You’re using the right types of variables in the right places. You’re also ensuring you don’t use integer arithmetic when you want to keep the fractional part of the result of a division.

Even without the explicit cast statement in the expression, the result was in floating-point form, even though it was still wrong. This is because the compiler automatically casts one or other of the operands when it’s dealing with an operation that involves values of different types. Your computer can perform only binary arithmetic operations (add, subtract, multiply, divide, and remainder) when both operands are of the same type. When the operands that are involved in an operation are of different types, the compiler arranges for the value that is of a type with a more limited range to be converted to the type of the other variable. So, referring back to the expression to calculate revenue:

QuarterSold / 150 * Revenue_Per_150

This was evaluated as 64400 (int)/150 (int), which equals 429 (int). Then 429 (intconverted to float) is multiplied by 4.5 (float), giving 1930.5 (float).

An automatic conversion applies when a binary operator applies operands of different types. With the first operation, the numbers are both of type int, so the result is of type int. With the second operation, the first value is type int and the second value is type float. Type int is more limited in its range than type float, so the value of type int is automatically cast to type float. Whenever there is a mixture of types in an arithmetic expression, C will use a set of specific rules to decide how the expression will be evaluated. Let’s have a look at some of these conversion rules now.

Conversion Rules in Casting

As I’ve said, for each operation in an expression that involves operands of different types, your compiler will promote the operand with the type that has the more restricted range of values to be the same type as the other operand. The order of types in this context from highest to lowest is long double, then double, then float, followed by long, then int, then short, and finally the lowest, char. You haven’t seen type char yet, but you’ll be looking at it in a moment.

Let’s see how these conversion rules apply in practice. Suppose you declare three variables:A as type double,B as type float, and C as typelong. You can see how the expression A + B – C will be evaluated.

The operation A + B will be carried out first. Because A is type double and B is type long,B will be converted to type double and the result will therefore be type double. To subtract C from this result, C is first converted to double and you end up with the final result as type double.

Casts in Assignment Statements

You can also cause an implicit cast to be applied by assigning the value of one type to a variable of a different type. This can cause values to be truncated so information is lost.

For instance, if you assign a float or double value to a variable of type int or long, the fractional part of the float or double will be lost, and just the integer part will be stored. The following code fragment illustrates this situation:

int number = 0;float value = 2.5f;number = value;

The value stored in number will be 2. Because you’ve assigned the value of decimal (2.5) to the variable, number, which is of type int, the fractional part,.5, will be lost and only the 2 will be stored. Notice how I’ve used a specifier f at the end of 2.5f.

Note that an assignment statement that may lose information because an automatic cast has to be applied will usually result in a warning from the compiler. However, the code will still compile, so there’s a risk that your program may be doing things that will result in incorrect results. Generally, it’s better to put explicit casts in your code wherever conversions that may result in information being lost are necessary.

More Numeric Data Types

To complete the set of numeric data types, I’ll now cover those that I haven’t yet discussed. The first is one that I mentioned previously: type char. A variable of type char can store the code for a single character. Because it stores a character code, which is an integer, it’s considered to be an integer type. Because it’s an integer type, the value stored can be treated just as an integer and can participate in arithmetic calculations.

The Character Type

Values of type char occupy the least amount of memory of all the data types. They require just 1 byte. The integer that’s stored in a variable of type char can be interpreted as a signed or unsigned value, depending on your compiler. An unsigned integer type is simply one that allows negative as well as positive integral values to be stored. As an unsigned type, the value stored in a variable of type char can range from 0 to 255. As a signed type, a variable of type char can store values from –128 to +127. Of course, both ranges correspond to the same set of bit patterns: from 0000 0000 to 1111 1111. With unsigned values, all 8 bits are data bits, so 0000 0000 corresponds to 0 and 1111 1111 corresponds to 255. With unsigned values, the leftmost bit is a sign bit, so –128 is the binary value 1000 0000, 0 is 0000 0000, and 127 is 0111 1111. The value 1111 1111 as a signed binary value is the decimal value –1.

Thus, from the point of view of representing character codes, which are bit patterns, it doesn’t matter whether type char is regarded as signed or unsigned. Where it does matter is when you perform arithmetic operations on values of type char.

A char variable can hold any single character, so you can specify the initial value for a variable of type char by a character constant. A character constant is a character written between single quotes. Here are some examples:

char letter = ‘A';char digit = ‘9’;char exclamation = ‘!';

You can use escape sequences to specify character constants too:

char newline = ‘n';char tab = ‘t';char single_quote = ”';

Of course, in every case the variable will be set to the code for the character between single quotes. The actual code value will depend on your computer environment, but by far the most common is American Standard Code for Information Interchange (ASCII). You can find the ASCII character set in Appendix B.

You can also initialize a variable of type char with an integer value, as long as the value fits into the range for type char with your compiler, for example:

char character = 74; /* ASCII code for the letter J */

A variable of type char has a sort of dual personality: you can interpret it as a character or as an integer. Here’s an example of an arithmetic operation with a value of type char:

Thus, you can perform arithmetic on a value of type char and still treat it as a character.

Character Input and Character Output

You can read a single character from the keyboard and store it in a variable of type char using the scanf()function with the format specifier %c:

char ch = 0;scanf(“%c”, &ch); /* Read one character */

To write a single character to the command line with the printf()function, you use the same format specifier,%c:

printf(“The character is %c”, ch);

Of course, you can output the numeric value of a character too:

printf(“The character is %c and the code value is %d”, ch, ch);

This statement will output ch as a character and as a numeric value.

Try It Out: Character Building

If you’re completely new to programming, you may be wondering how on earth the computer knows whether it’s dealing with a character or an integer. The reality is that it doesn’t. It’s a bit like in Alice’s Adventures in Wonderland when Humpty Dumpty told Alice, “When I use a word, it means just what I choose it to mean—neither more nor less.” An item of data in memory can mean whatever you choose it to mean. A byte containing the value 70 is a perfectly good integer. It’s equally correct to regard as the code for the letter J.

Let’s look at an example that should make it clear. Here, you’ll use the conversion specifier %c, which indicates that you want to output a value of type char as a character rather than an integer:

/* Program 2.13 Characters and numbers */#include <stdio.h>void main(){ char first = ‘T'; char second = 20; printf(“nThe first example as a letter looks like this – %c”, first); printf(“nThe first example as a number looks like this – %d”, first); printf(“nThe second example as a letter looks like this- %c”, second); printf(“nThe second example as a number looks like this- %dn”, second);}

The output from this program is

=======================================================The first example as a letter looks like this – TThe first example as a number looks like this – 84The second example as a letter looks like this – ¶The second example as a number looks like this – 20=======================================================

HOW IT WORKS

The program starts off by declaring two variables of type char:

char first = ‘T'; char second = 20;

One is initialized with a letter and the other with a number.

The next four statements output each of the variables in two ways:

printf(“nThe first example as a letter looks like this – %c”, first_example);printf(“nThe first example as a number looks like this – %d”, first_example);printf(“nThe second example as a letter looks like this – %c”, second_example);printf(“nThe second example as a number looks like this – %dn”, second_example);

The %c conversion specifier interprets the contents of the variable as a single character, and the % dspecifier interprets it as an integer. The numeric values that are output are the codes for the corresponding characters. These are ASCII codes in this instance, and will be in most instances, so that’s what you’ll assume throughout this book.

As I’ve noted, not all computers use the ASCII character set, so you may get different values than those shown previously. As long as you use the notation ‘character’ for a character constant, you’ll get the character that you want regardless of the character coding in effect.

You could also output the integer values of the variables of type char as hexadecimal values by using the format specifier %x instead of %d. You might like to try that.

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.

{mospagebreak title=Try It Out: Arithmetic with Values of Type char}

Let’s look at another example in which you apply arithmetic operations to values of type char:

=======================================================Character values C A Numerical equivalents 67 65 92The number 40 is the code for the character (=======================================================

HOW IT WORKS

This program demonstrates how you can happily perform arithmetic with char variables that you’ve initialized with characters. The first three statements in the body of main() are as follows:

char first = ‘A'; char second = ‘B'; char last = ‘Z';

These initialize the variables first, second, and last to the character values you see. The numerical value of these variables will be the ASCII codes for the respective characters. Because you can treat them as numeric, as well as characters, you can perform arithmetic operations with them.

The next statement initializes a variable of type char with an integer value:

char number = 40;

The initializing value must be within the range of values that a 1-byte variable can store, so with my compiler where char is a signed type it must be between –128 and 127. Of course, you can interpret the contents of the variable as a character. In this case, it will be the character that has the ASCII code value 40, which happens to be a left parenthesis.

These statements create new values and therefore new characters from the values stored in the variables first, second, and last; the results of these expressions are stored in the variables ex1, ex2, and ex3.

The next two statements output the three variables ex1, ex2, and ex3 in two different ways:

The first statement interprets the values stored as characters by using the %-5c conversion specifier. This specifies that the value should be output as a character left-aligned in a field width of 5. The second statement outputs the same variables again, but this time interprets the values as integers by using the %-5d specifier. The alignment and the field width are the same but d specifies the output is an integer. You can see that the two lines of output show the three characters with their ASCII codes aligned below on the next line.

The last line outputs the variable number as a character and as an integer:

printf(“nThe number %d is the code for the character % cn”, number, number);

To output the variable twice, you just write it twice—as the second and third arguments to the printf() function. It’s output first as an integer value and then as a character.

This ability to perform arithmetic with characters can be very useful. For instance, to convert from uppercase to lowercase, you simply add the result of ‘a’-‘A’ (which is 32 for ASCII) to the uppercase character. To achieve the reverse, just subtract ‘a’-‘A’. You can see how this works if you have a look at the decimal ASCII values for the alphabetic characters in Appendix B.

Unsigned Integers: Using Positive Integers

If you’re sure that you’ll be dealing with just positive integers, there’s a way of increasing the maximum value that you can use. The unsigned modifier can be used with all of the basic integer types that I’ve covered, to define types that store only positive integers. This allows you to handle integers roughly twice as large as you otherwise might. You use the unsigned modifier as follows:

unsigned char a_value; /* Can be from 0 to +255 */unsigned int number; /* Can be from 0 to +65,535 */unsigned long big_number; /* Can be from 0 to 4,294,967,295 */

You must be absolutely sure that you need only positive values if you want to use these. Unsigned variables can’t store negative values at all.

When you want to specify an integer constant as unsigned, you append the letter U as upper- or lowercase to the numeric value. For example, you could write

number = 25U;

This sets the unsigned variable number of type int to 25.

If you want to define a constant that is of type unsigned long, you need a U and an L as a suffix to the numeric value. You can specify the letters in upper- or lowercase, for example:

big_number = 100000000UL;

This stores the value 100,000,000 in the variable big_number.

You use the format specifier %u to output an unsigned integer. You can also include a field width specification and a-for left alignment in the field if you wish.

For example, you could output the value of the unsigned integer variable called number with this statement:

printf(“The value of number is %-12u”, number);

The field width is 12 here and the value will be left-aligned in the field. I’ve now covered all the numeric data types in C; Table 2-6 presents all of them.

Table 2-6. Numeric Data Types

Number

Range

Variable Type

Keyword

of Bytes

of Values

Character

char

1

–128 to +127 or 0 to 255

Unsigned character

unsigned char

1

0 to 255

Integer

int

2 or 4

–32,768 to +32,767 or

–2,147,438,648 to

+2,147,438,647

Unsigned integer

unsigned int

2 or 4

0 to 65,535 or 0 to

4,294,967,295

Short integer

short

2

–32,768 to +32,767

Unsigned short integer

unsigned short

2

0 to 65,535

Long integer

long

4

–2,147,438,648 to

+2,147,438,647

Unsigned long integer

unsigned long

4

0 to 4,294,967,295

Single precision

float

4

±3.4E38 (6 digits)

floating-point

Double precision

double

8

±1.7E308 (15 digits)

floating-point

Extended double

long double

10

±1.2E4932 (19 digits)

precision floating-point

Finding the Limits

I mentioned earlier and in various other places in this chapter how the limits for the range of values for some of these numerical types can vary from one system and/or compiler to another. This is obviously going to be a problem in some situations in which you really need to be able to determine within your program what the limits are in a particular instance. The C standard library includes header files that can provide you with this information. The limits.h header file provides information about integer types and the float.h header file does the same for floating-point types.

The limits.h header file contains definitions for symbols (not variables) such that define the upper and lower limits for each signed integer type. For instance,INT_MIN and INT_MAX are the symbols representing the upper and lower limits for type int, and CHAR_MINand CHAR_MAX represent the limits for type char. For unsigned types only symbols for upper limits are defined because the lower limit is always zero. There are symbols with similarly formed names for each of the integer types in Table 2-6.

In the float.h header are symbols with the names FLT_MIN and FLT_MAX that represent the minimum and maximum positive values of type float. There are similar symbols such as DBL_MIN, DBL_MAX,LDBL_MIN, and LDBL_MAX for the double and long double types. If you look in the documentation for the library that comes with your compiler, you’ll find many other symbols that represent values for other parameters relating to the implementation of the floating-point types on your system.

Let’s see how you can access some of these with an example.

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.

{mospagebreak title=Try It Out: Finding the Limits}

This program just outputs the values corresponding to the symbols defined in the header files:

/* Program 2.15 Finding the limits */#include <stdio.h>#include < limits.h > /* For limits on integer types */ #include <float.h> /* For limits on floating-point types */void main(){ printf(“Variables of type char store values from %d to % d”, CHAR_MIN, CHAR_MAX); printf(“nVariables of type unsigned char store values from 0 to %u”, UCHAR_MAX); printf(“nVariables of type short store values from % d to %d”, SHRT_MIN, SHRT_MAX); printf(“nVariables of type unsigned short store values from 0 to %u”,USHRT_MAX); printf(“nVariables of type int store values from %d to % d”, INT_MIN, INT_MAX); printf(“nVariables of type unsigned int store values from 0 to %u”, UINT_MAX); printf(“nVariables of type long store values from %d to %d”,LONG_MIN, LONG_MAX); printf(“nVariables of type unsigned long store values from 0 to %u”, ULONG_MAX); printf(“nnThe size of the smallest non-zero value of type float is %.3e”,FLT_MIN); printf(“nThe size of the largest value of type float is %.3e”, FLT_MAX); printf(“nThe size of the smallest non-zero value of type double is %.3e”,DBL_MIN); printf(“nThe size of the largest value of type double is %.3e”, DBL_MAX); printf(“nThe size of the smallest non-zero value of type long double is %.3e”,DBL_MIN); printf(“nThe size of the largest value of type long double is %.3en”, DBL_MAX);}

You’ll get output somewhat similar to the following:

===================================================Variables of type char store values from -128 to 127 Variables of type unsigned char store values from 0 to 255 Variables of type short store values from -32768 to 32767 Variables of type unsigned short store values from 0 to 65535Variables of type int store values from -2147483648 to 2147483647Variables of type unsigned int store values from 0 to 4294967295Variables of type long store values from -2147483648 to 2147483647Variables of type unsigned long store values from 0 to 4294967295The magnitude of the smallest non-zero value of type float is 1.175e-038The magnitude of the largest value of type float is 3.403e+038The magnitude of the smallest non-zero value of type double is 2.225e-308 The magnitude of the largest value of type double is 1.798e+308The magnitude of the smallest non-zero value of type long double is 2.225e-308The magnitude of the largest value of type long double is 1.798e+308======================================================

HOW IT WORKS

You just output the values of the symbols in a series of printf() function calls. You have used the %u specifier to output the unsigned integer values. If you use %d for the maximum value of an unsigned type, values that have the leftmost bit (the sign bit for signed types) as 1 won’t be interpreted correctly.

You use the %e specifier for the floating-point limits, which presents the values in exponential form. You also specify just three digits precision, as you don’t need the full accuracy in the output. The %f specifier presents values without an exponent, so it’s rather inconvenient for very large or very small values. If you try it in the example, you’ll see what I mean.

Introducing the sizeof Operator

You can find out how many bytes are occupied by a given type by using the sizeof operator. Of course, sizeof is a keyword in C. The expression sizeof(int) will result in the number of bytes occupied by a variable of type int. The sizeof operator has other uses too, but for the moment let’s just use it to find out how many bytes are occupied by each type.

Try It Out: Discovering the Number of Bytes Occupied by a Given Type

This program will output the number of bytes occupied by each numeric type:

Because the sizeof operator results in an integer value, you can output it using the %d specifier. Note that you can also obtain the number of bytes occupied by avariable, var_name, with the expression sizeof var_name. Obviously, the space between the sizeof keyword and the variable name in the expression is essential.

Now you know the range limits and the number of bytes occupied by each numeric type with your compiler.

The op= Form of Assignment

C is fundamentally a very concise language, so it provides you with abbreviated shortcuts for some operations. Consider the following line of code:

number = number + 10;

This sort of assignment, in which you’re incrementing or decrementing a variable by some amount, occurs very often, so there’s a shorthand version:

number += 10;

The +=operator after the variable name is one example of a family of op=operators. This statement has exactly the same effect as the previous one and it saves a bit of typing. The op in op= can be any of the following arithmetic operators:

+ – * / %

If you suppose number has the value 10, then you can write the following statements:

number *= 3; /* number will be set to number*3 which is 30 */number /= 3; /* number will be set to number/3 which is 3 */number %= 3; /* number will be set to number%3 which is 1 */

The op in op= can also be a few other operators that you haven’t encountered yet:

<< >> & ^ |

I’ll defer discussion of these to Chapter 3, however.

The op= set of operators always works in the same way. If you have a statement of the form

lhs op= rhs;

then the effect is the same as a statement of the form

lhs = lhs op (rhs);

Note the parentheses around the rhs expression. This means that op applies to the value that results from evaluating the entire rhs expression, whatever it is. So just to reinforce your understanding of this, let’s look at few more examples. The statement

variable *= 12;is the same asvariable = variable * 12;

You now have two different ways of incrementing an integer variable by 1. Both of the following statements increment count by 1:

count = count+1;count += 1;

You’ll learn about yet another way of doing this in the next chapter. This amazing level of choice tends to make it virtually impossible for indecisive individuals to write programs in C.

Because the op in op= applies to the result of evaluating the rhs expression, the statement

a /= b+1;is the same asa = a/(b+1);

Your computational facilities have been somewhat constrained so far. You’ve been able to use only a very basic set of arithmetic operators. You can get more power to your calculating elbow using standard library facilities, so before you come to the final example in this chapter, you’ll take a look at some of the mathematical functions that the standard library offers.

Mathematical Functions

The math.h header file includes declarations for a wide range of mathematical functions. To give you a feel for what’s available, you’ll take a look at those that are used most frequently. All the functions return a value of type double.

You have the set of functions shown in Table 2-7 available for numerical calculations of various kinds. These all require arguments to be of type double.

Table 2-7. Functions for Numerical Calculations

Function

floor(x) ceil(x) fabs(x) log(x) log10(x) exp(x) sqrt(x) pow(x, y)

Operation

Returns the largest integer that isn’t greater thanxas typedoubleReturns the smallest integer that isn’t less thanxas typedoubleReturns the absolute value ofxReturns the natural logarithm (base e) ofxReturns the logarithm to base 10 ofxReturns the value of exReturns the square root ofxReturns the value ofxy

Because 180 degrees is the same angle as π radians, dividing an angle measured in degrees by 180 and multiplying by the value of π will produce the angle in radians, as required by these functions.

You also have the inverse trigonometric functions available:asin(),acos(), and atan(), as well as the hyperbolic functions sinh(),cosh(), and tanh(). Don’t forget, you must include math.h into your program if you wish to use any of these functions. If this stuff is not your bag, you can safely ignore this section.

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.

{mospagebreak title=Designing a Program}

Now it’s time for the end-of-chapter real-life example. It would be a great idea to try out some of the numeric types in a new program. I’ll take you through the basic elements of the process of writing a program from scratch. This involves receiving an initial specification of the problem, analyzing the problem, preparing a solution, writing the program and, of course, running the program and testing it to make sure it works. Each step in the process can introduce problems, beyond just the theory.

The Problem

The height of a tree is of great interest to many people. For one thing, if a tree is being cut down, knowing its height tells you how far away safe is. This is very important to those with a nervous disposition. Your problem is to find out the height of a tree without using a very long ladder, which itself would introduce risk to life and limb. To find the height of a tree, you’re allowed the help of a friend—preferably a short friend. You should assume that the tree you’re measuring is taller than both you and your friend. Trees that are shorter than you present little risk, unless they’re of the spiky kind.

The Analysis

Real-world problems are rarely expressed in terms that are directly suitable for programming. Before you consider writing a line of code, you need to be sure that you have a complete understanding of the problem and how it’s going to be solved. Only then can you estimate how much time and effort will be involved in creating the solution.

The analysis phase involves gaining a full understanding of the problem and determining the logical process for solving it. Typically this requires a significant amount of work. It involves teasing out any detail in the specification of the problem that is vague or missing. Only when you fully understand the problem can you begin to express the solution in a form that’s suitable for programming.

You’re going to determine the height of a tree using some simple geometry and the heights of two people: you and one other. Let’s start by naming the tall person (you) Lofty and the shorter person (your friend) Shorty. If you’re vertically challenged, the roles can be reversed. For more accurate results, the tall person should be significantly taller than the short person. Otherwise the tall person could consider standing on a box. The diagram in Figure 2-2 will give you an idea of what you’re trying to do in this program.

Figure 2-2.The height of a tree

Finding the height of the tree is actually quite simple. You can get the height of the tree, h3, if you know the other dimensions shown in the illustration: h1and h2, which are the heights of Shorty and Lofty, and d1and d2, which are the distances between Lofty and Shorty, and from Lofty to the tree, respectively. You can use the technique of similar triangles to work out the height of the tree. You can see this in the simplified diagram in Figure 2-3.

Figure 2-3.Similar triangles

Here, because the triangles are similar, height1 divided by distance1 is equal to height2 divided by distance2. Using this relationship, you can get the height of the tree from the height of Shorty and Lofty and the distances to the tree as shown in Figure 2-4.

The triangles ADE and ABC are the same as those shown in the previous diagram. Using the fact that the triangles are similar, you can calculate the height of the tree as shown in the bottom equation in the diagram.

This means that you can calculate the height of the tree in your program from four values:

The distance between Shorty and Lofty, d1in the diagram. You’ll use the variable shorty_to_lofty to store this value.

The distance between Lofty and the tree, d2in the diagram. You’ll use the variable lofty_to_tree to store this value.

The height of Lofty to the top of his head, h2in the diagram. You’ll use the variable lofty to store this value.

The height of Shorty, but only up to the eyes, h1in the diagram. You’ll use the variable shorty to store this value.

You can then plug these values into the equation for the height of the tree.

Figure 2-4.Calculating the tree height

Your first task is to get these four values into the computer. You can then use your ratios to find out the height of the tree, and finally output the answer. The steps are as follows:

Input the values you need.

Calculate the height of the tree using the equation in the diagram.

Display the answer.

The Solution

This section outlines the steps you’ll take to solve the problem.

Step 1

Your first step is to get the values that you need to work out the height of the tree. This means that you have to include the stdio.h header file, because you need to use both printf()and scanf(). You then have to decide what variables you need to store these values in. After that, you can use printf() to prompt for the input and scanf() to read the values from the keyboard.

You’ll provide for the heights of the participants to be entered in feet and inches for the convenience of the user. Inside the program, though, it will be easier to work with all heights and distances in the same units, so you’ll convert all measurements to inches. You’ll need two variables to store the heights of Shorty and Lofty in inches. You’ll also need a variable to store the distance between Lofty and Shorty, and another to store the distance from Lofty to the tree—both distances in inches, of course.

In the input process, you’ll first get Lofty’s height as a number of whole feet and then as a number of inches, prompting for each value as you go along. You can use two more variables for this: one to store the feet value and the other to store the inches value. You’ll then convert these into just inches and store the result in the variable you’ve reserved for Lofty’s height. You’ll do the same thing for Shorty’s height (but only up to the height of his or her eyes) and finally the same for the distance between them. For the distance to the tree, you’ll use only whole feet, because this will be accurate enough—and again you’ll convert the distance to inches. You can reuse the same variables for each measurement in feet and inches that is entered. So here goes with the first part of the program:

Notice how the program code is spaced out to make it easier to read. You don’t have to do it this way, but if you decide to change the program next year, it will make it much easier to see how the program works if it’s well laid out. You should always add comments to your programs to help with this. It’s particularly important to at least make clear what the variables are used for and to document the basic logic of the program.

You use a variable that you’ve declared asconstto convert from feet to inches. The variable name, inches_per_foot, makes it reasonably obvious what’s happening when it’s used in the code. This is much better than using the “magic number” 12 explicitly. Here you’re dealing with feet and inches, and most people will be aware that there are 12 inches in a foot. In other circumstances, the significance of numeric constants may not be so obvious, though. If you’re using the value 0.22 in a program calculating salaries, it’s much less apparent what this might be; therefore, the calculation may seem rather obscure. If you create a const variable tax_rate that you’ve initialized to 0.22 and use that instead, then the mist clears.

Step 2

Now that you have all the data you need, you can calculate the height of the tree. All you need to do is implement the equation for the tree height in terms of your variables. You’ll need to declare another variable to store the height of the tree.

The statement to calculate the height is essentially the same as the equation in the diagram. It’s a bit messy, but it translates directly to the statement in the program to calculate the height.

Step 3

Finally, you need to output the answer. To present the result in the most easily understandable form, you’ll convert the result that you’ve stored in tree_height, which is in inches, back into feet and inchches:

/* Program 2.17 Calculating the height of a tree */ #include <stdio.h>

And there you have it. The output from the program looks something like this:

======================================================Enter Lofty’s height to the top of his/her head, in whole feet first: 6 … and then inches: 2Enter Shorty’s height up to his/her eyes, in whole feet: 4 … and then inches: 6Enter the distance between Shorty and Lofty, in whole feet : 5 … and then inches: 0Finally enter the distance to the tree to the nearest foot: 20The height of the tree is 12 feet and 10 inches.======================================================

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.

{mospagebreak title=Summary}

This chapter covered quite a lot of ground. By now, you know how a C program is structured, and you should be fairly comfortable with any kind of arithmetic calculation. You should also be able to choose variable types to suit the job at hand. Aside from arithmetic, you’ve added quite a bit of input and output capability to your knowledge. You should now feel at ease with inputting values into variables via scanf().You can output text and the values of character and numeric variables to the screen. You won’t remember it all the first time around, but you can always look back over this chapter if you need to. Not bad for the first two chapters, is it?

In the next chapter, you’ll start looking at how you can control the program by making decisions depending on the values you enter. As you can probably imagine, this is key to creating interesting and professional programs.

Table 2-9 summarizes the variable types and the format specifiers you’ve used so far. You can look back at these when you need a reminder as you continue through the book.

Table 2-9. Variable Types and Value Ranges

Number

Type

of Bytes

Range of Values

char

1

–128 to +127 or 0 to 255

unsigned char

1

0 to 255

int

2 or 4

–32,768 to +32,767 or –2,147,438,648 to +2,147,438,647

unsigned int

2 or 4

0 to 65,535 or 0 to 4,294,967,295

short

2

–32,768 to +32,767

unsigned short

2

0 to 65,535

long

4

–2,147,438,648 to +2,147,438,647

unsigned long

4

0 to 4,294,967,295

float

4

±3.4E38 (6 digits)

double

8

±1.7E308 (15 digits)

long double

10

±1.2E4932 (19 digits)

The output format specifiers shown in Table 2-10 are used to control the form of output for values of variables of various types when you’re using the printf() function.

Table 2-10. Output Format Specifiers

Output Format Specifier

Outputs

%[-][width]c

Character value

%[-][width]d

Signed decimal integer

%[width]x

Unsigned hexadecimal integer using “abcdef”

%[width]X

Unsigned hexadecimal integer using “ABCDEF”

%[-][width]ld

Long signed decimal integer

(Continued)

85

Table 2-10. Output Format Specifiers (Continued)

Output Format Specifier

Outputs

%[-][width]u

Unsigned decimal integer

%[-][width][.precision]f

Floating-point number without an exponent

%[-][width][.precision]e

Floating-point number with an exponent

The square brackets enclose optional elements in a format specification and aren’t part of the specifier. The-specifies that the output is left-aligned in the field, the default being right-aligned. The width specifies the field width as an integral number of characters..precision specifies the number of places that are to be displayed following the decimal point. Thus,%-15.6f is a specification for a left-aligned floating-point value in a field 15 characters wide with 6 digits following the decimal point.

The input format specifiers shown in Table 2-11 are used to control how data is interpreted when it’s read from the keyboard by the scanf() function.

Table 2-11. Input Format Specifiers

Input Format Specifier Reads

%c A single character%hd A value of type short %d A value of type int %ld A value of type long %for%e A value of type float%lfor%le A value of type double

You’ll see more on scanf() input specifiers in later chapters.

Exercises

The following exercises enable you to try out what you’ve learned in this chapter. If you get stuck, look back over the chapter for help. If you’re still stuck, you can download the solutions from the Downloads area of the Apress website (http://www.apress.com), but that really should be a last resort.

Exercise 2-1. Write a program that prompts the user to enter a distance in inches and then outputs that distance in yards, feet, and inches.

Exercise 2-2. Write a program that prompts for input of the length and width of a room in feet and inches, and then calculates and outputs the floor area in square yards with two decimal places after the decimal point.

Exercise 2-3. You’re selling a product that’s available in two versions: type 1 is a standard version priced at $3.50, and type 2 is a deluxe version priced at $5.50. Write a program using only what you’ve learned up to now that prompts for the user to enter the product type and a quantity, and then calculates and outputs the price for the quantity entered.

Exercise 2-4. Write a program that prompts for the user’s weekly pay in dollars and the hours worked to be entered through the keyboard as floating-point values, and then calculate and output the average pay per hour in the following form: