《C Primer Plus》第16章复习题与编程练习

《C Primer Plus》第16章复习题与编程练习

  • 复习题
    • 1. 下面的几组代码由一个或多个宏组成,其后是使用宏的源代码。在每种情况下代码的结果是什么?这些代码是否是有效代码?(假设其中的变量已声明)
    • 2. 修改复习题1中d部分的定义,使其更可靠
    • 3. 定义一个宏函数,返回两值中的较小值
    • 4. 定义EVEN_GT(X, Y)宏,如果X为偶数且大于Y,该宏返回1
    • 5. 定义一个宏函数,打印两个表达式及其值。
    • 6. 创建#define指令完成下面的任务。
    • 7. 定义一个宏,以下面的格式打印名称、值和int类型变量的地址:
    • 8. 假设在测试程序时要暂时跳过一块代码,如何在不移除这块代码的前提下完成这项任务?
    • 9. 编写一段代码,如果定义了PR_DATE宏,则打印预处理的日期
    • 10. 内联函数部分讨论了3种不同版本的square()函数。从行为方面看,这3种版本的函数有何不同?
    • 11. 创建一个使用泛型选择表达式的宏,如果宏参数是_Bool类型,对"boolean"求值,否则对"not boolean"求值
    • 12. 下面的程序有什么错误
    • 13. 假设 scores 是内含 1000 个 int 类型元素的数组,要按降序排序该数组中的值。假设你使用qsort()和comp()比较函数。
    • 14. 假设data1是内含100个double类型元素的数组,data2是内含300个double类型元素的数组。
  • 编程练习
    • 1. 开发一个包含你需要的预处理器定义的头文件
    • 2. 调和平均数的宏定义
    • 3. 极坐标变换
    • 4. clock()函数
    • 5. 从数组中随机选择指定数量的元素,并打印它们
    • 6. 修改程序清单16.17,使用struct names元素
    • 7. show_array()和new_d_array()函数

复习题

1. 下面的几组代码由一个或多个宏组成,其后是使用宏的源代码。在每种情况下代码的结果是什么?这些代码是否是有效代码?(假设其中的变量已声明)

a.

#define FPM 5280 /*每英里的英尺数*/ 
dist = FPM * miles; 

b.

#define FEET 4 
#define POD FEET + FEET 
plort = FEET * POD; 

c.

#define SIX = 6; 
nex = SIX; 

d.

#define NEW(X) X + 5 
y = NEW(y); 
berg = NEW(berg) * lob; 
est = NEW(berg) / NEW(y); 
nilp = lob * NEW(-berg);

答:

a.

有效。dist = 5280 * miles

b.

有效。plort = 4 * 4 + 4

c.

无效。

d.

有效。y = y + 5
有效,但可能有误。est = berg + 5 * lob
有效,但可能有误。est = breg + 5 / y + 5
有效(传递进去的是负值不是一个符号加变量)。 lob * (-berg) + 5

2. 修改复习题1中d部分的定义,使其更可靠

答:

#define NEW(X) ((X) + 5)//尽可能地多使用括号将宏函数的变量括起

3. 定义一个宏函数,返回两值中的较小值

#define MIN(X, Y) ((X) > (Y) ? (Y) : (X))

4. 定义EVEN_GT(X, Y)宏,如果X为偶数且大于Y,该宏返回1

#define EVEN_GT(X, Y) ((X) % 2 == 0 && (X) > (Y) ? 1 : 0)

5. 定义一个宏函数,打印两个表达式及其值。

例如,若参数为3 + 4和4 * 12,则打印:

3 + 4 is 7 and 4 * 12 is 48

答:

#define SHOW(X, Y) printf(#X " is %d and " #Y " is %d\n", X, Y)

6. 创建#define指令完成下面的任务。

a.创建一个值为25的命名常量。
b.SPACE表示空格字符。
c.PS()代表打印空格字符。
d.BIG(X)代表X的值加3。
e.SUMSQ(X, Y)代表X和Y的平方和。

答:

a. #define SIZE 25
b. #define SPACE ’ ’
c. #define PS() printf(" ")
d. #define BIG(X) ((X) += 3)
e. #define SUMSQ(X,Y) ((X)(X)+(Y)(Y))

7. 定义一个宏,以下面的格式打印名称、值和int类型变量的地址:

name: fop; value: 23; address: ff464016

答:

#define SHOW(X) printf(“name:”#X";value:%d;address:%p", X, &X)

8. 假设在测试程序时要暂时跳过一块代码,如何在不移除这块代码的前提下完成这项任务?

