Oslo College C Programming Tutorial (And GCC Guide)
Oslo College C Programming Tutorial (And GCC Guide)
Copyright c 2002 Free Software Foundation, Inc. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation; there being no Invariant Section, with the Front-Cover Texts being A GNU Manual, and with the Back-Cover Texts as in (a) below. A copy of the license is included in the section entitled GNU Free Documentation License. (a) The FSFs Back-Cover Text is: You have freedom to copy and modify this GNU Manual, like GNU software. Copies published by the Free Software Foundation raise funds for GNU development.
Preface
xi
Preface
This book is a tutorial for the computer programming language C. Unlike BASIC or Pascal, C was not written as a teaching aid, but as a professional tool. Programmers love C! Moreover, C is a standard, widely-used language, and a single C program can often be made to run on many dierent kinds of computer. As Richard M. Stallman remarks in GNU Coding Standards, Using another language is like using a non-standard feature: it will cause trouble for users. (See http://www.gnu.org/prep/standards_toc.html.) Skeptics have said that everything that can go wrong in C, does. True, it can be unforgiving, and holds some diculties that are not obvious at rst, but that is because it does not withhold its powerful capabilities from the beginner. If you have come to C seeking a powerful language for writing everyday computer programs, you will not be disappointed. To get the most from this book, you should have some basic computer literacy you should be able to run a program, edit a text le, and so on. You should also have access to a computer running a GNU system such as GNU/Linux. (For more information on GNU and the philosophy of free software, see http://www.gnu.org/philosophy/.) The tutorial introduces basic ideas in a logical order and progresses steadily. You do not need to follow the order of the chapters rigorously, but if you are a beginner to C, it is recommended that you do. Later, you can return to this book and copy C code from it; the many examples range from tiny programs that illustrate the use of one simple feature, to complete applications that ll several pages. Along the way, there are also brief discussions of the philosophy behind C. Computer languages have been around so long that some jargon has developed. You should not ignore this jargon entirely, because it is the language that programmers speak. Jargon is explained wherever necessary, but kept to a minimum. There is also a glossary at the back of the book. The authors of this book hope you will learn everything you need to write simple C programs from this book. Further, it is released under the GNU Free Documentation License, so as the computers and robots in the fantasies of Douglas Adams say, Share and Enjoy!
The rst edition of this book was written in 1987, then updated and rewritten in 1999. It was originally published by Dabs Press. After it went out of print, David Atherton of Dabs and the original author, Mark Burgess, agreed to release the manuscript. At the request of the Free Software Foundation, the book was further revised by Ron Hale-Evans in 2001 and 2002. The current edition is written in Texinfo, which is a documentation system using a single source le to produce both online information and printed output. You can read this tutorial online with either the Emacs Info reader, the stand-alone Info reader, or a World Wide Web browser, or you can read it as a printed book.
The advantages of C
1 Introduction
What is a high-level language? Why is C unusual? Any suciently complex object has levels of detail; the amount of detail we see depends on how closely we scrutinize the object. A computer has many levels of detail. The terms low level and high level are often used to describe these layers of complexity in computers. The low level is buried in the computers microchips and microcircuits. The low level is the level at which the computer seems most primitive and mechanical, whereas the high level describes the computer in less detail, and makes it easier to use. You can see high levels and low levels in the workings of a car. In a car, the nuts, bolts, and pistons of the low level can be grouped together conceptually to form the higher-level engine. Without knowing anything about the nuts and bolts, you can treat the engine as a black box: a simple unit that behaves in predictable ways. At an even higher level (the one most people use when driving), you can see a car as a group of these black boxes, including the engine, the steering, the brakes, and so on. At a high level, a computer also becomes a group of black boxes. C is a high-level language. The aim of any high-level computer language is to provide an easy, natural way to give a list of instructions (a computer program) to a computer. The native language of the computer is a stream of numbers called machine language. As you might expect, the action resulting from a single machine language instruction is very primitive, and many thousands of them can be required to do something substantial. A high-level language provides a set of instructions you can recombine creatively and give to the imaginary black boxes of the computer. The high-level language software will then translate these high-level instructions into low-level machine language instructions.
Chapter 1: Introduction
C is succinct. It permits the creation of tidy, compact programs. This feature can be a mixed blessing, however, and the C programmer must balance simplicity and readability. C allows commands that are invalid in other languages. This is no defect, but a powerful freedom which, when used with caution, makes many things possible. It does mean that there are concealed diculties in C, but if you write carefully and thoughtfully, you can create fast, ecient programs. With C, you can use every resource your computer oers. C tries to link closely with the local environment, providing facilities for gaining access to common peripherals like disk drives and printers. When new peripherals are invented, the GNU community quickly provides the ability to program them in C as well. In fact, most of the GNU project is written in C (as are many other operating systems). For the reasons outlined above, C is the preeminent high-level language. Clearly, no language can guarantee good programs, but C can provide a framework in which it is easy to program well.
The compiler
2 Using a compiler
How to use a compiler. What can go wrong. The operating system is the layer of software that drives the hardware of a computer and provides the user with a comfortable work environment. Operating systems vary, but most have a shell, or text interface. You use the GNU shell every time you type in a command that launches an email program or text editor under GNU. In the following sections of this chapter, we will explore how to create a C program from the GNU shell, and what might go wrong when you do.
The le name endings, or le extensions, identify the contents of les to the compiler. For example, the .c sux tells the compiler that the le contains C source code, and the other letters indicate other kinds of les in a similar way.
Errors
2.4 Errors
Errors are mistakes that programmers make in their code. There are two main kinds of errors. Compile-time errors are errors caught by the compiler. They can be syntax errors, such as typing fro instead of for, or they can be errors caused by the incorrect construction of your program. For example, you might tell the compiler that a certain variable is an integer, then attempt to give it a non-integer value such as 5.23. (See Section 2.4.2 [Type errors], page 6.) The compiler lists all compile-time errors at once, with the line number at which each error occurred in the source code, and a message that explains what went wrong. For example, suppose that, in your le eg.c you write y = sin (x]; instead of y = sin (x); (By the way, this is an example of assignment. With the equals sign (=), you are assigning the variable y (causing the variable y to contain) the sine of the variable x. This is somewhat dierent from the way equals signs work in mathematics. In math, an equals sign indicates that the numbers and variables on either side of it are already equal; in C, an equals sign makes things equal. Sometimes it is useful to think of the equals sign as an abbreviation for the phrase becomes the value of.) Ignore the syntactic details of the statements above for now, except to note that closing the (x) with a square bracket instead of a parenthesis is an error in C. Upon compilation, you will see something like this error message: error eg.c: In function main: eg.c:8: parse error before ] (If you compile the program within Emacs, you can jump directly to the error. We will discuss this feature later. See Chapter 23 [Debugging], page 231, for more information.) A program with compile-time errors will cause the compiler to halt, and will not produce an executable. However, the compiler will check the syntax up to the last line of your source code before stopping, and it is common for a single real error, even something as simple as a missing parenthesis, to result in a huge and confusing list of nonexistent errors from the compiler. This can be shocking and disheartening to novices, but youll get used to it with experience. (We will provide an example later in the book. See Chapter 23 [Debugging], page 231.) As a rule, the best way to approach this kind of problem is to look for the rst error, x that, and then recompile. You will soon come to recognize when subsequent error messages are due to independent problems and when they are due to a cascade. Run-time errors are errors that occur in a compiled and running program, sometimes long after it has been compiled. One kind of run-time error happens when you write a running program that does not do what you intend. For example, you intend to send a letter to all drivers whose
licenses will expire in June, but instead, you send a letter to all drivers whose licenses will ever expire. Another kind of run-time error can cause your program to crash, or quit abruptly. For example, you may tell the computer to examine a part of its memory that doesnt exist, or to divide some variable by zero. Fortunately, the GNU environment is extremely stable, and very little will occur other than an error message in your terminal window when you crash a program you are writing under GNU. If the compilation of a program is successful, then a new executable le is created. When a programmer wishes to make alterations and corrections to a C program, these must be made in the source code, using a text editor; after making the changes, the programmer must recompile the program, or its salient parts.
3. 4. 5. 6.
How does one usually compile a C program? Are upper and lower case equivalent in C? What the two main kinds of error that can occur in a program? If you had some C source code that you wished to call accounts, under what name would you save it? 7. What would be the name of the executable le for the program in the last question? 8. How would you run this program?
/******************************************************/ do_nothing() /* Function called */ { } (Any text sandwiched between /* and */ in C code is a comment for other humans to read. See the section on comments below for more information.) There are several things to notice about this program. First, this program consists of two functions, one of which calls the other. Second, the function do_nothing is called by simply typing the main part of its name followed by () parentheses and a semicolon. Third, the semicolon is vital; every simple statement in C ends with one. This is a signal to the compiler that the end of a statement has been reached and that anything that follows is part of another statement. This signal helps the compiler diagnose errors.
10
Fourth, the curly bracket characters { and } outline a block of statements. When this program meets the closing } of the second functions block, it transfers control back to main, where it meets another }, and the program ends.
3.2 Comments
Annotating programs.
Comments are a way of inserting remarks and reminders into code without aecting its behavior. Since comments are only read by other humans, you can put anything you wish to in a comment, but it is better to be informative than humorous. The compiler ignores comments, treating them as though they were whitespace (blank characters, such as spaces, tabs, or carriage returns), and they are consequently ignored. During compilation, comments are simply stripped out of the code, so programs can contain any number of comments without losing speed. Because a comment is treated as whitespace, it can be placed anywhere whitespace is valid, even in the middle of a statement. (Such a practice can make your code dicult to read, however.) Any text sandwiched between /* and */ in C code is a comment. Here is an example of a C comment:
11
/* ...... comment ......*/ Comments do not necessarily terminate at the end of a line, only with the characters */. If you forget to close a comment with the characters */, the compiler will display an unterminated comment error when you try to compile your code.
3.3 Example 1
#include <stdio.h> main () { /* This little line has no effect */ /* This little line has none */ /* This little line went all the way down to the next line, And so on... And so on... And so on... */ do_little(); printf ("Function main completing.\n"); } /**********************************************/ /* A bar like the one above can be used to */ /* separate functions visibly in a program */ /* header file */
/* Trivial program */
do_little () { /* This function does little. */ printf ("Function do_little completing.\n"); } Again, this example is old-fashioned C, and in mediocre style. To make it more compliant with the ANSI Standard and GNU guidelines, we would declare the variable type each function returns (int for main, which also requires an exit or return statement), and we would create function prototypes at the beginning of the le. (See Chapter 4 [Functions], page 13.)
12
1. What is a block? 2. Does a C program start at the beginning? Where is the beginning? 3. What happens when a program comes to a } character? What does this character signify? 4. What vital piece of punctuation goes at the end of every simple C statement? 5. What happens if a comment is not ended? That is if the programmer types /* .. to start but forgets the ..*/ to close?
Function examples
13
4 Functions
Solving problems and getting results. A function is a section of program code that performs a particular task. Making functions is a way of isolating one section of code from other independent sections. Functions allow a programmer to separate code by its purpose, and make a section of code reusable that is, make it so the section can be called in many dierent contexts. Functions should be written in the following form: type function name (type parameter1 name, type parameter2 name, ...) { variable declarations statements ... ... ... } You may notice when reading the examples in this chapter that this format is somewhat dierent from the one we have used so far. This format conforms to the ANSI Standard and is better C. The other way is old-fashioned C, although GCC will still compile it. Nevertheless, GCC is not guaranteed to do so in the future, and we will use ANSI Standard C in this text from now on. As shown above, a function can have a number of parameters, or pieces of information from outside, and the functions body consists of a number of declarations and statements, enclosed by curly brackets: {...}.
14
Chapter 4: Functions
Function prototyping
15
In C, returning a value from a function is a simple matter. Consider the function calculate_bill as it might be written in a program that contains the statement above: int calculate_bill (int a, int b, int c) { int total; total = a + b + c; return total; } As soon as the return statement is met, calculate_bill stops executing and returns the value total. A function that returns a value must have a return statement. Forgetting it can ruin a program. For instance if calculate_bill had read as follows, then the variable bill would have had no meaningful value assigned to it, and you might have received a warning from the compiler as well. (The word void below indicates that the function does not return a value. In ANSI C, you must place it before the name of any such function.) void calculate_bill (int a, int b, int c) { int total; total = a + b + c; } On the other hand, you do not need to actually use a value when a function returns one. For example, the C input/output functions printf and scanf return values, but the values are rarely used. See undened [les], page undened , for more information on these functions. If we use the rst version of the calculate_bill function (the one that contains the line return total;), the value of the function can simply be discarded. (Of course, the resulting program is not very useful, since it never displays a value to the user!) int main() { calculate_bill (1, 2, 3); exit (0); }
16
Chapter 4: Functions
1. At the beginning of the program, in global scope. (See Chapter 6 [Scope], page 27.) 2. In the denition of the function itself. Function declarations at the beginning of a program are called prototypes. Here is an example of a program in which prototypes are used: #include <stdio.h> void print_stuff (int foo, int bar); int calc_value (int bas, int quux);
void print_stuff (int foo, int bar) { int var_to_print; var_to_print = calc_value (foo, bar); printf ("var_to_print = %d\n", var_to_print); }
int main() { print_stuff (23, 5); exit (0); } The above program will print the text var_to_print = 115 and then quit. Prototypes may seem to be a nuisance, but they overcome a problem intrinsic to compilers, which is that they compile functions as they come upon them. Without function prototypes, you usually cannot write code that calls a function before the function itself is dened in the program. If you place prototypes for your functions in a header le, however, you can call the functions from any source code le that includes the header. This is one reason C is considered to be such a exible programming language. Some compilers avoid the use of prototypes by making a rst pass just to see what functions are there, and a second pass to do the work, but this takes about twice as long. Programmers already hate the time compilers take, and do not want to use compilers that make unnecessary passes on their source code, making prototypes a necessity. Also, prototypes enable the C compiler to do more rigorous error checking, and that saves an enormous amount of time and grief.
17
GNU coding standards specify that you should always use exit (or return) within your main function. (See Chapter 22 [Style], page 227.) You can use the exit function to terminate a program at any point, no matter how many function calls have been made. Before it terminates the program, it calls a number of other functions that perform tidy-up duties such as closing open les. exit is called with a return code, like this: exit(0); In the example above, the return code is 0. Any program that calls your program can read the return code from your program. The return code is like a return value from another function that is not main; in fact, most of the time you can use the return command within your main, instead of exit. Conventionally, a return code of 0 species that your program has ended normally and all is well. (You can remember this as zero errors, although for technical reasons, you cannot use the number of errors your program found as the return code. See Chapter 22 [Style], page 227.) A return code other than 0 indicates that some sort of error has occurred. If your code terminates when it encounters an error, use exit, and specify a non-zero return code.
18
Chapter 4: Functions
Integer variables
19
20
These integer types dier in the size of the integer they can hold and the amount of storage required for them. The sizes of these variables depend on the hardware and operating system of the computer. On a typical 32-bit GNU system, the sizes of the integer types are as follows. Type Bits Possible Values char unsigned char short unsigned short int unsigned int long unsigned long long long unsigned long long 8 8 16 16 32 32 32 32 64 64 -127 to 127 0 to 255 -32,767 to 32,767 0 to 65,535 -2,147,483,647 to 2,147,483,647 0 to 4,294,967,295 -2,147,483,647 to 2,147,483,647 0 to 4,294,967,295 -9,223,372,036,854,775,807 to 9,223,372,036,854,775,807 0 to 18,446,744,073,709,551,615
On some computers, the lowest possible value may be 1 less than shown here; for example, the smallest possible short may be -32,768 rather than -32,767. The word unsigned, when placed in front of integer types, means that only positive or zero values can be used in that variable (i.e. it cannot have a minus sign). The advantage is that larger numbers can then be stored in the same variable. The ANSI standard also allows the word signed to be placed before an integer, to indicate the opposite of unsigned.
Declarations
21
Floating point numbers are numbers with a decimal point. There are dierent sizes of oating point numbers in C. The float type can contain large oating point numbers with a small degree of precision, but the double-precision double type can hold even larger numbers with a higher degree of precision. (Precision is simply the number of decimal places to which a number can be computed with accuracy. If a number can be computed to ve decimal places, it is said to have ve signicant digits.) All oating point mathematical functions built into C require double or long float arguments (long float variables are generally the same as double variables on GNU systems), so it is common to use float only for storage of small oating point numbers, and to use double everywhere else. Here are the oating point variable types available in C: float: A single-precision oating point number, with at least 6 signicant decimal digits. double: A double-precision oating point number. Usually the same as long float on GNU systems. Has at least 10 signicant decimal digits. long double: Usually the same as double on GNU systems, but may be a 128-bit number in some cases. On a typical 32-bit GNU system, the sizes of the dierent oating point types are as follows. Type Bits Possible values (approx.) float double long double 32 64 64 1e-38 to 1e+38 2e-308 to 1e+308 2e-308 to 1e+308
You may nd the gures in the right-hand column confusing. They use a form of shorthand for large numbers. For example, the number 5e2 means 5 102, or 500. 5e-2 means 5 10 2 (5/100, or 1/20). You can see, therefore, that the float, double, and long double types can contain some very large and very small numbers indeed. (When you work with large and small numbers in C, you will use this notation in your code.)
5.2 Declarations
To declare a variable, write the type followed by a list of variables of that type: type name variable name 1, ..., variable name n; For example: int last_year, cur_year; long double earth_mass, mars_mass, venus_mass; unsigned int num_pets;
22
long city_pop, state_pop; state_pop = city_pop = 5000000; short moon_landing = 1969; float temp1 temp2 temp3 temp1, temp2, temp3; = 98.6; = 98.7; = 98.5;
double bignum, smallnum; bignum = 2.36e208; smallnum = 3.2e-300; Always declare your variables. A compiler will catch a missing declaration every time and terminate compilation, complaining bitterly. (You will often see a host of error messages, one for each use of the undeclared variable. See Chapter 23 [Debugging], page 231.)
5.3 Initialization
Assigning a variable its rst value is called initializing the variable. When you declare a variable in C, you can also initialize it at the same time. This is no more ecient in terms of a running program than doing it in two stages, but sometimes creates tidier and more compact code. Consider the following: int initial_year; float percent_complete; initial_year = 1969; percent_complete = 89.5; The code above is equivalent to the code below, but the code below is more compact. int initial_year = 1969; float percent_complete = 89.5; You can always write declarations and initializers this way, but you may not always want to. (See Chapter 22 [Style], page 227.)
23
exact_length = 3.37; rough_length = (int) exact_length; In the example above, the cast operator rounds the number down when converting it from a oat to an integer, because an integer number cannot represent the fractional part after the decimal point. Note that C always truncates, or rounds down, a number when converting it to an integer. For example, both 3.1 and 3.9 are truncated to 3 when C is converting them to integer values. The cast operator works the other way around, too: float exact_length; int rough_length; rough_length = 12; exact_length = (float) rough_length; In converting large integers to oating point numbers, you may lose some precision, since the float type guarantees only 6 signicant digits, and the double type guarantees only 10. It does not always make sense to convert types. (See Chapter 20 [Data structures], page 205, for examples of types that do not convert to other types well.)
my_float = 75.345; my_int = (int) my_float; my_ch = (int) my_float; printf ("Convert from float my_float=%f to my_int=%d and my_ch=%c\n", my_float, my_int, my_ch); my_int = 69; my_float = (float) my_int; my_ch = my_int;
24
printf ("Convert from int my_int=%d to my_float=%f and my_ch=%c\n", my_int, my_float, my_ch); my_ch = *; my_int = my_ch; my_float = (float) my_ch; printf ("Convert from int my_ch=%c to my_int=%d and my_float=%f\n", my_ch, my_int, my_float); exit(0); } Here is the sort of output you should expect (oating point values may dier slightly): Convert from float my_float=75.345001 to my_int=75 and my_ch=K Convert from int my_int=69 to my_float=69.000000 and my_ch=E Convert from int my_ch=* to my_int=42 and my_float=42.000000
} In this example, the variable my_var is created in the le secondary.c, assigned a value in the le main.c, and printed out in the function print_value, which is dened in the le secondary.c, but called from the le main.c. See Section 17.4 [Compiling multiple les], page 172, for information on how to compile a program whose source code is split among multiple les. For this example, you can
25
simply type the command gcc -o testprog main.c secondary.c, and run the program with ./testprog.
26
What is the dierence between the types int and unsigned int? Write a statement that assigns the value 1066 to the integer variable norman. What data type do C functions return by default? You must declare the data type a function returns at two places in a program. Where? Write a statement, using the cast operator, to print out the integer part of the number 23.1256. 10. Is it possible to have an automatic global variable?
5. 6. 7. 8. 9.
Global Variables
27
6 Scope
Where a programs ngers can and cant reach. Imagine that a function is a building with a person (Fred) standing in the doorway. This person can see certain things: other people and other buildings, out in the open. But Fred cannot see certain other things, such as the people inside the other buildings. Just so, some variables in a C program, like the people standing outside, are visible to nearly every other part of the program (these are called global variables), while other variables, like the people indoors, are hidden behind the brick walls of curly brackets (these are called local variables). Where a variable is visible to other C code is called the scope of that variable. There are two main kinds of scope, global and local, which stem from the two kinds of places in which you can declare a variable: 1. Global scope is outside all of the functions, that is, in the space between function denitions after the #include lines, for example. Variables declared in global scope are called global variables. Global variables can be used in any function, as well as in any block within that function. #include <stdio.h> int global_integer; float global_floating_point; int main () { exit (0); } 2. You can also declare variables immediately following the opening bracket ({) of any block of code. This area is called local scope, and variables declared here are called local variables. A local variable is visible within its own block and the ones that block contains, but invisible outside its own block. #include <stdio.h> int main() { int foo; float bar, bas, quux; exit (0); }
28
Chapter 6: Scope
laration of those global variables, but global variables are usually declared in a header le that is included everywhere they are needed.) Global variables are created when a program is started and are not destroyed until a program is stopped.
29
blocks, they can still communicate with other functions via parameters. See Chapter 7 [Expressions and operators], page 31, the next chapter, for information on parameters.
30
Chapter 6: Scope
31
32
Something that can be assigned to is called an lvalue, (l for left, because it can appear on the left side of an assignment). You will sometimes see the word lvalue in error messages from the compiler. For example, try to compile a program containing the following code: 5 = 2 + 3; You will receive an error such as the following: error bad_example.c:3: invalid lvalue in assignment You cant assign a value to 5; it has its own value already! In other words, 5 is not an lvalue.
Many people confuse the assignment operator (=) with the equality operator (==), and this is a major source of bugs in C programs. Because of early arithmetic training, people tend to think of = as indicating equality, but in C it means takes on the value produced by, and it should always be read that way. By way of contrast, == is an equality test operator and should always be read is tested for equality with. (See Section 7.8 [Comparisons and logic], page 37, for more information on the == operator.)
+ + * / / %
unary plus, example: +5 unary minus, example: -5 addition, example: 2 + 2 subtraction, example: 14 - 7 multiplication, example: 3 * 3 oating point division, example: 10.195 / 2.4 integer division div, example: 5 / 2 integer remainder mod, example: 24 % 7
Expressions
33
7.3 Expressions
An expression is simply a string of operators, variables, numbers, or some combination, that can be parsed by the compiler. All of the following are expressions: 19 1 + 2 + 3 my_var my_var + some_function() (my_var + 4 * (some_function() + 2)) 32 * circumference / 3.14 day_of_month % 7 Here is an example of some arithmetic expressions in C: #include <stdio.h> int main () { int my_int; printf ("Arithmetic Operators:\n\n"); my_int = 6; printf ("my_int = %d, -my_int = %d\n", my_int, -my_int); printf ("int 1 + 2 = %d\n", 1 + 2); printf ("int 5 - 1 = %d\n", 5 - 1); printf ("int 5 * 2 = %d\n", 5 * 2); printf ("\n9 div 4 = 2 remainder 1:\n"); printf ("int 9 / 4 = %d\n", 9 / 4); printf ("int 9 % 4 = %d\n", 9 % 4); printf ("double 9 / 4 = %f\n", 9.0 / 4.0); return 0; } The program above produces the output below: Arithmetic Operators: my_int = 6, -my_int = -6 int 1 + 2 = 3 int 5 - 1 = 4
34
7.6 Special Assignment Operators ++ and -C has some special operators that can simplify code. The simplest of these are the increment and decrement operators:
35
++ --
You can use these with any integer or oating point variable (or a character in some cases, carefully). They simply add or subtract 1 from a variable. The following three statements are equivalent: variable = variable + 1; variable++; ++variable; So are these three: variable = variable - 1; variable--; --variable; Notice that the ++ and -- operators can be placed before or after the variable. In the cases above, the two forms work identically, but there is actually a subtle dierence. (See Section 18.1.2 [Postx and prex ++ and ], page 187, for more information.)
36
There are more exotic kinds too, used for machine-level operations, which we will ignore for the moment. (See Chapter 18 [Advanced operators], page 185, if you want to know more.) Here is a short program that demonstrates these special assignment operators: #include <stdio.h> int main() { int my_int; printf ("Assignment Operators:\n\n"); my_int = 10; printf ("my_int = 10 : %d\n",my_int); my_int++; printf ("my_int++ /* Assignment */
my_int -= 2; printf ("my_int -= 2 : %d\n",my_int); my_int *= 5; printf ("my_int *= 5 : %d\n",my_int); my_int /= 2; printf ("my_int /= 2 : %d\n",my_int);
/* my_int = my_int * 5 */
/* my_int = my_int / 2 */
my_int %= 3; /* my_int = my_int % 3 */ printf ("my_int %%= 3 : %d\n",my_int); return 0; } The program above produces the output below: Assignment Operators: my_int = 10 my_int++ my_int += 5 my_int-my_int -= 2 my_int *= 5 my_int /= 2 : : : : : : : 10 11 16 15 13 65 32
37
my_int %= 3 : 2 The second to last line of output is my_int /= 2 : 32 In this example, 65 divided by 2 using the /= operator results in 32, not 32.5. This is because both operands, 65 and 2, are integers, type int, and when /= operates on two integers, it produces an integer result. This example only uses integer values, since that is how the numbers are declared. To get the fractional answer, you would have had to declare the three numbers involved as oats. The last line of output is my_int %= 3 : 2 This is because 32 divided by 3 is 10 with a remainder of 2.
Important: Remember that many people confuse the equality operator (==) with the assignment operator (=), and this is a major source of bugs in C programs. (See Section 7.2 [Expressions and values], page 32, for more information on the distinction between the == and = operators.) The operators above result in values, much as the addition operator + does. They produce Boolean values: true and false only. Actually, C uses 1 for true and 0 for false when evaluating expressions containing comparison operators, but it is easy to dene the strings TRUE and FALSE as macros, and they may well already be dened in a library le you are using. (See Chapter 12 [Preprocessor directives], page 73, for information on dening macros.)
38
#define TRUE 1 #define FALSE 0 Note that although any non-zero value in C is treated as true, you do not need to worry about a comparison evaluating to anything other than 1 or 0. Try the following short program: #include <stdio.h> int main () { int truth, falsehood; truth = (2 + 2 == 4); falsehood = (2 + 2 == 5); printf("truth is %d\n", truth); printf("falsehood is %d\n", falsehood); exit (0); } You should receive the following result: truth is 1 falsehood is 0
Here is another example. The question, Is the variable a greater than the variable b, or is the variable a not greater than the variable c? might be written: (a > b) || !(a > c)
7.9.1 Inclusive OR
Note well! Shakespeare might have been disappointed that, whatever the value of a variable to_be, the result of
39
to_be || !to_be (i.e. To be, or not to be?) is always 1, or true. This is because one or the other of to_be or !to_be must always be true, and as long as one side of an OR || expression is true, the whole expression is true.
40
Parameters
41
8 Parameters
Ways in and out of functions. Parameters are the main way in C to transfer, or pass, information from function to function. Consider a call to our old friend calculate_bill: total = calculate_bill (20, 35, 28); We are passing 20, 35, and 28 as parameters to calculate_bill so that it can add them together and return the sum. When you pass information to a function with parameters, in some cases the information can go only one way, and the function returns only a single value (such as total in the above snippet of code). In other cases, the information in the parameters can go both ways; that is, the function called can alter the information in the parameters it is passed. The former technique (passing information only one way) is called passing parameters by value in computer programming jargon, and the latter technique (passing information both ways) is referred to as passing parameters by reference. For our purposes, at the moment, there are two (mutually exclusive) kinds of parameters: Value parameters are the kind that pass information one-way. They are so-called because the function to which they are passed receives only a copy of their values, and they cannot be altered as variable parameters can. The phrase passing by value mentioned above is another way to talk about passing value parameters. Variable parameters are the kind that pass information back to the calling function. They are so called because the function to which they are passed can alter them, just as it can alter an ordinary variable. The phrase passing by reference mentioned above is another way to talk about passing variable parameters. Consider a slightly-expanded version of calculate_bill: #include <stdio.h> int main (void); int calculate_bill (int, int, int); int main() { int bill; int fred = 25; int frank = 32; int franny = 27; bill = calculate_bill (fred, frank, franny); printf("The total bill comes to $%d.00.\n", bill); exit (0); } int calculate_bill (int diner1, int diner2, int diner3)
42
Chapter 8: Parameters
{ int total; total = diner1 + diner2 + diner3; return total; } Note that all of the parameters in this example are value parameters: the information ows only one way. The values are passed to the function calculate_bill. The original values are not changed. In slightly dierent jargon, we are passing the parameters by value only. We are not passing them by reference; they are not variable parameters. All parameters must have their types declared. This is true whether they are value parameters or variable parameters. In the function calculate_bill above, the value parameters diner1, diner2, and diner3 are all declared to be of type int.
That is, unless you are competing in The International Obfuscated C Code Contest (http://www.ioccc.org/).
43
When you are passing data to a function by value, the parameters in the function you are passing the data to contain copies of the data in the parameters you are passing the data with. Let us modify the function main from the last example slightly: int main() { int bill; int fred = 25; int frank = 32; int franny = 27; bill = calculate_bill (fred, frank, franny); fred = 20000; frank = 50000; franny = 20000; printf("The total bill comes to $%d.00.\n", bill); exit (0); } As far as the function calculate_bill is concerned, fred, frank, and franny are still 25, 32, and 27 respectively. Changing their values to extortionate sums after passing them to calculate_bill does nothing; calculate_bill has already created local copies of the parameters, called diner1, diner2, and diner3 containing the earlier values. Important: Even if we named the parameters in the denition of calculate_bill to match the parameters of the function call in main (see example below), the result would be the same: main would print out $84.00, not $90000.00. When passing data by value, the parameters in the function call and the parameters in the function denition (which are only copies of the parameters in the function call) are completely separate. Just to remind you, this is the calculate_bill function: int calculate_bill (int fred, int frank, int franny) { int total; total = fred + frank + franny; return total; }
44
Chapter 8: Parameters
Formal parameters are parameters as they appear in function declarations. A parameter cannot be both a formal and an actual parameter, but both formal parameters and actual parameters can be either value parameters or variable parameters. Lets look at calculate_bill again: #include <stdio.h> int main (void); int calculate_bill (int, int, int); int main() { int bill; int fred = 25; int frank = 32; int franny = 27; bill = calculate_bill (fred, frank, franny); printf("The total bill comes to $%d.00.\n", bill); exit (0); } int calculate_bill (int diner1, int diner2, int diner3) { int total; total = diner1 + diner2 + diner3; return total; } In the function main in the example above, fred, frank, and franny are all actual parameters when used to call calculate_bill. On the other hand, the corresponding variables in calculate_bill (namely diner1, diner2 and diner3, respectively) are all formal parameters because they appear in a function denition. Although formal parameters are always variables (which does not mean that they are always variable parameters), actual parameters do not have to be variables. You can use numbers, expressions, or even function calls as actual parameters. Here are some examples of valid actual parameters in the function call to calculate_bill: bill = calculate_bill (25, 32, 27); bill = calculate_bill (50+60, 25*2, 100-75); bill = calculate_bill (fred, franny, (int) sqrt(25)); (The last example requires the inclusion of the math routines in math.h, and compilation with the -lm option. sqrt is the square-root function and returns a double, so it must be cast into an int to be passed to calculate_bill.)
45
sum = add_all (4); Unfortunately, the use of stdarg.h is beyond the scope of this tutorial. For more information on variadic functions, see the GNU C Library manual (http://www.gnu.org/manual/glibc-2.0.6/
46
Chapter 8: Parameters
Pointer operators
47
9 Pointers
Making maps of data. In one sense, any variable in C is just a convenient label for a chunk of the computers memory that contains the variables data. A pointer, then, is a special kind of variable that contains the location or address of that chunk of memory. (Pointers are so called because they point to a chunk of memory.) The address contained by a pointer is a lengthy number that enables you to pinpoint exactly where in the computers memory the variable resides. Pointers are one of the more versatile features of C. There are many good reasons to use them. Knowing a variables address in memory enables you to pass the variable to a function by reference (See Section 9.4 [Variable parameters], page 51.)1 Also, since functions are just chunks of code in the computers memory, and each of them has its own address, you can create pointers to functions too, and knowing a functions address in memory enables you to pass functions as parameters too, giving your functions the ability to switch among calling numerous functions. (See [Function pointers], page 286.) Pointers are important when using text strings. In C, a text string is always accessed with a pointer to a character the rst character of the text string. For example, the following code will print the text string Boy howdy!: char *greeting = "Boy howdy!"; printf ("%s\n\n", greeting); See Chapter 15 [Strings], page 105. Pointers are important for more advanced types of data as well. For example, there is a data structure called a linked list that uses pointers to glue the items in the list together. (See Chapter 20 [Data structures], page 205, for information on linked lists.) Another use for pointers stems from functions like the C input routine scanf. This function accepts information from the keyboard, just as printf sends output to the console. However, scanf uses pointers to variables, not variables themselves. For example, the following code reads an integer from the keyboard: int my_integer; scanf ("%d", &my_integer); (See Section 16.2.9.1 [scanf], page 141, for more information.)
This, by the way, is how the phrase pass by reference entered the jargon. Like other pointers, a variable parameter makes a reference to the address of a variable.
48
Chapter 9: Pointers
total_cost_ptr = &total_cost; The * symbol in the declaration of total_cost_ptr is the way to declare that variable to be a pointer in C. (The _ptr at the end of the variable name, on the other hand, is just a way of reminding humans that the variable is a pointer.) When you read C code to yourself, it is often useful to be able to pronounce Cs operators aloud; you will nd it can help you make sense of a dicult piece of code. For example, you can pronounce the above statement float *total_cost_ptr as Declare a oat pointer called total_cost_ptr, and you can pronounce the statement total_cost_ptr = &total_ cost; as Let total_cost_ptr take as its value the address of the variable total_cost. Here are some suggestions for pronouncing the * and & operators, which are always written in front of a variable: The contents of the address held in variable or the contents of the location pointed to by variable. The address of variable or the address at which the variable variable is stored.
&
For instance: The address of fred or the address at which the variable fred is stored.
&fred *fred_ptr
The contents of the address held in fred_ptr or the contents of the location pointed to by fred_ptr. The following examples show some common ways in which you might use the * and & operators: int some_var; /* 1 */ Declare an integer variable called some_var. int *ptr_to_some_var; /* 2 */ Declare an integer pointer called ptr_to_some_var. (The * in front of ptr_to_some_var is the way C declares ptr_to_some_var as a pointer to an integer, rather than just an integer.) some_var = 42; Let some_var take the value 42. /* 3 */
Pointer types
49
ptr_to_some_var = &some_var; /* 4 */ Let ptr_to_some_var take the address of the variable some_var as its value. (Notice that only now does ptr_to_some_var become a pointer to the particular variable some_var before this, it was merely a pointer that could point to any integer variable.) printf ("%d\n\n", *ptr_to_some_var); /* 5 */ Print out the contents of the location pointed to by ptr_to_some_var. (In other words, print out some_var itself. This will print just 42. Accessing what a pointer points to in this way is called dereferencing the pointer, because the pointer is considered to be referencing the variable.) *ptr_to_some_var = 56; /* 6 */ Let the contents of the location pointed to by ptr_to_some_var equal 56. (In the context of the other statements, this is the same as the more direct statement some_var = 56;.) A subtle point: dont confuse the usage of asterisks in code like examples 2 and 6 above. Using an asterisk in a declaration, as in example 2, declares the variable to be a pointer, while using it on the left-hand side of an assignment, as in example 6, dereferences a variable that is already a pointer, enabling you to access the variable to which the pointer is pointing.
50
Chapter 9: Pointers
{ int *integer_ptr; /* Declare an integer pointer called integer_ptr */ float *float_ptr; /* Declare a floating-point pointer called float_ptr */ int my_int = 17; /* Declare an integer variable called my_int and assign it the value 17 */ float my_float = 23.5; /* Declare a floating-point variable called my_float and assign it the value 23.5 */ integer_ptr = &my_int; /* Assign the address of the integer variable my_int to the integer pointer variable integer_ptr */ float_ptr = &my_float; /* Assign the address of the floating-point variable my_float to the floating-point pointer variable float_ptr */ *integer_ptr = *float_ptr; /* Assign the contents of the location pointed to by the floating-point pointer variable float_ptr to the location pointed to by the integer pointer variable integer_ptr (the value assigned will be truncated) */ printf ("%d\n\n", *integer_ptr); /* Print the contents of the location pointed to by the integer pointer variable integer_ptr */ return 0; /* Return a value of 0, indicating successful execution, to the operating system */ } There will still be times when you will want to convert one type of pointer into another. For example, GCC will give a warning if you try to pass oat pointers to a function that accepts integer pointers. Not treating pointer types interchangeably will also help you understand your own code better. To convert pointer types, use the cast operator. (See Section 5.4 [The cast operator], page 22.) As you know, the general form of the cast operator is as follows: (type) variable Here is the general form of the cast operator for pointers: (type *) pointer variable Here is an actual example:
Variable parameters
51
int *my_integer_ptr; long *my_long_ptr; my_long_ptr = (long *) my_integer_ptr; This copies the value of the pointer my_integer to the pointer my_long_ptr. The cast operator ensures that the data types match. (See Chapter 20 [Data structures], page 205, for more details on pointer casting.)
52
Chapter 9: Pointers
int num1, num2; get_values (&num1, &num2); printf ("num1 = %d and num2 = %d\n\n", num1, num2); return 0; }
void get_values (int *num_ptr1, int *num_ptr2) { *num_ptr1 = 10; *num_ptr2 = 20; } The output from this program reads: num1 = 10 and num2 = 20 Note that we do use a return command in this example in the main function. Remember, main must always be declared of type int and should always return an integer value. (See Chapter 22 [Style], page 227.) When you use value parameters, the formal parameters (the parameters in the function being called) are mere copies of the actual parameters (the parameters in the function call). When you use variable parameters, on the other hand, you are passing the addresses of the variables themselves. Therefore, in the program above, it is not copies of the variables num1 and num2 that are passed to get_values, but the addresses of their actual memory locations. This information can be used to alter the variables directly, and to return the new values.
53
get_values (&num1, &num2); Evaluate the function get_values, passing to it the addresses at which the variables num1 and num2 are stored.. The function get_values is dened like this: void get_values (int *num_ptr1, int *num_ptr2) Dene the function get_values. It returns a void value (so it operates only via side eects on the variable parameters it is passed). It takes two parameters, both of type int *. The rst parameter is called num_ptr1 and is a pointer to an integer value, and the second parameter is called num_ptr2 and is also a pointer to an integer value. When this function is called, it must be passed the addresses of variables, not the variables themselves. Remember that declaring a variable with an asterisk (*) before it means declare this variable to be a pointer, so the formal parameters of get_values are integer pointers. The parameters must be declared this way, because the main function sends the addresses of num1 and num2 that is, by the time the get_values function receives the parameters, they are already pointers hence their names in get_values: num_ptr1 and num_ptr2, rather than num1 and num2. In eect, we are matching up the data types of num1 and num2 with those of num_ptr1 and num_ptr2, respectively, when we prex num1 and num2 with ampersands while passing them, and prex num_ptr1 and num_ptr2 with asterisks in the parameter list of the function get_values. We do not have to write num_ptr1 = &num1; and num_ptr2 = &num2; the calling convention does that for us. Important! This is a general rule in C: when you pass actual parameters as pointers using ampersands (e.g. &num1, the address of the variable num1), you must use asterisks to declare as pointers the corresponding formal parameters in the function to which you pass them, (e.g. int *num_ptr1, the contents of the location pointed to by num_ptr1).
54
Chapter 9: Pointers
int main() { int height,width; height = 4; width = 5; scale_dimensions (&height, &width); printf ("Scaled height = %d\n", height); printf ("Scaled width = %d\n", width); return 0; }
void scale_dimensions (int *height_ptr, int *width_ptr) { int hscale = 3; /* scale factors */ int wscale = 5; *height_ptr = *height_ptr * hscale; *width_ptr = *width_ptr * wscale; }
if
55
10 Decisions
Testing and Branching. Making conditions. Until now, our code examples have been linear: control has owed in one direction from start to nish. In this chapter, we will examine ways to enable code to make decisions and to choose among options. You will learn how to program code that will function in situations similar to the following: If the user hits the jackpot, print a message to say so: Youve won! If a bank balance is positive, then print C for credit; otherwise, print D for debit. If the user has typed in one of ve choices, then do something that corresponds to the choice, otherwise display an error message. In the rst case there is a simple do or dont choice. In the second case, there are two choices. The nal case contains several possibilities. C oers four main ways of coding decisions like the ones above. They are listed below. if... if (condition) { do something } if...else... if (condition) { do something } else { do something else } ...?...:... (condition) ? do something : do something else; switch switch { case case case } (condition) rst case : do rst thing second case : do second thing third case : do third thing
10.1 if
The rst form of the if statement is an all-or-nothing choice: if some condition is satised, do something; otherwise, do nothing. For example:
56
if (condition) statement; or if (condition) { compound statement } In the second example, instead of a single statement, a whole block of statements is executed. In fact, wherever you can place a single statement in C, you can place a compound statement instead: a block of statements enclosed by curly brackets. A condition is usually an expression that makes some sort of comparison. It must be either true or false, and it must be enclosed in parentheses: (...). If the condition is true, then the statement or compound statement following the condition will be executed; otherwise, it will be ignored. For example: if (my_num == 0) { printf ("The number is zero.\n"); } if (my_num > 0) { printf ("The number is positive.\n"); } if (my_num < 0) { printf ("The number is negative.\n"); } The same code could be written more compactly in the following way: if (my_num == 0) printf ("The number is zero.\n"); if (my_num > 0) printf ("The number is positive.\n"); if (my_num < 0) printf ("The number is negative.\n"); It is often a good idea stylistically to use curly brackets in an if statement. It is no less ecient from the compilers viewpoint, and sometimes you will want to include more statements later. It also makes if statements stand out clearly in the code. However, curly brackets make no sense for short statements such as the following: if (my_num == 0) my_num++; The if command by itself permits only limited decisions. With the addition of else in the next section, however, if becomes much more exible.
Nested if statements
57
} else { compound statement } As with the bare if statement, there is a simplied version of the if... else... statement without code blocks: if (condition) statement else statement; When the if... else... is executed, the condition in parentheses is evaluated. If it is true, then the rst statement or code block is executed; otherwise, the second statement or code block is executed. This can save unnecessary tests and make a program more ecient: if (my_num > 0) { printf ("The number is positive."); } else { printf ("The number is zero or negative."); } It is not necessary to test my_num in the second block because that block is not executed unless my_num is not greater than zero.
58
than two, do what is in the rst code block. Inside it, my_num is always greater than two; otherwise the program would never have arrived there. Now, if my_num is also less than four, then do what is inside the second code block. Inside that block, my_num is always less than four. We also know it is more than two, since the whole of the second test happens inside the block where thats true. So, assuming my_num is an integer, it must be three. In short, there are two ways of making compound decisions in C. You make nested tests, or you can use the comparison operators &&, ||, and so on. In situations where sequences of comparison operators become too complex, nested tests are often a more attractive option. Consider the following example: if (i > 2) { /* i is greater than 2 here! */ } else { /* i is less than or equal to 2 here! */ } The code blocks in this example provide safe zones wherein you can rest assured that certain conditions hold. This enables you to think and code in a structured way. You can nest if statements in multiple levels, as in the following example: #include <stdio.h> int main () { int grade; printf("Type in your grade: "); scanf ("%d", &grade); if (grade < 10) { printf ("Man, youre lame! Just go away.\n"); } else { if (grade < 65) { printf ("You failed.\n"); } else { printf ("You passed!\n"); if (grade >= 90) { printf ("And you got an A!\n"); } else
59
60
case constant3 : statement3; break; /* optional */ ... } The integer or character expression in the parentheses is evaluated, and the program checks whether it matches one of the constants in the various cases listed. If there is a match, the statement following that case will be executed, and execution will continue until either a break statement or the closing curly bracket of the entire switch statement is encountered. One of the cases is called default. Statements after the default case are executed when none of the other cases are satised. You only need a default case if you are not sure you are covering every case with the ones you list. Here is an example program that uses the switch statement to translate decimal digits into Morse code:
int main () { int digit; printf ("Enter any digit in the range 0 to 9: "); scanf ("%d", &digit); if ((digit < 0) || (digit > 9)) { printf ("Your number was not in the range 0 to 9.\n"); } else { printf ("The Morse code of that digit is "); morse (digit); } return 0; }
void morse (int digit) /* print out Morse code */ { switch (digit) { case 0 : printf ("-----");
Example Listing
61
break; case 1 : break; case 2 : break; case 3 : break; case 4 : break; case 5 : break; case 6 : break; case 7 : break; case 8 : break; case 9 :
printf (".----"); printf ("..---"); printf ("...--"); printf ("....-"); printf ("....."); printf ("-...."); printf ("--..."); printf ("---.."); printf ("----.");
} printf ("\n\n"); } The morse function selects one of the printf statements with switch, based on the integer expression digit. After every case in the switch, a break statement is used to jump switch statements closing bracket }. Without break, execution would fall through to the next case and execute its printf statement. Here is an example of using fallthrough in a constructive way. The function yes accepts input from the user and tests whether it was y or Y. (The getchar function is from the standard library and reads a character of input from the terminal. See Section 16.3.1 [getchar], page 144.) #include <stdio.h> int main () { printf ("Will you join the Free Software movement? "); if (yes()) { printf("Great! The price of freedom is eternal vigilance!\n\n"); } else { printf("Too bad. Maybe next life...\n\n"); } return 0; }
int yes()
62
{ switch (getchar()) { case y : case Y : return 1; default : return 0; } } If the character is y, then the program falls through and meets the statement return 1. If there were a break statement after case y, then the program would not be able to reach case Y unless an actual Y were typed. Note: The return statements substitute for break in the above code, but they do more than break out of switch they break out of the whole function. This can be a useful trick.
while
63
11 Loops
Controlling repetitive processes. Nesting loops Loops are a kind of C construct that enable the programmer to execute a sequence of instructions over and over, with some condition specifying when they will stop. There are three kinds of loop in C: while do . . . while for
11.1 while
The simplest of the three is the while loop. It looks like this: while (condition) { do something } The condition (for example, (a > b)) is evaluated every time the loop is executed. If the condition is true, then statements in the curly brackets are executed. If the condition is false, then those statements are ignored, and the while loop ends. The program then executes the next statement in the program. The condition comes at the start of the loop, so it is tested at the start of every pass, or time through the loop. If the condition is false before the loop has been executed even once, then the statements inside the curly brackets will never be executed. (See Section 11.2 [do...while], page 64, for an example of a loop construction where this is not true.) The following example prompts the user to type in a line of text, and then counts all the spaces in the line. The loop terminates when the user hits the RET key and then prints out the number of spaces. (See Section 16.3.1 [getchar], page 144, for more information on the standard library getchar function.) #include <stdio.h> int main() { char ch; int count = 0; printf ("Type in a line of text.\n"); while ((ch = getchar()) != \n) { if (ch == ) { count++;
64
int main() { char ch; printf ("Enter a string with a quoted substring:\n\n"); do
for
65
void get_substring() { char ch; do { ch = getchar(); putchar(ch); if (ch == \n) { printf ("\nString was not closed "); printf ("before end of line.\n"); break; } } while (ch != "); printf ("\n\n"); }
11.3 for
The most complex loop in C is the for loop. The for construct, as it was developed in earlier computer languages such as BASIC and Pascal, was intended to behave in the following way: For all values of variable from value1 to value2, in steps of value3, repeat the following sequence of commands. . . The for loop in C is much more versatile than its counterpart in those earlier languages. The for loop looks like this in C: for (initialization; condition; increment) { do something;
66
} In normal usage, these expressions have the following signicance. initialization This is an expression that initializes the control variable, or the variable tested in the condition part of the for statement. (Sometimes this variable is called the loops index.) The initialization part is only carried out once before the start of the loop. Example: index = 1. condition This is a conditional expression that is tested every time through the loop, just as in a while loop. It is evaluated at the beginning of every loop, and the loop is only executed if the expression is true. Example: index <= 20. increment This is an expression that is used to alter the value of the control variable. In earlier languages, this usually meant adding or subtracting 1 from the variable. In C, it can be almost anything. Examples: index++, index *= 20, or index /= 2.3. For example, the following for loop prints out the integers from 1 to 10: int my_int; for (my_int = 1; my_int <= 10; my_int++) { printf ("%d ", my_int); printf("\n"); } The following example prints out all prime numbers between 1 and the macro value MAX_INT. (A prime numbers is a number that cannot be divided by any number except 1 and itself without leaving a remainder.) This program checks whether a number is a prime by dividing it by all smaller integers up to half its size. (See Chapter 12 [Preprocessor directives], page 73, for more information on macros.) #include <stdio.h> #define MAX_INT #define TRUE #define FALSE int main () { int poss_prime; for (poss_prime = 2; poss_prime <= MAX_INT; poss_prime++) { if (prime(poss_prime)) { printf ("%d ", poss_prime); } } 500 1 0
67
printf("\n\n"); return 0; }
for (poss_factor = 2; poss_factor <= poss_prime/2; poss_factor++) { if (poss_prime % poss_factor == 0) { return (FALSE); } } return (TRUE); } The program should print the following sequence of integers: 2 3 5 7 11 13 17 19 23 29 31 37 41 43 47 53 59 61 67 71 101 103 107 109 113 127 131 137 139 149 151 157 163 167 193 197 199 211 223 227 229 233 239 241 251 257 263 269 293 307 311 313 317 331 337 347 349 353 359 367 373 379 409 419 421 431 433 439 443 449 457 461 463 467 479 487
73 79 83 89 173 179 181 271 277 281 383 389 397 491 499
68
Consider the following loop: for (my_int = 2; my_int <= 1000; my_int = my_int * my_int) { printf ("%d ", my_int); } This loop begins with 2, and each time through the loop, my_int is squared. Heres another odd for loop: char ch; for (ch = *; ch != \n; ch = getchar()) { /* do something */ } This loop starts o by initializing ch with an asterisk. It checks that ch is not a linefeed character (which it isnt, the rst time through), then reads a new value of ch with the library function getchar and executes the code inside the curly brackets. When it detects a line feed, the loop ends. It is also possible to combine several increment parts in a for loop using the comma operator ,. (See Section 18.2 [The comma operator], page 189, for more information.) #include <stdio.h> int main() { int up, down; for (up = 0, down=10; up < down; up++, down--) { printf("up = %d, down= %d\n",up,down); } return 0; } The example above will produce the following output: up = 0, down= 10 up = 1, down= 9 up = 2, down= 8 up = 3, down= 7 up = 4, down= 6 One feature of the for loop that unnerves some programmers is that even the value of the loops conditional expression can be altered from within the loop itself: int index, number = 20; for (index = 0; index <= number; index++) { if (index == 9) {
69
number = 30; } } In many languages, this technique is syntactically forbidden. Not so in the exible language C. It is rarely a good idea, however, because it can make your code confusing and hard to maintain.
70
int returner (int foo, int bar) { while (foo <= 1000) { if (foo > bar) { return (foo); } foo++; } return foo; } The function returner contains a while loop that increments the variable foo and tests it against a value of 1000. However, if at any point the value of foo exceeds the value of the variable bar, the function will exit the loop, immediately returning the value of foo to the calling function. Otherwise, when foo reaches 1000, the function will increment foo one more time and return it to main. Because of the values it passes to returner, the main function will rst print a value of 11, then 1001. Can you see why?
71
72
5. Write a program to get 10 numbers from the user and add them together. 6. Rewrite the nested loops example to print a square with while loops instead of for loops.
Macros
73
12 Preprocessor directives
Making programming versatile. GCC, the GNU Compiler Collection, contains a C preprocessor. A preprocessor is a program that examines C code before it is compiled and manipulates it in various ways. There are two main uses of a preprocessor. One is to include external les, such as header les. The other is to dene macros, which are names (possibly with arguments) that are expanded by the preprocessor into pieces of text or C code. Macros that are expanded into text are usually displayed to the user, but macros that are expanded into C code are executed with the rest of the C code that surrounds them.
#if . . . #endif The #if directive is followed by an expression on the same line. The lines of code between #if and #endif will be compiled only if the expression is true. This is called conditional compilation. #else This is part of an #if preprocessor statement and works in the same way with #if that the regular C else does with the regular if.
#line constant lename This causes the compiler to act as though the next line is line number constant and is part of the le lename. Mainly used for debugging. #error This forces the compiler to abort. Also intended for debugging.
Below is an example of conditional compilation. The following code displays 23 to the screen.
74
#include <stdio.h> #define CHOICE 500 int my_int = 0; #if (CHOICE == 500) void set_my_int() { my_int = 23; } #else void set_my_int() { my_int = 17; } #endif int main () { set_my_int(); printf("%d\n", my_int); return 0; }
12.2 Macros
Macros can make long, ungainly pieces of code into short words. The simplest use of macros is to give constant values meaningful names. For example: #define MY_PHONE 5551234 This allows the programmer to use the word MY_PHONE to mean the number 5551234. In this case, the word is longer than the number, but it is more meaningful and makes a program read more naturally. It can also be centralised in a header le, where it is easily changed; this eliminates tedious search-and-replace procedures on code if the value appears frequently in the code. It has been said, with some humorous exaggeration, that the only values that should appear naked in C code instead of as macros or variables are 1 and 0. The dierence between dening a macro for 5551234 called MY_PHONE and declaring a long integer variable called my_phone with the same value is that the variable my_phone has the value 5551234 only provisionally; it can be incremented with the statement my_ phone++;, for example. In some sense, however, the macro MY_PHONE is that value, and only that value the C preprocessor simply searches through the C code before it is compiled and replaces every instance of MY_PHONE with 5551234. Issuing the command MY_PHONE++; is no more or less sensible than issuing the command 5551234++;. Any piece of C code can be made into a macro, Macros are not merely constants referred to at compile time, but are strings that are physically replaced with their values by the preprocessor before compilation. For example:
Macros
75
#define SUM 1 + 2 + 3 + 4
would allow SUM to be used instead of 1 + 2 + 3 + 4. Usually, this would equal 10, so that in the statement example1 = SUM + 10;, the variable example1 equals 20. Sometimes, though, this macro will be evaluated dierently; for instance, in the statement example2 = SUM * 10;, the variable example2 equals 46, instead of 100, as you might think. Can you gure out why? Hint: it has to do with the order of operations.
The quotation marks in the following macro allow the string to be called by the identier SONG instead of typing it out over and over. Because the text 99 bottles of beer on the wall... is enclosed by double quotation marks, it will never be interpreted as C code.
Macros cannot dene more than a single line, but they can be used anywhere except inside strings. (Anything enclosed in string quotes is assumed to be untouchable by the compiler.)
Some macros are dened already in the le stdio.h, for example, NULL (the value 0).
There are a few more directives for macro denition besides #define:
#undef
#ifdef
This is a kind of #if that is followed by a macro name. If that macro is dened then this directive is true. #ifdef works with #else in the same way that #if does.
#ifndef
This is the opposite of #ifdef. It is also followed by a macro name. If that name is not dened then this is true. It also works with #else.
Here is a code example using some macro denition directives from this section, and some conditional compilation directives from the last section as well.
76
#include <stdio.h> #define CHOICE 500 int my_int = 0; #undef CHOICE #ifdef CHOICE void set_my_int() { my_int = 23; } #else void set_my_int() { my_int = 17; } #endif int main () { set_my_int(); printf("%d\n", my_int); return 0; } The above code example displays 17 on the screen.
77
function, however, is speed. No time is taken up in passing control to a new function, because control never leaves the home function; the macro just makes the function a bit longer. A second caveat: function calls cannot be used as macro parameters. The following code will not work: ABS (cos(36)) Here is an example of macro functions in use: #include <stdio.h> #define #define #define #define #define #define #define STRING1 STRING2 EXPRESSION1 EXPRESSION2 ABS(x) MAX(a,b) BIGGEST(a,b,c) () (STRING1); (STRING2); ("%d\n", EXPRESSION1); ("%d\n", EXPRESSION2); ("%d\n", ABS(-5)); ("Biggest of 1, 2, and 3 is %d\n", BIGGEST(1,2,3)); "A macro definition\n" "must be all on one line!\n" 1 + 2 + 3 + 4 EXPRESSION1 + 10 ((x) < 0) ? -(x) : (x) (a < b) ? (b) : (a) (MAX(a,b) < c) ? (c) : (MAX(a,b))
return 0; } The output from the code example above is as follows: A macro definition must be all on one line! 10 20 5 Biggest of 1, 2, and 3 is 3
78
certain variables (how many bits they contain) aects every aspect of its operation, even determining how long an Emacs text le can be.
Each piece of code below is prexed with the name of the le from which the code is taken, and followed by a note on some interesting features of the macros dened.
emacs/src/config.h
/* Note that lisp.h uses this in a preprocessor conditional, so it would not work to use sizeof. That being so, we do all of them without sizeof, for uniformitys sake. */ #ifndef BITS_PER_INT #define BITS_PER_INT 32 #endif #ifndef BITS_PER_LONG #ifdef _LP64 #define BITS_PER_LONG 64 #else #define BITS_PER_LONG 32 #endif #endif In the middle of this set of macros, from config.h, the Emacs programmer used the characters /* and */ to create an ordinary C comment. C comments can be interspersed with macros freely. The macro BITS_PER_INT is dened here to be 32 (but only if it is not already dened, thanks to the #ifndef directive). The Emacs code will then treat integers as having 32 bits. (See Section 5.1 [Integer variables], page 19.) The second chunk of macro code in this example checks to see whether BITS_PER_LONG is dened. If it is not, but _LP64 is dened, it denes BITS_PER_LONG to be 64, so that all long integers will be treated as having 64 bits. (_LP64 is a GCC macro that is dened on 64-bit systems. It stands for longs and pointers are 64 bits.) If _LP64 is not present, the code assumes it is on a 32-bit system and denes BITS_PER_LONG to be 32. emacs/src/lisp.h
Questions
79
/* These are default choices for the types to use. */ #ifdef _LP64 #ifndef EMACS_INT #define EMACS_INT long #define BITS_PER_EMACS_INT BITS_PER_LONG #endif #ifndef EMACS_UINT #define EMACS_UINT unsigned long #endif #else /* not _LP64 */ #ifndef EMACS_INT #define EMACS_INT int #define BITS_PER_EMACS_INT BITS_PER_INT #endif #ifndef EMACS_UINT #define EMACS_UINT unsigned int #endif #endif This set of macros, from lisp.h, again checks to see whether _LP64 is dened. If it is, it denes EMACS_INT as long (if it is not already dened), and BITS_PER_EMACS_INT to be the same as BITS_PER_LONG, which was dened in config.h, above. It then denes EMACS_UINT to be an unsigned long, if it is not already dened. If _LP64 is not dened, it is assumed we are on a 32-bit system. EMACS_INT is dened to be an int if it is not already dened, and EMACS_UINT is dened to be an unsigned int if it is not already dened. Again, note that the programmer has freely interspersed a comment with the preprocessor code. emacs/src/lisp.h /* These values are overridden by the m- file on some machines. */ #ifndef VALBITS #define VALBITS (BITS_PER_EMACS_INT - 4) #endif Here is another example from lisp.h. The macro VALBITS, which denes another size of integer internal to Emacs, is dened as four less than BITS_PER_EMACS_INT that is, 60 on 64-bit systems, and 28 on 32-bit systems. emacs/src/lisp.h #ifndef XINT /* Some machines need to do this differently. */ #define XINT(a) ((EMACS_INT) (((a) << (BITS_PER_EMACS_INT - VALBITS)) \ >> (BITS_PER_EMACS_INT - VALBITS))) #endif The interesting feature of the XINT macro above is not only that it is a function, but that it is broken across multiple lines with the backslash character (\). The GCC preprocessor simply deletes the backslash, deletes the preceding whitespace from the next line, and appends it where the backslash was. In this way, it is possible to treat long, multi-line macros as though they are actually on a single line. (See Chapter 18 [Advanced operators], page 185, for more information on the the advanced operators << and >>.)
80
12.4 Questions
1. Dene a macro called BIRTHDAY which equals the day of the month upon which your birthday falls. 2. Write an instruction to the preprocessor to include the math library math.h. 3. A macro is always a number. True or false?
Header les
81
13 Libraries
Plug-in C expansions. Header les. The core of the C language is small and simple, but special functionality is provided in the form of external libraries of ready-made functions. Standardized libraries make C code extremely portable, or easy to compile on many dierent computers. Libraries are les of ready-compiled code that the compiler merges, or links, with a C program during compilation. For example, there are libraries of mathematical functions, string handling functions, and input/output functions. Indeed, most of the facilities C oers are provided as libraries. Some libraries are provided for you. You can also make your own, but to do so, you will need to know how GNU builds libraries. We will discuss that later. (See Section 17.6 [Building a library], page 180.) Most C programs include at least one library. You need to ensure both that the library is linked to your program and that its header les are included in your program. The standard C library, or glibc, is linked automatically with every program, but header les are never included automatically, so you must always include them yourself. Thus, you must always include stdio.h in your program if you intend to use the standard input/output features of C, even though glibc, which contains the input/output routines, is linked automatically. Other libraries, however, are not linked automatically. You must link them to your program yourself. For example, to link the math library libm.so, type gcc -o program name program name.c -lm The command-line option to link libm.so is simply -lm, without the lib or the .so, or in the case of static libraries, .a. (See Section 13.2 [Kinds of library], page 83.) The -l option was created because the average GNU system already has many libraries, and more can be added at any time. This means that sometimes two libraries provide alternate denitions of the same function. With judicious use of the -l option, however, you can usually clarify to the compiler which denition of the function should be used. Libraries specied earlier on the command line take precedence over those dened later, and code from later libraries is only linked in if it matches a reference (function denition, macro, global variable, etc.) that is still undened. (See Section 17.4 [Compiling multiple les], page 172, for more information.) In summary, you must always do two things: link the library with a -l option to gcc (a step that may be skipped in the case of glibc). include the library header les (a step you must always follow, even for glibc).
82
le, the compiler adds the functions, data types, and other information in the header le to the list of reserved words and commands in the language. After that, you cannot use the names of functions or macros in the header le to mean anything other than what the library species, in any source code le that includes the header le. The most commonly used header le is for the standard input/output routines in glibc and is called stdio.h. This and other header les are included with the #include command at the top of a source code le. For example, #include "name.h" includes a header le from the current directory (the directory in which your C source code le appears), and #include <name.h> includes a le from a system directory a standard GNU directory like /usr/include. (The #include command is actually a preprocessor directive, or instruction to a program used by the C compiler to simplify C code. (See Chapter 12 [Preprocessor directives], page 73, for more information.) Here is an example that uses the #include directive to include the standard stdio.h header in order to print a greeting on the screen with the printf command. (The characters \n cause printf to move the cursor to the next line.) #include <stdio.h> int main () { printf ("C standard I/O file is included.\n"); printf ("Hello world!\n"); return 0; } If you save this code in a le called hello.c, you can compile this program with the following command: gcc -o hello hello.c As mentioned earlier, you can use some library functions without having to link library les explicitly, since every program is always linked with the standard C library. This is called libc on older operating systems such as Unix, but glibc (GNU libc) on GNU systems. The glibc le includes standard functions for input/output, date and time calculation, string manipulation, memory allocation, mathematics, and other language features. Most of the standard glibc functions can be incorporated into your program just by using the #include directive to include the proper header les. For example, since glibc includes the standard input/output routines, all you need to do to be able to call printf is put the line #include <stdio.h> at the beginning of your program, as in the example that follows. Note that stdio.h is just one of the many header les you will eventually use to access glibc. The GNU C library is automatically linked with every C program, but you will eventually need a variety of header les to access it. These header les are not included in your code automatically you must include them yourself!
Kinds of library
83
#include <stdio.h> #include <math.h> int main () { double x, y; y = sin (x); printf ("Math library ready\n"); return 0; } However, programs that use a special function outside of glibc including mathematical functions that are nominally part of glibc, such as function sin in the example above! must use the -l option to gcc in order to link the appropriate libraries. If you saved this code above in a le called math.c, you could compile it with the following command: gcc -o math math.c -lm The option -lm links in the library libm.so, which is where the mathematics routines are actually located on a GNU system. To learn which header les you must include in your program in order to use the features of glibc that interest you, consult section Table of Contents in The GNU C Library Reference Manual. This document lists all the functions, data types, and so on contained in glibc, arranged by topic and header le. (See Section 13.3 [Common library functions], page 84, for a partial list of these header les.) Note: Strictly speaking, you need not always use a system header le to access the functions in a library. It is possible to write your own declarations that mimic the ones in the standard header les. You might want to do this if the standard header les are too large, for example. In practice, however, this rarely happens, and this technique is better left to advanced C programmers; using the header les that came with your GNU system is a more reliable way to access libraries.
84
Although shared libraries seem to have every advantage over static libraries, static libraries are still useful. For example, sometimes you will wish to distribute an executable to people whose computers do not have the libraries that yours does. In that case, you might link to a static version of the libraries. This will incorporate the library functions that you need into your executable, so that it will run on systems that dont have those libraries. (It is also sometimes easier to debug a program that is linked to static libraries than one linked to shared libraries. See Section 23.5 [Introduction to GDB], page 239, for more information.) The le name for a library always starts with lib and ends with either .a (if it is static) or .so (if it is shared). For example, libm.a is the static version of the C math library, and libm.so is the shared version. As explained above, you must use the -l option with the name of a library, minus its lib prex and .a or .so sux, to link that library to your program (except the library glibc, which is always linked). For example, the following shell command creates an executable program called math from the source code le math.c and the library libm.so. gcc -o math math.c -lm The shared version of the library is always linked by default. If you want to link the static version of the library, you must use the GCC option --static. The following example links libm.a instead of libm.so. gcc -o math math.c -lm --static Type info gcc at your shell prompt for more information about GCC options.
The version of ctype.h in the /usr/include directory proper is the one that comes with glibc; the one in /usr/include/linux is a special version associated with the Linux kernel. You can specify the one you want with a full pathname inside double quotes (for example, #include "/usr/include/linux/ctype.h"), or you can use the -I option of gcc to force GCC to search a set of directories in a specic order. See Section 17.6 [Building a library], page 180, for more information.)
Character handling
85
iscntrl
isdigit isgraph
86
toupper
Converts a character into its upper-case counterpart. Does not aect characters which are already in upper case.
/********************************************************/ /* */ /* Demonstration of character utility functions */ /* */ /********************************************************/ #include <stdio.h> #include <ctype.h> #define allchars ch = 0; isascii(ch); ch++ /* A criminally long main program! */
printf ("\n\nVALID CHARACTERS FROM isgraph:\n\n"); for (allchars) { if (isgraph(ch)) { printf ("%c ",ch); } } printf ("\n\nVALID CHARACTERS FROM isalnum:\n\n"); for (allchars) { if (isalnum(ch)) { printf ("%c ",ch); } } printf ("\n\nVALID CHARACTERS FROM isalpha:\n\n"); for (allchars) { if (isalpha(ch)) { printf ("%c ",ch); } } printf ("\n\nVALID CHARACTERS FROM isupper:\n\n"); for (allchars) { if (isupper(ch))
Character handling
87
{ printf ("%c ",ch); } } printf ("\n\nVALID CHARACTERS FROM islower:\n\n"); for (allchars) { if (islower(ch)) { printf ("%c ",ch); } } printf ("\n\nVALID CHARACTERS FROM isdigit:\n\n"); for (allchars) { if (isdigit(ch)) { printf ("%c ",ch); } } printf ("\n\nVALID CHARACTERS FROM isxdigit:\n\n"); for (allchars) { if (isxdigit(ch)) { printf ("%c ",ch); } } printf ("\n\nVALID CHARACTERS FROM ispunct:\n\n"); for (allchars) { if (ispunct(ch)) { printf ("%c ",ch); } } printf ("\n\n"); return 0; } The output of the above code example is as follows: VALID CHARACTERS FROM isgraph: ! " # $ % & ( ) * + , - . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @ A B C D
88
E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ] ^ _ a b c d e f g h i j k l m n o p q r s t u v w x y z { | } ~ VALID CHARACTERS FROM isalnum: 0 1 2 3 4 5 6 7 8 9 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z VALID CHARACTERS FROM isalpha: A B C D E F G H I J K L M N O P Q R S T U V W X Y Z a b c d e f g h i j k l m n o p q r s t u v w x y z VALID CHARACTERS FROM isupper: A B C D E F G H I J K L M N O P Q R S T U V W X Y Z VALID CHARACTERS FROM islower: a b c d e f g h i j k l m n o p q r s t u v w x y z VALID CHARACTERS FROM isdigit: 0 1 2 3 4 5 6 7 8 9 VALID CHARACTERS FROM isxdigit: 0 1 2 3 4 5 6 7 8 9 A B C D E F a b c d e f VALID CHARACTERS FROM ispunct: ! " # $ % & ( ) * + , - . / : ; < = > ? @ [ \ ] ^ _ { | } ~
Mathematical functions
89
Returns the unsigned value of the parameter in brackets. This function is a macro; see fabs for a proper function version. Returns the arccosine (or inverse cosine) of the parameter, which must lie between -1.0 and +1.0 inclusive. (The result is always in radians.) Returns the arcsine (or inverse sine) of the parameter, which must lie between -1.0 and +1.0 inclusive. (The result is always in radians.) Returns the arctangent (or inverse tangent) of the parameter. (The result is always in radians.) This is a special function for calculating the inverse tangent of the second parameter divided by the rst. atan2 will nd the result more accurately than atan will. result = atan2 (x, y); result = atan2 (x, 3.14); Returns the ceiling for the parameter: that is, the integer just above it. In eect, rounds the parameter up. Returns the cosine of the parameter in radians. (The parameter is also assumed to be specied in radians.) Returns the hyperbolic cosine of the parameter. Returns the exponential function of the parameter (i.e. e to the power of the parameter). Returns the absolute or unsigned value of the parameter in brackets. This is the version that is a proper function; see abs if you want one that is a macro. Returns the oor for the parameter: that is, the integer just below it. In eect, rounds the parameter down to the nearest integer value, i.e. truncates it. Returns the natural logarithm of the parameter. The parameter used must be greater than zero, but does not have to be declared as unsigned. Returns the base 10 logarithm of the parameter. The parameter used must be greater than zero, but does not have to be declared as unsigned. Returns the rst parameter raised to the power of the second. result = pow (x,y); /*raise x to the power y */ result = pow (x,2); /* square x */ Returns the sine of the parameter in radians. (The parameter is also assumed to be specied in radians.) Returns the hyperbolic sine of the parameter. (Pronounced shine or sinch.) Returns the positive square root of the parameter. Returns the tangent of the parameter in radians. (The parameter is also assumed to be specied in radians.) Returns the hyperbolic tangent of the parameter.
90
Here is a code example that uses a few of the math library routines listed above. #include <stdio.h> #include <math.h> int main() { double my_pi; my_pi = 4 * atan(1.0); /* Print the value of pi we just calculated, to 32 digits. */ printf ("my_pi = %.32f\n", my_pi); /* Print value of pi from math library, to 32 digits. */ printf ("M_PI = %.32f\n", M_PI); return 0; } If you save the above example as pi.c, you will have to enter a command such as the one below to compile it. gcc pi.c -o pi -lm When you compile and run the code example, it should print the following results: my_pi = 3.14159265358979311599796346854419 M_PI = 3.14159265358979311599796346854419
Arrays
91
14 Arrays
Rows and tables of storage. Suppose you have a long list of numbers, but you dont want to assign them to variables individually. For example, you are writing a simple program for a restaurant to keep a list of the amount each diner has on his or her tab, but you dont want to go through the tedium of writing a list like the following: float alfies_tab, bettys_tab, charlies_tab . . . ; alfies_tab = 88.33; bettys_tab = 17.23; charlies_tab = 55.55; etc. A list like that could run to hundreds or thousands of entries, and for each diner youd have to write special-case code referring to every diners data individually. No, what you really want is a single table in which you can nd the tab corresponding to a particular diner. You can then look up the tab of the diner with dining club card number 7712 in row number 7712 of the table much more easily. This is why arrays were invented. Arrays are a convenient way to group many variables under a single variable name. They are like pigeonholes, with each compartment storing a single value. Arrays can be one-dimensional like a list, two-dimensional like a chessboard, or three-dimensional like an apartment building in fact, they can have any arbitrary dimensionality, including ones humans cannot visualise easily. An array is dened using square brackets [...]. For example: an array of three integers called my_list would be declared thus: int my_list[3]; This statement would cause space for three adjacent integers to be created in memory, as in the diagram below. Notice that there is no space between the name of the array above (my_array) and the opening square bracket [. -----------------------------------my_list: | | | | -----------------------------------The number in the square brackets of the declaration is referred to as the subscript of the array, and it must be an integer greater than or equal to zero. The three integer pigeonholes in the above array are called its locations, and the values lling them are called the arrays elements. The position of an element in the array is called its index (the plural is indices). In the following example, 5, 17, and 23 are the arrays elements, and 0, 1, and 2 are its corresponding indices. Notice also that although we are creating space for three integers, arrays in C are zerobased, so the indices of the array run (0, 1, 2). If arrays in C were one-based, the indices would run (1, 2, 3).
92
int my_list[3]; my_list[0] = 5; my_list[1] = 17; my_list[2] = 23; The above example would result in an array that looks like the following diagram. (Of course, an array is merely an arrangement of bytes in the computers memory, so it does not look like much of anything, literally speaking.) index: 0 1 2 -----------------------------------my_list: | 5 | 17 | 23 | -----------------------------------Note that every element in an array must be of the same type, for example, integer. It is not possible in C to have arrays that contain multiple data types. However, if you want an array with multiple data types, you might instead be able to use multiple arrays of dierent data types that contain the same number of elements. For example, to continue our restaurant tab example above, one array, diner_names might contain a list of the names of the diners. If you are looking for a particular diner, say Xavier Nougat, you might nd that the index of his name in diner_names is 7498. If you have programmed an associated oating-point array called diner_tabs, you might look up element 7498 in that array and nd that his tab is $99.34.
93
When you declare an array, the computer allocates a block of memory for it, but the block contains garbage (random values). Therefore, before using an array, you should initialise it. It is usually a good idea to set all elements in the array to zero. The easiest way to initialise an array is with a for loop. The following example loops through every element in the array my_array and sets each to zero. Remember, because arrays in C are zero-based, the indices of the array my_array in the example below run 0 through 9, rather than 1 through 10. The eect is the same, however: an array of ARRAY_SIZE (that is, 10) elements. #include <stdio.h> #define ARRAY_SIZE 10 int main () { int index, my_array[ARRAY_SIZE]; for (index = 0; index < ARRAY_SIZE; index++) { my_array[index] = 0; printf ("my_array[%d] = %d\n", index, my_array[index]); } printf("\n"); return 0; } The output from the above example is as follows: my_array[0] my_array[1] my_array[2] my_array[3] my_array[4] my_array[5] my_array[6] my_array[7] my_array[8] my_array[9] = = = = = = = = = = 0 0 0 0 0 0 0 0 0 0
You can use similar code to ll the array with dierent values. The following code example is nearly identical to the one above, but the line my_array[index] = index; lls each element of the array with its own index:
94
#include <stdio.h> #define ARRAY_SIZE 5 int main () { int index, my_array[ARRAY_SIZE]; for (index = 0; index < ARRAY_SIZE; index++) { my_array[index] = index; printf ("my_array[%d] = %d\n", index, my_array[index]); } printf("\n"); return 0; } The output is as follows: my_array[0] = 0 my_array[1] = 1 my_array[2] = 2 my_array[3] = 3 my_array[4] = 4 Here is a humans-eye view of the internal representation of the array (how the array "looks" to the computer): index 0 1 2 3 4 ------------------element | 0 | 1 | 2 | 3 | 4 | ------------------You can use loops to do more than initialize an array. The next code example demonstrates the use of for loops with an array to nd prime numbers. The example uses a mathematical device called the Sieve of Erastosthenes. Erastosthenes of Cyrene discovered that one can nd all prime numbers by rst writing down a list of integers from 2 (the rst prime number) up to some arbitrary number, then deleting all multiples of 2 (which are by denition not prime numbers), nding the next undeleted number after 2 (which is 3), deleting all its multiples, nding the next undeleted number after that (5), deleting all its multiples, and so on. When you have nished this process, all numbers that remain are primes. The following code example creates a Sieve of Erastosthenes for integers up to 4999, initializes all elements with 1, then deletes all composite (non-prime) numbers by replacing the elements that have an index equal to the composite with the macro DELETED, which equals 0. #include <stdio.h> #define ARRAY_SIZE 5000 #define DELETED 0 int sieve[ARRAY_SIZE];
95
fill_sieve () { int index; for (index = 2; index < ARRAY_SIZE; index++) sieve[index] = 1; }
delete_nonprimes () { int index; for (index = 2; index < ARRAY_SIZE; index++) { if (sieve[index] != DELETED) delete_multiples_of_prime (index); } }
for (index = prime * multiplier; index < ARRAY_SIZE; index = prime * multiplier++) sieve[index] = DELETED; }
print_primes () { int index; for (index = 2; index < ARRAY_SIZE; index++) { if (sieve[index] != DELETED)
96
printf ("%d ", index); } printf("\n\n"); } Part of the output from the above program is shown below, for values up to 500. (The full output is considerably longer.) Results of Sieve of Erastosthenes: 2 3 101 193 293 409 5 7 103 197 307 419 11 13 17 19 107 109 113 199 211 223 311 313 317 421 431 433 23 29 31 37 127 131 137 227 229 233 331 337 347 439 443 449 41 43 47 53 139 149 151 239 241 251 349 353 359 457 461 463 59 61 67 71 157 163 167 257 263 269 367 373 379 467 479 487 73 79 83 89 173 179 181 271 277 281 383 389 397 491 499 ... 97 191 283 401
Suppose that you are writing a chess-playing program like GNU Chess (http://www.gnu.org/software/ A chessboard is an 8-by-8 grid. What data structure would you use to represent it? You could use an array that has a chessboard-like structure, that is, a two-dimensional array, to store the positions of the chess pieces. Two-dimensional arrays use two indices to pinpoint an individual element of the array. This is very similar to what is called algebraic notation, already commonly used in chess circles to record games and chess problems. In principle, there is no limit to the number of subscripts (or dimensions) an array can have. Arrays with more than one dimension are called multidimensional arrays. Although humans cannot easily visualize objects with more than three dimensions, representing multidimensional arrays presents no problem to computers. In practice, however, the amount of memory in a computer tends to place limits on how large an array can be. For example, a simple four-dimensional array of double-precision numbers, merely twenty elements wide in each dimension, already takes up 204 8, or 1,280,000 bytes of memory about a megabyte. (Each element of the array takes up 8 bytes, because doubles are 64 bits wide. See Section 5.1.2 [Floating point variables], page 21, for more information.) You can declare an array of two dimensions as follows: variable type array name[size1][size2] In the above example, variable type is the name of some type of variable, such as int. Also, size1 and size2 are the sizes of the arrays rst and second dimensions, respectively. Here is an example of dening an 8-by-8 array of integers, similar to a chessboard. Remember, because C arrays are zero-based, the indices on each side of the chessboard array run 0 through 7, rather than 1 through 8. The eect is the same, however: a two-dimensional array of 64 elements. int chessboard[8][8]; To pinpoint an element in this grid, simply supply the indices in both dimensions. Every element in this grid needs two indices to pin-point it. Normally, C programmers think of element 0,0 of a two-dimensional array as being the upper-left corner. The
97
computer, however, knows nothing of left and right, and for our purposes (attempting to conform to international chess notation), it makes more sense to mentally op the array vertically so that element 0,0 is the lower-left corner of the board, and 7,7 the upper-right. Thus, the rst index gives the row number for the grid and the second index gives the column number. For example, 1,0 is the square directly above the lower-left corner. Suppose that a value of 1 for an array location means a the chess king is on the space in question. To indicate the White kings usual position (that is, square a5 in algebraic chess notation or 0,4 in our zero-based integer notation), you would write this: chessboard[0][4] = 1; Since computer memory is essentially one-dimensional, with memory locations running straight from 0 up through the highest location in memory, a multidimensional array cannot be stored in memory as a grid. Instead, the array is dissected and stored in rows. Consider the following two-dimensional array. ----------row 0 | 1 | 2 | 3 | ----------row 1 | 4 | 5 | 6 | ----------row 2 | 7 | 8 | 9 | ----------Note that the numbers inside the boxes are not the actual indices of the array, which is two-dimensional and has two indices for each element, but only arbitrary placeholders to enable you to see which elements correspond in the following example. The row numbers do correspond to the rst index of the array, so they are numbered from 0 to 2 rather than 1 to 3. To the computer, the array above actually looks like this: -----------------------------------| 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -----------------------------------| row 0 | row 1 | row 2 | Another way of saying that arrays are stored by row is that the second index varies fastest. A two-dimensional array is always thought of as follows: array name[row][column] Every row stored will contain elements of many columns. The column index runs from 0 to size - 1 inside every row in the one-dimensional representation (where size is the number of columns in the array), so the column index is changing faster than the row index, as the one-dimensional representation of the array inside the computer is traversed. You can represent a three-dimensional array, such as a cube, in a similar way: variable type array name[size1][size2][size3] Arrays do not have to be shaped like squares and cubes; you can give each dimension of the array a dierent size, as follows: int non_cube[2][6][8]; Three-dimensional arrays (and higher) are stored in the same basic way as two-dimensional ones. They are kept in computer memory as a linear sequence of variables, and the last index is always the one that varies fastest (then the next-to-last, and so on).
98
Initializing arrays
99
my_array[1][2][0] my_array[1][2][1] my_array[1][2][2] my_array[2][0][0] my_array[2][0][1] my_array[2][0][2] my_array[2][1][0] my_array[2][1][1] my_array[2][1][2] my_array[2][2][0] my_array[2][2][1] my_array[2][2][2]
DONE DONE DONE DONE DONE DONE DONE DONE DONE DONE DONE DONE
Note: Although in this example we have followed the order in which indices vary inside the computer, you do not have to do so in your own code. For example, we could have switched the nesting of the innermost fastest and outermost fast loops, and every element would still have been initialized. It is better, however, to be systematic about initializing multidimensional arrays.
As mentioned above, you must initialize your arrays or they will contain garbage. There are two main ways to do so. The rst is by assigning values to array elements individually, either as shown in the example below, or with for loops. (See Section 14.2 [Arrays and for loops], page 93, above.) my_array[0] my_array[1] my_array[2] my_array[3] ... = = = = 42; 52; 23; 100;
The second method is more ecient and less tedious. It uses a single assignment operator (=) and a few curly brackets ({...}). Recall that arrays are stored by row, with the last index varying fastest. A 3 by 3 array could be initialized in the following way: int my_array[3][3] = { {10, 23, 42}, {1, 654, 0}, {40652, 22, 0} }; Here is a small program that uses the above initialization:
100
#include <stdio.h> int main() { int row, column; int my_array[3][3] = { {10, 23, 42}, {1, 654, 0}, {40652, 22, 0} }; for (row = 0; row <=2; row++) { for (column = 0; column <= 2; column++) { printf("%d\t", my_array[row][column]); } printf("\n"); } printf("\n"); return 0; } The internal curly brackets are unnecessary, but they help to distinguish the rows of the array. The following code has the same eect as the rst example: int my_array[3][3] = { 10, 23, 42, 1, 654, 0, 40652, 22, 0 }; The same array initialization could even be written this way: int my_array[3][3] = {10, 23, 42, 1, 654, 0, 40652, 22, 0}; Using any of these three array initializations, the program above will print the following text: 10 1 40652 23 654 22 42 0 0
Note 1: Be careful to place commas after every array element except the last one before a closing curly bracket (}). Be sure you also place a semicolon after the nal curly bracket of an array initializer, since here curly brackets are not delimiting a code block.
Arrays as Parameters
101
Note 2: All the expressions in an array initializer must be constants, not variables; that is, values such as 235 and q are acceptable, depending on the type of the array, but expressions such as the integer variable my_int are not.
Note 3: If there are not enough expressions in the array initializer to ll the array, the remaining elements will be set to 0 if the array is static, but will be lled with garbage otherwise.
There will be times when you want to pass an array as a parameter to a function. (For example, you might want to pass an array of numbers to a function that will sort them.)
In the following example, notice how the array my_array in main is passed to the function multiply as an actual parameter with the name my_array, but that the formal parameter in the multiply function is dened as int *the_array: that is, an integer pointer. This is the basis for much that you will hear spoken about the equivalence of pointers and arrays much that is best ignored until you have more C programming experience. The important thing to understand is that arrays passed as parameters are considered to be pointers by the functions receiving them. Therefore, they are always variable parameters, which means that other functions can modify the original copy of the variable, just as the function multiply does with the array my_array below. (See Chapter 8 [Parameters], page 41.)
102
int main() { int index; int my_array[5] = {0, 1, 2, 3, 4}; multiply (my_array, 2); for (index = 0; index < 5; index++) printf("%d ", my_array[index]); printf("\n\n"); return 0; }
void multiply (int *the_array, int multiplier) { int index; for (index = 0; index < 5; index++) the_array[index] *= multiplier; } Even though the function multiply is declared void and therefore does not return a result, it can still modify my_array directly, because it is a variable parameter. Therefore, the result of the program above is as follows: 0 2 4 6 8 If you nd the interchangeability of arrays and pointers as formal parameters in function declarations to be confusing, you can always avoid the use of pointers, and declare formal parameters to be arrays, as in the new version of the multiply function below. The result is the same. void multiply (int the_array[], int multiplier) { int index; for (index = 0; index < 5; index++) the_array[index] *= multiplier; }
103
3. When an array parameter is received by a function, does C allocate space for a local variable and copy the whole array to the new location? 4. What does it mean to say that one dimension of an array varies fastest? 5. Which dimension of an array varies fastest, the rst or the last?
104
Initializing strings
105
15 Strings
Communication using arrays. So far we have examined variables that can contain integers, oating-point numbers, and values that represent individual text characters. But what if you need a variable that can contain a sequence of text characters, such as a name in a database of diners at a restaurant, as in the examples for last chapter? Thats where strings and string variables come in. A string value is a sequence of text characters that can become a value for a string variable. Both a string value and a string variable can be referred to as a string, depending on context. In C, a string value is represented by text characters enclosed by double quotes: "This is a string value." A string can contain any character, including special control characters, such as the tab character \t, the newline character \n, the bell character \7 (which causes the terminal to beep when it is displayed), and so on. We have been using string values since we introduced the printf command early in the book. (See Chapter 3 [The form of a C program], page 9.) To cause your terminal to beep twice, include the following statement in a C program: printf("This is a string value. Beep! Beep! \7\7");
106
#include <stdio.h> #include <string.h> int main() { /* Example 1 */ char string1[] = "A string declared as an array.\n"; /* Example 2 */ char *string2 = "A string declared as a pointer.\n"; /* Example 3 */ char string3[30]; strcpy(string3, "A string constant copied in.\n"); printf (string1); printf (string2); printf (string3); return 0; } 1. char string1[] = "A string declared as an array.\n"; This is usually the best way to declare and initialize a string. The character array is declared explicitly. There is no size declaration for the array; just enough memory is allocated for the string, because the compiler knows how long the string constant is. The compiler stores the string constant in the character array and adds a null character (\0) to the end. 2. char *string2 = "A string declared as a pointer.\n"; The second of these initializations is a pointer to an array of characters. Just as in the last example, the compiler calculates the size of the array from the string constant and adds a null character. The compiler then assigns a pointer to the rst character of the character array to the variable string2. Note: Most string functions will accept strings declared in either of these two ways. Consider the printf statements at the end of the example program above the statements to print the variables string1 and string2 are identical. 3. char string3[30]; Declaring a string in this way is useful when you dont know what the string variable will contain, but have a general idea of the length of its contents (in this case, the string can be a maximum of 30 characters long). The drawback is that you will either have to use some kind of string function to assign the variable a value, as the next line of code does ( strcpy(string3, "A string constant copied in.\n");), or you will have to assign the elements of the array the hard way, character by character. (See Section 15.4 [String library functions], page 108, for more information on the function strcpy.)
String arrays
107
Suppose you want to print out a screenful of text instead of a single line. You could use one long character array, interspersed with \n characters where you want the lines to break, but you might nd it easier to use a string array. A string array is an array of strings, which, of course, are themselves arrays of characters; in eect, a string array is a two-dimensional character array. Just as there are easy methods of initializing integer arrays, oat arrays, strings, and so on, there is also an easy way of initializing string arrays. For example, here is a sample program which prints out a menu for a full application program. Thats all it does, but you might imagine that when the user chooses 3 in the full program, the application invokes the function calculate_bill we examined earlier. (See Chapter 8 [Parameters], page 41.) #include <stdio.h> char *menu[] = { " -------------------------------------- ", " | ++ MENU ++ |", " | ~~~~~~~~~~~~ |", " | (0) Edit Preferences |", " | (1) Print Charge Sheet |", " | (2) Print Log Sheet |", " | (3) Calculate Bill |", " | (q) Quit |", " | |", " | |", " | Please enter choice below. |", " | |", " -------------------------------------- " };
int main() { int line_num; for (line_num = 0; line_num < 13; line_num++) { printf ("%s\n", menu[line_num]); } return 0; } Notice that the string array menu is declared char *menu[]. This method of dening a two-dimensional string array is a combination of methods 1 and 2 for initializing strings from the last section. (See Section 15.2 [Initializing strings], page 105.) This is the most convenient method; if you try to dene menu with char menu[][], the compiler will return an unspecied bounds error. You can get around this by declaring the second subscript
108
of menu explicitly (e.g. char menu[][80]), but that necessitates you know the maximum length of the strings you are storing in the array, which is something you may not know and that it may be tedious to nd out. The elements of menu are initialized with string constants in the same way that an integer array, for example, is initialized with integers, separating each element with a comma. (See Section 14.5 [Initializing arrays], page 99.)
109
The example above attaches the contents of string2 to the current contents of string1. The array string1 then contains the string Hello, world!\n. Notice that string1 was declared to be 50 characters long, more than enough to contain the initial values of both string1 and string2. You must be careful to allocate enough space in the string variable that will receive the concatenated data; otherwise, your program is likely to crash. Again, on a GNU system, although your program wont run, nothing more drastic than an error message from the operating system is likely to occur in such a case. strcmp Compares two strings and returns a value that indicates which string comes rst alphabetically. Example: int comparison; char string1[] = "alpha"; char string2[] = "beta"; comparison = strcmp (string1, string2); printf ("%d\n", comparison); If the two strings are identical, strcmp returns 0. If the rst string passed to strcmp comes alphabetically before the second (that is, the rst string is less than the second one), strcmp returns a value less than 0. If the rst string comes alphabetically after the second one (that is, the rst string is greater than the second one), strcmp returns a value greater than zero. (Note that numbers come before letters in ASCII, and upper-case letters come before lower-case ones.) The example above prints out -1, because alpha is alphabetically less than beta. In all cases below, string1 comes alphabetically before string2, so strcmp(string1, string2) returns a negative value. string1 aaa aaa aa string2 aab aaba aaa
strcpy Copies a string into a string variable. Example: char dest_string[50]; char source_string[] = "Are we not men?"; /* Example 1 */ strcpy (dest_string, source_string); printf ("%s\n", dest_string); /* Example 2 */ strcpy (dest_string, "Are we having fun yet?"); printf ("%s\n", dest_string); The example above produces this output: Are we not men? Are we having fun yet? Notes:
110
The destination string in strcmp comes rst, then the source string. This works in exactly the opposite way from the GNU/Linux shell command, cp. You can use strcmp to copy one string variable into another (Example 1), or to copy a string constant into a string variable (Example 2). Note the use of the characters %s in the printf statements to display a string, rather than %d to display an integer or %f to display a oat. strlen Returns an integer that gives the length of a string in characters, not including the null character at the end of the string. The following example displays the number 5. int string_length char my_string[] = "fnord"; string_length = strlen (my_string); printf ("%d\n", string_length); strncat Works like strcat, but concatenates only a specied number of characters. The example below displays the string Hello, world! Bye. char string1[50] = "Hello, world! "; char string2[] = "Bye now!"; strncat (string1, string2, 3); printf ("%s\n", string1); strncmp Works like strcmp, but compares only a specied number of characters of both strings. The example below displays 0, because dogberry and dogwood are identical for their rst three characters. int comparison; char string1[] = "dogberry"; char string2[] = "dogwood"; comparison = strncmp (string1, string2, 3); printf ("%d\n", comparison); strncpy Works like strcpy, but copies only a specied number of characters. The example below displays the string Are we, because only the rst six characters of source_string are being copied into dest_string. char dest_string[50]; char source_string[] = "Are we not men?"; strncpy (dest_string, source_string, 6); printf ("%s\n", dest_string); Note: As in strcmp, the destination string in strncmp comes rst, then the source string. This works in exactly the opposite way from the GNU/Linux shell command, cp. strstr Tests whether a substring is present in a larger string. Returns a pointer to the rst occurrence of the substring in the larger string, or zero if the substring is not present. (When the substring is empty, strstr returns a pointer to the rst character of the larger string.) The example below displays foo is a substring of Got food?..
111
char string1[] = "Got food?"; char string2[] = "foo"; if (strstr (string1, string2)) printf("%s is a substring of %s.\n", string2, string1);
112
113
114
fprintf (my_stream, "Just a little hello from fprintf.\n"); close_error = fclose (my_stream); On the other hand, fopen takes a name, and returns a stream: my_stream = fopen (my_filename, "w"); This is how you map from names to streams or le descriptors: you open the le (for reading, writing, or both, or for appending), and the value returned from the open or fopen function is the appropriate le descriptor or stream. You can operate on a le either at a high level or at a low level. Operating on a le at a high level means that you are using the le at a high level of abstraction. (See Chapter 1 [Introduction], page 1, to refresh your memory about the distinction between high and low levels of abstraction.) Using high-level functions is usually safer and more convenient than using low-level functions, so we will mostly concern ourselves with high-level functions in this chapter, although we will touch on some low-level functions toward the end. A high-level connection opened to a le is called a stream. A low-level connection to a le is called a le descriptor. Streams and le descriptors have dierent data types, as we shall see. You must pass either a stream or a le descriptor to most input/output functions, to tell them which le they are operating on. Certain functions (usually high-level ones) expect to be passed streams, while others (usually low-level ones) expect le descriptors. A few functions will accept a simple lename instead of a stream or le descriptor, but generally these are only the functions that initialize streams or le descriptors in the rst place. You may consider it a nuisance to have to use a stream or a le descriptor to access your le when a simple le name would seem to suce, but these two mechanisms allow a level of abstraction to exist between your code and your les. Remember the black box analogy we explored at the beginning of the book. By using the data in les only through streams or le descriptors, we are guaranteed the ability to write a rich variety of functions that can exploit the behavior of these two black box abstractions. Interestingly enough, although streams are considered to be for high-level input/output, and le descriptors for low-level I/O, and GNU systems support both, more Unix-like systems support streams than le descriptors. You can expect any system running ISO C to support streams, but non-GNU systems may not support le descriptors at all, or may only implement a subset of the GNU functions that operate on le descriptors. Most of the le descriptor functions in the GNU library are included in the POSIX.1 standard, however. Once you have nished your input and output operations on the le, you must terminate your connection to it. This is called closing the le. Once you have closed a le, you cannot read from or write to it anymore until you open it again. In summary, to use a le, a program must go through the following routine: Open the le for reading, writing, or both. Read from or write to the le as appropriate, using le-handling functions provided by the GNU C Library. Close the le
Opening a le
115
16.1.1 Opening a le
The main high-level function for opening les is fopen. When you open a le with the fopen function, the GNU C Library creates a new stream and creates a connection between the stream and a le. If you pass this function the name of a le that does not exist, that le will be created. The fopen function normally returns a stream. A stream is a ow of data from a source to a destination within a GNU system. Programs can read characters from or write characters to a stream without knowing either the source or destination of the data, which may be a le on disk, a device such as a terminal meant as a human interface, or something entirely dierent. Streams are represented by variables of type FILE * fopen will return a null pointer if it fails to open the le. The rst parameter to this function is a string containing the lename of the le to open. The lename string can be either a constant or a variable, as in the following two equivalent examples: FILE *my_stream; my_stream = fopen ("foo", "r"); FILE *my_stream; char my_filename = "foo"; my_stream2 = fopen (my_filename, "r"); The second parameter is a string containing one of the following sets of characters: r w r+ Open the le for reading only. The le must already exist. Open the le for writing only. If the le already exists, its current contents are deleted. If the le does not already exist, it is created. Open the le for reading and writing. The le must already exist. The contents of the le are initially unchanged, but the le position is set to the beginning of the le. Open the le for both writing and reading. If the le already exists, its current contents are deleted. If the le does not already exist, it is created. Open the le for appending only. Appending to a le is the same as writing to it, except that data is only written to the current end of the le. If the le does not already exist, it is created.
w+ a
116
a+
Open the le for both appending and reading. If the le exists, its contents are unchanged until appended to. If the le does not exist, it is created. The initial le position for reading is at the beginning of the le, but the le position for appending is at the end of the le.
See Section 16.1.4 [File position], page 120, for more information on the concept of le position. You can also append the character x after any of the strings in the table above. This character causes fopen to fail rather than opening the le if the le already exists. If you append x to any of the arguments above, you are guaranteed not to clobber (that is, accidentally destroy) any le you attempt to open. (Any other characters in this parameter are ignored on a GNU system, but may be meaningful on other systems.) The following example illustrates the proper use of fopen to open a text le for reading (as well as highlighting the fact that you should clean up after yourself by closing les after you are done with them). Try running it once, then running it a second time after creating the text le snazzyjazz.txt in the current directory with a GNU command such as touch snazzyjazz.txt. #include <stdio.h> int main() { FILE *my_stream; my_stream = fopen ("snazzyjazz.txt", "r"); if (my_stream == NULL) { printf ("File could not be opened\n"); } else { printf ("File opened! Closing it now...\n"); /* Close stream; skip error-checking for brevity of example */ fclose (my_stream); } return 0; } See Section 16.1.2 [Closing a le], page 116, for more information on the function fclose.
16.1.2 Closing a le
The basic high-level function for closing les is fclose. Simply pass this function a stream, and fopen will close it and break the connection to the corresponding le, rst reading any buered input and writing any buered output. If the le was closed successfully, fclose will return 0; otherwise, it will return EOF. It is important to check for errors when you close a stream to which you are writing. For example, when fclose attempts to write the output remaining in its buer, it might
117
generate an error because the disk is full. Following is an example of closing a le with write access, while checking for errors. #include <stdio.h> int main() { FILE *my_stream; char my_filename[] = "snazzyjazz.txt"; int close_error; my_stream = fopen (my_filename, "w"); fprintf (my_stream, "Just a little hello from fprintf.\n"); close_error = fclose (my_stream); if (close_error != 0) { printf ("File could not be closed.\n"); } else { printf ("File closed.\n"); } return 0; }
118
fread
The fwrite function takes four parameters. The rst parameter to fwrite is a void pointer (void *) to an array that contains the data that will be written to the le. The second parameter is a variable of type size_t specifying the size of each object to be written, and the third parameter, also of type size_t, species the number of those objects that are to be written. The nal parameter is the stream to be written to (type FILE *). If the value returned by fopen does not match the third parameter passed (that is, the number of objects to be written), then there was an error. Like fwrite, the fread function takes four parameters. Its rst parameter is a void pointer to the array that will be written to. Its second parameter, of type size_t, species how large each object to be read is, and its third parameter, of type size_t, species how many of each object is to be read. The last parameter is simply the stream to read from. Again, if the return value of this function does not match the third parameter, which species how many object were to be read, there was an error. Here is an example that creates an array and lls it with multiples of 2, prints it out, writes the arrays data to a le with fwrite, zeroes the array and prints it out, reads the data from the le back into the array with fread, then prints the array out again so you can compare its data with the rst set of data. #include <stdio.h> int main() { int row, column; FILE *my_stream; int close_error; char my_filename[] = "my_numbers.dat"; size_t object_size = sizeof(int); size_t object_count = 25; size_t op_return; int my_array[5][5] = { 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50 }; printf ("Initial values of array:\n"); for (row = 0; row <= 4; row++) { for (column = 0; column <=4; column++) { printf ("%d } printf ("\n"); } ", my_array[row][column]);
119
my_stream = fopen (my_filename, "w"); op_return = fwrite (&my_array, object_size, object_count, my_stream); if (op_return != object_count) { printf ("Error writing data to file.\n"); } else { printf ("Successfully wrote data to file.\n"); } /* Close stream; skip error-checking for brevity of example */ fclose (my_stream); printf ("Zeroing array...\n"); for (row = 0; row <= 4; row++) { for (column = 0; column <=4; column++) { my_array[row][column] = 0; printf ("%d ", my_array[row][column]); } printf ("\n"); } printf ("Now reading data back in...\n"); my_stream = fopen (my_filename, "r"); op_return = fread (&my_array, object_size, object_count, my_stream); if (op_return != object_count) { printf ("Error reading data from file.\n"); } else { printf ("Successfully read data from file.\n"); } for (row = 0; row <= 4; row++) { for (column = 0; column <=4; column++) { printf ("%d } printf ("\n"); } /* Close stream; skip error-checking for brevity of example */ fclose (my_stream); return 0; } ", my_array[row][column]);
120
If all goes well, the code example above will produce the following output: Initial values of array: 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 Successfully wrote data to file. Zeroing array... 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 Now reading data back in... Successfully read data from file. 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 42 44 46 48 50 If you attempt to view the le my_numbers.dat produced by the program above with a GNU command such as more numbers.dat, you will see only garbage, because the information is stored in binary format, not readable by humans. After attempting to view this binary le, your terminal may continue to show only garbage and you may have to reset it. You may be able to do this with a menu option (if you are running gnome-terminal, for example), or you may have to type reset blindly.
Stream buering
121
level access to a le, you can change the le position at will. Any le that permits changing the le position in an arbitrary way is called a random-access le. (Many years ago, the people who invented computer jargon chose the word random to be part of the phrase random-access because, from the point of view of the computer, a random-access le can be read from or written to at any location, as if at random. Of course, programmers are not working randomly; they decide where their programs should read and write. The term RAM for random-access memory comes from the same source.) The main high-level function to tell where the current le position is, is called appropriately, ftell. It accepts a single parameter a le stream and returns a long integer representing the le position.1 (See section libc in The GNU C Library Reference Manual, for more information.) The main function to seek a dierent le position is called fseek. It accepts three parameters. The rst parameter is the stream in question, the second is a long integer oset, and the third parameter is a constant that species whether the oset is relative to the beginning of the le (SEEK_SET), to the current le position (SEEK_CUR), or to the end of the le (SEEK_END). The fseek function returns 0 if the operation was successful, or a nonzero integer value otherwise. (A successful fseek operation also clears the end-ofle indicator (see below), and discards the results of ungetc. See Section 16.3.5 [ungetc], page 148.) There is a simple macro called rewind that will take the le pointer back to the beginning of the le. You must simply pass it the stream that you want to rewind; it does not return a value. It is the same as calling fseek on the stream with an oset of 0 and a third parameter of SEEK_SET, except that it resets the error indicator for the stream and, as mentioned, there is no return value. An example of these functions will not be useful until we have introduced single-character I/O. See Section 16.3.3 [getc and fgetc], page 145, if you want to read a code example that uses the ftell, fseek, and rewind functions.
Since the le position is a long integer, the length of a le using one of these functions cannot be any greater than the maximum value of a 32-bit long integer under GNU, plus one (since the le position is zero-based) that is, such a le cannot be any more than 2,147,483,648 bytes, or about two gigabytes long. If you need to use longer les, you can use low-level le routines, which allow for longer les and le positions through such 64-bit functions as lseek64.
122
(You can bypass stream buering entirely, however, by using low-level rather than high-level le routines. See Section 16.5 [Low-level le routines], page 151, for more information.) There are three main kinds of buering you should know about: No buering: When you write characters to an unbuered stream, the operating system writes them to the le as soon as possible. Line buering: When you write characters to a line-buered stream, the operating system writes them to the le when it encounters a newline character. Full buering: When you write characters to a fully-buered stream, the operating system writes them to the le in blocks of arbitrary size. Most streams are fully buered when you open them, and this is usually the best solution. However, streams connected to interactive devices such as terminals are line-buered when you open them; yes, this means that stdin and stdout are line-buered. Having stdin and stdout be line-buered is convenient, because most meaningful chunks of data you write to them are terminated with a newline character. In order to ensure that the data you read from or write to a fully-buered stream shows up right away, use the fflush function. In the jargon, this is called ushing the stream. Flushing moves the characters from the buer to the le, if they havent already been moved. After the move, other functions can then work on the characters.2 To use fflush, simply pass the function the stream you want to ush. The fflush function returns 0 if successful, or the value EOF (which is a macro dened in the GNU C Library) if there was a write error. Note that using fflush is not always necessary; output is ushed automatically when you try to write and the output buer is already full, when the stream is closed, when the program exits, when an input operation on a stream actually reads data from the le, and of course, when a newline is written to a line-buered stream. (See Section 16.2.1.2 [fputs], page 124, for a code example that uses fflush.)
Strictly speaking, there are multiple levels of buering on a GNU system. Even after ushing characters to a le, data from the le may remain in memory, unwritten to disk. On GNU systems, there is an independently-running system program, or daemon, that periodically commits relevant data still in memory to disk. Under GNU/Linux, this daemon is called bdflush.
puts
123
otherwise. You can check the error indicator for a stream with the ferror function. This function takes a single argument (a stream), and returns TRUE (a nonzero value) if an error has occured during an operation on the stream, and FALSE (zero) otherwise. Unfortunately, ferror will not tell you what the error was, or when it occurred, only whether there has been an error. To get a more detailed diagnosis, you can check the global system variable errno. (See Section 16.5.1 [Usual le name errors], page 151.) It is possible to reset the error and end-of-le indicators once they have been set for a stream. To do so, simply pass the stream to the function clearerr; this will set both the error and end-of-le indicators back to 0. The clearerr function does not return a value. You should not simply reset the error ag and try a stream operation that failed a second time. Because of buering, you may lose or repeat data when writing, or access the wrong part of the le when reading. Before you try a failed stream operation again, you should seek to a known le position. (See Section 16.1.4 [File position], page 120.) However, most errors cannot be recovered from anyway trying the operation again will likely result in the same error so it is probably better to have your program report the error to the user and exit than to write complicated error-recovery routines for stream operation. An example of these functions will not be useful until we have introduced single-character I/O. See Section 16.3.3 [getc and fgetc], page 145, if you want to read a code example that uses the feof and ferror functions.
16.2.1.1 puts
The most convenient function for printing a simple message on standard outout is puts. It is even simpler than printf, since you do not need to include a newline character puts does that for you. Using puts couldnt be simpler. Here is an example:
124
puts ("Hello, multiverse."); This code example will print the string Hello, multiverse. to standard output. The puts function is safe and simple, but not very exible. See Section 16.2.2 [Formatted string output], page 125, if you want to print fancier output.
16.2.1.2 fputs
The fputs (le put string) function is similar to the puts function in almost every respect, except that it accepts a second parameter, a stream to which to write the string. It does not add a newline character, however; it only writes the characters in the string. It returns EOF if an error occurs; otherwise it returns a non-negative integer value. Here is a brief code example that creates a text le and uses fputs to write into it the phrase If its not too late... make it a cheeseburger., followed by a newline character. This example also demonstrates the use of the fflush function. (See Section 16.1.5 [Stream buering], page 121, for more information on this function.) #include <stdio.h> int main() { FILE *my_stream; char my_filename[] = "snazzyjazz.txt"; int flush_status; my_stream = fopen (my_filename, "w"); fputs ("If its not too late... make it a cheeseburger.\n", my_stream); /* Since the stream is fully-buffered by default, not line-buffered, it needs to be flushed periodically. Well flush it here for demonstration purposes, even though were about to close it. */ flush_status = fflush (my_stream); if (flush_status != 0) { puts ("Error flushing stream!"); } else { puts ("Stream flushed."); } /* Close stream; skip error-checking for brevity of example */ fclose (my_stream); return 0; }
125
16.2.2.1 printf
If you have been reading the book closely up to this point, you have seen the use of the printf function many times. To recap, this function prints a text string to the terminal (or, to be more precise, the text stream stdout). For example, the following line of code prints the string Hello there!, followed by a newline character, to the console: printf ("Hello there!\n"); You probably also remember that you can incorporate numeric constants and variables into your strings. Consider the following code example: printf ("Im free! Im free! (So what? Im %d.)\n", 4); The previous example is equivalent to the following one: int age = 4; printf ("Im free! Im free! (So what? Im %d.)\n", age); Both of the code examples above produce the following output: Im free! Im free! (So what? Im 4.) You may recall that besides using %d with printf to print integers, we have also used %f on occasion to print oating-point numbers, and that on occasion we have used more than one argument. Consider this example: printf ("Im free! Im free! (So what? Im %d.) Well, Im %f.\n", 4, 4.5); That example produces the following output: Im free! Im free! (So what? Im 4.) Well, Im 4.500000. In fact, printf is a very exible function. The general scheme is that you provide it with a format string or template string (such as "So what? Im %d."), which can contain zero or more conversion specications, conversion speciers, or sometimes just conversions (in this case %d), and zero or more arguments (for example, 4). Each conversion specication is said to specify a conversion, that is, how to convert its corresponding argument into a printable string. After the template string, you supply one argument for each conversion specier in the template string. The printf function then prints the template string,
126
including each argument as converted to a printable sub-string by its conversion specier, and returns an integer containing the number of characters printed, or a negative value if there was an error.
s u x X %
In between the percent sign (%) and the output conversion character, you can place some combination of the following modiers. (Note that the percent sign conversion (%%) doesnt use arguments or modiers.) Zero or more ag characters, from the following table: - Left-justify the number in the eld (right justication is the default). Can also be used for string and character conversions (%s and %c).
127
+ Always print a plus or minus sign to indicate whether the number is positive or negative. Valid for %d, %e, %E, and %i. Space character If the number does not start with a plus or minus sign, prex it with a space character instead. This ag is ignored if the + ag is specied. # For %e, %E, and %f, forces the number to include a decimal point, even if no digits follow. For %x and %X, prexes 0x or 0X, respectively. Separate the digits of the integer part of the number into groups, using a locale-specic character. In the United States, for example, this will usually be a comma, so that one million will be rendered 1,000,000. GNU systems only. 0 Pad the eld with zeroes instead of spaces; any sign or indication of base (such as 0x) will be printed before the zeroes. This ag is ignored if the - ag or a precision is specied. In the example given above, %-17.7ld, the ag given is -. An optional non-negative decimal integer specifying the minimum eld width within which the conversion will be printed. If the conversion contains fewer characters, it will be padded with spaces (or zeroes, if the 0 ag was specied). If the conversion contains more characters, it will not be truncated, and will overow the eld. The output will be right-justied within the eld, unless the - ag was specied. In the example given above, %-17.7ld, the eld width is 17. For numeric conversions, an optional precision that species the number of digits to be written. If it is specied, it consists of a dot character (.), followed by a non-negative decimal integer (which may be omitted, and defaults to zero if it is). In the example given above, %-17.7ld, the precision is .7. Leading zeroes are produced if necessary. If you dont specify a precision, the number is printed with as many digits as necessary (with a default of six digits after the decimal point). If you supply an argument of zero with and explicit precision of zero, printf will not print any characters. Specifying a precision for a string conversion (%s) indicates the maximum number of characters to write. An optional type modier character from the table below. This character species the data type of the argument if it is dierent from the default. In the example given above, %-17.7ld, the type modier character is l; normally, the d output conversion character expects a data type of int, but the l species that a long int is being used instead. The numeric conversions usually expect an argument of either type int, unsigned int, or double. (The %c conversion converts its argument to unsigned char.) For the integer conversions (%d and %i), char and short arguments are automatically converted to type int, and for the unsigned integer conversions (%u, %x, and %X),
128
they are converted to type unsigned int. For the oating-point conversions (%e, %E, and %f), all float arguments are converted to type double. You can use one of the type modiers from the table below to specify another type of argument.
Species that the argument is a long int (for %d and %i), or an unsigned long int (for %u, %x, and %X).
Species that the argument is a long double for the oating-point conversions (%e, %E, and %f). Same as ll, for integer conversions (%d and %i).
ll
Species that the argument is a long long int (for %d and %i). On systems that do not have extra-long integers, this has the same eect as l.
Species that the argument is of type size_t. (The size_t type is used to specify the sizes of blocks of memory, and many functions in this chapter use it.)
Make sure that your conversion speciers use valid syntax; if they do not, if you do not supply enough arguments for all conversion speciers, or if any arguments are of the wrong type, unpredictable results may follow. Supplying too many arguments is not a problem, however; the extra arguments are simply ignored.
fprintf
129
#include <stdio.h> #include <errno.h> int main() { int my_integer = -42; unsigned int my_ui = 23; float my_float = 3.56; double my_double = 424242.171717; char my_char = w; char my_string[] = "Pardon me, may I borrow your nose?"; printf ("Integer: %d\n", my_integer); printf ("Unsigned integer: %u\n", my_ui); printf ("The same, as hexadecimal: %#x %#x\n", my_integer, my_ui); printf ("Floating-point: %f\n", my_float); printf ("Double, exponential notation: %17.11e\n", my_double); printf ("Single character: %c\n", my_char); printf ("String: %s\n", my_string); errno = EACCES; printf ("errno string (EACCES): %m\n"); return 0; } The code example above produces the following output on a GNU system: Integer: -42 Unsigned integer: 23 The same, as hexadecimal: 0xffffffd6 0x17 Floating-point: 3.560000 Double, exponential notation: 4.24242171717e+05 Single character: w String: Pardon me, may I borrow your nose? errno string (EACCES): Permission denied
16.2.3 fprintf
The fprintf (le print formatted) command is identical to printf, except that its rst parameter is a stream to which to send output. The following code example is the same as the one for printf, except that it sends its output to the text le snazzyjazz.txt.
130
#include <stdio.h> #include <errno.h> int main() { int my_integer = -42; unsigned int my_ui = 23; float my_float = 3.56; double my_double = 424242.171717; char my_char = w; char my_string[] = "Pardon me, may I borrow your nose?"; FILE *my_stream; char my_filename[] = "snazzyjazz.txt"; my_stream = fopen (my_filename, "w"); fprintf (my_stream, "Integer: %d\n", my_integer); fprintf (my_stream, "Unsigned integer: %u\n", my_ui); fprintf (my_stream, "The same, as hexadecimal: %#x %#x\n", my_integer, my_ui); fprintf (my_stream, "Floating-point: %f\n", my_float); fprintf (my_stream, "Double, exponential notation: %17.11e\n", my_double); fprintf (my_stream, "Single character: %c\n", my_char); fprintf (my_stream, "String: %s\n", my_string); errno = EACCES; fprintf (my_stream, "errno string (EACCES): %m\n"); /* Close stream; skip error-checking for brevity of example */ fclose (my_stream); return 0; }
16.2.4 asprintf
The asprintf (mnemonic: allocating string print formatted) command is identical to printf, except that its rst parameter is a string to which to send output. It terminates the string with a null character. It returns the number of characters stored in the string, not including the terminating null. The asprintf function is nearly identical to the simpler sprintf, but is much safer, because it dynamically allocates the string to which it sends output, so that the string will never overow. The rst parameter is a pointer to a string variable, that is, it is of type char **. The return value is the number of characters allocated to the buer, or a negative value if an error occurred. The following code example prints the string Being 4 is cool, but being free is best of all. to the string variable my_string, then prints the string on the screen. No-
String input
131
tice that my_string is not initially allocated any space at all; asprintf allocates the space itself. (See Section 16.2.1.1 [puts], page 123, for more information on the puts function.) #include <stdio.h> int main() { char *my_string; asprintf (&my_string, "Being %d is cool, but being free is best of all.", 4); puts (my_string); return 0; }
This section discusses unsafe functions for formatted string output. It actually contains only one function, sprintf. You should never use the sprintf function; use asprintf instead.
16.2.5.1 sprintf
The sprintf (string print formatted) command is similar to asprintf, except that it is much less safe. Its rst parameter is a string to which to send output. It terminates the string with a null character. It returns the number of characters stored in the string, not including the terminating null. This function will behave unpredictably if the string to which it is printing overlaps any of its arguments. It is dangerous because the characters output to the string may overow it. This problem cannot be solved with the eld width modier to the conversion specier, because only the minimum eld width can be specied with it. To avoid this problem, it is better to use asprintf, but there is a lot of C code that still uses sprintf, so it is important to know about it. (See Section 16.2.4 [asprintf], page 130.) The following code example prints the string Being 4 is cool, but being free is best of all. to the string variable my_string then prints the string on the screen. Notice that my_string has been allocated 100 bytes of space, enough to contain the characters output to it. (See Section 16.2.1.1 [puts], page 123, for more information on the puts function.)
132
#include <stdio.h> int main() { char my_string[100]; sprintf (my_string, "Being %d is cool, but being free is best of all.", 4); puts (my_string); return 0; }
16.2.6.1 getline
The getline function is the preferred method for reading lines of text from a stream, including standard input. The other standard functions, including gets, fgets, and scanf, are too unreliable. (Doubtless, in some programs you will see code that uses these unreliable functions, and at times you will come across compilers that cannot handle the safer getline function. As a professional, you should avoid unreliable functions and any compiler that requires you to be unsafe.) The getline function reads an entire line from a stream, up to and including the next newline character. It takes three parameters. The rst is a pointer to a block allocated with malloc or calloc. (These two functions allocate computer memory for the program when it is run. See Section 20.2 [Memory allocation], page 212, for more information.) This parameter is of type char **; it will contain the line read by getline when it returns. The second parameter is a pointer to a variable of type size_t; this parameter species the size in bytes of the block of memory pointed to by the rst parameter. The third parameter is simply the stream from which to read the line. The pointer to the block of memory allocated for getline is merely a suggestion. The getline function will automatically enlarge the block of memory as needed, via the realloc function, so there is never a shortage of space one reason why getline is so safe. Not only that, but getline will also tell you the new size of the block by the value returned in the second parameter. If an error occurs, such as end of le being reached without reading any bytes, getline returns -1. Otherwise, the rst parameter will contain a pointer to the string containing the line that was read, and getline returns the number of characters read (up to and including the newline, but not the nal null character). The return value is of type ssize_t. Although the second parameter is of type pointer to string (char **), you cannot treat it as an ordinary string, since it may contain null characters before the nal null character
getdelim
133
marking the end of the line. The return value enables you to distinguish null characters that getline read as part of the line, by specifying the size of the line. Any characters in the block up to the number of bytes specied by the return value are part of the line; any characters after that number of bytes are not. Here is a short code example that demonstrates how to use getline to read a line of text from the keyboard safely. Try typing more than 100 characters. Notice that getline can safely handle your line of input, no matter how long it is. Also note that the puts command used to display the line of text read will be inadequate if the line contains any null characters, since it will stop displaying text at the rst null, but that since it is dicult to enter null characters from the keyboard, this is generally not a consideration. #include <stdio.h> int main() { int bytes_read; int nbytes = 100; char *my_string; puts ("Please enter a line of text."); /* These 2 lines are the heart of the program. */ my_string = (char *) malloc (nbytes + 1); bytes_read = getline (&my_string, &nbytes, stdin); if (bytes_read == -1) { puts ("ERROR!"); } else { puts ("You typed:"); puts (my_string); } return 0; }
16.2.6.2 getdelim
The getdelim function is a more general form of the getline function; whereas getline stops reading input at the rst newline character it encounters, the getdelim function enables you to specify other delimiter characters than newline. In fact, getline simply calls getdelim and species that the delimiter character is a newline. The syntax for getdelim is nearly the same as that of getline, except that the third parameter species the delimiter character, and the fourth parameter is the stream from which to read. You can exactly duplicate the getline example in the last section with getdelim, by replacing the line bytes_read = getline (&my_string, &nbytes, stdin);
134
16.2.7.1 gets
If you want to read a string from standard input, you can use the gets function, the name of which stands for get string. However, this function is deprecated that means it is obsolete and it is strongly suggested you do not use it because it is dangerous. It is dangerous because it provides no protection against overowing the string into which it is saving data. Programs that use gets can actually be a security problem on your computer. Since it is sometimes used in older code (which is why the GNU C Library still provides it), we will examine it briey; nevertheless, you should always use the function getline instead. (See Section 16.2.6.1 [getline], page 132.) The gets function takes one parameter, the string in which to store the data read. It reads characters from standard input up to the next newline character (that is, when the user presses RETURN ), discards the newline character, and copies the rest into the string passed to it. If there was no error, it returns the same string (as a return value, which may be discarded); otherwise, if there was an error, it returns a null pointer. Here is a short code example that uses gets: #include <stdio.h> int main() { char my_string[500]; printf("Type something.\n"); gets(my_string); printf ("You typed: %s\n", my_string); return 0; } If you attempt to compile the example above, it will compile and will run properly, but GCC will warn you against the use of a deprecated function, as follows: /tmp/ccPW3krf.o: In function main: /tmp/ccPW3krf.o(.text+0x24): the gets function is dangerous and should not be used. Remember! Never use this function in your own code. Always use getline instead.
fgets
135
16.2.7.2 fgets
The fgets (le get string) function is similar to the gets function. This function is deprecated that means it is obsolete and it is strongly suggested you do not use it because it is dangerous. It is dangerous because if the input data contains a null character, you cant tell. Dont use fgets unless you know the data cannot contain a null. Dont use it to read les edited by the user because, if the user inserts a null character, you should either handle it properly or print a clear error message. Always use getline or getdelim instead of fgets if you can. Rather than reading a string from standard input, as gets does, fgets reads it from a specied stream, up to and including a newline character. It stores the string in the string variable passed to it, adding a null character to terminate the string. This function takes three parameters: the rst is the string into which to read data, the second is the maximum number of characters to read. (You must supply at least this many characters of space in the string, or your program will probably crash, but at least the fgets function protects against overowing the string and creating a security hazard, unlike gets.) The third parameter is the stream from which to read. The number of characters that fgets reads is actually one less than than number specied; it stores the null character in the extra character space. If there is no error, fgets returns the string read as a return value, which may be discarded. Otherwise, for example if the stream is already at end of le, it returns a null pointer. Unfortunately, like the gets function, fgets is deprecated, in this case because when fgets cannot tell whether a null character is included in the string it reads. If a null character is read by fgets, it will be stored in the string along with the rest of the characters read. Since a null character terminates a string in C, C will then consider your string to end prematurely, right before the rst null character. Only use fgets if you are certain the data read cannot contain a null; otherwise, use getline. Here is a code example that uses fgets. It will create a text le containing the string Hidee ho! plus a newline, read it back with fgets, and print it on standard output. Notice that although 100 characters are allocated for the string my_string, and requested to be read in the fgets call, there are not that many characters in the le. The fgets function only reads the string up to the newline character; the important thing is to allocate enough space in the string variable to contain the string to be read. #include <stdio.h> int main() { int input_character; FILE *my_stream; char my_filename[] = "snazzyjazz.txt"; char my_string[100];
136
my_stream = fopen (my_filename, "w"); fprintf (my_stream, "Hidee ho!\n"); /* Close stream; skip error-checking for brevity of example */ fclose (my_stream); my_stream = fopen (my_filename, "r"); fgets (my_string, 100, my_stream); /* Close stream; skip error-checking for brevity of example */ fclose (my_stream); printf ("%s", my_string); return 0; }
16.2.8.1 sscanf
The sscanf function accepts a string from which to read input, then, in a manner similar to printf and related functions, it accepts a template string and a series of related arguments. It tries to match the template string to the string from which it is reading input, using conversion specier like those of printf. The sscanf function is just like the deprecated parent scanf function, except that the rst argument of sscanf species a string from which to read, whereas scanf can only read from standard input. Reaching the end of the string is treated as an end-of-le condition. Here is an example of sscanf in action: sscanf (input_string, "%as %as %as", &str_arg1, &str_arg2, &str_arg3); If the string sscanf is scanning overlaps with any of the arguments, unexpected results will follow, as in the following example. Dont do this! sscanf (input_string, "%as", &input_string); Here is a good code example that parses input from the user with sscanf. It prompts the user to enter three integers separated by whitespace, then reads an arbitrarily long line of text from the user with getline. It then checks whether exactly three arguments were assigned by sscanf. If the line read does not contain the data requested (for example, if it
sscanf
137
contains a oating-point number or any alphabetic characters), the program prints an error message and prompts the user for three integers again. When the program nally receives exactly the data it was looking for from the user, it prints out a message acknowledging the input, and then prints the three integers. It is this exibility of input and great ease of recovery from errors that makes the getline/sscanf combination so vastly superior to scanf alone. Simply put, you should never use scanf where you can use this combination instead. #include <stdio.h> int main() { int nbytes = 100; char *my_string; int int1, int2, int3; int args_assigned; args_assigned = 0; while (args_assigned != 3) { puts ("Please enter three integers separated by whitespace."); my_string = (char *) malloc (nbytes + 1); getline (&my_string, &nbytes, stdin); args_assigned = sscanf (my_string, "%d %d %d", &int1, &int2, &int3); if (args_assigned != 3) puts ("\nInput invalid!"); } printf ("\nThanks!\n%d\n%d\n%d\n", int1, int2, int3); return 0; } Template strings for sscanf and related functions are somewhat more free-form than those for printf. For example, most conversion speciers ignore any preceding whitespace. Further, you cannot specify a precision for sscanf conversion speciers, as you can for those of printf. Another important dierence between sscanf and printf is that the arguments to sscanf must be pointers; this allows sscanf to return values in the variables they point to. If you forget to pass pointers to sscanf, you may receive some strange errors, and it is easy to forget to do so; therefore, this is one of the rst things you should check if code containing a call to sscanf begins to go awry. A sscanf template string can contain any number of any number of whitespace characters, any number of ordinary, non-whitespace characters, and any number of conversion speciers starting with %. A whitespace character in the template string matches zero or more whitespace characters in the input string. Ordinary, non-whitespace characters must correspond exactly in the template string and the input stream; otherwise, a matching error occurs. Thus, the template string " foo " matches "foo" and " foo ", but not " food ".
138
If you create an input conversion specier with invalid syntax, or if you dont supply enough arguments for all the conversion speciers in the template string, your code may do unexpected things, so be careful. Extra arguments, however, are simply ignored. Conversion speciers start with a percent sign (%) and terminate with a character from the following table:
Matches a xed number of characters. If you specify a maximum eld width (see below), that is how many characters will be matched; otherwise, %c matches one character. This conversion does not append a null character to the end of the text it reads, as does the %s conversion. It also does not skip whitespace characters, but reads precisely the number of characters it was told to, or generates a matching error if it cannot. Matches an optionally signed decimal integer, containing the following sequence: 1. An optional plus or minus sign (+ or -). 2. One or more decimal digits. Note that %d and %i are not synonymous for scanf, as they are for printf.
Matches an optionally signed oating-point number, containing the following sequence: 1. An optional plus or minus sign (+ or -). 2. A oating-point number in decimal or hexadecimal format. The decimal format is a sequence of one or more decimal digits, optionally containing a decimal point character (usually .), followed by an optional exponent part, consisting of a character e or E, an optional plus or minus sign, and a sequence of decimal digits. The hexadecimal format is a 0x or 0X, followed by a sequence of one or more hexadecimal digits, optionally containing a decimal point character, followed by an optional binary-exponent part, consisting of a character p or P, an optional plus or minus sign, and a sequence of digits.
E f g G i
Same as e. Same as e. Same as e. Same as e. Matches an optionally signed integer, containing the following sequence: 1. An optional plus or minus sign (+ or -). 2. A string of characters representing an unsigned integer.
139
If the string begins with 0x or 0X, the number is assumed to be in hexadecimal format, and the rest of the string must contain hexadecimal digits. Otherwise, if the string begins with 0, the number is assumed to be in octal format (base eight), and the rest of the string must contain octal digits. Otherwise, the number is assumed to be in decimal format, and the rest of the string must contain decimal digits. Note that %d and %i are not synonymous for scanf, as they are for printf. You can print integers in this syntax with printf by using the # ag character with the %x or %d output conversions. (See Section 16.2.2.1 [printf], page 125.) s Matches a string of non-whitespace characters. It skips initial whitespace, but stops when it meets more whitespace after it has read something. It stores a null character at the end of the text that it reads, to mark the end of the string. (See Section 16.2.9.2 [String overows with scanf], page 141, for a warning about using this conversion.) Matches an unsigned integer in hexadecimal format. The string matched must begin with 0x or 0X, and the rest of the string must contain hexadecimal digits. Same as x. Matches a string containing an arbitrary set of characters. For example, %12[0123456789] means to read a string with a maximum eld width of 12, containing characters from the set 0123456789 in other words, twelve decimal digits. An embedded - character means a range of characters; thus %12[0-9] means the same thing as the last example. Preceding the characters in the square brackets with a caret (^) means to read a string not containing the characters listed. Thus, %12[^0-9] means to read a twelve-character string not containing any decimal digit. (See Section 16.2.9.2 [String overows with scanf], page 141, for a warning about using this conversion.) Matches a percent sign. Does not correspond to an argument, and does not permit ags, eld width, or type modier to be specied (see below).
X [
In between the percent sign (%) and the input conversion character, you can place some combination of the following modiers, in sequence. (Note that the percent sign conversion (%%) doesnt use arguments or modiers.) An optional * ag. This ag species that a match should be made between the conversion specier and an item in the input stream, but that the value should not then be assigned to an argument. An optional a ag, valid with string conversions only. This is a GNU extension to scanf that requests allocation of a buer long enough to safely store the string that was read. (See Section 16.2.9.2 [String overows with scanf], page 141, for information on how to use this ag.)
140
An optional ag. This ag species that the number read will be grouped according to the rules currently specied on your system. For example, in the United States, this usually means that 1,000 will be read as one thousand. An optional decimal integer that species the maximum eld width. The scanf function will stop reading characters from the input stream either when this maximum is reached, or when a non-matching character is read, whichever comes rst. Discarded initial whitespace does not count toward this width; neither does the null character stored by string input conversions to mark the end of the string. An optional type modier character from the following table. (The default type of the corresponding argument is int * for the %d and %i conversions, unsigned int * for %x and %X, and float * for %e and its synonyms. You can use these type modiers to specify otherwise.) h Species that the argument to which the value read should be assigned is of type short int * or unsigned short int *. Valid for the %d and %i conversions. For the %d and %i conversions, species that the argument to which the value read should be assigned is of type long int * or unsigned long int *. For the %e conversion and its synonyms, species that the argument is of type double *. For the %d and %i conversions, species that the argument to which the value read should be assigned is of type long long int * or unsigned long long int *. On systems that do not have extra-long integers, this has the same eect as l. For the %e conversion and its synonyms, species that the argument is of type long double *. ll q z Same as L, for the %d and %i conversions. Same as L, for the %d and %i conversions. Species that the argument to which the value read should be assigned is of type size_t. (The size_t type is used to specify the sizes of blocks of memory, and many functions in this chapter use it.) Valid for the %d and %i conversions.
16.2.9.1 scanf
141
The rst of the functions we will examine is scanf (scan formatted). The scanf function is considered dangerous for a number of reasons. First, if used improperly, it can cause your program to crash by reading character strings that overow the string variables meant to contain them, just like gets. (See Section 16.2.7.1 [gets], page 134.) Second, scanf can hang if it encounters unexpected non-numeric input while reading a line from standard input. Finally, it is dicult to recover from errors when the scanf template string does not match the input exactly. If you are going to read input from the keyboard, it is far better to read it with getline and parse the resulting string with sscanf (string scan formatted) than to use scanf directly. However, since sscanf uses nearly the same syntax as sscanf, as does the related fscanf, and since scanf is a standard C function, it is important to learn about it. If scanf cannot match the template string to the input string, it will return immediately and it will leave the rst non-matching character as the next character to read from the stream. This is called a matching error, and is the main reason scanf tends to hang when reading input from the keyboard; a second call to scanf will almost certainly choke, since the le position indicator of the stream is not pointing where scanf will expect it to. Normally, scanf returns the number of assignments made to the arguments it was passed, so check the return value to see if scanf found all the items you expected.
If you use the %s and %[ conversions improperly, then the number of characters read is limited only by where the next whitespace character appears. This almost cetainly means that invalid input could make your program crash, because input too long would overow whatever buer you have provided for it. No matter how long your buer is, a user could always supply input that is longer. A well-written program reports invalid input with a comprehensible error message, not with a crash. Fortunately, it is possible to avoid scanf buer overow by either specifying a eld width or using the a ag. When you specify a eld width, you need to provide a buer (using malloc or a similar function) of type char *. (See Section 20.2 [Memory allocation], page 212, for more information on malloc.) You need to make sure that the eld width you specify does not exceed the number of bytes allocated to your buer. On the other hand, you do not need to allocate a buer if you specify the a ag character scanf will do it for you. Simply pass scanf an pointer to an unallocated variable of type char *, and scanf will allocate however large a buer the string requires, and return the result in your argument. This is a GNU-only extension to scanf functionality. Here is a code example that shows rst how to safely read a string of xed maximum length by allocating a buer and specifying a eld width, then how to safely read a string of any length by using the a ag.
142
#include <stdio.h> int main() { int bytes_read; int nbytes = 100; char *string1, *string2; string1 = (char *) malloc (25); puts ("Please enter a string of 20 characters or fewer."); scanf ("%20s", string1); printf ("\nYou typed the following string:\n%s\n\n", string1); puts ("Now enter a string of any length."); scanf ("%as", &string2); printf ("\nYou typed the following string:\n%s\n", string2); return 0; } There are a couple of things to notice about this example program. First, notice that the second argument passed to the rst scanf call is string1, not &string1. The scanf function requires pointers as the arguments corresponding to its conversions, but a string variable is already a pointer (of type char *), so you do not need the extra layer of indirection here. However, you do need it for the second call to scanf. We passed it an argument of &string2 rather than string2, because we are using the a ag, which allocates a string variable big enough to contain the characters it read, then returns a pointer to it. The second thing to notice is what happens if you type a string of more than 20 characters at the rst prompt. The rst scanf call will only read the rst 20 characters, then the second scanf call will gobble up all the remaining characters without even waiting for a response to the second prompt. This is because scanf does not read a line at a time, the way the getline function does. Instead, it immediately matches attempts to match its template string to whatever characters are in the stdin stream. The second scanf call matches all remaining characters from the overly-long string, stopping at the rst whitespace character. Thus, if you type 12345678901234567890xxxxx in response to the rst prompt, the program will immediately print the following text without pausing: You typed the following string: 12345678901234567890 Now enter a string of any length. You typed the following string: xxxxx (See Section 16.2.8.1 [sscanf], page 136, for a better example of how to parse input from the user.)
16.2.10 fscanf
getchar
143
The fscanf function is just like the scanf function, except that the rst argument of fscanf species a stream from which to read, whereas scanf can only read from standard input. Here is a code example that generates a text le containing ve numbers with fprintf, then reads them back in with fscanf. Note the use of the # ags in the %#d conversions in the fprintf call; this is a good way to generate data in a format that scanf and related functions can easily read with the %i input conversion. #include <stdio.h> #include <errno.h> int main() { float f1, f2; int i1, i2; FILE *my_stream; char my_filename[] = "snazzyjazz.txt"; my_stream = fopen (my_filename, "w"); fprintf (my_stream, "%f %f %#d %#d", 23.5, -12e6, 100, 5); /* Close stream; skip error-checking for brevity of example */ fclose (my_stream); my_stream = fopen (my_filename, "r"); fscanf (my_stream, "%f %f %i %i", &f1, &f2, &i1, &i2); /* Close stream; skip error-checking for brevity of example */ fclose (my_stream); printf printf printf printf ("Float 1 ("Float 2 ("Integer ("Integer = = 1 2 %f\n", f1); %f\n", f2); = %d\n", i1); = %d\n", i2);
return 0; } This code example prints the following output on the screen: Float 1 Float 2 Integer Integer = = 1 2 23.500000 -12000000.000000 = 100 = 5
If you examine the text le snazzyjazz.txt, you will see it contains the following text: 23.500000 -12000000.000000 100 5
144
This section covers the use of several functions for the input and output of single characters from standard input and output or les.
16.3.1 getchar
If you want to read a single character from standard input, you can use the getchar function. This function takes no parameters, but reads the next character from stdin as an unsigned char, and returns its value, converted to an integer. Here is a short program that uses getchar: #include <stdio.h> int main() { int input_character; printf("Hit any key, then hit RETURN.\n"); input_character = getchar(); printf ("The key you hit was %c.\n", input_character); printf ("Bye!\n"); return 0; } Note that because stdin is line-buered, getchar will not return a value until you hit the RETURN key. However, getchar still only reads one character from stdin, so if you type hellohellohello at the prompt, the program above will still only get once character. It will print the following line, and then terminate: The key you hit was h. Bye!
16.3.2 putchar
If you want to print a single character on standard output, you can use the putchar function. It takes a single integer parameter containing a character (the argument can be a single-quoted text character, as in the example below), and sends the character to stdout. If a write error occurs, putchar returns EOF; otherwise, it returns the integer it was passed. This can simply be disregarded, as in the example below. Here is a short code example that makes use of putchar. It prints an X, a space, and then a line of ten exclamation marks (!!!!!!!!!!) on the screen, then outputs a newline so that the next shell prompt will not occur on the same line. Notice the use of the for loop; by this means, putchar can be used not just for one character, but multiple times.
145
#include <stdio.h> int main() { int i; putchar (X); putchar ( ); for (i=1; i<=10; i++) { putchar (!); } putchar (\n); return 0; }
If you want to read a single character from a stream other than stdin, you can use the getc function. This function is very similar to getchar, but accepts an argument that species the stream from which to read. It reads the next character from the specied stream as an unsigned char, and returns its value, converted to an integer. If a read error occurs or the end of the le is reached, getc returns EOF instead. Here is a code example that makes use of getc. This code example creates a text le called snazzyjazz.txt with fopen, writes the alphabet in upper-case letters plus a newline to it with fprintf, reads the le position with ftell, and gets the character there with getc. It then seeks position 25 with fseek and repeats the process, attempts to read past the end of the le and reports end-of-le status with feof, and generates an error by attempting to write to a read-only stream. It then reports the error status with ferror, returns to the start of the le with rewind and prints the rst character, and nally attempts to close the le and prints a status message indicating whether it could do so. See Section 16.1.4 [File position], page 120, for information on ftell, fseek, and rewind. See Section 16.1.6 [End-of-le and error functions], page 122, for more information on feof and ferror. #include <stdio.h> int main() { int input_char; FILE *my_stream; char my_filename[] = "snazzyjazz.txt"; long position; int eof_status, error_status, close_error;
146
my_stream = fopen (my_filename, "w"); fprintf (my_stream, "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); /* Close stream; skip error-checking for brevity of example */ fclose (my_stream); printf ("Opening file...\n"); my_stream = fopen (my_filename, "r"); position = ftell (my_stream); input_char = getc (my_stream); printf ("Character at position %d = %c.\n\n", position, input_char); printf ("Seeking position 25...\n"); fseek (my_stream, 25, SEEK_SET); position = ftell (my_stream); input_char = getc (my_stream); printf ("Character at position %d = %c.\n\n", position, input_char); printf ("Attempting to read again...\n"); input_char = getc (my_stream); eof_status = feof (my_stream); printf ("feof returns %d.\n\n", eof_status); error_status = ferror (my_stream); printf ("ferror returns %d.\n", error_status); printf ("Attempting to write to this read-only stream...\n"); putc (!, my_stream); error_status = ferror (my_stream); printf ("ferror returns %d.\n\n", error_status); printf ("Rewinding...\n"); rewind (my_stream); position = ftell (my_stream); input_char = getc (my_stream); printf ("Character at position %d = %c.\n", position, input_char); close_error = fclose (my_stream); /* Handle fclose errors */ if (close_error != 0) { printf ("File could not be closed.\n"); } else { printf ("File closed.\n"); } return 0; } There is another function in the GNU C Library called fgetc. It is identical to getc in most respects, except that getc is usually implemented as a macro function and is highly optimised, so is preferable in most situations. (In situations where you are reading from
ungetc()
147
standard input, getc is about as fast as fgetc, since humans type slowly compared to how fast computers can read their input, but when you are reading from a stream that is not interactively produced by a human, fgetc is probably better.)
16.3.5 ungetc()
148
Every time a character is read from a stream by a function like getc, the le position indicator advances by 1. It is possible to reverse the motion of the le position indicator with the function ungetc, which steps the le position indicator back by one byte within the le and reverses the eect of the last character read operation. (This is called unreading the character or pushing it back onto the stream.) The intended purpose is to leave the indicator in the correct le position when other functions have moved too far ahead in the stream. Programs can therefore peek ahead, or get a glimpse of the input they will read next, then reset the le position with ungetc. On GNU systems, you cannot call ungetc twice in a row without reading at least one character in between; in other words, GNU only supports one character of pushback. Pushing back characters does not change the le being accessed at all; ungetc only aects the stream buer, not the le. If fseek, rewind, or some other le positioning function is called, any character due to be pushed back by ungetc is discarded. Unreading a character on a stream that is at end-of-le resets the end-of-le indicator for the stream, because there is once again a character available to be read. However, if the character pushed back onto the stream is EOF, ungetc does nothing and just returns EOF. Here is a code example that reads all the whitespace at the beginning of a le with getc, then backs up one byte to the rst non-whitespace character, and reads all following characters up to a newline character with the getline function. (See Section 16.2.6.1 [getline], page 132, for more information on that function.) #include <stdio.h> int main() { int in_char; FILE *my_stream; char *my_string = NULL; size_t nchars = 0; my_stream = fopen ("snazzyjazz.txt", "w"); fprintf (my_stream, " Heres some non-whitespace.\n"); /* Close stream; skip error-checking for brevity of example */ fclose (my_stream); my_stream = fopen ("snazzyjazz.txt", "r"); /* Skip all whitespace in stream */ do in_char = getc (my_stream); while (isspace (in_char));
149
/* Back up to first non-whitespace character */ ungetc (in_char, my_stream); getline (&my_string, &nchars, my_stream); /* Close stream; skip error-checking for brevity of example */ fclose (my_stream); printf ("String read:\n"); printf ("%s", my_string); return 0; } The code example will skip all initial whitespace in the le snazzyjazz.txt, and display the following text on standard output: String read: Heres some non-whitespace.
150
The popen function accepts as its rst argument a string containing a shell command, such as lpr. Its second argument is a string containing either the mode argument r or w. If you specify r, the pipe will be open for reading; if you specify w, it will be open for writing. The return value is a stream open for reading or writing, as the case may be; if there is an error, popen returns a null pointer. The pclose function closes a pipe opened by popen. It accepts a single argument, the stream to close. It waits for the stream to close, and returns the status code returned by the program that was called by popen. If you open the pipe for reading or writing, in between the popen and pclose calls, it is possible to read from or write to the pipe in the same way that you might read from or write to any other stream, with high-level input/output calls such as getdelim, fprintf and so on. The following program example shows how to pipe the output of the ps -A command to the grep init command, exactly as in the GNU/Linux command line example above. The output of this program should be almost exactly the same as sample output shown above. #include <stdio.h> #include <stdlib.h> int main () { FILE *ps_pipe; FILE *grep_pipe; int bytes_read; int nbytes = 100; char *my_string; /* Open our two pipes */ ps_pipe = popen ("ps -A", "r"); grep_pipe = popen ("grep init", "w"); /* Check that pipes are non-null, therefore open */ if ((!ps_pipe) || (!grep_pipe)) { fprintf (stderr, "One or both pipes failed.\n"); return EXIT_FAILURE; } /* Read from ps_pipe until two newlines */ my_string = (char *) malloc (nbytes + 1); bytes_read = getdelim (&my_string, &nbytes, "\n\n", ps_pipe); /* Close ps_pipe, checking for errors */ if (pclose (ps_pipe) != 0) { fprintf (stderr, "Could not run ps, or other error.\n"); }
151
/* Send output of ps -A to grep init, with two newlines */ fprintf (grep_pipe, "%s\n\n", my_string); /* Close grep_pipe, cehcking for errors */ if (pclose (grep_pipe) != 0) { fprintf (stderr, "Could not run grep, or other error.\n"); } /* Exit! */ return 0; }
152
Most functions that accept le name arguments can detect the following error conditions. These are known as the usual le name errors. The names of the errors, such as EACCES, are compounded of E for error and a term indicating the type of error, such as ACCES for access. EACCES The program is not permitted to search within one of the directories in the le name.
ENAMETOOLONG Either the full le name is too long, or some component is too long. GNU does not limit the overall length of le names, but depending on which le system you are using, the length of component names may be limited. (For example, you may be running GNU/Linux but accessing a Macintosh HFS disk; the names of Macintosh les cannot be longer than 31 characters.) ENOENT ENOTDIR ELOOP Either some component of the le name does not exist, or some component is a symbolic link whose target le does not exist. One of the le name components that is supposed to be a directory is not a directory. Too many symbolic links had to be followed to nd the le. (GNU has a limit on how many symbolic links can be followed at once, as a basic way to detect recursive (looping) links.)
You can display English text for each of these errors with the m conversion specier of the printf function, as in the following short example. errno = EACCES; printf ("errno string (EACCES): %m\n"); This example prints the following string: errno string (EACCES): Permission denied See Section 16.2.2.2 [Formatted output conversion speciers], page 126, for more information on the m conversion specier.
153
The following ags are the more important ones for a beginning C programmer to know. There are a number of le status ags which are relevant only to more advanced programmers; for more details, see section File Status Flags in The GNU C Library Reference Manual.) Note that these ags are dened in macros in the GNU C Library header le fcntl.h, so remember to insert the line #include <fcntl.h> at the beginning of any source code le that uses them. O_RDONLY O_WRONLY O_RDWR O_READ Same as O_RDWR. GNU systems only. O_WRITE O_EXEC O_CREAT O_EXCL O_TRUNC Same as O_WRONLY. GNU systems only. Open the le for executing. GNU systems only. The le will be created if it doesnt already exist. If O_CREAT is set as well, then open fails if the specied le exists already. Set this ag if you want to ensure you will not clobber an existing le. Truncate the le to a length of zero bytes. This option is not useful for directories or other such special les. You must have write permission for the le, but you do not need to open it for write access to truncate it (under GNU). Open the le for appending. All write operations then write the data at the end of the le. This is the only way to ensure that the data you write will always go to the end of the le, even if there are other write operations happening at the same time. Open the le for read access. Open the le for write access. Open the le for both read and write access. Same as O_RDONLY | O_WRONLY.
O_APPEND
The open function normally returns a non-negative integer le descriptor connected to the specied le. If there is an error, open will return -1 instead. In that case, you can check the errno variable to see which error occurred. In addition to the usual le name errors, open can set errno to the following values. (It can also specify a few other errors of interest only to advanced C programmers. See section Opening and Closing Files in The GNU C Library Reference Manual, for a full list of error values. See Section 16.5.1 [Usual le name errors], page 151, for a list of the usual le name errors.). EACCES The le exists but is cannot be does not have read or write access (as requested), or the le does not exist but cannot be created because the directory does not have write access. Both O_CREAT and O_EXCL are set, and the named le already exists. To open it would clobber it, so it will not be opened. Write access to the le was requested, but the le is actually a directory. Your program has too many les open.
154
The le named does not exist, and O_CREAT was not specied, so the le will not be created. The le cannot be created, because the disk is out of space. The le is on a read-only le system, but either one of O_WRONLY, O_RDWR, or O_TRUNC was specied, or O_CREAT was set and the le does not exist.
See Section 16.5.3 [Closing les at a low level], page 154, for a code example using both the low-level le functions open and close.
Remember, close a stream by using fclose instead. This allows the necessary system bookkeeping to take place before the le is closed. Here is a code example using both the low-level le functions open and close. #include <stdio.h> #include <fcntl.h> int main() { char my_filename[] = "snazzyjazz17.txt"; int my_file_descriptor, close_err;
155
/* Open my_filename for writing. Do not clobber it if it does. */ my_file_descriptor = open (my_filename, O_WRONLY | O_CREAT | O_EXCL); if (my_file_descriptor == -1) { printf ("Open failed.\n"); } close_err = close (my_file_descriptor); if (close_err == -1) { printf ("Close failed.\n"); } return 0; } Running the above code example for the rst time should produce no errors, and should create an empty text le called snazzyjazz17.txt. Running it a second time should display the following errors on your monitor, since the le snazzyjazz17.txt already exists, and should not be clobbered according to the ags passed to open. Open failed. Close failed. Create it if it does not exist.
156
tion 16.5.1 [Usual le name errors], page 151.) The read function can also return some other error conditions in errno that are mostly of interest to advanced C programmers. (See section Input and Output Primitives in The GNU C Library Reference Manual, for more information.) EBADF EIO The le descriptor passed to read is not valid, or is not open for reading. There was a hardware error. (This error code also applies to more abstruse conditions detailed in the GNU C Library manual.)
See Section 16.5.5 [Writing les at a low level], page 156, for a code example that uses the read function.
In addition to the error codes above, write can return some error codes that are mainly of interest to advanced C programmers. If write fails, you should check errno to see if the error was EINTR; if it was, you should repeat the write call each time. Even though low-level le routines do not use buering, and once you call write, your data can be read from the le immediately, it may take up to a minute before your data is physically written to disk. You can call the fsync routine (see below) to ensure that all data is written to the le; this usage is roughly analogous to the high-level le routine fflush. The fsync routine takes a single parameter, the le descriptor to synchronise. It does not return a value until all data has been written. If no error occurred, it returns a 0; otherwise, it returns -1 and sets the system variable errno to one of the following values:
157
EBADF EINVAL
The le descriptor specied is invalid. No synchronization is possible because the system does not implement it.
Here is a code example that demonstrates the use of the write, read, and fsync functions. (See Section 16.5.4 [Reading les at a low level], page 155, for more information on read.) #include <stdio.h> #include <fcntl.h> int main() { char my_write_str[] = "1234567890"; char my_read_str[100]; char my_filename[] = "snazzyjazz.txt"; int my_file_descriptor, close_err; /* Open the file. Clobber it if it exists. */ my_file_descriptor = open (my_filename, O_RDWR | O_CREAT | O_TRUNC); /* Write 10 bytes of data and make sure its written */ write (my_file_descriptor, (void *) my_write_str, 10); fsync (my_file_descriptor); /* Seek the beginning of the file */ lseek (my_file_descriptor, 0, SEEK_SET); /* Read 10 bytes of data */ read (my_file_descriptor, (void *) my_read_str, 10); /* Terminate the data weve read with a null character */ my_read_str[10] = \0; printf ("String read = %s.\n", my_read_str); close (my_file_descriptor); return 0; }
158
the oset is relative to the beginning of the le (SEEK_SET), to the current le position (SEEK_CUR), or to the end of the le (SEEK_END). If SEEK_CUR or SEEK_END is used, the oset specied can be positive or negative. If you specify SEEK_END, set the position past the current end of the le, and actually write data, you will extend the le with zeroes up to the position you specify. However, the blocks of zeroes are not actually written to disk, so the le takes up less space on disk than it seems to; this is called a sparse le. The return value of lseek is of type off_t and normally contains the resulting le position, as measured in bytes from the beginning of the le. If you wish to read the current le position, therefore, you can specify an oset of 0 and a third parameter of SEEK_CUR, as follows: le position = lseek (le descriptor, 0, SEEK_CUR); If there was an error, lseek returns a -1 and sets the system variable errno to one of the following values: EBADF EINVAL ESPIPE The le descriptor specied is invalid. Either the third parameter of lseek is invalid, or the le oset is invalid. The le descriptor corresponds to an object that cannot be positioned, such as a terminal device.
The lseek function is called by many high-level le position functions, including fseek, rewind, and ftell.
Questions
159
If you wish to delete a directory rather than an ordinary le, use the rmdir function. Simply pass it the name of an empty directory you wish to delete. It acts like unlink in most respects, except that it can return an extra error code in the system variable errno: ENOTEMPTY The directory was not empty, so cannot be deleted. This code is synonymous with EEXIST, but GNU always returns ENOTEMPTY.
EBUSY ENOTEMPTY
160
16.6 Questions
1. What are the following? 1. File name 2. File descriptor 3. Stream 2. What is a pseudo-device name? 3. Where does stdin usually get its input? 4. Where does stdout usually send its output? 5. Write a program that simply prints out the following string to the screen: 6.23e+00. 6. Investigate what happens when you type the wrong conversion specier in a program. e.g. try printing an integer with %f or a oating point number with %c. This is bound to go wrong but how will it go wrong? 7. What is wrong with the following statements? 1. printf (x); 2. printf ("%d"); 3. printf (); 4. printf ("Number = %d"); 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. Hint: if you dont know, try them in a program! What is a whitespace character? Write a program that aceepts two integers from the user, multiplies them together, and prints the answer on your printer. Try to make the input as safe as possible. Write a program that simply echoes all the input to the output. Write a program that strips all space characters out of the input and replaces each string of them with a single newline character. The scanf function always takes pointer arguments. True or false? What is the basic dierence between high-level and low-level le routines? Write a statement that opens a high level le for reading. Write a statement that opens a low level le for writing. Write a program that checks for illegal characters in text les. The only valid characters are ASCII codes 10, 13, and 32..126. What statement performs formatted writing to text les? Poke around in the header les on your system so you can see what is dened where.
161
162
As you can see, main now has arguments. The name of the variable argc stands for argument count; argc contains the number of arguments passed to the program. The name of the variable argv stands for argument vector. A vector is a one-dimensional array, and argv is a one-dimensional array of strings. Each string is one of the arguments that was passed to the program. For example, the command line gcc -o myprog myprog.c would result in the following values internal to GCC: argc argv[0] argv[1] argv[2] argv[3] 4 gcc -o myprog myprog.c
As you can see, the rst argument (argv[0]) is the name by which the program was called, in this case gcc. Thus, there will always be at least one argument to a program, and argc will always be at least 1. The following program accepts any number of command-line arguments and prints them out: #include <stdio.h> int main (int argc, char *argv[]) { int count; printf ("This program was called with \"%s\".\n",argv[0]); if (argc > 1) { for (count = 1; count < argc; count++) { printf("argv[%d] = %s\n", count, argv[count]); } } else { printf("The command had no other arguments.\n"); } return 0; } If you name your executable fubar, and call it with the command ./fubar a b c, it will print out the following text: This program was called with "./fubar". argv[1] = a argv[2] = b argv[3] = c
argp description
163
164
--option-name=value You may not type whitespace between the option name and the equals sign, or between the equals sign and the option value.
argp description
165
2. KEY: The integer key to pass to the PARSER function when parsing the current option; this is the same as the name of the current options short option, if it is a printable ASCII character. 3. ARG: The name of this options argument, if any. 4. FLAGS: Flags describing this option. You can specify multiple ags with logical OR (for example, OPTION_ARG_OPTIONAL | OPTION_ALIAS). Some of the available options are: OPTION_ARG_OPTIONAL: The argument to the current option is optional. OPTION_ALIAS: The current option is an alias for the previous option. OPTION_HIDDEN: Dont show the current option in --help output. 5. DOC: A documentation string for the current option; will be shown in --help output. 2. PARSER: A pointer to a function to be called by argp for each option parsed. It should return one of the following values: 0: Success. ARGP_ERR_UNKNOWN: The given key was not recognized. An errno value indicating some other error. (See Section 16.5.1 [Usual le name errors], page 151.) The parser function takes the following arguments: 1. KEY: An integer specifying which argument this is, taken from the KEY eld in each argp_option structure, or else a key with a special meaning, such as one of the following: ARGP_KEY_ARG: The current command-line argument is not an option. ARGP_KEY_END: All command-line arguments have been parsed. 2. ARG: The string value of the current command-line argument, or NULL if it has none. 3. STATE: A pointer to an argp_state structure, containing information about the parsing state, such as the following elds: 1. input: The same as the last parameter to argp_parse. We use this in the main code example below to pass information between the main and parse_ opt functions. 2. arg_num: The number of the current non-option argument being parsed. 3. ARGS_DOC: If non-zero, a string describing how the non-option arguments should look. It is only used to print the Usage: message. If it contains newlines, the strings separated by them are considered alternative usage patterns, and printed on separate lines (subsequent lines are preceded by or: rather than Usage:.
166
4. DOC: If non-zero, a descriptive string about this program. It will normally be printed before the options in a help message, but if you include a vertical tab character (\v), the part after the vertical tab will be printed following the options in the output to the --help option. Conventionally, the part before the options is just a short string that says what the program does, while the part afterwards is longer and describes the program in more detail.
There are also some utility functions associated with argp, such as argp_usage, which prints out the standard usage message. We use this function in the parse_opt function in the following example. See section Functions For Use in Argp Parsers in The GNU C Library Reference Manual, for more of these utility functions.
Here is a code example that uses argp to parse command-line options. Remember, to compile this example, copy it to a le called something like argex.c, then compile it with the command gcc -o argex argex.c and run the resulting binary with the command ./argex.
#include <stdio.h> #include <argp.h> const char *argp_program_version = "argex 1.0"; const char *argp_program_bug_address = "<[email protected]>"; /* This structure is used by main to communicate with parse_opt. */ struct arguments { char *args[2]; /* ARG1 and ARG2 */ int verbose; /* The -v flag */ char *outfile; /* Argument for -o */ char *string1, *string2; /* Arguments for -a and -b */ };
argp example
167
/* OPTIONS. Field 1 in ARGP. Order of fields: {NAME, KEY, ARG, FLAGS, DOC}. */ static struct argp_option options[] = { {"verbose", v, 0, 0, "Produce verbose output"}, {"alpha", a, "STRING1", 0, "Do something with STRING1 related to the letter A"}, {"bravo", b, "STRING2", 0, "Do something with STRING2 related to the letter B"}, {"output", o, "OUTFILE", 0, "Output to OUTFILE instead of to standard output"}, {0} }; /* PARSER. Field 2 in ARGP. Order of parameters: KEY, ARG, STATE. */ static error_t parse_opt (int key, char *arg, struct argp_state *state) { struct arguments *arguments = state->input; switch (key) { case v: arguments->verbose break; case a: arguments->string1 break; case b: arguments->string2 break; case o: arguments->outfile break;
= 1;
= arg;
= arg;
= arg;
168
case ARGP_KEY_ARG: if (state->arg_num >= 2) { argp_usage(state); } arguments->args[state->arg_num] = arg; break; case ARGP_KEY_END: if (state->arg_num < 2) { argp_usage (state); } break; default: return ARGP_ERR_UNKNOWN; } return 0; } /* ARGS_DOC. Field 3 in ARGP. A description of the non-option command-line arguments that we accept. */ static char args_doc[] = "ARG1 ARG2"; /* DOC. Field 4 in ARGP. Program documentation. */ static char doc[] = "argex -- A program to demonstrate how to code command-line options and arguments.\vFrom the GNU C Tutorial."; /* The ARGP structure itself. */ static struct argp argp = {options, parse_opt, args_doc, doc}; /* The main function. Notice how now the only function call needed to process all command-line options and arguments nicely is argp_parse. */ int main (int argc, char **argv) { struct arguments arguments; FILE *outstream;
argp example
169
char waters[] = "a place to stay enough to eat somewhere old heroes shuffle safely down the street where you can speak out loud about your doubts and fears and whats more no-one ever disappears you never hear their standard issue kicking in your door you can relax on both sides of the tracks and maniacs dont blow holes in bandsmen by remote control and everyone has recourse to the law and no-one kills the children anymore and no-one kills the children anymore --\"the gunners dream\", Roger Waters, 1983\n"; /* Set argument defaults */ arguments.outfile = NULL; arguments.string1 = ""; arguments.string2 = ""; arguments.verbose = 0; /* Where the magic happens */ argp_parse (&argp, argc, argv, 0, 0, &arguments); /* Where do we send output? */ if (arguments.outfile) outstream = fopen (arguments.outfile, "w"); else outstream = stdout; /* Print argument values */ fprintf (outstream, "alpha = %s\nbravo = %s\n\n", arguments.string1, arguments.string2); fprintf (outstream, "ARG1 = %s\nARG2 = %s\n\n", arguments.args[0], arguments.args[1]); /* If in verbose mode, print song stanza */ if (arguments.verbose) fprintf (outstream, waters); return 0; } Compile the code, then experiment! For example, here is the program output if you simply type argex: Usage: argex [OPTION...] ARG1 ARG2 Try argex --help or argex --usage for more information. Here is the output from argex --usage:
170
Usage: argex [-v?V] [-a STRING1] [-b STRING2] [-o OUTFILE] [--alpha=STRING1] [--bravo=STRING2] [--output=OUTFILE] [--verbose] [--help] [--usage] [--version] ARG1 ARG2
Usage: argex [OPTION...] ARG1 ARG2 argex -- A program to demonstrate how to code command-line options and arguments. -a, -b, -o, -v, -?, --alpha=STRING1 --bravo=STRING2 --output=OUTFILE --verbose --help --usage -V, --version Do something with STRING1 related to the letter A Do something with STRING2 related to the letter B Output to OUTFILE instead of to standard output Produce verbose output Give this help list Give a short usage message Print program version
Mandatory or optional arguments to long options are also mandatory or optional for any corresponding short options. From the GNU C Tutorial. Report bugs to <[email protected]>.
And nally, here is the output from argex --verbose -a 123 --bravo=456 Foo Bar:
Environment variables
171
alpha = 123 bravo = 456 ARG1 = Foo ARG2 = Bar a place to stay enough to eat somewhere old heroes shuffle safely down the street where you can speak out loud about your doubts and fears and whats more no-one ever disappears you never hear their standard issue kicking in your door you can relax on both sides of the tracks and maniacs dont blow holes in bandsmen by remote control and everyone has recourse to the law and no-one kills the children anymore and no-one kills the children anymore --"the gunners dream", Roger Waters, 1983 You can of course also send the output to a text le with the -o or --output option.
172
#include <stdio.h> /* To shorten example, not using argp */ int main (int argc, char *argv[], char *envp[]) { return 0; } Notice that envp is an array of strings, just as argv is. It consists of a list of the environment variables of your shell, in the following format: NAME=value Just as you can manually process command-line options from argv, so can you manually process environment variables from envp. However, the simplest way to access the value of an environment variable is with the getenv function, dened in the system header stdlib.h. It takes a single argument, a string containing the name of the variable whose value you wish to discover. It returns that value, or a null pointer if the variable is not dened. #include <stdio.h> #include <stdlib.h> /* To shorten example, not using argp */ int main (int argc, char *argv[], char *envp[]) { char *home, *host; home = getenv("HOME"); host = getenv("HOSTNAME"); printf ("Your home directory is %s on %s.\n", home, host); return 0; } When you run this code, it will print out a line like the following one. Your home directory is /home/rwhe on linnaeus. Note: Do not modify strings returned from getenv; they are pointers to data that belongs to the system. If you want to process a value returned from getenv, copy it to another string rst with strcpy. (See Chapter 15 [Strings], page 105.) If you want to change an environment variable from within your program (not usually advisable), use the putenv, setenv, and unsetenv functions. See section Environment Access in The GNU C Library Reference Manual, for more information on these functions.
Writing a makele
173
gcc -o executable sourcele.c you would type gcc -o executable sourcele 1.c sourcele 2.c ... sourcele n.c For example, if you were building a simple database program called mydb, the command line might look something like this: gcc -o mydb main.c keyboard_io.c db_access.c sorting.c Of course, if (say) db_access.c were lengthy, it might take a long time to compile your program every time you executed this command, even if you only made a small change in one of the other les. To avoid this, you might want to compile each of the source les into its own object le, then link them together to make your program. If you did, each time you made a small change in one le, you need only recompile that single le and then link the object les together again, potentially a great savings in time and patience. Here is how to generate a permanent object le for db_access.c. gcc -c db_access.c This would generate a permanent object code le called db_access.o, indicated by the sux .o. You would perform this step when needed for each of the source code les, then link them together with the following command line: gcc -o mydb main.o keyboard_io.o db_access.o sorting.o You might even put the various commands into a shell le, so that you wouldnt need to type them repeatedly. For example, you could put the last command line into a shell le called build, so that all you would need to do to build your executable from object code les is type the following line. ./build For programs on a very small scale, this approach works quite well. If your project grows even slightly complex, however, you will have a hard time keeping track of which object les are fresh and which need to be recreated because the corresponding source les have been changed since their last compilation. Thats where the GNU utility make comes in. (See Section 17.5 [Writing a makele], page 173.)
174
Your makele describes the relationships among les in your program and provides commands for updating each le. In a program, typically, the executable le is updated from object les, which are in turn made by compiling source les. Once a suitable makele exists, each time you change some source les, this simple shell command: make suces to perform all necessary recompilations. The make program uses the makele database and the last-modication times of the les to decide which of the les need to be updated. For each of those les, it issues the commands recorded in the database. You can provide command line arguments to make to control which les should be recompiled, or how. When make recompiles the editor, each changed C source le must be recompiled. If a header le has changed, each C source le that includes the header le must be recompiled to be safe. Each compilation produces an object le corresponding to the source le. Finally, if any source le has been recompiled, all the object les, whether newly made or saved from previous compilations, must be linked together to produce the new executable editor.
A simple makele
175
176
be updated rst. In this example, edit depends on each of the eight object les; the object le main.o depends on the source le main.c and on the header le defs.h. A shell command follows each line that contains a target and prerequisites. These shell commands tell make how to update the target le. A tab character must come at the beginning of every command line to distinguish command lines from other lines in the makele. (Bear in mind that make does not know anything about how the commands work. It is up to you to supply commands that will update the target le properly.) The target clean is not a le, but merely the name of an action. Since this action is not carried out as part of the other targets, clean is not a prerequisite of any other rule. Consequently, make never does anything with it unless you explicitly type make clean. Not only is this rule not a prerequisite, it does not have any prerequisites itself, so the only purpose of the rule is to run the specied commands. Targets like clean that do not refer to les but are just actions are called phony targets.
177
make will recompile the object les kbd.o, command.o and files.o, and then link the le edit.
In our example, we had to list all the object les twice in the rule for edit (repeated here):
edit : main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o cc -o edit main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o
Such duplication is error-prone; if a new object le is added to the system, we might add it to one list and forget the other. We can eliminate the risk and simplify the makele by using a variable. Variables in make enable a text string to be dened once and substituted in multiple places later. They are similar to C macros. (See Section 12.2 [Macros], page 74.)
It is standard practice for every makele to have a variable named objects, OBJECTS, objs, OBJS, obj, or OBJ that is a list of all object le names. We would dene such a variable objects with a line like this in the makele:
Then, in every place we want to put a list of the object le names, we can substitute the variables value by writing $(objects)
Here is how the complete simple makele looks when you use a variable for the object les:
178
objects = main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o edit : $(objects) cc -o edit $(objects) main.o : main.c defs.h cc -c main.c kbd.o : kbd.c defs.h command.h cc -c kbd.c command.o : command.c defs.h command.h cc -c command.c display.o : display.c defs.h buffer.h cc -c display.c insert.o : insert.c defs.h buffer.h cc -c insert.c search.o : search.c defs.h buffer.h cc -c search.c files.o : files.c defs.h buffer.h command.h cc -c files.c utils.o : utils.c defs.h cc -c utils.c clean : rm edit $(objects)
It is not necessary to spell out the commands for compiling the individual C source les, because make can gure them out: it has an implicit rule for updating a .o le from a correspondingly named .c le using a gcc -c command. For example, it will use the command gcc -c main.c -o main.o to compile main.c into main.o. We can therefore omit the commands from the rules for the object les.
When a .c le is used automatically in this way, it is also automatically added to the list of prerequisites. We can therefore omit the .c les from the prerequisites, provided we omit the commands.
Here is the entire example, with both of these changes, and the variable objects as suggested above:
179
objects = main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o edit : $(objects) cc -o edit $(objects) main.o : defs.h kbd.o : defs.h command.h command.o : defs.h command.h display.o : defs.h buffer.h insert.o : defs.h buffer.h search.o : defs.h buffer.h files.o : defs.h buffer.h command.h utils.o : defs.h .PHONY : clean clean : -rm edit $(objects) This is how we would write the makele in actual practice. (See Section 17.5.7 [Rules for cleaning the directory], page 180, for the complications associated with clean.) Because implicit rules are so convenient, they are important. You will see them used frequently.
When the objects of a makele are created by implicit rules alone, an alternative style of makele is possible. In this style of makele, you group entries by their prerequisites instead of by their targets. Here is an example of this alternative style: objects = main.o kbd.o command.o display.o \ insert.o search.o files.o utils.o edit : $(objects) cc -o edit $(objects) $(objects) : defs.h kbd.o command.o files.o : command.h display.o insert.o search.o files.o : buffer.h Here defs.h is given as a prerequisite of all the object les, and command.h and buffer.h are prerequisites of the specic object les listed for them. Whether this is better is a matter of taste: it is more compact, but some people dislike it because they nd it clearer to put all the information about each target in one place.
180
Compiling a program is not the only thing you might want to write rules for. Makeles commonly do a few other things besides compiling a program: for example, they can often delete all the object les and executables so that the directory is clean. Here is how we could write a make rule for cleaning our example editor: clean: rm edit $(objects) In practice, we might want to write the rule in a somewhat more complicated manner to handle unanticipated situations. For example: .PHONY : clean clean : -rm edit $(objects) This prevents make from getting confused by an actual le called clean and causes it to continue in spite of errors from rm. A rule such as this should not be placed at the beginning of the makele, because we do not want it to run by default! Thus, in the example makele, we want the rule for edit, which recompiles the editor, to remain the default goal. Since clean is not a prerequisite of edit, this rule will not run at all if we give the command make with no arguments. In order to run the rule, we have to type make clean.
We explored what libraries are and how to use them in a previous chapter. (See Chapter 13 [Libraries], page 81, if you need to refresh your memory.) You may have wondered how libraries are written in the rst place. Is the whole process too complicated for a mortal C programmer to attempt? Not at all. Suppose you have a function (or set of functions) that you would like to use widely across the various C programs you write. You might even like to make it available to other users in a convenient way. To create a code library that will enable you to achieve this, follow the sequence below. We will use a code example, but you can create your own library by taking similar steps. 1. Heres an example of the kind of function you might like to use in multiple programs. It accepts one string containing some text to print, and then prints it on the default printer. For the sake of example, the le below is named lpr_print.c.
Building a library
181
#include <stdio.h> void lpr_print (char *the_text) { FILE *printer; printer = popen ("lpr", "w"); fprintf (printer, the_text); pclose (printer); } (See Section 16.4 [Programming with pipes], page 149, for the rationale behind this function.) 2. Now we will create a library. To create a static library called liblprprint.a containing this function, just type the following two command lines in your GNU shell: gcc -c lpr_print.c ar rs liblprprint.a lpr_print.o The -c option to gcc produces only a .o object code le, without linking it, while the ar command (with its rs options) permits the creation of an archive le, which can contain a bundle of other les that can be re-extracted later (for example, when executing library code). In this case, we are only archiving one object code le, but in some cases, you might want to archive multiple ones. (See the man page for ar for more information.) To create a shared library called liblprprint.so instead, enter the following sequence of commands:1 gcc -c -fpic lpr_print.c gcc -shared -o liblprprint.so lpr_print.o (For the record, pic stands for position-independent code, an object-code format required for shared libraries. You might need to use the option -fPIC instead of -fpic if your library is very large.) 3. Now create a header le that will allow users access to the functions in your library. You should provide one function prototype for each function in your library. Here is a header le for the library we have created, called liblprprint.h.
1
To create library les containing multiple object les, simply include the object les on the same command line. For example, to create a static library with multiple object les, type a command such as ar rs liblprprint.a lpr_print.o lpr_print2.o lpr_ print3.o. Similarly, to create a shared library, type gcc -shared -o liblprprint.so lpr_print.o lpr_print2.o lpr_print3.o.
182
/* liblprprint.h: routines in liblprprint.a and liblprprint.so */ extern void lpr_print (char *the_text); 4. Now you should put your libraries and include le somewhere your code can access them. For the sake of this example, create the directories include and lib in your home directory. Once you have done so, move the .a and .so les you have created to lib, and the .h le to include. 5. If you have taken the last step, and you want to run a program linked to a shared version of your library, you should type a line like the following into your shell (the following command line assumes you are using the Bash shell and that your home directory is named /home/fred): export LD_LIBRARY_PATH=/home/fred/lib:$LD_LIBRARY_PATH This command line sets an environment variable that makes the linker search the /home/fred/lib directory before it searches anywhere else. You can include it in your .bashrc or .bash_profile le. If you dont execute this command before you attempt to run a program using your shared library, you will probably receive an error. 6. Now you can write programs that use your library. Consider the following short program, called printer.c: #include <liblprprint.h> /* To shorten example, not using argp */ int main () { lpr_print ("Hello, Multiverse!\nHowarya?\n"); return 0; } To compile this program using your static library, type something like the following command line: gcc --static -I../include -L../lib -o printer printer.c -llprprint The --static option forces your static library to be linked; the default is your shared version. The -llprprint option makes GCC link in the liblprprint library, just as you would need to type -lm to link in the libm math library. The -I../include and -L../lib options specify that the compiler should look in the ../include directory for include les and in the ../lib directory for library les. This assumes that you have created the include and lib directories in your home directory as outlined above, and that you are compiling your code in a subdirectory of your home directory. If you are working two directories down, you would specify -I../../include, and so on.
Questions
183
The above command line assumes you are using only one .c source code le; if you are using more than one, simply include them on the command line as well. (See Section 17.4 [Compiling multiple les], page 172.) Note: Using the --static option will force the compiler to link all libraries you are using statically. If you want to use the static version of your library, but some shared versions of other libraries, you can omit the --static option from the command line and specify the static version of your library explicitly, as follows: gcc -I../include -L../lib -o printer printer.c ../lib/liblprprint.a To compile this program using your shared library, type something like the following command line. gcc -I../include -L../lib -o printer printer.c -llprprint 7. The executable produced is called printer. Try it!
17.7 Questions
1. 2. 3. 4. 5. What What What What What is the name of the preferred method for handling command-line options? does the -c option of the gcc command do? information does the argc variable contain? information does the argv variable contain? information does the envp variable contain?
184
Hidden assignments
185
18 Advanced operators
Concise expressions In this chapter, we will examine some advanced mathematical and logical operators in C.
186
b = (c = 0); or simply: b = c = 0; These equivalent statements set b and c to the value 0, provided b and c are of the same type. They are equivalent to the more usual: b = 0; c = 0; Note: Dont confuse this technique with a logical test for equality. In the above example, both b and c are set to 0. Consider the following, supercially similar, test for equality, however: b = (c == 0); In this case, b will only be assigned a zero value (FALSE) if c does not equal 0. If c does equal 0, then b will be assigned a non-zero value for TRUE, probably 1. (See Section 7.8 [Comparisons and logic], page 37, for more information.) Any number of these assignments can be strung together: a = (b = (c = (d = (e = 5)))); or simply: a = b = c = d = e = 5; This elegant syntax compresses ve lines of code into a single line. There are other uses for treating assignment expressions as values. Thanks to Cs exible syntax, they can be used anywhere a value can be used. Consider how an assignment expression might be used as a parameter to a function. The following statement gets a character from standard input and passes it to a function called process_character. process_character (input_char = getchar()); This is a perfectly valid statement in C, because the hidden assignment statements passes the value it assigns on to process_character. The assignment is carried out rst and then the process_character function is called, so this is merely a more compact way of writing the following statements. input_char = getchar(); process_character (input_char); All the same remarks apply about the specialized assignment operators +=, *=, /=, and so on. The following example makes use of a hidden assignment in a while loop to print out all values from 0.2 to 20.0 in steps of 0.2.
187
#include <stdio.h> /* To shorten example, not using argp */ int main () { double my_dbl = 0; while ((my_dbl += 0.2) < 20.0) printf ("%lf ", my_dbl); printf ("\n"); return 0; }
18.1.2 Postx and prex ++ and -Increment (++) and decrement (--) expressions also have values, and like assignment expressions, can be hidden away in inconspicuous places. These two operators are slightly more complicated than assignments because they exist in two forms, postx (for example, my_var++) and prex (for example, ++my_var). Postx and prex forms have subtly dierent meanings. Take the following example: int my_int = 3; printf ("%d\n", my_int++); The increment operator is hidden in the parameter list of the printf call. The variable my_int has a value before the ++ operator acts on it (3) and afterwards (4). Which value is passed to printf? Is my_int incremented before or after the printf call? This is where the two forms of the operator (postx and prex) come into play. If the increment or decrement operator is used as a prex, the operation is performed before the function call. If the operator is used as a postx, the operation is performed after the function call. In the example above, then, the value passed to printf is 3, and when the printf function returns, the value of my_int is incremented to 4. The alternative is to write int my_int = 3; printf ("%d\n", ++my_int); in which case the value 4 is passed to printf. The same remarks apply to the decrement operator as to the increment operator.
188
#include <stdio.h> #define ARRAY_SIZE 20 /* To shorten example, not using argp */ int main () { int idx, array[ARRAY_SIZE]; for (idx = 0; idx < ARRAY_SIZE; array[idx++] = 0) ; return 0; } This is a convenient way to initialize an array to zero. Notice that the body of the loop is completely empty! Strings can benet from hidden operators as well. If the standard library function strlen, which nds the length of a string, were not available, it would be easy to write it with hidden operators: #include <stdio.h> int my_strlen (char *my_string) { char *ptr; int count = 0; for (ptr = my_string; *(ptr++) != \0; count++) ; return (count); } /* To shorten example, not using argp */ int main (int argc, char *argv[], char *envp[]) { char string_ex[] = "Fabulous!"; printf ("String = %s\n", string_ex); printf ("Length = %d\n", my_strlen (string_ex)); return 0; } The my_strlen function increments count while the end of string marker \0 is not found. Again, notice that the body of the loop in this function is completely empty.
Machine-level operators
189
Overuse of hidden operators can produce code that is dicult to understand. See Section 22.6 [Hidden operators and style], page 229, for some cautions about when not to use them.
190
The only dierence between a text string and a oating-point value is the way we interpret the pattern of bits in the computers memory. For the most part, we can simply ignore the low level of the computer in which computer data appears as bit strings. Systems programmers, on the other hand, such as those who wrote GNU/Linux, must frequently manipulate bits directly in order to handle ags. A ag is a bit in a bit string that can be either set (1) or cleared (0). We have run across a few ags already, such as the various ags passed to the GNU C Library functions open; the ags O_RDONLY and O_WRONLY are actually macros that specify binary values, which can be manipulated and examined with binary OR and similar functions. Flags are normally declared as integers in C. Programmers who perform bit operations on a regular basis often use either octal (base8) or hexadecimal (base-16) numbers, because every octal digit species exactly three bits, and every hexadecimal digit species four.
The meaning and syntax of these operators is given below. Dont confuse bitwise operators (such as bitwise AND, &) with logical operators (such as logical AND, &&). Bitwise operators operate on each bit in the operand individually.
191
Bit-shift operators move whole bit strings left or right. The syntax of the bit-shift left operation is value << positions; that of bit-shift right is value >> positions; So for example, using the bit string (1) above, the value of 1 << 1 is 2, because the bit string would have been moved one position to the left: 128 64 32 16 8 4 2 1 ------------------------------| 0 | 0 | 0 | 0 | 0 | 0 | 1 | 0 | -------------------------------
Notice how the space to the right of the shifted bit string is simply lled with a 0. Similarly, the value of 1 << 4 is 16, because the original bit string is shifted left four places: 128 64 32 16 8 4 2 1 ------------------------------| 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 | -------------------------------
16
Notice, again, that the spaces to the right of the original bit string are lled out with zeros. Now for a slightly more dicult one. The value of 6 << 2 is 24. Here is the bit string representing 6: 128 64 32 16 8 4 2 1 ------------------------------| 0 | 0 | 0 | 0 | 0 | 1 | 1 | 0 | ------------------------------Shift 6 left 2 places: 128 64 32 16 8 4 2 1 ------------------------------| 0 | 0 | 0 | 1 | 1 | 0 | 0 | 0 | -------------------------------
24
Notice that every shift left multiplies by 2. (Since 6 << 2 means to shift 6 left twice, the result is 24.) As you might expect, every shift right performs (integer) division by two on the number. If a bit is shifted beyond the ones position (the rightmost box), however, then it drops o and is lost. So the following equalities hold: 1 2 2 n >> >> >> >> 1 1 2 n == == == == 0 1 0 0
One common use of bit-shifting is to scan through the bits of a bit-string one by one in a loop. This is done with bit masks, as described in the next section.
192
Masks
193
Bitwise XOR operates on two values, for example 0 ^ 1. The result is 1 if the rst value or the second value is 1, but not if both are 1 (hence the name exclusive OR). As a truth table this would be summarized as follows: value1 0 0 1 1 value2 0 1 0 1 result 0 1 1 0
18.3.3.5 Masks
Bit strings and bitwise operators are often used to make masks. A mask is a bit string that ts over another bit string and produces a desired result, such as singling out particular bits from the second bit string, when the two bit strings are operated upon. This is particularly useful for handling ags; programmers often wish to know whether one particular ag is set in a bit string, but may not care about the others. For example, you might create a mask that only allows the ag of interest to have a non-zero value, then AND that mask with the bit string containing the ag. Consider the following mask, and two bit strings from which we want to extract the nal bit: mask = 00000001 value1 = 10011011 value2 = 10011100 mask & value1 == 00000001 mask & value2 == 00000000 The zeros in the mask mask o the rst seven bits and only let the last bit show through. (In the case of the rst value, the last bit is 1; in the case of the second value, the last bit is 0.) Alternatively, masks can be built up by operating on several ags, usually with inclusive OR: flag1 = 00000001 flag2 = 00000010 flag3 = 00000100 mask = flag1 | flag2 | flag3 mask == 00000111 See Section 16.5.2 [Opening les at a low level], page 152, for a code example that actually uses bitwise OR to join together several ags. It should be emphasized that the ag and mask examples are written in pseudo-code, that is, a means of expressing information that resembles source code, but cannot be compiled. It is not possible to use binary numbers directly in C.
194
The following code example shows how bit masks and bit-shifts can be combined. It accepts a decimal number from the user between 0 and 128, and prints out a binary number in response.
Questions 18
195
#include <stdio.h> #define NUM_OF_BITS 8 /* To shorten example, not using argp */ int main () { char *my_string; int input_int, args_assigned; int nbytes = 100; short my_short, bit; int idx; /* This hex number is the same as binary 10000000 */ short MASK = 0x80; args_assigned = 0; input_int = -1; while ((args_assigned != 1) || (input_int < 0) || (input_int > 128)) { puts ("Please enter an integer from 0 to 128."); my_string = (char *) malloc (nbytes + 1); getline (&my_string, &nbytes, stdin); args_assigned = sscanf (my_string, "%d", &input_int); if ((args_assigned != 1) || (input_int < 0) || (input_int > 128)) puts ("\nInput invalid!"); } my_short = (short) input_int; printf ("Binary value = "); /* Convert decimal numbers into binary Keep shifting my_short by one to the left and test the highest bit. This does NOT preserve the value of my_short! */ for (idx = 0; idx < NUM_OF_BITS; idx++) { bit = my_short & MASK; printf ("%d", bit/MASK); my_short <<= 1; } printf ("\n"); return 0; }
196
18.4 Questions 18
1. Hidden operators can be used in return statements, for example, return (++x); Would there be any point in writing the following? return (x++); 2. What distinguishes a bit string from an ordinary variable? Can any variable be a bit string? 3. What is the dierence between an inclusive OR operation and an exclusive OR operation? 4. Find out what the decimal values of the following operations are. 1. 7 & 2 2. 1 & 1 3. 15 & 3 4. 15 & 7 5. 15 & 7 & 3 Try to explain the results. (Hint: sketch out the numbers as bit strings.) 5. Find out what the decimal values of the following operations are. 1. 1 | 2 2. 1 | 2 | 3 6. Find out the decimal values of the following operations. 1. 1 & (~1) 2. 23 & (~23) 3. 2012 & (~2012) (Hint: write a short program to work them out.)
enum
197
In addition, there are two data types called struct and union that are so important, they have received their own chapter. (See Chapter 20 [Data structures], page 205, for more information on struct and union.)
19.1 enum
The enum type specier is short for enumerated data. The user can dene a xed set of words that a variable of type enum can take as its value. The words are assigned integer values by the compiler so that code can compare enum variables. Consider the following code example: #include <stdio.h> /* To shorten example, not using argp */ int main () { enum compass_direction { north, east, south, west }; enum compass_direction my_direction; my_direction = west; return 0; } This example denes an enumerated variable type called compass_direction, which can be assigned one of four enumerated values: north, east, south, or west. It then declares a variable called my_direction of the enumerated compass_direction type, and assigns my_direction the value west. Why go to all this trouble? Because enumerated data types allow the programmer to forget about any numbers that the computer might need in order to process a list of words,
198
and simply concentrate on using the words themselves. Its a higher-level way of doing things; in fact, at a lower level, the computer assigns each possible value in an enumerated data type an integer cconstant one that you do not need to worry about. Enumerated variables have a natural partner in the switch statement, as in the following code example. #include <stdio.h> enum compass_direction { north, east, south, west }; enum compass_direction get_direction() { return south; } /* To shorten example, not using argp */ int main () { enum compass_direction my_direction; puts ("Which way are you going?"); my_direction = get_direction(); switch (my_direction) { case north: puts("North? Say hello to the polar bears!"); break; case south: puts("South? Say hello to Tux the penguin!"); break; case east: puts("If you go far enough east, youll be west!"); break; case west: puts("If you go far enough west, youll be east!"); break; } return 0; } In this example, the compass_direction type has been made global, so that the get_ direction function can return that type. The main function prompts the user, Which way
void
199
are you going?, then calls the dummy function get_direction. In a real program, such a function would accept input from the user and return an enumerated value to main, but in this case it merely returns the value south. The output from this code example is therefore as follows: Which way are you going? South? Say hello to Tux the penguin! As mentioned above, enumerated values are converted into integer values internally by the compiler. It is practically never necessary to know what integer values the compiler assigns to the enumerated words in the list, but it may be useful to know the order of the enumerated items with respect to one another. The following code example demonstrates this. #include <stdio.h> /* To shorten example, not using argp */ int main () { enum planets { Mercury, Venus, Earth, Mars, Jupiter, Saturn, Uranus, Neptune, Pluto }; enum planets planet1, planet2; planet1 = Mars; planet2 = Earth; if (planet1 > planet2) puts ("Mars is farther from the Sun than Earth is."); else puts ("Earth is farther from the Sun than Mars is."); return 0; } The output from this example reads as follows: Mars is farther from the Sun than Earth is.
19.2 void
200
The void data type was introduced to make C syntactically consistent. The main reason for void is to declare functions that have no return value. The word void is therefore used in the sense of empty rather than that of invalid. C functions are considered by the compiler to return type int unless otherwise specied. Although the data returned by a function can legally be ignored by the function calling it, the void data type was introduced by the ANSI standard so that C compilers can issue warnings when an integer value is not returned by a function that is supposed to return one. If you want to write a function that does not return a value, simply declare it void. A function declared void has no return value and simply returns with the command return;. Variables can be declared void as well as functions: void my_variable; void *my_pointer; A variable that is itself declared void (such as my_variable above) is useless; it cannot be assigned a value, cannot be cast to another type, in fact, cannot be used in any way. Void pointers (type void *) are a dierent case, however. A void pointer is a generic pointer; any pointer can be cast to a void pointer and back without any loss of information. Any type of pointer can be assigned to (or compared with) a void pointer, without casting the pointer explicitly. Finally, a function call can be cast to void in order to explicitly discard a return value. For example, printf returns a value, but it is seldom used. Nevertheless, the two lines of code that follow are equivalent: printf ("Hullo!\n"); (void) printf ("Hullo!\n"); There is no good reason to prefer the second line to the rst, however, so using the more concise form is preferred.
19.3 volatile
The volatile type qualier was introduced by the ANSI Standard to permit the use of memory-mapped variables, that is, variables whose value changes autonomously based on input from hardware. One might declare a volatile variable volatile float temperature; whose value uctuated according to readings from a digital thermometer connected to the computer. There is another use for the volatile qualier that has to do with multiprocessing operating systems. Independent processes that share common memory might each change the value of a variable independently. The volatile keyword serves as a warning to the compiler that it should not optimize the code containing the variable (that is, compile it so that it will run in the most ecient way possible) by storing the value of the variable and referring to it repeatedly, but should reread the value of the variable every time. (Volatile variables are also agged by the compiler as not to be stored in read-only memory.)
Constant expressions
201
19.4 Constants
Constants in C usually refer to two things: either a type of variable whose value cannot change declared with the const qualier (in this case, variable is something of a misnomer), or a string or numeric value incorporated directly into C code, such as 1000. We will examine both kinds of constant in the next two sections.
19.4.1 const
Sometime a variable must be assigned a value once and once only; for example, it might be in read-only memory. The reserved word const is, like static and volatile, a data type qualier that can be applied to many dierent data types. It declares a variable to be a constant, whose value cannot be reassigned. A const must be assigned a value when it is declared. const double avogadro = 6.02e23; const int moon_landing = 1969; You can also declare constant arrays: const int my_array[] = {0, 1, 2, 3, 4, 5, 6, 7, 8}; Any attempt to assign a new value to a const variable will result in a compile-time error such as the following: const.c: In function main: const.c:11: warning: assignment of read-only variable avogadro
202
hexadecimal value with \x or an octal value with \. Consider the following code example, which demonstrates how to print the letter A, using either a hexadecimal character code (\x41) or an octal one (\101). #include <stdio.h> /* To shorten example, not using argp */ int main () { printf ("\\x41 hex = \x41\n"); printf ("\\101 octal = \101\n"); return 0; } The preceding code prints the following text: \x41 hex = A \101 octal = A Of course, you can assign a variable declared with the const qualier (the rst kind of constant we examined) a constant expression declared with one of the typographical expressions above. For example: const int my_hex_integer = 0xFF; const int my_octal_integer = 077; /* hex FF */ /* octal 77 */
19.6 typedef
You can dene your own data types in C with the typedef command, which may be written inside functions or in global scope. This statement is used as follows: typedef existing type new type; You can then use the new type to declare variables, as in the following code example, which declares a new type called my_type and declares three variables to be of that type.
Questions 19
203
#include <stdio.h> /* To shorten example, not using argp */ int main (int argc, char *argv[], char *envp[]) { typedef int my_type; my_type var1, var2, var3; var1 = 10; var2 = 20; var3 = 30; return 0; } The new type called my_type behaves just like an integer. Why, then, would we use it instead of integer? Actually, you will seldom wish to rename an existing data type. The most important use for typedef is in renaming structures and unions, whose names can become long and tedious to declare otherwise. Well investigate structures and unions in the next chapter. (See Chapter 20 [Data structures], page 205.)
19.7 Questions 19
1. Enumerated names are given integer values by the compiler so that it can do multiplication and division with them. True or false? 2. Does void do anything which C cannot already do without this type? 3. What type qualier might a variable accessed directly by a timer be given? 4. Write a statement which declares a new type "real" to be like the usual type "double". 5. Variables declared with the qualier const can be of any type. True or false?
204
Structure declarations
205
20 Data structures
Grouping data. Tidying up programs. It would be hard for a program to manipulate data if it were scattered around with no particular structure. C therefore has several facilities to group data together in convenient packages, or data structures. One type of data structure in C is the struct (or structure) data type, which is a group of variables clustered together with a common name. A related data type is the union, which can contain any type of variable, but only one at a time. Finally, structures and unions can be linked together into complex data structures such as lists and trees. This chapter explores all of these kinds of data structure. It is important to distinguish the terms structure and data structure. Data structure is a generic term that refers to any pattern of data in a computer program. An array is a data structure, as is a string. A structure is a particular data type in C, the struct; all struct variables (structures) are data structures, but not all data structures are structures.
20.1 struct
A structure is a group of one or more variables under a single name. Unlike arrays, structures can contain a combination of dierent types of data; they can even contain arrays. A structure can be arbitrarily complex. Every type of structure that is dened is given a name, and the variables it contains (called members) are also given names. Finally, every variable declared to be of a particular structure type has its own name as well, just as any other variable does.
206
computer will recognize them as dierent entities, with dierent values. This is similar to the naming convention for humans, where two dierent men may share the name "John Smith", but are recognized as being dierent people. Once you have declared a type of structure, you can declare variables to be of that type. For example: struct personal_data person0001; The statement above declares a variable called person0001 to be of type struct personal_data. This is probably the most common method of declaring a structure variable, but there are two equivalent methods. For example, a structure variable can be declared immediately after the declaration of the structure type: struct personal_data { char name[100]; char address[200]; int year_of_birth; int month_of_birth; int day_of_birth; } person0001;
Alternatively, the typedef command can be used to cut down on typing out code in the long term. The type denition is made once at the start of the program and subsequent variable declarations are made by using the new name, without the word struct: typedef struct { char name[100]; char address[200]; int year_of_birth; int month_of_birth; int day_of_birth; } personal_data; personal_data person001; personal_data person002; personal_data person003; Note that this use of the typedef command parallels the usage we have already seen: typedef existing type new type In the example above of using typedef to declare a new type of structure, the metasyntactic variable new type corresponds to the identier personal_data, and the metasyntactic variable existing type corresponds to the following code:
Using structures
207
struct { char name[100]; char address[200]; int year_of_birth; int month_of_birth; int day_of_birth; } Structure type and variable declarations can be either local or global, depending on their placement in the code, just as any other declaration can be.
208
Note that in order to declare this function, the struct personal_data type must be declared globally. Finally, a function that returns a structure variable would be declared thusly: struct personal_data structure_returning_fn () { struct personal_data random_person; return random_person; } Of course, random_person is a good name for the variable returned by this bare-bones function, because without unless one writes code to initialize it, it can only be lled with garbage values.
Just as arrays of basic types such as integers and oats are allowed in C, so are arrays of structures. An array of structures is declared in the usual way: struct personal_data my_struct_array[100]; The members of the structures in the array are then accessed by statements such as the following: The value of a member of a structure in an array can be assigned to another variable, or the value of a variable can be assigned to a member. For example, the following code assigns the number 1965 to the year_of_birth member of the fourth element of my_struct_array: my_struct_array[3].year_of_birth = 1965; (Like all other arrays in C, struct arrays start their numbering at zero.) The following code assigns the value of the year_of_birth member of the fourth element of my_struct_array to the variable yob: yob = my_struct_array[3].year_of_birth; Finally, the following example assigns the values of all the members of the second element of my_struct_array, namely my_struct_array[1], to the third element, so my_struct_ array[2] takes the overall value of my_struct_array[1]. my_struct_array[2] = my_struct_array[1];
Pointers to structures
209
struct first_structure_type { int integer_member; float float_member; }; struct second_structure_type { double double_member; struct first_structure_type struct_member; }; The rst structure type is incorporated as a member of the second structure type. You can initialize a variable of the second type as follows: struct second_structure_type demo; demo.double_member = 12345.6789; demo.struct_member.integer_member = 5; demo.struct_member.float_member = 1023.17; The member operator . is used to access members of structures that are themselves members of a larger structure. No parentheses are needed to force a special order of evaluation; a member operator expression is simply evaluated from left to right. In principle, structures can be nested indenitely. Statements such as the following are syntactically acceptable, but bad style. (See Chapter 22 [Style], page 227.) my_structure.member1.member2.member3.member4 = 5; What happens if a structure contains an instance of its own type, however? For example: struct regression { int int_member; struct regression self_member; }; In order to compile a statement of this type, your computer would theoretically need an innite amount of memory. In practice, however, you will simply receive an error message along the following lines: struct5.c: In function main: struct5.c:8: field self_member has incomplete type The compiler is telling you that self_member has been declared before its data type, regression has been fully declared naturally, since youre declaring self_member in the middle of declaring its own data type!
210
A pointer to a structure type variable is declared by a statement such as the following: struct personal_data *my_struct_ptr; The variable my_struct_ptr is a pointer to a variable of type struct personal_data. This pointer can be assigned to any other pointer of the same type, and can be used to access the members of its structure. According to the rules we have outlined so far, this would have to be done like so: struct personal_data person1; my_struct_ptr = &person1; (*my_struct_ptr).day_of_birth = 23; This code example says, in eect, Let the member day_of_birth of the structure pointed to by my_struct_ptr take the value 23. Notice the use of parentheses to avoid confusion about the precedence of the * and . operators. There is a better way to write the above code, however, using a new operator: ->. This is an arrow made out of a minus sign and a greater than symbol, and it is used as follows: my_struct_ptr->day_of_birth = 23; The -> enables you to access the members of a structure directly via its pointer. This statement means the same as the last line of the previous code example, but is considerably clearer. The -> operator will come in very handy when manipulating complex data structures. (See Section 20.4 [Complex data structures], page 215.)
In the chapter on arrays, we explored how to initialize an array with values at compile time. (See Section 14.5 [Initializing arrays], page 99.) It is also possible to initialize structures at compile time, as shown below. (This code example also shows how to dynamically allocate structures with malloc and initialize them with the -> operator. See Section 20.2 [Memory allocation], page 212, for more information on this technique.) #include <stdio.h> /* To shorten example, not using argp */ int main() { struct personal_data { char name[100]; char address[200]; int year_of_birth; int month_of_birth; int day_of_birth; };
Memory allocation
211
struct personal_data person1 = { "Liddell, Alice", "Wonderland", 1852, 5, 4 }; struct personal_data person2 = { "Hale-Evans, Ron", "Seattle, Washington", 1965, 6, 27 }; struct personal_data* person_ptr1; struct personal_data* person_ptr2; person_ptr1 = (struct personal_data*) malloc (sizeof (struct personal_data)); strcpy (person_ptr1->name, "Adams, Douglas"); strcpy (person_ptr1->address, "The Galaxy"); person_ptr1->year_of_birth = 1952; person_ptr1->month_of_birth = 3; /* Dont know his exact birthday */ person_ptr2 = (struct personal_data*) malloc (sizeof (struct personal_data)); strcpy (person_ptr2->name, "Egan, Greg"); strcpy (person_ptr2->address, "Permutation City"); person_ptr2->year_of_birth = 1961; /* Dont know his birthday */ puts puts puts puts puts ("Data contained:"); (person1.name); (person2.name); (person_ptr1->name); (person_ptr2->name);
return 0; } Any trailing items not initialized by data you specify are set to zero.
212
Most variables in C have a xed size. For example, a string declared to be 200 bytes long will always be 200 bytes long throughout the program. Sometimes, however, you will need variables whose size can vary. You might want a string whose size can vary between 0 and 100 kilobytes, for instance. We have already seen occasions where this sort of string is needed with the getline function. (See Section 16.2.6.1 [getline], page 132.) This is where dynamic data, or data whose size can vary, comes in. Dynamic data is created via the process of memory allocation, that is, assigning a block of memory to a variable. Blocks of memory are usually assigned with the malloc function (the function name is from the phrase memory allocation), and can be resized with the realloc (memory reallocation) function, and even merged back into the pool of available memory with the free function. The malloc function takes one argument, the number of bytes to allocate. It returns a void pointer, which provides the address of the beginning of a block of memory that the program can use. This void pointer can be assigned to any other type of pointer. The only way to make use of the block of memory that has been allocated is through its pointer; in that sense, the block is not a real variable, that is to say, you cannot assign a value to the memory block directly. Instead, the address returned by malloc enables you to use the block indirectly; in this way, the block can contain any kind of value a real variable can. Having to use blocks indirectly through pointers is a small price to pay for the exibility of dynamic data. The following code example allocates a ten-byte string: char *my_string; my_string = (char *) malloc(10+1); Notice that the void pointer returned by malloc is cast to a character pointer (type char *) before it is assigned to my_string. (See Section 5.4 [The cast operator], page 22.) Also notice that we have actually allocated 11 bytes of space; this is because the 11th byte must contain a null character that terminates the string but does not count toward its actual length. Careful! The newly-allocated block will be lled with garbage. To reallocate the memory, use the realloc function. This function takes two parameters. The rst is the pointer to the memory block to be reallocated, and the second is a number of type size_t that species the new size for the block. It returns a void pointer to the newly reallocated block. Here is how to reallocate the block allocated for my_string above, to a new size of 1000 bytes: my_string = (char *) realloc (my_string, 1001); The new block will contain all the data in the old block, followed by enough space to pad out the block to the new length. The new space will be lled with garbage. Finally, to free up the memory allocated to a block and return it to the common pool of memory available to your program, use the free function, which takes only one argument, the pointer to the block you wish to free. It does not return a value. free (my_string); It is also possible to allocate the memory for a structure when it is needed and use the -> operator to access the members of the structure, since we must access the structure via a pointer. (See the code sample following the next paragraph for an example of how to
Declaration of unions
213
do this.) If you are creating complex data structures that require hundreds or thousands of structure variables (or more), the ability to create and destroy them dynamically can mean quite a savings in memory. Its easy enough to allocate a block of memory when you know you want 1000 bytes for a string, but how do you know how much memory to allocate for a structure? For this task, C provides the sizeof function, which calculates the size of an object. For example, sizeof (int) returns the numbers of bytes occupied by an integer variable. Similarly, sizeof (struct personal_data) returns the number of bytes occupied by our personal_data structure. To allocate a pointer to one of these structures, then set the year_of_birth member to 1852, you would write something like the following: struct personal_data* my_struct_ptr; my_struct_ptr = (struct personal_data*) malloc (sizeof (struct personal_data)); my_struct_ptr->year_of_birth = 1852;
20.3 union
A union is like a structure in which all of the members are stored at the same address. Only one member can be in a union at one time. The union data type was invented to prevent the computer from breaking its memory up into many ineciently sized chunks, a condition that is called memory fragmentation. The union data type prevents fragmentation by creating a standard size for certain data. When the computer allocates memory for a program, it usually does so in one large block of bytes. Every variable allocated when the program runs occupies a segment of that block. When a variable is freed, it leaves a hole in the block allocated for the program. If this hole is of an unusual size, the computer may have diculty allocating another variable to ll the hole, thus leading to inecient memory usage. Since unions have a standard data size, however, any hole left in memory by freeing a union can be lled by another instance of the same type of union. A union works because the space allocated for it is the space taken by its largest member; thus, the small-scale memory ineciency of allocating space for the worst case leads to memory eciency on a larger scale.
214
Just like structures, the members of unions can be accessed with the . and -> operators. However, unlike structures, the variables my_union1 and my_union2 above can be treated as either integers or oating-point variables at dierent times during the program. For example, if you write my_union1.int_member = 5;, then the program sees my_union1 as being an integer. (This is only a manner of speaking. However, my_union1 by itself does not have a value; only its members have values.) On the other hand, if you then type my_union1.float_member = 7.7;, the my_union variable loses its integer value. It is crucial to remember that a union variable can only have one type at the same time.
215
216
If the user of this hypothetical application wishes to know what is to the north of a particular town, the program only has to check that towns north pointer.
There are some advantages to the use of dynamic storage for data structures: As mentioned above, since memory is allocated as needed, we dont need to declare how much we shall use in advance. Complex data structures can be made up of lots of lesser data structures in a modular way, making them easier to program. Using pointers to connect structures means that they can be re-connected in dierent ways as the need arises. (Data structures can be sorted, for example.)
217
struct list_node { double value; struct list_node *next; }; Here the value member holds the actual content of the node, in this case a double-precision oating-point number, and the next member points to the next node in the list. You will often encounter another basic kind of linked list, called a doubly-linked list. Each node in a doubly-linked list contains not only a pointer to the next node, but also to the previous node. This kind of list makes it easier to determine what the node preceding a node is, as well as the node succeeding it.
218
2. Add structure pointers to the structure type to reect the way in which each bundle of information is connected to the others. 3. Design the algorithms to handle the memory allocation, node linking, and data storage.
Questions 20
219
7. Link neighboring nodes to the current node, as appropriate: root->north = current; 8. Repeat steps 5 through 7, as necessary. See Section 21.3 [Controlled recursion with data structures], page 224, for a practical example of building a simple linked list programmatically.
20.6 Questions 20
1. 2. 3. 4. 5. 6. 7. 8. What is the dierence between a structure and a union? What is a member? If foo is a structure variable, how would you nd out the value of its member bar? If foo is a pointer to a structure variable, how would you nd out the value of its member bar? How are data usually linked to make a complex data structure? Every structure variable in a complex data structure must have its own variable name. True or false? How are the members of structures accessed in a data structure? Write a small program to make linked list that contains three nodes long and set all their values to be zero. Can you automate this program with a loop? Can you make it work for any number of nodes?
220
221
21 Recursion
The program that swallowed its tail. This chapter is about functions that call themselves. Consider the program below: #include <stdio.h> void black_hole() { black_hole(); } /* To shorten example, not using argp */ int main () { black_hole(); return 0; } The main function calls the black_hole function, which calls itself, which calls itself, which calls. . . Once the control ow enters black_hole, it will never exit. This kind of function is called a recursive function, and a functions act of calling itself is called recursion.
222
The answer is simple. The computer keeps a list of the addresses in memory of the places to which it must return, no matter how many function calls are made. This list is the stack. The stack gets its name from the fact that it is a LIFO, or last in, rst out structure, meaning that the last item to be pushed onto the stack is the rst item to be popped o. It works, in other words, like the stack of dinner plates you keep in your kitchen cabinet. As you wash plates, you pile them one by one on top of the stack, and when you want a plate, you take one from the top of the stack. The stack of plates in your cabinet is therefore also a last in, rst out structure, like the computers stack. When one C function calls a second function, the computer leaves itself an address at the top of the stack of where it should return when it has nished executing the second function. If the second function calls a third function, the computer will push another address onto the stack. When the third function has nished executing, the computer pops the top address o the stack, which tells it where in the second function it should return. When the second function has nished, the computer again pops the top address o the stack which tells it where in the rst function it should return. Perhaps the rst function then calls another function, and the whole process starts again. What happens when black_hole calls itself? The computer makes a note of the address it must return to and pushes that address onto the top of the stack. It begins executing black_hole again, and encounters another call to black_hole. The computer pushes another address onto the top of the stack, and begins executing black_hole again. Since the program has no chance of popping addresses o the stack, as the process continues, the stack gets lled up with addresses. Eventually, the stack lls up and the program crashes.
Controlled recursion
223
A standard example of controlled recursion is the factorial function. This is a mathematical function which is important in statistics. The factorial function is dened to be the product (multiplication) of all integers from 1 to the parameter of the function. (The factorial of 0 is 1.) Here are some examples of the factorial function. These are not executable C code examples, but pseudocode: factorial(3) == 1 * 2 * 3 == 6 factorial(4) == 1 * 2 * 3 * 4 == 24 factorial(3) == 1 * 2 * 3 * 4 * 5 == 120 Formally, the factorial function is dened by two equations. (Again, these are in pseudocode). factorial(n) = n * factorial(n-1) factorial(0) = 1 The rst of these statements is recursive, because it denes the value of factorial(n) in terms of factorial(n-1). The second statement allows the function to bottom out. Here is a short code example that incorporates a factorial function. #include <stdio.h> int factorial (int n) { if (n == 0) return 1; else return (n * factorial (n-1)); } /* To shorten example, not using argp */ int main () { printf ("%d\n", factorial(3)); return 0; } Lets follow the control ow in this program to see how controlled recursion can work. The main function prints the value of factorial(3). First, the factorial function is called with the parameter 3. The function tests whether its parameter n is zero. It is not, so it takes the else branch if the if statement, which instructs it to return the value of factorial(3-1). It therefore calls itself recursively with a parameter of 2. The new call checks whether its parameter is zero. It isnt (its 2), so it takes the else branch again, and tries to calculate 2 * factorial (1). In order to do so, it calls itself recursively with a value of 2-1, or 1. The new call checks whether its parameter is zero. It is actually 1, so it takes the else branch again and attempts to calculate 1 * factorial (0). In order to do so, it calls itself again with the parameter 0. Again, the function checks whether its parameter is zero. This time it is, so the function bottoms out. It takes the rst branch of the if statement and returns a value of 1. Now the previous function call can also return a value, and so on, until the very rst call to factorial terminates, and the function returns a value of 6.
224
To sum up, the expression factorial(3) goes through the following steps before nally being evaluated: factorial (3) == == == == == 3 3 3 3 6 * * * * factorial(2) (2 * factorial(1)) (2 * (1 * factorial(0))) (2 * (1 * 1)))
Note: Make sure that the test for whether to bottom out your recursive function does not depend on a global variable. Suppose you have a global variable called countdown, which your recursive function decrements by 1 every time it is called. When countdown equals zero, your recursive function bottoms out. However, since other functions than the recursive function have access to global variables, it is possible that another function might independently change countdown in such a way that your recursive function would never bottom out perhaps by continually incrementing it, or perhaps even by setting it to a negative number.
Questions 21
225
/* To shorten example, not using argp */ int main () { struct list_node *root; struct list_node *current; struct list_node *old; struct list_node *last; /* Initialize list. */ root = (struct list_node *) malloc (sizeof (struct list_node)); root->data = 1; old = root; current = (struct list_node *) malloc (sizeof (struct list_node)); current->data = 2; old->next = current; old = current; current = (struct list_node *) malloc (sizeof (struct list_node)); current->data = 3; old->next = current; current->next = NULL; /* Print data in last node. */ last = last_node (root); printf ("Data in last node is %d.\n", last->data); return 0; } This example program prints out the following line: Data in last node is 3. The last_node function, when passed a pointer to a node (such as the root), follows the linked list to its end from that point, and returns a pointer to that node. It does so through recursion. When it is passed a pointer to a node, it checks whether that nodes next link is a null pointer. If the pointer is null, last_node has found the last node, and bottoms out, returning a pointer to the current node; otherwise, it calls itself with a pointer to the next node as a parameter.
226
21.5 Questions 21
1. What is a recursive function? 2. What is a program stack, and what is it for? 3. State the major disadvantage of recursion.
227
22 Style
C has no rules about when to start new lines, where to place whitespace, and so on. Users are free to choose a style which best suits them, but unless a strict style is adopted, sloppy programs tend to result. In older compilers, memory restrictions sometimes necessitated bizarre, cryptic styles in the interest of eciency. However, contemporary compilers such as GCC have no such restrictions, and have optimizers that can produce faster code than most programmers could write themselves by hand, so there are no excuses not to write programs as clearly as possible. No simple set of rules will ever provide a complete methodology for writing good programs. In the end, experience and good judgment are the factors which determine whether you will write good programs. Nevertheless, a few guidelines to good style can be stated. Many of the guidelines in this chapter are the distilled wisdom of countless C programmers over the decades that C has existed, and some come directly from the GNU Coding Standards. That document contains more good advice than can be crammed into this short chapter, so if you plan to write programs for the Free Software Foundation, you are urged to consult section Table of Contents in GNU Coding Standards.
228
229
230
22.8 Questions 22
1. Where should the name of a program and the opening bracket of a function denition begin? 2. In what human language should comments be written for the GNU Project? Why? 3. Which is better as the name of a variable: plotArea, PlotArea, or plot_area? Why? 4. Why is it important to initialize a variable near where it is used in a long function? 5. Give an example of a case where using local variables is impractical.
231
23 Debugging
True articial intelligence has not yet been achieved. C compilers are not intelligent, but unconscious: mechanical in the derogatory sense of the word. Therefore, debugging your programs can be a dicult process. A single typographical error can cause a compiler to completely misunderstand your code and generate a misleading error message. Sometimes a long string of compiler error messages are generated because of a single error in your code. To minimize the time you spend debugging, it is useful to become familiar with the most common compiler messages and their probable causes. The rst section in this chapter lists some of these common compile-time errors and what to do about them. The next two sections discuss run-time errors in general, and mathematical errors in particular. The nal section introduces GDB, the GNU Debugger, and explains some simple steps you can take to debug your programs with it.
232
printf ("Hello, world!\n") return 0; Of course this code makes no sense, and that is why the compiler complains. Often a missing curly bracket will cause one of these errors. For example, the following code: #include <stdio.h> /* To shorten example, not using argp */ int main() { if (1==1) { printf ("Hello, world!\n");
return 0; } generates the following error: brackets.c: In function main: brackets.c:11: parse error at end of input Because there is no closing curly bracket for the if statement, the compiler thinks the curly bracket that terminates the main function actually terminates the if statement. When it does not nd a curly bracket on line 11 of the program to terminate the main function, it complains. One way to avoid this problem is to type both members of a matching pair of brackets before you ll them in.
233
The answer, however, is very simple. C is case-sensitive. The main function calls the function Print_hello (with a capital P), but the correct name of the function is print_ hello (with a lower-case p). The linker could not nd a function with the name Print_ hello.
234
The variable my_int is local to the function set_value, so referring to it from within main results in the following error: undec.c: In undec.c:10: undec.c:10: undec.c:10: function main: my_int undeclared (first use in this function) (Each undeclared identifier is reported only once for each function it appears in.)
You might get this warning if you mismatch a parameter to printf and a conversion specier. For example, the following code: #include <stdio.h> /* To shorten example, not using argp */ int main() { int my_int = 5; printf ("%f", my_int); return 0; } produces the folliwing warning: wrongtype2.c: In function main: wrongtype2.c:6: warning: double format, different type arg (arg 2) The %f conversion specier requires a oating-point argument, while my_int is an integer, so GCC complains. Note: GCC is quite lenient about type mismatches and will usually coerce one type to another dynamically without complaining, for example when assigning a oating-point number to an integer. This extends to mismatched parameters and conversion speciers although you may receive odd results from printf and so on, the causes of which may not be obvious. Therefore, in order to generate this warning, the -Wall option of GCC was used. This option causes GCC to be especially sensitive to errors, and to complain about problems it usually ignores. You will often nd the -Wall option to be useful in nding tricky problems. Here is the actual command line used to compile this program: gcc -Wall -o wrong wrongtype2.c
Confusion of = and ==
235
#include <stdio.h> void tweedledee (int a, int b, int c) { } void tweedledum (int a, int b) { } /* To shorten example, not using argp */ int main() { tweedledee (1, 2); tweedledum (1, 2, 3); return 0; } The tweedledee function takes three parameters, but main passes it two, whereas the tweedledum function takes two parameters, but main passes it three. The result is a pair of straightforward error messages: params.c: In function main: params.c:14: too few arguments to function tweedledee params.c:15: too many arguments to function tweedledum This is one reason for the existence of function prototypes. Before the ANSI Standard, compilers did not complain about this kind of error. If you were working with a library of functions with which you were not familiar, and you passed one the wrong number of parameters, the error was sometimes dicult to track. Contemporary C compilers such as GCC that follow the standard make nding parameter mismatch errors simple.
236
#include <stdio.h> /* To shorten example, not using argp */ int main() { int my_int = 0; if (my_int = 1) { printf ("Hello!\n"); } return 0; } What will this program do? If you guessed that it will print Hello!, you are correct. The assignment operator (=) was used by mistake instead of the equality operator (==). What is being tested in the above if statement is not whether my_int has a value of 1 (which would be written if my_int == 1), but instead what the value is of the assignment statement my_int = 1. Since the value of an assignment statement is always the result of the assignment, and my_int is here being assigned a value of 1, the result is 1, which C considers to be equivalent to TRUE. Thus, the program prints out its greeting. Even the best C programmers make this mistake from time to time, and tracking down an error like this can be maddening. Using the -Wall option of GCC can help at least a little by giving you a warning like the following: equals.c: In function main: equals.c:7: warning: suggest parentheses around assignment used as truth value
Mathematical errors
237
This kind of code is always safe: int my_array[3]; my_array[0] = 0; my_array[1] = 0; my_array[2] = 0; This kind of code is not: int my_array[3]; *my_array = 0; *(my_array + (1 * sizeof(int))) = 0; *(my_array + (2 * sizeof(int))) = 0; While it is true that the variable my_array used without its square brackets is a pointer to the rst element of the array, you must not assume that you can simply calculate a pointer to the third element with code like the following: my_array + 2 * sizeof(int); Do something like this instead: &(my_array[2]);
238
Questions 23
239
23.6 Questions 23
Spot the errors in the following: Blah blah blah.
240
Example programs
241
24 Example programs
The aim of this section is to provide a substantial example of C programming, using input from and output to disk, GNU-style long options, and the linked list data structure (including insertion, deletion, and sorting of nodes). #include <stdio.h> #include <string.h> #include <argp.h> #define NAME_LEN 100 #define ADDR_LEN 500 const char *argp_program_version = "bigex 1.0"; const char *argp_program_bug_address = "<bug-gnu-utilsgnu.org>";
/* This structure is used by main to communicate with parse_opt. */ struct arguments { char *args[1]; /* No arguments to this function */ int verbose; /* The -v flag */ char *infile; /* Argument for -i */ char *outfile; /* Argument for -o */ };
/* OPTIONS. Field 1 in ARGP. Order of fields: {NAME, KEY, ARG, FLAGS, DOC}. */ static struct argp_option options[] = { {"verbose", v, 0, 0, "Produce verbose output"}, {"input", i, "INFILE", 0, "Read addresses from INFILE"},
242
/* PARSER. Field 2 in ARGP. Order of parameters: KEY, ARG, STATE. */ static error_t parse_opt (int key, char *arg, struct argp_state *state) { struct arguments *arguments = state->input; switch (key) { case v: arguments->verbose = 1; break; case i: arguments->infile = arg; break; case o: arguments->outfile = arg; break; case ARGP_KEY_ARG: if (state->arg_num >= 1) { argp_usage(state); } arguments->args[state->arg_num] = arg; break; case ARGP_KEY_END: if (state->arg_num < 1) { argp_usage (state); } break; default: return ARGP_ERR_UNKNOWN; } return 0; }
/*
Example programs
243
ARGS_DOC. Field 3 in ARGP. A description of the non-option command-line arguments that we accept. */ static char args_doc[] = "ARG";
/* DOC. Field 4 in ARGP. Program documentation. */ static char doc[] = "bigex -- Add ARG new names to an address book file.\vThe largest code example in th
/* The ARGP structure itself. */ static struct argp argp = {options, parse_opt, args_doc, doc};
struct personal_data * new_empty_node() { struct personal_data *new_node; new_node = (struct personal_data*) malloc (sizeof (struct personal_data)); strcpy (new_node->name, ""); strcpy (new_node->address, ""); new_node->next = NULL; return new_node; }
struct personal_data * create_node() { int bytes_read; int nbytes; struct personal_data *current_node; char *name; char *address; current_node = new_empty_node();
244
puts ("Name?"); nbytes = NAME_LEN; name = (char *) malloc (nbytes + 1); bytes_read = getline (&name, &nbytes, stdin); if (bytes_read == -1) { puts ("ERROR!"); } else { strncpy (current_node->name, name, NAME_LEN); free (name); } puts ("Address?"); nbytes = ADDR_LEN; address = (char *) malloc (nbytes + 1); bytes_read = getline (&address, &nbytes, stdin); if (bytes_read == -1) { puts ("ERROR!"); } else { strncpy (current_node->address, address, ADDR_LEN); free (address); } printf("\n"); return current_node; }
struct personal_data * find_end_node (struct personal_data *current_node) { if (current_node->next == NULL) { return current_node; } else { return find_end_node (current_node->next); } }
int
Example programs
245
list_length (struct personal_data *root) { struct personal_data *current_node; int count = 0; current_node = root; while (current_node->next != NULL) { current_node = current_node->next; count++; } return count; }
struct personal_data * find_node (struct personal_data *root, int node_wanted) { struct personal_data *current_node; int index = 0; current_node = root; while ((index < node_wanted) && (current_node->next != NULL)) { current_node = current_node->next; index++; } return current_node; }
delete_node (struct personal_data *root, int location) { struct personal_data *previous_node; struct personal_data *current_node; previous_node = find_node (root, location - 1); current_node = find_node (root, location); previous_node->next = current_node->next; }
246
struct personal_data *new_node, int location) { struct personal_data *temp_ptr; struct personal_data *previous_node; previous_node = find_node (root, location - 1); temp_ptr = previous_node->next; previous_node->next = new_node; new_node->next = temp_ptr; }
swap_nodes (struct personal_data *root, int a, int b) { int temp; struct personal_data *node_a; struct personal_data *node_b; struct personal_data *temp_node; if (a > b) { temp = a; a = b; b = temp; } node_b = find_node (root, b); delete_node (root, b); node_a = find_node (root, a); delete_node (root, a); insert_node (root, node_b, a); insert_node (root, node_a, b); }
sort_list (struct personal_data *root) { int i, j, list_len, diff; list_len = list_length (root); for (i=2; i<=list_len; i++) { j = i; while (strcmp ( (find_node(root, j))->name, (find_node(root, j-1))->name) < 0)
Example programs
247
print_node (struct personal_data *current_node, FILE *save_stream) { fprintf (save_stream, "%s%s", current_node->name, current_node->address); }
print_list (struct personal_data *current_node, FILE *save_stream) { print_node (current_node, save_stream); if (current_node->next != NULL) { print_list (current_node->next, save_stream); } }
struct personal_data * read_node (FILE *instream) { int bytes_read; int nbytes; struct personal_data *current_node; char *name; char *address; char *blankline; int read_err = 0; current_node = new_empty_node(); nbytes = NAME_LEN; name = (char *) malloc (nbytes + 1); bytes_read = getline (&name, &nbytes, instream); if (bytes_read == -1)
248
{ read_err = 1; } else { puts (name); strncpy (current_node->name, name, NAME_LEN); free (name); } nbytes = ADDR_LEN; address = (char *) malloc (nbytes + 1); bytes_read = getline (&address, &nbytes, instream); if (bytes_read == -1) { read_err = 1; } else { puts (address); strncpy (current_node->address, address, ADDR_LEN); free (address); } if (read_err) { return NULL; } else { return current_node; } }
struct personal_data * read_file (char *infile) { FILE *input_stream = NULL; struct personal_data *root; struct personal_data *end_node; struct personal_data *current_node; root = new_empty_node(); end_node = root; input_stream = fopen (infile, "r"); if (input_stream) {
Example programs
249
while (current_node = read_node (input_stream)) { end_node->next = current_node; end_node = current_node; end_node->next = NULL; } } return root; }
/* The main function. Notice how now the only function call needed to process all command-line options and arguments nicely is argp_parse. */ int main (int argc, char **argv) { struct arguments arguments; struct personal_data *root; struct personal_data *end_node; struct personal_data *current_node; int i, newnum; FILE *save_stream;
/* Set argument defaults */ arguments.infile = NULL; arguments.outfile = NULL; arguments.verbose = 0; /* Where the magic happens */ argp_parse (&argp, argc, argv, 0, 0, &arguments); if (arguments.infile) { root = read_file (arguments.infile); end_node = find_end_node (root); } else { root = new_empty_node(); end_node = root; } /* Where do we send output? */
250
if (arguments.outfile) save_stream = fopen (arguments.outfile, "w"); else save_stream = stdout; newnum = atoi (arguments.args[0]); for (i = 1; i <= newnum; i++) { current_node = create_node(); end_node->next = current_node; end_node = current_node; end_node->next = NULL; } sort_list (root); print_list (root->next, save_stream); /* Close stream; skip error-checking for brevity of example */ fclose (save_stream); /* If in verbose mode, print song stanza */ if (arguments.verbose) {}; return 0; }
251
252
Reserved words in C
253
254
Precedence of operators
255
Evaluated left to right left to right right right right right right right right right to to to to to to to to left left left left left left left left
left to right left to right left to right left to right left to right left to right left to right left left left left to to to to right right right right
left to right left to right left left left left left to to to to to right right right right right left left left left left left left
assign add assign subtract assign multiply assign divide assign remainder assign right shift assign
to to to to to to to
256
<<= &= ^= |=
to to to to
Special characters
257
Here is a code example that prints special characters: /***************************************************/ /* */ /* Special Characters */ /* */ /***************************************************/ #include <stdio.h> main () { printf ("Beep! \7 \n"); printf ("ch = \a\ \n"); printf (" <- Start of this line!! \r"); } The output of this program is: Beep! (and the BELL sound) ch = a <- Start of this line!! and the text cursor is left where the arrow points.
258
259
This table lists the decimal, octal, and hexadecimal numbers for characters 0 127.
Decimal 0 1 2 3 4 5
Octal 0 1 2 3 4 5
Hexadecimal 0 1 2 3 4 5
260
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64
6 7 10 11 12 13 14 15 16 17 20 21 22 23 24 25 26 27 30 31 32 33 34 35 36 37 40 41 42 43 44 45 46 47 50 51 52 53 54 55 56 57 60 61 62 63 64 65 66 67 70 71 72 73 74 75 76 77 100
6 7 8 9 A B C D E F 10 11 12 13 14 15 16 17 18 19 1A 1B 1C 1D 1E 1F 20 21 22 23 24 25 26 27 28 29 2A 2B 2C 2D 2E 2F 30 31 32 33 34 35 36 37 38 39 3A 3B 3C 3D 3E 3F 40
CTRL-F CTRL-G CTRL-H CTRL-I CTRL-J CTRL-K CTRL-L CTRL-M CTRL-N CTRL-O CTRL-P CTRL-Q CTRL-R CTRL-S CTRL-T CTRL-U CTRL-V CTRL-W CTRL-X CTRL-Y CTRL-Z CTRL-[ CTRL-\ CTRL-] CTRL-^ CTRL-_ ! " # $ % & ( ) * + , . / 0 1 2 3 4 5 6 7 8 9 : ; < = > ? @
261
262
Answers to questions
263
264
Bibliography
265
Bibliography
Blah blah blah.
266
Bibliography
Glossary
267
Glossary
Blah blah blah.
268
Glossary
Code index
269
Code index
#
# output conversion specier modier . . . . . . . . 127 #define preprocessor directive . . . . . . . . . . . . . . . . 74 #else preprocessor directive . . . . . . . . . . . . . . . . . . 73 #error preprocessor directive . . . . . . . . . . . . . . . . . 73 #if preprocessor directive . . . . . . . . . . . . . . . . . . . . 73 #ifdef preprocessor directive . . . . . . . . . . . . . . . . . 75 #ifndef preprocessor directive . . . . . . . . . . . . . . . . 75 #include preprocessor directive . . . . . . . . . . . . . . . 73 #line preprocessor directive . . . . . . . . . . . . . . . . . . 73 #undef preprocessor directive . . . . . . . . . . . . . . . . . 75
- operator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 - output conversion specier modier . . . . . . . . 126 - subtraction operator . . . . . . . . . . . . . . . . . . . . . . . 32 - unary minus operator . . . . . . . . . . . . . . . . . . . . . . 32 -- decrement operator . . . . . . . . . . . . . . . . . . . 34, 187 -- operator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185 -- postx operator . . . . . . . . . . . . . . . . . . . . . . . . . 187 -- prex operator . . . . . . . . . . . . . . . . . . . . . . . . . . 187 --static option of GCC . . . . . . . . . . . . . . . . . . . . 182 -= operator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35, 185 -> dot operator of structures . . . . . . . . . . . . . . . . 207 -> member operator . . . . . . . . . . . . . . . . . . . . . . . . 212 -c option of GCC . . . . . . . . . . . . . . . . . . . . . . . . . . . 181 -fpic option of GCC . . . . . . . . . . . . . . . . . . . . . . . 181 -fPIC option of GCC . . . . . . . . . . . . . . . . . . . . . . . 181 -I option of GCC . . . . . . . . . . . . . . . . . . . . . . . 84, 182 -l option of GCC . . . . . . . . . . . . . . . . . . . . . . . . . . . 182 -L option of GCC . . . . . . . . . . . . . . . . . . . . . . . . . . . 182
%
% % % % % input conversion specier . . . . . . . . . . . . . . . . . . 139 integer remainder operator . . . . . . . . . . . . . . . . . . 32 mod operator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 modulo operator . . . . . . . . . . . . . . . . . . . . . . . . . . . 32 output conversion specier . . . . . . . . . . . . . . . . . 126
&
& bitwise operator . . . . . . . . . . . . . . . . . . . . . . . . . . 190 & bitwise operator truth table . . . . . . . . . . . . . . . . 192 & pointer operator . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 &= bitwise operator . . . . . . . . . . . . . . . . . . . . . . . . . 190
.
. dot operator of structures . . . . . . . . . . . . . . . . . 207 .a le sux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4, 84 .c le sux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 .h le sux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 .o le sux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 .so le sux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4, 84
input conversion specier modier . . . . . . . . . . 139 output conversion specier modier . . . . . . . . 127
/
/ div operator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . / division operator . . . . . . . . . . . . . . . . . . . . . . . . . . . / integer division operator . . . . . . . . . . . . . . . . . . . . /usr/include directory . . . . . . . . . . . . . . . . . . . 82, /usr/include/linux directory . . . . . . . . . . . . . . . . 32 32 32 84 84
*
* input conversion specier modier . . . . . . . . . . 139 * multiplication operator . . . . . . . . . . . . . . . . . . . . . 32 * operator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 * pointer operator . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 *= operator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
=
= (equals sign) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 = assignment operator . . . . . . . . . . . . . . . . . . . . . . . . 31 = confused with == . . . . . . . . . . . . . . . . . . . 32, 37, 235 = operator. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185 == confused with = . . . . . . . . . . . . . . . . . . . . . . 32, 37 == confused with = . . . . . . . . . . . . . . . . . . . . . . . . . . 235
,
, operator. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189
270
Code index
?
? operator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55, 59
<
< less-than operator . . . . . . . . . . . . . . . . . . . . . . . . . . 31 << bitwise operator . . . . . . . . . . . . . . . . . . . . . . . . . 190 <<= bitwise operator . . . . . . . . . . . . . . . . . . . . . . . . 190
[
[ input conversion specier . . . . . . . . . . . . . . . . . . 139
0
0 output conversion specier modier . . . . . . . . 127 0 return code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165
|
| (pipe symbol). . . . . . . . . . . . . . . . . . . . . . . . . . . . . | bitwise operator . . . . . . . . . . . . . . . . . . . . . . . . . . | bitwise operator truth table . . . . . . . . . . . . . . . . |= bitwise operator . . . . . . . . . . . . . . . . . . . . . . . . . 149 190 192 190
A
a input conversion specier modier . . . . . . . . . . 139 a.out . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 abs function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88 acos function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89 ar program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 181 ARG eld . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165 ARG parser function argument . . . . . . . . . . . . . . . . 165 arg_num eld . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165 argc variable . . . . . . . . . . . . . . . . . . . . . . . . . . 161, 162 argp function . . . . . . . . . . . . . . . . . . . . . . 163, 164, 166 ARGP structure . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164 ARGP_ERR_UNKNOWN return code . . . . . . . . . . . . . . 165 ARGP_KEY_ARG key . . . . . . . . . . . . . . . . . . . . . . . . . . 165 ARGP_KEY_END key . . . . . . . . . . . . . . . . . . . . . . . . . . 165 argp_option structure . . . . . . . . . . . . . . . . . . . . . . 164 argp_option structure elds . . . . . . . . . . . . . . . . . 164 argp_parse function . . . . . . . . . . . . . . . . . . . . . . . . 164 argp_usage function . . . . . . . . . . . . . . . . . . . . . . . . 166 ARGS_DOC eld . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165 arguments structure . . . . . . . . . . . . . . . . . . . . . . . . 164 argv array . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172 argv variable . . . . . . . . . . . . . . . . . . . . . . . . . . 161, 162 asin function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89 asprintf function . . . . . . . . . . . . . . . . . . . . . . . . . . 130 atan function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89 atan2 function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89 atof function. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108 atoi function. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108 atol function. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108 auto storage class specier . . . . . . . . . . . . . . . . . . . 25
~
~ bitwise operator . . . . . . . . . . . . . . . . . . . . . . . . . . 190 ~ bitwise operator truth table . . . . . . . . . . . . . . . . 192
+
+ addition operator . . . . . . . . . . . . . . . . . . . . . . . . . . 32 + operator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 + output conversion specier modier . . . . . . . . 126 + unary plus operator . . . . . . . . . . . . . . . . . . . . . . . . 32 += operator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35, 185 ++ increment operator . . . . . . . . . . . . . . . . . . . 34, 187 ++ operator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 185 ++ postx operator . . . . . . . . . . . . . . . . . . . . . . . . . 187 ++ prex operator . . . . . . . . . . . . . . . . . . . . . . . . . . 187
>
> greater-than operator . . . . . . . . . . . . . . . . . . . . . . 31 >> bitwise operator . . . . . . . . . . . . . . . . . . . . . . . . . 190 >>= bitwise operator . . . . . . . . . . . . . . . . . . . . . . . . 190
^
^ bitwise operator . . . . . . . . . . . . . . . . . . . . . . . . . . 190 ^ bitwise operator truth table . . . . . . . . . . . . . . . . 193 ^= bitwise operator . . . . . . . . . . . . . . . . . . . . . . . . . 190
Code index
271
B
bdflush daemon . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122 break command . . . . . . . . . . . . . . . . . . . . . . . . . . 60, 69
C
c input conversion specier . . . . . . . . . . . . . . . . . . 138 c output conversion specier . . . . . . . . . . . . . . . . . 126 cast operator . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22, 23 ceil function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89 char type . . . . . . . . . . . . . . . . . . . . . . . . . . . 19, 20, 105 clean makele target . . . . . . . . . . . . . . . . . . . . . . . 180 clearerr function . . . . . . . . . . . . . . . . . . . . . . . . . . 123 close function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154 const type. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197, 201 cos function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89 cosh function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89 creat function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154 ctype.h header le . . . . . . . . . . . . . . . . . . . . . . . 84, 85
EMLINK le name error . . . . . . . . . . . . . . . . . . . . . . 159 ENAMETOOLONG le name error . . . . . . . . . . . . . . . . 152 ENOENT le name error . . . . . . . . . 152, 153, 158, 159 ENOMEM error code . . . . . . . . . . . . . . . . . . . . . . . . . . . 164 ENOSPC le name error . . . . . . . . . . . . . 154, 156, 159 ENOTDIR le name error . . . . . . . . . . . . . . . . . . . . . 152 ENOTEMPTY le name error . . . . . . . . . . . . . . . . . . . 159 enum type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197 envp array . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 171, 172 EOF character . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148 EPERM le name error . . . . . . . . . . . . . . . . . . . . . . . 158 EROFS le name error . . . . . . . . . . . . . . . 154, 158, 159 errno system variable . . . . 153, 154, 155, 156, 159, 165 error_t function . . . . . . . . . . . . . . . . . . . . . . . . . . . 164 ESPIPE le name error . . . . . . . . . . . . . . . . . . . . . . 158 EXDEV le name error . . . . . . . . . . . . . . . . . . . . . . . 159 exit command . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 exp function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89 extern storage class specier . . . . . . . . . . . . . . . . . 24
D
d input conversion specier . . . . . . . . . . . . . . . . . . 138 d output conversion specier . . . . . . . . . . . . . . . . . 126 do ... while command . . . . . . . . . . . . . . . . . . . . . . 63 DOC eld . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165 double type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
F
f input conversion specier . . . . . . . . . . . . . . . . . . 138 f output conversion specier . . . . . . . . . . . . . . . . . 126 fabs function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89 FALSE macro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 fclose command . . . . . . . . . . . . . . . . . . . . . . . . . . . 116 fclose function . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154 FE_ALL_EXCEPT function . . . . . . . . . . . . . . . . . . . . . 238 FE_DIVBYZERO oating-point exception. . . . . . . . 238 FE_INEXACT oating-point exception . . . . . . . . . . 238 FE_INVALID oating-point exception . . . . . . . . . . 238 FE_OVERFLOW oating-point exception . . . . . . . . . 238 FE_UNDERFLOW oating-point exception. . . . . . . . 238 feof function. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122 ferror function . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122 fetestexcept function . . . . . . . . . . . . . . . . . . . . . . 238 fflush function . . . . . . . . . . . . . . . . . . . . . . . . 122, 237 fgetc function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145 fgets function . . . . . . . . . . . . . . . . . . . . . . . . . 123, 135 le status ag . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153 FLAGS eld . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165 float type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 floor function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89 fopen command . . . . . . . . . . . . . . . . . . . 113, 115, 116 for command . . . . . . . . . . . . . . . . . . . . . 63, 65, 67, 93
E
E input conversion specier . . . . . . . . . . . . . . . . . . 138 e output conversion specier . . . . . . . . . . . . . . . . . 126 E output conversion specier . . . . . . . . . . . . . . . . . 126 EACCES le name error . . . . . . . . . 152, 153, 158, 159 EBADF le name error . . . . . . . . . . 154, 156, 157, 158 EBUSY le name error . . . . . . . . . . . . . . . . . . . 158, 159 EEXIST le name error . . . . . . . . . . . . . . . . . . . . . . 153 EFBIG le name error . . . . . . . . . . . . . . . . . . . . . . . 156 EINTR le name error . . . . . . . . . . . . . . . . . . . . . . . 156 EINVAL error code . . . . . . . . . . . . . . . . . . . . . . . . . . . 164 EINVAL le name error . . . . . . . . . . . . . 157, 158, 159 EIO le name error . . . . . . . . . . . . . . . . . . . . . . . . . . 156 EISDIR le name error . . . . . . . . . . . . . . . . . . 153, 159 ELOOP le name error . . . . . . . . . . . . . . . . . . . . . . . 152 else command . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55 EMFILE le name error . . . . . . . . . . . . . . . . . . . . . . 153
272
Code index
fprintf function . . . . . . . . . . . . . . . . . . . . . . . . . . . fputc function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . fputs function . . . . . . . . . . . . . . . . . . . . . . . . . 123, fread function . . . . . . . . . . . . . . . . . . . . . . . . . 117, free function. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . fscanf function . . . . . . . . . . . . . . . . . . . . . . . . . . . . fseek function . . . . . . . . . . . . . . . . . . . . . . . . . 121, fsync function . . . . . . . . . . . . . . . . . . . . . . . . . 156, ftell function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . fwrite function . . . . . . . . . . . . . . . . . . . . . . . . 117,
129 147 124 118 212 143 148 157 121 118
isprint function . . . . . . . . . . . . . . . . . . . . . . . . . . . . ispunct function . . . . . . . . . . . . . . . . . . . . . . . . . . . . isspace function . . . . . . . . . . . . . . . . . . . . . . . . . . . . isupper function . . . . . . . . . . . . . . . . . . . . . . . . . . . . isxdigit function . . . . . . . . . . . . . . . . . . . . . . . . . . .
85 85 85 85 85
K
KEY eld . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164 KEY parser function argument . . . . . . . . . . . . . . . . 165
G
g input conversion specier . . . . . . . . . . . . . . . . . . 138 G input conversion specier . . . . . . . . . . . . . . . . . . 138 gcc . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4, 161, 172 getc function. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 145 getchar function . . . . . . . . . . . . . . . . . . . . . . . . . . . 144 getdelim function . . . . . . . . . . . . . . . . . . . . . . 123, 133 getenv function . . . . . . . . . . . . . . . . . . . . . . . . . . . . 172 getline function . . . . . . . . . . . . . . . . . . 123, 132, 133 getopt function . . . . . . . . . . . . . . . . . . . . . . . . . . . . 163 gets function . . . . . . . . . . . . . . . . . . . . . . . . . . 123, 134 glibc library . . . . . . . . . . . . . . . . . . . . . . . . . 81, 82, 85 goto command . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 261 grep command . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149
L
l input conversion specier modier . . . . . . . . . . 140 L input conversion specier modier . . . . . . . . . . 140 l output conversion specier modier . . . . . . . . 128 L output conversion specier modier . . . . . . . . 128 LD_LIBRARY_PATH shell variable . . . . . . . . . . . . . . 182 limits.h header le . . . . . . . . . . . . . . . . . . . . . . . . . 88 ll input conversion specier modier . . . . . . . . . 140 ll output conversion specier modier . . . . . . . 128 log function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89 log10 function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89 long double type . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 long float type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21 long long type . . . . . . . . . . . . . . . . . . . . . . . . . . . 19, 20 long type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19, 20 lseek function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157
H
h input conversion specier modier . . . . . . . . . . 140
I
i input conversion specier . . . . . . . . . . . . . . . . . . 138 i output conversion specier . . . . . . . . . . . . . . . . . 126 if command . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55, 57 INFINITY macro . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238 input conversion specier . . . . . . . . . . . . . . . . . . . . 138 input eld . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165 int type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19, 20 isalnum function . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85 isalpha function . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85 isascii function . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85 iscntrl function . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85 isdigit function . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85 isgraph function . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85 islower function . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
M
m output conversion specier . . . . . . . . . . . . 126, 152 make program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173 malloc function . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212 math.h header le . . . . . . . . . . . . . . . . . . . . . 82, 84, 88 math.h system header le . . . . . . . . . . . . . . . . . . . . 44
N
NAME eld . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 164 NAN macro. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238 NULL pointer. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218
Code index
273
O
O_APPEND le status ag . . . . . . . . . . . . . . . . . . . . . O_CREAT le status ag . . . . . . . . . . . . . . . . . . . . . . O_EXCL le status ag . . . . . . . . . . . . . . . . . . . . . . . O_EXEC le status ag . . . . . . . . . . . . . . . . . . . . . . . O_RDONLY le status ag . . . . . . . . . . . . . . . . . . . . . O_RDWR le status ag . . . . . . . . . . . . . . . . . . . . . . . O_TRUNC le status ag . . . . . . . . . . . . . . . . . . . . . . O_WRITE le status ag . . . . . . . . . . . . . . . . . . . . . . O_WRONLY le status ag . . . . . . . . . . . . . . . . . . . . . obj makele variable . . . . . . . . . . . . . . . . . . . . . . . . OBJ makele variable . . . . . . . . . . . . . . . . . . . . . . . . objects . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . OBJECTS makele variable . . . . . . . . . . . . . . . . . . . objs makele variable . . . . . . . . . . . . . . . . . . . . . . . OBJS makele variable . . . . . . . . . . . . . . . . . . . . . . . off_t type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . open command . . . . . . . . . . . . . . . . . . . . . . . . . . . . . open function . . . . . . . . . . . . . . . . . . . . . . . . . . 153, OPTION_ALIAS option ag . . . . . . . . . . . . . . . . . . . . OPTION_ARG_OPTIONAL option ag . . . . . . . . . . . . OPTION_HIDDEN option ag. . . . . . . . . . . . . . . . . . . OPTIONS eld . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 153 153 153 153 153 153 153 153 153 177 177 177 177 177 177 158 113 154 165 165 165 164
R
read function . . . . . . . . . . . . . . . . . . . . . . . . . . 155, 157 realloc function . . . . . . . . . . . . . . . . . . . . . . . . . . . 212 register storage class specier . . . . . . . . . . . . . . . 25 rename function . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159 return command . . . . . . . . . . . . . . . . . . . . . 17, 62, 69 rewind function . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148 rewind macro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121 rm program . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176 rmdir function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 159
S
s input conversion specier . . . . . . . . . . . . . . . . . . 139 s output conversion specier . . . . . . . . . . . . . . . . . 126 scanf function . . . . . . . . . . . . . . . . . . . . . . . . . . 47, 141 SEEK_CUR constant . . . . . . . . . . . . . . . . . . . . . . . . . . 157 SEEK_END constant . . . . . . . . . . . . . . . . . . . . . . . . . . 157 SEEK_SET constant . . . . . . . . . . . . . . . . . . . . . . . . . . 157 short type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19, 20 sin function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83, 89 sinh function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89 size_t type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 118 sizeof function . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213 SPACE output conversion specier modier . . . . 127 sprintf function . . . . . . . . . . . . . . . . . . . . . . . . . . . 131 sqrt function . . . . . . . . . . . . . . . . . . . . . . . . . . . . 44, 89 sscanf function . . . . . . . . . . . . . . . . . . . . . . . . 136, 137 STATE parser function argument . . . . . . . . . . . . . . 165 static storage class specier . . . . . . . . . . . . . . . . . 25 stdarg.h system header le . . . . . . . . . . . . . . . . . . 45 stdin device . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122 stdio.h header le . . . . . . . . . . . . . . . . . . . . . . . . . . 82 stdlib.h header le . . . . . . . . . . . . . . . . . . . . . . . . 108 stdout device . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122 strcat function . . . . . . . . . . . . . . . . . . . . . . . . . . . . 108 strcmp function . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109 strcpy function . . . . . . . . . . . . . . . . . . . . . . . . . . . . 109 string.h header le . . . . . . . . . . . . . . . . . . . . . 84, 108 strlen function . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110 strncat function . . . . . . . . . . . . . . . . . . . . . . . . . . . 110 strncmp function . . . . . . . . . . . . . . . . . . . . . . . . . . . 110 strncpy function . . . . . . . . . . . . . . . . . . . . . . . . . . . 110 strstr function . . . . . . . . . . . . . . . . . . . . . . . . . . . . 110 struct type . . . . . . . . . . . . . . . . . . . . . . . 197, 202, 205 switch command . . . . . . . . . . . . . . . . . . . . . . . . . 55, 59
P
PARSER eld . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 165 pclose function . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149 popen function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149 pow function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89 printf . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 printf function . . . . . . . . . . . . . . . . . . . . . . . . 125, 128 ps command . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 149 putc function. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 147 putchar function . . . . . . . . . . . . . . . . . . . . . . . . . . . 144 puts function. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123
Q
q input conversion specier modier . . . . . . . . . . 140 q output conversion specier modier . . . . . . . . 128
274
Code index
T
tan function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89 tanh function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89 tgmath.h header le . . . . . . . . . . . . . . . . . . . . . . . . . 88 toascii function . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85 tolower function . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85 toupper function . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85 TRUE macro. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 typedef command . . . . . . . . . . . . . . . . . . . . . . . . . . 202
V
void type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197, 200 volatile type . . . . . . . . . . . . . . . . . . . . . . . . . 197, 200
W
while command . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63 write function . . . . . . . . . . . . . . . . . . . . . . . . . 156, 157
U
u output conversion specier . . . . . . . . . . . . . . . . . 126 ungetc function . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148 union type . . . . . . . . . . . . . . . . . . . . . . . . 197, 202, 213 unlink function . . . . . . . . . . . . . . . . . . . . . . . . . . . . 158 unsigned char type . . . . . . . . . . . . . . . . . . . . . . . . . . 20 unsigned int type . . . . . . . . . . . . . . . . . . . . . . . . . . . 20 unsigned long long type . . . . . . . . . . . . . . . . . . . . . 20 unsigned long type . . . . . . . . . . . . . . . . . . . . . . . . . . 20 unsigned short type . . . . . . . . . . . . . . . . . . . . . . . . . 20
X
x X x X input conversion specier . . . . . . . . . . . . . . . . . . input conversion specier . . . . . . . . . . . . . . . . . . output conversion specier . . . . . . . . . . . . . . . . . output conversion specier . . . . . . . . . . . . . . . . . 139 139 126 126
Z
z input conversion specier modier . . . . . . . . . . 140 z output conversion specier modier . . . . . . . . 128 Z output conversion specier modier . . . . . . . . 128
Concept index
275
Concept index
.
./ (dot-slash) prex in shell . . . . . . . . . . . . . . . . . . 3
\
\ (backslash), for makele continuation lines . . 175
Assignment operator . . . . . . . . . . . . . . . . . . . . . . . . . 31 Assignment operator, confused with equality operator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32, 37 Assignment, example of . . . . . . . . . . . . . . . . . . . . . . . 5 Assignments, hidden . . . . . . . . . . . . . . . . . . . . . . . . 185 Automobile as metaphor for computer . . . . . . . . . . 1
A
Actual parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 Actual parameters, passing as pointers . . . . . . . . 53 Addition operator . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 Addresses, memory . . . . . . . . . . . . . . . . . . . . . . . . . . 47 Advantages of the C language. . . . . . . . . . . . . . . . . . 1 Allocation of memory . . . . . . . . . . . . . . . . . . . . . . . 212 AND assignment . . . . . . . . . . . . . . . . . . . . . . . . . . . 190 AND, bitwise, truth table . . . . . . . . . . . . . . . . . . . 192 Annotating programs . . . . . . . . . . . . . . . . . . . . . . . . 10 ANSI Standard C . . . . . . . . . . . . . . . . . . . . . 10, 11, 13 argc, example of. . . . . . . . . . . . . . . . . . . . . . . . . . . . 162 argp, example of. . . . . . . . . . . . . . . . . . . . . . . . . . . . 166 Argument count variable . . . . . . . . . . . . . . . . . . . . 161 Argument vector . . . . . . . . . . . . . . . . . . . . . . . . . . . 161 argv, example of. . . . . . . . . . . . . . . . . . . . . . . . . . . . 162 Arithmetic operators . . . . . . . . . . . . . . . . . . . . . 32, 35 Array bounds . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92 Array out of bounds errors . . . . . . . . . . . . . . . . . . 237 Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91 Arrays and for loops . . . . . . . . . . . . . . . . . . . . . . . . 93 Arrays and hidden operators. . . . . . . . . . . . . . . . . 187 Arrays and nested loops . . . . . . . . . . . . . . . . . . . . . . 98 Arrays and pointers, equivalence of. . . . . . . . . . . 101 Arrays as parameters . . . . . . . . . . . . . . . . . . . . . . . 101 Arrays of strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107 Arrays of structures . . . . . . . . . . . . . . . . . . . . . . . . . 208 Arrays, bounds of . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92 Arrays, dening . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91 Arrays, initializing . . . . . . . . . . . . . . . . . . . . 93, 98, 99 Arrays, multidimensional . . . . . . . . . . . . . . 71, 91, 96 Arrays, multidimensional, initializing . . . . . . . . . . 98 Arrays, one-based . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91 Arrays, out of bounds . . . . . . . . . . . . . . . . . . . . . . . 237 Arrays, reading from streams . . . . . . . . . . . . 117, 118 Arrays, writing to streams . . . . . . . . . . . . . . 117, 118 Arrays, zero-based nature of . . . . . . . . . . . . . . . . . . 91 Assignment. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
B
backslash (\), for makele continuation lines . . 175 Binary digits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189 Binary trees . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217 Bit masks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192, 193 Bit strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189 Bit-shift left assignment . . . . . . . . . . . . . . . . . . . . . 190 Bit-shift left operator . . . . . . . . . . . . . . . . . . . . . . . 190 Bit-shift right assignment . . . . . . . . . . . . . . . . . . . 190 Bit-shift right operator . . . . . . . . . . . . . . . . . . . . . . 190 Bits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189 Bitwise AND . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190 Bitwise AND, truth table . . . . . . . . . . . . . . . . . . . 192 Bitwise exclusive OR . . . . . . . . . . . . . . . . . . . . . . . . 190 Bitwise exclusive OR, truth table . . . . . . . . . . . . 193 Bitwise inclusive OR . . . . . . . . . . . . . . . . . . . . . . . . 190 Bitwise inclusive OR, truth table . . . . . . . . . . . . 192 Bitwise NOT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190 Bitwise NOT, truth table. . . . . . . . . . . . . . . . . . . . 192 Bitwise operators . . . . . . . . . . . . . . . . . . . . . . . . . . . 190 Black boxes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 Black boxes, disadvantages of . . . . . . . . . . . . . . . . . . 1 Block input . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117 Block output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117 Blocks, code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 Bookmark, le position compared to . . . . . . . . . 120 Boolean values . . . . . . . . . . . . . . . . . . . . . . . . . . . 31, 37 Bounds of arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92 Boxes, black . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 break, terminating loops with . . . . . . . . . . . . . . . . 69 Breaking out of switch statement . . . . . . . . . 60, 62 Buering, full . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122 Buering, line . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122 Buering, no . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122 Buering, stream . . . . . . . . . . . . . . . . . . . . . . . . . . . 121 Buers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121 Buers, ushing . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237 Bugs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
276
Concept index
Bugs, compile-time. . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 Building block, function as . . . . . . . . . . . . . . . . . . . . 9 Building libraries . . . . . . . . . . . . . . . . . . . . . . . . . . . 180 Buildings as metaphor for functions . . . . . . . . . . . 27 Bytes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 189
Command shell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Command-line options . . . . . . . . . . . . . . . . . . . . . . 163 Commands, deducing from implicit makele rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178 Comment characters . . . . . . . . . . . . . . . . . . . . . . . 9, 10 Comments . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9, 10 Comments, example . . . . . . . . . . . . . . . . . . . . . . . . . 11 Comments, style guidelines for . . . . . . . . . . . . . . . 228 Common library functions . . . . . . . . . . . . . . . . . . . . 84 Communication via parameters . . . . . . . . . . . . . . . 28 Comparison operators . . . . . . . . . . . . . . . . . 31, 37, 38 Compile-time bugs . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 Compile-time errors . . . . . . . . . . . . . . . . . . . . . . 5, 231 Compiler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3, 4 Compiler passes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 Compiling libraries . . . . . . . . . . . . . . . . . . . . . . . . . 180 Compiling multiple les . . . . . . . . . . . . . . . . . . . . . 172 Complex data structures . . . . . . . . . . . . . . . . 215, 216 Compound decisions . . . . . . . . . . . . . . . . . . . . . . . . . 58 Computer crash . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 Concealed diculties of C language . . . . . . . . . . . . 2 Constant expressions . . . . . . . . . . . . . . . . . . . . . . . . 201 Constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 201 Constants, string . . . . . . . . . . . . . . . . . . . . . . . . . . . 105 Continuation lines in makeles . . . . . . . . . . . . . . . 175 continue, optimizing loops with . . . . . . . . . . . . . . 70 continue, speeding loops with . . . . . . . . . . . . . . . . 70 Controlled recursion with data structures . . . . . 224 Conventions, le name . . . . . . . . . . . . . . . . . . . . . . . . 4 Conversion speciers, formatted input . . . 137, 138 Conversion speciers, formatted output . . . . . . . 126 Conversion speciers, formatted output, modiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126, 128 Conversion speciers, formatted output, table of . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126 Conversion table, character . . . . . . . . . . . . . . . . . . 259 Crash, computer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 Creating shared libraries . . . . . . . . . . . . . . . . . . . . 181 Creating static libraries . . . . . . . . . . . . . . . . . . . . . 181 Creation of les . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154 Curly brackets as walls . . . . . . . . . . . . . . . . . . . . . . . 27
C
C language and peripherals . . . . . . . . . . . . . . . . . . . . 2 C language as high-level language . . . . . . . . . . . . . . 1 C language as standard . . . . . . . . . . . . . . . . . . . . . . . xi C language, advantages of . . . . . . . . . . . . . . . . . . . . . 1 C language, case-sensitivity of . . . . . . . . . . . . . . . . . 6 C language, concealed diculties . . . . . . . . . . . . . . . 2 C language, exibility of . . . . . . . . . . . . . . . . . . . . . . . 1 C language, power of . . . . . . . . . . . . . . . . . . . . . . . xi, 2 C language, succinctness of . . . . . . . . . . . . . . . . . . . . 1 C language, unforgiving nature . . . . . . . . . . . . . . . . xi C language, why it is useful . . . . . . . . . . . . . . . . . . . xi C program, simplest . . . . . . . . . . . . . . . . . . . . . . . . . . 9 C, ANSI Standard . . . . . . . . . . . . . . . . . . . . 10, 11, 13 C, reserved words in . . . . . . . . . . . . . . . . . . . . . . . . 253 Car as metaphor for computer . . . . . . . . . . . . . . . . . 1 Case-sensitivity of C language . . . . . . . . . . . . . . . . . 6 Cast operator . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31, 50 Casting pointer types . . . . . . . . . . . . . . . . . . . . . . . . 50 Casting types. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 Casting types, example . . . . . . . . . . . . . . . . . . . . . . . 23 Character conversion table . . . . . . . . . . . . . . . . . . 259 Character functions, example of . . . . . . . . . . . . . . . 86 Character handling . . . . . . . . . . . . . . . . . . . . . . . . . . 85 Characters, confused with strings . . . . . . . . . . . . 105 Characters, special . . . . . . . . . . . . . . . . . . . . . . . . . . 257 Chess, GNU . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96 Chessboard, represented by array . . . . . . . . . . . . . 96 Classes, storage . . . . . . . . . . . . . . . . . . . . . . . . . . 24, 25 clean makele target . . . . . . . . . . . . . . . . . . . . . . . 176 cleaning up. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 180 close, example of . . . . . . . . . . . . . . . . . . . . . . . . . . 154 Closing les . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116 Closing les at a low level . . . . . . . . . . . . . . . . . . . 154 Code blocks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 Code, object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 Code, source . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 Combining rules by prerequisite . . . . . . . . . . . . . . 179 Comma operator . . . . . . . . . . . . . . . . . . . . . . . . . . . 189
Concept index
277
D
Daemons . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122 Data structure diagrams . . . . . . . . . . . . . . . . . . . . 215 Data structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205 Data structures with controlled recursion . . . . . 224 Data structures, as distinguished from structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205 Data structures, complex . . . . . . . . . . . . . . . 215, 216 Data structures, dynamic . . . . . . . . . . . . . . . . . . . . 216 Data structures, initializing . . . . . . . . . . . . . . . . . . 218 Data structures, recursive . . . . . . . . . . . . . . . . . . . 224 Data structures, setting up . . . . . . . . . . . . . . . . . . 217 Data types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 197 Data, dynamic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212 Debugging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231 Decisions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55 Decisions, compound . . . . . . . . . . . . . . . . . . . . . . . . . 58 Declaration, variable . . . . . . . . . . . . . . . . . . . . . . . . . . 6 Declarations, style guidelines for . . . . . . . . . . . . . 228 Declarations, variable . . . . . . . . . . . . . . . . . . . . . . . . 13 Declaring functions . . . . . . . . . . . . . . . . . . . . . . . . . . 15 Declaring parameters . . . . . . . . . . . . . . . . . . . . . . . . 42 Declaring structures . . . . . . . . . . . . . . . . . . . . . . . . 205 Declaring structures with typedef . . . . . . . . . . . 206 Declaring unions . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213 Declaring variables . . . . . . . . . . . . . . . . . . . . . . . 19, 21 Deducing commands from implicit makele rules . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 178 default makele goal . . . . . . . . . . . . . . . . . . . . . . . . 176 Dening your own types . . . . . . . . . . . . . . . . . . . . . . . 6 Deleting les at a low level . . . . . . . . . . . . . . . . . . 158 Deprecated formatted string input functions . . 140 Deprecated formatted string output functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131 Deprecated string input functions . . . . . . . . . . . . 134 Descriptors, le . . . . . . . . . . . . . . . . . . . . . . . . 113, 114 Detail, levels of . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 Devices . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113 Diagrams, data structures . . . . . . . . . . . . . . . . . . . 215 Dierence between while and do . . . . . . . . . . . . . . 64 Dierent type argument error . . . . . . . . . . . . . . . . 234 Directives, preprocessor . . . . . . . . . . . . . . . . . . . 73, 75 Directives, preprocessor, example . . . . . . . . . . . . . 75 Disadvantages of black boxes . . . . . . . . . . . . . . . . . . 1 Disk input . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241 Disk output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241
do and while, dierence between . . . . . . . . . . . . . . 64 Dot-slash (./) prex in shell . . . . . . . . . . . . . . . . . . 3 Dynamic data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 212 Dynamic data structures . . . . . . . . . . . . . . . . . . . . 216
E
editor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174 Emacs Info reader . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi End-of-le functions . . . . . . . . . . . . . . . . . . . . . . . . 122 End-of-le indicator . . . . . . . . . . . . . . . . . . . . . . . . . 122 End-of-le indicator, resetting . . . . . . . . . . . . . . . 123 Environment variables . . . . . . . . . . . . . . . . . . . . . . 171 EOR, truth table . . . . . . . . . . . . . . . . . . . . . . . . . . . 193 Equality operator, confused with assignment operator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32, 37 Equals sign (=) . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 Equivalence of pointers and arrays . . . . . . . . . . . 101 Error cascade . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 Error functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122 Error indicator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122 Error indicator, resetting . . . . . . . . . . . . . . . . . . . . 123 Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 Errors, compile time . . . . . . . . . . . . . . . . . . . . . . . . 231 Errors, compile-time . . . . . . . . . . . . . . . . . . . . . . . . . . 5 Errors, methematical. . . . . . . . . . . . . . . . . . . . . . . . 238 Errors, run-time . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 Errors, syntax . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 Errors, type . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5, 6 Errors, typographical. . . . . . . . . . . . . . . . . . . . . . . . . . 6 Example function . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 Example program, substantial . . . . . . . . . . . . . . . 241 Exceptions, oating-point . . . . . . . . . . . . . . . . . . . 238 Exclusive OR assignment . . . . . . . . . . . . . . . . . . . . 190 Exclusive OR, bitwise, truth table . . . . . . . . . . . 193 Executable le . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4, 6 Executable le, running . . . . . . . . . . . . . . . . . . . . . . . 3 Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33 Expressions, constant . . . . . . . . . . . . . . . . . . . . . . . 201 External variables . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
278
Concept index
F
False Boolean value . . . . . . . . . . . . . . . . . . . . . . . . . . 37 fclose command, example of . . . . . . . . . . . . . . . . 117 FDL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi File creation. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 154 File descriptors . . . . . . . . . . . . . . . . . . . . 113, 114, 151 File functions, low-level . . . . . . . . . . . . . . . . . . . . . 151 File name conventions . . . . . . . . . . . . . . . . . . . . . . . . . 4 File name errors, usual . . . . . . . . . . . . . . . . . . . . . . 151 File operations, high-level . . . . . . . . . . . . . . . . . . . 114 File operations, low-level . . . . . . . . . . . . . . . . . . . . 114 File position . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120 File position indicator . . . . . . . . . . . . . . . . . . . . . . . 148 File position, compared to bookmark . . . . . . . . . 120 File routines, high-level . . . . . . . . . . . . . . . . . . . . . 115 File, executable . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4, 6 File, header . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 File, library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 File, object . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 File, object code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 File, source code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 Files, closing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 116 Files, header . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81 Files, high-level operations on . . . . . . . . . . . . . . . 114 Files, low-level operations on . . . . . . . . . . . . . . . . 114 Files, opening . . . . . . . . . . . . . . . . . . . . . . . . . . 113, 115 Files, random-access . . . . . . . . . . . . . . . . . . . . . . . . 120 findex, example of . . . . . . . . . . . . . . . . . . . . . . . . . 135 Finding le positions at a low level . . . . . . . . . . . 157 Flags . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190 Flexibility of for command . . . . . . . . . . . . . . . . . . . 67 Floating point numbers . . . . . . . . . . . . . . . . . . . . . . 21 Floating point variables . . . . . . . . . . . . . . . . . . . . . . 21 Floating-point exceptions . . . . . . . . . . . . . . . . . . . . 238 Flushing buers . . . . . . . . . . . . . . . . . . . . . . . . . . . . 237 Flushing streams . . . . . . . . . . . . . . . . . . . . . . . . . . . 122 fopen command, example of . . . . . . . . . . . . . . . . . 116 for command, exibility of . . . . . . . . . . . . . . . . . . . 67 for loops and arrays . . . . . . . . . . . . . . . . . . . . . . . . . 93 for loops, nested . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98 Formal parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 Format strings, printf . . . . . . . . . . . . . . . . . . . . . . 125 Formatted input conversion speciers . . . . 137, 138 Formatted output conversion speciers . . . . . . . 126 Formatted output conversion speciers, modiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126, 128
Formatted output conversion speciers, table of . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126 Formatted string input . . . . . . . . . . . . . . . . . . . . . . 136 Formatted string input functions, deprecated . . 140 Formatted string output. . . . . . . . . . . . . . . . . . . . . 125 Formatted string output functions, deprecated . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131 Formatting code, style guidelines . . . . . . . . . . . . . 227 Free Documentation License . . . . . . . . . . . . . . . . . . xi Free software . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi Freedom of style in C language . . . . . . . . . . . . . . . . 1 fsync, example of . . . . . . . . . . . . . . . . . . . . . . . . . . 157 Full buering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122 Function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Function declarations . . . . . . . . . . . . . . . . . . . . . . . . 15 Function names . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 Function names, characters available for . . . . . . . 13 Function names, style guidelines for . . . . . . . . . . 228 Function prototypes. . . . . . . . . . . . . . . . . . . . . . . . . . 15 Function prototypes, parameters in. . . . . . . . . . . . 42 Function prototypes, reasons for using . . . . . . . . . 16 Function values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 Function, as building block . . . . . . . . . . . . . . . . . . . . 9 Function, example . . . . . . . . . . . . . . . . . . . . . . . . . . . 14 Function, main . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 Functions, as buildings . . . . . . . . . . . . . . . . . . . . . . . 27 Functions, common library . . . . . . . . . . . . . . . . . . . 84 Functions, declaring . . . . . . . . . . . . . . . . . . . . . . . . . . 15 Functions, macro . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 Functions, macro, caveats . . . . . . . . . . . . . . . . . . . . 76 Functions, macro, example . . . . . . . . . . . . . . . . . . . 77 Functions, mathematical . . . . . . . . . . . . . . . . . . . . . 88 Functions, names of . . . . . . . . . . . . . . . . . . . . . . . . . . 13 Functions, prototyping . . . . . . . . . . . . . . . . . . . . . . . 15 Functions, return values . . . . . . . . . . . . . . . . . . . . . . 14 Functions, returning values from . . . . . . . . . . . . . . 14 Functions, string library . . . . . . . . . . . . . . . . . . . . . 108 Functions, variadic . . . . . . . . . . . . . . . . . . . . . . . . . . . 45 Functions, with values. . . . . . . . . . . . . . . . . . . . . . . . 14
Concept index
279
G
GCC. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 GDB, introduction to . . . . . . . . . . . . . . . . . . . . . . . 239 general-purpose programming . . . . . . . . . . . . . . . . . . 1 getline, example of . . . . . . . . . . . . . . . . . . . . . . . . 133 Global scope . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 Global variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 Global variables and recursion . . . . . . . . . . . . . . . 237 Global variables, style guidelines for . . . . . . . . . . 229 GNU C Compiler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 GNU C Library . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113 GNU Chess . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96 GNU Compiler Collection . . . . . . . . . . . . . . . . . . . . . 4 GNU FDL . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi GNU Free Documentation License . . . . . . . . . . . . . xi GNU long options . . . . . . . . . . . . . . . . . . . . . . 163, 241 GNU Project . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi GNU shell . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 GNU style guidelines . . . . . . . . . . . . . . . . . . . . . . . . . 11 GNU system, stability of . . . . . . . . . . . . . . . . . . . . . . 6 GNU/Linux . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi goal . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176 goal, makele, default . . . . . . . . . . . . . . . . . . . . . . . 176
Initialization and pointers . . . . . . . . . . . . . . . . . . . . 51 Initialization, style guidelines for . . . . . . . . . . . . . 228 Initializing arrays . . . . . . . . . . . . . . . . . . . . . 93, 98, 99 Initializing data structurse . . . . . . . . . . . . . . . . . . 218 Initializing multidimensional arrays . . . . . . . . . . . 98 Initializing strings . . . . . . . . . . . . . . . . . . . . . . . . . . 105 Initializing structures . . . . . . . . . . . . . . . . . . . . . . . 210 Initializing variables . . . . . . . . . . . . . . . . . . . . . . . . . 22 Input . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113 Input and output . . . . . . . . . . . . . . . . . . . . . . . . . . . 113 Input conversion speciers, formatted . . . . 137, 138 Input functions, string, deprecated formatted . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 140 Input, block . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117 Input, disk . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241 Input, single-character . . . . . . . . . . . . . . . . . . . . . . 144 Input, string . . . . . . . . . . . . . . . . . . . . . . 123, 132, 134 Input, string formatted . . . . . . . . . . . . . . . . . . . . . . 136 Integer variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 Integer variables, sizes of . . . . . . . . . . . . . . . . . . . . . 19 International Obfuscated C Code Contest . . . . . . 42
J
Jargon . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi
H
Header le . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 Header les . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81 Header les, for libraries . . . . . . . . . . . . . . . . . . . . 181 Hidden assignments . . . . . . . . . . . . . . . . . . . . . . . . . 185 Hidden operators . . . . . . . . . . . . . . . . . . . . . . . . . . . 185 Hidden operators and arrays . . . . . . . . . . . . . . . . . 187 Hidden operators, style guidelines for . . . . . . . . . 229 High level, the . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 High-level le operations . . . . . . . . . . . . . . . . . . . . 114 High-level le routines . . . . . . . . . . . . . . . . . . . . . . 115 High-level language, C language as . . . . . . . . . . . . . 1
K
Kinds of library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83
L
Levels of detail . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 Libraries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81 Libraries, compiling . . . . . . . . . . . . . . . . . . . . . . . . . 180 Libraries, linking to your code . . . . . . . . . . . . . . . . 81 Libraries, shared . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83 Libraries, shared, creating . . . . . . . . . . . . . . . . . . . 181 Libraries, static . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83 Libraries, static, creating . . . . . . . . . . . . . . . . . . . . 181 Library le . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 Library functions, common . . . . . . . . . . . . . . . . . . . 84 Library functions, string. . . . . . . . . . . . . . . . . . . . . 108 Library header les . . . . . . . . . . . . . . . . . . . . . . . . . 181 Library, kinds of . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83 Line buering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122
I
if statements, nested . . . . . . . . . . . . . . . . . . . . . . . . 57 Implicit makele rules, introduction . . . . . . . . . . 178 Inclusive OR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 Inclusive OR assignment . . . . . . . . . . . . . . . . . . . . 190 Inclusive OR, bitwise, truth table . . . . . . . . . . . . 192 Info reader . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi
280
Concept index
Linked lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216, 241 Linker . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 Linking libraries to your code . . . . . . . . . . . . . . . . . 81 Links . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216 Lists . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216 Lists, linked . . . . . . . . . . . . . . . . . . . . . . . . . . . 216, 241 Local scope . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 Local variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 Local variables, scope of . . . . . . . . . . . . . . . . . . . . . . 28 Local variables, visibility of . . . . . . . . . . . . . . . . . . . 28 Logical operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 Long options, GNU. . . . . . . . . . . . . . . . . . . . . 163, 241 Loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63 Loops, nested . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71, 98 Loops, speeding . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69 Loops, terminating . . . . . . . . . . . . . . . . . . . . . . . . . . . 69 Loops, terminating with break . . . . . . . . . . . . . . . . 69 Loops, terminating with return . . . . . . . . . . . . . . . 69 Low level, closing les at . . . . . . . . . . . . . . . . . . . . 154 Low level, deleting les at . . . . . . . . . . . . . . . . . . . 158 Low level, nding le positions at . . . . . . . . . . . . 157 Low level, opening les at . . . . . . . . . . . . . . . . . . . 152 Low level, reading les at. . . . . . . . . . . . . . . . . . . . 155 Low level, renaming les at . . . . . . . . . . . . . . . . . . 159 Low level, the . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 Low level, writing les at . . . . . . . . . . . . . . . . . . . . 156 Low-level le functions . . . . . . . . . . . . . . . . . . . . . . 151 Low-level le operations . . . . . . . . . . . . . . . . . . . . . 114 Lvalues . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31
Makele, simple . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175 Makeles, writing . . . . . . . . . . . . . . . . . . . . . . . . . . . 173 Masks, bit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192, 193 Math functions, example of . . . . . . . . . . . . . . . . . . . 90 Mathematical errors . . . . . . . . . . . . . . . . . . . . . . . . 238 Mathematical function . . . . . . . . . . . . . . . . . . . . . . . 88 Mathematical operators . . . . . . . . . . . . . . . . . . . . . . 31 Member operator of structures . . . . . . . . . . . . . . . 207 Members of structures . . . . . . . . . . . . . . . . . . . . . . 205 Memory addresses . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 Memory allocation . . . . . . . . . . . . . . . . . . . . . . . . . . 212 Memory, random-access . . . . . . . . . . . . . . . . . . . . . 120 Multidimensional arrays . . . . . . . . . . . . . . . . . . 71, 96 Multidimensional arrays, initializing . . . . . . . . . . . 98 Multiple les, compiling . . . . . . . . . . . . . . . . . . . . . 172 Multiplication operator. . . . . . . . . . . . . . . . . . . . . . . 31
N
Nested for loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98 Nested if statements . . . . . . . . . . . . . . . . . . . . . . . . 57 Nested loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71, 98 Nested loops and arrays . . . . . . . . . . . . . . . . . . . . . . 98 Nested structures . . . . . . . . . . . . . . . . . . . . . . . . . . . 208 Newline character, quoting in makele . . . . . . . . 175 No buering . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122 Node, root . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216 Nodes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216 Nodes, root . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218 NOT, bitwise, truth table . . . . . . . . . . . . . . . . . . . 192 Null pointers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218 Numbers, oating point . . . . . . . . . . . . . . . . . . . . . . 21
M
Macro functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 76 Macro functions, caveats . . . . . . . . . . . . . . . . . . . . . 76 Macro functions, example . . . . . . . . . . . . . . . . . . . . 77 Macros. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 main function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 makele . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 173 Makele commands, introduction to . . . . . . . . . . 174 Makele prerequisites, introduction to . . . . . . . . 174 Makele rule parts . . . . . . . . . . . . . . . . . . . . . . . . . . 174 Makele rule, introduction to . . . . . . . . . . . . . . . . 174 Makele rules, implicit, introduction . . . . . . . . . 178 Makele rules, tab characters in . . . . . . . . . . . . . 174 Makele targets, introduction to . . . . . . . . . . . . . 174 makele, processing . . . . . . . . . . . . . . . . . . . . . . . . . 176
O
Obfuscated C Code Contest, International . . . . . 42 Object code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 Object code le . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 Object le. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 One-based arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91 open, example of. . . . . . . . . . . . . . . . . . . . . . . . . . . . 154 Opening les . . . . . . . . . . . . . . . . . . . . . . . . . . . 113, 115 Opening les at a low level . . . . . . . . . . . . . . . . . . 152 Operating system . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Operating systems, 64-bit . . . . . . . . . . . . . . . . . . . . 19 Operations, order of . . . . . . . . . . . . . . . . . . . . . . . . . 34
Concept index
281
Operator precedence . . . . . . . . . . . . . . . . . . . . . . . . . 34 Operator, addition . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 Operator, assignment . . . . . . . . . . . . . . . . . . . . . . . . 31 Operator, cast . . . . . . . . . . . . . . . . . . . . . . . . . . . 31, 50 Operator, comma . . . . . . . . . . . . . . . . . . . . . . . . . . . 189 Operator, multiplication . . . . . . . . . . . . . . . . . . . . . . 31 Operator, subtraction . . . . . . . . . . . . . . . . . . . . . . . . 31 Operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 31 Operators, arithmetic . . . . . . . . . . . . . . . . . . . . . 32, 35 Operators, bitwise . . . . . . . . . . . . . . . . . . . . . . . . . . 190 Operators, comparison . . . . . . . . . . . . . . . . 31, 37, 38 Operators, hidden . . . . . . . . . . . . . . . . . . . . . . . . . . 185 Operators, hidden, and arrays . . . . . . . . . . . . . . . 187 Operators, logical . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 Operators, mathematical . . . . . . . . . . . . . . . . . . . . . 31 Operators, precedence of . . . . . . . . . . . . . . . . . . . . 255 Operators, shift. . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190 Operators, special assignment . . . . . . . . . . . . . 34, 35 Optimizing loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 Options, command-line . . . . . . . . . . . . . . . . . . . . . . 163 OR, bitwise exclusive, truth table . . . . . . . . . . . . 193 OR, bitwise inclusive, truth table . . . . . . . . . . . . 192 OR, inclusive . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 Order of operation, unary operators . . . . . . . . . . . 34 Order of operations . . . . . . . . . . . . . . . . . . . . . . . . . . 34 Output . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113 Output conversion speciers, formatted . . . . . . . 126 Output conversion speciers, formatted, modiers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126, 128 Output conversion speciers, formatted, table of . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 126 Output, block . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 117 Output, disk . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 241 Output, formatted string . . . . . . . . . . . . . . . . . . . . 125 Output, single-character . . . . . . . . . . . . . . . . . . . . . 144 Output, string . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123 Output, uncoordinated . . . . . . . . . . . . . . . . . . . . . . 237 Output, unformatted string. . . . . . . . . . . . . . . . . . 123
P
Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . 13, 28, 41 Parameters in function prototypes . . . . . . . . . . . . 42 Parameters, actual . . . . . . . . . . . . . . . . . . . . . . . . . . . 43 Parameters, arrays as . . . . . . . . . . . . . . . . . . . . . . . 101 Parameters, communication via . . . . . . . . . . . . . . . 28
Parameters, declaring . . . . . . . . . . . . . . . . . . . . . . . . 42 Parameters, formal. . . . . . . . . . . . . . . . . . . . . . . . . . . 43 Parameters, passing arrays as . . . . . . . . . . . . . . . . 101 Parameters, value . . . . . . . . . . . . . . . . . . . . . . . . 41, 43 Parameters, value, example of . . . . . . . . . . . . . . . . 41 Parameters, variable . . . . . . . . . . . . . . . . . . 41, 51, 53 Parentheses . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 Parse error . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231 Parts of makele rules. . . . . . . . . . . . . . . . . . . . . . . 174 Passes, compiler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 Passing actual parameters as pointers . . . . . . . . . 53 Passing arrays as parameters . . . . . . . . . . . . . . . . 101 Passing by reference . . . . . . . . . . . . . . . . . . . . . . . . . 51 Passing by reference, origin of term . . . . . . . . . . . 47 Passing information to program . . . . . . . . . . . . . . 161 Passing information with parameters . . . . . . . . . . 41 Passing parameters . . . . . . . . . . . . . . . . . . . . . . . . . . 41 Passing parameters by reference . . . . . . . . . . . . . . 41 Passing parameters by value. . . . . . . . . . . . . . . 41, 43 Peripherals . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113 Peripherals and C language . . . . . . . . . . . . . . . . . . . . 2 Peripherals as devices . . . . . . . . . . . . . . . . . . . . . . . 113 Pipe symbol (|) . . . . . . . . . . . . . . . . . . . . . . . . . . . 149 Pipes, programming with . . . . . . . . . . . . . . . . . . . . 149 Pointer expressions, pronunciation of . . . . . . . . . . 49 Pointer types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49 Pointer types, casting . . . . . . . . . . . . . . . . . . . . . . . . 50 Pointers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 Pointers and arrays, equivalence of . . . . . . . . . . . 101 Pointers and initialization . . . . . . . . . . . . . . . . . . . . 51 Pointers to structures . . . . . . . . . . . . . . . . . . . . . . . 209 Pointers, types of . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49 POSIX standard, command-line conventions . . 163 Postx -- operator . . . . . . . . . . . . . . . . . . . . . . . . . 187 Postx ++ operator . . . . . . . . . . . . . . . . . . . . . . . . . 187 Postx and prex ++, confused . . . . . . . . . . . . . . . 236 Postx operators . . . . . . . . . . . . . . . . . . . . . . . . . . . 187 Power of C language . . . . . . . . . . . . . . . . . . . . . . . xi, 2 Precedence of operators . . . . . . . . . . . . . . . . . . . . . 255 Precedence, operator . . . . . . . . . . . . . . . . . . . . . . . . . 34 Prex -- operator . . . . . . . . . . . . . . . . . . . . . . . . . . 187 Prex ++ operator . . . . . . . . . . . . . . . . . . . . . . . . . . 187 Prex operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . 187 Preprocessor . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73 Preprocessor directives . . . . . . . . . . . . . . . . . . . . 73, 75 Preprocessor directives, example . . . . . . . . . . . . . . 75
282
Concept index
Prerequisite, combining rules by . . . . . . . . . . . . . 179 printf format strings . . . . . . . . . . . . . . . . . . . . . . . 125 printf, example of . . . . . . . . . . . . . . . . . . . . . . . . . 128 processing a makele . . . . . . . . . . . . . . . . . . . . . . . . 176 programming, general-purpose . . . . . . . . . . . . . . . . . 1 Programs, annotating . . . . . . . . . . . . . . . . . . . . . . . . 10 Pronunciation of pointer expressions . . . . . . . . . . 49 Prototypes, function, parameters in . . . . . . . . . . . 42 Prototyping function . . . . . . . . . . . . . . . . . . . . . . . . . 15 Pseudo-code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 Pushback . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 148 Pushing back characters . . . . . . . . . . . . . . . . . . . . . 148
S
scanf, string overows with . . . . . . . . . . . . . . . . . 141 Scope of local variables . . . . . . . . . . . . . . . . . . . . . . . 28 Scope of variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 Scope, example of. . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 Scope, global . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 Scope, local . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 Setting up data structures . . . . . . . . . . . . . . . . . . . 217 Shakespeare . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 Shared libraries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83 Shared libraries, creating . . . . . . . . . . . . . . . . . . . . 181 shell command . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176 Shell, command. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Shell, GNU . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Shift operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 190 Simple makele . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 175 Simplest C program . . . . . . . . . . . . . . . . . . . . . . . . . . . 9 Simplifying makeles with variables . . . . . . . . . . 177 Single-character input . . . . . . . . . . . . . . . . . . . . . . . 144 Single-character output . . . . . . . . . . . . . . . . . . . . . 144 Software, free . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi Source code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 Source code le . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4 Special assignment operators . . . . . . . . . . . . . . 34, 35 Special assignment operators, example. . . . . . . . . 36 Special characters. . . . . . . . . . . . . . . . . . . . . . . . . . . 257 Speeding loops . . . . . . . . . . . . . . . . . . . . . . . . . . . 69, 70 sscanf example . . . . . . . . . . . . . . . . . . . . . . . . . . . . 137 sscanf, common errors with . . . . . . . . . . . . . . . . . 137 Stability of GNU system . . . . . . . . . . . . . . . . . . . . . . 6 Stack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221 Stack, variable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 Standard input . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122 Standard output . . . . . . . . . . . . . . . . . . . . . . . . . . . . 122 Statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 Static libraries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 83 Static libraries, creating . . . . . . . . . . . . . . . . . . . . . 181 Static variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 Storage classes . . . . . . . . . . . . . . . . . . . . . . . . . . . 24, 25 Storage, false assumptions about . . . . . . . . . . . . . 236 Stream buering . . . . . . . . . . . . . . . . . . . . . . . . . . . . 121 Streams . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 113, 114 Streams, reading arrays from . . . . . . . . . . . . 117, 118 Streams, writing arrays to . . . . . . . . . . . . . . 117, 118 String arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 107 String constants . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
Q
Quoting newline character in makele . . . . . . . . 175
R
RAM . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 120 Random-access les . . . . . . . . . . . . . . . . . . . . . . . . . 120 Random-access memory . . . . . . . . . . . . . . . . . . . . . 120 read, example of. . . . . . . . . . . . . . . . . . . . . . . . . . . . 157 Reading arrays from streams . . . . . . . . . . . . 117, 118 Reading les at a low level . . . . . . . . . . . . . . . . . . 155 recompilation. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 174 Recursion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221 Recursion and global variables . . . . . . . . . . . . . . . 237 Recursion, controlled . . . . . . . . . . . . . . . . . . . . . . . . 222 Recursion, controlled, with data structures. . . . 224 Recursive data structures. . . . . . . . . . . . . . . . . . . . 224 Reference, passing by . . . . . . . . . . . . . . . . . . . . . . . . 51 Reference, passing by, origin of term . . . . . . . . . . 47 Reference, passing parameters by . . . . . . . . . . . . . 41 relinking . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 176 Renaming les at a low level . . . . . . . . . . . . . . . . . 159 Reserved words in C . . . . . . . . . . . . . . . . . . . . . . . . 253 Return codes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 return, terminating loops with . . . . . . . . . . . . . . . 69 Returning values from functions . . . . . . . . . . . . . . 14 Root node . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216 Root nodes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 218 Run-time errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 Running an executable le . . . . . . . . . . . . . . . . . . . . . 3
Concept index
283
String input . . . . . . . . . . . . . . . . . . . . . . . 123, 132, 134 String input functions, deprecated . . . . . . . . . . . 134 String input functions, deprecated formatted . . 140 String input, formatted . . . . . . . . . . . . . . . . . . . . . 136 String library functions . . . . . . . . . . . . . . . . . . . . . 108 String output. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 123 String output functions, formatted, deprecated . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 131 String output, formatted . . . . . . . . . . . . . . . . . . . . 125 String output, unformatted . . . . . . . . . . . . . . . . . . 123 String overows with scanf . . . . . . . . . . . . . . . . . 141 String values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105 Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105 Strings, confused with characters. . . . . . . . . . . . . 105 Strings, initializing . . . . . . . . . . . . . . . . . . . . . . . . . . 105 Structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205 Structures, -> operator . . . . . . . . . . . . . . . . . . . . . . 207 Structures, . dot operator . . . . . . . . . . . . . . . . . . . 207 Structures, arrays of . . . . . . . . . . . . . . . . . . . . . . . . 208 Structures, as distinguished from data structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205 Structures, data . . . . . . . . . . . . . . . . . . . . . . . . . . . . 205 Structures, declaring . . . . . . . . . . . . . . . . . . . . . . . . 205 Structures, declaring with typedef . . . . . . . . . . . 206 Structures, initializing. . . . . . . . . . . . . . . . . . . . . . . 210 Structures, member operator of . . . . . . . . . . . . . . 207 Structures, members of . . . . . . . . . . . . . . . . . . . . . . 205 Structures, nested . . . . . . . . . . . . . . . . . . . . . . . . . . 208 Structures, pointers to . . . . . . . . . . . . . . . . . . . . . . 209 Structures, using . . . . . . . . . . . . . . . . . . . . . . . . . . . 207 Style . . . . . . . . . . . . . . . . . . . . . . . . . . . 10, 11, 189, 227 Style guidelines . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227 Style guidelines for comments . . . . . . . . . . . . . . . . 228 Style guidelines for declarations . . . . . . . . . . . . . . 228 Style guidelines for formatting code . . . . . . . . . . 227 Style guidelines for function names . . . . . . . . . . . 228 Style guidelines for global variables. . . . . . . . . . . 229 Style guidelines for hidden operators . . . . . . . . . 229 Style guidelines for initialization . . . . . . . . . . . . . 228 Style guidelines for variable names . . . . . . . . . . . 228 Style, freedom of in C language . . . . . . . . . . . . . . . . 1 Style, warning about . . . . . . . . . . . . . . . . . . . . . . . . 189 Subtraction operator . . . . . . . . . . . . . . . . . . . . . . . . . 31 Suucinctness of C language . . . . . . . . . . . . . . . . . . . . 1 switch statement, breaking out of . . . . . . . . . 60, 62 Syntax errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5
T
Tab characters in makele rules . . . . . . . . . . . . . . 174 Tables, truth . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192 Template string, . . . . . . . . . . . . . . . . . . . . . . . . . . . 137 Terminating loops . . . . . . . . . . . . . . . . . . . . . . . . . . . 69 Terminating loops with break . . . . . . . . . . . . . . . . 69 Terminating loops with return . . . . . . . . . . . . . . . 69 Texinfo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi To be or not to be . . . . . . . . . . . . . . . . . . . . . . . . . . . 38 Too few parameters error . . . . . . . . . . . . . . . . . . . . 234 Trees . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 216 Trees, binary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 217 True Boolean value . . . . . . . . . . . . . . . . . . . . . . . . . . 37 Truth tables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 192 Type errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5, 6 typedef, declaring structures with . . . . . . . . . . . 206 Types, casting . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22 Types, casting, example . . . . . . . . . . . . . . . . . . . . . . 23 Types, dening your own . . . . . . . . . . . . . . . . . . . . . . 6 Types, pointer . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49 Types, variable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 Typographical errors . . . . . . . . . . . . . . . . . . . . . . . . . . 6
U
Unary operators . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34 Unary operators, order of operation . . . . . . . . . . . 34 Uncoordinated output. . . . . . . . . . . . . . . . . . . . . . . 237 Undened reference error . . . . . . . . . . . . . . . . . . . . 232 Unforgiving nature of C language . . . . . . . . . . . . . . xi Unformatted string output . . . . . . . . . . . . . . . . . . 123 Unions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 213 Unions and ag variables . . . . . . . . . . . . . . . . . . . . 214 Unions, declaring . . . . . . . . . . . . . . . . . . . . . . . . . . . 213 Unions, using . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214 Unreading characters . . . . . . . . . . . . . . . . . . . . . . . 148 Using structures . . . . . . . . . . . . . . . . . . . . . . . . . . . . 207 Using unions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 214 Usual le name errors . . . . . . . . . . . . . . . . . . . . . . . 151
284
Concept index
V
Value parameters . . . . . . . . . . . . . . . . . . . . . . . . . 41, 43 Value parameters, example of . . . . . . . . . . . . . . . . . 41 Value, passing parameters by . . . . . . . . . . . . . . . . . 41 Values, Boolean . . . . . . . . . . . . . . . . . . . . . . . . . . 31, 37 Variable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 Variable declaration . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 Variable declarations . . . . . . . . . . . . . . . . . . . . . . . . . 13 Variable names, characters available for . . . . . . . 19 Variable names, style guidelines for . . . . . . . . . . 228 Variable parameters . . . . . . . . . . . . . . . . . . . 41, 51, 53 Variable stack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29 Variable types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 Variables, declaring . . . . . . . . . . . . . . . . . . . . . . . 19, 21 Variables, environment . . . . . . . . . . . . . . . . . . . . . . 171 Variables, external . . . . . . . . . . . . . . . . . . . . . . . . . . . 24 Variables, oating point . . . . . . . . . . . . . . . . . . . . . . 21 Variables, global . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 Variables, global, and recursion . . . . . . . . . . . . . . 237 Variables, initializing . . . . . . . . . . . . . . . . . . . . . . . . . 22 Variables, integer . . . . . . . . . . . . . . . . . . . . . . . . . . . . 19 Variables, integer, sizes of . . . . . . . . . . . . . . . . . . . . 19 Variables, local . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 Variables, local, scope of . . . . . . . . . . . . . . . . . . . . . 28
Variables, local, visibility of . . . . . . . . . . . . . . . . . . 28 Variables, scope of . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 Variables, simplifying makeles with . . . . . . . . . 177 Variables, static . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25 Variables, visibility of . . . . . . . . . . . . . . . . . . . . . . . . 27 Variadic functions . . . . . . . . . . . . . . . . . . . . . . . . . . . 45 Visibility of local variables . . . . . . . . . . . . . . . . . . . . 28 Visibility of variables . . . . . . . . . . . . . . . . . . . . . . . . . 27
W
Walls, as metaphors for curly brackets . . . . . . . . . 27 while and do, dierence between . . . . . . . . . . . . . . 64 write, example of . . . . . . . . . . . . . . . . . . . . . . . . . . 157 Writing arrays to streams . . . . . . . . . . . . . . . 117, 118 Writing les at a low level . . . . . . . . . . . . . . . . . . . 156 Writing makeles . . . . . . . . . . . . . . . . . . . . . . . . . . . 173
X
XOR, truth table . . . . . . . . . . . . . . . . . . . . . . . . . . . 193
Z
Zero-based arrays in C . . . . . . . . . . . . . . . . . . . . . . . 91
285
Characters
In C, single characters are written enclosed by single quotes. This is in contrast to strings of characters, which use double quotes ("..."). int ch; ch = a; would give ch the value of the character a. The same eect can also be achieved by writing: char ch = a; It is also possible to have the type: unsigned char This admits ASCII values from 0 to 255, rather than -128 to 127.
286
var1 = 23; var2 = var1; The variable or value on either side of the = symbol must usually be of the same type. However, integers and characters will interconvert because characters are stored by their ASCII codes (which are integers!) Thus the following will work: int i; char ch = A; i = ch; printf ("The ASCII code of %c is %d",ch,i); The result of this would be: The ASCII code of A is 65
Function pointers
You can create pointers to functions as well as to variables. Function pointers can be tricky, however, and caution is advised in using them. Function pointers allow you to pass functions as a parameters to another function. This enables you to give the latter function a choice of functions to call. That is, you can plug in a new function in place of an old one simply by passing a dierent parameter. This technique is sometimes called indirection or vectoring. To pass a pointer for one function to a second function, simply use the name of the rst function, as long as there is no variable with the same name. Do not include the rst functions parentheses or parameters when you pass its name. For example, the following code passes a pointer for the function named fred_function to the function barbara_function: void fred(); barbara (fred); Notice that fred is declared with a regular function prototype before barbara calls it. You must also declare barbara, of course: void barbara (void (*function_ptr)() ); Notice the parentheses around function_ptr and the parentheses after it. As far as barbara is concerned, any function passed to it is named (*function_ptr)(), and this is how fred is called in the example below: #include <stdio.h> void fred(); void barbara ( void (*function_ptr)() ); int main(); int main() { barbara (fred);
Function pointers
287
return 0; } void fred() { printf("fred here!\n"); } void barbara ( void (*function_ptr)() ) { /* Call fred */ (*function_ptr)(); } The output from this example is simply fred here!. Again, notice how barbara called fred. Given a pointer to a function, the syntax for calling the function is as follows: variable = (*function pointer)(parameter list); For example, in the program below, the function do_math calls the functions add and subtract with the following line: result = (*math_fn_ptr) (num1, num2); Here is the example program: #include <stdio.h> int int int int add (int, int); subtract (int, int); do_math (int (*math_fn_ptr) (int, int), int, int); main();
int main() { int result; result = do_math (add, 10, 5); printf ("Addition = %d.\n", result); result = do_math (subtract, 40, 5); printf ("Subtraction = %d.\n\n", result); return 0; } int add (int num1, int num2) { return (num1 + num2); }
288
int do_math (int (*math_fn_ptr) (int, int), int num1, int num2) { int result; printf ("\ndo_math here.\n"); /* Call one of the math functions passed to us: either add or subtract. */ result = (*math_fn_ptr) (num1, num2); return result; } The output from this program reads: do_math here. Addition = 15. do_math here. Subtraction = 35. You can also initialize a function pointer by setting it to the name of a function, then treating the function pointer as an ordinary function, as in the next example: #include <stdio.h> int main(); void print_it(); void (*fn_ptr)(); int main() { void (*fn_ptr)() = print_it; (*fn_ptr)(); return 0; } void print_it() { printf("We are here! We are here!\n\n"); } Remember to initialize any function pointers you use this way! If you do not, your program will probably crash, because the uninitialized function pointer will contain garbage.
Function pointers
Table of Contents
Preface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi 1 Introduction . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
1.1 The advantages of C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1.2 Questions for Chapter 1 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2
Using a compiler . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
2.1 Basic ideas about C . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.2 The compiler . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.3 File names . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.4 Errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.4.1 Typographical errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.4.2 Type errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.5 Questions for Chapter 2 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 4 4 5 6 6 6
Functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
4.1 4.2 4.3 4.4 4.5 4.6 Function names . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Function examples . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Functions with values . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Function prototyping . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . The exit function . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Questions for Chapter 4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13 14 14 15 16 17
5.6
ii
Scope . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
6.1 6.2 6.3 6.4 6.5 Global Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Local Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Communication via parameters . . . . . . . . . . . . . . . . . . . . . . . . . . Scope example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Questions for Chapter 6 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27 28 28 29 29
Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 41
8.1 8.2 8.3 8.4 8.5 Parameters in function prototypes . . . . . . . . . . . . . . . . . . . . . . . Value Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Actual parameters and formal parameters . . . . . . . . . . . . . . . . Variadic functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Questions for Chapter 8 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 42 42 43 45 45
Pointers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47
9.1 9.2 9.3 9.4 Pointer operators. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Pointer types . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Pointers and initialization . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Variable parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 9.4.1 Passing pointers correctly . . . . . . . . . . . . . . . . . . . . . . 9.4.2 Another variable parameter example . . . . . . . . . . . . 9.5 Questions for Chapter 9 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 47 49 51 51 52 53 54
10
Decisions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
10.1 if . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10.2 if... else... . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10.3 Nested if statements . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10.4 The ?. . . :. . . operator . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10.5 The switch statement . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10.6 Example Listing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 10.7 Questions for Chapter 10 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55 56 57 59 59 60 62
Function pointers
iii
11
Loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63
11.1 while . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.2 do. . . while . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.3 for . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.4 The exibility of for . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.5 Terminating and speeding loops . . . . . . . . . . . . . . . . . . . . . . . . 11.5.1 Terminating loops with break . . . . . . . . . . . . . . . . . 11.5.2 Terminating loops with return . . . . . . . . . . . . . . . . 11.5.3 Speeding loops with continue . . . . . . . . . . . . . . . . . 11.6 Nested loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11.7 Questions for Chapter 11 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 63 64 65 67 69 69 69 70 71 71
12
Preprocessor directives. . . . . . . . . . . . . . . . . . . 73
12.1 12.2 A few directives . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Macros . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.2.1 Macro functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.3 Extended macro example . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 12.4 Questions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73 74 76 77 80
13
Libraries . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
13.1 13.2 13.3 Header les . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Kinds of library . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Common library functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13.3.1 Character handling . . . . . . . . . . . . . . . . . . . . . . . . . . . 13.4 Mathematical functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13.5 Questions for Chapter 13 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81 83 84 85 88 90
14
Arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 91
14.1 14.2 14.3 14.4 14.5 14.6 14.7 Array bounds . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92 Arrays and for loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92 Multidimensional arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 96 Arrays and nested loops . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 98 Initializing arrays . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 99 Arrays as Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 101 Questions for Chapter 14 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 102
15
Strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105
15.1 15.2 15.3 15.4 15.5 Conventions and declarations . . . . . . . . . . . . . . . . . . . . . . . . . Initializing strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . String arrays. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . String library functions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Questions for Chapter 15 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 105 105 106 108 111
iv
16
Function pointers 16.5.6 Finding le positions at a low level. . . . . . . . . . . . 16.5.7 Deleting les at a low level . . . . . . . . . . . . . . . . . . . 16.5.8 Renaming les at a low level . . . . . . . . . . . . . . . . . Questions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 157 158 159 160
16.6
17
18
vi
19
20
21
Recursion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221
21.1 21.2 21.3 21.4 21.5 The stack . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21.1.1 The stack in detail. . . . . . . . . . . . . . . . . . . . . . . . . . . Controlled recursion . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Controlled recursion with data structures . . . . . . . . . . . . . . Recursion summary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Questions 21 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 221 221 222 224 225 226
Function pointers
vii
22
Style . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227
22.1 22.2 22.3 22.4 22.5 22.6 22.7 22.8 Formatting code . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Comments and style . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Variable and function names . . . . . . . . . . . . . . . . . . . . . . . . . . Declarations and initialization . . . . . . . . . . . . . . . . . . . . . . . . . Global variables and style . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Hidden operators and style . . . . . . . . . . . . . . . . . . . . . . . . . . . Final words on style . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Questions 22 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 227 228 228 228 229 229 230 230
23
Debugging . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231
23.1 Compile-time errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 231 23.1.1 parse error at. . . , parse error before. . . . . . . . . . 231 23.1.2 undened reference to. . . . . . . . . . . . . . . . . . . . . . . 232 23.1.3 unterminated string or character constant . . . . . 233 . . . undeclared (rst use in this function) . . . . . . . . . . . . . . . 233 23.2.1 dierent type arg . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234 23.2.2 too few parameters. . . , too many parameters. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 234 Run-time errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 235 23.3.1 Confusion of = and == . . . . . . . . . . . . . . . . . . . . . . . 235 23.3.2 Confusing foo++ and ++foo . . . . . . . . . . . . . . . . . . 236 23.3.3 Unwarranted assumptions about storage . . . . . . . 236 23.3.4 Array out of bounds . . . . . . . . . . . . . . . . . . . . . . . . . 237 23.3.5 Uncoordinated output . . . . . . . . . . . . . . . . . . . . . . . 237 23.3.6 Global variables and recursion . . . . . . . . . . . . . . . . 237 Mathematical errors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 238 Introduction to GDB . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239 Questions 23 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 239
23.2
23.3
24
Appendix A A note from the original author . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 251 Appendix B Appendix C Appendix D Appendix E Appendix F Reserved words in C . . . . . . . . . . 253 Precedence of operators . . . . . . . 255 Special characters . . . . . . . . . . . . . 257 Character conversion table . . . . . 259 A word about goto . . . . . . . . . . . . 261
viii
Appendix G
Bibliography. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 265 Glossary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 267 Code index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 269 Concept index . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 275 Bits and pieces . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285
Allocating memory for strings . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Characters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Assigning variables to one another. . . . . . . . . . . . . . . . . . . . . . . . . . . Function pointers . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 285 285 285 286