The GNU C Reference Manual

Table of Contents


Next: , Up: (dir)

The GNU C Reference Manual

This is the GNU C reference manual.


Next: , Previous: Top, Up: Top

Preface

This is a reference manual for the GNU C programming language: the C programming language as implemented by the GNU C compiler.

GCC supports several variants of C; this manual ultimately aims to explicitly document three of them:

By default, GCC will compile code as C89 plus GNU-specific extensions. Much of C99 is supported; once full support is available, the default compilation dialect will be C99 plus GNU-specific extensions. (Note that some of the GNU extensions to C89 ended up, sometimes slightly modified, as standard language features in C99.)

Presently, this manual describes C89 only. Descriptions of C99 and GNU extensions will be included in future releases, labeled as such alongside the original C89 material. While most users of GCC are free to use the latest and greatest additions to the compiler, some users must continue to use older versions of GCC. (For example, avionics programmers cannot switch to newer compilers on a whim, and indeed often use the same compiler for years until a new version is approved for use.) For this reason, we feel that a clear distinction between C dialects will be useful to our readers.

The C language includes a set of preprocessor directives, which are used for things such as macro text replacement, conditional compilation, and file inclusion. Although normally described in a C language manual, the GNU C preprocessor has been thoroughly documented in The C Preprocessor, a separate manual which covers preprocessing for C, C++, and Objective C programs, so it is not included here.

A number of people have contributed to this manual. Most of the text was written by Trevis Rothwell. Other contributors, who have offered editing, proofreading, ideas, and/or help with typesetting or administrative details, include: Karl Berry, Robert Chassell, Lisa Goldstein, Robert Hansen, Jean-Christophe Helary, Joe Humphries, J. Wren Hunt, Adam Johansen, Steve Morningthunder, Richard Stallman, J. Otto Tennant, Ole Tetlie, and T.F. Torrey.

Please send bug reports and suggestions to gnu-c-manual@gnu.org.


Next: , Previous: Preface, Up: Top

1 Lexical Elements

This chapter describes the lexical elements that make up C source code after preprocessing. These basic elements are called tokens, and there are several distinct types of tokens: keywords, identifiers, constants, operators, and separators. White space, sometimes required to separate tokens, is also described in this chapter.


Next: , Up: Lexical Elements

1.1 Identifiers

Identifiers are strings of characters used for naming variables, functions, new data types, and preprocessor macros. The characters can be letters, decimal digits, the underscore character `_', or the dollar sign character `$'.

The first character of an identifier cannot be a digit.

Lowercase letters and uppercase letters are distinct, so squid and SQUID are two different identifiers.


Next: , Previous: Identifiers, Up: Lexical Elements

1.2 Keywords

Keywords are special identifiers, reserved for use by the programming language itself. You cannot use them for any other purpose.

Here is a list of keywords recognized by ANSI C89:

     auto break case char const continue default do double else enum extern
     float for goto if int long register return short signed sizeof static
     struct switch typedef union unsigned void volatile while


Next: , Previous: Keywords, Up: Lexical Elements

1.3 Constants

A constant is a literal numeric or character value, such as 5 or `m'. All constants are of a particular data type; you can use type casting to explicitly specify the type of a constant, or let the compiler use the default type based on the value of the constant.


Next: , Up: Constants

1.3.1 Integer Constants

An integer constant is a sequence of digits.

If the sequence of digits is preceded by 0x or 0X (zero x or zero X), then the constant is considered to be hexadecimal (base 16). Hexadecimal values may use the digits from 0 to 9, as well as the letters a to f and A to F.

     0x2f
     0x88
     0xAB43
     0xAbCd
     0x1

If the first digit is 0 (zero), and the next character is not x or X, then the constant is considered to be octal (base 8). Octal values may only use the digits from 0 to 7; 8 and 9 are not allowed.

     057
     012
     03
     0841

In all other cases, the sequence of digits is assumed to be decimal (base 10). Decimal values may use the digits from 0 to 9.

     459
     23901
     8
     12

There are various integer data types, for short integers, long integers, signed integers, and unsigned integers. You can force an integer constant to be of a long and/or unsigned integer type by appending a sequence of one or more letters to the end of the constant:

u
U
Unsigned integer type.
l
L
Long integer type.

For example, 45U is an unsigned int constant. You can also combine letters: 45UL is an unsigned long int constant. (The letters may be used in any order.) You can use two L's to get a long long int constant; add a U and you have an unsigned long long int constant.

There is no way to force an integer constant to be interpreted as a short integer. In addition, an integer constant will never be interpreted as a short integer by default, even if its value is small enough to be represented as one.


Next: , Previous: Integer Constants, Up: Constants

1.3.2 Character Constants

A character constant is usually a single character enclosed within single quotation marks, such as 'Q'. A character constant is of type int by default.

Some characters, such as the single quotation mark character ' itself, cannot be represented using only one character. To represent such characters, there are several “escape sequences” that you can use:

\\
Backslash character.
\?
Question mark character.
\'
Single quotation mark.
\"
Double quotation mark.
\a
Audible alert.
\b
Backspace character.
\e
<ESC> character.
\f
Form feed.
\n
Newline character.
\r
Carriage return.
\t
Horizontal tab.
\v
Vertical tab.
\ooo
Octal number.
\xhh
Hexadecimal number.

To use any of these escape sequences, enclose the sequence in single quotes, and treat it as if it were any other character. For example, the letter m is 'm' and the newline character is '\n'.

The octal number escape sequence is the backslash character followed by one, two, or three octal digits (0 to 7). For example, 101 is the octal equivalent of 65, which is the ASCII character 'A'. Thus, the character constant '\101' is the same as the character constant 'A'.

The hexadecimal escape sequence is the backslash character, followed by x and an unlimited number of hexadecimal digits (0 to 9, and a to f or A to F).

While the number of possible hexadecimal digits is unlimited, the number of character constants is not. (The much-used extended ASCII character set has only 256 characters in it.) If you try to use a hexadecimal value that is outside the range of characters, you will get a compile-time error.


Next: , Previous: Character Constants, Up: Constants

1.3.3 Real Number Constants

A real number constant is a value that represents a fractional (floating point) number. It consists of a sequence of digits which represents the integer (or “whole”) part of the number, a decimal point, and a sequence of digits which represents the fractional part.

Either the integer part or the fractional part may be omitted, but not both. Here are some examples:

     double a, b, c, d, e, f;
     
     a = 4.7;     /* This is okay. */
     
     b = 4.;      /* This is okay. */
     
     c = 4;       /* This is okay. */
     
     d = .7;      /* This is okay. */
     
     e = 0.7;     /* This is okay. */
     
     f = .;       /* This is NOT okay! */

Real number constants can also be followed by e or E, and an integer exponent. The exponent can be either positive or negative.

     double x, y;
     
     x = 5e2;   /* x is 5 x (10 ^ 2), or 500.0. */
     y = 5e-2;  /* y is 5 x (10 ^ -2), or 0.05. */

You can append a letter to the end of a real number constant to cause it to be of a particular type. If you append the letter F (or f) to a real number constant, then its type is float. If you append the letter L (or l), then its type is long double. If you do not append any letters, then its type is double.


Previous: Real Number Constants, Up: Constants

1.3.4 String Constants

A string constant is a sequence of characters, digits, and/or escape sequences enclosed within double quotation marks. A string constant is of type “array of characters”. All string constants contain a null termination character (\0) as their last character. Strings are stored as arrays of characters, with no inherent size attribute. The null termination character lets string-processing functions know where the string ends.

Adjacent string constants are concatenated (combined) into one string, with the null termination character added to the end of the final concatenated string.

A string cannot contain double quotation marks, as double quotation marks are used to enclose the string. To include the double quotation mark character in a string, use the \" escape sequence. You can use any of the escape sequences that can be used as character constants in strings. Here are some example of string constants:

     /* This is a single string constant. */
     "tutti frutti ice cream"
     
     /* These string constants will be concatenated, same as above. */
     "tutti " "frutti" " ice " "cream"
     
     /* This one uses two escape sequences. */
     "\"hello, world!\""

If a string is too long to fit on one line, you can use a backslash \ to break it up onto separate lines.

     "Today's special is a pastrami sandwich on rye bread with \
     a potato knish and a cherry soda."

Adjacent strings are automatically concatenated, so you can also have string constants span multiple lines by writing them as separate, adjacent, strings. For example:

     "Tomorrow's special is a corned beef sandwich on "
     "pumpernickel bread with a kasha knish and seltzer water."

is the same as

     "Tomorrow's special is a corned beef sandwich on \
     pumpernickel bread with a kasha knish and seltzer water."

To insert a newline character into the string, so that when the string is printed it will be printed on two different lines, you can use the newline escape sequence `\n'.

     printf ("potato\nknish");