#define DROP//如果不需要跳过代码,则删除该指令
#ifndef DROP
/*被跳过的代码块*/
#endif

9. 编写一段代码,如果定义了PR_DATE宏,则打印预处理的日期

#ifdef PR_DATE
	printf("%s\n", _ _DATE_ _);
#endif

10. 内联函数部分讨论了3种不同版本的square()函数。从行为方面看,这3种版本的函数有何不同?

第一个正常返回一个double类型的数,输入1.3时,返回值为1.69。
第二个在返回之前将结果强制转化为了int型,丢失精度。在返回转换时,返回值的小数部分全为0,输入1.3时,程序中返回值为1
第三个也在返回之前也将结果强制转化为int型,但在强制转化前结果加上了0.5,当输入为1.3时,返回值为2,输入为1.2时,返回值为1,以此来判断是调用了哪一个函数

11. 创建一个使用泛型选择表达式的宏,如果宏参数是_Bool类型,对"boolean"求值,否则对"not boolean"求值

答:

#define BOOL(X) _Generic((X), _Bool : "boolean", default : "not boolean")

12. 下面的程序有什么错误

#include  
int main(int argc, char argv[]) 
{ 
    printf("The square root of %f is %f\n", argv[1],sqrt(argv[1]) ); 
}

答:

argv[] 应该改为 *argv[]
第一个%f应该改为%s
第二个argv[1]应当使用类似于atof()的函数转换为float型
应当在头文件中加上math.h
程序在使用sqrt应该排除参数是负数

13. 假设 scores 是内含 1000 个 int 类型元素的数组,要按降序排序该数组中的值。假设你使用qsort()和comp()比较函数。

a.如何正确调用qsort()?
b.如何正确定义comp()?

答:

a.

qsort((void*)scores, (size_t)1000, sizeof(int), comp);

b.

int comp(const void *a, const void *b)
{
    return (*(int*)a) - (*(int*)b);
}

14. 假设data1是内含100个double类型元素的数组,data2是内含300个double类型元素的数组。

a.编写memcpy()的函数调用,把data2中的前100个元素拷贝到data1中。
b.编写memcpy()的函数调用,把data2中的后100个元素拷贝到data1中。

答:

a. memcpy(data1, data2, 100 * sizeof(double));
b. memcpy(data1, data2 + 200, 100 * sizeof(double));

编程练习

1. 开发一个包含你需要的预处理器定义的头文件

代码:

#ifndef DRAFT_ALLDEFINE_H
#define DRAFT_ALLDEFINE_H

#include 
#include 
#include 
#include 
#include 
#include 

#define MAX(X, Y) ((X) > (Y) ? (X) : (Y))
#define MIN(X, Y) ((X) > (Y) ? (Y) : (X))

#endif // !DRAFT_ALLDEFINE_H

2. 调和平均数的宏定义

两数的调和平均数这样计算:先得到两数的倒数,然后计算两个倒数的平均值,最后取计算结果的倒数。使用#define指令定义一个宏“函数”,执行该运算。编写一个简单的程序测试该宏。

代码:

#include 
#include 

#define HARMONIC_MEAN(X, Y) 2 / (1 / (X) + 1 / (Y))

int main()
{
    float a, b;
    printf("Please give me two numbers, and I'will calculate the harmonic mean: ");
    scanf("%f %f", &a, &b);

    printf("The harmonic mean of %.2f and %.2f is %.2f.\n", a, b, HARMONIC_MEAN(a, b));

    system("pause");
    return 0;
}

运行结果:

《C Primer Plus》第16章复习题与编程练习_第1张图片

3. 极坐标变换

极坐标用向量的模(即向量的长度)和向量相对x轴逆时针旋转的角度来描述该向量。直角坐标用向量的x轴和y轴的坐标来描述该向量(见图16.3)。编写一个程序,读取向量的模和角度(单位:度),然后显示x轴和y轴的坐标。相关方程如下:

x = r*cos A
y = r*sin A

需要一个函数来完成转换,该函数接受一个包含极坐标的结构,并返回一个包含直角坐标的结构(或返回指向该结构的指针)。

代码:

#include 
#include 
#include 

#define PI 3.1415926

struct Rectangular translate(struct Polar p);
void show_polar(const struct Polar p);
void show_rectangular(const struct Rectangular r);

struct Polar // 极坐标
{
    float r;
    float A;
};

struct Rectangular // 直角坐标
{
    float x;
    float y;
};

int main()
{
    struct Polar polar;
    struct Rectangular rec;

    printf("please input the length and angle of the vector:\n");
    scanf("%f %f", &polar.r, &polar.A);
    show_polar(polar);
    rec = translate(polar);
    show_rectangular(rec);

    system("pause");
    return 0;
}

