C Primer Plus 第十六章 课后答案

目录

 

复习题

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

a.

b.

c.

d.

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

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

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

5.定义一个宏函数,打印两个表达式及其值。例如,若参数为3+4和4*12,则打印:

3+4 is 7 and 4*12 is 48

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

a.创建一个值为25的命名常量。

b.SPACE表示空格字符。

c.PS()代表打印空格字符。

d.BIG(X)代表X的值加3。

e.SUMSQ(X, Y)代表X和Y的平方和。

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

name: fop; value: 23; address: ff464016

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

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

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

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

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

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

a.如何正确调用qsort()?

b.如何正确定义comp()?

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

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

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

编程题

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

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

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

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

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

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

#include

clock_t clock (void);

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

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

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

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

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


复习题

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

a.

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

dist = 5280 * miles

有效

b.

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

plort = 4 * 4 + 4;

有效,但是如果想要表示4 * (4 + 4)的话应该修改POD的定义为(FEET + FEET)

c.

#define SIX = 6; 
nex = SIX; 

nex = = 6;;

无效

d.

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

y = y + 5;

有效

est = berg + 5 * lob;

有效,但可能有误

est = breg + 5 / y + 5

有效,但可能有误

nilp = 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)

//(X) % 2 == 0 && (X) > (Y)是一个完整的表达式

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)

//因为没有运算符作用于X或Y所以可以不加,括号这种东西注意就好- -

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

a.创建一个值为25的命名常量。

b.SPACE表示空格字符。

c.PS()代表打印空格字符。

d.BIG(X)代表X的值加3。

e.SUMSQ(X, Y)代表X和Y的平方和。

a. #define CON 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

#ifdef 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 <stdio.h> 
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()?

qsort(scores, 1000, sizeof(int), comp);

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(date1, &date2[200], 100 * sizeof(double));

编程题

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

#ifndef DRAFT_ALLDEFINE_H
#define DRAFT_ALLDEFINE_H

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <time.h>
#include <math.h>

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

#endif //DRAFT_ALLDEFINE_H

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

#include "alldefine.h"

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

int main()
{
    double a, b;
    scanf("%lf %lf", &a, &b);
    printf("%lf", RE(a, b));
}

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

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

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

#include "alldefine.h"

typedef struct PC
{
    double length, angle;
}PC;

typedef struct CC
{
    double x, y;
}CC;

CC trans(PC a)
{
    CC cc;
    cc.x = a.length * cos(a.angle);
    cc.y = a.length * sin(a.angle);
    return cc;
}


int main()
{
    PC pc;
    scanf("%lf %lf", &pc.length, &pc.angle);
    pc.angle *= PI / 180.0;//函数接收的是弧度- -,要转换下
    CC cc = trans(pc);
    printf("%lf %lf\n", cc.x, cc.y);
}

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

#include <time.h>

clock_t clock (void);

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

#include "alldefine.h"

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


int main()
{
    double a;
    scanf("%lf", &a);
    delay(a);
}

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

#include "alldefine.h"

void select(int a[], int l, int n)
{
    srand((unsigned long)clock());
    int *b = (int*)calloc(l, sizeof(int));
    int x;
    while(n)
    {
        x = rand() % l;
        if(b[x])
        {
            continue;
        }
        printf("%d ", a[x]);
        b[x] = 1;
        n--;
    }
}


int main()
{
    int a[50], l, n;
    scanf("%d %d", &l, &n);
    for (int i = 0; i < l; ++i) {
        scanf("%d", a + i);
    }
    select(a, l, n);
    return 0;
}

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

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

typedef struct names
{
    char first[40];
    char last[40];
}names;

names vals[100];

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

int main(void)
{
    fillarray(vals, 100);
    puts("Random list:");
    showarray(vals, 100);
    qsort(vals, 100, sizeof(names), mycomp);
    puts("\nSorted list:");
    showarray(vals, 100);
    return 0;
}

void fillarray(names ar [], int n)
{
    int index;
    int x;
    srand((unsigned long)time(0));
    for (index = 0; index < n; index++)
    {
        x = rand() % 10 + 1;
        for (int i = 0; i < x; ++i) {
            ar[index].first[i] = rand() % 26 + 'a';
        }
        x = rand() % 10 + 1;
        for (int i = 0; i < x; ++i) {
            ar[index].last[i] = rand() % 26 + 'a';
        }
    }

}

void showarray(const names ar [], int n)
{
    int index;
    for (index = 0; index < n; index++)
    {
        printf("%10s.%-10s ", ar[index].first, ar[index].last);
        if (index % 4 == 3)
            putchar('\n');
    }
    if (index % 4 != 0)
        putchar('\n');
} /* 按从小到大的顺序排序 */

int mycomp(const void * p1, const void * p2) /* 要使用指向double的指针来访问这两个值 */
{
    const names * a1 = (const names *) p1;
    const names * a2 = (const names *) p2;
    int x = strcmp(a1->first, a2->first);
    if(x)//不知道为什么返回值只返回01的话会乱序
    {
        return x;
    }
    else
    {
        return 0;
    }
}

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

#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
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 <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
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;
}

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, ...)
{
    double *re = (double*)malloc(n * sizeof(double));
    va_list list;
    va_start(list, n);
    for (int i = 0; i < n; ++i) {
        re[i] = va_arg(list, double);
    }
    va_end(list);
    return re;
}

 

  • 2
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值