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


the variable everytime it is read; i.o.w. it may not optimize the variable by putting it in a register or so. This is mainly used for multithreading and interrupt processing purposes etc., things you needn't worry about yet.
The register modifier requests the compiler to optimize the variable into a register. This is only possible with auto variables and in many cases the compiler can better select the variables to optimize into registers itself, so this keyword is obsolescent. The only direct consequence of making a variable register is that its address cannot be taken (see 10.4. Addresses and pointers).3.3. printf()
Then there is the line:

   printf("And the answer is: %d\n", answer);

printf(), like puts(), is a function that is declared in stdio.h. It also prints text to the standard output device (often the screen). However, there are two important differences:
1) While puts() automatically adds a newline (\n) to the text, this must be done explicitly when using printf() [*]
[*] If the newline is omitted, the output may not show up. If you really want no newline, you must add fflush(stdout); afterwards. (see 11.4. Using the standard I/O streams)
2) While puts() can only print a fixed string, printf() can also be used to print variables etc. To be able to do that, printf() accepts a variable number of parameters (later we'll discuss how to write such functions yourself, see 14. Variable argument functions). The first parameter is the format string. In this string % signs have a special meaning (so if you need a % sign to be printed using printf() you must double it, i.e. use %%): they are placeholders for variable values. These variables are passed as parameters after the format string. For every variable passed, there must be a corresponding format specifier (% placeholder) in the format string, of the right type and in the right order. These are the possible format specifiers:

%d   signed int variable, decimal representation (equivalent to %i)
%u   unsigned int variable, decimal representation
%x   unsigned int variable, lowercase hexadecimal representation
%X   unsigned int variable, uppercase hexadecimal representation
%o   unsigned int variable, octal representation
     (there are no format specifiers for binary representation)
%f   float/double, normal notation
%e   float/double, exponential notation (%E uses E instead of e)
%g   float/double, notation %f or %e chosen depending on value (%E if %G)
%c   character (passed as int), text representation
%s   string (see 10. Arrays, strings and pointers)
%p   pointer (see 10. Arrays, strings and pointers)
%n   number of characters written upto now will be written to int
     that the corresponding argument points to

You can change the type of the printed variable by inserting one of the following characters between the % sign and the type character (for example: %ld for long int instead of an int).

h     for d,i,o,u,x,X: short int instead of int
      (the short int will be promoted to int when passed anyway)
      for n: store result in short int instead of int
l     for d,i,o,u,x,X: long int instead of int
      for n: store result in long int instead of int
      Do NOT use for e,E,f,F,g,G for e.g. printing doubles.
L     for e,E,f,F,g,G: long double instead of float/double

There are some flags and modifiers that can be put between the % and the type character:

-     left alignment, pad on the right with spaces (default=right alignment)
+     print plus sign if positive (default=only print minus sign if negative)
      (for signed numbers only)
space print space if positive (default=only print minus sign if negative)
      (for signed numbers only)
0     pad with zeros instead of with spaces (for numbers only)
#     "alternate form": - o: 0 will be prepended to a non-zero result
                        - x/X: prepends 0x/0X to result
                        - f/F,e/E,g/G: decimal point even if no decimals
                        - g/G: trailing zeros are not removed
<nonzero decimal value> specify field width to which result will be padded
      (this can be used together with the 0 flag)
*     field width will be passed as int parameter before the actual argument
.<nonzero decimal value> specify precision (default for f/F,e/E = 6)
      (for s, precision will limit the number of printed characters)
.0    no decimal point is printed for f/F,e/E
.*    precision will be passed as int parameter before the actual argument

Here's an example:

printf("Record %lX: name = %s, age = %d, hourly wage = %.3f\n",
       record_num, name, age, hourly_wage);


Would print the hexadecimal record number, the name, age, and hourly wage with 3 digits precision, provided record_num is of type unsigned long, name is a string (see 10. Arrays, strings and pointers), age is an integer (a smaller type would also be OK since it would automatically be promoted to an integer when passed to printf()) and hourly_wage is a double (or float, for the same reason).
Now you should understand how this program works, so we can move on to new territory...

4. Doing calculations
4.1. The calc program

/* prog4-1.c: calc */

#include <stdio.h>
#include <math.h>

int main(void)
{
   double a, pi;
   int b;

   a = 500 / 40; /* Fraction is thrown away (integer math) */

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

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

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

   a++;

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

   b = (int) a;
   b ^= 5;

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

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

   return 0;
}


The output of this program is: [*]

a = 12.000
a = 12.500
a now = 13.500
b = 8
pi ~= 3.1415926536

[*] If you get "undefined symbol" or similar errors, you have to enable floating-point support in your compiler (see manual / online help)4.2. Operators and typecasts
The first lines of the body of main() should be obvious:

   double a, pi;
   int b;


2 uninitialized double-precision floating-point variables, called a and pi, and an unitialized integer variable called b are defined. The next line contains something new:

   a = 500 / 40; /* Fraction is thrown away (integer math) */

We've encountered the assignment operator = before. The / is the division operator. So what this code does is dividing the value 500 by the value 40 [*] and storing the result in the variable a.
[*] Because both operands are constants, the compiler will most likely optimize this by calculating the result at compile-time.
The following operators are available (in order of precedence):

Precedence      Operator    Explanation
1. Highest      ()          Function call
                            (see 2.4. Functions and types)
                []          Array subscript
                            (see 10. Arrays, strings and pointers)
                ->          Indirect member selector
                            (see 6. Structs, unions and bit-fields)
                .           Direct member selector
                            (see 6. Structs, unions and bit-fields)
2. Unary        !           Logical

Page : << Previous 4  Next >>