1. 程式人生 > >C Primer Plus 第十二章 課後答案

C Primer Plus 第十二章 課後答案

目錄

複習題

程式設計練習

I

doing

this

複習題

1.哪些類別的變數可以成為它所在函式的區域性變數?

  1. 自動儲存類別
  2. 暫存器儲存類別
  3. 靜態、無連結儲存類別

2.哪些類別的變數在它所在程式的執行期一直存在?

  1. 靜態、無連結儲存類別
  2. 靜態、內部連結儲存類別
  3. 靜態、外部連結儲存類別

3.哪些類別的變數可以被多個檔案使用?哪些類別的變數僅限於在一個檔案中使用?

1)靜態、外部連結儲存內容

2)靜態、內部連結儲存內容

4.塊作用域變數具有什麼連結屬性?

無連結

5.extern關鍵字有什麼用途?

用於宣告,表名該變數或函式已經在別處定義了

6.考慮下面兩行程式碼,就輸出的結果而言有何異同:

int * p1 = (int *)malloc(100 * sizeof(int));

int * p1 = (int *)calloc(100, sizeof(int));

前者在分配時記憶體中儲存元素的值是未定義的,後者中的每一個元素都設定為0

7.下面的變數對哪些函式可見?程式是否有誤?

/* 檔案 1 */ 
int daisy;
int main(void) 
{ 
    int lily; 
    ...; 
} 
int petal() 
{ 
    extern int daisy, lily; 
    ...; 
}
/* 檔案 2 */ 
extern int daisy; 
static int lily; 
int rose; 
int stem() 
{ 
    int rose; 
    ...;
} 
void root() 
{
    ...;
}

1)

  1. 檔案1中daisy對main()和petal()可見,檔案2中以extern宣告的daisy才對stem()、root()可見//12.1.7  【附錄A中的答案給的是petal()中也要以extern宣告,但書上12.1.7說是可選的宣告不是必須的宣告】
  2. 檔案1中main()中的lily僅對main()函式可見
  3. 檔案2中的lily,rose對檔案2中的stem()和root()可見,其中stem()中宣告的rose只對stem()可見

2)

  1. 檔案1中lily的引用是錯誤的,不存在變數名為lily的外部連結變數

8.下面程式會列印什麼

#include <stdio.h>
char color = 'B';
void first(void);
void second(void);
int main(void)
{
    extern char color;
    printf("color in main() is %c\n", color);
    first();
    printf("color in main() is %c\n", color);
    second();
    printf("color in main() is %c\n", color);
    return 0;
}
void first(void)
{
    char color;
    color = 'R';
    printf("color in first() is %c\n", color);
}

void second(void) 
{
    color = 'G';
    printf("color in second() is %c\n", color);
}

color in main() is B

color in first() is R

color in main() is B

color in second() is G

color in main() is G

9.假設檔案的開始處有如下宣告:

static int plink;

int value_ct(const int arr[], int value, int n);

a.以上宣告表明了程式設計師的什麼意圖?

b.用const int value和const int n分別替換int value和int n,是否對主調程式的值加強保護。

a.

  1. 定義一個名為plink的內部連結的儲存變數       
  2. 定義一個函式名為value_ct的函式,該函式第一個引數為int型的陣列,且在函式執行過程中該陣列內容不可改變,第二引數和第三個引數都是int型變數,該函式返回一個int型的值

b. 否,形參的值改變並不改變實參的值

程式設計練習

1.不使用全域性變數,重寫程式清單12.4

#include <stdio.h>
#include <stdlib.h>

void critic(int * u)
{
    printf("No luck, my friend. Try again.\n");
    scanf("%d", u);
}

int main(void)
{
    int units; 
    printf("How many pounds to a firkin of butter?\n");
    scanf("%d", &units);
    while ( units != 56)
    {
        critic(&units);
    }
    printf("You must have looked it up!\n");
    return 0;
}

2.在美國,通常以英里/加侖來計算油耗;在歐洲,以升/100 公里來計算。下面是程式的一部分,提示使用者選擇計算模式(美製或公制),然後接收資料並計算油耗

如果使用者輸入了不正確的模式,程式向用戶給出提示訊息並使用上一次輸入的正確模式。請提供pe12-2a.h標頭檔案和pe12-2a.c原始檔。原始碼檔案應定義3個具有檔案作用域、內部連結的變數。一個表示模式、一個表示距離、一個表示消耗的燃料。get_info()函式根據使用者輸入的模式提示使用者輸入相應資料,並將其儲存到檔案作用域變數中。show_info()函式根據設定的模式計算並顯示油耗。可以假設使用者輸入的都是數值資料

//pe12-2a.c
#include "pe12-2a.h"