prints

     potato
     knish


Next: , Previous: Constants, Up: Lexical Elements

1.4 Operators

An operator is a special token that performs an operation, such as addition or subtraction, on either one, two, or three operands. Full coverage of operators can be found in a later chapter. See Expressions and Operators.


Next: , Previous: Operators, Up: Lexical Elements

1.5 Separators

A separator separates tokens. White space (see next section) is a separator, but it is not a token. The other separators are all single-character tokens themselves:

     ( ) [ ] { } ; , . :


Previous: Separators, Up: Lexical Elements

1.6 White Space

White space is the collective term used for a number of characters, including the space character, the tab character, and the newline character. In C programs, white space is ignored (outside of string and character constants), and is therefore optional, except when it is used to separate tokens. This means that

     #include <stdio.h>
     
     int
     main()
     {
       printf( "hi there\n" );
       return 0;
     }

and

     #include <stdio.h> int main(){printf("hi there\n");
     return 0;}

are functionally the same program.

Although you must use white space to separate many tokens, no white space is required between operators and operands, nor is it required between other separators and that which they separate.

     /* All of these are valid. */
     
     x++;
     x ++ ;
     x=y+z;
     x = y + z ;
     x=array[2];
     x = array [ 2 ] ;
     fraction=numerator/*denominator_ptr;
     fraction = numerator / * denominator_ptr ;

Furthermore, wherever one space is allowed, any amount of white space is allowed.

     /* These two statements are functionally identical. */
     x++;
     
     x
            ++       ;

In string constants, spaces and tabs are not ignored; rather, they are part of the string. Therefore,

     "potato knish"

is not the same as

     "potato                        knish"


Next: , Previous: Lexical Elements, Up: Top

2 Data Types


Next: , Up: Data Types

2.1 Primitive Data Types


Next: , Up: Primitive Types

2.1.1 Integer Types

The integer data types range in size from at least 8 bits to at least 64 bits. You should use them for storing whole number values (and the char data type for storing characters). (Note that the sizes and ranges listed for these types are minimums; depending on your computer platform, these sizes and ranges may be larger.)


Previous: Integer Types, Up: Primitive Types

2.1.2 Real Number Types

There are several data types that represent fractional numbers, such as 3.14159 and 2.83. The exact sizes and ranges for the floating point data types can vary from system to system; these values are stored in macro definitions in the library header file float.h. In this section, we include the names of the macro definitions in place of their possible values:

All floating point data types are signed; trying to use unsigned float, for example, will cause a compile-time error.


Next: , Previous: Primitive Types, Up: Data Types

2.2 Enumerations

An enumeration is a custom data type used for storing constant integer values and referring to them by names. By default, these values are of type signed int; however, you can use the -fshort-enums GCC compiler option to cause the smallest possible integer type to be used instead.


Next: , Up: Enumerations

2.2.1 Defining Enumerations

You define an enumeration using the enum keyword, followed by the name of the enumeration (this is optional), followed by a list of constant names (separated by commas and enclosed in braces), and ending with a semicolon.

     enum fruit {grape, cherry, lemon, kiwi};

That example defines an enumeration, fruit, which contains four constant integer values, grape, cherry, lemon, and kiwi, whose values are, by default, 0, 1, 2, and 3, respectively. You can also specify one or more of the values explicitly:

     enum more_fruit {banana = -17, apple, blueberry, mango};