struct Rectangular translate(struct Polar p)
{
    struct Rectangular r;

    r.x = p.r * cos(p.A * PI / 180.0);
    r.y = p.r * sin(p.A * PI / 180.0);

    return r;
}

void show_polar(const struct Polar p)
{
    printf("length: %.2f, angle: %.2f°\n", p.r, p.A);
}

void show_rectangular(const struct Rectangular r)
{
    printf("x: %.2f, y: %.2f\n", r.x, r.y);
}

运行结果:

《C Primer Plus》第16章复习题与编程练习_第2张图片

4. clock()函数

ANSI库这样描述clock()函数的特性:

#include 
clock_t clock (void);

这里,clock_t是定义在time.h中的类型。该函数返回处理器时间,其单位取决于实现(如果处理器时间不可用或无法表示,该函数将返回-1)。然而,CLOCKS_PER_SEC(也定义在time.h中)是每秒处理器时间单位的数量。因此,两个 clock()返回值的差值除以 CLOCKS_PER_SEC得到两次调用之间经过的秒数。在进行除法运算之前,把值的类型强制转换成double类型,可以将时间精确到小数点以后。编写一个函数,接受一个double类型的参数表示时间延迟数,然后在这段时间运行一个循环。编写一个简单的程序测试该函数。

代码:

#include 
#include 
#include 

void delay(double a);

int main()
{
    double a;

    printf("Enter a number of seconds(q to quit): ");
    while (scanf("%lf", &a) == 1)
    {
        delay(a);
        printf("Enter a number of seconds(q to quit): ");
    }
    printf("Bye!\n");
    system("pause");
    return 0;
}

void delay(double a)
{
    double s = (double)clock();
    double f = 0;
    while ((a - f) > 0.00000001)
    {
        f = ((double)clock() - s) / CLOCKS_PER_SEC;
    }
    printf("%.2lfs have passed.\n", f);
}

运行结果:

《C Primer Plus》第16章复习题与编程练习_第3张图片

5. 从数组中随机选择指定数量的元素,并打印它们

编写一个函数接受这些参数:内含int类型元素的数组名、数组的大小和一个代表选取次数的值。该函数从数组中随机选择指定数量的元素,并打印它们。每个元素只能选择一次(模拟抽奖数字或挑选陪审团成员)。另外,如果你的实现有time()(第12章讨论过)或类似的函数,可在srand()中使用这个函数的输出来初始化随机数生成器rand()。编写一个简单的程序测试该函数。

代码:

#include 
#include 
#include 

#define LEN 10

void Print_sd(int *, int, int);
int Find_df(int *, int);

int main()
{
    srand(time(0));

    int data[LEN] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
    int count;

    printf("Enter a number, I'll pick you randomly(enter q to quit):\n");
    while (scanf("%d", &count) && count <= 10)
    {
        // printf("%d", count);
        Print_sd(data, LEN, count);
    }

    printf("Bye!\n");

    system("pause");
    return 0;
}

void Print_sd(int *ar, int n, int count)
{
    int index[LEN] = {0};
    int i = 0;

    printf("The result of random selection: ");
    while (i < count)
    {
        index[i] = Find_df(index, n);
        // printf("%d ", index[i]);
        printf("%d ", ar[index[i] - 1]);
        i++;
    }
    printf("\n");
}

int Find_df(int *index, int n)
{
    int key = rand() % 10 + 1;

    //    printf("%d", key);
    for (int i = 0; i < n; i++)
        if (key == index[i]) // 如果找到相同的下标,就向下递归
        {
            key = Find_df(index, n);
            break;
        }

    return key;
}

运行结果:

《C Primer Plus》第16章复习题与编程练习_第4张图片

6. 修改程序清单16.17,使用struct names元素

修改程序清单16.17,使用struct names元素(在程序清单16.17后面的讨论中定义过),而不是double类型的数组。使用较少的元素,并用选定的名字显式初始化数组。

代码:

#include 
#include 
#include 
#include 

#define NUM 100
#define LEN 40

struct Name
{
    char first[LEN];
    char last[LEN];
};

struct Name staff[NUM];

void fillarray(struct Name ar[], int n);
void showarray(const struct Name ar[], int n);
int mycomp(const void *p1, const void *p2);

int main()
{
    fillarray(staff, NUM);
    puts("Random list:");
    showarray(staff, NUM);
    qsort((void *)staff, (size_t)NUM, sizeof(struct Name), mycomp);
    puts("\nSorted list:");
    showarray(staff, NUM);

    system("pause");
    return 0;
}

