Topic : An introduction to C
Author : Tom Torfs
Page : << Previous 6  Next >>
Go to page :


  right operand  result
   zero          zero           0
   zero          nonzero        0
   nonzero       zero           0
   nonzero       nonzero        1

logical OR: (||)

   left operand  right operand  result
   zero          zero           0
   zero          nonzero        1
   nonzero       zero           1
   nonzero       nonzero        1

Onto the next line of code:

   printf("a = %.1f\n", a);

This line outputs the value of a, which is 12.0. But 500/40 is 12.5, and since a double is used one could reasonably expect the decimal digits to be correct. The reason for the wrong result is that the constants 500 and 40 are both interpreted as integer values by the compiler. At least one of the constants should be explicitly made a floating-point constant by writing it as e.g. 500.0. That's what's done in the next line of code:

   a = 500.0 / 40; /* Fraction is NOT thrown away (floating point math) */

   printf("a = %.1f\n", a);


And this time the printf() will print the correct result.
Omitting this .0 (or just .) is a mistake beginners often make. The same goes for e.g. multiplying two int values into a long: if the result doesn't fit in an int, at least one of the constants must be explicitly made a long, e.g. 1000L*1000 instead of simply 1000*1000. There's also the U suffix to indicate an unsigned constant. There are more, but you'll rarely need any others.

   a++;

This is an example of the postfix increment operator. This is a special operator because it has the side effect of actually changing the value of the variable. The ++ (double plus) operator adds 1 to the value, the -- (double minus) operator substracts one from the value. Whether the operator is placed before (prefix) or after (postfix) the variable determines whether the value used in the expression is the one after resp. before the modification. An example will probably make this clear: (assume a and b are integer variables)

a = 5;
b = a++;
/* b will now be 5, a will be 6 */

a = 5;
b = ++a;
/* b will now be 6, a will be 6 */

You can't use something like:

a = a++;                      /* wrong! use a++; or a = a + 1; instead */


Because this code changes the variable a twice in the same line: in the assignment, and with the ++ operator. This has something to do with the so-called sequence points. For more information, see question 3.8 in the c.l.c FAQ, the URL can be found in: 17.2. Other interesting C-related online material However, in our example program we don't use the result of the expression, so the only effect is that a will be incremented by one, and will contain the value 13.5.

   b = (int)a;

This line assigns the value of a to b. But there is something special: the int between parentheses. This is called a typecast (or conversion). It basically tells the compiler "turn this double value into an integer value" [*]. If you would simply write b = a; this would automatically happen, but the compiler would probably give a warning because an int can't hold all the information that a double can (for example, the fractional digits we just calculated will be lost). Typecasting can be useful, but also dangerous, so you should avoid it when you can.
[*] Note that a typecasts does NOT reinterpret the bit pattern of a variable for the new type, but converts the value of the variable.

   b ^= 5;

This line uses a special assignment operator. It is actually a shorthand notation for:

   b = b ^ 5;   /* bitwise XOR of b with 5 */

Such a "shorthand" assignment operator exists for most operators (see table above).

   printf("b = %d\n",b);

This will output the value of b. Since the value of a that was assigned to b was 13 (1101b), the bitwise XOR operation with 5 (0101b) results in the value 8 (1000b) for b (you'll also need to know binary to understand this).4.3. Using the functions from math.h

   pi = 4 * atan(1.0);
   printf("pi ~= %.10f\n", pi);


This piece of code calculates and prints an approximation for pi. It uses a function from the standard header math.h to do this: atan(), which calculates the arc tangent in radians. The arc tangent of 1 (written as 1.0 to make clear this is a floating-point constant) is pi/4, so by multiplying by 4 we get an approximation of pi. There are many useful functions like this in math.h (see 16. Overview of the standard library) They operate on doubles. For example, there is a pow() function in case you were worried that there was no power operator in the above table.

5. Enums and typedefs
5.1. The colours program

/* prog5-1.c: colours */

#include <stdio.h>

enum colours {RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET,
              NUMBER_OF_COLOURS};

typedef enum colours colour_t;

int main(void)
{
   colour_t sky, forest;

   printf("There are %d colours in the enum\n", NUMBER_OF_COLOURS);

   sky = BLUE;
   forest = GREEN;

   printf("sky = %d\n", (int)sky);
   printf("forest = %d\n", (int)forest);

   return 0;
}


The output of this program is:

There are 7 colours in the enum
sky = 4
forest = 3

5.2. Defining and using enums and typedefs

enum colours {RED, ORANGE, YELLOW, GREEN, BLUE, INDIGO, VIOLET,
              NUMBER_OF_COLOURS};


This is the definition of an enumeration type (enum). Every one of the word constants (here colour names) will be assigned a numeric value, counting up and starting at 0 [*]. So the constants will have the following values:
[*] You can override this default numeric value by adding an explicit =value after the constant; the counting for subsequent constants will then continue from there.

word constant     numeric value
RED               0
ORANGE            1
YELLOW            2
GREEN             3
BLUE              4
INDIGO            5
VIOLET            6
NUMBER_OF_COLOURS 7

The reason that the NUMBER_OF_COLOURS is at the end of the enum is that because of the counting system, by adding a constant like this at the end of the enum, this constant will always correspond to the number of defined constants before it [*].
[*] Of course this will not be valid when different values are explicitly assigned to the constants as mentioned in the above note.

typedef enum colours colour_t;

If we wanted to define a variable of the enum type defined above, we would normally have to do that like this:

enum colours somevariable;

However, sometimes we may prefer to make the name "fit in" better with the rest of the types, so that we could simply use it like int etc. without the enum required. That's what the typedef keyword is for. If we add typedef before what would otherwise be a variable definition, instead of creating a variable with a certain name we are creating a new type with that name.
In our example this means that everywhere where we use colour_t this is compiled as if there was an enum colours instead. So:

   colour_t sky, forest;

Is equivalent to:

enum colours sky, forest;

Onto the next line of code:

   printf("There are %d colours in the enum\n", NUMBER_OF_COLOURS);

C has a rather relaxed way of dealing with types (this is called weak typing). This is especially noticeable when it comes to enums: they are equivalent [*]

Page : << Previous 6  Next >>