My Basket
You have nothing in your shopping cart yet.
Title: C language
Description: Full knowledge of c language..
Document Preview
Extracts from the notes are below, to see the PDF you'll receive please use the links above
Table of Contents
Preface
...
1
Introduction
...
1
1
...
1
1
...
3
1
...
7
1
...
8
1
...
8
1
...
1 File Copying
...
5
...
9
1
...
3 Line Counting
...
5
...
11
1
...
12
1
...
14
1
...
16
1
...
17
1
...
19
Chapter 2 - Types, Operators and Expressions
...
1 Variable Names
...
2 Data Types and Sizes
...
3 Constants
...
4 Declarations
...
5 Arithmetic Operators
...
6 Relational and Logical Operators
...
7 Type Conversions
...
8 Increment and Decrement Operators
...
9 Bitwise Operators
...
10 Assignment Operators and Expressions
...
11 Conditional Expressions
...
12 Precedence and Order of Evaluation
...
1
3
...
1
3
...
1
3
...
2
3
...
3
3
...
4
3
...
6
3
...
7
3
...
8
Chapter 4 - Functions and Program Structure
...
1 Basics of Functions
...
2 Functions Returning Non-integers
...
3 External Variables
...
4 Scope Rules
...
5 Header Files
...
6 Static Variables
...
7 Register Variables
...
8 Block Structure
...
9 Initialization
...
10 Recursion
...
11 The C Preprocessor
...
11
...
17
4
...
2 Macro Substitution
...
11
...
19
Chapter 5 - Pointers and Arrays
...
1 Pointers and Addresses
...
2 Pointers and Function Arguments
...
3 Pointers and Arrays
...
4 Address Arithmetic
...
5 Character Pointers and Functions
...
6 Pointer Arrays; Pointers to Pointers
...
7 Multi-dimensional Arrays
...
8 Initialization of Pointer Arrays
...
9 Pointers vs
...
17
5
...
18
5
...
22
5
...
24
Chapter 6 - Structures
...
1 Basics of Structures
...
2 Structures and Functions
...
3 Arrays of Structures
...
4 Pointers to Structures
...
5 Self-referential Structures
...
6 Table Lookup
...
7 Typedef
...
8 Unions
...
9 Bit-fields
...
1
7
...
1
7
...
2
7
...
3
7
...
4
7
...
7
7
...
9
7
...
10
7
...
11
7
...
1 String Operations
...
8
...
12
7
...
3 Ungetc
...
8
...
12
7
...
5 Storage Management
...
8
...
13
7
...
7 Random Number generation
...
1
8
...
1
8
...
1
8
...
3
8
...
5
8
...
5
8
...
8
8
...
12
Appendix A - Reference Manual
...
1 Introduction
...
2 Lexical Conventions
...
2
...
1
A
...
2 Comments
...
2
...
1
A
...
4 Keywords
...
2
...
2
A
...
6 String Literals
...
3 Syntax Notation
...
4 Meaning of Identifiers
...
4
...
4
A
...
2 Basic Types
...
4
...
5
A
...
4 Type Qualifiers
...
5 Objects and Lvalues
...
6 Conversions
...
6
...
6
A
...
2 Integral Conversions
...
6
...
6
A
...
4 Floating Types
...
6
...
7
A
...
6 Pointers and Integers
...
6
...
8
A
...
8 Pointers to Void
...
7 Expressions
...
7
...
8
A
...
2 Primary Expressions
...
7
...
9
A
...
4 Unary Operators
...
7
...
12
A
...
6 Multiplicative Operators
...
7
...
13
A
...
8 Shift Operators
...
7
...
14
A
...
10 Equality Operators
...
7
...
15
A
...
12 Bitwise Exclusive OR Operator
...
7
...
15
A
...
14 Logical AND Operator
...
7
...
15
A
...
16 Conditional Operator
...
7
...
16
iii
Table of Contents
Appendix A - Reference Manual
A
...
18 Comma Operator
...
7
...
17
A
...
17
A
...
1 Storage Class Specifiers
...
8
...
18
A
...
3 Structure and Union Declarations
...
8
...
22
A
...
5 Declarators
...
8
...
23
A
...
7 Initialization
...
8
...
28
A
...
9 Typedef
...
8
...
29
A
...
29
A
...
1 Labeled Statements
...
9
...
30
A
...
3 Compound Statement
...
9
...
31
A
...
5 Iteration Statements
...
9
...
32
A
...
32
A
...
1 Function Definitions
...
10
...
34
A
...
35
A
...
1 Lexical Scope
...
11
...
35
A
...
36
A
...
1 Trigraph Sequences
...
12
...
36
A
...
3 Macro Definition and Expansion
...
12
...
38
A
...
5 Conditional Compilation
...
12
...
40
A
...
7 Error Generation
...
12
...
40
A
...
9 Null directive
...
12
...
41
A
...
41
Appendix B - Standard Library
...
1
...
1
B
...
2 Formatted Output
...
1
...
4
B
...
4 Character Input and Output Functions
...
1
...
6
B
...
6 File Positioning Functions
...
1
...
6
B
...
h>
...
3 String Functions:
...
7 B
...
h>
...
5 Utility Functions:
...
9 iv Table of Contents Appendix B - Standard Library B
...
h>
...
7 Variable Argument Lists:
...
11 B
...
h>
...
9 Signals:
...
12 B
...
h>
...
11 Implementation-defined Limits:
...
h>
...
1 v Preface The computing world has undergone a revolution since the publication of The C Programming Language in 1978
...
During this time, C has changed too, although only modestly, and it has spread far beyond its origins as the language of the UNIX operating system
...
In 1983, the American National Standards Institute (ANSI) established a committee whose goal was to produce ``an unambiguous and machine-independent definition of the language C'', while still retaining its spirit
...
The standard formalizes constructions that were hinted but not described in the first edition, particularly structure assignment and enumerations
...
It specifies a standard library, with an extensive set of functions for performing input and output, memory management, string manipulation, and similar tasks
...
This Second Edition of The C Programming Language describes C as defined by the ANSI standard
...
For the most part, this makes no significant difference; the most visible change is the new form of function declaration and definition
...
We have tried to retain the brevity of the first edition
...
We have improved the exposition of critical features, such as pointers, that are central to C programming
...
For instance, the treatment of complicated declarations is augmented by programs that convert declarations into words and vice versa
...
Appendix A, the reference manual, is not the standard, but our attempt to convey the essentials of the standard in a smaller space
...
Appendix B is a summary of the facilities of the standard library
...
Appendix C is a concise summary of the changes from the original version
...
With a decade more experience, we still feel that way
...
We are deeply indebted to friends who helped us to produce this second edition
...
We are grateful for careful reading by Al Aho, Dennis Allison, Joe Campbell, G
...
Emlin, Karen Fortgang, Allen Holub, Andrew Hume, Dave Kristol, John Linderman, Dave Prosser, Gene Spafford, and Chris van Wyk
...
Dave Prosser answered many detailed questions about the ANSI standard
...
Rich Drechsler helped greatly with typesetting
...
Preface 1 2 Preface Brian W
...
Ritchie Index -- Preface to the first edition Compiled by tmdcjsl(skidrow8123@hotmail
...
C is not a ``very high level'' language, nor a ``big'' one, and is not specialized to any particular area of application
...
C was originally designed for and implemented on the UNIX operating system on the DEC PDP-11, by Dennis Ritchie
...
Production compilers also exist for several other machines, including the IBM System/370, the Honeywell 6000, and the Interdata 8/32
...
This book is meant to help the reader learn how to program in C
...
Most of the treatment is based on reading, writing and revising examples, rather than on mere statements of rules
...
All examples have been tested directly from the text, which is in machine-readable form
...
The book is not an introductory programming manual; it assumes some familiarity with basic programming concepts like variables, assignment statements, loops, and functions
...
In our experience, C has proven to be a pleasant, expressive and versatile language for a wide variety of programs
...
We hope that this book will help you to use it well
...
In particular, Mike Bianchi, Jim Blue, Stu Feldman, Doug McIlroy Bill Roome, Bob Rosin and Larry Rosler all read multiple volumes with care
...
Brian W
...
Ritchie Back to the Preface -- Index -- Introduction Compiled by tmdcjsl(skidrow8123@hotmail
...
It has been closely associated with the UNIX operating system where it was developed, since both the system and most of the programs that run on it are written in C
...
Many of the important ideas of C stem from the language BCPL, developed by Martin Richards
...
BCPL and B are ``typeless'' languages
...
The fundamental types are characters, and integers and floating point numbers of several sizes
...
Expressions are formed from operators and operands; any expression, including an assignment or a function call, can be a statement
...
C provides the fundamental control-flow constructions required for well-structured programs: statement grouping, decision making (if-else), selecting one of a set of possible values (switch), looping with the termination test at the top (while, for) or at the bottom (do), and early loop exit (break)
...
Any function may be called recursively
...
Function definitions may not be nested but variables may be declared in a block-structured fashion
...
Variables may be internal to a function, external but known only within a single source file, or visible to the entire program
...
C is a relatively ``low-level'' language
...
These may be combined and moved about with the arithmetic and logical operators implemented by real machines
...
There are no operations that manipulate an entire array or string, although structures may be copied as a unit
...
Finally, C itself provides no input/output facilities; there are no READ or WRITE statements, and no built-in file access methods
...
Most C implementations have included a reasonably standard collection of such functions
...
Although the absence of some of these features may seem like a grave deficiency, (``You mean I have to call a function to compare two character strings?''), keeping the language down to modest size has real benefits
...
A programmer can reasonably expect to know and understand and indeed regularly use the entire language
...
In 1983, the American National Standards Institute (ANSI) established a committee to provide a modern, comprehensive definition of C
...
Most of the features of the standard are already supported by modern compilers
...
The language is relatively little changed; one of the goals of the standard was to make sure that most existing programs would remain valid, or, failing that, that compilers could produce warnings of new behavior
...
A function declaration can now include a description of the arguments of the function; the definition syntax changes to match
...
There are other small-scale language changes
...
Floating-point computations may now be done in single precision
...
The preprocessor is more elaborate
...
A second significant contribution of the standard is the definition of a library to accompany C
...
A collection of standard headers provides uniform access to declarations of functions in data types
...
Most of the library is closely modeled on the ``standard I/O library'' of the UNIX system
...
Again, most programmers will not see much change
...
The standard library functions are only called explicitly, so they can be avoided if they are not needed
...
Although C matches the capabilities of many computers, it is independent of any particular machine architecture
...
The standard makes portability issues explicit, and prescribes a set of constants that characterize the machine on which the program is run
...
The original definition of C frowned on, but permitted, the interchange of pointers and integers; this has long since been eliminated, and the standard now requires the proper declarations and explicit conversions that had already been enforced by good compilers
...
Compilers will warn of most type errors, and there is no automatic conversion of incompatible data types
...
C, like any other language, has its blemishes
...
Nonetheless, C has proven to ben an extremely effective and expressive language for a wide variety of programming applications
...
Chapter 1 is a tutorial on the central part of C
...
The tutorial does assume a working knowledge of the basic elements of programming; there is no explanation of computers, of compilation, nor of the meaning of an expression like n=n+1
...
Chapters 2 through 6 discuss various aspects of C in more detail, and rather more formally, than does Chapter 2 Introduction Introduction 3 1, although the emphasis is still on examples of complete programs, rather than isolated fragments
...
Chapter 3 threats control flow: if-else, switch, while, for, etc
...
Chapter 5 discusses pointers and address arithmetic
...
Chapter 7 describes the standard library, which provides a common interface to the operating system
...
Chapter 8 describes an interface between C programs and the UNIX operating system, concentrating on input/output, the file system, and storage allocation
...
Appendix A contains a language reference manual
...
That document, however, is intended foremost for compiler writers
...
Appendix B is a summary of the standard library, again for users rather than implementers
...
In cases of doubt, however, the standard and one's own compiler remain the final authorities on the language
...
com) Back to Introduction -- Index -- Chapter 2 Introduction 3 Chapter 1 - A Tutorial Introduction Let us begin with a quick introduction in C
...
At this point, we are not trying to be complete or even precise (save that the examples are meant to be correct)
...
We are intentionally leaving out of this chapter features of C that are important for writing bigger programs
...
This approach and its drawbacks
...
And because the examples do not use the full power of C, they are not as concise and elegant as they might be
...
Another drawback is that later chapters will necessarily repeat some of this chapter
...
In any case, experienced programmers should be able to extrapolate from the material in this chapter to their own programming needs
...
Both groups can use it as a framework on which to hang the more detailed descriptions that begin in Chapter 2
...
1 Getting Started The only way to learn a new programming language is by writing programs in it
...
With these mechanical details mastered, everything else is comparatively easy
...
As a specific example, on the UNIX operating system you must create the program in a file whose name ends in ``
...
c, then compile it with the command cc hello
...
out
...
out by typing the command a
...
Chapter 1 - A Tutorial Introduction 1 2 Chapter 1 - A Tutorial Introduction Now, for some explanations about the program itself
...
A function contains statements that specify the computing operations to be done, and variables store values used during the computation
...
Our example is a function named main
...
This means that every program must have a main somewhere
...
The first line of the program, #include
...
The standard library is described in Chapter 7 and Appendix B
...
The parentheses after the function name surround the argument list
...
"hello, world\n"); } main calls library function printf to print this sequence of characters \n represents the newline character The first C program The statements of a function are enclosed in braces { }
...
printf is a library function that prints output, in this case the string of characters between the quotes
...
For the moment our only use of character strings will be as arguments for printf and other functions
...
If you leave out the \n (a worthwhile experiment), you will find that there is no line advance after the output is printed
...
printf never supplies a newline character automatically, so several calls may be used to build up an output line in stages
...
h> main() { printf("hello, "); printf("world"); 2 Chapter 1 - A Tutorial Introduction Chapter 1 - A Tutorial Introduction 3 printf("\n"); } to produce identical output
...
An escape sequence like \n provides a general and extensible mechanism for representing hard-to-type or invisible characters
...
There is a complete list in Section 2
...
Exercise 1-1
...
Experiment with leaving out parts of the program, to see what error messages you get
...
Experiment to find out what happens when prints's argument string contains \c, where c is some character not listed above
...
2 Variables and Arithmetic Expressions The next program uses the formula oC=(5/9)(oF-32) to print the following table of Fahrenheit temperatures and their centigrade or Celsius equivalents: 1 20 40 60 80 100 120 140 160 180 200 220 240 260 280 300 -17 -6 4 15 26 37 48 60 71 82 93 104 115 126 137 148 The program itself still consists of the definition of a single function named main
...
It introduces several new ideas, including comments, declarations, variables, arithmetic expressions, loops , and formatted output
...
h> /* print Fahrenheit-Celsius table for fahr = 0, 20,
...
, 300 */ are a comment, which in this case explains briefly what the program does
...
Comments may appear anywhere where a blank, tab or newline can
...
A declaration announces the properties of variables; it consists of a name and a list of variables, such as int fahr, celsius; int lower, upper, step; The type int means that the variables listed are integers; by contrast with float, which means floating point, i
...
, numbers that may have a fractional part
...
A float number is typically a 32-bit quantity, with at least six significant digits and magnitude generally between about 10-38 and 1038
...
There are also arrays, structures and unions of these basic types, pointers to them, and functions that return them, all of which we will meet in due course
...
Individual statements are terminated by semicolons
...
} The while loop operates as follows: The condition in parentheses is tested
...
Then the condition is re-tested, and if true, the body is executed again
...
There are no further statements in this program, so it terminates
...
The indentation emphasizes the logical structure of the program
...
We recommend writing only one statement per line, and using blanks around operators to clarify grouping
...
We have chosen one of several popular styles
...
Most of the work gets done in the body of the loop
...
Since 5 and 9 are integers
...
This example also shows a bit more of how printf works
...
Its first argument is a string of characters to be printed, with each % indicating where one of the other (second, third,
...
For instance, %d specifies an integer argument, so the statement printf("%d\t%d\n", fahr, celsius); causes the values of the two integers fahr and celsius to be printed, with a tab (\t) between them
...
; they must match up properly by number and type, or you will get wrong answers
...
printf is just a useful function from the standard library of functions that are normally accessible to C programs
...
In order to concentrate on C itself, we don't talk much about input and output until chapter 7
...
If you have to input numbers, read the discussion of the function scanf in Section 7
...
scanf is like printf, except that it reads input instead of writing output
...
The simpler one is that the output isn't very pretty because the numbers are not right-justified
...
For instance, we might say printf("%3d %6d\n", fahr, celsius); to print the first number of each line in a field three digits wide, and the second in a field six digits wide, like this: 0 20 -17 -6 Chapter 1 - A Tutorial Introduction 5 6 Chapter 1 - A Tutorial Introduction 40 60 80 100
...
8oC, not -17
...
This requires some changes in the program
...
h> /* print Fahrenheit-Celsius table for fahr = 0, 20,
...
0/9
...
0); printf("%3
...
1f\n", fahr, celsius); fahr = fahr + step; } } This is much the same as before, except that fahr and celsius are declared to be float and the formula for conversion is written in a more natural way
...
A decimal point in a constant indicates that it is floating point, however, so 5
...
0 is not truncated because it is the ratio of two floating-point values
...
If an arithmetic operator has one floating-point operand and one integer operand, however, the integer will be converted to floating point before the operation is done
...
Nevertheless, writing floating-point constants with explicit decimal points even when they have integral values emphasizes their floating-point nature for human readers
...
For now, notice that the assignment fahr = lower; and the test while (fahr <= upper) also work in the natural way - the int is converted to float before the operation is done
...
0f says that a floating-point number (here fahr) is to be printed at least three characters wide, with no decimal point and no fraction digits
...
1f describes another number (celsius) that is to be printed at least six characters wide, with 1 digit after the decimal point
...
7 -17
...
7 4
...
2f specifies two characters after the decimal point, but the width is not constrained; and %f merely says to print the number as floating point
...
2f print as floating point, 2 characters after decimal point %6
...
Exercise 1-3
...
Exercise 1-4
...
1
...
Let's try a variation on the temperature converter
...
1f\n", fahr, (5
...
0)*(fahr-32)); } This produces the same answers, but it certainly looks different
...
The lower and upper limits and the step size appear only as constants in the for statement, itself a new construction, and the expression that computes the Celsius temperature now appears as the third argument of printf instead of a separate assignment statement
...
Since the third argument of printf must be a floating-point value to match the %6
...
The for statement is a loop, a generalization of the while
...
Within the parentheses, there are three parts, separated by semicolons
...
The second part is the test or condition that controls the loop: fahr <= 300 This condition is evaluated; if it is true, the body of the loop (here a single ptintf) is executed
...
The loop terminates if the condition has become false
...
The initialization, condition and increment can be any expressions
...
The for is usually appropriate for loops in which the initialization and increment are single statements and logically related, since it is more compact than while and it keeps the loop control statements together in one place
...
Modify the temperature conversion program to print the table in reverse order, that is, from 300 degrees to 0
...
4 Symbolic Constants A final observation before we leave temperature conversion forever
...
One way to deal with magic numbers is to give them meaningful names
...
The name has the same form as a variable name: a sequence of letters and digits that begins with a letter
...
#include
...
1f\n", fahr, (5
...
0)*(fahr-32)); } The quantities LOWER, UPPER and STEP are symbolic constants, not variables, so they do not appear in declarations
...
Notice that there is no semicolon at the end of a #define line
...
5 Character Input and Output We are going to consider a family of related programs for processing character data
...
The model of input and output supported by the standard library is very simple
...
A text stream is a sequence of characters divided into lines; each line consists of zero or more characters followed by a newline character
...
8 Chapter 1 - A Tutorial Introduction Chapter 1 - A Tutorial Introduction 9 The standard library provides several functions for reading or writing one character at a time, of which getchar and putchar are the simplest
...
That is, after c = getchar(); the variable c contains the next character of input
...
The function putchar prints a character each time it is called: putchar(c); prints the contents of the integer variable c as a character, usually on the screen
...
1
...
1 File Copying Given getchar and putchar, you can write a surprising amount of useful code without knowing anything more about input and output
...
html">Chapter 2
...
Verify that the expression getchar() != EOF is 0 or 1
...
Write a program to print the value of EOF
...
5
...
#include
...
You could instead write nc = nc + 1 but Chapter 1 - A Tutorial Introduction 9 10 Chapter 1 - A Tutorial Introduction ++nc is more concise and often more efficient
...
The operators ++ and -- can be either prefix operators (++nc) or postfix operators (nc++); these two forms have different values in expressions, as will be shown in Chapter 2, but ++nc and nc++ both increment nc
...
The character counting program accumulates its count in a long variable instead of an int
...
Although on some machines, int and long are the same size, on others an int is 16 bits, with a maximum value of 32767, and it would take relatively little input to overflow an int counter
...
It may be possible to cope with even bigger numbers by using a double (double precision float)
...
"%
...
0f suppresses the printing of the decimal point and the fraction part, which is zero
...
But the grammatical rules of C require that a for statement have a body
...
We put it on a separate line to make it visible
...
This is important
...
If there is nothing to do, nothing is done, even if that means never going through the loop body
...
The while and for statements help ensure that programs do reasonable things with boundary conditions
...
5
...
As we mentioned above, the standard library ensures that an input text stream appears as a sequence of lines, each terminated by a newline
...
h> /* count lines in input */ main() { int c, nl; nl = 0; while ((c = getchar()) != EOF) if (c == '\n') ++nl; printf("%d\n", nl); } The body of the while now consists of an if, which in turn controls the increment ++nl
...
We have again indented to show what is controlled by what
...
EQ
...
A word of caution: newcomers to C occasionally write = when they mean ==
...
A character written between single quotes represents an integer value equal to the numerical value of the character in the machine's character set
...
So, for example, 'A' is a character constant; in the ASCII character set its value is 65, the internal representation of the character A
...
The escape sequences used in string constants are also legal in character constants, so '\n' stands for the value of the newline character, which is 10 in ASCII
...
The topic of strings versus characters is discussed further in Chapter 2
...
Write a program to count blanks, tabs, and newlines
...
Write a program to copy its input to its output, replacing each string of one or more blanks by a single blank
...
Write a program to copy its input to its output, replacing each tab by \t, each backspace by \b, and each backslash by \\
...
1
...
4 Word Counting The fourth in our series of useful programs counts lines, words, and characters, with the loose definition that a word is any sequence of characters that does not contain a blank, tab or newline
...
"%d %d %d\n", nl, nw, nc); } Every time the program encounters the first character of a word, it counts one more word
...
We prefer the symbolic constants IN and OUT to the literal values 1 and 0 because they make the program more readable
...
You'll also find that it's easier to make extensive changes in programs where magic numbers appear only as symbolic constants
...
This is not a special case, but a consequence of the fact that an assignment is an expression with the value and assignments associated from right to left
...
(Recall that the escape sequence \t is a visible representation of the tab character
...
Expressions connected by && or || are evaluated left to right, and it is guaranteed that evaluation will stop as soon as the truth or falsehood is known
...
This isn't particularly important here, but is significant in more complicated situations, as we will soon see
...
The general form is if (expression) statement1 else statement2 One and only one of the two statements associated with an if-else is performed
...
Each statement can be a single statement or several in braces
...
Exercise 1-11
...
Write a program that prints its input one word per line
...
6 Arrays Let is write a program to count the number of occurrences of each digit, of white space characters (blank, tab, newline), and of all other characters
...
There are twelve categories of input, so it is convenient to use an array to hold the number of occurrences of each digit, rather than ten individual variables
...
h> /* count digits, white space, others */ main() { int c, i, nwhite, nother; int ndigit[10]; nwhite = nother = 0; for (i = 0; i < 10; ++i) ndigit[i] = 0; while ((c = getchar()) != EOF) if (c >= '0' && c <= '9') ++ndigit[c-'0']; else if (c == ' ' || c == '\n' || c == '\t') ++nwhite; else ++nother; printf("digits ="); for (i = 0; i < 10; ++i) printf(" %d", ndigit[i]); printf(", white space = %d, other = %d\n", nwhite, nother); } The output of this program on itself is digits = 9 3 0 0 0 0 0 0 0 1, white space = 123, other = 345 12 Chapter 1 - A Tutorial Introduction Chapter 1 - A Tutorial Introduction 13 The declaration int ndigit[10]; declares ndigit to be an array of 10 integers
...
, ndigit[9]
...
A subscript can be any integer expression, which includes integer variables like i, and integer constants
...
For example, the test if (c >= '0' && c <= '9') determines whether the character in c is a digit
...
, '9' have consecutive increasing values
...
By definition, chars are just small integers, so char variables and constants are identical to ints in arithmetic expressions
...
The decision as to whether a character is a digit, white space, or something else is made with the sequence if (c >= '0' && c <= '9') ++ndigit[c-'0']; else if (c == ' ' || c == '\n' || c == '\t') ++nwhite; else ++nother; The pattern if (condition1) statement1 else if (condition2) statement2
...
else statementn occurs frequently in programs as a way to express a multi-way decision
...
(Any statement can be several statements enclosed in braces
...
If the final else and statement are omitted, as in the word count program, no action takes place
...
Chapter 1 - A Tutorial Introduction 13 14 Chapter 1 - A Tutorial Introduction As a matter of style, it is advisable to format this construction as we have shown; if each if were indented past the previous else, a long sequence of decisions would march off the right side of the page
...
For contrast, we will present a switch version of this program in Section 3
...
Exercise 1-13
...
It is easy to draw the histogram with the bars horizontal; a vertical orientation is more challenging
...
Write a program to print a histogram of the frequencies of different characters in its input
...
7 Functions In C, a function is equivalent to a subroutine or function in Fortran, or a procedure or function in Pascal
...
With properly designed functions, it is possible to ignore how a job is done; knowing what is done is sufficient
...
So far we have used only functions like printf, getchar and putchar that have been provided for us; now it's time to write a few of our own
...
That is, the value of power(2,5) is 32
...
(The standard library contains a function pow(x,y) that computes xy
...
#include
...
If the source program appears in several files, you may have to say more to compile and load it than if it all appears in one, but that is an operating system matter, not a language attribute
...
The function power is called twice by main, in the line printf("%d %d %d\n", i, power(2,i), power(-3,i)); Each call passes two arguments to power, which each time returns an integer to be formatted and printed
...
(Not all functions produce an integer value; we will take this up in Chapter 4
...
The names used by power for its parameters are local to power, and are not visible to any other function: other routines can use the same names without conflict
...
We will generally use parameter for a variable named in the parenthesized list in a function
...
The value that power computes is returned to main by the return: statement
...
And the calling function can ignore a value returned by a function
...
Since main is a function like any other, it may return a value to its caller, which is in effect the environment in which the program was executed
...
In the interests of simplicity, we have omitted return statements from our main functions up to this point, but we will include them hereafter, as a reminder that programs should return status to their environment
...
This declaration, which is called a function prototype, has to agree with the definition and uses of power
...
parameter names need not agree
...
A note of history: the biggest change between ANSI C and earlier versions is how functions are declared and defined
...
(The body of the function is the same as before
...
Indeed, since by default power would have been assumed to return an int, the entire declaration might well have been omitted
...
The old style of declaration and definition still works in ANSI C, at least for a transition period, but we strongly recommend that you use the new form when you have a compiler that supports it
...
15
...
2 to use a function for conversion
...
8 Arguments - Call by Value One aspect of C functions may be unfamiliar to programmers who are used to some other languages, particulary Fortran
...
'' This means that the called function is given the values of its arguments in temporary variables rather than the originals
...
Call by value is an asset, however, not a liability
...
For example, here is a version of power that makes use of this property
...
Whatever is done to n inside power has no effect on the argument that power was originally called with
...
The caller must provide the address of the variable to be set (technically a pointer to the variable), and the called function must declare the parameter to be a pointer and access the variable indirectly through it
...
The story is different for arrays
...
By subscripting this value, the function can access and alter any argument of the array
...
1
...
To illustrate the use of character arrays and functions to manipulate them, let's write a program that reads a set of text lines and prints the longest
...
One piece gets a new line, another saves it, and the rest controls the process
...
Accordingly, let us first write a separate function getline to fetch the next line of input
...
At the minimum, getline has to return a signal about possible end of file; a more useful design would be to return the length of the line, or zero if end of file is encountered
...
Every text line has at least one character; even a line containing only a newline has length 1
...
This suggests a second function, copy, to copy the new line to a safe place
...
Here is the result
...
main and getline communicate through a pair of arguments and a returned value
...
The purpose of supplying the size of an array in a declaration is to set aside storage
...
getline uses return to send a value back to the caller, just as the function power did
...
Some functions return a useful value; others, like copy, are used only for their effect and return no value
...
getline puts the character '\0' (the null character, whose value is zero) at the end of the array it is creating, to mark the end of the string of characters
...
The %s format specification in printf expects the corresponding argument to be a string represented in this form
...
It is worth mentioning in passing that even a program as small as this one presents some sticky design problems
...
By testing the length and the last character returned, main can determine whether the line was too long, and then cope as it wishes
...
There is no way for a user of getline to know in advance how long an input line might be, so getline checks for overflow
...
Exercise 1-16
...
Exercise 1-17
...
Exercise 1-18
...
Exercise 1-19
...
Use it to write a program that reverses its input a line at a time
...
10 External Variables and Scope The variables in main, such as line, longest, etc
...
Because they are declared within main, no other function can have direct access to them
...
Each local variable in a function comes into existence only when the function is called, and disappears when the function is exited
...
We will use the term automatic henceforth to refer to these local variables
...
) Because automatic variables come and go with function invocation, they do not retain their values from one call to the next, and must be explicitly set upon each entry
...
As an alternative to automatic variables, it is possible to define variables that are external to all functions, that is, variables that can be accessed by name by any function
...
) Because external variables are globally accessible, they can be used instead of argument lists to communicate data between functions
...
An external variable must be defined, exactly once, outside of any function; this sets aside storage for it
...
The declaration may be an explicit extern statement or may be implicit from context
...
This requires changing the calls, declarations, and bodies of all three functions
...
Syntactically, external definitions are just like definitions of local variables, but since they occur outside of functions, the variables are external
...
In certain circumstances, the extern declaration can be omitted
...
The extern declarations in main, getline and copy are thus redundant
...
If the program is in several source files, and a variable is defined in file1 and used in file2 and file3, then extern declarations are needed in file2 and file3 to connect the occurrences of the variable
...
The suffix
...
The functions of the standard library, for example, are declared in headers like
...
This topic is discussed at length in Chapter 4, and the library itself in Chapter 7 and Appendix B
...
But for compatibility with older C programs the standard takes an empty list as an old-style declaration, and turns off all argument list checking; the word void must be used for an explicitly empty list
...
You should note that we are using the words definition and declaration carefully when we refer to external variables in this section
...
By the way, there is a tendency to make everything in sight an extern variable because it appears to simplify communications - argument lists are short and variables are always there when you want them
...
Relying too heavily on external variables is fraught with peril since it leads to programs whose data connections are not all obvious - variables can be changed in unexpected and even inadvertent ways, and the program is hard to modify
...
At this point we have covered what might be called the conventional core of C
...
These exercises suggest programs of somewhat greater complexity than the ones earlier in this chapter
...
Write a program detab that replaces tabs in the input with the proper number of blanks to space to the next tab stop
...
Should n be a variable or a 20 Chapter 1 - A Tutorial Introduction Chapter 1 - A Tutorial Introduction 21 symbolic parameter? Exercise 1-21
...
Use the same tab stops as for detab
...
Write a program to ``fold'' long input lines into two or more shorter lines after the last non-blank character that occurs before the n-th column of input
...
Exercise 1-23
...
Don't forget to handle quoted strings and character constants properly
...
Exercise 1-24
...
Don't forget about quotes, both single and double, escape sequences, and comments
...
) Back to Introduction -- Index -- Chapter 2 Compiled by tmdcjsl(skidrow8123@hotmail
...
Declarations list the variables to be used, and state what type they have and perhaps what their initial values are
...
Expressions combine variables and constants to produce new values
...
These building blocks are the topics of this chapter
...
There are now signed and unsigned forms of all integer types, and notations for unsigned constants and hexadecimal character constants
...
String constants may be concatenated at compile time
...
Objects may be declared const, which prevents them from being changed
...
2
...
Names are made up of letters and digits; the first character must be a letter
...
Don't begin variable names with underscore, however, since library routines often use such names
...
Traditional C practice is to use lower case for variable names, and all upper case for symbolic constants
...
For function names and external variables, the number may be less than 31, because external names may be used by assemblers and loaders over which the language has no control
...
Keywords like if, else, int, float, etc
...
They must be in lower case
...
We tend to use short names for local variables, especially loop indices, and longer names for external variables
...
2 Data Types and Sizes There are only a few basic data types in C: char a single byte, capable of holding one character in the local character set int an integer, typically reflecting the natural size of integers on the host machine float single-precision floating point double double-precision floating point In addition, there are a number of qualifiers that can be applied to these basic types
...
The intent is that short and long should provide different lengths of integers where practical; int will Chapter 2 - Types, Operators and Expressions 1 2 Chapter 2 - Types, Operators and Expressions normally be the natural size for a particular machine
...
Each compiler is free to choose appropriate sizes for its own hardware, subject only to the the restriction that shorts and ints are at least 16 bits, longs are at least 32 bits, and short is no longer than int, which is no longer than long
...
unsigned numbers are always positive or zero, and obey the laws of arithmetic modulo 2n, where n is the number of bits in the type
...
) Whether plain chars are signed or unsigned is machine-dependent, but printable characters are always positive
...
As with integers, the sizes of floating-point objects are implementation-defined; float, double and long double could represent one, two or three distinct sizes
...
h> and
...
These are discussed in Appendix B
...
Write a program to determine the ranges of char, short, int, and long variables, both signed and unsigned, by printing appropriate values from standard headers and by direct computation
...
2
...
A long constant is written with a terminal l (ell) or L, as in 123456789L; an integer constant too big to fit into an int will also be taken as a long
...
Floating-point constants contain a decimal point (123
...
The suffixes f or F indicate a float constant; l or L indicate a long double
...
A leading 0 (zero) on an integer constant means octal; a leading 0x or 0X means hexadecimal
...
Octal and hexadecimal constants may also be followed by L to make them long and U to make them unsigned: 0XFUL is an unsigned long constant with value 15 decimal
...
The value of a character constant is the numeric value of the character in the machine's character set
...
If we write '0' instead of a numeric value like 48 that depends on the character set, the program is independent of the particular value and easier to read
...
Certain characters can be represented in character and string constants by escape sequences like \n (newline); these sequences look like two characters, but represent only one
...
7) or by '\xhh' 2 Chapter 2 - Types, Operators and Expressions Chapter 2 - Types, Operators and Expressions 3 where hh is one or more hexadecimal digits (0
...
f, A
...
So we might write \a "center" border=1> alert (bell) character \\ \b backspace \? question mark \f formfeed \n newline \" \r carriage return \ooo \t horizontal tab \xhh \v vertical tab backslash \' single quote double quote octal number hexadecimal number The character constant '\0' represents the character with value zero, the null character
...
A constant expression is an expression that involves only constants
...
The same escape sequences used in character constants apply in strings; \" represents the double-quote character
...
Technically, a string constant is an array of characters
...
This representation means that there is no limit to how long a string can be, but programs must scan a string completely to determine its length
...
Here is our version: /* strlen: return length of s */ int strlen(char s[]) { int i; while (s[i] != '\0') ++i; return i; } strlen and other string functions are declared in the standard header
...
Be careful to distinguish between a character constant and a string that contains a single character: 'x' is not the same as "x"
...
The latter is an array of characters that contains one character (the letter x) and a '\0'
...
An enumeration is a list of constant integer values, as in enum boolean { NO, YES }; The first name in an enum has value 0, the next 1, and so on, unless explicit values are specified
...
*/ Names in different enumerations must be distinct
...
Enumerations provide a convenient way to associate constant values with names, an alternative to #define with the advantage that the values can be generated for you
...
Nevertheless, enumeration variables offer the chance of checking and so are often better than #defines
...
2
...
A declaration specifies a type, and contains a list of one or more variables of that type, as in int lower, upper, step; char c, line[1000]; Variables can be distributed among declarations in any fashion; the lists above could well be written as int int int char char 4 lower; upper; step; c; line[1000]; Chapter 2 - Types, Operators and Expressions Chapter 2 - Types, Operators and Expressions 5 The latter form takes more space, but is convenient for adding a comment to each declaration for subsequent modifications
...
If the name is followed by an equals sign and an expression, the expression serves as an initializer, as in char int int float esc = '\\'; i = 0; limit = MAXLINE+1; eps = 1
...
An explicitly initialized automatic variable is initialized each time the function or block it is in is entered; the initializer may be any expression
...
Automatic variables for which is no explicit initializer have undefined (i
...
, garbage) values
...
For an array, the const qualifier says that the elements will not be altered
...
71828182845905; const char msg[] = "warning: "; The const declaration can also be used with array arguments, to indicate that the function does not change that array: int strlen(const char[]); The result is implementation-defined if an attempt is made to change a const
...
5 Arithmetic Operators The binary arithmetic operators are +, -, *, /, and the modulus operator %
...
The expression x % y produces the remainder when x is divided by y, and thus is zero when y divides x exactly
...
Therefore if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) printf("%d is a leap year\n", year); else printf("%d is not a leap year\n", year); The % operator cannot be applied to a float or double
...
The binary + and - operators have the same precedence, which is lower than the precedence of *, / and %, which is in turn lower than unary + and -
...
Table 2
...
Chapter 2 - Types, Operators and Expressions 5 6 Chapter 2 - Types, Operators and Expressions 2
...
Just below them in precedence are the equality operators: == != Relational operators have lower precedence than arithmetic operators, so an expression like i < lim-1 is taken as i < (lim-1), as would be expected
...
Expressions connected by && or || are evaluated left to right, and evaluation stops as soon as the truth or falsehood of the result is known
...
For example, here is a loop from the input function getline that we wrote in Chapter 1: for (i=0; i < lim-1 && (c=getchar()) != '\n' && c != EOF; ++i) s[i] = c; Before reading a new character it is necessary to check that there is room to store it in the array s, so the test i < lim-1 must be made first
...
Similarly, it would be unfortunate if c were tested against EOF before getchar is called; therefore the call and assignment must occur before the character in c is tested
...
But since the precedence of != is higher than assignment, parentheses are needed in (c=getchar()) != '\n' to achieve the desired result of assignment to c and then comparison with '\n'
...
The unary negation operator ! converts a non-zero operand into 0, and a zero operand in 1
...
Constructions like !valid read nicely (``if not valid''), but more complicated ones can be hard to understand
...
Write a loop equivalent to the for loop above without using && or ||
...
7 Type Conversions When an operator has operands of different types, they are converted to a common type according to a small number of rules
...
Expressions that don't make sense, like using a float as a subscript, are disallowed
...
A char is just a small integer, so chars may be freely used in arithmetic expressions
...
One is exemplified by this naive implementation of the function atoi, which converts a string of digits into its numeric equivalent
...
, form a contiguous increasing sequence
...
If the character is not an upper case letter, lower returns it unchanged
...
This latter observation is not true of the EBCDIC character set, however, so this code would convert more than just letters in EBCDIC
...
h>, described in Appendix B, defines a family of functions that provide tests and conversions that are independent of character set
...
Similarly, the test c >= '0' && c <= '9' can be replaced by isdigit(c) Chapter 2 - Types, Operators and Expressions 7 8 Chapter 2 - Types, Operators and Expressions We will use the
...
There is one subtle point about the conversion of characters to integers
...
When a char is converted to an int, can it ever produce a negative integer? The answer varies from machine to machine, reflecting differences in architecture
...
On others, a char is promoted to an int by adding zeros at the left end, and thus is always positive
...
But arbitrary bit patterns stored in character variables may appear to be negative on some machines, yet positive on others
...
Relational expressions like i > j and logical expressions connected by && and || are defined to have value 1 if true, and 0 if false
...
However, functions like isdigit may return any non-zero value for true
...
, ``true'' just means ``non-zero'', so this makes no difference
...
In general, if an operator like + or * that takes two operands (a binary operator) has operands of different types, the ``lower'' type is promoted to the ``higher'' type before the operation proceeds
...
Section 6 of Appendix A states the conversion rules precisely
...
• Otherwise, if either operand is double, convert the other to double
...
• Otherwise, convert char and short to int
...
Notice that floats in an expression are not automatically converted to double; this is a change from the original definition
...
h> will use double precision
...
Conversion rules are more complicated when unsigned operands are involved
...
For example, suppose that int is 16 bits and long is 32 bits
...
But -1L > 1UL because -1L is promoted to unsigned long and thus appears to be a large positive number
...
A character is converted to an integer, either by sign extension or not, as described above
...
Thus in int i; char c; 8 Chapter 2 - Types, Operators and Expressions Chapter 2 - Types, Operators and Expressions 9 i = c; c = i; the value of c is unchanged
...
Reversing the order of assignments might lose information, however
...
When a double is converted to float, whether the value is rounded or truncated is implementation dependent
...
In the absence of a function prototype, char and short become int, and float becomes double
...
Finally, explicit type conversions can be forced (``coerced'') in any expression, with a unary operator called a cast
...
The precise meaning of a cast is as if the expression were assigned to a variable of the specified type, which is then used in place of the whole construction
...
(sqrt is declared in
...
) So if n is an integer, we can use sqrt((double) n) to convert the value of n to double before passing it to sqrt
...
The cast operator has the same high precedence as other unary operators, as summarized in the table at the end of this chapter
...
Thus, given a function prototype for sqrt: double sqrt(double) the call root2 = sqrt(2) coerces the integer 2 into the double value 2
...
The standard library includes a portable implementation of a pseudo-random number generator and a function for initializing the seed; the former illustrates a cast: unsigned long int next = 1; /* rand: return pseudo-random integer on 0
...
Write a function htoi(s), which converts a string of hexadecimal digits (including an optional 0x or 0X) into its equivalent integer value
...
2
...
The increment operator ++ adds 1 to its operand, while the decrement operator -- subtracts 1
...
In both cases, the effect is to increment n
...
This means that in a context where the value is being used, not just the effect, ++n and n++ are different
...
In both cases, n becomes 6
...
In a context where no value is wanted, just the incrementing effect, as in if (c == '\n') nl++; prefix and postfix are the same
...
For instance, consider the function squeeze(s,c), which removes all occurrences of the character c from the string s
...
This is exactly equivalent to if (s[i] != c) { s[j] = s[i]; j++; } 10 Chapter 2 - Types, Operators and Expressions Chapter 2 - Types, Operators and Expressions 11 Another example of a similar construction comes from the getline function that we wrote in Chapter 1, where we can replace if (c == '\n') { s[i] = c; ++i; } by the more compact if (c == '\n') s[i++] = c; As a third example, consider the standard function strcat(s,t), which concatenates the string t to the end of string s
...
As we have written it, strcat returns no value; the standard library version returns a pointer to the resulting string
...
Exercise 2-4
...
Exercise 2-5
...
(The standard library function strpbrk does the same job but returns a pointer to the location
...
9 Bitwise Operators C provides six operators for bit manipulation; these may only be applied to integral operands, that is, char, short, int, and long, whether signed or unsigned
...
Chapter 2 - Types, Operators and Expressions 11 12 Chapter 2 - Types, Operators and Expressions The bitwise OR operator | is used to turn bits on: x = x | SET_ON; sets to one in x the bits that are set to one in SET_ON
...
One must distinguish the bitwise operators & and | from the logical operators && and ||, which imply left-to-right evaluation of a truth value
...
The shift operators << and >> perform left and right shifts of their left operand by the number of bit positions given by the right operand, which must be non-negative
...
Right shifting an unsigned quantity always fits the vacated bits with zero
...
The unary operator ~ yields the one's complement of an integer; that is, it converts each 1-bit into a 0-bit and vice versa
...
Note that x & ~077 is independent of word length, and is thus preferable to, for example, x & 0177700, which assumes that x is a 16-bit quantity
...
As an illustration of some of the bit operators, consider the function getbits(x,p,n) that returns the (right adjusted) n-bit field of x that begins at position p
...
For example, getbits(x,4,3) returns the three bits in positions 4, 3 and 2, right-adjusted
...
~0 is all 1-bits; shifting it left n positions with ~0< with ones in the rightmost n bits
...
Write a function setbits(x,p,n,y) that returns x with the n bits that begin at position p set to the rightmost n bits of y, leaving the other bits unchanged
...
Write a function invert(x,p,n) that returns x with the n bits that begin at position p inverted (i
...
, 1 changed into 0 and vice versa), leaving the others unchanged
...
Write a function rightrot(x,n) that returns the value of the integer x rotated to the right by n positions
...
10 Assignment Operators and Expressions An expression such as 12 Chapter 2 - Types, Operators and Expressions Chapter 2 - Types, Operators and Expressions 13 i = i + 2 in which the variable on the left side is repeated immediately on the right, can be written in the compressed form i += 2 The operator += is called an assignment operator
...
Notice the parentheses around expr2: x *= y + 1 means x = x * (y + 1) rather than x = x * y + 1 As an example, the function bitcount counts the number of 1-bits in its integer argument
...
Quite apart from conciseness, assignment operators have the advantage that they correspond better to the way people think
...
Thus the expression i += 2 is preferable to i = i+2
...
And an assignment Chapter 2 - Types, Operators and Expressions 13 14 Chapter 2 - Types, Operators and Expressions operator may even help a compiler to produce efficient code
...
The other assignment operators (+=, -=, etc
...
In all such expressions, the type of an assignment expression is the type of its left operand, and the value is the value after the assignment
...
In a two's complement number system, x &= (x-1) deletes the rightmost 1-bit in x
...
Use this observation to write a faster version of bitcount
...
11 Conditional Expressions The statements if (a > b) z = a; else z = b; compute in z the maximum of a and b
...
In the expression expr1 ? expr2 : expr3 the expression expr1 is evaluated first
...
Otherwise expr3 is evaluated, and that is the value
...
Thus to set z to the maximum of a and b, z = (a > b) ? a : b; /* z = max(a, b) */ It should be noted that the conditional expression is indeed an expression, and it can be used wherever any other expression can be
...
For example, if f is a float and n an int, then the expression (n > 0) ? f : n is of type float regardless of whether n is positive
...
They are advisable anyway, however, since they make the condition part of the expression easier to see
...
For example, this loop prints n elements of an array, 10 per line, with each column separated by one blank, and with each line (including the last) terminated by a newline
...
All other elements are followed by one blank
...
Another good example is printf("You have %d items%s
...
Rewrite the function lower, which converts upper case letters to lower case, with a conditional expression instead of if-else
...
12 Precedence and Order of Evaluation Table 2
...
Operators on the same line have the same precedence; rows are in order of decreasing precedence, so, for example, *, /, and % all have the same precedence, which is higher than that of binary + and -
...
The operators -> and
...
Chapter 5 discusses * (indirection through a pointer) and & (address of an object), and Chapter 3 discusses the comma operator
...
left to right ! ~ ++ -- + - * (type) right to left sizeof * / % left to right + left to right << >> left to right < <= > >= left to right == != left to right & left to right ^ left to right | left to right && left to right || left to right ?: right to left = += -= *= /= %= &= right to left ^= |= <<= >>= , left to right Unary & +, -, and * have higher precedence than the binary forms
...
1: Precedence and Associativity of Operators Note that the precedence of the bitwise operators &, ^, and | falls below == and !=
...
must be fully parenthesized to give proper results
...
(The exceptions are &&, ||, ?:, and `,'
...
Intermediate results can be stored in temporary variables to ensure a particular sequence
...
The solution, of course, is to write ++n; printf("%d %d\n", n, power(2, n)); Function calls, nested assignment statements, and increment and decrement operators cause ``side effects'' some variable is changed as a by-product of the evaluation of an expression
...
One unhappy situation is typified by the statement a[i] = i++; The question is whether the subscript is the old value of i or the new
...
The standard intentionally leaves most such matters unspecified
...
(The standard does specify that all side effects on arguments take effect before a function is called, but that would not help in the call to printf above
...
Naturally, it is necessary to know what things to avoid, but if you don't know how they are done on various machines, you won't be tempted to take advantage of a particular implementation
...
com) Back to Chapter 2 -- Index -- Chapter 4 16 Chapter 2 - Types, Operators and Expressions Chapter 3 - Control Flow The control-flow of a language specify the order in which computations are performed
...
3
...
) becomes a statement when it is followed by a semicolon, as in x = 0; i++; printf(
...
Braces { and } are used to group declarations and statements together into a compound statement, or block, so that they are syntactically equivalent to a single statement
...
(Variables can be declared inside any block; we will talk about this in Chapter 4
...
3
...
Formally the syntax is if (expression) statement1 else statement2 where the else part is optional
...
If it is false (expression is zero) and if there is an else part, statement2 is executed instead
...
The most obvious is writing if (expression) instead of if (expression != 0) Sometimes this is natural and clear; at other times it can be cryptic
...
This is resolved by associating the else with the closest previous else-less if
...
If that isn't what you want, braces must be used to force the proper association: if (n > 0) { if (a > b) z = a; } else z = b; The ambiguity is especially pernicious in situations like this: if (n > 0) for (i = 0; i < n; i++) if (s[i] > 0) { printf("
...
This kind of bug can be hard to find; it's a good idea to use braces when there are nested ifs
...
3
...
This sequence of if statements is the most general way of writing a multi-way decision
...
As always, the code for each statement is either a single statement, or a group of them in braces
...
Sometimes there is no explicit action for the default; in that case the trailing 2 Chapter 3 - Control Flow Chapter 3 - Control Flow 3 else statement can be omitted, or it may be used for error checking to catch an ``impossible'' condition
...
The elements of v must be in increasing order
...
Binary search first compares the input value x to the middle element of the array v
...
In either case, the next step is to compare x to the middle element of the selected half
...
/* binsearch: find x in v[0] <= v[1] <=
...
Exercise 3-1
...
) Write a version with only one test inside the loop and measure the difference in run-time
...
4 Switch The switch statement is a multi-way decision that tests whether an expression matches one of a number of constant integer values, and branches accordingly
...
If a case matches the expression value, execution starts at that case
...
The case labeled default is executed if none of the other cases are satisfied
...
Cases and the default clause can occur in any order
...
else if
...
Here is the same program with a switch: "digits ="); Chapter 3 - Control Flow 3 4 Chapter 3 - Control Flow for (i = 0; i < 10; i++) printf(" %d", ndigit[i]); printf(", white space = %d, other = %d\n", nwhite, nother); return 0; } The break statement causes an immediate exit from the switch
...
break and return are the most common ways to leave a switch
...
Falling through cases is a mixed blessing
...
But it also implies that normally each case must end with a break to prevent falling through to the next
...
With the exception of multiple labels for a single computation, fall-throughs should be used sparingly, and commented
...
Some day when another case gets added at the end, this bit of defensive programming will save you
...
Write a function escape(s,t) that converts characters like newline and tab into visible escape sequences like \n and \t as it copies the string t to s
...
Write a function for the other direction as well, converting escape sequences into the real characters
...
5 Loops - While and For We have already encountered the while and for loops
...
If it is non-zero, statement is executed and expression is re-evaluated
...
The for statement for (expr1; expr2; expr3) statement is equivalent to expr1; while (expr2) { statement expr3; } except for the behaviour of continue, which is described in Section 3
...
Grammatically, the three components of a for loop are expressions
...
Any of the three parts can be omitted, although the semicolons must remain
...
If the test, expr2, is not present, it is taken as permanently true, so for (;;) { 4 Chapter 3 - Control Flow Chapter 3 - Control Flow 5
...
Whether to use while or for is largely a matter of personal preference
...
The for is preferable when there is a simple initialization and increment since it keeps the loop control statements close together and visible at the top of the loop
...
which is the C idiom for processing the first n elements of an array, the analog of the Fortran DO loop or the Pascal for
...
Because the components of the for are arbitrary expressions, for loops are not restricted to arithmetic progressions
...
As a larger example, here is another version of atoi for converting a string to its numeric equivalent
...
(Chapter 4 shows atof, which does the same conversion for floating-point numbers
...
The whole process terminates on the first character that could not be part of a number
...
html#sb
...
The advantages of keeping loop control centralized are even more obvious when there are several nested loops
...
The basic idea of this sorting algorithm, which was invented in 1959 by D
...
Shell, is that in early stages, far-apart elements are compared, rather than adjacent ones as in simpler interchange sorts
...
The interval between compared elements is gradually decreased to one, at which point the sort effectively becomes an adjacent interchange method
...
v[n-1] into increasing order */ void shellsort(int v[], int n) { int gap, i, j, temp; for (gap = n/2; gap > 0; gap /= 2) for (i = gap; i < n; i++) for (j=i-gap; j>=0 && v[j]>v[j+gap]; j-=gap) { temp = v[j]; v[j] = v[j+gap]; v[j+gap] = temp; } Chapter 3 - Control Flow 5 6 Chapter 3 - Control Flow } There are three nested loops
...
The middle loop steps along the elements
...
Since gap is eventually reduced to one, all elements are eventually ordered correctly
...
One final C operator is the comma ``,'', which most often finds use in the for statement
...
Thus in a for statement, it is possible to place multiple expressions in the various parts, for example to process two indices in parallel
...
#include
...
, are not comma operators, and do not guarantee left to right evaluation
...
The most suitable uses are for constructs strongly related to each other, as in the for loop in reverse, and in macros where a multistep computation has to be a single expression
...
Write a function expand(s1,s2) that expands shorthand notations like a-z in the string s1 into the equivalent complete list abc
...
Allow for letters of either case and digits, and be prepared to handle cases like a-b-c and a-z0-9 and -a-z
...
3
...
By contrast, the third loop in C, the do-while, tests at the bottom after making each pass through the loop body; the body is always executed at least once
...
If it is true, statement is evaluated again, and so on
...
Except for the sense of the test, do-while is equivalent to the Pascal repeat-until statement
...
Nonetheless, from time to time it is valuable, as in the following function itoa, which converts a number to a character string (the inverse of atoi)
...
We have chosen to generate the string backwards, then reverse it
...
We also used braces around the single statement that makes up the body of the do-while, even though they are unnecessary, so the hasty reader will not mistake the while part for the beginning of a while loop
...
In a two's complement number representation, our version of itoa does not handle the largest negative number, that is, the value of n equal to -(2wordsize-1)
...
Modify it to print that value correctly, regardless of the machine on which it runs
...
Write the function itob(n,s,b) that converts the integer n into a base b character representation in the string s
...
Exercise 3-6
...
The third argument is a minimum field width; the converted number must be padded with blanks on the left if necessary to make it wide enough
...
7 Break and Continue It is sometimes convenient to be able to exit from a loop other than by testing at the top or bottom
...
A break causes the innermost enclosing loop or switch to be exited immediately
...
/* trim: remove trailing blanks, tabs, newlines */ int trim(char s[]) { int n; for (n = strlen(s)-1; n >= 0; n--) Chapter 3 - Control Flow 7 8 Chapter 3 - Control Flow if (s[n] != ' ' && s[n] != '\t' && s[n] != '\n') break; s[n+1] = '\0'; return n; } strlen returns the length of the string
...
The loop is broken when one is found, or when n becomes negative (that is, when the entire string has been scanned)
...
The continue statement is related to break, but less often used; it causes the next iteration of the enclosing for, while, or do loop to begin
...
The continue statement applies only to loops, not to switch
...
As an example, this fragment processes only the non-negative elements in the array a; negative values are skipped
...
/* do positive elements */ The continue statement is often used when the part of the loop that follows is complicated, so that reversing a test and indenting another level would nest the program too deeply
...
8 Goto and labels C provides the infinitely-abusable goto statement, and labels to branch to
...
We have not used goto in this book
...
The most common is to abandon processing in some deeply nested structure, such as breaking out of two or more loops at once
...
Thus: for (
...
) {
...
error: /* clean up the mess */ This organization is handy if the error-handling code is non-trivial, and if errors can occur in several places
...
It can be attached to any statement in the same function as the goto
...
As another example, consider the problem of determining whether two arrays a and b have an element in common
...
found: /* got one: a[i] == b[j] */
...
For example, the array search becomes found = 0; for (i = 0; i < n && !found; i++) for (j = 0; j < m && !found; j++) if (a[i] == b[j]) found = 1; if (found) /* got one: a[i-1] == b[j-1] */
...
With a few exceptions like those cited here, code that relies on goto statements is generally harder to understand and to maintain than code without gotos
...
Back to Chapter 2 -- Index -- Chapter 4 Compiled by tmdcjsl(skidrow8123@hotmail
...
Appropriate functions hide details of operation from parts of the program that don't need to know about them, thus clarifying the whole, and easing the pain of making changes
...
A program may reside in one or more source files
...
We will not go into that process here, however, since the details vary from system to system
...
As we saw first in Chapter 1, it is now possible to declare the type of arguments when a function is declared
...
This makes it possible for a compiler to detect many more errors than it could before
...
The standard clarifies the rules on the scope of names; in particular, it requires that there be only one definition of each external object
...
The C preprocessor has also been enhanced
...
4
...
(This is a special case of the UNIX program grep
...
Three small pieces are better to deal with than one big one, because irrelevant details can be buried in the functions, and the chance of unwanted interactions is minimized
...
Chapter 4 - Functions and Program Structure 1 2 Chapter 4 - Functions and Program Structure ``While there's another line'' is getline, a function that we wrote in Chapter 1, and ``print it'' is printf, which someone has already provided for us
...
We can solve that problem by writing a function strindex(s,t) that returns the position or index in the string s where the string t begins, or -1 if s does not contain t
...
When we later need more sophisticated pattern matching, we only have to replace strindex; the rest of the code can remain the same
...
) Given this much design, filling in the details of the program is straightforward
...
For now, the pattern to be searched for is a literal string, which is not the most general of mechanisms
...
There is also a slightly different version of getline; you might find it instructive to compare it to the one in Chapter 1
...
A do-nothing function like this is sometimes useful as a place holder during program development
...
A program is just a set of definitions of variables and functions
...
The functions can occur in any order in the source file, and the source program can be split into multiple files, so long as no function is split
...
Any expression can follow return: return expression; The expression will be converted to the return type of the function if necessary
...
The calling function is free to ignore the returned value
...
Control also returns to the caller with no value when execution ``falls off the end'' of the function by reaching the closing right brace
...
In any case, if a function fails to return a value, its ``value'' is certain to be garbage
...
This value is available for use by the environment that called the program The mechanics of how to compile and load a C program that resides on multiple source files vary from one system to the next
...
Suppose that the three functions are stored in three files called main
...
c, and strindex
...
Then the command cc main
...
c strindex
...
o, getline
...
o, then loads them all into an executable file called a
...
If there is an error, say in main
...
c getline
...
o The cc command uses the ``
...
o'' naming convention to distinguish source files from object files
...
Write the function strindex(s,t) which returns the position of the rightmost occurrence of t in s, or -1 if there is none
...
2 Functions Returning Non-integers So far our examples of functions have returned either no value (void) or an int
...
To illustrate how to deal with this, let us write and use the function atof(s), which converts the string s to its double-precision floating-point equivalent
...
It handles an optional sign and decimal point, and the presence or absence of either part or fractional part
...
The standard library includes an atof; the header
...
First, atof itself must declare the type of value it returns, since it is not int
...
The function atof must be declared and defined consistently
...
But if (as is more likely) atof were compiled separately, the mismatch would not be detected, atof would return a double that main would treat as an int, and meaningless answers would result
...
The reason a mismatch can happen is that if there is no function prototype, a function is implicitly declared by its first appearance in an expression, such as sum += atof(line) If a name that has not been previously declared occurs in an expression and is followed by a left parentheses, it is declared by context to be a function name, the function is assumed to return an int, and nothing is assumed about its arguments
...
This special meaning of the empty argument list is intended to permit older C programs to compile with new compilers
...
If the function takes arguments, declare them; if it takes no arguments, use void
...
The value of the expression in return expression; is converted to the type of the function before the return is taken
...
This operation does potentionally discard information, however, so some compilers warn of it
...
Exercise 4-2
...
45e-6 where a floating-point number may be followed by e or E and an optionally signed exponent
...
3 External Variables A C program consists of a set of external objects, which are either variables or functions
...
External variables are defined outside of any function, and are thus potentionally available to many functions
...
By default, external variables and functions have the property that all references to them by the same name, even from functions compiled separately, are references to the same thing
...
) In this sense, external variables are analogous to Fortran COMMON blocks or variables in the outermost block in Pascal
...
Because external variables are globally accessible, they provide an alternative to function arguments and return values for communicating data between functions
...
If a large number of variables must be shared among functions, external variables are more convenient and efficient than long argument lists
...
External variables are also useful because of their greater scope and lifetime
...
External variables, on the other hand, are permanent, so they can retain values from one function invocation to the next
...
Let us examine this issue with a larger example
...
Because it is easier to implement, the calculator will use reverse Polish notation instead of infix
...
) In reverse Polish notation, each operator follows its operands; an infix expression like (1 - 2) * (4 + 5) is entered as 1 2 - 4 5 + * Chapter 4 - Functions and Program Structure 5 6 Chapter 4 - Functions and Program Structure Parentheses are not needed; the notation is unambiguous as long as we know how many operands each operator expects
...
Each operand is pushed onto a stack; when an operator arrives, the proper number of operands (two for binary operators) is popped, the operator is applied to them, and the result is pushed back onto the stack
...
Next, 4 and 5 are pushed and then replaced by their sum, 9
...
The value on the top of the stack is popped and printed when the end of the input line is encountered
...
And there should be a separate function for fetching the next input operator or operand
...
On possibility is to keep it in main, and pass the stack and the current stack position to the routines that push and pop it
...
So we have decided to store the stack and its associated information in external variables accessible to the push and pop functions but not to main
...
If for now we think of the program as existing in one source file, it will look like this: "temp0032
...
4">Section 3
...
#include
...
h> /* for #define MAXOP #define NUMBER /* max size of operand or operator */ /* signal that a number was found */ 100 '0' atof() */ int getop(char []); void push(double); double pop(void); /* reverse Polish calculator */ main() { int type; double op2; char s[MAXOP]; while ((type = getop(s)) != EOF) { switch (type) { 6 Chapter 4 - Functions and Program Structure Chapter 4 - Functions and Program Structure 7 case NUMBER: push(atof(s)); break; case '+': push(pop() + pop()); break; case '*': push(pop() * pop()); break; case '-': op2 = pop(); push(pop() - op2); break; case '/': op2 = pop(); if (op2 != 0
...
8g\n", pop()); break; default: printf("error: unknown command %s\n", s); break; } } return 0; } Because + and * are commutative operators, the order in which the popped operands are combined is irrelevant, but for - and / the left and right operand must be distinguished
...
To guarantee the right order, it is necessary to pop the first value into a temporary variable as we did in main
...
0; } } Chapter 4 - Functions and Program Structure 7 8 Chapter 4 - Functions and Program Structure A variable is external if it is defined outside of any function
...
But main itself does not refer to the stack or stack position - the representation can be hidden
...
The task is easy
...
If the next character is not a digit or a hexadecimal point, return it
...
#include
...
') return c; /* not a number */ i = 0; if (isdigit(c)) /* collect integer part */ while (isdigit(s[++i] = c = getch())) ; if (c == '
...
One instance is collecting characters that make up a number: until the first non-digit is seen, the number is not complete
...
The problem would be solved if it were possible to ``un-read'' the unwanted character
...
Fortunately, it's easy to simulate un-getting a character, by writing a pair of cooperating functions
...
How they work together is simple
...
getch reads from the buffer if there is anything else, and calls getchar if the buffer is empty
...
Since the buffer and the index are shared by getch and ungetch and must retain their values between calls, they must be external to both routines
...
We have used an array for the pushback, rather than a single character, to illustrate a more general approach
...
Given the basic framework, it's straightforward to extend the calculator
...
Exercise 4-4
...
Add a command to clear the stack
...
Add access to library functions like sin, exp, and pow
...
h> in Appendix B, Section 4
...
Add commands for handling variables
...
) Add a variable for the most recently printed value
...
Write a routine ungets(s) that will push back an entire string onto the input
...
Suppose that there will never be more than one character of pushback
...
Exercise 4-9
...
Decide what their properties ought to be if an EOF is pushed back, then implement your design
...
An alternate organization uses getline to read an entire input line; this makes getch and ungetch unnecessary
...
4
...
Among the questions of interest are • How are declarations written so that variables are properly declared during compilation? • How are declarations arranged so that all the pieces will be properly connected when the program is loaded? • How are declarations organized so there is only one copy? • How are external variables initialized? Let us discuss these topics by reorganizing the calculator program into several files
...
Chapter 4 - Functions and Program Structure 9 10 Chapter 4 - Functions and Program Structure The scope of a name is the part of the program within which the name can be used
...
Local variables of the same name in different functions are unrelated
...
The scope of an external variable or a function lasts from the point at which it is declared to the end of the file being compiled
...
} int sp = 0; double val[MAXVAL]; void push(double f) {
...
} then the variables sp and val may be used in push and pop simply by naming them; no further declarations are needed
...
On the other hand, if an external variable is to be referred to before it is defined, or if it is defined in a different source file from the one where it is being used, then an extern declaration is mandatory
...
A declaration announces the properties of a variable (primarily its type); a definition also causes storage to be set aside
...
On the other hand, the lines extern int sp; extern double val[]; declare for the rest of the source file that sp is an int and that val is a double array (whose size is determined elsewhere), but they do not create the variables or reserve storage for them
...
(There may also be extern declarations in the file containing the definition
...
Initialization of an external variable goes only with the definition
...
Then these definitions and declarations would be necessary to tie them together: in file1: extern int sp; extern double val[]; void push(double f) {
...
} in file2: int sp = 0; double val[MAXVAL]; Because the extern declarations in file1 lie ahead of and outside the function definitions, they apply to all functions; one set of declarations suffices for all of file1
...
4
...
The main function would go in one file, which we will call main
...
c; getop goes into a third, getop
...
Finally, getch and ungetch go into a fourth file, getch
...
There is one more thing to worry about - the definitions and declarations shared among files
...
Accordingly, we will place this common material in a header file, calc
...
(The #include line is described in Section 4
...
) The resulting program then looks like this: Chapter 4 - Functions and Program Structure 11 12 Chapter 4 - Functions and Program Structure There is a tradeoff between the desire that each file have access only to the information it needs for its job and the practical reality that it is harder to maintain more header files
...
For a much larger program, more organization and more headers would be needed
...
6 Static Variables The variables sp and val in stack
...
c, are for the private use of the functions in their respective source files, and are not meant to be accessed by anything else
...
External static thus provides a way to hide names like buf and bufp in the getch-ungetch combination, which must be external so they can be shared, yet which should not be visible to users of getch and ungetch
...
If the two routines and the two variables are compiled in one file, as in static char buf[BUFSIZE]; static int bufp = 0; /* buffer for ungetch */ /* next free position in buf */ int getch(void) {
...
} then no other routine will be able to access buf and bufp, and those names will not conflict with the same names in other files of the same program
...
The external static declaration is most often used for variables, but it can be applied to functions as well
...
If a function is declared static, however, its name is invisible outside of the file in which it is declared
...
Internal static variables are local to a particular function just as automatic variables are, but unlike automatics, they remain in existence rather than coming and going each time the function is activated
...
Exercise 4-11
...
Hint: use an internal static variable
...
7 Register Variables A register declaration advises the compiler that the variable in question will be heavily used
...
But compilers are free to ignore the advice
...
The register declaration can only be applied to automatic variables and to the formal parameters of a function
...
} Chapter 4 - Functions and Program Structure 13 14 Chapter 4 - Functions and Program Structure In practice, there are restrictions on register variables, reflecting the realities of underlying hardware
...
Excess register declarations are harmless, however, since the word register is ignored for excess or disallowed declarations
...
The specific restrictions on number and types of register variables vary from machine to machine
...
8 Block Structure C is not a block-structured language in the sense of Pascal or similar languages, because functions may not be defined within other functions
...
Declarations of variables (including initializations) may follow the left brace that introduces any compound statement, not just the one that begins a function
...
For example, in if (n > 0) { int i; /* declare a new i */ for (i = 0; i < n; i++)
...
An automatic variable declared and initialized in a block is initialized each time the block is entered
...
Given the declarations int x; int y; f(double x) { double y; } then within the function f, occurrences of x refer to the parameter, which is a double; outside f, they refer to the external int
...
As a matter of style, it's best to avoid variable names that conceal names in an outer scope; the potential for confusion and error is too great
...
9 Initialization Initialization has been mentioned in passing many times so far, but always peripherally to some other topic
...
In the absence of explicit initialization, external and static variables are guaranteed to be initialized to zero; automatic and register variables have undefined (i
...
, garbage) initial values
...
For automatic and register variables, the initializer is not restricted to being a constant: it may be any expression involving previously defined values, even function calls
...
3 could be written as int binsearch(int x, int v[], int n) { int low = 0; int high = n - 1; int mid;
...
Which form to prefer is largely a matter of taste
...
An array may be initialized by following its declaration with a list of initializers enclosed in braces and separated by commas
...
If there are fewer initializers for an array than the specified size, the others will be zero for external, static and automatic variables
...
There is no way to specify repetition of an initializer, nor to initialize an element in the middle of an array without supplying all the preceding values as well
...
4
...
Consider printing a number as a character string
...
Chapter 4 - Functions and Program Structure 15 16 Chapter 4 - Functions and Program Structure There are two solutions to this problem
...
6
...
Again, this version can fail on the largest negative number
...
h> /* printd: print n in decimal */ void printd(int n) { if (n < 0) { putchar('-'); n = -n; } if (n / 10) printd(n / 10); putchar(n % 10 + '0'); } When a function calls itself recursively, each invocation gets a fresh set of all the automatic variables, independent of the previous set
...
It passes 12 to a second printd, which in turn passes 1 to a third
...
That printd prints 2, then returns to the first level
...
Another good example of recursion is quicksort, a sorting algorithm developed by C
...
R
...
Given an array, one element is chosen and the others partitioned in two subsets - those less than the partition element and those greater than or equal to it
...
When a subset has fewer than two elements, it doesn't need any sorting; this stops the recursion
...
We use the middle element of each subarray for partitioning
...
v[right] into increasing order */ void qsort(int v[], int left, int right) { int i, last; void swap(int v[], int i, int j); if (left >= right) /* do nothing if array contains */ return; /* fewer than two elements */ swap(v, left, (left + right)/2); /* move partition elem */ last = left; /* to v[0] */ for (i = left + 1; i <= right; i++) /* partition */ if (v[i] < v[left]) swap(v, ++last, i); swap(v, left, last); /* restore partition elem */ qsort(v, left, last-1); qsort(v, last+1, right); } We moved the swapping operation into a separate function swap because it occurs three times in qsort
...
Recursion may provide no saving in storage, since somewhere a stack of the values being processed must be maintained
...
But recursive code is more compact, and often much easier to write and understand than the non-recursive equivalent
...
6
...
Adapt the ideas of printd to write a recursive version of itoa; that is, convert an integer into a string by calling a recursive routine
...
Write a recursive version of the function reverse(s), which reverses the string s in place
...
11 The C Preprocessor C provides certain language facilities by means of a preprocessor, which is conceptionally a separate first step in compilation
...
Other features described in this section include conditional compilation and macros with arguments
...
11
...
Any source line of the form #include "filename" or #include is replaced by the contents of the file filename
...
An included file may itself contain #include lines
...
h>
...
) #include is the preferred way to tie the declarations together for a large program
...
Naturally, when an included file is changed, all files that depend on it must be recompiled
...
11
...
The name in a #define has the same form as a variable name; the Chapter 4 - Functions and Program Structure 17 18 Chapter 4 - Functions and Program Structure replacement text is arbitrary
...
The scope of a name defined with #define is from its point of definition to the end of the source file being compiled
...
Substitutions are made only for tokens, and do not take place within quoted strings
...
Any name may be defined with any replacement text
...
It is also possible to define macros with arguments, so the replacement text can be different for different calls of the macro
...
Each occurrence of a formal parameter (here A or B) will be replaced by the corresponding actual argument
...
If you examine the expansion of max, you will notice some pitfalls
...
For instance max(i++, j++) /* WRONG */ will increment the larger twice
...
Nonetheless, macros are valuable
...
h>, in which getchar and putchar are often defined as macros to avoid the run-time overhead of a function call per character processed
...
h> are also usually implemented as macros
...
} Formal parameters are not replaced within quoted strings
...
This can be combined with string concatenation to make, for example, a debugging print macro: 18 Chapter 4 - Functions and Program Structure Chapter 4 - Functions and Program Structure #define dprint(expr) 19 printf(#expr " = %g\n", expr) When this is invoked, as in dprint(x/y) the macro is expanded into printf("x/y" " = &g\n", x/y); and the strings are concatenated, so the effect is printf("x/y = &g\n", x/y); Within the actual argument, each " is replaced by \" and each \ by \\, so the result is a legal string constant
...
If a parameter in the replacement text is adjacent to a ##, the parameter is replaced by the actual argument, the ## and surrounding white space are removed, and the result is re-scanned
...
The rules for nested uses of ## are arcane; further details may be found in Appendix A
...
Define a macro swap(t,x,y) that interchanges two arguments of type t
...
) 4
...
3 Conditional Inclusion It is possible to control preprocessing itself with conditional statements that are evaluated during preprocessing
...
The "sysv
...
h" #elif SYSTEM == MSDOS #define HDR "msdos
...
h" #endif #include HDR The #ifdef and #ifndef lines are specialized forms that test whether a name is defined
...
h go here */ #endif Back to Chapter 3 -- Index -- Chapter 5 Compiled by tmdcjsl(skidrow8123@hotmail
...
Pointers are much used in C, partly because they are sometimes the only way to express a computation, and partly because they usually lead to more compact and efficient code than can be obtained in other ways
...
Pointers have been lumped with the goto statement as a marvelous way to create impossible-to-understand programs
...
With discipline, however, pointers can also be used to achieve clarity and simplicity
...
The main change in ANSI C is to make explicit the rules about how pointers can be manipulated, in effect mandating what good programmers already practice and good compilers already enforce
...
5
...
A typical machine has an array of consecutively numbered or addressed memory cells that may be manipulated individually or in contiguous groups
...
A pointer is a group of cells (often two or four) that can hold an address
...
The & operator only applies to objects in memory: variables and array elements
...
The unary operator * is the indirection or dereferencing operator; when applied to a pointer, it accesses the object the pointer points to
...
This artificial sequence shows how to declare a pointer and how to use & and *: int x = 1, y = 2, z[10]; int *ip; /* ip is a pointer to int */ ip = x y = *ip; *ip = 0; ip = &z[0]; /* ip now points to x */ /* y is now 1 */ /* x is now 0 */ /* ip now points to z[0] */ The declaration of x, y, and z are what we've seen all along
...
The syntax of the declaration for a variable mimics the syntax of expressions in which the variable might appear
...
For example, double *dp, atof(char *); says that in an expression *dp and atof(s) have values of double, and that the argument of atof is a pointer to char
...
(There is one exception: a ``pointer to void'' is used to hold any type of pointer but cannot be dereferenced itself
...
11
...
The unary operators * and & bind more tightly than arithmetic operators, so the assignment y = *ip + 1 takes whatever ip points at, adds 1, and assigns the result to y, while *ip += 1 increments what ip points to, as do ++*ip and (*ip)++ The parentheses are necessary in this last example; without them, the expression would increment ip instead of what it points to, because unary operators like * and ++ associate right to left
...
For example, if iq is another pointer to int, iq = ip copies the contents of ip into iq, thus making iq point to whatever ip pointed to
...
2 Pointers and Function Arguments Since C passes arguments to functions by value, there is no direct way for the called function to alter a variable in the calling function
...
It is not enough to write swap(a, b); where the swap function is defined as void swap(int x, int y) 2 /* WRONG */ Chapter 5 - Pointers and Arrays Chapter 5 - Pointers and Arrays 3 { int temp; temp = x; x = y; y = temp; } Because of call by value, swap can't affect the arguments a and b in the routine that called it
...
The way to obtain the desired effect is for the calling program to pass pointers to the values to be changed: swap(&a, &b); Since the operator & produces the address of a variable, &a is a pointer to a
...
void swap(int *px, int *py) { int temp; /* interchange *px and *py */ temp = *px; *px = *py; *py = temp; } Pictorially: Pointer arguments enable a function to access and change objects in the function that called it
...
getint has to return the value it found and also signal end of file when there is no more input
...
One solution is to have getint return the end of file status as its function value, while using a pointer argument to store the converted integer back in the calling function
...
4
...
Notice that it is essential to pass the address of array[n] to getint
...
Our version of getint returns EOF for end of file, zero if the next input is not a number, and a positive value if the input contains a valid number
...
h> int getch(void); void ungetch(int); /* getint: get next integer from input into *pn */ int getint(int *pn) { int c, sign; while (isspace(c = getch())) /* skip white space */ ; if (!isdigit(c) && c != EOF && c != '+' && c != '-') { ungetch(c); /* it is not a number */ return 0; } sign = (c == '-') ? -1 : 1; if (c == '+' || c == '-') c = getch(); for (*pn = 0; isdigit(c), c = getch()) *pn = 10 * *pn + (c - '0'); *pn *= sign; if (c != EOF) ungetch(c); return c; } Throughout getint, *pn is used as an ordinary int variable
...
3) so the one extra character that must be read can be pushed back onto the input
...
As written, getint treats a + or - not followed by a digit as a valid representation of zero
...
Exercise 5-2
...
What type does getfloat return as its function value? 4 Chapter 5 - Pointers and Arrays Chapter 5 - Pointers and Arrays 5 5
...
Any operation that can be achieved by array subscripting can also be done with pointers
...
The declaration int a[10]; defines an array of size 10, that is, a block of 10 consecutive objects named a[0], a[1],
...
The notation a[i] refers to the i-th element of the array
...
Now the assignment x = *pa; will copy the contents of a[0] into x
...
Thus, if pa points to a[0], *(pa+1) refers to the contents of a[1], pa+i is the address of a[i], and *(pa+i) is the contents of a[i]
...
The meaning of ``adding 1 to a pointer,'' and by extension, all pointer arithmetic, is that pa+1 points to the next object, and pa+i points to the i-th object beyond pa
...
By definition, the value of a variable or expression of type array is the address of element zero of the array
...
Since the name of an array is a synonym for the location of the initial element, the assignment pa=&a[0] can also be written as pa = a; Rather more surprising, at first sight, is the fact that a reference to a[i] can also be written as *(a+i)
...
Applying the operator & to both parts of this equivalence, it follows that &a[i] and a+i are also identical: a+i is the address of the i-th element beyond a
...
In short, an array-and-index expression is equivalent to one written as a pointer and offset
...
A pointer is a variable, so pa=a and pa++ are legal
...
When an array name is passed to a function, what is passed is the location of the initial element
...
We can use this fact to write another version of strlen, which computes the length of a string
...
That means that calls like strlen("hello, world"); strlen(array); 6 /* string constant */ /* char array[100]; */ Chapter 5 - Pointers and Arrays Chapter 5 - Pointers and Arrays strlen(ptr); 7 /* char *ptr; */ all work
...
When an array name is passed to a function, the function can at its convenience believe that it has been handed either an array or a pointer, and manipulate it accordingly
...
It is possible to pass part of an array to a function, by passing a pointer to the beginning of the subarray
...
Within f, the parameter declaration can read f(int arr[]) {
...
} So as far as f is concerned, the fact that the parameter refers to part of a larger array is of no consequence
...
Of course, it is illegal to refer to objects that are not within the array bounds
...
4 Address Arithmetic If p is a pointer to some element of an array, then p++ increments p to point to the next element, and p+=i increments it to point i elements beyond where it currently does
...
C is consistent and regular in its approach to address arithmetic; its integration of pointers, arrays, and address arithmetic is one of the strengths of the language
...
There are two routines
...
The second, afree(p), releases the storage thus acquired so it can be re-used later
...
That is, the storage managed by alloc and afree is a stack, or last-in, first-out
...
7 we will show how they can be implemented
...
This array is private to alloc and afree
...
In practical implementations, the array may well not even have a name; it might instead be obtained by calling malloc or by asking the operating system for a pointer to some unnamed block of storage
...
We use a pointer, called allocp, that points to the next free element
...
If so, alloc returns the current value of allocp (i
...
, the beginning of the free block), then increments it by n to point to the next free area
...
afree(p) merely sets allocp to p if p is inside allocbuf
...
The declaration static char *allocp = allocbuf; defines allocp to be a character pointer and initializes it to point to the beginning of allocbuf, which is the next free position when the program starts
...
The test if (allocbuf + ALLOCSIZE - allocp >= n) { /* it fits */ checks if there's enough room to satisfy a request for n characters
...
If the request can be satisfied, alloc returns a pointer to the beginning of a block of characters (notice the declaration of the function itself)
...
C guarantees that zero is never a valid address for data, so a return value of zero can be used to signal an abnormal event, in this case no space
...
Zero is the sole exception: the constant zero may be assigned to a pointer, and a pointer may be compared with the constant zero
...
NULL is defined in
...
We will use NULL henceforth
...
First, pointers may be compared under certain circumstances
...
, work properly
...
Any pointer can be meaningfully compared for equality or inequality with zero
...
(There is one exception: the address of the first element past the end of an array can be used in pointer arithmetic
...
The construction p + n means the address of the n-th object beyond the one p currently points to
...
If an int is four bytes, for example, the int will be scaled by four
...
This fact can be used to write yet another version of strlen: /* strlen: return length of string s */ int strlen(char *s) { char *p = s; while (*p != '\0') p++; return p - s; Chapter 5 - Pointers and Arrays 9 10 Chapter 5 - Pointers and Arrays } In its declaration, p is initialized to s, that is, to point to the first character of the string
...
Because p points to characters, p++ advances p to the next character each time, and p-s gives the number of characters advanced over, that is, the string length
...
The header
...
If we were being cautious, however, we would use size_t for the return value of strlen, to match the standard library version
...
Pointer arithmetic is consistent: if we had been dealing with floats, which occupy more storage that chars, and if p were a pointer to float, p++ would advance to the next float
...
All the pointer manipulations automatically take into account the size of the objects pointed to
...
All other pointer arithmetic is illegal
...
5
...
In the internal representation, the array is terminated with the null character '\0' so that programs can find the end
...
Perhaps the most common occurrence of string constants is as arguments to functions, as in printf("hello, world\n"); When a character string like this appears in a program, access to it is through a character pointer; printf receives a pointer to the beginning of the character array
...
String constants need not be function arguments
...
This is not a string copy; only pointers are involved
...
There is an important difference between these definitions: char amessage[] = "now is the time"; /* an array */ char *pmessage = "now is the time"; /* a pointer */ 10 Chapter 5 - Pointers and Arrays Chapter 5 - Pointers and Arrays 11 amessage is an array, just big enough to hold the sequence of characters and '\0' that initializes it
...
On the other hand, pmessage is a pointer, initialized to point to a string constant; the pointer may subsequently be modified to point elsewhere, but the result is undefined if you try to modify the string contents
...
The first function is strcpy(s,t), which copies the string t to the string s
...
To copy the characters, we need a loop
...
Here they are conveniently initialized pointers, which are marched along the arrays a character at a time, until the '\0' that terminates t has been copied into s
...
Experienced C programmers would prefer /* strcpy: copy t to s; pointer version 2 */ void strcpy(char *s, char *t) { while ((*s++ = *t++) != '\0') ; } This moves the increment of s and t into the test part of the loop
...
In the same way, the character is stored into the old s position before s is incremented
...
The net effect is that characters are copied from t to s, up and including the terminating '\0'
...
So the function would likely be written as /* strcpy: copy t to s; pointer version 3 */ void strcpy(char *s, char *t) { while (*s++ = *t++) ; } Although this may seem cryptic at first sight, the notational convenience is considerable, and the idiom should be mastered, because you will see it frequently in C programs
...
h>) returns the target string as its function value
...
The value is obtained by subtracting the characters at the first position where s and t disagree
...
For example, *--p decrements p before fetching the character that p points to
...
3
...
h> contains declarations for the functions mentioned in this section, plus a variety of other string-handling functions from the standard library
...
Write a pointer version of the function strcat that we showed in Chapter 2: strcat(s,t) copies the string t to the end of s
...
Write the function strend(s,t), which returns 1 if the string t occurs at the end of the string s, and zero otherwise
...
Write versions of the library functions strncpy, strncat, and strncmp, which operate on at most the first n characters of their argument strings
...
Full descriptions are in Appendix B
...
Rewrite appropriate programs from earlier chapters and exercises with pointers instead of array indexing
...
5
...
Let us illustrate by writing a program that will sort a set of text lines into alphabetic order, a stripped-down version of the UNIX program sort
...
The same algorithms will work, except that now we have to deal with lines of text, which are of different lengths, and which, unlike integers, can't be compared or moved in a single operation
...
This is where the array of pointers enters
...
The pointers themselves can bee stored in an array
...
When two out-of-order lines have to be exchanged, the pointers in the pointer array are exchanged, not the text lines themselves
...
The sorting process has three steps: read all the lines of input sort them print them in order As usual, it's best to divide the program into functions that match this natural division, with the main routine controlling the other functions
...
The input routine has to collect and save the characters of each line, and build an array of pointers to the lines
...
Since the input function can only cope with a finite number of input lines, it can return some illegal count like Chapter 5 - Pointers and Arrays 13 14 Chapter 5 - Pointers and Arrays -1 if too much input is presented
...
"error: input too big to sort\n"); return 1; } } #define MAXLEN 1000 /* max length of any input line */ int getline(char *, int); char *alloc(int); /* readlines: read input lines */ int readlines(char *lineptr[], int maxlines) { int len, nlines; char *p, line[MAXLEN]; nlines = 0; while ((len = getline(line, MAXLEN)) > 0) if (nlines >= maxlines || p = alloc(len) == NULL) return -1; else { line[len-1] = '\0'; /* delete newline */ strcpy(p, line); lineptr[nlines++] = p; } return nlines; } /* writelines: write output lines */ void writelines(char *lineptr[], int nlines) { int i; for (i = 0; i < nlines; i++) printf("%s\n", lineptr[i]); } The function getline is from Section 1
...
The main new thing is the declaration for lineptr: char *lineptr[MAXLINES] says that lineptr is an array of MAXLINES elements, each element of which is a pointer to a char
...
Since lineptr is itself the name of an array, it can be treated as a pointer in the same manner as in our earlier examples, and writelines can be written instead as /* writelines: write output lines */ void writelines(char *lineptr[], int nlines) { while (nlines-- > 0) printf("%s\n", *lineptr++); } Initially, *lineptr points to the first line; each element advances it to the next line pointer while nlines 14 Chapter 5 - Pointers and Arrays Chapter 5 - Pointers and Arrays 15 is counted down
...
The quicksort from Chapter 4 needs minor changes: the declarations have to be modified, and the comparison operation must be done by calling strcmp
...
/* qsort: sort v[left]
...
Exercise 5-7
...
How much faster is the program? 5
...
In this section, we will show some of their properties
...
For example, March 1 is the 60th day of a non-leap year, and the 61st day of a leap year
...
Since this latter function computes two values, the month and day arguments will be pointers: month_day(1988, 60, &m, &d) sets m to 2 and d to 29 (February 29th)
...
Since the number of days per month differs for leap years and non-leap years, it's easier Chapter 5 - Pointers and Arrays 15 16 Chapter 5 - Pointers and Arrays to separate them into two rows of a two-dimensional array than to keep track of what happens to February during computation
...
The array daytab has to be external to both day_of_year and month_day, so they can both use it
...
daytab is the first two-dimensional array we have dealt with
...
Hence subscripts are written as daytab[i][j] /* [row][col] */ rather than daytab[i,j] /* WRONG */ Other than this notational distinction, a two-dimensional array can be treated in much the same way as in other languages
...
An array is initialized by a list of initializers in braces; each row of a two-dimensional array is initialized by a corresponding sub-list
...
Since space is not at a premium here, this is clearer than adjusting the indices
...
In this particular case, it is a pointer to objects that are arrays of 13 ints
...
} It could also be f(int daytab[][13]) {
...
} which says that the parameter is a pointer to an array of 13 integers
...
Without parentheses, the declaration int *daytab[13] is an array of 13 pointers to integers
...
Section 5
...
Exercise 5-8
...
Remedy this defect
...
8 Initialization of Pointer Arrays Consider the problem of writing a function month_name(n), which returns a pointer to a character string containing the name of the n-th month
...
month_name contains a private array of character strings, and returns a pointer to the proper one when called
...
The syntax is similar to previous initializations: /* month_name: return name of n-th month */ char *month_name(int n) { static char *name[] = { "Illegal month", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December" }; return (n < 1 || n > 12) ? name[0] : name[n]; } The declaration of name, which is an array of character pointers, is the same as lineptr in the sorting example
...
The characters of the i-th string are placed somewhere, and a pointer to them is stored in name[i]
...
5
...
Multi-dimensional Arrays Newcomers to C are sometimes confused about the difference between a two-dimensional array and an array of pointers, such as name in the example above
...
But a is a true two-dimensional array: 200 int-sized locations have been set aside, and the conventional rectangular subscript calculation 20 * row +col is used to find the element a[row,col]
...
Assuming that each element of b does point to a twenty-element array, then there will be 200 ints set aside, plus ten cells for the pointers
...
That is, each element of b need not point to a twenty-element vector; some may point to two elements, some to fifty, and some to none at all
...
Compare the declaration and picture for an array of pointers: char *name[] = { "Illegal month", "Jan", "Feb", "Mar" }; with those for a two-dimensional array: char aname[][15] = { "Illegal month", "Jan", "Feb", "Mar" }; Exercise 5-9
...
5
...
When main is called, it is called with two arguments
...
We customarily use multiple levels of pointers to manipulate these character strings
...
That is, the command echo hello, world prints the output 18 Chapter 5 - Pointers and Arrays Chapter 5 - Pointers and Arrays 19 hello, world By convention, argv[0] is the name by which the program was invoked, so argc is at least 1
...
In the example above, argc is 3, and argv[0], argv[1], and argv[2] are "echo", "hello,", and "world" respectively
...
The first version of echo treats argv as an array of character pointers: #include
...
This next variant is based on incrementing argv, which is a pointer to pointer to char, while argc is counted down: #include
...
Each successive increment moves it along to the next argument; *argv is then the pointer to that argument
...
Alternatively, we could write the printf statement as printf((argc > 1) ? "%s " : "%s", *++argv); Chapter 5 - Pointers and Arrays 19 20 Chapter 5 - Pointers and Arrays This shows that the format argument of printf can be an expression too
...
1
...
Following the lead of the UNIX program grep, let us enhance the program so the pattern to be matched is specified by the first argument on the command line
...
h> #include
...
It is declared in
...
The model can now be elaborated to illustrate further pointer constructions
...
One says ``print all the lines except those that match the pattern;'' the second says ``precede each printed line by its line number
...
If we choose -x (for ``except'') to signal the inversion, and -n (``number'') to request line numbering, then the command find -x -npattern will print each line that doesn't match the pattern, preceded by its line number
...
Furthermore, it is convenient for users if option arguments can be combined, as in find -nx pattern Here is the program: #include
...
h> #define MAXLINE 1000 int getline(char *line, int max); /* find: print lines that match pattern from 1st arg */ 20 Chapter 5 - Pointers and Arrays Chapter 5 - Pointers and Arrays 21 main(int argc, char *argv[]) { char line[MAXLINE]; long lineno = 0; int c, except = 0, number = 0, found = 0; while (--argc > 0 && (*++argv)[0] == '-') while (c = *++argv[0]) switch (c) { case 'x': except = 1; break; case 'n': number = 1; break; default: printf("find: illegal option %c\n", c); argc = 0; found = -1; break; } if (argc != 1) printf("Usage: find -x -n pattern\n"); else while (getline(line, MAXLINE) > 0) { lineno++; if ((strstr(line, *argv) != NULL) != except) { if (number) printf("%ld:", lineno); printf("%s", line); found++; } } return found; } argc is decremented and argv is incremented before each optional argument
...
Thus argc should be 1 and *argv should point at the pattern
...
(An alternate valid form would be **++argv
...
In fact, that is what we have used in the inner loop, where the task is to walk along a specific argument string
...
Exercise 5-10
...
For example, expr 2 3 4 + * evaluates 2 * (3+4)
...
Modify the program entab and detab (written as exercises in Chapter 1) to accept a list of tab stops as arguments
...
Exercise 5-12
...
Choose convenient (for the user) default behavior
...
Write the program tail, which prints the last n lines of its input
...
The program should behave rationally no matter how unreasonable the input or the value of n
...
6, not in a two-dimensional array of fixed size
...
11 Pointers to Functions In C, a function itself is not a variable, but it is possible to define pointers to functions, which can be assigned, placed in arrays, passed to functions, returned by functions, and so on
...
A sort often consists of three parts - a comparison that determines the ordering of any pair of objects, an exchange that reverses their order, and a sorting algorithm that makes comparisons and exchanges until the objects are in order
...
This is the approach taken in our new sort
...
These functions are declared ahead of main and a pointer to the appropriate one is passed to qsort
...
#include
...
h> #define MAXLINES 5000 char *lineptr[MAXLINES]; /* max #lines to be sorted */ /* pointers to text lines */ int readlines(char *lineptr[], int nlines); void writelines(char *lineptr[], int nlines); void qsort(void *lineptr[], int left, int right, int (*comp)(void *, void *)); int numcmp(char *, char *); /* sort input lines */ main(int argc, char *argv[]) { int nlines; /* number of input lines read */ int numeric = 0; /* 1 if numeric sort */ if (argc > 1 && strcmp(argv[1], "-n") == 0) numeric = 1; if ((nlines = readlines(lineptr, MAXLINES)) >= 0) { qsort((void**) lineptr, 0, nlines-1, (int (*)(void*,void*))(numeric ? numcmp : strcmp)); writelines(lineptr, nlines); return 0; } else { printf("input too big to sort\n"); return 1; } } 22 Chapter 5 - Pointers and Arrays Chapter 5 - Pointers and Arrays 23 In the call to qsort, strcmp and numcmp are addresses of functions
...
We have written qsort so it can process any data type, not just character strings
...
The generic pointer type void * is used for the pointer arguments
...
The elaborate cast of the function argument casts the arguments of the comparison function
...
/* qsort: sort v[left]
...
The fourth parameter of qsort is int (*comp)(void *, void *) which says that comp is a pointer to a function that has two void * arguments and returns an int
...
The parentheses are needed so the components are correctly associated; without them, int *comp(void *, void *) /* WRONG */ says that comp is a function returning a pointer to an int, which is very different
...
Here is numcmp, which compares two strings on a leading numeric value, computed by calling atof: #include
...
void swap(void *v[], { void *temp; int i, int j;) temp = v[i]; v[i] = v[j]; v[j] = temp; } A variety of other options can be added to the sorting program; some make challenging exercises
...
Modify the sort program to handle a -r flag, which indicates sorting in reverse (decreasing) order
...
Exercise 5-15
...
Exercise 5-16
...
Make sure it works in conjunction with -f
...
Add a field-searching capability, so sorting may bee done on fields within lines, each field sorted according to an independent set of options
...
) 5
...
The syntax is an attempt to make the declaration and the use agree; it works well for simple cases, but it can be confusing for the harder ones, because declarations cannot be read left to right, and because parentheses are over-used
...
Although truly complicated declarations rarely arise in practice, it is important to know how to understand them, and, if necessary, how to create them
...
7
...
The word description reads left to 24 Chapter 5 - Pointers and Arrays Chapter 5 - Pointers and Arrays 25 right
...
It converts a C declaration into a word description, as in these examples: char **argv argv: pointer to char int (*daytab)[13] daytab: pointer to array[13] of int int *daytab[13] daytab: array[13] of pointer to int void *comp() comp: function returning pointer to void void (*comp)() comp: pointer to function returning void char (*(*x())[])() x: function returning pointer to array[] of pointer to function returning char char (*(*x[3])())[5] x: array[3] of pointer to function returning pointer to array[5] of char dcl is based on the grammar that specifies a declarator, which is spelled out precisely in Appendix A, Section 8
...
A direct-dcl is a name, or a parenthesized dcl, or a direct-dcl followed by parentheses, or a direct-dcl followed by brackets with an optional size
...
For instance, consider this declarator: (*pfa[])() pfa will be identified as a name and thus as a direct-dcl
...
Then *pfa[] is recognized as a dcl, so (*pfa[]) is a direct-dcl
...
We can also illustrate the parse with a tree like this (where direct-dcl has been abbreviated to dir-dcl): Chapter 5 - Pointers and Arrays 25 26 Chapter 5 - Pointers and Arrays The heart of the dcl program is a pair of functions, dcl and dirdcl, that parse a declaration according to this grammar
...
/* dcl: parse a declarator */ void dcl(void) { int ns; for (ns = 0; gettoken() == '*'; ) /* count *'s */ ns++; dirdcl(); while (ns-- > 0) strcat(out, " pointer to"); } /* dirdcl: parse a direct declarator */ void dirdcl(void) { int type; if (tokentype == '(') { /* ( dcl ) */ dcl(); if (tokentype != ')') printf("error: missing )\n"); } else if (tokentype == NAME) /* variable name */ strcpy(name, token); else printf("error: expected name or (dcl)\n"); 26 Chapter 5 - Pointers and Arrays Chapter 5 - Pointers and Arrays 27 while ((type=gettoken()) == PARENS || type == BRACKETS) if (type == PARENS) strcat(out, " function returning"); else { strcat(out, " array"); strcat(out, token); strcat(out, " of"); } } Since the programs are intended to be illustrative, not bullet-proof, there are significant restrictions on dcl
...
It does not handle argument types in functions, or qualifiers like const
...
It doesn't do much error recovery, so invalid declarations will also confuse it
...
Here are the global variables and the main routine: #include
...
h> #include
...
*/ main() /* convert declaration to words */ { while (gettoken() != EOF) { /* 1st token on line */ strcpy(datatype, token); /* is the datatype */ out[0] = '\0'; dcl(); /* parse rest of line */ if (tokentype != '\n') printf("syntax error\n"); printf("%s: %s %s\n", name, out, datatype); } return 0; } The function gettoken skips blanks and tabs, then finds the next token in the input; a ``token'' is a name, a pair of parentheses, a pair of brackets perhaps including a number, or any other single character
...
Going in the other direction is easier, especially if we do not worry about generating redundant parentheses
...
undcl also uses the same external variables as dcl does
...
Make dcl recover from input errors
...
Modify undcl so that it does not add redundant parentheses to declarations
...
Expand dcl to handle declarations with function argument types, qualifiers like const, and so on
...
com) Back to Chapter 5 -- Index -- Chapter 7 Chapter 5 - Pointers and Arrays 29 Chapter 6 - Structures A structure is a collection of one or more variables, possibly of different types, grouped together under a single name for convenient handling
...
) Structures help to organize complicated data, particularly in large programs, because they permit a group of related variables to be treated as a unit instead of as separate entities
...
Some of these in turn could be structures: a name has several components, as does an address and even a salary
...
The main change made by the ANSI standard is to define structure assignment - structures may be copied and assigned to, passed to functions, and returned by functions
...
Automatic structures and arrays may now also be initialized
...
1 Basics of Structures Let us create a few structures suitable for graphics
...
The two components can be placed in a structure declared like this: struct point { int x; int y; }; The keyword struct introduces a structure declaration, which is a list of declarations enclosed in braces
...
The tag names this kind of structure, and can be used subsequently as a shorthand for the part of the declaration in braces
...
A structure member or tag and an ordinary (i
...
, non-member) variable can have the same name without conflict, since they can always be distinguished by context
...
A struct declaration defines a type
...
That is, struct {
...
A structure declaration that is not followed by a list of variables reserves no storage; it merely describes a template or shape of a structure
...
For example, given the declaration of point above, struct point pt; defines a variable pt which is a structure of type struct point
...
A member of a particular structure is referred to in an expression by a construction of the form structure-name
...
'' connects the structure name and the member name
...
x, pt
...
x * pt
...
y * pt
...
One representation of a rectangle is a pair of points that denote the diagonally opposite corners: struct rect { struct point pt1; struct point pt2; }; The rect structure contains two point structures
...
pt1
...
6
...
Copy and assignment include passing arguments to functions and returning values from functions as well
...
A structure may be initialized by a list of constant member values; an automatic structure may also be initialized by an assignment
...
There are at least three possible approaches: pass components separately, pass an entire structure, or pass a pointer to it
...
The first function, makepoint, will take two integers and return a point structure: /* makepoint: make a point from x and y components */ struct point makepoint(int x, int y) { struct point temp; temp
...
y = y; return temp; } Notice that there is no conflict between the argument name and the member with the same name; indeed the re-use of the names stresses the relationship
...
pt1 = makepoint(0,0); screen
...
pt1
...
pt2
...
pt1
...
pt2
...
For instance, /* addpoints: add two points */ struct addpoint(struct point p1, struct point p2) { p1
...
x; p1
...
y; return p1; } Here both the arguments and the return value are structures
...
As another example, the function ptinrect tests whether a point is inside a rectangle, where we have adopted the convention that a rectangle includes its left and bottom sides but not its top and right sides: /* ptinrect: return 1 if int ptinrect(struct point { return p
...
pt1
...
y >= r
...
y } p in r, 0 if not */ p, struct rect r) && p
...
pt2
...
y < r
...
y; This assumes that the rectangle is presented in a standard form where the pt1 coordinates are less than the pt2 coordinates
...
x, (*pp)
...
x because the precedence of the structure member operator
...
The expression *pp
...
x), which is illegal here because x is not a pointer
...
If p is a pointer to a structure, then p->member-of-structure refers to the particular member
...
and -> associate from left to right, so if we have struct rect r, *rp = r then these four expressions are equivalent: r
...
x rp->pt1
...
pt1)
...
x The structure operators
...
For example, given the declaration struct { int len; char *str; } *p; then ++p->len increments len, not p, because the implied parenthesization is ++(p->len)
...
(This last set of parentheses is unnecessary
...
6
...
We need an array of character strings to hold the names, and an array of integers for the counts
...
Each keyword is a pair: char *word; int cout; and there is an array of pairs
...
Each element of the array is a structure
...
The structure initialization is analogous to earlier ones - the definition is followed by a list of initializers enclosed in braces: struct key { char *word; int count; } keytab[] = { "auto", 0, "break", 0, "case", 0, "char", 0, "const", 0, "continue", 0, "default", 0, /*
...
It would be more precise to enclose the initializers for each "row" or structure in braces, as in { "auto", 0 }, Chapter 6 - Structures 5 6 Chapter 6 - Structures { "break", 0 }, { "case", 0 },
...
As usual, the number of entries in the array keytab will be computed if the initializers are present and the [] is left empty
...
The main routine reads the input by repeatedly calling a function getword that fetches one word at a time
...
The list of keywords must be sorted in increasing order in the table
...
count, keytab[n]
...
tab[n-1] */ int binsearch(char *word, struct key tab[], int n) { int cond; int low, high, mid; low = 0; high = n - 1; while (low <= high) { mid = (low+high) / 2; if ((cond = strcmp(word, tab[mid]
...
The quantity NKEYS is the number of keywords in keytab
...
One possibility would be to terminate the list of initializers with a null pointer, then loop along keytab until the end is found
...
The size of the array is the size of one entry times the number of entries, so the number of entries is just size of keytab / size of struct key C provides a compile-time unary operator called sizeof that can be used to compute the size of any object
...
(Strictly, sizeof produces an unsigned integer value whose type, size_t, is defined in the header
...
) An object can be a variable or array or structure
...
In our case, the number of keywords is the size of the array divided by the size of one element
...
A sizeof can not be used in a #if line, because the preprocessor does not parse type names
...
Now for the function getword
...
getword fetches the next ``word'' from the input, where a word is either a string of letters and digits beginning with a letter, or a single non-white space character
...
/* getword: get next word or character from input */ int getword(char *word, int lim) { int c, getch(void); void ungetch(int); char *w = word; while (isspace(c = getch())) ; if (c != EOF) *w++ = c; if (!isalpha(c)) { *w = '\0'; return c; } for ( ; --lim > 0; w++) if (!isalnum(*w = getch())) { ungetch(*w); break; } *w = '\0'; return word[0]; } getword uses the getch and ungetch that we wrote in Chapter 4
...
The call to ungetch pushes that character back on the input for the next call
...
h>
...
Our version of getword does not properly handle underscores, string constants, comments, or preprocessor control lines
...
Chapter 6 - Structures 7 8 Chapter 6 - Structures 6
...
The external declaration of keytab need not change, but main and binsearch do need modification
...
tab[n-1] */ struct key *binsearch(char *word, struck key *tab, int n) { int cond; struct key *low = &tab[0]; struct key *high = &tab[n]; struct key *mid; while (low < high) { mid = low + (high-low) / 2; if ((cond = strcmp(word, mid->word)) < 0) high = mid; else if (cond > 0) low = mid + 1; else return mid; } return NULL; } There are several things worthy of note here
...
If binsearch finds the word, it returns a pointer to it; if it fails, it returns NULL
...
This requires significant changes in binsearch
...
The computation of the middle element can no longer be simply mid = (low+high) / 2 /* WRONG */ because the addition of pointers is illegal
...
The most important change is to adjust the algorithm to make sure that it does not generate an illegal pointer or attempt to access an element outside the array
...
The former is strictly illegal, and it is illegal to dereference the latter
...
In main we wrote 8 Chapter 6 - Structures Chapter 6 - Structures 9 for (p = keytab; p < keytab + NKEYS; p++) If p is a pointer to a structure, arithmetic on p takes into account the size of the structure, so p++ increments p by the correct amount to get the next element of the array of structures, and the test stops the loop at the right time
...
Because of alignment requirements for different objects, there may be unnamed ``holes'' in a structure
...
The sizeof operator returns the proper value
...
Accordingly an alternate style is sometimes used: struct key * binsearch(char *word, struct key *tab, int n) This is a matter of personal taste; pick the form you like and hold to it
...
5 Self-referential Structures Suppose we want to handle the more general problem of counting the occurrences of all the words in some input
...
Yet we can't do a linear search for each word as it arrives, to see if it's already been seen; the program would take too long
...
) How can we organize the data to copy efficiently with a list or arbitrary words? One solution is to keep the set of words seen so far sorted at all times, by placing each word into its proper position in the order as it arrives
...
Instead we will use a data structure called a binary tree
...
No node may have more than two children; it might have only zero or one
...
This is the tree for the sentence ``now is the time for all good men to come to the aid of their party'', as built by inserting each word as it is encountered: Chapter 6 - Structures 9 10 Chapter 6 - Structures To find out whether a new word is already in the tree, start at the root and compare the new word to the word stored at that node
...
If the new record is less than the tree word, continue searching at the left child, otherwise at the right child
...
This process is recursive, since the search from any node uses a search from one of its children
...
Going back to the description of a node, it is most conveniently represented as a structure with four components: struct tnode { /* the char *word; int count; struct tnode *left; struct tnode *right; }; tree node: */ /* points to the text */ /* number of occurrences */ /* left child */ /* right child */ This recursive declaration of a node might look chancy, but it's correct
...
Occasionally, one needs a variation of self-referential structures: two structures that refer to each other
...
struct s *p; }; struct s {
...
The main routine reads words with getword and installs them in the tree with addtree
...
h> #include
...
h> #define MAXWORD 100 10 Chapter 6 - Structures Chapter 6 - Structures 11 struct tnode *addtree(struct tnode *, char *); void treeprint(struct tnode *); int getword(char *, int); /* word frequency count */ main() { struct tnode *root; char word[MAXWORD]; root = NULL; while (getword(word, MAXWORD) != EOF) if (isalpha(word[0])) root = addtree(root, word); treeprint(root); return 0; } The function addtree is recursive
...
At each stage, that word is compared to the word already stored at the node, and is percolated down to either the left or right subtree by a recursive call to adtree
...
If a new node is created, addtree returns a pointer to it, which is installed in the parent node
...
(We will discuss these routines in a moment
...
This part of the code is executed only at the leaves of the tree, when a new node is being added
...
treeprint prints the tree in sorted order; at each node, it prints the left subtree (all the words less than this word), then the word itself, then the right subtree (all the words greater)
...
/* treeprint: in-order print of tree p */ void treeprint(struct tnode *p) { if (p != NULL) { treeprint(p->left); Chapter 6 - Structures 11 12 Chapter 6 - Structures printf("%4d %s\n", p->count, p->word); treeprint(p->right); } } A practical note: if the tree becomes ``unbalanced'' because the words don't arrive in random order, the running time of the program can grow too much
...
There are generalizations of the binary tree that do not suffer from this worst-case behavior, but we will not describe them here
...
Clearly it's desirable that there be only one storage allocator in a program, even though it allocates different kinds of objects
...
First, how does it meet the requirement of most real machines that objects of certain types must satisfy alignment restrictions (for example, integers often must be located at even addresses)? Second, what declarations can cope with the fact that an allocator must necessarily return different kinds of pointers? Alignment requirements can generally be satisfied easily, at the cost of some wasted space, by ensuring that the allocator always returns a pointer that meets all alignment restrictions
...
In Chapter 8 we will show one way to implement malloc
...
In C, the proper method is to declare that malloc returns a pointer to void, then explicitly coerce the pointer into the desired type with a cast
...
h>
...
html">Chapters 8 and 7
...
Write a program that reads a C program and prints in alphabetical order each group of variable names that are identical in the first 6 characters, but different somewhere thereafter
...
Make 6 a parameter that can be set from the command line
...
Write a cross-referencer that prints a list of all words in a document, and for each word, a list of the line numbers on which it occurs
...
Exercise 6-4
...
Precede each word by its count
...
6 Table Lookup In this section we will write the innards of a table-lookup package, to illustrate more aspects of structures
...
For example, consider the "center"> 12 Chapter 6 - Structures Chapter 6 - Structures 13 A block in the list is a structure containing pointers to the name, the replacement text, and the next block in the list
...
struct nlist { /* table entry: */ struct nlist *next; /* next entry in chain */ char *name; /* defined name */ char *defn; /* replacement text */ }; The pointer array is just #define HASHSIZE 101 static struct nlist *hashtab[HASHSIZE]; /* pointer table */ The hashing function, which is used by both lookup and install, adds each character value in the string to a scrambled combination of the previous ones and returns the remainder modulo the array size
...
/* hash: form hash value for string s */ unsigned hash(char *s) { unsigned hashval; for (hashval = 0; *s != '\0'; s++) hashval = *s + 31 * hashval; return hashval % HASHSIZE; } Unsigned arithmetic ensures that the hash value is non-negative
...
The search is performed by lookup
...
/* lookup: look for s in hashtab */ struct nlist *lookup(char *s) { struct nlist *np; for (np = hashtab[hash(s)]; np != NULL; np = np->next) if (strcmp(s, np->name) == 0) return np; /* found */ return NULL; /* not found */ } Chapter 6 - Structures 13 14 Chapter 6 - Structures The for loop in lookup is the standard idiom for walking along a linked list: for (ptr = head; ptr != NULL; ptr = ptr->next)
...
Otherwise, a new entry is created
...
struct nlist *lookup(char *); char *strdup(char *); /* install: put (name, defn) in hashtab */ struct nlist *install(char *name, char *defn) { struct nlist *np; unsigned hashval; if ((np = lookup(name)) == NULL) { /* not found */ np = (struct nlist *) malloc(sizeof(*np)); if (np == NULL || (np->name = strdup(name)) == NULL) return NULL; hashval = hash(name); np->next = hashtab[hashval]; hashtab[hashval] = np; } else /* already there */ free((void *) np->defn); /*free previous defn */ if ((np->defn = strdup(defn)) == NULL) return NULL; return np; } Exercise 6-5
...
Exercise 6-6
...
e
...
You may also find getch and ungetch helpful
...
7 Typedef C provides a facility called typedef for creating new data type names
...
The type Length can be used in declarations, casts, etc
...
Syntactically, typedef is like the storage classes extern, static, etc
...
As a more complicated example, we could make typedefs for the tree nodes shown earlier in this chapter: typedef struct tnode *Treeptr; typedef struct tnode { /* char *word; int count; struct tnode *left; struct tnode *right; } Treenode; the tree node: */ /* points to the text */ /* number of occurrences */ /* left child */ /* right child */ This creates two new type keywords called Treenode (a structure) and Treeptr (a pointer to the structure)
...
Nor are there any new semantics: variables declared this way have exactly the same properties as variables whose declarations are spelled out explicitly
...
For example, typedef int (*PFI)(char *, char *); creates the type PFI, for ``pointer to function (of two char * arguments) returning int,'' which can be used in contexts like PFI strcmp, numcmp; in the sort program of Chapter 5
...
The first is to parameterize a program against portability problems
...
One common situation is to use typedef names for various integer quantities, then make an appropriate set of choices of short, int, and long for each host machine
...
The second purpose of typedefs is to provide better documentation for a program - a type called Treeptr may be easier to understand than one declared only as a pointer to a complicated structure
...
8 Unions A union is a variable that may hold (at different times) objects of different types and sizes, with the compiler keeping track of size and alignment requirements
...
They are analogous to variant records in pascal
...
The value of a particular constant must be stored in a variable of the proper type, yet it is most convenient for table management if the value occupies the same amount of storage and is stored in the same place regardless of its type
...
The syntax is based on structures: union u_tag { int ival; float fval; char *sval; } u; The variable u will be large enough to hold the largest of the three types; the specific size is implementation-dependent
...
It is the programmer's responsibility to keep track of which type is currently stored in a union; the results are implementation-dependent if something is stored as one type and extracted as another
...
member or union-pointer->member just as for structures
...
ival); if (utype == FLOAT) printf("%f\n", u
...
sval); else printf("bad type %d in utype\n", utype); Unions may occur within structures and arrays, and vice versa
...
For example, in the structure array defined by struct { char *name; int flags; 16 Chapter 6 - Structures Chapter 6 - Structures 17 int utype; union { int ival; float fval; char *sval; } u; } symtab[NSYM]; the member ival is referred to as symtab[i]
...
ival and the first character of the string sval by either of *symtab[i]
...
sval symtab[i]
...
sval[0] In effect, a union is a structure in which all members have offset zero from the base, the structure is big enough to hold the ``widest'' member, and the alignment is appropriate for all of the types in the union
...
A union may only be initialized with a value of the type of its first member; thus union u described above can only be initialized with an integer value
...
6
...
Externally-imposed interfaces to hardware devices, also often require pieces of a word
...
Each identifier in a program has certain information associated with it, for example, whether or not it is a keyword, whether or not it is external and/or static, and so on
...
The usual way this is done is to define a set of ``masks'' corresponding to the relevant bit positions, as in "temp0019
...
Certain idioms appear frequently: flags |= EXTERNAL | STATIC; turns on the EXTERNAL and STATIC bits in flags, while flags &= ~(EXTERNAL | STATIC); turns them off, and Chapter 6 - Structures 17 18 Chapter 6 - Structures if ((flags & (EXTERNAL | STATIC)) == 0)
...
Although these idioms are readily mastered, as an alternative C offers the capability of defining and accessing fields within a word directly rather than by bitwise logical operators
...
'' For example, the symbol table #defines above could be replaced by the definition of three fields: struct { unsigned int is_keyword : 1; unsigned int is_extern : 1; unsigned int is_static : 1; } flags; This defines a variable table called flags that contains three 1-bit fields
...
The fields are declared unsigned int to ensure that they are unsigned quantities
...
is_keyword, flags
...
Fields behave like small integers, and may participate in arithmetic expressions just like other integers
...
is_extern = flags
...
is_extern = flags
...
is_extern == 0 && flags
...
to test them
...
Whether a field may overlap a word boundary is implementation-defined
...
The special width 0 may be used to force alignment at the next word boundary
...
This means that although fields are useful for maintaining internally-defined data structures, the question of which end comes first has to be carefully considered when picking apart externally-defined data; programs that depend on such things are not portable
...
They are not arrays and they do not have addresses, so the & operator cannot be applied on them
...
com) Back to Chapter 6 -- Index -- Chapter 8 18 Chapter 6 - Structures Chapter 7 - Input and Output Input and output are not part of the C language itself, so we have not emphasized them in our presentation thus far
...
In this chapter we will describe the standard library, a set of functions that provide input and output, string handling, storage management, mathematical routines, and a variety of other services for C programs
...
Programs that confine their system interactions to facilities provided by the standard library can be moved from one system to another without change
...
h>,
...
h>
...
The library is described in detail in Appendix B
...
1 Standard Input and Output As we said in Chapter 1, the library implements a simple model of text input and output
...
If the system doesn't operate that way, the library does whatever necessary to make it appear as if it does
...
The simplest input mechanism is to read one character at a time from the standard input, normally the keyboard, with getchar: int getchar(void) getchar returns the next input character each time it is called, or EOF when it encounters end of file
...
h>
...
In many environments, a file may be substituted for the keyboard by using the < convention for input redirection: if a program prog uses getchar, then the command line prog causes prog to read characters from infile instead
...
Input switching is also invisible if the input comes from another program via a pipe mechanism: on some systems, the command line otherprog | prog runs the two programs otherprog and prog, and pipes the standard output of otherprog into the standard input for prog
...
putchar returns the character written, or EOF is an error occurs
...
If pipes are supported, prog | anotherprog puts the standard output of prog into the standard input of anotherprog
...
Calls to putchar and printf may be interleaved - output happens in the order in which the calls are made
...
html#s8
...
5
...
h> functions are implemented on a given machine, programs that use them are shielded from knowledge of the character set
...
Write a program that converts upper case to lower or lower case to upper, depending on the name it is invoked with, as found in argv[0]
...
2 Formatted Output - printf The output function printf translates internal values to characters
...
The description here covers most typical uses but is not complete; for the full story, see Appendix B
...
); printf converts, formats, and prints its arguments on the standard output under control of the format
...
The format string contains two types of objects: ordinary characters, which are copied to the output stream, and conversion specifications, each of which causes conversion and printing of the next successive argument to printf
...
Between the % and the conversion character there may be, in order: • A minus sign, which specifies left adjustment of the converted argument
...
The converted argument will be printed in a field at least this wide
...
• A period, which separates the field width from the precision
...
• An h if the integer is to be printed as a short, or l (letter ell) if as a long
...
1
...
Table 7
...
,15
...
f double; [-]m
...
double; [-]m
...
ddddddE+/-xx, where the number of d's is given by e,E the precision (default 6)
...
Trailing zeros and a trailing decimal point are not printed
...
% no argument is converted; print a % A width or precision may be specified as *, in which case the value is computed by converting the next argument (which must be an int)
...
*s", max, s); Most of the format conversions have been illustrated in earlier chapters
...
The following table shows the effect of a variety of specifications in printing ``hello, world'' (12 characters)
...
:%s: :%10s: :%
...
15s: :%-15s: :%15
...
10s: :hello, world: :hello, world: :hello, wor: :hello, world: :hello, world: :hello, world : : hello, wor: :hello, wor : A warning: printf uses its first argument to decide how many arguments follow and what their type is
...
You should also be aware of the difference between these two calls: printf(s); printf("%s", s); /* FAILS if s contains % */ /* SAFE */ The function sprintf does the same conversions as printf does, but stores the output in a string: int sprintf(char *string, char *format, arg1, arg2,
...
, according to format as before, but places the result in string instead of the standard output; string must be big enough to receive the result
...
Write a program that will print arbitrary input in a sensible way
...
7
...
Since we are mainly interested in the argument processing, minprintf will process the format string and arguments but will call the real Chapter 7 - Input and Output 3 4 Chapter 7 - Input and Output printf to do the format conversions
...
) where the declaration
...
The declaration
...
Our minprintf is declared as void minprintf(char *fmt,
...
The tricky bit is how minprintf walks along the argument list when the list doesn't even have a name
...
h> contains a set of macro definitions that define how to step through an argument list
...
The type va_list is used to declare a variable that will refer to each argument in turn; in minprintf, this variable is called ap, for ``argument pointer
...
It must be called once before ap is used
...
Each call of va_arg returns one argument and steps ap to the next; va_arg uses a type name to determine what type to return and how big a step to take
...
It must be called before the program returns
...
Revise minprintf to handle more of the other facilities of printf
...
4 Formatted Input - Scanf The function scanf is the input analog of printf, providing many of the same conversion facilities in the opposite direction
...
) scanf reads characters from the standard input, interprets them according to the specification in format, 4 Chapter 7 - Input and Output Chapter 7 - Input and Output 5 and stores the results through the remaining arguments
...
As with printf, this section is a summary of the most useful features, not an exhaustive list
...
It returns as its value the number of successfully matched and assigned input items
...
On the end of file, EOF is returned; note that this is different from 0, which means that the next input character does not match the first specification in the format string
...
There is also a function sscanf that reads from a string instead of the standard input: int sscanf(char *string, char *format, arg1, arg2,
...
These arguments must be pointers
...
The format string may contain: • Blanks or tabs, which are not ignored
...
• Conversion specifications, consisting of the character %, an optional assignment suppression character *, an optional number specifying a maximum field width, an optional h, l or L indicating the width of the target, and a conversion character
...
Normally the result is places in the variable pointed to by the corresponding argument
...
An input field is defined as a string of non-white space characters; it extends either to the next white space character or until the field width, is specified, is exhausted
...
(White space characters are blank, tab, newline, carriage return, vertical tab, and formfeed
...
The corresponding argument must be a pointer, as required by the call-by-value semantics of C
...
2
...
2: Basic Scanf Conversions Character d i o u x c s e,f,g % Input Data; Argument type decimal integer; int * integer; int *
...
octal integer (with or without leading zero); int * unsigned decimal integer; unsigned int * hexadecimal integer (with or without leading 0x or 0X); int * characters; char *
...
The normal skip-over white space is suppressed; to read the next non-white space character, use %1s character string (not quoted); char *, pointing to an array of characters long enough for the string and a terminating '\0' that will be added
...
Chapter 7 - Input and Output 5 6 Chapter 7 - Input and Output The conversion characters d, i, o, u, and x may be preceded by h to indicate that a pointer to short rather than int appears in the argument list, or by l (letter ell) to indicate that a pointer to long appears in the argument list
...
2f\n", sum += v); return 0; } Suppose we want to read input lines that contain dates of the form 25 Dec 1988 The scanf statement is int day, year; char monthname[20]; scanf("%d %s %d", &day, monthname, &year); No & is used with monthname, since an array name is a pointer
...
So we could read dates of the form mm/dd/yy with the scanf statement: int day, month, year; scanf("%d/%d/%d", &month, &day, &year); scanf ignores blanks and tabs in its format string
...
) as it looks for input values
...
For example, suppose we want to read lines that might contain a date in either of the forms above
...
The next call to any input function will begin by reading the first character not read by scanf
...
By far the most common error is writing scanf("%d", n); instead of scanf("%d", &n); 6 Chapter 7 - Input and Output Chapter 7 - Input and Output 7 This error is not generally detected at compile time
...
Write a private version of scanf analogous to minprintf from the previous section
...
Rewrite the postfix calculator of Chapter 4 to use scanf and/or sscanf to do the input and number conversion
...
5 File Access The examples so far have all read the standard input and written the standard output, which are automatically defined for a program by the local operating system
...
One program that illustrates the need for such operations is cat, which concatenates a set of named files into the standard output
...
For example, the command cat x
...
c prints the contents of the files x
...
c (and nothing else) on the standard output
...
The rules are simple
...
fopen takes an external name like x
...
c, does some housekeeping and negotiation with the operating system (details of which needn't concern us), and returns a pointer to be used in subsequent reads or writes of the file
...
Users don't need to know the details, because the definitions obtained from
...
The only declaration needed for a file pointer is exemplified by FILE *fp; FILE *fopen(char *name, char *mode); This says that fp is a pointer to a FILE, and fopen returns a pointer to a FILE
...
(Details of how fopen can be implemented on the UNIX system are given in Section 8
...
) The call to fopen in a program is fp = fopen(name, mode); The first argument of fopen is a character string containing the name of the file
...
Allowable modes include read ("r"), write ("w"), and append ("a")
...
If a file that does not exist is opened for writing or appending, it is created if possible
...
Trying to read a file that does not exist is an error, and there may be other causes of error as well, like trying to read a file when you don't have permission
...
(The error can be Chapter 7 - Input and Output 7 8 Chapter 7 - Input and Output identified more precisely; see the discussion of error-handling functions at the end of Section 1 in Appendix B
...
getc returns the next character from a file; it needs the file pointer to tell it which file
...
putc is an output function: int putc(int c, FILE *fp) putc writes the character c to the file fp and returns the character written, or EOF if an error occurs
...
When a C program is started, the operating system environment is responsible for opening three files and providing pointers for them
...
h>
...
1
...
These are identical to scanf and printf, except that the first argument is a file pointer that specifies the file to be read or written; the format string is the second argument
...
) int fprintf(FILE *fp, char *format,
...
The design is one that has been found convenient for many programs
...
If there are no arguments, the standard input is processed
...
h> /* cat: main(int { FILE void concatenate files, version 1 */ argc, char *argv[]) *fp; filecopy(FILE *, FILE *) if (argc == 1) /* no args; copy standard input */ filecopy(stdin, stdout); else while(--argc > 0) if ((fp = fopen(*++argv, "r")) == NULL) { printf("cat: can't open %s\n, *argv); return 1; } else { filecopy(fp, stdout); fclose(fp); } 8 Chapter 7 - Input and Output Chapter 7 - Input and Output 9 return 0; } /* filecopy: copy file ifp to file ofp */ void filecopy(FILE *ifp, FILE *ofp) { int c; while ((c = getc(ifp)) != EOF) putc(c, ofp); } The file pointers stdin and stdout are objects of type FILE *
...
The function int fclose(FILE *fp) is the inverse of fopen, it breaks the connection between the file pointer and the external name that was established by fopen, freeing the file pointer for another file
...
There is also another reason for fclose on an output file - it flushes the buffer in which putc is collecting output
...
(You can close stdin and stdout if they are not needed
...
) 7
...
The trouble is that if one of the files can't be accessed for some reason, the diagnostic is printed at the end of the concatenated output
...
To handle this situation better, a second output stream, called stderr, is assigned to a program in the same way that stdin and stdout are
...
Let us revise cat to write its error messages on the standard error
...
h> /* cat: main(int { FILE void char concatenate files, version 2 */ argc, char *argv[]) *fp; filecopy(FILE *, FILE *); *prog = argv[0]; /* program name for errors */ if (argc == 1 ) /* no args; copy standard input */ filecopy(stdin, stdout); else while (--argc > 0) if ((fp = fopen(*++argv, "r")) == NULL) { fprintf(stderr, "%s: can't open %s\n", prog, *argv); exit(1); } else { filecopy(fp, stdout); fclose(fp); } Chapter 7 - Input and Output 9 10 Chapter 7 - Input and Output if (ferror(stdout)) { fprintf(stderr, "%s: error writing stdout\n", prog); exit(2); } exit(0); } The program signals errors in two ways
...
We included the program name, from argv[0], in the message, so if this program is used with others, the source of an error is identified
...
The argument of exit is available to whatever process called this one, so the success or failure of the program can be tested by another program that uses this one as a sub-process
...
exit calls fclose for each open output file, to flush out any buffered output
...
exit has the advantage that it can be called from other functions, and that calls to it can be found with a pattern-searching program like those in Chapter 5
...
int ferror(FILE *fp) Although output errors are rare, they do occur (for example, if a disk fills up), so a production program should check this as well
...
int feof(FILE *fp) We have generally not worried about exit status in our small illustrative programs, but any serious program should take care to return sensible, useful status values
...
7 Line Input and Output The standard library provides an input and output routine fgets that is similar to the getline function that we have used in earlier chapters: char *fgets(char *line, int maxline, FILE *fp) fgets reads the next input line (including the newline) from file fp into the character array line; at most maxline-1 characters will be read
...
Normally fgets returns line; on end of file or error it returns NULL
...
) For output, the function fputs writes a string (which need not contain a newline) to a file: int fputs(char *line, FILE *fp) It returns EOF if an error occurs, and non-negative otherwise
...
Confusingly, gets deletes the terminating '\n', and puts adds it
...
It is easy to implement our getline from fgets: /* getline: read a line, return length */ int getline(char *line, int max) { if (fgets(line, max, stdin) == NULL) return 0; else return strlen(line); } Exercise 7-6
...
Exercise 7-7
...
Should the file name be printed when a matching line is found? Exercise 7-8
...
7
...
This section is a brief synopsis of the most useful
...
7
...
1 String Operations We have already mentioned the string functions strlen, strcpy, strcat, and strcmp, found in
...
In the following, s and t are char *'s, and c and n are ints
...
8
...
h> perform character tests and conversions
...
The function returns int
...
8
...
int ungetc(int c, FILE *fp) pushes the character c back onto file fp, and returns either c, or EOF for an error
...
ungetc may be used with any of the input functions like scanf, getc, or getchar
...
8
...
The contents of s depend strongly on the local operating system
...
system returns a system-dependent integer status from the command executed
...
7
...
5 Storage Management The functions malloc and calloc obtain blocks of memory dynamically
...
void *calloc(size_t n, size_t size) returns a pointer to enough free space for an array of n objects of the specified size, or NULL if the request cannot be satisfied
...
The pointer returned by malloc or calloc has the proper alignment for the object in question, but it must be cast into the appropriate type, as in int *ip; ip = (int *) calloc(n, sizeof(int)); free(p) frees the space pointed to by p, where p was originally obtained by a call to malloc or calloc
...
It is also an error to use something after it has been freed
...
7 shows the implementation of a storage allocator like malloc, in which allocated blocks may be freed in any order
...
8
...
h>; here are some of the more frequently used
...
sin(x) cos(x) atan2(y,x) exp(x) log(x) log10(x) pow(x,y) sqrt(x) fabs(x) sine of x, x in radians cosine of x, x in radians arctangent of y/x, in radians exponential function ex natural (base e) logarithm of x (x>0) common (base 10) logarithm of x (x>0) xy square root of x (x>0) absolute value of x 7
...
7 Random Number generation The function rand() computes a sequence of pseudo-random integers in the range zero to RAND_MAX, which is defined in
...
One way to produce random floating-point numbers greater than or equal to zero but less than one is Chapter 7 - Input and Output 13 14 Chapter 7 - Input and Output #define frand() ((double) rand() / (RAND_MAX+1
...
) The function srand(unsigned) sets the seed for rand
...
7
...
Functions like isupper can be implemented to save space or to save time
...
Back to Chapter 6 -- Index -- Chapter 8 Compiled by tmdcjsl(skidrow8123@hotmail
...
This chapter describes how to use some of the most important system calls from C programs
...
Even if you use C on a different operating system, however, you should be able to glean insight into C programming from studying these examples; although details vary, similar code will be found on any system
...
This chapter is divided into three major parts: input/output, file system, and storage allocation
...
Chapter 7 was concerned with an input/output interface that is uniform across operating systems
...
In the next few sections we will describe the UNIX system calls for input and output, and show how parts of the standard library can be implemented with them
...
1 File Descriptors In the UNIX operating system, all input and output is done by reading or writing files, because all peripheral devices, even keyboard and screen, are files in the file system
...
In the most general case, before you read and write a file, you must inform the system of your intent to do so, a process called opening the file
...
The system checks your right to do so (Does the file exist? Do you have permission to access it?) and if all is well, returns to the program a small non-negative integer called a file descriptor
...
(A file descriptor is analogous to the file pointer used by the standard library, or to the file handle of MS-DOS
...
Since input and output involving keyboard and screen is so common, special arrangements exist to make this convenient
...
If a program reads 0 and writes 1 and 2, it can do input and output without worrying about opening files
...
Normally file descriptor 2 remains attached to the screen, so error messages can go there
...
In all cases, the file assignments are changed by the shell, not by the program
...
8
...
For both, the first argument is a file descriptor
...
The third argument is the number is the number of bytes to be transferred
...
On reading, the number of bytes returned may be less than the number requested
...
For writing, the return value is the number of bytes written; an error has occurred if this isn't equal to the number requested
...
The most common values are 1, which means one character at a time (``unbuffered''), and a number like 1024 or 4096 that corresponds to a physical block size on a peripheral device
...
Putting these facts together, we can write a simple program to copy its input to its output, the equivalent of the file copying program written for Chapter 1
...
"syscalls
...
h so we can include it in the programs of this chapter
...
The parameter BUFSIZ is also defined in syscalls
...
If the file size is not a multiple of BUFSIZ, some read will return a smaller number of bytes to be written by write; the next call to read after that will return zero
...
For example, here is a version of getchar that does unbuffered input, by reading the standard input one character at a time
...
h" /* getchar: unbuffered single character input */ int getchar(void) { char c; return (read(0, &c, 1) == 1) ? (unsigned char) c : EOF; } c must be a char, because read needs a character pointer
...
The second version of getchar does input in big chunks, and hands out the characters one at a time
...
h" 2 Chapter 8 - The UNIX System Interface Chapter 8 - The UNIX System Interface 3 /* getchar: simple buffered version */ int getchar(void) { static char buf[BUFSIZ]; static char *bufp = buf; static int n = 0; if (n == 0) { /* buffer is empty */ n = read(0, buf, sizeof buf); bufp = buf; } return (--n >= 0) ? (unsigned char) *bufp++ : EOF; } If these versions of getchar were to be compiled with
...
8
...
There are two system calls for this, open and creat [sic]
...
open returns -1 if any error occurs
...
h> on System V UNIX systems, and in
...
To open an existing file for reading, fd = open(name, O_RDONLY,0); The perms argument is always zero for the uses of open that we will discuss
...
The system call creat is provided to create new files, or to re-write old ones
...
If the file already exists, creat will truncate it to zero length, thereby discarding its previous contents; it is not an error to creat a file that already exists
...
In the UNIX file system, there are nine bits of permission information associated with a file that control read, write and execute access for the owner of the file, for the owner's group, and for all others
...
For example, 0775 specifies read, write and execute permission for the owner, and read and execute permission for the group and everyone else
...
Our version copies only one file, it does not permit the second argument to be a directory, and it invents permissions instead of copying them
...
h> #include
...
h" #define PERMS 0666 void error(char *, /* RW for owner, group, others */
...
With the stat system call, described in Section 8
...
Notice that the function error is called with variable argument lists much like printf
...
The standard library function vprintf is like printf except that the variable argument list is replaced by a single argument that has been initialized by calling the va_start macro
...
#include
...
h> /* error: print an error message and die */ void error(char *fmt,
...
Accordingly, any program that intends to process many files must be prepared to re-use file descriptors
...
Termination of a program via exit or return from the main program closes all open files
...
It corresponds to the standard library function remove
...
Rewrite the program cat from Chapter 7 using read, write, open, and close instead of their standard library equivalents
...
8
...
When necessary, however, a file can be read or written in any arbitrary order
...
Subsequent reading or writing will begin at that position
...
For example, to append to a file (the redirection >> in the UNIX shell, or "a" for fopen), seek to the end before writing: lseek(fd, 0L, 2); To get back to the beginning (``rewind''), lseek(fd, 0L, 0); Notice the 0L argument; it could also be written as (long) 0 or just as 0 if lseek is properly declared
...
For example, the following function reads any number of bytes from any arbitrary place in a file
...
"syscalls
...
The standard library function fseek is similar to lseek except that the first argument is a FILE * and the return is non-zero if an error occurred
...
5 Example - An implementation of Fopen and Getc Let us illustrate how some of these pieces fit together by showing an implementation of the standard library routines fopen and getc
...
A file pointer is a pointer to a structure that contains several pieces of information about the file: a pointer to a buffer, so the file can be read in large chunks; a count of the number of characters left in the buffer; a pointer to the next character position in the buffer; the file descriptor; and flags describing read/write mode, error status, etc
...
h>, which must be included (by #include) in any source file that uses routines from the standard input/output library
...
In the following excerpt from a typical
...
This convention is used by all standard library routines
...
(Recall that a long #define is continued with a backslash
...
The characters are returned unsigned, which ensures that all characters will be positive
...
We have also included macros for accessing the error and end-of-file status and the file descriptor
...
Most of fopen is concerned with getting the file opened and positioned at the right place, and setting the flag bits to indicate the proper state
...
#include
...
h" 6 Chapter 8 - The UNIX System Interface Chapter 8 - The UNIX System Interface #define PERMS 0666 7 /* RW for owner, group, others */ FILE *fopen(char *name, char *mode) { int fd; FILE *fp; if (*mode != 'r' && *mode != 'w' && *mode != 'a') return NULL; for (fp = _iob; fp < _iob + OPEN_MAX; fp++) if ((fp->flag & (_READ | _WRITE)) == 0) break; /* found free slot */ if (fp >= _iob + OPEN_MAX) /* no free slots */ return NULL; if (*mode == 'w') fd = creat(name, PERMS); else if (*mode == 'a') { if ((fd = open(name, O_WRONLY, 0)) == -1) fd = creat(name, PERMS); lseek(fd, 0L, 2); } else fd = open(name, O_RDONLY, 0); if (fd == -1) /* couldn't access name */ return NULL; fp->fd = fd; fp->cnt = 0; fp->base = NULL; fp->flag = (*mode == 'r') ? _READ : _WRITE; return fp; } This version of fopen does not handle all of the access mode possibilities of the standard, though adding them would not take much code
...
The first call to getc for a particular file finds a count of zero, which forces a call of _fillbuf
...
Otherwise, it tries to allocate a buffer (if reading is to be buffered)
...
Subsequent calls to _fillbuf will find a buffer allocated
...
h" /* _fillbuf: allocate and fill input buffer */ int _fillbuf(FILE *fp) { int bufsize; if ((fp->flag&(_READ|_EOF_ERR)) != _READ) return EOF; bufsize = (fp->flag & _UNBUF) ? 1 : BUFSIZ; if (fp->base == NULL) /* no buffer yet */ if ((fp->base = (char *) malloc(bufsize)) == NULL) return EOF; /* can't get buffer */ fp->ptr = fp->base; fp->cnt = read(fp->fd, fp->ptr, bufsize); if (--fp->cnt < 0) { if (fp->cnt == -1) fp->flag |= _EOF; else fp->flag |= _ERR; Chapter 8 - The UNIX System Interface 7 8 Chapter 8 - The UNIX System Interface fp->cnt = 0; return EOF; } return (unsigned char) *fp->ptr++; } The only remaining loose end is how everything gets started
...
Exercise 8-2
...
Compare code size and execution speed
...
Design and write _flushbuf, fflush, and fclose
...
The standard library function int fseek(FILE *fp, long offset, int origin) is identical to lseek except that fp is a file pointer instead of a file descriptor and return value is an int status, not a position
...
Make sure that your fseek coordinates properly with the buffering done for the other functions of the library
...
6 Example - Listing Directories A different kind of file system interaction is sometimes called for - determining information about a file, not what it contains
...
The MS-DOS dir command is analogous
...
But is is necessary to use a system call to access other information about a file, such as its size
...
What we want is provide access to the information in a relatively system-independent way, even though the implementation may be highly system-dependent
...
fsize is a special form of ls that prints the sizes of all files named in its commandline argument list
...
If there are no arguments at all, it processes the current directory
...
A directory is a file that contains a list of filenames and some indication of where they are located
...
'' The inode for a file is where all information about the file except its name is kept
...
Regrettably, the format and precise contents of a directory are not the same on all versions of the system
...
The outer level defines a structure called a Dirent and three routines opendir, readdir, and closedir to provide 8 Chapter 8 - The UNIX System Interface Chapter 8 - The UNIX System Interface 9 system-independent access to the name and inode number in a directory entry
...
Then we will show how to implement these on systems that use the same directory structure as Version 7 and System V UNIX; variants are left as exercises
...
The maximum length of a filename component is NAME_MAX, which is a system-dependent value
...
This information is collected into a file called dirent
...
#define NAME_MAX 14 /* longest filename component; */ /* system-dependent */ typedef struct { /* portable directory entry */ long ino; /* inode number */ char name[NAME_MAX+1]; /* name + '\0' terminator */ } Dirent; typedef struct { int fd; Dirent d; } DIR; /* minimal DIR: no buffering, etc
...
That is, char *name; struct stat stbuf; int stat(char *, struct stat *); stat(name, &stbuf); fills the structure stbuf with the inode information for the file name
...
h>, and typically looks like this: struct stat { dev_t ino_t short short short short dev_t off_t time_t time_t time_t }; /* inode information returned by stat */ st_dev; st_ino; st_mode; st_nlink; st_uid; st_gid; st_rdev; st_size; st_atime; st_mtime; st_ctime; /* /* /* /* /* /* /* /* /* /* /* device of inode */ inode number */ mode bits */ number of links to file */ owners user id */ owners group id */ for special files */ file size in characters */ time last accessed */ time last modified */ time originally created */ Most of these values are explained by the comment fields
...
h>, which must be included too
...
The flag definitions are also included in
...
*/ 0020000 0060000 0010000 /* character special */ /* block special */ /* regular */ Now we are ready to write the program fsize
...
If the name is a directory, however, then we have to process that directory one file at a time; it may in turn contain sub-directories, so the process is recursive
...
#include #include #include #include #include #include #include
...
h> "syscalls
...
h>
...
h> "dirent
...
"); else while (--argc > 0) fsize(*++argv); return 0; } The function fsize prints the size of the file
...
Note how the flag names S_IFMT and S_IFDIR are used to decide if the file is a directory
...
int stat(char *, struct stat *); void dirwalk(char *, void (*fcn)(char *)); /* fsize: print the name of file "name" */ void fsize(char *name) { struct stat stbuf; if (stat(name, &stbuf) == -1) { fprintf(stderr, "fsize: can't access %s\n", name); return; } if ((stbuf
...
st_size, name); } The function dirwalk is a general routine that applies a function to each file in a directory
...
Since fsize calls dirwalk on each directory, the two functions call each other recursively
...
") == 0 || strcmp(dp->name, "
...
Each directory always contains entries for itself, called "
...
"; these must be skipped, or the program will loop forever
...
The next step is to present minimal versions of opendir, readdir, and closedir for a specific system
...
h>, which looks like this: #ifndef DIRSIZ #define DIRSIZ 14 #endif struct direct { /* directory entry */ ino_t d_ino; /* inode number */ char d_name[DIRSIZ]; /* long name does not have '\0' */ }; Some versions of the system permit much longer names and have a more complicated directory structure
...
It happens to be unsigned short on the systems we use regularly, but this is not the sort of information to embed in a program; it might be different on a different system, so the typedef is better
...
h>
...
st_mode & S_IFMT) != S_IFDIR || (dp = (DIR *) malloc(sizeof(DIR))) == NULL) return NULL; dp->fd = fd; return dp; } closedir closes the directory file and frees the space: /* closedir: close directory opened by opendir */ void closedir(DIR *dp) { if (dp) { close(dp->fd); free(dp); } } Finally, readdir uses read to read each directory entry
...
Otherwise, the inode number and name are placed in a static structure and a pointer to that is returned to the user
...
#include
...
d_ino == 0) /* slot not in use */ continue; d
...
d_ino; strncpy(d
...
d_name, DIRSIZ); d
...
First, many programs are not ``system programs''; they merely use information that is maintained by the operating system
...
The second observation is that with care it is possible to create an interface to system-dependent objects that is itself relatively system-independent
...
Exercise 8-5
...
8
...
The version that we will now write is unrestricted
...
These routines illustrate some of the considerations involved in writing machine-dependent code in a relatively machine-independent way, and also show a real-life application of 12 Chapter 8 - The UNIX System Interface Chapter 8 - The UNIX System Interface 13 structures, unions and typedef
...
Since other activities in the program may also request space without calling this allocator, the space that malloc manages may not be contiguous
...
Each block contains a size, a pointer to the next block, and the space itself
...
When a request is made, the free list is scanned until a big-enough block is found
...
If the block is exactly the size requested it is unlinked from the list and returned to the user
...
If no big-enough block is found, another large chunk is obtained by the operating system and linked into the free list
...
If the block being freed is adjacent to a free block on either side, it is coalesced with it into a single bigger block, so storage does not become too fragmented
...
One problem, which we alluded to in Chapter 5, is to ensure that the storage returned by malloc is aligned properly for the objects that will be stored in it
...
On some machines, the most restrictive type is a double; on others, int or long suffices
...
'' To simplify alignment, all blocks are multiples of the header size, and the header is aligned properly
...
In malloc, the requested size in characters is rounded up to the proper number of header-sized units; the block that will be allocated contains one more unit, for the header itself, and this is the value recorded in the size field of the header
...
The user can do anything with the space requested, but if anything is written outside of the allocated space the list is likely to be scrambled
...
The variable base is used to get started
...
In any case, the free list is then searched
...
If a too-big block is found, the tail end is returned to the user; in this way the header of the original needs only to have its size adjusted
...
static Header base; /* empty list to get started */ static Header *freep = NULL; /* start of free list */ /* malloc: general-purpose storage allocator */ void *malloc(unsigned nbytes) { Header *p, *prevp; Header *moreroce(unsigned); unsigned nunits; nunits = (nbytes+sizeof(Header)-1)/sizeof(header) + 1; if ((prevp = freep) == NULL) { /* no free list yet */ base
...
ptr = freeptr = prevptr = &base; base
...
size = 0; } for (p = prevp->s
...
ptr) { if (p->s
...
size == nunits) /* exactly */ prevp->s
...
ptr; else { /* allocate tail end */ p->s
...
size; 14 Chapter 8 - The UNIX System Interface Chapter 8 - The UNIX System Interface 15 p->s
...
The details of how it does this vary from system to system
...
we don't want to do that on every call to malloc, so morecore requests al least NALLOC units; this larger block will be chopped up as needed
...
The UNIX system call sbrk(n) returns a pointer to n more bytes of storage
...
The -1 must be cast to char * so it can be compared with the return value
...
There is still one assumption, however, that pointers to different blocks returned by sbrk can be meaningfully compared
...
Thus this version of malloc is portable only among machines for which general pointer comparison is meaningful
...
com) Back to Chapter 8 -- Index -- Appendix B Chapter 8 - The UNIX System Interface 15 Appendix A - Reference Manual A
...
159-1989
...
For the most part, this document follows the broad outline of the standard, which in turn follows that of the first edition of this book, although the organization differs in detail
...
Throughout this manual, commentary material is indented and written in smaller type, as this is
...
A
...
It is translated in several phases, which are described in Par
...
12
...
When the preprocessing of Par
...
12 is complete, the program has been reduced to a sequence of tokens
...
2
...
Blanks, horizontal and vertical tabs, newlines, formfeeds and comments as described below (collectively, ``white space'') are ignored except as they separate tokens
...
If the input stream has been separated into tokens up to a given character, the next token is the longest string of characters that could constitute a token
...
2
...
Comments do not nest, and they do not occur within a string or character literals
...
2
...
The first character must be a letter; the underscore _ counts as a letter
...
Identifiers may have any length, and for internal identifiers, at least the first 31 characters are significant; some implementations may take more characters significant
...
A
...
2)
...
A
...
4 Keywords The following identifiers are reserved for the use as keywords, and may not be used otherwise: Appendix A - Reference Manual 1 2 Appendix A - Reference Manual auto break case char const continue default do double else enum extern float for goto if int long register return short signed sizeof static struct switch typedef union unsigned void volatile while Some implementations also reserve the words fortran and asm
...
A
...
5 Constants There are several kinds of constants
...
A
...
2 discusses the basic types: constant: integer-constant character-constant floating-constant enumeration-constant A
...
5
...
Octal constants do not contain the digits 8 or 9
...
The hexadecimal digits include a or A through f or F with values 10 through 15
...
It may also be suffixed by the letter l or L to specify that it is long
...
(See Par
...
4 for a discussion of types)
...
If it is unsuffixed, octal or hexadecimal, it has the first possible of these types: int, unsigned int, long int, unsigned long int
...
If it is suffixed by l or L, then long int, unsigned long int
...
The elaboration of the types of integer constants goes considerably beyond the first edition, which merely caused large integer constants to be long
...
A
...
5
...
The value of a character constant with only one character is the numeric value of the character in the machine's character set at execution time
...
Character constants do not contain the ' character or newlines; in order to represent them, and certain other characters, the following escape sequences may be used: 2 newline NL (LF) \n horizontal tab HT \t backslash \ question ? mark \\ \? Appendix A - Reference Manual Appendix A - Reference Manual 3 vertical tab VT \v backspace BS \b carriage return CR \r formfeed \f FF single quote double quote octal number hex number ' \' " \" ooo \ooo hh \xhh audible alert BEL \a The escape \ooo consists of the backslash followed by 1, 2, or 3 octal digits, which are taken to specify the value of the desired character
...
The escape \xhh consists of the backslash, followed by x, followed by hexadecimal digits, which are taken to specify the value of the desired character
...
For either octal or hexadecimal escape characters, if the implementation treats the char type as signed, the value is sign-extended as if cast to char type
...
In some implementations, there is an extended set of characters that cannot be represented in the char type
...
Such a constant has type wchar_t, an integral type defined in the standard header
...
As with ordinary character constants, hexadecimal escapes may be used; the effect is undefined if the specified value exceeds that representable with wchar_t
...
Extended characters are also new
...
A
...
5
...
The integer and fraction parts both consist of a sequence of digits
...
The type is determined by the suffix; F or f makes it float, L or l makes it long double, otherwise it is double
...
5
...
A
...
4) are constants of type int
...
2
...
A string has type ``array of characters'' and storage class static (see Par
...
3 below) and is initialized with the given characters
...
Adjacent string literals are concatenated into a single string
...
String literals do not contain newline or double-quote characters; in order to represent them, the same escape sequences as for character constants are available
...
Wide-character string literals have type ``array of wchar_t
...
The specification that string literals need not be distinct, and the prohibition against modifying them, are new in the ANSI standard, as is the concatenation of adjacent string literals
...
A
...
Alternative categories are usually listed on separate lines; in a few cases, a long set of narrow alternatives is presented on one line, marked by the phrase ``one of
...
The syntax is summarized in Par
...
13
...
A
...
An object, sometimes called a variable, is a location in storage, and its interpretation depends on two main attributes: its storage class and its type
...
A name also has a scope, which is the region of the program in which it is known, and a linkage, which determines whether the same name in another scope refers to the same object or function
...
A
...
A
...
1 Storage Class There are two storage classes: automatic and static
...
Automatic objects are local to a block (Par
...
3), and are discarded on exit from the block
...
Objects declared register are automatic, and are (if possible) stored in fast registers of the machine
...
Within a block, including a block that provides the code for a function, static objects are declared with the keyword static
...
They may be made local to a particular translation unit by use of the static keyword; this gives them internal linkage
...
A
...
2 Basic Types There are several fundamental types
...
h> described in Appendix B defines the largest and smallest values of each type in the local implementation
...
Objects declared as characters (char) are large enough to store any member of the execution character set
...
Other quantities may be stored into char variables, but the available range of values, and especially whether the value is signed, is implementation-dependent
...
unsigned char type does not appear in the first edition of this book, but is in common use
...
Besides the char types, up to three sizes of integer, declared short int, int, and long int, are available
...
Longer integers provide at least as much storage as shorter ones, but the implementation may make plain integers equivalent to either short integers, or long integers
...
Unsigned integers, declared using the keyword unsigned, obey the laws of arithmetic modulo 2n where n is the number of bits in the representation, and thus arithmetic on unsigned quantities can never overflow
...
Any of single precision floating point (float), double precision floating point (double), and extra precision floating point (long double) may be synonymous, but the ones later in the list are at least as precise as those before
...
The first edition made long float equivalent to double; the locution has been withdrawn
...
A
...
4)
...
Because objects of these types can be interpreted as numbers, they will be referred to as arithmetic types
...
The types float, double, and long double will be called floating types
...
It is used as the type returned by functions that generate no value
...
4
...
In general these methods of constructing objects can be applied recursively
...
4
...
Declaring an object const announces that its value will not be changed; declaring it volatile announces that it has special properties relevant to optimization
...
Qualifiers are discussed in Par
...
8
...
Appendix A - Reference Manual 5 6 Appendix A - Reference Manual A
...
An obvious example of an lvalue expression is an identifier with suitable type and storage class
...
The name ``lvalue'' comes from the assignment expression E1 = E2 in which the left operand E1 must be an lvalue expression
...
A
...
This section explains the result to be expected from such conversions
...
6
...
A
...
1 Integral Promotion A character, a short integer, or an integer bit-field, all either signed or not, or an object of enumeration type, may be used in an expression wherever an integer may be used
...
This process is called integral promotion
...
6
...
In a two's complement representation, this is equivalent to left-truncation if the bit pattern of the unsigned type is narrower, and to zero-filling unsigned values and sign-extending signed values if the unsigned type is wider
...
A
...
3 Integer and Floating When a value of floating type is converted to integral type, the fractional part is discarded; if the resulting value cannot be represented in the integral type, the behavior is undefined
...
When a value of integral type is converted to floating, and the value is in the representable range but is not exactly representable, then the result may be either the next higher or next lower representable value
...
A
...
4 Floating Types When a less precise floating value is converted to an equally or more precise floating type, the value is unchanged
...
If the result is out of range, the behavior is undefined
...
6
...
The effect is to bring operands into a common type, which is also the type of the result
...
• First, if either operand is long double, the other is converted to long double
...
• Otherwise, if either operand is float, the other is converted to float
...
• Otherwise, if one operand is long int and the other is unsigned int, the effect depends on whether a long int can represent all values of an unsigned int; if so, the unsigned int operand is converted to long int; if not, both are converted to unsigned long int
...
• Otherwise, if either operand is unsigned int, the other is converted to unsigned int
...
There are two changes here
...
Second, shorter unsigned types, when combined with a larger signed type, do not propagate the unsigned property to the result type; in the first edition, the unsigned always dominated
...
Unexpected results may still occur when an unsigned expression is compared to a signed expression of the same size
...
6
...
A
...
7)
...
A
...
7)
...
This produces a null pointer that is equal to another null pointer of the same type, but unequal to any pointer to a function or object
...
They must be specified by an explicit type-conversion operator, or cast (Pars
...
7
...
8
...
A pointer may be converted to an integral type large enough to hold it; the required size is implementation-dependent
...
A pointer to one type may be converted to a pointer to another type
...
It is guaranteed that a pointer to an object may be converted to a pointer to an object whose type requires less or equally strict storage alignment and back again without change; the notion of ``alignment'' is implementation-dependent, but objects of the char types have least strict alignment requirements
...
A
...
8, a pointer may also be converted to type void * and back again without change
...
A
...
4, A
...
2) of the object type to which the pointer refers
...
If qualifiers are removed, operations on the underlying object remain subject to the qualifiers in its actual declaration
...
Calling the function specified by the converted pointer is implementation-dependent; however, if the converted pointer is reconverted to its original type, the result is identical to the original pointer
...
6
...
Because a void expression denotes a nonexistent value, such an expression may be used only where the value is not required, for example as an expression statement (Par
...
9
...
A
...
18)
...
For example, a void cast documents the discarding of the value of a function call used as an expression statement
...
A
...
8 Pointers to Void Any pointer to an object may be converted to type void * without loss of information
...
Unlike the pointer-to-pointer conversions discussed in Par
...
6
...
This interpretation of void * pointers is new; previously, char * pointers played the role of generic pointer
...
A
...
Thus, for example, the expressions referred to as the operands of + (Par
...
7
...
A
...
1-A
...
6
...
Left- or right-associativity is specified in each subsection for the operators discussed therein
...
13 incorporates the precedence and associativity of the operators
...
That is, unless the definition of the operator guarantees that its operands are evaluated in a particular order, the implementation is free to evaluate operands in any order, or even to interleave their evaluation
...
This rule revokes the previous freedom to reorder expressions with operators that are mathematically commutative and associative, but can fail to be computationally associative
...
The handling of overflow, divide check, and other exceptions in expression evaluation is not defined by the language
...
Treatment of division by 0, and all floating-point exceptions, varies among implementations; sometimes it is adjustable by a non-standard library function
...
7
...
'' This 8 Appendix A - Reference Manual Appendix A - Reference Manual 9 conversion does not take place if the expression is in the operand of the unary & operator, or of ++, --, sizeof, or as the left operand of an assignment operator or the
...
Similarly, an expression of type ``function returning T,'' except when used as the operand of the & operator, is converted to ``pointer to function returning T
...
7
...
primary-expression identifier constant string (expression) An identifier is a primary expression, provided it has been suitably declared as discussed below
...
An identifier is an lvalue if it refers to an object (Par
...
5) and if its type is arithmetic, structure, union, or pointer
...
Its type depends on its form as discussed in Par
...
2
...
A string literal is a primary expression
...
A
...
1, this is usually modified to ``pointer to char'' (wchar_t) and the result is a pointer to the first character in the string
...
A
...
7
...
The precedence of parentheses does not affect whether the expression is an lvalue
...
7
...
postfix-expression: primary-expression postfix-expression[expression] postfix-expression(argument-expression-listopt) postfix-expression
...
7
...
1 Array References A postfix expression followed by an expression in square brackets is a postfix expression denoting a subscripted array reference
...
The expression E1[E2] is identical (by definition) to *((E1)+(E2))
...
A
...
6
...
Appendix A - Reference Manual 9 10 Appendix A - Reference Manual A
...
3
...
A7
...
If the postfix expression consists of an identifier for which no declaration exists in the current scope, the identifier is implicitly declared as if the declaration extern int identifier(); had been given in the innermost block containing the function call
...
A7
...
In the first edition, the type was restricted to ``function,'' and an explicit * operator was required to call through pointers to functions
...
The older syntax is still usable
...
The terms ``actual argument (parameter)'' and ``formal argument (parameter)'' respectively are sometimes used for the same distinction
...
A function may change the values of its parameter objects, which are copies of the argument expressions, but these changes cannot affect the values of the arguments
...
There are two styles in which functions may be declared
...
In the old style, parameter types are not specified
...
A
...
6
...
10
...
If the function declaration in scope for a call is old-style, then default argument promotion is applied to each argument as follows: integral promotion (Par
...
6
...
The effect of the call is undefined if the number of arguments disagrees with the number of parameters in the definition of the function, or if the type of an argument after promotion disagrees with that of the corresponding parameter
...
If it is old-style, then the comparison is between the promoted type of the arguments of the call, and the promoted type of the parameter, if the definition is new-style, the promoted type of the argument must be that of the parameter itself, without promotion
...
The number of arguments must be the same as the number of explicitly described parameters, unless the declaration's parameter list ends with the ellipsis notation (,
...
If the definition of the function is old-style, then the type of each parameter in the definition, after the definition parameter's type has undergone argument promotion
...
Mixtures are to be avoided if possible
...
However, the arguments and the function designator are completely evaluated, including all side effects, before the function is entered
...
10 Appendix A - Reference Manual Appendix A - Reference Manual 11 A
...
3
...
The first operand expression must be a structure or a union, and the identifier must name a member of the structure or union
...
The expression is an lvalue if the first expression is an lvalue, and if the type of the second expression is not an array type
...
The first operand expression must be a pointer to a structure or union, and the identifier must name a member of the structure or union
...
Thus the expression E1->MOS is the same as (*E1)
...
Structures and unions are discussed in Par
...
8
...
In the first edition of this book, it was already the rule that a member name in such an expression had to belong to the structure or union mentioned in the postfix expression; however, a note admitted that this rule was not firmly enforced
...
A
...
3
...
The value of the expression is the value of the operand
...
The operand must be an lvalue; see the discussion of additive operators (Par
...
7
...
A
...
17) for further constraints on the operand and details of the operation
...
A
...
4 Unary Operators Expressions with unary operators group right-to-left
...
7
...
1 Prefix Incrementation Operators A unary expression followed by a ++ or -- operator is a unary expression
...
The value of the expression is the value after the incrementation (decrementation)
...
A
...
7) and assignment (Par
...
7
...
The result is not an lvalue
...
7
...
2 Address Operator The unary operator & takes the address of its operand
...
The result is a pointer to the object or function referred to by the lvalue
...
'' Appendix A - Reference Manual 11 12 Appendix A - Reference Manual A
...
4
...
It is an lvalue if the operand is a pointer to an object of arithmetic, structure, union, or pointer type
...
A
...
4
...
An integral operand undergoes integral promotion
...
The unary + is new with the ANSI standard
...
A
...
4
...
An integral operand undergoes integral promotion
...
The type of the result is the type of the promoted operand
...
7
...
6 One's Complement Operator The operand of the ~ operator must have integral type, and the result is the one's complement of its operand
...
If the operand is unsigned, the result is computed by subtracting the value from the largest value of the promoted type
...
The type of the result is the type of the promoted operand
...
7
...
7 Logical Negation Operator The operand of the ! operator must have arithmetic type or be a pointer, and the result is 1 if the value of its operand compares equal to 0, and 0 otherwise
...
A
...
4
...
The operand is either an expression, which is not evaluated, or a parenthesized type name
...
When applied to a structure or union, the result is the number of bytes in the object, including any padding required to make the object tile an array: the size of an array of n elements is n times the size of one element
...
The result is an unsigned integral constant; the particular type is implementation-defined
...
h> (See appendix B) defines this type as size_t
...
7
...
cast-expression: unary expression (type-name) cast-expression This construction is called a cast
...
A
...
8
...
A
...
An expression with a cast is not an lvalue
...
7
...
multiplicative-expression: multiplicative-expression * cast-expression multiplicative-expression / cast-expression multiplicative-expression % cast-expression The operands of * and / must have arithmetic type; the operands of % must have integral type
...
The binary * operator denotes multiplication
...
Otherwise, it is always true that (a/b)*b + a%b is equal to a
...
A
...
7 Additive Operators The additive operators + and - group left-to-right
...
There are some additional type possibilities for each operator
...
A pointer to an object in an array and a value of any integral type may be added
...
The sum is a pointer of the same type as the original pointer, and points to another object in the same array, appropriately offset from the original object
...
If the sum pointer points outside the bounds of the array, except at the first location beyond the high end, the result is undefined
...
It legitimizes a common idiom for looping over the elements of an array
...
A value of any integral type may be subtracted from a pointer, and then the same conversions and conditions as for addition apply
...
The type of the result is defined as ptrdiff_t in the standard header
...
The value is undefined unless the pointers point to objects within the same array; however, if P points to the last member of an array, then (P+1)-P has value 1
...
7
...
For both operators, each operand must be integral, and is subject to integral the promotions
...
The result is undefined if the right operand is negative, or greater than or equal to the number of bits in the left expression's type
...
The value of E1>>E2 is E1 right-shifted E2 bit positions
...
A
...
9 Relational Operators The relational operators group left-to-right, but this fact is not useful; a evaluates to either 0 or 1
...
The type of the result is int
...
Pointers to objects of the same type (ignoring any qualifiers) may be compared; the result depends on the relative locations in the address space of the pointed-to objects
...
If P points to the last member of an array, then P+1 compares higher than P, even though P+1 points outside the array
...
These rules slightly liberalize the restrictions stated in the first edition, by permitting comparison of pointers to different members of a structure or union
...
A
...
10 Equality Operators equality-expression: relational-expression equality-expression == relational-expression equality-expression != relational-expression The == (equal to) and the != (not equal to) operators are analogous to the relational operators except for their lower precedence
...
) The equality operators follow the same rules as the relational operators, but permit additional possibilities: a pointer may be compared to a constant integral expression with value 0, or to a pointer to void
...
A
...
6
...
7
...
The operator applies only to integral operands
...
7
...
The operator applies only to integral operands
...
7
...
The operator applies only to integral operands
...
7
...
It returns 1 if both its operands compare unequal to zero, 0 otherwise
...
Otherwise, the right operand is evaluated, and if it is equal to 0, the expression's value is 0, otherwise 1
...
The result is int
...
7
...
It returns 1 if either of its operands compare unequal to zero, and 0 otherwise
...
Otherwise, the right operand is evaluated, and if it is unequal to 0, the expression's value is 1, otherwise 0
...
The result is int
...
7
...
Only one of the second and third operands is evaluated
...
If both are void, or structures or unions of the same type, or pointers to objects of the same type, the result has the common type
...
If one is a pointer to void and the other is another pointer, the other pointer is converted to a pointer to void, and that is the type of the result
...
A
...
2) in the type to which the pointer points are insignificant, but the result type inherits qualifiers from both arms of the conditional
...
7
...
assignment-expression: conditional-expression unary-expression assignment-operator assignment-expression assignment-operator: one of = *= /= %= += -= <<= >>= &= ^= |= All require an lvalue as left operand, and the lvalue must be modifiable: it must not be an array, and must not have an incomplete type, or be a function
...
The type of an assignment expression is that of its left operand, and the value is the value stored in the left operand after the assignment has taken place
...
One of the following must be true: both operands have arithmetic type, in which case the right operand is converted to the type of the left by the assignment; or both operands are structures or unions of the same type; or one operand is a pointer and the other is a pointer to void, or the left operand is a pointer and the right operand is a constant expression with value 0; or both operands are pointers to functions or objects whose types are the same except for the possible absence of const or volatile in the right operand
...
A
...
18 Comma Operator expression: assignment-expression expression , assignment-expression 16 Appendix A - Reference Manual Appendix A - Reference Manual 17 A pair of expressions separated by a comma is evaluated left-to-right, and the value of the left expression is discarded
...
All side effects from the evaluation of the left-operand are completed before beginning the evaluation of the right operand
...
A
...
3
...
A
...
7), the required syntactic unit is an assignment expression, so the comma operator appears only in a parenthetical grouping, for example, f(a, (t=3, t+2), c) has three arguments, the second of which has the value 5
...
7
...
Constant expressions may not contain assignments, increment or decrement operators, function calls, or comma operators; except in an operand of sizeof
...
This necessarily rules out arrays, indirection, address-of, and structure member operations
...
) More latitude is permitted for the constant expressions of initializers; the operands may be any type of constant, and the unary & operator may be applied to external or static objects, and to external and static arrays subscripted with a constant expression
...
Initializers must evaluate either to a constant or to the address of a previously declared external or static object plus or minus a constant
...
See Par
...
12
...
A
...
Declarations that reserve storage are called definitions
...
declaration-specifiers: storage-class-specifier declaration-specifiersopt type-specifier declaration-specifiersopt type-qualifier declaration-specifiersopt Appendix A - Reference Manual 17 18 Appendix A - Reference Manual init-declarator-list: init-declarator init-declarator-list , init-declarator init-declarator: declarator declarator = initializer Declarators will be discussed later (Par
...
8
...
A declaration must have at least one declarator, or its type specifier must declare a structure tag, a union tag, or the members of an enumeration; empty declarations are not permitted
...
8
...
A
...
4
...
Such declarations also serve as definitions and cause storage to be reserved
...
Only a few objects are actually placed into registers, and only certain types are eligible; the restrictions are implementation-dependent
...
The rule that it is illegal to calculate the address of an object declared register, but actually taken to be auto, is new
...
Inside a function, this specifier causes storage to be allocated, and serves as a definition; for its effect outside a function, see Par
...
11
...
A declaration with extern, used inside a function, specifies that the storage for the declared objects is defined elsewhere; for its effects outside a function, see Par
...
11
...
The typedef specifier does not reserve storage and is called a storage class specifier only for syntactic convenience; it is discussed in Par
...
8
...
At most one storage class specifier may be given in a declaration
...
See Pars
...
10-A
...
A
...
2 Type Specifiers The type-specifiers are 18 Appendix A - Reference Manual Appendix A - Reference Manual 19 type specifier: void char short int long float double signed unsigned struct-or-union-specifier enum-specifier typedef-name At most one of the words long or short may be specified together with int; the meaning is the same if int is not mentioned
...
At most one of signed or unsigned may be specified together with int or any of its short or long varieties, or with char
...
The signed specifier is useful for forcing char objects to carry a sign; it is permissible but redundant with other integral types
...
If the type-specifier is missing from a declaration, it is taken to be int
...
type-qualifier: const volatile Type qualifiers may appear with any type specifier
...
There are no implementation-dependent semantics for volatile objects
...
The purpose of const is to announce objects that may be placed in read-only memory, and perhaps to increase opportunities for optimization
...
For example, for a machine with memory-mapped input/output, a pointer to a device register might be declared as a pointer to volatile, in order to prevent the compiler from removing apparently redundant references through the pointer
...
A
...
3 Structure and Union Declarations A structure is an object consisting of a sequence of named members of various types
...
Structure and union specifiers have the same form
...
A structure member may also consist of a specified number of bits
...
struct-declarator: declarator declaratoropt : constant-expression A type specifier of the form struct-or-union identifier { struct-declaration-list } declares the identifier to be the tag of the structure or union specified by the list
...
Objects with an incomplete structure or union type may be mentioned in contexts where their size is not needed, for example in declarations (not definitions), for specifying a pointer, or for creating a typedef, but not otherwise
...
Even in specifiers with a list, the structure or union type being declared is incomplete within the list, and becomes complete only at the } terminating the specifier
...
Therefore, it is impossible to declare a structure or union containing an instance of itself
...
A very special rule applies to declarations of the form struct-or-union identifier; that declare a structure or union, but have no declaration list and no declarators
...
A
...
1), this declaration makes the identifier the tag of a new, incompletely-typed structure or union in the current scope
...
It is intended to deal with mutually-recursive structures declared in an inner scope, but whose tags might already be declared in the outer scope
...
20 Appendix A - Reference Manual Appendix A - Reference Manual 21 The names of members and tags do not conflict with each other or with ordinary variables
...
In the first edition of this book, the names of structure and union members were not associated with their parent
...
A non-field member of a structure or union may have any object type
...
Adjacent field members of structures are packed into implementation-dependent storage units in an implementation-dependent direction
...
An unnamed field with width 0 forces this padding, so that the next field will begin at the edge of the next allocation unit
...
It is advisable to read the language rules for storing bit-fields as ``implementation-dependent'' without qualification
...
In the second case, it is necessary to understand the rules of the local implementation
...
A non-field member of a structure is aligned at an addressing boundary depending on its type; therefore, there may be unnamed holes in a structure
...
A union may be thought of as a structure all of whose members begin at offset 0 and whose size is sufficient to contain any of its members
...
If a pointr to a union is cast to the type of a pointer to a member, the result refers to that member
...
Once this declaration has bene given, the declaration struct tnode s, *sp; declares s to be a structure of the given sort, and sp to be a pointer to a structure of the given sort
...
left refers to the left subtree pointer of the structure s, and s
...
In general, a member of a union may not be inspected unless the value of the union has been assigned using the same member
...
For example, the following is a legal fragment: union { struct { int type; } n; struct { int type; int intnode; } ni; struct { int type; float floatnode; } nf; } u;
...
nf
...
nf
...
14;
...
n
...
sin(u
...
floatnode)
...
8
...
The form of an enumeration specifier borrows from that of structures and unions
...
If no enumerations with = appear, then the values of the corresponding constants begin at 0 and increase by 1 as the declaration is read from left to right
...
Enumerator names in the same scope must all be distinct from each other and from ordinary variable names, but the values need not be distinct
...
The rules for enum-specifiers with and without tags and lists are the same as those for structure or union specifiers, except that incomplete enumeration types do not exist; the tag of an enum-specifier without an enumerator list must refer to an in-scope specifier with a list
...
A
...
5 Declarators Declarators have the syntax: declarator: pointeropt direct-declarator direct-declarator: identifier (declarator) direct-declarator [ constant-expressionopt ] direct-declarator ( parameter-type-list ) direct-declarator ( identifier-listopt ) pointer: * type-qualifier-listopt * type-qualifier-listopt pointer type-qualifier-list: type-qualifier type-qualifier-list type-qualifier The structure of declarators resembles that of indirection, function, and array expressions; the grouping is the same
...
8
...
Each declarator declares a unique main identifier, the one that appears as the first alternative of the production for direct-declarator
...
A declarator is read as an assertion that when its identifier appears in an expression of the same form as the declarator, it yields an object of the specified type
...
A
...
2) and a particular declarator, a declaration has the form ``T D,'' where T is a type and D is a declarator
...
In a declaration T D where D is an unadored identifier, the type of the identifier is T
...
The parentheses do not alter the type, but may change the binding of complex declarators
...
8
...
1 Pointer Declarators In a declaration T D where D has the form * type-qualifier-listopt D1 Appendix A - Reference Manual 23 24 Appendix A - Reference Manual and the type of the identifier in the declaration T D1 is ``type-modifier T,'' the type of the identifier of D is ``type-modifier type-qualifier-list pointer to T
...
For example, consider the declaration int *ap[]; Here, ap[] plays the role of D1; a declaration ``int ap[]'' (below) would give ap the type ``array of int,'' the type-qualifier list is empty, and the type-modifier is ``array of
...
'' As other examples, the declarations int i, *pi, *const cpi = i const int ci = 3, *pci; declare an integer i and a pointer to an integer pi
...
The integer ci is constant, and may not be changed (though it may be initialized, as here
...
A
...
6
...
'' If the constant-expression is present, it must have integral type, and value greater than 0
...
An array may be constructed from an arithmetic type, from a pointer, from a structure or union, or from another array (to generate a multi-dimensional array)
...
This implies that for a multi-dimensional array, only the first dimension may be missing
...
A
...
2), or by initializing it (Par
...
8
...
For example, float fa[17], *afp[17]; declares an array of float numbers and an array of pointers to float numbers
...
In complete detail, x3d is an array of three items: each item is an array of five arrays; each of the latter arrays is an array of seven integers
...
The first three have type ``array,'', the last has type int
...
The array subscripting operation is defined so that E1[E2] is identical to *(E1+E2)
...
Because of the conversion rules that apply to + and to arrays (Pars
...
6, A
...
1, A
...
7), if E1 is an array and E2 an integer, then E1[E2] refers to the E2-th member of E1
...
The first subexpression x3d[i][j] is converted by Par
...
7
...
A
...
7, the addition involves multiplication by the size of an integer
...
A
...
6
...
'' The syntax of the parameters is parameter-type-list: parameter-list parameter-list ,
...
As a special case, the declarator for a new-style function with no parameters has a parameter list consisting soley of the keyword void
...
'', then the function may accept more arguments than the number of parameters explicitly described, see Par
...
7
...
2
...
A
...
1
...
Similarly, if the declarators in the parameter declarations contain identifiers and the function declarator does not head a function definition, the identifiers go out of scope immediately
...
A
...
8
...
'' The parameters (if present) have the form identifier-list: identifier identifier-list , identifier In the old-style declarator, the identifier list must be absent unless the declarator is used in the head of a function definition (Par
...
10
...
No information about the types of the parameters is supplied by the Appendix A - Reference Manual 25 26 Appendix A - Reference Manual declaration
...
In none of these are the parameter types specified; they are old-style
...
The parameter names are effectively comments
...
Function declarators with parameter prototypes are, by far, the most important language change introduced by the ANSI standard
...
Some syntactic ugliness was required for the sake of compatibility, namely void as an explicit marker of new-style functions without parameters
...
'' for variadic functions is also new, and, together with the macros in the standard header
...
These notations were adapted from the C++ language
...
8
...
The initializer is preceded by =, and is either an expression, or a list of initializers nested in braces
...
initializer: assignment-expression { initializer-list } { initializer-list , } initializer-list: initializer initializer-list , initializer All the expressions in the initializer for a static object or array must be constant expressions as described in Par
...
7
...
The expressions in the initializer for an auto or register object or array must likewise be constant expressions if the initializer is a brace-enclosed list
...
The first edition did not countenance initialization of automatic structures, unions, or arrays
...
A static object not explicitly initialized is initialized as if it (or its members) were assigned the constant 0
...
26 Appendix A - Reference Manual Appendix A - Reference Manual 27 The initializer for a pointer or an object of arithmetic type is a single expression, perhaps in braces
...
The initializer for a structure is either an expression of the same type, or a brace-enclosed list of initializers for its members in order
...
If there are fewer initializers in the list than members of the structure, the trailing members are initialized with 0
...
Unnamed bit-field members are ignored,and are not initialized
...
If the array has unknown size, the number of initializers determines the size of the array, and its type becomes complete
...
As a special case, a character array may be initialized by a string literal; successive characters of the string initialize successive members of the array
...
A
...
6) may initialize an array of type wchar_t
...
The initializer for a union is either a single expression of the same type, or a brace-enclosed initializer for the first member of the union
...
The ``first-member'' rule is clumsy, but is hard to generalize without new syntax
...
An aggregate is a structure or array
...
Braces may be elided in the initialization as follows: if the initializer for an aggregate's member that itself is an aggregate begins with a left brace, then the succeding comma-separated list of initializers initializes the members of the subaggregate; it is erroneous for there to be more initializers than members
...
For example, int x[] = { 1, 3, 5 }; declares and initializes x as a 1-dimensional array with three members, since no size was specified and there are three initializers
...
Likewise the next two lines initialize y[1] and y[2]
...
Precisely the same effect could have been achieved by float y[4][3] = { 1, 3, 5, 2, 4, 6, 3, 5, 7 }; Appendix A - Reference Manual 27 28 Appendix A - Reference Manual The initializer for y begins with a left brace, but that for y[0] does not; therefore three elements from the list are used
...
Also, float y[4][3] = { { 1 }, { 2 }, { 3 }, { 4 } }; initializes the first column of y (regarded as a two-dimensional array) and leaves the rest 0
...
A
...
8 Type names In several contexts (to specify type conversions explicitly with a cast, to declare parameter types in function declarators, and as argument of sizeof) it is necessary to supply the name of a data type
...
type-name: specifier-qualifier-list abstract-declaratoropt abstract-declarator: pointer pointeropt direct-abstract-declarator direct-abstract-declarator: ( abstract-declarator ) direct-abstract-declaratoropt [constant-expressionopt] direct-abstract-declaratoropt (parameter-type-listopt) It is possible to identify uniquely the location in the abstract-declarator where the identifier would appear if the construction were a declarator in a declaration
...
For example, int int int int int int * *[3] (*)[] *() (*[])(void) name respectively the types ``integer,'' ``pointer to integer,'' ``array of 3 pointers to integers,'' ``pointer to an unspecified number of integers,'' ``function of unspecified parameters returning pointer to integer,'' and ``array, of unspecified size, of pointers to functions with no parameters each returning an integer
...
8
...
These identifiers are called typedef names
...
A
...
6)
...
For example, after typedef long Blockno, *Blockptr; typedef struct { double r, theta; } Complex; the constructions Blockno b; extern Blockptr bp; Complex z, *zp; are legal declarations
...
typedef does not introduce new types, only synonyms for types that could be specified in another way
...
Typedef names may be redeclared in an inner scope, but a non-empty set of type specifiers must be given
...
A
...
10 Type Equivalence Two type specifier lists are equivalent if they contain the same set of type specifiers, taking into account that some specifiers can be implied by others (for example, long alone implies long int)
...
Two types are the same if their abstract declarators (Par
...
8
...
Array sizes and function parameter types are significant
...
9 Statements Except as described, statements are executed in sequence
...
They fall into several groups
...
9
...
labeled-statement: identifier : statement case constant-expression : statement default : statement A label consisting of an identifier declares the identifier
...
The scope of the identifier is the current function
...
See Par
...
11
...
Case labels and default labels are used with the switch statement (Par
...
9
...
The constant expression of case must have integral type
...
A
...
2 Expression Statement Most statements are expression statements, which have the form expression-statement: expressionopt; Most expression statements are assignments or function calls
...
If the expression is missing, the construction is called a null statement; it is often used to supply an empty body to an iteration statement to place a label
...
9
...
The body of a function definition is a compound statement
...
A
...
1), after which it resumes its force
...
These rules apply to identifiers in the same name space (Par
...
11); identifiers in different name spaces are treated as distinct
...
If a jump into the block is executed, these initializations are not performed
...
A
...
4 Selection Statements Selection statements choose one of several flows of control
...
In the second form, the second substatement is executed if the expression is 0
...
The switch statement causes control to be transferred to one of several statements depending on the value of an expression, which must have integral type
...
Any statement within the substatement may be labeled with one or more case labels (Par
...
9
...
The controlling expression undergoes integral promotion (Par
...
6
...
No two of these case constants associated with the same switch may have the same value after conversion
...
Switches may be nested; a case or default label is associated with the smallest switch that contains it
...
If one of the case constants is equal to the value of the expression, control passes to the statement of the matched case label
...
If no case matches, and if there is no default, then none of the substatements of the swtich is executed
...
A
...
5 Iteration Statements Iteration statements specify looping
...
With while, the test, including all side effects from the expression, occurs before each execution of the statement; with do, the test follows each iteration
...
There is no restriction on its type
...
The third expression is evaluated after each iteration, and thus specifies a re-initialization for the loop
...
Side-effects from each expression are completed immediately after its evaluation
...
A missing second expression makes the implied test equivalent to testing a non-zero element
...
9
...
jump-statement: goto identifier; continue; break; return expressionopt; In the goto statement, the identifier must be a label (Par
...
9
...
Control transfers to the labeled statement
...
It causes control to pass to the loop-continuation portion of the smallest enclosing such statement
...
) {
...
contin: ; } while (
...
) {
...
A break statement may appear only in an iteration statement or a switch statement, and terminates execution of the smallest enclosing such statement; control passes to the statement following the terminated statement
...
When return is followed by an expression, the value is returned to the caller of the function
...
Flowing off the end of a function is equivalent to a return with no expression
...
A
...
32 Appendix A - Reference Manual Appendix A - Reference Manual 33 translation-unit: external-declaration translation-unit external-declaration external-declaration: function-definition declaration The scope of external declarations persists to the end of the translation unit in which they are declared, just as the effect of declarations within the blocks persists to the end of the block
...
A
...
1 Function Definitions Function definitions have the form function-definition: declaration-specifiersopt declarator declaration-listopt compound-statement The only storage-class specifiers allowed among the declaration specifiers are extern or static; see Par
...
11
...
A function may return an arithmetic type, a structure, a union, a pointer, or void, but not a function or an array
...
A
...
6
...
direct-declarator ( parameter-type-list ) direct-declarator ( identifier-listopt ) where the direct-declarator is an identifier or a parenthesized identifier
...
In the first form, the definition is a new-style function, and its parameters, together with their types, are declared in its parameter type list; the declaration-list following the function's declarator must be absent
...
If the parameter type list ends with ``,
...
h> and described in Appendix B must be used to refer to the extra arguments
...
In the second form, the definition is old-style: the identifier list names the parameters, while the declaration list attributes types to them
...
The declaration list must declare only parameters named in the list, initialization is not permitted, and the only storage-class specifier possible is register
...
If a parameter is declared to have type ``array of type,'' the declaration is adjusted to read ``pointer to type;'' similarly, if a parameter is declared to have type ``function returning type,'' the declaration is adjusted to read ``pointer to function returning type
...
A
...
3
...
New-style function definitions are new with the ANSI standard
...
The difference Appendix A - Reference Manual 33 34 Appendix A - Reference Manual becomes noticable when a pointer to a parameter is generated within a function
...
} is the block giving the code for the function
...
*/ } where now int max(a, b, c) is the declarator, and int a, b, c; is the declaration list for the parameters
...
10
...
The term ``external'' refers to their location outside functions, and is not directly connected with the extern keyword; the storage class for an externally-declared object may be left empty, or it may be specified as extern or static
...
Two declarations for an object or function are deemed to agree in type under the rule discussed in Par
...
8
...
In addition, if the declarations differ because one type is an incomplete structure, union, or enumeration type (Par
...
8
...
Moreover, if one type is an incomplete array type (Par
...
8
...
2) and the other is a completed array type, the types, if otherwise identical, are also taken to agree
...
If the first external declarator for a function or object includes the static specifier, the identifier has internal linkage; otherwise it has external linkage
...
11
...
An external declaration for an object is a definition if it has an initializer
...
If a definition for an object appears in a translation unit, any tentative definitions are treated merely as redundant declarations
...
Each object must have exactly one definition
...
For objects with external linkage, it applies to the entire program
...
Some implementations relax it by generalizing the notion of tentative definition
...
If a definition occurs somewhere in the program, then the tentative definitions become merely declarations, but if no definition appears, then all its tentative definitions become a definition with initializer 0
...
11 Scope and Linkage A program need not all be compiled at one time: the source text may be kept in several files containing translation units, and precompiled routines may be loaded from libraries
...
Therefore, there are two kinds of scope to consider: first, the lexical scope of an identifier which is the region of the program text within which the identifier's characteristics are understood; and second, the scope associated with objects and functions with external linkage, which determines the connections between identifiers in separately compiled translation units
...
11
...
These classes are: objects, functions, typedef names, and enum constants; labels; tags of structures or unions, and enumerations; and members of each structure or union individually
...
Labels did not previously have their own name space; tags of structures and unions each had a separate space, and in some implementations enumerations tags did as well; putting different kinds of tags into the same space is a new restriction
...
This rule has been common practice for several years
...
The scope of a parameter of a function definition begins at the start of the block defining the function, and persists through the function; the scope of a parameter in a function declaration ends at the end of the declarator
...
The scope of a label is the whole of the function in which it appears
...
If an identifier is explicitly declared at the head of a block, including the block constituting a function, any declaration of the identifier outside the block is suspended until the end of the block
...
11
...
All declarations for the same object or function identifier with external linkage refer to the same thing, and the object or function is shared by the entire program
...
A
...
2, the first external declaration for an identifier gives the identifier internal linkage if the static specifier is used, external linkage otherwise
...
If it does include extern, and an external declaration for is active in the scope surrounding the block, then the identifier has the same linkage as the external declaration, and refers to the same object or function; but if no external declaration is visible, its linkage is external
...
12 Preprocessing A preprocessor performs macro substitution, conditional compilation, and inclusion of named files
...
The syntax of these lines is independent of the rest of the language; they may appear anywhere and have effect that lasts (independent of scope) until the end of the translation unit
...
A
...
2 for how to adjoin lines)
...
A
...
4); in addition, any character not otherwise defined is taken as a token
...
Preprocessing itself takes place in several logically successive phases that may, in a particular implementation, be condensed
...
First, trigraph sequences as described in Par
...
12
...
Should the operating system environment require it, newline characters are introduced between the lines of the source file
...
Each occurrence of a backslash character \ followed by a newline is deleted, this splicing lines (Par
...
12
...
3
...
Then preprocessing directives are obeyed, and macros (Pars
...
12
...
12
...
4
...
A
...
5
...
2
...
5
...
A
...
1 Trigraph Sequences The character set of C source programs is contained within seven-bit ASCII, but is a superset of the ISO 646-1983 Invariant Code Set
...
This replacement occurs before any other processing
...
Trigraph sequences are new with the ANSI standard
...
12
...
This occurs before division into tokens
...
12
...
A second #define for the same identifier is erroneous unless the second token sequence is identical to the first, where all white space separations are taken to be equivalent
...
As with the first form, leading and trailing white space arround the token sequence is discarded, and the macro may be redefined only with a definition in which the number and spelling of parameters, and the token sequence, is identical
...
It is not erroneous to apply #undef to an unknown identifier
...
The arguments of the call are the comma-separated token sequences; commas that are quoted or protected by nested parentheses do not separate arguments
...
The number of arguments in the call must match the number of parameters in the definition
...
Then the token sequence resulting from each argument is substituted for each unquoted occurrence of the corresponding parameter's identifier in the replacement token sequence of the macro
...
Two special operators influence the replacement process
...
A \ character is inserted before each " or \ character that appears surrounding, or inside, a string literal or character constant in the argument
...
The effect is undefined if invalid tokens are produced, or if the result depends on the order of processing of the ## operators
...
In both kinds of macro, the replacement token sequence is repeatedly rescanned for more defined identifiers
...
Even if the final value of a macro expansion begins with with #, it is not taken to be a preprocessing directive
...
The most important change is the addition of the # and ## operators, which make quotation and concatenation admissible
...
(See example below
...
Unlike a function to do the same thing, the arguments and returned value may have any arithmetic type or even be pointers
...
Given the definition #define tempfile(dir) #dir "%s" the macro call tempfile(/usr/tmp) yields "/usr/tmp" "%s" which will subsequently be catenated into a single string
...
However, the call cat(cat(1,2),3) is undefined: the presence of ## prevents the arguments of the outer call from being expanded
...
If a second level of macro definition is introduced, #define xcat(x, y) cat(x,y) things work more smoothly; xcat(xcat(1, 2), 3) does produce 123, because the expansion of xcat itself does not involve the ## operator
...
A
...
4 File Inclusion A control line of the form # include causes the replacement of that line by the entire contents of the file filename
...
The named file is searched for in a sequence of implementation-defined places
...
The effect of using ', \, or /* in the filename remains undefined, but > is permitted
...
> or "
...
#include files may be nested
...
12
...
preprocessor-conditional: if-line text elif-parts else-partopt #endif if-line: # if constant-expression # ifdef identifier # ifndef identifier elif-parts: elif-line text elif-partsopt elif-line: # elif constant-expression else-part: else-line text else-line: #else Each of the directives (if-line, elif-line, else-line, and #endif) appears alone on a line
...
The text following the successful directive line is treated normally
...
Once a successful #if or #elif line has been found and its text processed, succeeding #elif and #else lines, together with their text, are discarded
...
Text controlled by inactive arms of the conditional is ignored except for checking the nesting of conditionals
...
Moreover, any expressions of the form defined identifier or defined (identifier) are replaced, before scanning for macros, by 1L if the identifier is defined in the preprocessor, and by 0L if not
...
Finally, each integer constant is Appendix A - Reference Manual 39 40 Appendix A - Reference Manual considered to be suffixed with L, so that all arithmetic is taken to be long or unsigned long
...
A
...
19) is restricted: it must be integral, and may not contain sizeof, a cast, or an enumeration constant
...
#elif is new since the first edition, although it has been available is some preprocessors
...
A
...
6 Line Control For the benefit of other preprocessors that generate C programs, a line in one of the forms # line constant "filename" # line constant causes the compiler to believe, for purposes of error diagnostics, that the line number of the next source line is given by the decimal integer constant and the current input file is named by the identifier
...
Macros in the line are expanded before it is interpreted
...
12
...
A
...
8 Pragmas A control line of the form # pragma token-sequenceopt causes the preprocessor to perform an implementation-dependent action
...
A
...
9 Null directive A control line of the form # 40 Appendix A - Reference Manual Appendix A - Reference Manual 41 has no effect
...
12
...
They, and also the preprocessor expansion operator defined, may not be undefined or redefined
...
A string literal containing the name of the file being compiled
...
It is intended that this identifier be defined to be 1 only in standard-conforming __STDC__ implementations
...
A
...
It has exactly the same content, but is in different order
...
This grammar can be transformed mechanically into input acceptable for an automatic parser-generator
...
With one further change, namely deleting the production typedef-name: identifier and making typedef-name a terminal symbol, this grammar is acceptable to the YACC parser-generator
...
translation-unit: external-declaration translation-unit external-declaration external-declaration: function-definition declaration function-definition: declaration-specifiersopt declarator declaration-listopt compound-statement declaration: declaration-specifiers init-declarator-listopt; declaration-list: declaration declaration-list declaration declaration-specifiers: storage-class-specifier declaration-specifiersopt type-specifier declaration-specifiersopt Appendix A - Reference Manual 41 42 Appendix A - Reference Manual type-qualifier declaration-specifiersopt storage-class specifier: one of auto register static extern typedef type specifier: one of void char short int long float double signed unsigned struct-or-union-specifier enum-specifier typedef-name type-qualifier: one of const volatile struct-or-union-specifier: struct-or-union identifieropt { struct-declaration-list } struct-or-union identifier struct-or-union: one of struct union struct-declaration-list: struct declaration struct-declaration-list struct declaration init-declarator-list: init-declarator init-declarator-list, init-declarator init-declarator: declarator declarator = initializer struct-declaration: specifier-qualifier-list struct-declarator-list; specifier-qualifier-list: type-specifier specifier-qualifier-listopt type-qualifier specifier-qualifier-listopt struct-declarator-list: struct-declarator struct-declarator-list , struct-declarator struct-declarator: declarator declaratoropt : constant-expression enum-specifier: enum identifieropt { enumerator-list } enum identifier enumerator-list: enumerator enumerator-list , enumerator 42 Appendix A - Reference Manual Appendix A - Reference Manual 43 enumerator: identifier identifier = constant-expression declarator: pointeropt direct-declarator direct-declarator: identifier (declarator) direct-declarator [ constant-expressionopt ] direct-declarator ( parameter-type-list ) direct-declarator ( identifier-listopt ) pointer: * type-qualifier-listopt * type-qualifier-listopt pointer type-qualifier-list: type-qualifier type-qualifier-list type-qualifier parameter-type-list: parameter-list parameter-list ,
...
identifier postfix-expression->+identifier postfix-expression++ postfix-expression-primary-expression: identifier constant string (expression) argument-expression-list: assignment-expression assignment-expression-list , assignment-expression constant: integer-constant character-constant floating-constant enumeration-constant The following grammar for the preprocessor summarizes the structure of control lines, but is not suitable for mechanized parsing
...
control-line: # define identifier token-sequence # define identifier(identifier,
...
com) Back to Appendix A -- Index -- Appendix C Appendix A - Reference Manual 47 Appendix B - Standard Library This appendix is a summary of the library defined by the ANSI standard
...
We have omitted a few functions that are of limited utility or easily synthesized from others; we have omitted multi-byte characters; and we have omitted discussion of locale issues; that is, properties that depend on local language, nationality, or culture
...
h>
...
h>
...
h>
...
h>
...
h>
...
h>
...
h>
...
h> A header can be accessed by "sb
...
1 Input and Output:
...
h> represent nearly one third of the library
...
The library supports text streams and binary streams, although on some systems, notably UNIX, these are identical
...
An environment may need to convert a text stream to or from some other representation (such as mapping '\n' to carriage return and linefeed)
...
A stream is connected to a file or device by opening it; the connection is broken by closing the stream
...
We will use ``file pointer'' and ``stream'' interchangeably when there is no ambiguity
...
B
...
1 File Operations The following functions deal with operations on files
...
FILE *fopen(const char *filename, const char *mode) fopen opens the named file, and returns a stream, or NULL if the attempt fails
...
e
...
If the mode includes b after the initial letter, as in "rb" or "w+b", that indicates a binary file
...
At most FOPEN_MAX files may be open at once
...
It returns stream, or NULL if an error occurs
...
int fflush(FILE *stream) On an output stream, fflush causes any buffered but unwritten data to be written; on an input stream, the effect is undefined
...
fflush(NULL) flushes all output streams
...
It returns EOF if any errors occurred, and zero otherwise
...
It returns non-zero if the attempt fails
...
FILE *tmpfile(void) tmpfile creates a temporary file of mode "wb+" that will be automatically removed when closed or when the program terminates normally
...
char *tmpnam(char s[L_tmpnam]) tmpnam(NULL) creates a string that is not the name of an existing file, and returns a pointer to an internal static array
...
tmpnam generates a different name each time it is called; at most TMP_MAX different names are guaranteed during execution of the program
...
int setvbuf(FILE *stream, char *buf, int mode, size_t size) setvbuf controls buffering for the stream; it must be called before reading, writing or any other operation
...
If buf is not NULL, it will be used as the buffer, otherwise a buffer will be allocated
...
setvbuf returns non-zero for any error
...
Otherwise, setbuf is equivalent to (void) setvbuf(stream, buf, _IOFBF, BUFSIZ)
...
1
...
int fprintf(FILE *stream, const char *format,
...
The return value is the number of characters written, or negative if an error occurred
...
Each conversion specification begins with the character % and ends with a conversion character
...
♦ +, which specifies that the number will always be printed with a sign
...
♦ 0: for numeric conversions, specifies padding to the field width with leading zeros
...
For o, the first digit will become zero
...
For e, E, f, g, and G, the output will always have a decimal point; for g and G, trailing zeros will not be removed
...
The converted argument will be printed in a field at least this wide, and wider if necessary
...
The padding character is normally space, but is 0 if the zero padding flag is present
...
• A number, the precision, that specifies the maximum number of characters to be printed from a string, or the number of digits to be printed after the decimal point for e, E, or f conversions, or the number of significant digits for g or G conversion, or the number of digits to be printed for an integer (leading 0s will be added to make up the necessary width)
...
``h'' indicates that the corresponding argument is to be printed as a short or unsigned short; ``l'' indicates that the argument is a long or unsigned long, ``L'' indicates that the argument is a long double
...
The conversion characters and their meanings are shown in Table B
...
If the character after the % is not a conversion character, the behavior is undefined
...
1 Printf Conversions Character Argument type; Printed As d,i int; signed decimal notation
...
unsigned int; unsigned hexadecimal notation (without a leading 0x or 0X), using abcdef x,X for 0x or ABCDEF for 0X
...
c int; single character, after conversion to unsigned char char *; characters from the string are printed until a '\0' is reached or until the number of s characters indicated by the precision have been printed
...
ddd, where the number of d's is given by the f precision
...
double; decimal notation of the form [-]m
...
ddddddE+/-xx, where e,E the number of d's is specified by the precision
...
double; %e or %E is used if the exponent is less than -4 or greater than or equal to the precision; g,G otherwise %f is used
...
p void *; print as a pointer (implementation-dependent representation)
...
No argument is converted
...
) printf(
...
int sprintf(char *s, const char *format,
...
s must be big enough to hold the result
...
int vprintf(const char *format, va_list arg) int vfprintf(FILE *stream, const char *format, va_list arg) Appendix B - Standard Library 3 4 Appendix B - Standard Library int vsprintf(char *s, const char *format, va_list arg) The functions vprintf, vfprintf, and vsprintf are equivalent to the corresponding printf functions, except that the variable argument list is replaced by arg, which has been initialized by the va_start macro and perhaps va_arg calls
...
h> in Section B
...
B
...
3 Formatted Input The scanf function deals with formatted input conversion
...
) fscanf reads from stream under control of format, and assigns converted values through subsequent arguments, each of which must be a pointer
...
fscanf returns EOF if end of file or an error occurs before any conversion; otherwise it returns the number of input items converted and assigned
...
The format string may contain: • Blanks or tabs, which are not ignored
...
• Conversion specifications, consisting of a %, an optional assignment suppression character *, an optional number specifying a maximum field width, an optional h, l, or L indicating the width of the target, and a conversion character
...
Normally the result is placed in the variable pointed to by the corresponding argument
...
An input field is defined as a string of non-white space characters; it extends either to the next white space character or until the field width, if specified, is exhausted
...
(White space characters are blank, tab, newline, carriage return, vertical tab, and formfeed
...
The corresponding argument must be a pointer
...
2
...
The conversion characters e, f, and g may be preceded by l if a pointer to double rather than float is in the argument list, and by L if a pointer to a long double
...
2 Scanf Conversions Character d i o u x c 4 Input Data; Argument type decimal integer; int* integer; int*
...
octal integer (with or without leading zero); int *
...
hexadecimal integer (with or without leading 0x or 0X); int*
...
The next input characters are placed in the indicated array, up to the number given by the width field; the default is 1
...
The normal skip Appendix B - Standard Library Appendix B - Standard Library s e,f,g p n [
...
] % 5 over white space characters is suppressed in this case; to read the next non-white space character, use %1s
...
floating-point number; float *
...
pointer value as printed by printf("%p");, void *
...
No input is read
...
matches the longest non-empty string of input characters from the set between brackets; char *
...
] includes ] in the set
...
A '\0' is added
...
literal %; no assignment is made
...
) scanf(
...
int sscanf(const char *s, const char *format,
...
) is equivalent to scanf(
...
B
...
4 Character Input and Output Functions int fgetc(FILE *stream) fgetc returns the next character of stream as an unsigned char (converted to an int), or EOF if end of file or error occurs
...
fgets returns s, or NULL if end of file or error occurs
...
It returns the character written, or EOF for error
...
int getc(FILE *stream) getc is equivalent to fgetc except that if it is a macro, it may evaluate stream more than once
...
char *gets(char *s) gets reads the next input line into the array s; it replaces the terminating newline with '\0'
...
int putc(int c, FILE *stream) putc is equivalent to fputc except that if it is a macro, it may evaluate stream more than once
...
int puts(const char *s) puts writes the string s and a newline to stdout
...
int ungetc(int c, FILE *stream) Appendix B - Standard Library 5 6 Appendix B - Standard Library ungetc pushes c (converted to an unsigned char) back onto stream, where it will be returned on the next read
...
EOF may not be pushed back
...
B
...
5 Direct Input and Output Functions size_t fread(void *ptr, size_t size, size_t nobj, FILE *stream) fread reads from stream into the array ptr at most nobj objects of size size
...
feof and ferror must be used to determine status
...
It returns the number of objects written, which is less than nobj on error
...
1
...
For a binary file, the position is set to offset characters from origin, which may be SEEK_SET (beginning), SEEK_CUR (current position), or SEEK_END (end of file)
...
fseek returns non-zero on error
...
void rewind(FILE *stream) rewind(fp) is equivalent to fseek(fp, 0L, SEEK_SET); clearerr(fp)
...
The type fpos_t is suitable for recording such values
...
int fsetpos(FILE *stream, const fpos_t *ptr) fsetpos positions stream at the position recorded by fgetpos in *ptr
...
B
...
7 Error Functions Many of the functions in the library set status indicators when error or end of file occur
...
In addition, the integer expression errno (declared in
...
void clearerr(FILE *stream) clearerr clears the end of file and error indicators for stream
...
int ferror(FILE *stream) ferror returns non-zero if the error indicator for stream is set
...
3
...
2 Character Class Tests:
...
h> declares functions for testing characters
...
The functions return non-zero (true) if the argument c satisfies the condition described, and zero if not
...
isalnum(c) isalpha(c) iscntrl(c) isdigit(c) isgraph(c) islower(c) isprint(c) ispunct(c) In addition, there are two functions that convert the case of letters: int tolower(c) convert c to lower case int toupper(c) convert c to upper case If c is an upper-case letter, tolower(c) returns the corresponding lower-case letter, toupper(c) returns the corresponding upper-case letter; otherwise it returns c
...
3 String Functions:
...
h>
...
Except for memmove, the behavior is undefined if copying takes place between overlapping objects
...
In the following table, variables s and t are of type char *; cs and ct are of type const char *; n is of type size_t; and c is an int converted to char
...
copy at most n characters of string ct to s; return s
...
concatenate string ct to end of string s; return s
...
compare string cs to string ct, return <0 if cs0 if cs>ct
...
return pointer to first occurrence of c in cs or NULL if not present
...
size_t return length of prefix of cs consisting of characters in ct
...
strcspn(cs,ct) char return pointer to first occurrence in string cs of any character string ct, or *strpbrk(cs,ct) NULL if not present
...
size_t strlen(cs) return length of cs
...
char *strtok(s,ct) strtok searches s for tokens delimited by characters from ct; see below
...
The first call in a sequence has a non-NULL s, it finds the first token in s consisting of characters not in ct; it terminates that by overwriting the next character of s with '\0' and returns a pointer to the token
...
strtok returns NULL when no further token is found
...
The mem
...
In the following table, s and t are of type void *; cs and ct are of type const void *; n is of type size_t; and c is an int converted to an unsigned char
...
same as memcpy except that it works even if the objects overlap
...
return pointer to first occurrence of character c in cs, or NULL if not present among the first n characters
...
B
...
h> The header
...
The macros EDOM and ERANGE (found in
...
A domain error occurs if an argument is outside the domain over which the function is defined
...
A range error occurs if the result of the function cannot be represented as a double
...
If the result underflows, the function returns zero; whether errno is set to ERANGE is implementation-defined
...
Angles for trigonometric functions are expressed in radians
...
cos-1(x) in range [0,pi], x in [-1,1]
...
tan-1(y/x) in range [-pi,pi]
...
base 10 logarithm log10(x), x>0
...
A domain error occurs if x=0 and y<=0, or if x<0 and y is not an integer
...
smallest integer not less than x, as a double
...
absolute value |x| x*2n splits x into a normalized fraction in the interval [1/2,1) which is returned, and a power of 2, which is stored in *exp
...
splits x into integral and fractional parts, each with the same sign as x
...
floating-point remainder of x/y, with the same sign as x
...
B
...
h> The header
...
double atof(const char *s) atof converts s to double; it is equivalent to strtod(s, (char**)NULL)
...
long atol(const char *s) converts s to long; it is equivalent to strtol(s, (char**)NULL, 10)
...
If the answer would overflow, HUGE_VAL is returned with the proper sign; if the answer would underflow, zero is returned
...
long strtol(const char *s, char **endp, int base) strtol converts the prefix of s to long, ignoring leading white space; it stores a pointer to any unconverted suffix in *endp unless endp is NULL
...
If base is zero, the base is 8, 10, or 16; leading 0 implies octal and leading 0x or 0X hexadecimal
...
If the answer would overflow, LONG_MAX or LONG_MIN is returned, depending on the sign of the result, and errno is set to ERANGE
...
int rand(void) rand returns a pseudo-random integer in the range 0 to RAND_MAX, which is at least 32767
...
The initial seed is 1
...
The space is initialized to zero bytes
...
The space is uninitialized
...
The contents will be unchanged up to the minimum of the old and new sizes
...
realloc returns a pointer to the new space, or NULL if the request cannot be satisfied, in which case *p is unchanged
...
p must be a pointer to space previously allocated by calloc, malloc, or realloc
...
void exit(int status) exit causes normal program termination
...
How status is returned to the environment is implementation-dependent, but zero is taken as successful termination
...
int atexit(void (*fcn)(void)) atexit registers the function fcn to be called when the program terminates normally; it returns non-zero if the registration cannot be made
...
If s is NULL, system returns non-zero if there is a command processor
...
char *getenv(const char *name) getenv returns the environment string associated with name, or NULL if no string exists
...
void *bsearch(const void *key, const void *base, size_t n, size_t size, int (*cmp)(const void *keyval, const void *datum)) bsearch searches base[0]
...
The function cmp must return negative if its first argument (the search key) is less than its second (a table entry), zero if equal, and positive if greater
...
bsearch returns a pointer to a matching item, or NULL if none exists
...
base[n-1] of objects of size size
...
int abs(int n) abs returns the absolute value of its int argument
...
div_t div(int num, int denom) div computes the quotient and remainder of num/denom
...
ldiv_t ldiv(long num, long denom) ldiv computes the quotient and remainder of num/denom
...
B
...
h> The assert macro is used to add diagnostics to programs: void assert(int expression) 10 Appendix B - Standard Library Appendix B - Standard Library 11 If expression is zero when assert(expression) is executed, the assert macro will print on stderr a message, such as Assertion failed: expression, file filename, line nnn It then calls abort to terminate execution
...
If NDEBUG is defined at the time
...
B
...
h> The header
...
Suppose lastarg is the last named parameter of a function f with a variable number of arguments
...
B
...
h> The declarations in
...
int setjmp(jmp_buf env) The macro setjmp saves state information in env for use by longjmp
...
A call to setjmp can only occur in certain contexts, basically the test of if, switch, and loops, and only in simple relational expressions
...
The function containing the setjmp must not have terminated
...
B
...
h> The header
...
void (*signal(int sig, void (*handler)(int)))(int) signal determines how subsequent signals will be handled
...
Valid signals include SIGABRT SIGFPE SIGILL SIGINT SIGSEGV SIGTERM abnormal termination, e
...
, from abort arithmetic error, e
...
, zero divide or overflow illegal function image, e
...
, illegal instruction interactive attention, e
...
, interrupt illegal storage access, e
...
, access outside memory limits termination request sent to this program signal returns the previous value of handler for the specific signal, or SIG_ERR if an error occurs
...
If the handler returns, execution will resume where it was when the signal occurred
...
int raise(int sig) raise sends the signal sig to the program; it returns non-zero if unsuccessful
...
10 Date and Time Functions:
...
h> declares types and functions for manipulating date and time
...
clock_t and time_t are arithmetic types representing times, and struct tm holds the components of a calendar time: int int int int int int int int int 12 tm_sec; tm_min; tm_hour; tm_mday; tm_mon; tm_year; tm_wday; tm_yday; tm_isdst; seconds after the minute (0,61) minutes after the hour (0,59) hours since midnight (0,23) day of the month (1,31) months since January (0,11) years since 1900 days since Sunday (0,6) days since January 1 (0,365) Daylight Saving Time flag Appendix B - Standard Library Appendix B - Standard Library 13 tm_isdst is positive if Daylight Saving Time is in effect, zero if not, and negative if the information is not available
...
clock()/CLK_PER_SEC is a time in seconds
...
If tp is not NULL, the return value is also assigned to *tp
...
time_t mktime(struct tm *tp) mktime converts the local time in the structure *tp into calendar time in the same representation used by time
...
mktime returns the calendar time or -1 if it cannot be represented
...
char *asctime(const struct tm *tp) asctime*tp into a string of the form Sun Jan 3 15:14:13 1988\n\0 char *ctime(const time_t *tp) ctime converts the calendar time *tp to local time; it is equivalent to asctime(localtime(tp)) struct tm *gmtime(const time_t *tp) gmtime converts the calendar time *tp into Coordinated Universal Time (UTC)
...
The name gmtime has historical significance
...
size_t strftime(char *s, size_t smax, const char *fmt, const struct tm *tp) strftime formats date and time information from *tp into s according to fmt, which is analogous to a printf format
...
Each %c is replaced as described below, using values appropriate for the local environment
...
strftime returns the number of characters, excluding the '\0', or zero if more than smax characters were produced
...
full weekday name
...
full month name
...
day of the month (01-31)
...
hour (12-hour clock) (01-12)
...
month (01-12)
...
local equivalent of AM or PM
...
Appendix B - Standard Library 13 14 Appendix B - Standard Library %U %w %W %x %X %y %Y %Z %% week number of the year (Sunday as 1st day of week) (00-53)
...
week number of the year (Monday as 1st day of week) (00-53)
...
local time representation
...
year with century
...
% B
...
h> and
...
h> defines constants for the sizes of integral types
...
CHAR_BIT 8 bits in a char CHAR_MAX UCHAR_MAX or SCHAR_MAX maximum value of char CHAR_MIN 0 or SCHAR_MIN maximum value of char INT_MAX 32767 maximum value of int INT_MIN -32767 minimum value of int LONG_MAX 2147483647 maximum value of long LONG_MIN -2147483647 minimum value of long SCHAR_MAX +127 maximum value of signed char SCHAR_MIN -127 minimum value of signed char SHRT_MAX +32767 maximum value of short SHRT_MIN -32767 minimum value of short UCHAR_MAX 255 maximum value of unsigned char UINT_MAX 65535 maximum value of unsigned int ULONG_MAX 4294967295 maximum value of unsigned long USHRT_MAX 65535 maximum value of unsigned short The names in the table below, a subset of
...
When a value is given, it represents the minimum magnitude for the corresponding quantity
...
FLT_RADIX FLT_ROUNDS FLT_DIG FLT_EPSILON FLT_MANT_DIG FLT_MAX FLT_MAX_EXP FLT_MIN FLT_MIN_EXP DBL_DIG DBL_EPSILON DBL_MANT_DIG DBL_MAX 14 2 6 1E-5 1E+37 1E-37 10 1E-9 1E+37 radix of exponent, representation, e
...
, 2, 16 floating-point rounding mode for addition decimal digits of precision smallest number x such that 1
...
0 number of base FLT_RADIX in mantissa maximum floating-point number maximum n such that FLT_RADIXn-1 is representable minimum normalized floating-point number minimum n such that 10n is a normalized number decimal digits of precision smallest number x such that 1
...
0 number of base FLT_RADIX in mantissa maximum double floating-point number Appendix B - Standard Library Appendix B - Standard Library DBL_MAX_EXP DBL_MIN DBL_MIN_EXP 1E-37 15 maximum n such that FLT_RADIXn-1 is representable minimum normalized double floating-point number minimum n such that 10n is a normalized number Back to Appendix A -- Index -- Appendix C Compiled by tmdcjsl(skidrow8123@hotmail
...
Almost all were extensions of the original language, and were carefully designed to remain compatible with existing practice; some repaired ambiguities in the original description; and some represent modifications that change existing practice
...
More recently, the ANSI committee standardizing the language incorporated most of the changes, and also introduced other significant modifications
...
This Appendix summarizes the differences between the language defined by the first edition of this book, and that expected to be defined by the final standard
...
• Preprocessing is more carefully defined in the Standard than in the first edition, and is extended: it is explicitly token based; there are new operators for concatenation of tokens ("temp0103
...
12">Par
...
12
...
(Many implementations provide more
...
Escapes for #\^[]{}|~ are defined, see Par
...
12
...
Observe that the introduction of trigraphs may change the meaning of strings containing the sequence ??
...
The stillborn entry keyword is withdrawn
...
The effect of following \ by a character not part of an approved escape sequence is undefined
...
A
...
5
...
• Everyone's favorite trivial change: 8 and 9 are not octal digits
...
It also refines the rules for the type of unsiffixed constants (Par
...
2
...
• Adjacent string literals are concatenated
...
A
...
6
...
The locution long float as a synonym for double is withdrawn, but long double may be used to declare an extra-precision floating quantity
...
The standard introduces the signed keyword to make signedness explicit for char and other integral objects
...
The Standard introduces the use of the void * type as a generic pointer type; previously char * played this role
...
• The Standard places explicit minima on the ranges of the arithmetic types, and mandates headers (
...
h>) giving the characteristics of each particular implementation
...
• The Standard adopts from C++ the notion of type qualifier, for example const (Par
...
8
...
• Strings are no longer modifiable, and so may be placed in read-only memory
...
'' See Par
...
6
...
• The old assignment operators like =+ are truly gone
...
Appendix C - Summary of Changes 1 2 Appendix C - Summary of Changes • A compiler's license to treat mathematically associative operators as computationally associative is revoked
...
• A pointer to a function may be used as a function designator without an explicit * operator
...
A
...
3
...
• Structures may be assigned, passed to functions, and returned by functions
...
• The sizeof operator, in the first edition, yielded type int; subsequently, many implementations made it unsigned
...
h>)
...
See Par
...
7
...
8 and Par
...
7
...
• The address-of operator & may not be applied to an object declared register, even if the implementation chooses not to keep the object in a register
...
See Par
...
7
...
• The Standard legalizes the creation of a pointer just beyond the end of an array, and allows arithmetic and relations on it; see Par
...
7
...
• The Standard introduces (borrowing from C++) the notion of a function prototype declaration that incorporates the types of the parameters, and includes an explicit recognition of variadic functions together with an approved way of dealing with them
...
A
...
3
...
8
...
3, B
...
The older style is still accepted, with restrictions
...
On the other hand, a declaration with just a structure or union tag redeclares that tag even if it was declared in an outer scope
...
• Some implementations, when presented with an extern declaration in an inner block, would export the declaration to the rest of the file
...
• The scope of parameters is injected into a function's compound statement, so that variable declarations at the top level of the function cannot hide the parameters
...
The Standard puts all tags in a single name 2 Appendix C - Summary of ChangesTitle: C language
Description: Full knowledge of c language..