Cover | Table of Contents | Colophon
main(): this is the first function invoked when the program starts. The main() function is the program's top level of control, and can call other functions as subroutines.main() and circularArea(). The main() function calls circularArea() to obtain the area of a circle with a given radius, and then calls the standard library function printf() to output the results in formatted
strings on the console.// circle.c: Calculate and print the areas of circles
#include <stdio.h> // Preprocessor directive
double circularArea( double r ); // Function declaration (prototype form)
int main() // Definition of main() begins
{
double radius = 1.0, area = 0.0;
printf( " Areas of Circles\n\n" );
printf( " Radius Area\n"
"-------------------------\n" );
area = circularArea( radius );
printf( "%10.1f %10.2f\n", radius, area );
radius = 5.0;
area = circularArea( radius );
printf( "%10.1f %10.2f\n", radius, area );
return 0;
}
// The function circularArea() calculates the area of a circle
// Parameter: The radius of the circle
// Return value: The area of the circle
double circularArea( double r ) // Definition of circularArea() begins
{
const double pi = 3.1415926536; // Pi is a constant
return pi * r * r;
}// circle.c: Prints the areas of circles.
// Uses circulararea.c for the math
#include <stdio.h>
double circularArea( double r );
int main()
{
/* ... As inExample 1-1 ... */
}// circulararea.c: Calculates the areas of circles.
// Called by main() in circle.c
double circularArea( double r )
{
/* ... As inExample 1-1 ... */
}#include directive in each source code file. Header files are customarily identified by the filename suffix .h
. A header file explicitly included in a C source file may in turn include other files./* and end with */, and line comments
begin with // and end with the next new line character./* and */ delimiters to begin and end comments within a line, and to enclose comments of several lines. For example, in the following function prototype, the ellipsis (...) signifies that the open() function has a third, optional parameter. The comment explains the usage of the optional parameter:int open( const char *name, int mode, ... /* int permissions */ );
// to insert comments that fill an entire line, or to write source code in a two-column format, with program code on the left and comments on the right:const double pi = 3.1415926536; // Pi is constant
/* and // do not start a comment. For example, the following statement contains no comments:printf( "Comments in C begin with /* or //.\n" );
/* and */ to comment out part of a program that contains line comments: /* Temporarily removing two lines:
const double pi = 3.1415926536; // Pi is constant
area = pi * r * r // Calculate the area
Temporarily removed up to here */ #if 0
const double pi = 3.1415926536; /* Pi is constant */
area = pi * r * r /* Calculate the area */
#endifA B C D E F G H I J K L M N O P Q R S T U V W X Y Za b c d e f g h i j k l m n o p q r s t u v w x y z0 1 2 3 4 5 6 7 8 9! " # % & ' () * + , − . / : ; < = > ? [ \ ] ^ _ { | } ~\0 for the null character, \a for alert, \b for backspace, and \r for carriage return. See Chapter 3 for more details.a-z and A-Z. Identifiers are case-sensitive._.0-9, although the first character of an identifier must not be a digit.autoenumrestrictunsignedbreakexternreturnvoidcasefloatshortvolatilecharforsignedwhileconstgotosizeof_Boolcontinueifstatic_Complexdefaultinlinestruct_Imaginarydointswitchdoublelongtypedefelseregisterunionx dollar Break error_handler scale641st_rank switch y/n x-ray doubleα = 0.5;\u03B1._ _func_ _, which you can use in any function to access a string constant containing the name of the function. This is useful for logging or for debugging output; for example:#include directives. If the compiler finds no errors in the translation unit, it generates an object file containing the corresponding machine code. Object files are usually identified by the filename suffix .o
or .obj
. In addition, the compiler may also generate an assembler listing (see Part III).
voidextern float fArr[ ]; // External declaration
fArr as an array whose elements have type float. However, because the array's size is not specified here, fArr's type is incomplete. As long as the global array fArr is defined with a specified size at another location in the program—in another source file, for example—this declaration is sufficient to let you use the array in its present scope. (For more details on external
declarations, see Chapter 11.)voidextern float fArr[ ]; // External declaration
fArr as an array whose elements have type float. However, because the array's size is not specified here, fArr's type is incomplete. As long as the global array fArr is defined with a specified size at another location in the program—in another source file, for example—this declaration is sufficient to let you use the array in its present scope. (For more details on external
declarations, see Chapter 11.)void. The derived types are described in Chapters 7 through 10.unsigned short. In such cases, the keywords can be written in any order. However, there is a conventional keyword order, which we use in this book.Type | Synonyms |
|---|---|
signed char
| |
int | signed, signed int |
short | short int, signed short, signed short int |
long | long int, signed long, signed long int |
long long (C99) | long long int, signed long long, signed long long int |
signed int objects on even-numbered byte addresses, then unsigned
int objects are also aligned on even addresses. These unsigned types are listed in Table 2-2.Type | Synonyms |
|---|---|
_Bool | bool
(defined in stdbool.h
) |
unsigned char
| |
unsigned int | unsigned |
unsigned short | unsigned short int |
unsigned long | unsigned long int |
unsigned long long | unsigned long long int |
_Bool to represent Boolean truth values. The Boolean value true is coded as 1, and false is coded as 0. If you include the header file stdbool.h in a program, you can also use the identifiers bool, true, and false, which are familiar to C++ programmers. The macro bool is a synonym for the type _Bool, and true and false are symbolic constants equal to 1 and 0.char is also one of the standard integer types. However, the one-word type name char is synonymous either with signed char or with unsigned char, depending on the compiler. Because this choice is left up to the implementation, char, signed char, and unsigned char are formally three different types.char being able to hold values less than zero or greater than 127, you should be using either signed char or unsigned char instead.char variable as a character code or as something else. For example, the following short program treats the floatdoublelong doubledouble type. float height = 1.2345, width = 2.3456; // Float variables have single
// precision.
double area = height * width; // The actual calculation is
// performed with double
// (or greater) precision.float variable, the value is rounded as necessary. For more details on floating-point math, see the section "math.h" in Chapter 15.csin(), ctan(), and so on (see Chapter 15).float, double, or long double. Accordingly, these are the three complex floating-point types:float _Complexdouble _Complexlong double _Complexfloat, double, or long double elements.complex and I. The macro complex is a synonym for the keyword _Complex. The macro I represents the imaginary unit i, and has the type const float _Complex: #include <complex.h>
// ...
double complex z = 1.0 + 2.0 * I;
z *= I; // Rotate z through 90° counterclockwise around the origin.enum, possibly followed by an identifier for the enumeration, and contains a list of the type's possible values, with a name for each value:enum [identifier] { enumerator-list };
enum color: enum color { black, red, green, yellow, blue, white=7, gray };color is the tag of this enumeration. The identifiers in the list—black, red, and so on—are the enumeration constants
, and have the type int. You can use these constants anywhere within their scope—as case constants in a switch statement, for example.enum color bgColor = blue, // Define two variables fgColor = yellow; // of type enum color. void setFgColor( enum color fgc ); // Declare a function with a parameter // of type enum color.
char would be sufficient to represent all the values of the enumerated type enum color. enum { OFF, ON, STOP = 0, GO = 1, CLOSED = 0, OPEN = 1 };void
indicates that no value is available. Consequently, you cannot declare variables or constants with this type. You can use the type void for the purposes described in the following sections.void. For example, the standard function perror() is declared by the prototype:void perror( const char * );
void in the parameter list of a function prototype indicates that the function has no parameters:FILE *tmpfile( void );
tmpfile("name.tmp"). If the function were declared without void in the parameter list, the C compiler would have no information about the function's parameters, and hence be unable to determine whether the function call is correct.void expression is one that has no value. For example, a call to a function with no return value is an expression of type void: char filename[ ] = "memo.txt";
if ( fopen( filename, "r" ) == NULL )
perror( filename ); // A void expression.(void)expression explicitly discards the value of an expression, such as the return value of a function: (void)printf("I don't need this function's return value!\n");void * represents the address of an object, but not its type. You can use such quasi-typeless pointers mainly to declare functions that can operate on various types of pointer arguments, or that return a "multipurpose" pointer. The standard memory management functions are a simple example: void *malloc( size_t size );
void *realloc( void *ptr, size_t size );
void free( void *ptr );void pointer value to another object pointer type, or vice versa, without explicit type conversion.// usingvoid.c: Demonstrates uses of the type void
// -------------------------------------------------------
#include <stdio.h>
#include <time.h>
#include <stdlib.h> // Provides the following function prototypes:
// void srand( unsigned int seed );
// int rand( void );
// void *malloc( size_t size );
// void free( void *ptr );
// void exit( int status );
enum { ARR_LEN = 100 };
int main()
{
int i, // Obtain some storage space.
*pNumbers = malloc(ARR_LEN * sizeof(int));
if ( pNumbers == NULL )
{
fprintf(stderr, "Insufficient memory.\n");
exit(1);
}
srand( (unsigned)time(NULL) ); // Initialize the
// random number generator.
for ( i=0; i < ARR_LEN; ++i )
pNumbers[i] = rand() % 10000; // Store some random numbers.
printf("\n%d random numbers between 0 and 9999:\n", ARR_LEN );
for ( i=0; i < ARR_LEN; ++i ) // Output loop:
{
printf("%6d", pNumbers[i]); // Print one number per loop iteration
if ( i % 10 == 9 ) putchar('\n'); // and a newline after every 10 numbers.
}
free( pNumbers ); // Release the storage space.
return 0;
}255 is the decimal constant for the base-10 value 255.047 is a valid octal constant representing 4 × 8 + 7, and is equivalent with the decimal constant 39. The decimal constant 255 is equal to the octal constant 0377.0x or 0X. The hexadecimal digits A to F can be upper- or lowercase. For example, 0xff, 0Xff, 0xFF, and 0XFF represent the same hexadecimal constant, which is equivalent to the decimal constant 255.int. However, if the value of an integer constant is outside the range of the type int, then it must have a bigger type. In this case, the compiler assigns it the first type in a hierarchy that is large enough to represent the value. For decimal constants, the type hierarchy is:int, long, long long
int, unsigned int, long, unsigned long, long long, unsigned long long
255 is the decimal constant for the base-10 value 255.047 is a valid octal constant representing 4 × 8 + 7, and is equivalent with the decimal constant 39. The decimal constant 255 is equal to the octal constant 0377.0x or 0X. The hexadecimal digits A to F can be upper- or lowercase. For example, 0xff, 0Xff, 0xFF, and 0XFF represent the same hexadecimal constant, which is equivalent to the decimal constant 255.int. However, if the value of an integer constant is outside the range of the type int, then it must have a bigger type. In this case, the compiler assigns it the first type in a hierarchy that is large enough to represent the value. For decimal constants, the type hierarchy is:int, long, long long
int, unsigned int, long, unsigned long, long long, unsigned long long
50000 has the type long, since the greatest possible int value is 32,767, or 215 − 1.l or L has the type long (or a larger type if necessary, in accordance with the hierarchies just mentioned). Similarly, a constant with the suffix ll or LL has at least the type long long. The suffix u or U can be used to ensure that the constant has an unsigned type. The e or E. A floating-point constant that contains an exponent does not need to have a decimal point. Table 3-2 gives a few examples of decimal floating-point constants
.Floating-point constant | Value |
|---|---|
10.0 | 10 |
2.34E5 | 2.34 × 105 |
67e-12 | 67.0 × 10−12 |
10. and .234E6 are permissible numerals. However, the numeral 10 with no decimal point would be an integer constant, not a floating-point
constant.double. You can also append the suffix F or f to assign a constant the type float, or the suffix L or l to give a constant the type long double, as this example shows: float f_var = 123.456F; // Initialize a float variable.
long double ld_var = f_var * 987E7L; // Initialize a long double variable
// with the product of a
// multiplication performed with
// long double precision.'a' 'XY' '0' '*'
', the backslash \, and the newline character. To represent these characters, you must use escape sequences:'\'' '\\' '\n'
int, unless they are explicitly defined as wide characters, with type wchar_t, by the prefix L. If a character constant contains one character that can be represented in a single byte, then its value is the character code of that character in the execution character set. For example, the constant 'a' in ASCII encoding has the decimal value 97. The value of character constants
that consist of more than one character can vary from one compiler to another. #include <stdio.h>
int c = 0;
/* ... */
c = getchar(); // Read a character.
if ( c != EOF && c > '0' && c < '6' ) // Compare input to character
// constants.
{
/* This block is executed if the user entered a digit from 1 to 5. */
}char is signed, then the value of a character constant can also be negative, because the constant's value is the result of a type conversion of the character code from char to int. For example, ISO 8859-1 is a commonly used 8-bit character set, also known as the ISO Latin 1
or ANSI character set
. In this character set, the currency symbol for pounds sterling, £, is coded as hexadecimal A3: int c = '\xA3'; // Symbol for pounds sterling
printf("Character: %c Code: %d\n", c, c);char is signed, then the printf statement in the preceding example generates the following output:"Hello world!\n"
", the backslash \, and the newline character, which must be represented by escape sequences. The following printf statement first produces an alert tone, then indicates a documentation directory in quotation marks, substituting the string literal addressed by the pointer argument doc_path for the conversion specification %s: char doc_path[128] = ".\\share\\doc";
printf("\aSee the documentation in the directory \"%s\"\n", doc_path);char that contains character codes followed by a string terminator, the null character \0 (see also Chapter 8). The empty string "" occupies exactly one byte in memory, which holds the terminating null character. Characters that cannot be represented in one byte are stored as multibyte characters.char array. A string literal can also be used to initialize a pointer to char:char *pStr = "Hello, world!"; // pStr points to the first character, 'H'
error_msg contains three pointers to char, each of which is assigned the address of the first character of a string literal.#include <stdlib.h>
#include <stdio.h>
void error_exit(unsigned int error_n) // Print a last error message
{ // and exit the program.char * error_msg[ ] = { "Unknown error code.\n",
"Insufficient memory.\n",
"Illegal memory access.\n" };
unsigned int arr_len = sizeof(error_msg)/sizeof(char *);
if ( error_n >= arr_len )
error_n = 0;
fputs( error_msg[error_n], stderr );
exit(1);
} double dVar = 2.5; // Define dVar as a variable of type double.
dVar *= 3; // Multiply dVar by an integer constant.
if ( dVar < 10L ) // Compare dVar with a long-integer constant.
{ /* ... */ }void (meaning that the value of the expression is discarded: see "Expressions of Type void" in Chapter 2), or a scalar type—that is, an arithmetic type or a pointer. For example, a pointer to a structure can be converted into a different pointer type. However, an actual structure value cannot be converted into a different structure type.(type_name) expression
int sum = 22, count = 5;
double mean = (double)sum / count;sum in this example is first converted to type double. The compiler must then implicitly convert the divisor, the value of count, to the same type before performing the division.double to the type int, the new type simply cannot represent the original value. In such cases the compiler generally issues a warning.char has the same rank as signed char and unsigned char._Bool < char < short < int < long < long long
float < double < long double
float, has a higher rank than any integer type.int in place of an operand of type int or unsigned int. You can also use a bit-field as an integer operand (bit-fields are discussed in Chapter 10). In these cases, the compiler applies integer promotion
: any operand whose type ranks lower than int is automatically converted to the type int, provided int is capable of representing all values of the operand's original type. If sizeof operator&char or wchar_t%p to print pointer values: #include <stdio.h>
int *iPtr = 0; // A pointer to int, initialized with 0.
int iArray[ ] = { 0, 10, 20 }; // An array of int, initialized.
int array_length = sizeof(iArray) / sizeof(int); // The number of elements:
// in this case, 3.
printf("The array starts at the address %p.\n", iArray);
*iArray = 5; // Equivalent to iArray[0] = 5;
iPtr = iArray + array_length - 1; // Point to the last element of iArray:
// Equivalent to
// iPtr = &iArray[array_length-1];
printf("The last element of the array is %d.\n", *iPtr);array_length in this example, the expression sizeof(iArray) yields the size of the whole array, not the size of a pointer. However, the same identifier iArray is implicitly converted to a pointer in the other three statements in which it appears:printf() call.*.iPtr (see also "Modifying and Comparing Pointers" in Chapter 9).