void set_mode(int n)
{
    mode = n;
}

void get_info()
{
    printf("Enter distance traveled in kilometers:");
    scanf("%lf", &km);
    printf("Enter fuel consumed in liters:");
    scanf("%lf", &fc);
}

void show_info()
{
    if(mode)
    {
        printf("Fuel consumption is %.1lf miles per gallon.\n", km / fc);
    }
    else
    {
        printf("Fuel consumption is %.2lf liters per 100 km.\n", fc / km);
    }
}
//pe12-2a.h
#ifndef DRAFT_PE12_2A_H
#define DRAFT_PE12_2A_H

#include <stdio.h>

static int mode;
static double km, fc;

void set_mode(int n);
void get_info();
void show_info();


#endif

3.重新設計程式設計練習2,要求只使用自動變數。該程式提供的使用者介面不變,即提示使用者輸入模式等。但是,函式呼叫要作相應變化

//pe12-2a.c
#include "pe12-2a.h"

void show_info(int mode)
{
    double km, fc;
    printf("Enter distance traveled in kilometers:");
    scanf("%lf", &km);
    printf("Enter fuel consumed in liters:");
    scanf("%lf", &fc);
    if(mode)
    {
        printf("Fuel consumption is %.1lf miles per gallon.\n", km / fc);
    }
    else
    {
        printf("Fuel consumption is %.2lf liters per 100 km.\n", fc / km);
    }
}
//pe12-2a.h
#ifndef DRAFT_PE12_2A_H
#define DRAFT_PE12_2A_H

#include <stdio.h>

void show_info(int mode);

#endif

4.在一個迴圈中編寫並測試一個函式,該函式返回它被呼叫的次數

#include <stdio.h>
#include <stdlib.h>

void func()
{
    static num = 0;
    printf("%d\n", ++num);
}

int main(void)
{
    int n = 0;
    scanf("%d", &n);
    while(n--)
    {
        func();
    }
    return 0;
}

5.編寫一個程式,生成100個1~10範圍內的隨機數,並以降序排列(可以把第11章的排序演算法稍加改動,便可用於整數排序,這裡僅對整數排序)

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

void qqsort(int a[], int c, int d)
{
    int s = c;
    int e = d;
    if(s < e)
    {
        int t = a[s];
        while (s < e) {
            while (s < e && a[e] <= t) {
                e--;
            }
            a[s] = a[e];
            while (s < e && a[s] >= t) {
                s++;
            }
            a[e] = a[s];
        }
        a[s] = t;
        qqsort(a, c, s - 1);
        qqsort(a, s + 1, d);
    }
}

int main()
{
    srand((unsigned int)time(0));
    int a[101];
    for(int i = 0; i < 100; i++)
    {
        a[i] = rand() % 11 + 1;
    }
    qqsort(a, 0, 99);
    for(int i = 0; i < 100; i++)
    {
        printf("%d ", a[i]);
    }
    printf("\n");
}

6.編寫一個程式,生成1000個1~10範圍內的隨機數。不用儲存或列印這些數字,僅列印每個數出現的次數。用 10 個不同的種子值執行,生成的數字出現的次數是否相同?可以使用本章自定義的函式或ANSI C的rand()和srand()函式,它們的格式相同。這是一個測試特定隨機數生成器隨機性的方法

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main()
{
    int n;
    for (int i = 0; i < 10; ++i)
    {
        n = 1000;
        srand(i);//這裡把i改成time(0)就每次結果都一樣- -?
        int *x = calloc(11, sizeof(int));
        while(n--)
        {
            x[rand() % 11 + 1]++;
        }
        for (int j = 1; j < 11; ++j) {
            printf("%d ", x[j]);
        }
        putchar('\n');
        free(x);
    }

}

7.編寫一個程式,按照程式清單12.13輸出示例後面討論的內容,修改該程式。使其輸出類似:

Enter the number of sets; enter q to stop : 18

How many sides and how many dice? 6 3

Here are 18 sets of 3 6-sided throws.

12 10 6 9 8 14 8 15 9 14 12 17 11 7 10 13 8 14

How many sets? Enter q to stop: q

//main.h
#include <stdio.h>
#include <stdlib.h>    /* 為庫函式 srand() 提供原型 */
#include <time.h>     /* 為 time() 提供原型      */
#include "diceroll.h"   /* 為roll_n_dice()提供原型,為roll_count變數提供宣告 */
int main(void)
{
    int dice, roll;
    int sides;
    int set;
    srand((unsigned int) time(0)); /* 隨機種子 */
    printf("Enter the number of sets; enter q to stop :");
    if(scanf("%d", &set) != 1)
    {
        return 0;
    }
    printf("How many sides and how many dice?");
    while (scanf("%d %d", &sides, &dice) == 2 && sides > 0 && dice > 0)
    {
        printf("Here are %d sets of 3 6-sided throws.\n", set);
        for (int i = 0; i < set; ++i)
        {
            roll = roll_n_dice(dice, sides);
            printf("%d ", roll);
        }
        putchar('\n');
    }
    printf("The rollem() function was called %d times.\n", roll_count);     /* 使用外部變數 */
    printf("GOOD FORTUNE TO YOU!\n");
    return 0;
}
//diceroll
#include "diceroll.h"
#include <stdio.h>
#include <stdlib.h>      /* 提供庫函式 rand()的原型 */
int roll_count = 0;      /* 外部連結 */
static int rollem(int sides)  /* 該函式屬於該檔案私有 */
{
    int roll;
    roll = rand() % sides + 1;
    ++roll_count;       /* 計算函式呼叫次數 */
    return roll;
}

int roll_n_dice(int dice, int sides)
{
    int d;
    int total = 0;
    if (sides < 2)
    {
        printf("Need at least 2 sides.\n");
        return -2;
    }
    if (dice < 1)
    {
        printf("Need at least 1 die.\n");
        return -1;
    }
    for (d = 0; d < dice; d++)
        total += rollem(sides);
    return total;
}
//diceroll.h
#ifndef DRAFT_DICEROLL_H
#define DRAFT_DICEROLL_H

//diceroll.h
extern int roll_count;
int roll_n_dice(int dice, int sides);

#endif //DRAFT_DICEROLL_H

8.下面是程式的一部分:

// pe12-8.c #include 
#incude <stdio.h> 
int * make_array(int elem, int val); 
void show_array(const int ar [], int n); 
int main(void) 
{ 
    int * pa; 
    int size; 
    int value; 
    printf("Enter the number of elements: "); 
    while (scanf("%d", &size) == 1 && size > 0) 
    { 
        printf("Enter the initialization value: ");
        scanf("%d", &value); 
        pa = make_array(size, value); 
        if (pa) 
        { 
            show_array(pa, size); 
            free(pa); 
        } 
        printf("Enter the number of elements (<1 to quit): "); 
    } 
    printf("Done.\n"); 
    return 0;
}

提供make_array()和show_array()函式的定義,完成該程式。make_array()函式接受兩個引數,第1個引數是int型別陣列的元素個數,第2個引數是要賦給每個元素的值。該函式呼叫malloc()建立一個大小合適的陣列,將其每個元素設定為指定的值,並返回一個指向該陣列的指標。show_array()函式顯示陣列的內容,一行顯示8個數

int* make_array(int a, int b)
{
    int *p = (int*)malloc(a * sizeof(int));
    for (int i = 0; i < a; ++i) {
        p[i] = b;
    }
    return p;
}

void show_array(int *a, int b)
{
    for (int i = 0; i < b; ++i) {
        printf("%d ", a[i]);
        if((i + 1) % 8 == 0)
        {
            putchar('\n');
        }
    }
}

9.編寫一個符合以下描述的函式。首先,詢問使用者需要輸入多少個單詞。然後,接收使用者輸入的單詞,並顯示出來,使用malloc()並回答第1個問題(即要輸入多少個單詞),建立一個動態陣列,該陣列內含相應的指向char的指標(注意,由於陣列的每個元素都是指向char的指標,所以用於儲存malloc()返回值的指標應該是一個指向指標的指標,且它所指向的指標指向char)。在讀取字串時,該程式應該把單詞讀入一個臨時的char陣列,使用malloc()分配足夠的儲存空間來儲存單詞,並把地址存入該指標陣列(該陣列中每個元素都是指向 char 的指標)。然後,從臨時陣列中把單詞拷貝到動態分配的儲存空間中。因此,有一個字元指標陣列,每個指標都指向一個物件,該物件的大小正好能容納被儲存的特定單詞。下面是該程式的一個執行示例:

How many words do you wish to enter? 5

Enter 5 words now: I enjoyed doing this exerise

Here are your words:

I

enjoyed

doing

this

exercise

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


int main(void)
{
    int n;
    printf("How many words do you wish to enter?");
    scanf("%d", &n);
    printf("Enter 5 words now: ");
    char **a = (char**)malloc(n * sizeof(char*));
    for (int i = 0; i < n; ++i) {
        char b[100];
        scanf("%s", b);
        int n = strlen(b);
        char* str = (char*)malloc(n * sizeof(char));
        for (int j = 0; j < n; ++j) {
            str[j] = b[j];
        }
        a[i] = str;
    }
    for (int k = 0; k < n; ++k) {
        puts(a[k]);
    }
    return 0;
}