void fillarray(struct Name ar[], int n)
{
    srand((unsigned long)time(0));

    for (int i = 0; i < n; i++)
    {
        int firstLen = rand() % 10 + 1;
        int lastLen = rand() % 10 + 1;
        // 随机生成first
        for (int j = 0; j < firstLen; j++)
        {
            ar[i].first[j] = rand() % 26 + 'a';
        }
        // 随机生成last
        for (int j = 0; j < lastLen; j++)
        {
            ar[i].last[j] = rand() % 26 + 'a';
        }
    }
}

void showarray(const struct Name ar[], int n)
{
    int i;

    for (i = 0; i < n; i++)
    {
        printf("%10s.%-10s ", ar[i].first, ar[i].last);
        if (i % 4 == 3)
            putchar('\n');
    }
    if (i % 4 != 0)
        putchar('\n');
}

int mycomp(const void *p1, const void *p2)
{
    const struct Name *ps1 = (const struct Name *)p1;
    const struct Name *ps2 = (const struct Name *)p2;
    int res = strcmp(ps1->last, ps2->last);

    if (res != 0)
        return res;
    else
        return strcmp(ps1->first, ps2->first);
}

运行结果:

C:\Users\81228\Documents\Program\VScode C Program\chapter16>16.6
Random list:
 zljeezddl.in              cwytt.hdtagwq    xmeukcamly.vjkgkkii         npuh.hrhvis     
  caxadvqb.lf                asf.puhpvvd       ldidgum.g            lctizmdm.rnr        
  ipdafwiv.bcaofo     vvabbuqylv.bm              rdipz.soahbrqg       ovnnzv.g
  kpjekesh.jhzmnmwh    dpzmepdnw.enkmhjz        cqoemj.nbojoonr         mcqm.clqauva    
      csqr.ovlmxyuamf       jiyp.mlnhp          zmadux.stszk         ycohuah.qpy        
       gie.dgg         tfgglmtcb.ozcmibpkpa   uwcfxxcm.hvujzr          bovtp.xrmyadnd
   enqnrlz.jkzmxbsi       ntxnyw.uhpum      uobllmhluj.ixwhn           zshca.lsuokfu
    osqrvl.ccilrqfl   svcennyfwx.zzyycfiix     uqwoxrh.v                  og.hzssx
     rdswg.k               joktr.edm          pttefhmm.ki                 mi.cip
   mhielxt.qdjzixk     rvchhwiyy.gj              nvsui.zreupwvm   qgvrutmbao.z
     itoeq.jrnoxil             z.fnlq         eyoyblsp.jxqoaupbfo    eysgmne.egcezy     
  upumzuhb.i               xwbgj.s                  lq.pl                 cy.baqbirsxx
         i.kwr          foktbczo.gi              qvfqh.pcg           avwnrye.xjpg
      jzfe.z               bznxq.gfcqkvhbp           w.agmzauzcml vbswqcdook.thxhrruanf
     xtcqq.trxnctf         qxgok.iefpavd          ixym.vgyviq            ryv.rcurez
     kashj.vlf        hpertiqynm.pk            unsoezl.ioqph        mzmmxiao.wzmwluvk
      bbnr.mihjc           gtgvz.iccmltrru         xfu.qc                 fv.dzbk
    trixyn.idcat              vu.oyjielzi         isnt.yagoiaity   qkydpctgw.ngppmnkex
ymhafpltrz.ziyifn              q.c          epbanewzmw.jd            rbetyax.ujpqpliz
fwvjhpterm.th              zzxli.agikkic      nlooufyt.pp                  d.hkyye
      tgxt.vffv        ubsbanlok.kpoxdgp         tmicu.q                   l.l
     xxwez.ozqd       myxzsgwjyg.bbwygsi      ktqrvbmt.ro              sssuf.xx
         s.agmdsk           wlpo.bipdjysce           q.mb             mvemkw.dbyh
   jvestub.aqi           plwttjy.dy                 sn.answyswc        qpbht.kxlm
         w.nwdvd             ifa.cjeqsvfat    qqesohik.bn         thdydiqblr.elyas

Sorted list:
     zzxli.agikkic             s.agmdsk              w.agmzauzcml         sn.answyswc
   jvestub.aqi                cy.baqbirsxx  myxzsgwjyg.bbwygsi      ipdafwiv.bcaofo
      wlpo.bipdjysce  vvabbuqylv.bm           qqesohik.bn                  q.c
    osqrvl.ccilrqfl           mi.cip               ifa.cjeqsvfat        mcqm.clqauva
    mvemkw.dbyh              gie.dgg           plwttjy.dy                 fv.dzbk
     joktr.edm           eysgmne.egcezy     thdydiqblr.elyas       dpzmepdnw.enkmhjz    
         z.fnlq          ldidgum.g              ovnnzv.g               bznxq.gfcqkvhbp
  foktbczo.gi          rvchhwiyy.gj              cwytt.hdtagwq             d.hkyye
      npuh.hrhvis       uwcfxxcm.hvujzr             og.hzssx        upumzuhb.i
     gtgvz.iccmltrru      trixyn.idcat           qxgok.iefpavd     zljeezddl.in
   unsoezl.ioqph      uobllmhluj.ixwhn      epbanewzmw.jd           kpjekesh.jhzmnmwh
   enqnrlz.jkzmxbsi        itoeq.jrnoxil      eyoyblsp.jxqoaupbfo      rdswg.k
  pttefhmm.ki          ubsbanlok.kpoxdgp             i.kwr             qpbht.kxlm
         l.l            caxadvqb.lf              zshca.lsuokfu             q.mb
      bbnr.mihjc            jiyp.mlnhp          cqoemj.nbojoonr    qkydpctgw.ngppmnkex
         w.nwdvd            csqr.ovlmxyuamf         vu.oyjielzi    tfgglmtcb.ozcmibpkpa
     xxwez.ozqd            qvfqh.pcg        hpertiqynm.pk                 lq.pl
  nlooufyt.pp                asf.puhpvvd         tmicu.q                 xfu.qc
   mhielxt.qdjzixk       ycohuah.qpy               ryv.rcurez       lctizmdm.rnr
  ktqrvbmt.ro              xwbgj.s               rdipz.soahbrqg       zmadux.stszk
fwvjhpterm.th         vbswqcdook.thxhrruanf      xtcqq.trxnctf        ntxnyw.uhpum
   rbetyax.ujpqpliz      uqwoxrh.v                tgxt.vffv             ixym.vgyviq
xmeukcamly.vjkgkkii        kashj.vlf          mzmmxiao.wzmwluvk      avwnrye.xjpg
     bovtp.xrmyadnd        sssuf.xx               isnt.yagoiaity        jzfe.z
qgvrutmbao.z          ymhafpltrz.ziyifn          nvsui.zreupwvm   svcennyfwx.zzyycfiix
请按任意键继续. . .

C:\Users\81228\Documents\Program\VScode C Program\chapter16>

7. show_array()和new_d_array()函数

下面是使用变参函数的一个程序段:

#include 
#include 
#include 
void show_array(const double ar[], int n);
double * new_d_array(int n, ...);
int main()
{
    double * p1;
    double * p2;
    p1 = new_d_array(5, 1.2, 2.3, 3.4, 4.5, 5.6);
    p2 = new_d_array(4, 100.0, 20.00, 8.08, -1890.0);
    show_array(p1, 5);
    show_array(p2, 4);
    free(p1);
    free(p2);
    return 0;
}

new_d_array()函数接受一个int类型的参数和double类型的参数。该函数返回一个指针,指向由malloc()分配的内存块。int类型的参数指定了动态数组中的元素个数,double类型的值用于初始化元素(第1个值赋给第1个元素,以此类推)。编写show_array()和new_d_array()函数的代码,完成这个程序。

代码:

#include 
#include 
#include 

void show_array(const double ar[], int n);
double *new_d_array(int n, ...);

int main()
{
    double *p1;
    double *p2;

    p1 = new_d_array(5, 1.2, 2.3, 3.4, 4.5, 5.6);
    p2 = new_d_array(4, 100.0, 20.00, 8.08, -1890.0);
    show_array(p1, 5);
    show_array(p2, 4);
    free(p1);
    free(p2);

    system("pause");
    return 0;
}

void show_array(const double ar[], int n)
{
    for (int i = 0; i < n; ++i)
    {
        printf("%.2lf ", ar[i]);
    }
    printf("\n");
}

double *new_d_array(int n, ...)
{
    va_list ap;      // 声明一个对象储存参数
    va_start(ap, n); // 把ap初始化为参数列表
    double *array = (double *)malloc(n * sizeof(double));

    for (int i = 0; i < n; i++)
        array[i] = va_arg(ap, double); // 访问参数列表中的每一项
    va_end(ap);

    return array;
}

运行结果:

《C Primer Plus》第16章复习题与编程练习_第5张图片

你可能感兴趣的:(C,Primer,Plus,c语言,C,Primer,Plus)