[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