C primer plus 一到五章
C Primer Plus, Fifth Edition | |
By Stephen Prata | |
|
|
Publisher | : Sams |
Pub Date | : November 23, 2004 |
ISBN | : 0-672-32696-5 |
Pages | : 984 |
1.6 使用C语言的7个步骤
Step 1: Define the Program Objectives
Step 2: Design the Program
Step 3: Write the Code
#include <stdio.h>
int main(void)
{
int dogs;
printf("How many dogs do you have?/n");
scanf("%d", &dogs);
printf("So you have %d dog(s)!/n", dogs);
return 0;
}
Step 4: Compile
Step 5: Run the Program
Step 6: Test and Debug the Program
Step 7: Maintain and Modify the Program
2.4 使程序可读的技巧
Tips on Making Your Programs Readable
Choose meaningful variable names and use comments.
Another technique involves using blank lines to separate one conceptual section of a function from another.
A fourth technique is to use one line per statement.
The following is legitimate, but ugly, code:
int main( void ) { int four; four
=
4
;
printf(
"%d/n",
four); return 0;}
2.7 调试
Introducing Debugging
/* nogood.c -- a program with errors */
#include <stdio.h>
int main(void)
(
int n, int n2, int n3;
/* this program has several errors
n = 5;
n2 = n * n;
n3 = n2 * n2;
printf("n = %d, n squared = %d, n cubed = %d/n", n, n2, n3)
return 0;
)
(1) int n, n2, n3;
(2) Next, the example omits the */ symbol pair necessary to complete a comment. (Alternatively, you could replace /* with the new // form.)
(3) Finally, it omits the mandatory semicolon that should terminate the printf() statement.
Semantic Errors :n3 = n2 * n2;
/* stillbad.c -- a program with its syntax errors fixed */
#include <stdio.h>
int main(void)
{
int n, n2, n3;
/* this program has a semantic error */
n = 5;
n2 = n * n;
n3 = n2 * n2;
printf("n = %d, n squared = %d, n cubed = %d/n", n, n2, n3);
return 0;
}
n = 5, n squared = 25, n cubed = 625
step-by-step manually
Another approach to locating semantic problems is to sprinkle extra printf()
A third method for examining the program states is to use a debugger.
3.2 变量与常量数据
Data Variables and Constants
The difference between a variable and a constant is that a variable can have its value assigned or changed while the program is running, and a constant can't.
3.6 参数和易犯的错误
Arguments and Pitfalls
The printf() and scanf() functions are unusual in that they aren't limited to a particular number of arguments.
/* badcount.c -- incorrect argument counts */
#include <stdio.h>
int main(void)
{
int f = 4;
int g = 5;
float h = 5.0f;
printf("%d/n", f, g); /* too many arguments */
printf("%d %d/n",f); /* too few arguments */
printf("%d %f/n", h, g); /* wrong kind of values */
return 0;
}
3.7 另一个例子:转义序列
One More Example: Escape Sequences
/* escape.c -- uses escape characters */
#include <stdio.h>
int main(void)
{
float salary;
printf("/aEnter your desired monthly salary:");/* 1 */
printf(" $_______/b/b/b/b/b/b/b"); /* 2 */
scanf("%f", &salary);
printf("/n/t$%.2f a month is $%.2f a year.", salary,
salary * 12.0); /* 3 */
printf("/rGee!/n"); /* 4 */
return 0;
}
(1) Because there is no /n at the end of the string, the cursor is left positioned after the colon.
(2) The effect of the seven backspace characters is to move the cursor seven positions to the left.
(3) The third printf() statement output begins with /n/t.
(4) The fourth printf() statement begins with /r. This positions the cursor at the beginning of the current line.
(5) the /n moves the cursor to the next line.
Here is the final appearance of the screen:
Enter your desired monthly salary: $2000.00
Gee! $2000.00 a month is $24000.00 a year.
4.3 常量和C预处理器
Constants and the C Preprocessor
The C preprocessor uses #include to incorporate information from another file.
The preprocessor also lets you define constants.
#define TAXRATE 0.015
When your program is compiled, the value 0.015 will be substituted everywhere you have used TAXRATE. This is called a compile-time substitution.
/* pizza.c -- uses defined constants in a pizza context */
#include <stdio.h>
#define PI 3.14159
int main(void)
{
float area, circum, radius;
printf("What is the radius of your pizza?/n");
scanf("%f", &radius);
area = PI * radius * radius;
circum = 2.0 * PI *radius;
printf("Your basic pizza parameters are as follows:/n");
printf("circumference = %1.2f, area = %1.2f/n", circum,
area);
return 0;
}
The #define statement can be used for character and string constants, too. Just use single quotes for the former and double quotes for the latter. The following examples are valid:
#define BEEP '/a'
#define TEE 'T'
#define ESC '/033'
#define OOPS "Now you have done it!"
Remember that everything following the symbolic name is substituted for it. Don't make this common error:
/* the following is wrong */
#define TOES = 20
If you do this, TOES is replaced by = 20, not just 20. In that case, a statement such as
digits = fingers + TOES;
is converted to the following misrepresentation:
digits = fingers + = 20;
A second way to create symbolic constants—using the const keyword to convert a declaration for a variable into a declaration for a constant:
const int MONTHS = 12; // MONTHS a symbolic constant for 12
This newer approach is more flexible than using #define;
C has yet a third way to create symbolic constants ---- enum
// defines.c -- uses defined constants from limit.h and float.
#include <stdio.h>
#include <limits.h> // integer limits
#include <float.h> // floating-point limits
int main(void)
{
printf("Some number limits for this system:/n");
printf("Biggest int: %d/n", INT_MAX);
printf("Smallest long long: %lld/n", LLONG_MIN);
printf("One byte = %d bits on this system./n", CHAR_BIT);
printf("Largest double: %e/n", DBL_MAX);
printf("Smallest normal float: %e/n", FLT_MIN);
printf("float precision = %d digits/n", FLT_DIG);
printf("float epsilon = %e/n", FLT_EPSILON);
return 0;
}
Here is the sample output:
Some number limits for this system:
Biggest int: 2147483647
Smallest long long: -9223372036854775808
One byte = 8 bits on this system.
Largest double: 1.797693e+308
Smallest normal float: 1.175494e-38
float precision = 6 digits
float epsilon = 1.192093e-07
4.4 研究和利用printf()和scanf()
Exploring and Exploiting printf() and scanf()
The printf() Function
Using printf()
Listing 4.6 contains a program that uses some of the conversion specifications.
Listing 4.6. The printout.c Program
/* printout.c -- uses conversion specifiers */
#include <stdio.h>
#define PI 3.141593
int main(void)
{
int number = 5;
float espresso = 13.5;
int cost = 3100;
printf("The %d CEOs drank %f cups of espresso./n", number,
espresso);
printf("The value of pi is %f./n", PI);
printf("Farewell! thou art too dear for my possessing,/n");
printf("%c%d/n", '$', 2 * cost);
return 0;
}
The output, of course, is
The 5 CEOs drank 13.500000 cups of espresso.
The value of pi is 3.141593.
Farewell! thou art too dear for my possessing,
$6200
If you want to print only a phrase, you don't need any conversion specifications. If you just want to print data, you can dispense with the running commentary. Each of the following statements from Listing 4.6 is quite acceptable:
printf("Farewell! thou art too dear for my possessing,/n");
printf("%c%d/n", '$', 2 * cost);
Table 4.4. The printf() Modifiers | |
Modifier | Meaning |
flag | The five flags (-, +, space, #, and 0) are described in Table 4.5. Zero or more flags may be present. Example: "%-10d" |
digit(s) | The minimum field width. A wider field will be used if the printed number or string won't fit in the field. Example: "%4d" |
.digit(s) | Precision. For %e, %E, and %f conversions, the number of digits to be printed to the right of the decimal. For %g and %G conversions, the maximum number of significant digits. For %s conversions, the maximum number of characters to be printed. For integer conversions, the minimum number of digits to appear; leading zeros are used if necessary to meet this minimum. Using only . implies a following zero, so %.f is the same as %.0f. Example: "%5.2f" prints a float in a field five characters wide with two digits after the decimal point. |
h | Used with an integer conversion specifier to indicate a short int or unsigned short int value. Examples: "%hu", "%hx", and "%6.4hd" |
hh | Used with an integer conversion specifier to indicate a signed char or unsigned char value. Examples: "%hhu", "%hhx", and "%6.4hhd" |
j | Used with an integer conversion specifier to indicate an intmax_t or uintmax_t value. Examples: "%jd" and "%8jX" |
l | Used with an integer conversion specifier to indicate a long int or unsigned long int. Examples: "%ld" and "%8lu" |
ll | Used with an integer conversion specifier to indicate a long long int or unsigned long long int. (C99) Examples: "%lld" and "%8llu" |
L | Used with a floating-point conversion specifier to indicate a long double value. Examples: "%Lf" and "%10.4Le" |
t | Used with an integer conversion specifier to indicate a ptrdiff_t value. This is the type corresponding to the difference between two pointers. (C99) Examples: "%td" and "%12ti" |
z | Used with an integer conversion specifier to indicate a size_t value. This is the type returned by sizeof. (C99). Examples: "%zd" and "%12zx" |
Examples Using Modifiers and Flags
Let's put these modifiers to work, beginning with a look at the effect of the field width modifier on printing an integer. Consider the program in Listing 4.7.
Listing 4.7. The width.c Program
/* width.c -- field widths */
#include <stdio.h>
#define PAGES 931
int main(void)
{
printf("*%d*/n", PAGES);
printf("*%2d*/n", PAGES);
printf("*%10d*/n", PAGES);
printf("*%-10d*/n", PAGES);
return 0;
}
Listing 4.7 prints the same quantity four times using four different conversion specifications. It uses an asterisk (*) to show you where each field begins and ends. The output looks as follows:
*931*
*931*
* 931*
*931 *
Now look at some floating-point formats. Enter, compile, and run the program in Listing 4.8.
Listing 4.8. The floats.c Program
// floats.c -- some floating-point combinations
#include <stdio.h>
int main(void)
{
const double RENT = 3852.99; // const-style constant
printf("*%f*/n", RENT);
printf("*%e*/n", RENT);
printf("*%4.2f*/n", RENT);
printf("*%3.1f*/n", RENT);
printf("*%10.3f*/n", RENT);
printf("*%10.3e*/n", RENT);
printf("*%+4.2f*/n", RENT);
printf("*%010.2f*/n", RENT);
return 0;
}
This time, the program uses the keyword const to create a symbolic constant. The output is
*3852.990000*
*3.852990e+03*
*3852.99*
*3853.0*
* 3852.990*
* 3.853e+03*
*+3852.99*
*0003852.99*
The example begins with the default version, %f. In this case, there are two defaults—the field width and the number of digits to the right of the decimal. The second default is six digits, and the field width is whatever it takes to hold the number.
Next is the default for %e. It prints one digit to the left of the decimal point and six places to the right. We're getting a lot of digits! The cure is to specify the number of decimal places to the right of the decimal, and the next four examples in this segment do that. Notice how the fourth and the sixth examples cause the output to be rounded off.
Finally, the + flag causes the result to be printed with its algebraic sign, which is a plus sign in this case, and the 0 flag produces leading zeros to pad the result to the full field width. Note that in the specifier %010, the first 0 is a flag, and the remaining digits (10) specify the field width.
You can modify the RENT value to see how variously sized values are printed. Listing 4.9 demonstrates a few more combinations.
Listing 4.9. The flags.c Program
/* flags.c -- illustrates some formatting flags */
#include <stdio.h>
int main(void)
{
printf("%x %X %#x/n", 31, 31, 31);
printf("**%d**% d**% d**/n", 42, 42, -42);
printf("**%5d**%5.3d**%05d**%05.3d**/n", 6, 6, 6, 6);
return 0;
}
The output looks as follows:
1f 1F 0x1f
**42** 42**-42**
** 6** 006**00006** 006**
First, 1f is the hex equivalent of 31. The x specifier yields 1f, and the X specifier yields 1F. Using the # flag provides an initial 0x.
The second line of output illustrates how using a space in the specifier produces a leading space for positive values, but not for negative values. This can produce a pleasing output because positive and negative values with the same number of significant digits are printed with the same field widths.
The third line illustrates how using a precision specifier (%5.3d) with an integer form produces enough leading zeros to pad the number to the minimum value of digits (three, in this case). Using the 0 flag, however, pads the number with enough leading zeros to fill the whole field width. Finally, if you provide both the 0 flag and the precision specifier, the 0 flag is ignored.
Now let's examine some of the string options. Consider the example in Listing 4.10.
Listing 4.10. The strings.c Program
/* strings.c -- string formatting */
#include <stdio.h>
#define BLURB "Authentic imitation!"
int main(void)
{
printf("/%2s//n", BLURB);
printf("/%24s//n", BLURB);
printf("/%24.5s//n", BLURB);
printf("/%-24.5s//n", BLURB);
return 0;
}
Here is the output:
/Authentic imitation!/
/ Authentic imitation!/
/ Authe/
/Authe /
Notice how the field is expanded to contain all the specified characters. Also notice how the precision specification limits the number of characters printed. The .5 in the format specifier tells printf() to print just five characters. Again, the - modifier left-justifies the text.
Naturally, you should match the conversion specification to the type of value being printed. Often, you have choices. For instance, if you want to print a type int value, you can use %d or %x or %o.
// input.c -- when to use &
#include <stdio.h>
int main(void)
{
int age; // variable
float assets; // variable
char pet[30]; // string
printf("Enter your age, assets, and favorite pet./n");
scanf("%d %f", &age, &assets); // use the & here
scanf("%s", pet); // no & for char array
printf("%d $%.2f %s/n", age, assets, pet);
return 0;
}
Here is a sample exchange:
Enter your age, assets, and favorite pet.
38
92360.88 llama
38 $92360.88 llama
The * serves quite a different purpose for scanf(). When placed between the % and the specifier letter, it causes that function to skip over corresponding input. Listing 4.17 provides an example.
Listing 4.17. The skip2.c Program
/* skip2.c -- skips over first two integers of input */
#include <stdio.h>
int main(void)
{
int n;
printf("Please enter three integers:/n");
scanf("%*d %*d %d", &n);
printf("The last integer was %d/n", n);
return 0;
}
The scanf() instruction in Listing 4.17 says, "Skip two integers and copy the third into n." Here is a sample run:
Please enter three integers:
2004 2005 2006
The last integer was 2006
This skipping facility is useful if, for example, a program needs to read a particular column of a file that has data arranged in uniform columns.
5.3 其他运算符
Some Additional Operators
The sizeof Operator and the size_t Type
C says that sizeof returns a value of type size_t. This is an unsigned integer type, but not a brand-new type. Instead, like the portable types (int32_t and so on), it is defined in terms of the standard types.
Modulus Operator: %
Increment and Decrement Operators: ++ and –
Type Conversions
The basic rules are
1. When appearing in an expression, char and short, both signed and unsigned, are automatically converted to int or, if necessary, to unsigned int. (If short is the same size as int, unsigned short is larger than int; in that case, unsigned short is converted to unsigned int.) Under K&R C, but not under current C, float is automatically converted to double. Because they are conversions to larger types, they are called promotions.
2. In any operation involving two types, both values are converted to the higher ranking of the two types.
3. The ranking of types, from highest to lowest, is long double, double, float, unsigned long long, long long, unsigned long, long, unsigned int, and int. One possible exception is when long and int are the same size, in which case unsigned int outranks long. The short and char types don't appear in this list because they would have been already promoted to int or perhaps unsigned int.
4. In an assignment statement, the final result of the calculations is converted to the type of the variable being assigned a value. This process can result in promotion, as described in rule 1, or demotion, in which a value is converted to a lower-ranking type.
5. When passed as function arguments, char and short are converted to int, and float is converted to double. This automatic promotion can be overridden by function prototyping, as discussed in Chapter 9, "Functions."
/* convert.c -- automatic type conversions */
#include <stdio.h>
int main(void)
{
char ch;
int i;
float fl;
fl = i = ch = 'C'; /* line 9 */
printf("ch = %c, i = %d, fl = %2.2f/n", ch, i, fl); /* line 10 */
ch = ch + 1; /* line 11 */
i = fl + 2 * ch; /* line 12 */
fl = 2.0 * ch + i; /* line 13 */
printf("ch = %c, i = %d, fl = %2.2f/n", ch, i, fl); /* line 14 */
ch = 5212205.17; /* line 15 */
printf("Now ch = %c/n", ch);
return 0;
}
Running convert.c produces the following output:
ch = C, i = 67, fl = 67.00
ch = D, i = 203, fl = 339.00
Now ch = -
On this system, which has an 8-bit char and a 32-bit int, here is what happened:
· Lines 9 and 10— The character 'C' is stored as a 1-byte ASCII value in ch. The integer variable i receives the integer conversion of 'C', which is 67 stored as 4 bytes. Finally, fl receives the floating conversion of 67, which is 67.00.
· Lines 11 and 14— The character variable 'C' is converted to the integer 67, which is then added to the 1. The resulting 4-byte integer 68 is truncated to 1 byte and stored in ch. When printed using the %c specifier, 68 is interpreted as the ASCII code for 'D'.
· Lines 12 and 14— The value of ch is converted to a 4-byte integer (68) for the multiplication by 2. The resulting integer (136) is converted to floating point in order to be added to fl. The result (203.00f) is converted to int and stored in i.
· Lines 13 and 14— The value of ch ('D', or 68) is converted to floating point for multiplication by 2.0. The value of i (203) is converted to floating point for the addition, and the result (339.00) is stored in fl.
· Lines 15 and 16— Here the example tries a case of demotion, setting ch equal to a rather large number. After truncation takes place, ch winds up with the ASCII code for the hyphen character.
5.5 类型转换
The Cast Operator