That example defines banana to be −17, and the remaining values are incremented by 1—apple is −16, blueberry is −15, and mango is -14. Unless specified otherwise, an enumeration value is equal to one more than the previous value (and the first value defaults to 0).

You can also refer to an enumeration value defined earlier in the same enumeration:

     enum yet_more_fruit {kumquat, raspberry, peach,
                          plum = peach + 2};

In that example, kumquat is 0, raspberry is 1, peach is 2, and plum is 4.


Previous: Defining Enumerations, Up: Enumerations

2.2.2 Declaring Enumerations

You can declare variables of an enumeration type both when the enumeration is defined and afterward. This example declares one variable, named my_fruit of type enum fruit:

     enum fruit {banana, apple, blueberry, mango} my_fruit;

While this example declares the type and variable separately:

     enum fruit {banana, apple, blueberry, mango};
     enum fruit my_fruit;

(Of course, you couldn't declare it that way if you hadn't named the enumeration.)

Although such variables are considered to be of an enumeration type, you can assign them any value that you could assign to an int variable, including values from other enumerations. Furthermore, any variable that can be assigned an int value can be assigned a value from an enumeration.

However, you cannot change the values in an enumeration once it has been defined; they are constant values. For example, this won't work:

     enum fruit {banana, apple, blueberry, mango};
     banana = 15;  /* You can't do this! */


Next: , Previous: Enumerations, Up: Data Types

2.3 Unions

A union is a custom data type used for storing several variables in the same memory space. Although you can access any of those variables at any time, you should only read from one of them at a time—assigning a value to one of them overwrites the values in the others.


Next: , Up: Unions

2.3.1 Defining Unions

You define a union using the union keyword followed by the declarations of the union's members, enclosed in braces. You declare each member of a union just as you would normally declare a variable—using the data type followed by one or more variable names separated by commas, and ending with a semicolon. Then end the union definition with a semicolon after the closing brace.

You should also include a name for the union between the union keyword and the opening brace. This is syntactically optional, but if you leave it out, you can't refer to that union data type later on (without a typedef, see The typedef Statement).

Here is an example of defining a simple union for holding an integer value and a floating point value:

     union numbers
       {
         int i;
         float f;
       };

That defines a union named numbers, which contains two members, i and f, which are of type int and float, respectively.


Next: , Previous: Defining Unions, Up: Unions

2.3.2 Declaring Union Variables

You can declare variables of a union type when both you initially define the union and after the definition, provided you gave the union type a name.


Next: , Up: Declaring Union Variables
2.3.2.1 Declaring Union Variables at Definition

You can declare variables of a union type when you define the union type by putting the variable names after the closing brace of the union definition, but before the final semicolon. You can declare more than one such variable by separating the names with commas.

     union numbers
       {
         int i;
         float f;
       } first_number, second_number;

That example declares two variables of type union numbers, first_number and second_number.


Next: , Previous: Declaring Union Variables at Definition, Up: Declaring Union Variables
2.3.2.2 Declaring Union Variables After Definition

You can declare variables of a union type after you define the union by using the union keyword and the name you gave the union type, followed by one or more variable names separated by commas.

     union numbers
       {
         int i;
         float f;
       };
     union numbers first_number, second_number;

That example declares two variables of type union numbers, first_number and second_number.


Previous: Declaring Union Variables After Definition, Up: Declaring Union Variables
2.3.2.3 Initializing Union Members

You can initialize the first member of a union variable when you declare it:

     union numbers
       {
         int i;
         float f;
       };
     union numbers first_number = { 5 };

In that example, the i member of first_number gets the value 5. The f member is left alone.

Another way to initialize a union member is to specify the name of the member to initialize. This way, you can initialize whichever member you want to, not just the first one. There are two methods that you can use—either follow the member name with a colon, and then its value, like this:

     union numbers first_number = { f: 3.14159 };

or precede the member name with a period and assign a value with the assignment operator, like this:

     union numbers first_number = { .f = 3.14159 };

You can also initialize a union member when you declare the union variable during the definition:

     union numbers
       {
         int i;
         float f;
       } first_number = { 5 };


Next: , Previous: Declaring Union Variables, Up: Unions

2.3.3 Accessing Union Members

You can access the members of a union variable using the member access operator. You put the name of the union variable on the left side of the operator, and the name of the member on the right side.

     union numbers
       {
         int i;
         float f;
       };
     union numbers first_number;
     first_number.i = 5;
     first_number.f = 3.9;

Notice in that example that giving a value to the f member overrides the value stored in the i member.


Previous: Accessing Union Members, Up: Unions

2.3.4 Size of Unions

This size of a union is equal to the size of its largest member. Consider the first union example from this section:

     union numbers
       {
         int i;
         float f;
       };

The size of the union data type is the same as sizeof (float), because the float type is larger than the int type. Since all of the members of a union occupy the same memory space, the union data type size doesn't need to be large enough to hold the sum of all their sizes; it just needs to be large enough to hold the largest member.


Next: , Previous: Unions, Up: Data Types

2.4 Structures

A structure is a programmer-defined data type made up of variables of other data types (possibly including other structure types).


Next: , Up: Structures

2.4.1 Defining Structures

You define a structure using the struct keyword followed by the declarations of the structure's members, enclosed in braces. You declare each member of a structure just as you would normally declare a variable—using the data type followed by one or more variable names separated by commas, and ending with a semicolon. Then end the structure definition with a semicolon after the closing brace.

You should also include a name for the structure in between the struct keyword and the opening brace. This is optional, but if you leave it out, you can't refer to that structure data type later on (without a typedef, see The typedef Statement).

Here is an example of defining a simple structure for holding the X and Y coordinates of a point:

     struct point
       {
         int x, y;
       };

That defines a structure type named struct point, which contains two members, x and y, both of which are of type int.


Next: , Previous: Defining Structures, Up: Structures

2.4.2 Declaring Structure Variables

You can declare variables of a structure type when both you initially define the structure and after the definition, provided you gave the structure type a name.


Next: , Up: Declaring Structure Variables
2.4.2.1 Declaring Structure Variables at Definition

You can declare variables of a structure type when you define the structure type by putting the variable names after the closing brace of the structure definition, but before the final semicolon. You can declare more than one such variable by separating the names with commas.

     struct point
       {
         int x, y;
       } first_point, second_point;

That example declares two variables of type struct point, first_point and second_point.


Next: , Previous: Declaring Structure Variables at Definition, Up: Declaring Structure Variables
2.4.2.2 Declaring Structure Variables After Definition

You can declare variables of a structure type after defining the structure by using the struct keyword and the name you gave the structure type, followed by one or more variable names separated by commas.

     struct point
       {
         int x, y;
       };
     struct point first_point, second_point;

That example declares two variables of type struct point, first_point and second_point.


Previous: Declaring Structure Variables After Definition, Up: Declaring Structure Variables
2.4.2.3 Initializing Structure Members

You can initialize the members of a structure type to have certain values when you declare structure variables. One way is to specify the values in a set of braces and separated by commas. Those values are assigned to the structure members in the same order that the members are declared in the structure in definition.

     struct point
       {
         int x, y;
       };
     struct point first_point = { 5, 10 };

In that example, the x member of first_point gets the value 5, and the y member gets the value 10.

Another way to initialize the members is to specify the name of the member to initialize. This way, you can initialize the members in any order you like, and even leave some of them uninitialized. There are two methods that you can use—either follow the member name with a colon, and then its value, like this:

     struct point first_point = { y: 10, x: 5 };

or precede the member name with a period and assign a value with the assignment operator, like this:

     struct point first_point = { .y = 10, .x = 5 };

You can also initialize the structure variable's members when you declare the variable during the structure definition:

     struct point
       {
         int x, y;
       } first_point = { 5, 10 };

You can also initialize fewer than all of a structure variable's members:

     struct point
       {
         int x, y;
       };
     struct point first_point = { 5 };

In that example, only one member, x, is initialized. y is left uninitialized. (This is because the members are initialized in order of declaration, and x was declared before y.)

Here is another example that initializes a structure's members which are structure variables themselves:

     struct point
       {
         int x, y;
       };
     
     struct rectangle
       {
         struct point top_left, bottom_right;
       };
     
     struct rectangle my_rectangle = { {0, 5}, {10, 0} };

That example defines the rectangle structure to consist of two point structure variables. Then it declares one variable of type struct rectangle and initializes its members. Since its members are structure variables, we used an extra set of braces surrounding the members that belong to the point structure variables. However, those extra braces are not necessary; they just make the code easier to read.


Next: , Previous: Declaring Structure Variables, Up: Structures

2.4.3 Accessing Structure Members

You can access the members of a structure variable using the member access operator. You put the name of the structure variable on the left side of the operator, and the name of the member on the right side.

     struct point
       {
         int x, y;
       };
     
     struct point first_point;
     
     first_point.x = 0;
     first_point.y = 5;

You can also access the members of a structure variable which is itself a member of a structure variable.

     struct rectangle
       {
         struct point top_left, bottom_right;
       };
     
     struct rectangle my_rectangle;
     
     my_rectangle.top_left.x = 0;
     my_rectangle.top_left.y = 5;
     
     my_rectangle.bottom_right.x = 10;
     my_rectangle.bottom_right.y = 0;


Next: , Previous: Accessing Structure Members, Up: Structures

2.4.4 Bit Fields

You can create structures with integer members of nonstandard sizes, called bit fields. You do this by specifying an integer (int, char, long int, etc.) member as usual, and inserting a colon and the number of bits that the member should occupy in between the member's name and the semicolon.

     struct card
       {
         unsigned int suit : 2;
         unsigned int face_value : 4;
       };

That example defines a structure type with two bit fields, suit and face_value, which take up 2 bits and 4 bits, respectively. suit can hold values from 0 to 3, and face_value can hold values from 0 to 15. Notice that these bit fields were declared as unsigned int; had they been signed integers, then their ranges would have been from −2 to 1, and from −8 to 7, respectively.

More generally, the range of an unsigned bit field of N bits is from 0 to 2^N - 1, and the range of a signed bit field of N bits is from -(2^N) / 2 to ((2^N) / 2) - 1.


Previous: Bit Fields, Up: Structures

2.4.5 Size of Structures

The size of a structure type is equal to the sum of the size of all of its members, possibly including padding to cause the structure type to align to a particular byte boundary. The details vary depending on your computer platform, but it would not be atypical to see structures padded to align on four- or eight-byte boundaries. This is done in order to speed up memory accesses of instances of the structure type.

If you wish to explicitly omit padding from your structure types (which may, in turn, decrease the speed of structure memory accesses), then GCC provides multiple methods of turning packing off. The quick and easy method is to use the -fpack-struct compiler option. For more details on omitting packing, please see the GCC manual which corresponds to your version of the compiler.


Next: , Previous: Structures, Up: Data Types

2.5 Arrays

An array is a data structure that lets you store one or more elements consecutively in memory. In C, array elements are indexed beginning at position zero, not one.


Next: , Up: Arrays

2.5.1 Declaring Arrays

You declare an array by specifying the data type for its elements, its name, and the number of elements it can store. Here is an example that declares an array that can store ten integers:

     int my_array[10];

The number of elements in an array must be positive.


Next: , Previous: Declaring Arrays, Up: Arrays

2.5.2 Initializing Arrays

You can initialize the elements in an array when you declare it by listing the initializing values, separated by commas, in a set of braces. Here is an example:

     int my_array[5] = { 0, 1, 2, 3, 4 };

You don't have to initialize all of the array elements. For example, this code initializes only the first three elements:

     int my_array[5] = { 0, 1, 2 };

That leaves the last two elements uninitialized.


Next: , Previous: Initializing Arrays, Up: Arrays

2.5.3 Accessing Array Elements

You can access the elements of an array by specifying the array name, followed by the element index, enclosed in brackets. Remember that the array elements are numbered starting with zero. Here is an example:

     my_array[0] = 5;

That assigns the value 5 to the first element in the array, at position zero. You can treat individual array elements like variables of whatever data type the array is made up of. For example, if you have an array made of a structure data type, you can access the structure elements like this:

     struct point
     {
       int x, y;
     };
     struct point point_array[2] = { {4, 5}, {8, 9} };
     point_array[0].x = 3;


Next: , Previous: Accessing Array Elements, Up: Arrays

2.5.4 Multidimensional Arrays

You can make multidimensional arrays, or “arrays of arrays”. You do this by adding an extra set of brackets and array lengths for every additional dimension you want your array to have. For example, here is a declaration for a two-dimensional array that holds five elements in each dimension (a two-element array consisting of five-element arrays):

     int two_dimensions[2][5] { {1, 2, 3, 4, 5}, {6, 7, 8, 9, 10} };

Multidimensional array elements are accessed by specifying the desired index of both dimensions:

     two_dimensions[1][3] = 12;


Next: , Previous: Multidimensional Arrays, Up: Arrays

2.5.5 Arrays as Strings

You can use an array of characters to hold a string (see String Constants). The array may be built of either signed or unsigned characters.

When you declare the array, you can specify the number of elements it will have. That number will be the maximum number of characters that should be in the string, including the null character used to end the string. If you choose this option, then you do not have to initialize the array when you declare it. Alternately, you can simply initialize the array to a value, and its size will then be exactly large enough to hold whatever string you used to initialize it.

There are two different ways to initialize the array. You can specify of comma-delimited list of characters enclosed in braces, or you can specify a string literal enclosed in double quotation marks.

Here are some examples:

     char blue[26];
     char yellow[26] = {'y', 'e', 'l', 'l', 'o', 'w', '\0'};
     char orange[26] = "orange";
     char gray[] = {'g', 'r', 'a', 'y', '\0'};
     char salmon[] = "salmon";

In each of these cases, the null character \0 is included at the end of the string, even when not explicitly stated. (Note that if you initialize a string using an array of individual characters, then the null character is not guaranteed to be present. It might be, but such an occurrence would be one of chance, and should not be relied upon.)

After initialization, you cannot assign a new string literal to an array using the assignment operator. For example, this will not work:

     char lemon[26] = "custard";
     lemon = "steak sauce";      /* Fails! */

However, there are functions in the GNU C library that perform operations (including copy) on string arrays. You can also change one character at a time, by accessing individual string elements as you would any other array:

     char name[] = "bob";
     name[0] = 'r';

It is possible for you to explicitly state the number of elements in the array, and then initialize it using a string that has more characters than there are elements in the array. This is not a good thing. The larger string will not override the previously specified size of the array, and you will get a compile-time warning. Since the original array size remains, any part of the string that exceeds that original size is being written to a memory location that was not allocated for it.


Next: , Previous: Arrays as Strings, Up: Arrays

2.5.6 Arrays of Unions

You can create an array of a union type just as you can an array of a primitive data type.

     union numbers
       {
         int i;
         float f;
       };
     union numbers number_array [3];

That example creates a 3-element array of union numbers variables called number_array. You can also initialize the first members of the elements of a number array:

     struct point point_array [3] = { {3}, {4}, {5} };

The additional inner grouping braces are optional.

After initialization, you can still access the union members in the array using the member access operator. You put the array name and element number (enclosed in brackets) to the left of the operator, and the member name to the right.

     union numbers number_array [3];
     number_array[0].i = 2;


Previous: Arrays of Unions, Up: Arrays

2.5.7 Arrays of Structures

You can create an array of a structure type just as you can an array of a primitive data type.

     struct point
       {
         int x, y;
       };
     struct point point_array [3];

That example creates a 3-element array of struct point variables called point_array. You can also initialize the elements of a structure array:

     struct point point_array [3] = { {2, 3}, {4, 5}, {6, 7} };

As with initializing structures which contain structure members, the additional inner grouping braces are optional. But, if you use the additional braces, then you can partially initialize some of the structures in the array, and fully initialize others:

     struct point point_array [3] = { {2}, {4, 5}, {6, 7} };

In that example, the first element of the array has only its x member initialized. Because of the grouping braces, the value 4 is assigned to the x member of the second array element, not to the y member of the first element, as would be the case without the grouping braces.

After initialization, you can still access the structure members in the array using the member access operator. You put the array name and element number (enclosed in brackets) to the left of the operator, and the member name to the right.

     struct point point_array [3];
     point_array[0].x = 2;
     point_array[0].y = 3;


Next: , Previous: Arrays, Up: Data Types

2.6 Pointers

Pointers hold memory addresses of stored constants or variables. For any data type, including both primitive types and custom types, you can create a pointer that holds the memory address of an instance of that type.


Next: , Up: Pointers

2.6.1 Declaring Pointers

You declare a pointer by specifying a name for it and a data type. The data type indicates of what type of variable the pointer will hold memory addresses.

To declare a pointer, include the indirection operator (see The Indirection Operator) before the identifier. Here is the general form of a pointer declaration:

     data-type * name;

You can also put the operator either directly next to name, or directly next to data-type, like these:

     data-type *name;
     data-type* name;

Any of these three is fine, and they all work the same way (white space is not significant, as usual). Here is an example of declaring a pointer to hold the address of an int variable:

     int *ip;

Be careful, though: when declaring multiple pointers in the same statement, you must explicitly declare each as a pointer, using the indirection operator:

     int *bob, *emily;  /* Two pointers. */
     int *rob, laura;   /* A pointer and an integer variable. */


Next: , Previous: Declaring Pointers, Up: Pointers

2.6.2 Initializing Pointers

You can initialize a pointer when you first declare it by specifying a variable address to store in it. For example, the following code declares an int variable `i', and a pointer which is initialized with the address of `i':

     int i;
     int *ip = &i;

Note the use of the address operator (see The Address Operator), used to get the memory address of a variable. Be careful, though: after you declare a pointer, you do not use the indirection operator with the pointer's name when assigning it a new address to point to. On the contrary, that would change the value of the variable that the points to, not the value of the pointer itself. For example:

     int i, j;
     int *ip = &i;  /* `ip' now holds the address of `i'. */
     ip = &j;       /* `ip' now holds the address of `j'. */
     *ip = &i;      /* `j' now holds the address of `i'. */

The value stored in a pointer is an integral number: a location within the computer's memory space. If you are so inclined, you can assign pointer values explicitly using literal integers, casting them to the appropriate pointer type. However, we do not recommend this practice unless you need to have extremely fine-tuned control over what is stored in memory, and you know exactly what you are doing. It would be all too easy to accidentally overwrite something that you did not intend to.


Next: , Previous: Initializing Pointers, Up: Pointers

2.6.3 Pointers to Unions

You can create a pointer to a union type just as you can a pointer to a primitive data type.

     union numbers
       {
         int i;
         float f;
       };
     union numbers foo = {4};
     union numbers *number_ptr = &foo;

That example creates a new union type, union numbers, and declares (and initializes the first member of) a variable of that type named foo. Finally, it declares a pointer to the type union numbers, and gives it the address of foo.

You can access the members of a union variable through a pointer, but you can't use the regular member access operator anymore. Instead, you have to use the indirect member access operator (see Member Access Operators). Continuing with the previous example, the following example will change the value of the first member of foo:

     number_ptr -> i = 450;

Now the i member in foo is 450.


Previous: Pointers to Unions, Up: Pointers

2.6.4 Pointers to Structures

You can create a pointer to a structure type just as you can a pointer to a primitive data type.

     struct fish
       {
         float length, weight;
       };
     struct fish salmon = {4.3, 5.8};
     struct fish *fish_ptr = &salmon;

That example creates a new structure type, struct fish, and declares (and initializes) a variable of that type named salmon. Finally, it declares a pointer to the type struct fish, and gives it the address of salmon.

You can access the members of a structure variable through a pointer, but you can't use the regular member access operator anymore. Instead, you have to use the indirect member access operator (see Member Access Operators). Continuing with the previous example, the following example will change the values of the members of salmon:

     fish_ptr -> length = 5.1;
     fish_ptr -> weight = 6.2;

Now the length and width members in salmon are 5.1 and 6.2, respectively.


Next: , Previous: Pointers, Up: Data Types

2.7 Incomplete Types

You can define structures, unions, and enumerations without listing their members (or values, in the case of enumerations). Doing so results in an incomplete type. You can't declare variables of incomplete types, but you can work with pointers to those types.

     struct point;

At some time later in your program you will want to complete the type. You do this by defining it as you usually would:

     struct point
       {
         int x, y;
       };


Next: , Previous: Incomplete Types, Up: Data Types

2.8 Type Specifiers

There are two type specifiers that you can prepend to your variable declarations which change how the variables may be accessed: const and volatile.

const causes the variable to be read-only; after initialization, its value may not be changed.

     const float pi = 3.14159;

In addition to helping to prevent accidental value changes, declaring variables with const can aid the compiler in code optimization.

volatile tells the compiler that the variable is explicitly changeable, and seemingly useless accesses of the variable (for instance, via pointers) should not be optimized away. You might use volatile variables to store data that is updated via callback functions.

     volatile float currentTemperature = 40.0;


Next: , Previous: Type Specifiers, Up: Data Types

2.9 Storage Class Specifiers

There are four storage class specifiers that you can prepend to your variable declarations which change how the variables are stored in memory: auto, extern, register, and static.

You use auto for variables which are local to a function, and whose values should be discarded upon return from the function in which they are declared. This is the default behavior for variables declared within functions.

     void
     foo (int value)
     {
       auto int x = value;
       ...
       return;
     }

register is nearly identical in purpose to auto, except that it also suggests to the compiler that the variable will be heavily used, and, if possible, should be stored in a register in memory. You cannot use the address-of operator to obtain the address of a variable declared with register.

static is essentially the opposite of auto: when applied to variables within a function or block, these variables will retain their value even when the function or block is finished.

     int
     sum (int x)
     {
       static int sumSoFar = 0;
       sumSoFar = sumSoFar + x;
       return x;
     }

You can also declare variables outside of functions to be static; such variables are visible (global) to the current source file (but not other source files).

extern is useful for declaring variables that you want to be visible to all source files that are linked into your project. You cannot initialize a variable in an extern declaration, as no space is actually allocated during the declaration. You must make both an extern declaration (typically in a header file that is included by the other source files which need to access the variable) and a non-extern declaration which is where space is actually allocated to store the variable. The extern declaration may be repeated multiple times.

     extern int numberOfClients;
     
     ...
     
     int numberOfClients = 0;

See Program Structure and Scope, for related information.


Previous: Storage Class Specifiers, Up: Data Types

2.10 Renaming Types

Sometimes it is conveninent to give a new name to a type. You can do this using the typedef statement. See The typedef Statement, for more information.


Next: , Previous: Data Types, Up: Top

3 Expressions and Operators


Next: , Up: Expressions and Operators

3.1 Expressions

An expression consists of at least one operand and zero or more operators. The operands may be any value, including constants, variables, and function calls that return values. Here are some examples:

     47
     2 + 2
     function()

The last of those, function(), is only an expression if function() has a return type other than void.

You can use parentheses to group subexpressions:

     ( 2 * ( ( 3 + 10 ) - ( 2 * 6 ) ) )

Innermost expressions are evaluated first. In the above example, 3 + 10 and 2 * 6 evaluate to 13 and 12, respectively. Then 12 is subtracted from 13, resulting in 1. Finally, 1 is multiplied by 2, resulting in 2. The outermost parentheses are completely optional.

An operator specifies an operation to be performed on its operand(s). Operators may have one, two, or three operands, depending on the operator.


Next: , Previous: Expressions, Up: Expressions and Operators

3.2 Unary Operators

Unary operators perform an operation on a single operand.


Next: , Up: Unary Operators

3.2.1 The Increment Operator

The increment operator ++ adds 1 to its operand. The operand must be a either a variable of one of the primitive data types, a pointer, or an enumeration variable. Here are some examples:

     int x = 5;
     char y = 'B';
     float z = 5.2;
     int *p = &x;
     
     x++;   /* x is now 6. */
     y++;   /* y is now `C'. */
     z++;   /* z is now 6.2. */
     p++;   /* p is now &x + sizeof(int). */

You can use the increment operator either before or after the operand. A prefix increment adds 1 before the operand is evaluated. A postfix increment adds 1 after the operand is evaluated. In the previous examples, that wouldn't have made any difference. However, there are cases where it does make a difference:

     int x = 5;
     printf ("%d \n", x++);    /* Print x and then increment it. */
     /* x is now equal to 6. */
     printf ("%d \n", ++x);    /* Increment x and then print it. */

The output of the above example is:

     5
     7


Next: , Previous: The Increment Operator, Up: Unary Operators

3.2.2 The Decrement Operator

The decrement operator -- subtracts 1 from its operand. The operand must be a either a variable of one of the primitive data types, a pointer, or an enumeration variable. Here are some examples:

     int x = 5;
     char y = 'B';
     float z = 5.2;
     int *p = &x;
     
     x--;   /* x is now 4. */
     y--;   /* y is now `A'. */
     z--;   /* z is now 4.2. */
     p--;   /* p is now &x - sizeof(int). */

You can use the decrement operator either before or after the operand. A prefix decrement subtracts 1 before the operand is evaluated. A postfix increment subtracts 1 after the operand is evaluated. In the previous examples, that wouldn't have made any difference. However, there are cases where it does make a difference:

     int x = 5;
     printf ("%d \n", x--);   /* Print x and then decrement it. */
     /* x is now 4 */
     printf ("%d \n", --x);   /* Decrement x and then print it. */

The output of the above example is:

     5
     3


Next: , Previous: The Decrement Operator, Up: Unary Operators

3.2.3 The Positive Operator

You can use the positive operator + on numeric values to indicate that their value is positive. By default, values are positive unless explicitly stated to be negative, so there is no need to use this operator as far as the compiler is concerned. However, you can use it to visually reinforce the fact that a value is positive. Here are some examples:

     int x = +5;
     float y = +3.14159;


Next: , Previous: The Positive Operator, Up: Unary Operators

3.2.4 The Negative Operator

You can use the negative operator - on numeric variables and constants to indicate that their value is negative. Here are some examples:

     int x = -5;
     float y = -3.14159;

If the operand you use with the negative operator is of an unsigned data type, then the result is not negative, but rather the maximum value of the unsigned data type, minus the value of the operand.


Next: , Previous: The Negative Operator, Up: Unary Operators

3.2.5 The Logical Negation Operator

You can use the logical negation operator ! to get the logical opposite of its operand. If its operand is 0 (or null, if the operand is a pointer), then the result of the logical negation operator is 1. If its operand is anything other than 0 (or null), then the result of the logical negation operator is 0. In any case, the result is an integer value. Here are some examples:

     int x = !5;   /* x is 0. */
     if (!x)
       printf ("x is 0");


Next: , Previous: The Logical Negation Operator, Up: Unary Operators

3.2.6 The Bitwise Complement Operator

You can use the bitwise complement operator ~ to get the one's complement of its operand. The operand must be an integer or character type. The bitwise complement operator examines its operand's bits, and changes all 0 bits to 1 and all 1 bits to 0. Here is an example:

     unsigned int x = 500;
     unsigned int y;
     y = ~x;

Using signed data types with the bitwise complement operator may cause portability problems, so use unsigned data types for maximum portability.


Next: , Previous: The Bitwise Complement Operator, Up: Unary Operators

3.2.7 The Address Operator

You can use the address operator & to obtain the memory address of its operand. You can use this operator both with variables of any data type (including arrays and structures) and with functions, but you can't use it with literal values. You should only store the result of the address operator in pointer variables.

     int x = 5;
     int *ptr = &x;


Next: , Previous: The Address Operator, Up: Unary Operators

3.2.8 The Indirection Operator

You can use the indirection operator * to obtain the value stored at the address specified by its operand. This is known as dereferencing its operand. Its operand must be a pointer.

     int x = 5;
     int y;
     int *ptr;
     
     ptr = &x;    /* ptr now holds the address of x. */
     
     y = *ptr;    /* y gets the value stored at the address
                     stored in ptr. */

The result of using the indirection operator with pointers that have not been initialized is unspecified; usually the program will crash.


Next: , Previous: The Indirection Operator, Up: Unary Operators

3.2.9 The sizeof Operator

You can use the sizeof operator to obtain the size (in bytes) of the data type of its operand. The operand may be an actual type specifier (such as int or float), as well as any valid expression. You must enclose the operand in parentheses after the operator. Here are some examples:

     size_t a = sizeof(int);
     size_t b = sizeof(float);
     size_t c = sizeof(5);
     size_t d = sizeof(5.143);

The result of the sizeof operator is of a type called size_t, which is defined in the header file <stddef.h>. size_t is an unsigned integer type, perhaps identical to unsigned int or unsigned long int; it varies from system to system.


Next: , Previous: The sizeof Operator, Up: Unary Operators

3.2.10 Type Casts

You can use a type cast to explicitly cause an expression to be of a specified data type. A type cast consists of a type specifier enclosed in parentheses, followed by an expression. To ensure proper casting, you should also enclose the expression that follows the type specifier in parentheses. Here is an example:

     float x;
     int y = 7;
     int z = 3;
     x = (float) (y / z);

In that example, since y and z are both integers, integer division is performed, and even though x is a floating-point variable, it receives the value 2. By explicitly casting the result of the division to float, the floating-point value 2.333... is retained and assigned to x.

Type casting also works with custom data types. Here is an example of converting an array of 8 bytes to a 8-byte structure type:

     struct fooType
     {
       float f;
       unsigned short int a;
       unsigned short int b;
     };
     
     struct fooType foo;
     unsigned char byteArray[8];
     
     foo = (struct fooType) byteArray;

In practice, you should also pack your structure type to ensure that the compiler doesn't add any padding, thereby increasing the size of the type. In general, different compilers may use different representations for data types, so such constructs are not portable.


Next: , Previous: Type Casts, Up: Unary Operators

3.2.11 Array Subscripts

You can access array elements by specifying the name of the array, and the array subscript (or index, or element number) enclosed in brackets. Here is an example, supposing an integer array called my_array:

     my_array[0] = 5;


Previous: Array Subscripts, Up: Unary Operators

3.2.12 Function Calls as Expressions

A call to any function which returns a value is an expression.

     int function(void);
     ...
     a = 10 + function();


Next: , Previous: Unary Operators, Up: Expressions and Operators

3.3 Binary Operators


Next: , Up: Binary Operators

3.3.1 The Addition Operator

You use the addition operator + to add two operands. You put the operands on either side of the operator, and it does not matter which operand goes on which side (in the absence of side effects): 3 + 5 and 5 + 3 both result in 8. The operands must be either expressions of a primitive data type or pointers.

     x = 5 + 3;
     y = 10 + 37;
     z = 1 + 2 + 3 + 4 + 5;

When you use more than one addition operator (and more than two operands), such as in the last example, the expression is evaluated from left to right.


Next: , Previous: The Addition Operator, Up: Binary Operators

3.3.2 The Subtraction Operator

You use the subtraction operator - to subtract its second operand from its first operand. You put the operands on either side of the operator, and it does matter which operand goes on which side: 3 - 5 and 5 - 3 do not have the same result. The operands must be either expressions of a primitive data type or pointers.

     x = 5 - 3;
     y = 57 - 10;
     z = 5 - 4 - 3 - 2 - 1;

When you use more than one subtraction operator (and more than two operands), such as in the last example, the expression is evaluated from left to right.


Next: , Previous: The Subtraction Operator, Up: Binary Operators

3.3.3 The Multiplication Operator

You use the multiplication operator * to multiply two operands together. You put the operands on either side of the operator, and it does not matter which operand goes on which side: 3 * 5 and 5 * 3 both result in 15. The operands must be expressions of a primitive data type.

     x = 5 * 3;
     y = 47 * 1;
     z = 1 * 2 * 3 * 4 * 5;

When you use more than one multiplication operator (and more than two operands), such as in the last example, the expression is evaluated from left to right.


Next: , Previous: The Multiplication Operator, Up: Binary Operators

3.3.4 The Division Operator

You use the division operator / to divide its first operand by its second operand. You put the operands on either side of the operator, and it does matter which operand goes on which side: 3 / 5 and 5 / 3 do not have the same result. The operands must be expressions of a primitive data type.

     x = 5 / 3;
     y = 940 / 20;
     z = 100 / 2 / 2;

When you use more than one division operator (and more than two operands), such as in the last example, the expression is evaluated from left to right.


Next: , Previous: The Division Operator, Up: Binary Operators

3.3.5 The Modulus Operator

You use the modulus operator % to obtain the remainder produced by dividing its two operands. You put the operands on either side of the operator, and it does matter which operand goes on which side: 3 % 5 and 5 % 3 do not have the same result. The operands must be expressions of a primitive data type.

     x = 5 % 3;
     y = 74 % 47;
     z = 47 % 32 % 21;

When you use more than one modulus operator (and more than two operands), like in the last example, the expression is evaluated from left to right.

A common application of the modulus operator is to determine if one number is divisible by another number. If it is divisible, then the remainder is zero. Here is an example of that:

     int counter;
     for (counter = 0; counter <= 100; counter++)
       {
         if (counter % 5 == 0)
           printf ("%d\n", counter);
       }

That prints all of the integers from 0 to 100 that are divisible by 5.


Next: , Previous: The Modulus Operator, Up: Binary Operators

3.3.6 The Shift Operators

You use the left-shift operator << to shift its first operand's bits to the left. You specify the number of bit-places shifted with the second operand. If there is a 1 bit in the leftmost bit position, it will be discarded. New bits that are added to the rightmost bit position will all be 0.

     x = 47;    /* 47 is 00101111 in binary. */
     x << 1;    /* 00101111 << 1 is 01011110. */

You use the right-shift operator >> to shift its first operand's bits to the right. You specify the number of bit-places shifted with the second operand. If there is a 1 bit in the rightmost bit position, it will be discarded. New bits that are added to the leftmost bit position may be either 0 or 1. If the first operand is unsigned, then the added bits will be 0. If it is signed, the added bits will be either 0 or whatever value was previously in the leftmost bit position.

     x = 47;   /* 47 is 00101111 in binary. */
     x >> 1;   /* 00101111 >> 1 is 00010111. */


Next: , Previous: The Shift Operators, Up: Binary Operators

3.3.7 The Bitwise AND Operator

The bitwise AND operator & examines each bit in its two operands, and when two corresponding bits are both 1, the resulting bit is 1. In every other case the result is 0. Here is an example of how this operator works, using binary numbers:

     11001001 & 10011011 = 10001001

If you look closely at that, you'll see that when a bit is 1 in both operands, the corresponding bit in the result is set to 1. Otherwise it is set to 0. Here is another example, this time in C:

     char x = 149, y = 34, z;
     z = x & y;


Next: , Previous: The Bitwise AND Operator, Up: Binary Operators

3.3.8 The Bitwise Inclusive OR Operator

The bitwise inclusive OR operator | examines each bit in its two operands, and when two corresponding bits are both 0, the resulting bit is 0. In every other case the resulting bit is 1. Here is an example of how this operator works, using binary numbers:

     11001001 | 10011011 = 11011011

Here is another example, this time in C:

     char x = 149, y = 34, z;
     z = x | y;


Next: , Previous: The Bitwise Inclusive OR Operator, Up: Binary Operators

3.3.9 The Bitwise Exclusive OR Operator

The bitwise exclusive OR operator ^ (also known as XOR) examines each bit in its two operands, and when two corresponding bits are different, the resulting bit is 1. When they are the same, the resulting bit is 0. Here is an example of how this operator works, using binary numbers:

     11001001 | 10011011 = 01011001

Here is another example, this time in C.

     char x = 149, y = 34, z;
     z = x ^ y;


Next: , Previous: