[C语言程序设计现代方法] 第3章 第4章 格式输入输出和表达式


教材:《C语言程序设计_现代方法 第2版》


格式输入输出和表达式

第3章 格式化的输入/输出

printf函数

printf函数被设计来显示格式串的内容。printf(格式串,表达式1,表达式2...)

格式串包含普通字符转换说明。转换说明%后面的信息指定了把数据从二进制形式转换成字符形式的方法。例如%d是把int类型数据转换成字符串,%f表示把float类型转换成字符串。

转换说明

一般的,可以用%m.pX表示转换说明的通用形式。

  • m最小字段宽度。如果显示数值长度小于m,则最终显示右对齐(例如123使用转换说明%4d显示为·123),如果长度大于m,则最终显示会自动补全。如果在前面加个-%-4d则为左对齐。
  • p精度,依赖转换说明符X
    • d:表示十进制形式(基数为10)的整数。p是控制输出高位为0的,例如输出10%3.2d输出结果为·10%3.3d输出结果为010%3.6d输出结果为000010%4.3d输出结果为·010
    • e:表示科学计数法形式的浮点数。p是控制小数点后的位数。例如输出233.33%1.3e输出结果为2.333e+02%0.0e输出结果为2e+02
    • f:表示定点十进制形式的浮点数。p是控制小数点后的位数。
    • g:表示指数形式或者定点十进制形式的浮点数。p是控制有效数字的位数,用于显示变化范围很大的数。

转义序列

  • 警报符:\a
  • 回退符:\b
  • 换行符:\n
  • 水平制表符:\t
  • 引号:\"
  • 斜杠号:\\

scanf函数

scanf的转换说明和printf差不多,区别在于scanf要和输入的做匹配,并且写入数据,所以使用到取址符&

scanf会忽略输入的空格,换行符,制表符。但是当格式串中有符号时,就会在输入中匹配(空格也会因此如果格式串中有符号,在输入字符串时要严格匹配输入,主要是转换说明符后面的符号)

exercise & project

exercise

3.01

What output do the following calls of printf produce?

(a) printf("%6d,%4d", 86, 1040);
(b) printf("%12.5e", 30.253);
(c) printf("%.4f", 83.162);
(d) printf("%-6.2g", .0000009979);

Solution:

(a)     86,1040
(b) 3.02530e+01
(c) 83.1620
(d) 1e-06 
3.02

Write calls of printf that display a float variable x in the following formats.

(a) Exponential notation; left-justified in a field of size 8: one digit after the decimal point.
(b) Exponential notation: right-justified in a field of size 10; six digits after the decimal point.
(c) Fixed decimal notation; left-justified in a field of size 8; three digits after the decimal point.
(d) Fixed decimal notation; right-justified in a field of size 6; no digits after the decimal point.

Solution:

(a) %-8.1e
(b) %10.6e
(c) %-8.3f
(d) %6.0f
3.03

For each of the following pairs of scanf format strings, indicate whether or not the two strings are equivalent. If they're not, show how they can be distinguished.

(a) "%d"       versus " %d"
(b) "%d-%d-%d" versus "%d -%d -%d"
(c) "%f"       versus "%f "
(d) "%f,%f"    versus "%f, %f"

Solution:

(a), (b) and (d) are equivalent, because the scanf function matches zero or more whitespace characters on each whitespace character, except the final character, as shown in (c). (c) is not equivalent because the trailing space will require the user to input a non-whitespace character at the end of the input signifying the end of the whitespace sequence matched by the space.

3.04

Suppose that we call scanf as follows:

scanf("%d%f%d", &i, &x, &j);

If the user enters

10.3 5 6

what will be the values of i, x and j after the call? (Assume that i and j are int variables and x is a float variable.)

Solution:

i = 10
x = 0.3
j = 5

The decimal point will end the input for i and begin x, and the next input, 5, will be assigned to j.

3.05

Suppose that we call scanf as follows:

scanf("%f%d%f", &x, &i, &y);

If the user enters

12.3 45.6 789

what will be the values of x, i and y after the call? (Assume that x and
y are float variables and i is an int variable.)

Solution:

x = 12.3
i = 45
y = 0.6

scanf will read the decimal in 45.6 as the beginning of y, enter 0.6,
and will not enter 789 until the next scan.

3.06

Show how to modify the addfrac.c program of Section 3.2 so that the user is allowed to enter fractions that contain spaces before and after each / character.

Solution:

Add a space after the first %d for each scanf statement. This will allow pattern matching for whitespace between the two %ds and the / character.

See addfrac.c.

project

3.01

Write a program that accepts a date from the user in the form mm/dd/yyy and
then displays it in the form yyymmdd:

Enter a date (mm/dd/yyyy): 2/17/2011
You entered the date 20110217

Solution:

#include <stdio.h>

int main(void) {

    int year, month, day;

    printf("Enter a date (mm/dd/yyyy): ");
    scanf("%d /%d /%d", &month, &day, &year);

    printf("You entered the date %.4d%.2d%.2d\n", year, month, day);
    return 0;
}
3.02

Write a program that formats product information entered by the user. A session with the program should look like this:

Enter item number: 583
Enter unit price: 13.5
Enter purchase date (mm/dd/yyyy): 10/24/2010
Item            Unit            Purchase
                Price           Date
583             $  13.50        10/24/2010

The item number and date should be left justified; the unit price should be right justified. Allow dollar amounts up to $9999.99. Hint Use tabs to line up the columns.

Solution:

#include <stdio.h>

int main(void) {

    int item, year, month, day;
    float price;

    printf("Enter item number: ");
    scanf("%d", &item);

    printf("Enter unit price: ");
    scanf("%f", &price);

    printf("Enter purchase date (mm/dd/yyyy): ");
    scanf("%d /%d /%d", &month, &day, &year);

    printf("Item\t\tUnit\t\tPurchase\n\t\tPrice\t\tDate\n");
    printf("%d\t\t$%8.2f\t%.2d/%.2d/%.4d\n", item, price, month, day, year);

    return 0;
}

3.03

Books are identified by an International Standard Book Number (ISBN). ISBNs
assigned after January 1, 2007 contain 13 digits, arranged in five groups, such
as 978-0-393-97950-3. (Older ISBNs use 10 digits.) The first group (the GSI
prefix
) is currently either 978 or 979. The group identifier specifies the
language or country of origin (for example, 0 and 1 are used in English-speaking
countries). The publisher code identifies the publisher (393 is the code for
W. W. Norton). The item number is assigned by the publisher to identify a
specific book (97950 is the code for this book). An ISBN ends with a check
digit
that's used to verify the accuracy of the preceding digits. Write a
program that breas down an ISBN entered by the user:

Enter ISBN: 978-0-393-97950-3
GSI prefix: 978
Group identifier: 0
Publisher code: 393
Item number: 97950
Check digit: 3

Note: The number of digits in each group may very: you can't assume that
groups have the lengths shown in this example. Test your program with actual
ISBN values (usually found on the back cover of a book and on the copyright
page).

Solution:

#include <stdio.h>

int main(void) {
    
    int gsi, group_id, pub_code, item_num, check_digit;

    printf("Enter ISBN: ");
    scanf("%d -%d -%d -%d -%d", 
          &gsi, &group_id, &pub_code, &item_num, &check_digit);
    printf("GSI prefix: %d\nGroup identifier: %d\n", gsi, group_id);
    printf("Publisher code: %d\nItem number: %d\nCheck digit: %d\n", 
           pub_code, item_num, check_digit);

    return 0;
}
3.04

Write a program that prompts the user to enter a telephone number in the form
(xxx) xxx-xxxx and then displays the number in the form xxx.xxx.xxxx:

Enter phone number [(xxx) xxx-xxxx]: (404) 817-6900
You entered 404.817.6900

Solution:

#include <stdio.h>

int main(void) {
    int beg, mid, end;

    printf("Enter phone number [(xxx) xxx-xxxx]: ");
    scanf(" (%d ) %d- %d", &beg, &mid, &end);
    printf("You entered %.3d.%3d.%.4d\n", beg, mid, end);

    return 0;
}
3.05

Write a program that asks the user to enter the numbers from 1 to 16 (in any
order) and then displays the numbers in a 4 by 4 arrangement, followed by the
sums of the rows, columns, and diagonals:

Enter the numbers from 1 to 16 in any order:
16 3 2 13 5 10 11 8 9 6 7 12 4 15 14 1
16  3  2 13
 5 10 11  8
 9  6  7 12
 4 15 14  1
Row sums: 34 34 34 34
Column sums: 34 34 34 34
Diagonal sums: 34 34

If the row, column, and diagonal sums are all the same (as they are in this
example), the numbers are said to form a magic square. The magic square shown
here appears in a 1514 engraving by artist and mathematician Albrecht Dürer.
(Note that the middle numbers in the last row give the date of engraving.)

Solution:

#include <stdio.h>

int main(void) {
    
    int n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15, n16;

    printf("Enter the numbers from 1 to 16 in any order:\n");
    scanf("%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d",
          &n1, &n2, &n3, &n4, &n5, &n6, &n7, &n8,
          &n9, &n10, &n11, &n12, &n13, &n14, &n15, &n16);

    printf("\n%3d%3d%3d%3d\n%3d%3d%3d%3d\n", 
           n1, n2, n3, n4, n5, n6, n7, n8);

    printf("%3d%3d%3d%3d\n%3d%3d%3d%3d\n\n", 
           n9, n10, n11, n12, n13, n14, n15, n16);

    printf("Row sums: %d %d %d %d\n", (n1 + n2 + n3 + n4), (n5 + n6 + n7 + n8),
           (n9 + n10 + n11 + n12), (n13 + n14 + n15 + n16));

    printf("Column sums: %d %d %d %d\n", 
           (n1 + n5 + n9 + n13), (n2 + n6 + n10 + n14),
           (n3 + n7 + n11 + n15), (n4 + n8 + n12 + n16));

    printf("Diagonal sums: %d %d\n",
           (n1 + n6 + n11 + n16), (n4 + n7 + n10 + n13));
    
    return 0;
}
3.06

Modify the addfrac.c program of Section 3.2 so that the user enters both
fractions at the same time, separated by a plus sign:

Enter two fractions separated by a plus sign: 5/6+3/4
The sum is 38/24

Solution:

/* Adds two fractions */

#include <stdio.h>

int main(void) {
    int num1, denom1, num2, denom2, result_num, result_denom;

    printf("Enter two fractions separated by a plus sign: ");
    scanf("%d /%d +%d /%d", &num1, &denom1, &num2, &denom2);

    result_num = num1 * denom2 + num2 * denom1;
    result_denom = denom1 * denom2;
    printf("The sum is %d/%d\n", result_num, result_denom);

    return 0;
}

第4章 表达式

算术运算符

  • 一元运算符
    • 一元正号运算符
    • 一元负号运算符
  • 二元运算符
    • 加法类
      • +加法运算符
      • -减法运算符
    • 乘法类
      • *乘法运算符
      • /除法运算符
      • %取余运算符

注意

  • /需要注意数据类型,如果两个都是整数,会舍掉小数部分。
  • %两边都需要为整数。

关于运算符的优先级问题:用括号即可。

赋值运算符

运算符=是右结合的,所以i=j=k=0也就是i=(j=(k=0))

要保证数是同类型的,运算符=会把右边数的类型强制转换成左边类型。

运算符=要求左操作数必须是某个变量,而不能是表达式或者常量。

复合赋值

  • +=
  • -=
  • *=
  • /=

自增运算符或自减运算符

  • i++ 下一条语句自增
  • i-- 下一条语句自减
  • ++i 立即自增
  • --i 立即自减

表达式求值

关于表达式,我们应当避免未定义行为

例如

a = 5
c = (b=a+2) - (a=1)

问题关键就在于(b=a+2)(a=1)是同级的,程序在执行时不会确定谁先谁后,导致结果不确定,因此我们应当避免同级语句有相关性。
又如j=i*i++++优先级高于*因此ii++是同级别的,所以没法确定最终结果。

表达式语句

表达式语句最终需要赋值才有意义,否则运算后的结果会被丢弃。

exercise & project

exercise

4.01

Show the output produced by each of the following program fragments. Assume that
i, j, and k are int variables.

(a) i = 5; j = 3;
    printf("%d %d", i / j, i % j);
(b) i = 2; j = 3;
    printf("%d", (i + 10) % j);
(c) i = 7; j = 8; k = 9;
    printf("%d", (i + 10) % k / j);
(d) i = 1; j = 2; k = 3;
    printf("%d", (i + 5) % (j + 2) / k);

Solution:

(a) 1 2  
(b) 0  
(c) 1  
(d) 0
4.02

If i and j are positive integers, does (-i)/j always have the same value
as -(i/j)? Justify your answer.

Solution

No. The C89 and C99 standards implement division of negative numbers
differently: (-9)/7 can produce -1 or -2 in C89, while -(9/7) will always
produce -1. C99 will always truncate the remainder towards zero, however, so the
answers produced by (-i)/j and -(i/j) will be equivalent.

4.03

What is the value of each of the following expressions in C89? (Give all
possible values if an expression may have more than one value.)

(a) 8 / 5
(b) -8 / 5
(c) 8 / -5
(d) -8 / -5

Solution

(a) 1  
(b) -1 or -2  
(c) -1 or -2  
(d) 1 or 2
4.04

Repeat Exercise 3 for C99.

Solution

(a) 1  
(b) -1  
(c) -1  
(d) 1
4.05

What is the value of each of the following expressions in C89? (Give all
possible values if an expression may have more than one value.)

(a) 8 % 5  
(b) -8 % 5  
(c) 8 % -5  
(d) -8 % -5

Solution

(a) 3  
(b) -3 or 5  
(c) 3 or -5  
(d) 3 or 5
4.06

Repeat Exercise 5 for C99.

Solution

(a) 1  
(b) -3  
(c) 3  
(d) -3
4.07

The algorithm for computing the UPC check digit ends with the following steps:

Subtract 1 from the total.
Compute the remainder when the adjusted total is divided by 10.
Subtract the remainder from 9.

It's tempting to try to simplify the algorithm by using these steps instead:

Compute the remainder when the total is divided by 10.
Subtract the remainder from 10.

Why doesn't this work?

Solution

The second, "simplified" algorithm could produce a check digit of 10, which
would not be valid.

4.08

Would the upc.c program still work if the expression 9 - ((total - 1) % 10)
were replaced by (10 - (total % 10)) % 10?

Solution

Yes, both expressions would produce equal answers.

4.09

Show the output produced by the following program fragments. Assume that i,
j, and k are int variables.

(a) i = 7; j = 8;
    i *= j + 1;
    printf("%d %d", i, j);
(b) i = j = k = 1;
    i += j += k;
    printf("%d %d %d", i, j, k);
(c) i = 1; j = 2; k = 3;
    i -= j -= k;
    printf("%d %d %d", i, j, k);
(d) i = 2; j = 1; k = 0;
    i *= j *= k;
    printf("%d %d %d", i, j, k);

Solution

(a) 63 8  
(b) 3 2 1  
(c) 2 -1 3  
(d) 0 0 0
4.10

Show the output produced by each of the following program fragments. Assume that
i and j are int variables.

(a) i = 6;
    j = i += i;
    printf("%d %d", i, j);
(b) i = 5;
    j = (i -= 2) + 1;
    printf("%d %d", i, j);
(c) i = 7;
    j = 6 + (i = 2.5);
    printf("%d %d", i, j);
(d) i = 2; j = 8;
    j = (i = 6) + (j = 3);
    printf("%d %d", i, j);

Solution

(a) 12 12  
(b) 3 4  
(c) 2 9  
(d) 6 9
4.11

Show the output produced by each of the following program fragments. Assume that
i, j, and k are int variables.

(a) i = 1;
    printf("%d ", i++ - 1);
    printf("%d", i);
(b) i = 10; j = 5;
    printf("%d ", i++ - ++j);
    printf("%d %d", i, j);
(c) i = 7; j = 8;
    printf("%d ", i++ - --j);
    printf("%d %d", i, j);
(d) i = 3; j = 4; k = 5;
    printf("%d ", i++ - j++ + --k);
    printf("%d %d %d", i, j, k);

Solution

(a) 0 2  
(b) 4 11 6  
(c) 0 8 7  
(d) 3 4 5 4
4.12

Show the output produced by each of the following program fragments. Assume that
i and j are int variables.

(a) i = 5;
    j = ++i * 3 - 2;
    printf("%d %d", i, j);
(b) i = 5;
    j = 3 - 2 * i++;
    printf("%d %d", i, j);
(c) i = 7;
    j = 3 * i-- + 2;
    printf("%d %d", i, j);
(d) i = 7;
    j = 3 + --i * 2;
    printf("%d %d", i, j);

Solution

(a) 6 16  
(b) 6 -7  
(c) 6 23  
(d) 6 15
4.13

Only one of the expressions ++i and i++ is exactly the same as (i += 1);
which is it? Justify your answer.

Solution

The prefix increment operator ++i is equivalent to (i += 1) because the
value is immediately read as i + 1, unlike the postfix operator, which applies
the assignment but does not read the value immediately as i + 1 but as i.

4.14

Supply parentheses to show how a C compiler would interpret each of the
following expressions.

(a) a * b - c * d + e
(b) a / b % c / d
(c) - a - b + c - + d
(d) a * - b / c - d

Solution

(a) (((a * b) - (c * d)) + e)
(b) (((a / b) % c) / d)
(c) ((((- a) - b) + c) - (+ d))
(d) (((a * (- b)) / c) - d)
4.15

Give the values of i and j after each of the following expression statements
has been executed. (Assume that i has the value 1 initially and j has the
value 2.)

(a) `i += j;`  
(b) `i--;`  
(c) `i * j / i;`  
(d) `i % ++j;`

Solution

(a) 3, 2  
(b) 0, 2  
(c) 1, 2  
(d) 1, 3

project

4.01

Write a program that asks the user to enter a two-digit number, then prints the
number with its digits reversed. A session with the program should have the
following appearance:

Enter a two-digit number: 28
The reversal is: 82

Read the number using %d, then break it into two digits. Hint: If n is an
integer, then n % 10 is the last digit in n and n / 10 is n with the
last digit removed.

Solution


#include <stdio.h>

int main(void) {

    int n = 0;

    printf("Enter a two-digit number: ");
    scanf("%d", &n);

    printf("The reversal is: %d%d\n", n % 10, n / 10);

    return 0;

4.02

Extend the program in Programming Project 1 to handle three-digit numbers.

Solution

#include <stdio.h>

int main(void) {

    int n = 0;

    printf("Enter a three-digit number: ");
    scanf("%d", &n);

    printf("The reversal is: %d%d%d\n", n % 10, n / 10 % 10, n / 100);

    return 0;
}

4.03

Rewrite the program in Programming Project 2 so that it prints the reversal of a
three-digit number without using arithmeic to split the number into digits.
Hint: See the upc.c program of Section 4.1.

Solution

#include <stdio.h>

int main(void) {

    int n1, n2, n3;

    printf("Enter a three-digit number: ");
    scanf("%1d%1d%1d", &n1, &n2, &n3);

    printf("The reversal is: %d%d%d\n", n3, n2, n1);

    return 0;
}

4.04

Write a program that reads an integer entered by the user and displays it in
octal (base 8):

Enter a number between 0 and 32767: 1953
In octal, your number is: 03641

The output should be displayed using five digits, even if fewer digits are
sufficient. Hint: To convert the number to octal, first divide it by 8; the
remainder is the last digit of the octal number (1, in this case). Then divide
the original number by 8 and repeat the process to arrive at the next-to-last
digit. (printf is capable of displaying numbers in base 8, as we'll see in
Chapter 7, so there's actually an easier way to write this program.)

Solution

#include <stdio.h>

int main(void) 
{
    int n;
    
    printf("Enter a number between 0 and 32767: "); 
    scanf("%d", &n);
  
    printf("In octal, your number is: %d%d%d%d%d\n", 
           (n/4096)%8, 
           (n/512)%8, 
           (n/64)%8, 
           (n/8)%8, 
           n%8);
    
  return 0;
}
4.05

Rewrite the upc.c program of Section 4.1 so that the user enters 11 digits at
one time, instead of entering one digit, then five digits, and then another five
digits.

Enter the first 11 digits of a UPC: 01380015173
Check digit: 5

Solution

/* Computes a Universal Product Code check digit */

#include <stdio.h>

int main(void) {

    int d, i1, i2, i3, i4, i5, j1, j2, j3, j4, j5,
        first_sum, second_sum, total;

    printf("Enter the first 11 digits of a UPC: ");
    scanf("%1d%1d%1d%1d%1d%1d%1d%1d%1d%1d%1d",
          &d, &i1, &i2, &i3, &i4, &i5, &j1, &j2, &j3, &j4, &j5);

    first_sum = d + i2 + i4 + j1 + j3 + j5;
    second_sum = i1 + i3 + i5 + j2 + j4;
    total = 3 * first_sum + second_sum;

    printf("Check digit: %d\n", 9 - ((total - 1) % 10));

    return 0;
}


4.06

European countries use a 13-digit code, known as a European Article Number (EAN)
instead of the 12-digit Universal Product Code (UPC) found in North America.
Each EAN ends with a check digit, just as UPC does. The technique for
calculating the check digit is also similar:

Add the second, fourth, sixth, eighth, tenth and twelfth digits.
Add the first, third, fifth, seventh, ninth, and eleventh digits.
Multiply the first sum by 3 and add it to the second sum.
Subtract 1 from the total.
Compute the remainder when the adjusted total is divided by 10.
Subtract the remainder from 9.

For example, consider Güllüoglu Turkish Delight Pistachio & Coconut, which has
an EAN of 86914842660008. The first sum is 6 + 1 + 8 + 2 + 0 + 0 = 17, and the
second sum is 8 + 9 + 4 + 4 + 6 + 0 = 31. Multiplying the first sum by 3 and
adding the second yields 82. Subtracting 1 gives 81. The remainder upon dividing
by 10 is 1. When the remainder is subtracted from 9, the result is 8, which
matches the last digit of the original code. Your job is to modify the upc.c
program of Section 4.1 so that it calculates the check digit for an EAN. The
user will enter the first 12 digits of the EAN as a single number:

Enter the first 12 digits of an EAN: 869148426000
Check digit: 8

Solution


#include <stdio.h>

int main(void) {

    int n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, sum1, sum2, total;

    printf("Enter the first 12 digits of an EAN: ");
    scanf("%1d%1d%1d%1d%1d%1d%1d%1d%1d%1d%1d%1d",
          &n1, &n2, &n3, &n4, &n5, &n6, &n7, &n8, &n9, &n10, &n11, &n12);

    sum1 = n2 + n4 + n6 + n8 + n10 + n12;
    sum2 = n1 + n3 + n5 + n7 + n9 + n11;
    total = 3 * sum1 + sum2;

    printf("Check digit: %d\n", 9 - ((total - 1) % 10));

    return 0;
}


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM