《C Primer Plus》中文版第十六章习题

16.17 复习题

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

a.

#define FPM 5280

dist = FPM * miles;

b.

#define FEET 4

#define POD FEET + FEET

plort = FEET * POD;

c.

#define SIX = 6;

new = 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;有效。但是如果用户需要的是4 * (4 + 4),应使用#define POD (FEET + FEET)

c. new == 6;;无效(如果两个等号之间没有空格,则有效,但是没有意义)。

d. y = y + 5;有效。 berg = berg + 5 * lob;有效。est = berg + 5/ y + 5;有效。nilp = lob * -berg + 5;有效。

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

答案:

#define NEW(X) ((X) + 5)

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

#include <stdio.h>
#define MIN(x, y) ((x < y) ? (x) : (y))
int main(void)
{int x = 5, y = 3;printf("min(%d,%d) is %d ", x, y , MIN(x, y));return 0;
}

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

#include <stdio.h>
#define EVEN_GT(X, Y) (((X) % 2 == 0) && ((X) > (Y))) ? 1 : 0
int main(void)
{int x = 6, y = 3;printf("EVEN_GT(%d,%d) is %d ", x, y, EVEN_GT(x, y));return 0;
}

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

3+4 is 7 and 4*12 is 48

#include <stdio.h>
#define PR(X, Y) printf(#X " is %d and " #Y " is %d\n", X ,Y);
int main(void)
{PR(3+4, 4*12);return 0;
}

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

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

b. SPACE表示空格字符。

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

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

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

#define NUM 25
#define SPACE ' '
#define PS() putchar(' ');
#define BIG(X) ((X) + 3)
#define SUMSQ(X, Y) ((X)*(X) + (Y)*(Y))

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

name: fop; value: 23; address: ff464016

#include <stdio.h>
#define PR(X) printf("name: " #X "; value: %d; address %p\n", X, &X);
int main(void)
{int fop = 23;PR(fop);return 0;
}

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

答案:

使用条件编译指令。一种方法是使用#ifndef:

#define _SKIP_ /*如果不需要跳过代码,则删除这条指令*/

#ifndef _SKIP_

/*需要跳过的代码*/

#endif

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

#include <stdio.h>
#define PRDATE
int main(void)
{
#ifdef PRDATEprintf("Date is %s\n", __DATE__);
#endif // PRDATEreturn 0;
}

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

答案:

第1个版本返回x*x,这只是返回了square()的double类型值。例如square(1.3)会返回1.69。

第2个版本返回(int)(x*x),计算结果被截断后返回。但是,由于该函数的返回类型是double,所以1.69先被转换成1,然后被转换成1.00。

第3个版本返回(int)(x*x +0.5),可以让函数把结果四舍五入,而不是简单的截断。1.69+0.5的2.19,然后被截断为2,然后被转换成2.00。

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

答案:

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

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

答案:

#include <stdio.h>
#include <math.h>
#include <stdlib.h>
int main(int argc, char* argv[])
{printf("The square root of %f is %f\n", argv[1], sqrt(atof(argv[1])));
}

argv参数声明改为char *argv[]类型。

命令行参数被储存为字符串,所以应把argv[1]转换成double类型,使用stdlib.h库中的atof()函数。

程序使用了sqrt函数,应包含math.h头文件。

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

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

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

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define NUM 1000
void fillarray(int ar[], int n);
void showarray(const int ar[], int n);
int mycomp(const void* p1, const void* p2);
int main(void)
{int scores[NUM];fillarray(scores, NUM);puts("Random list:");showarray(scores, NUM);qsort(scores, NUM, sizeof(int), mycomp);puts("\nSorted list:");showarray(scores, NUM);return 0;
}
void fillarray(int ar[], int n)
{srand((unsigned int) time(NULL));int index;for (index = 0; index < n; index++)ar[index] = (int)rand() ;
}
void showarray(const int ar[], int n)
{int index;for (index = 0; index < n; index++){printf("%9.4d ", ar[index]);if (index % 10 == 9)putchar('\n');}if (index % 9 != 0)putchar('\n');
}
int mycomp(const void* p1, const void* p2)
{const int* a1 = (const int*)p1;const int* a2 = (const int*)p2;if (*a1 < *a2)return -1;else if (*a1 == *a2)return 0;elsereturn 1;
}

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

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

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

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define SIZE 100
#define THIRDSIZE 300
void set_array(double* data, int num);
void show_array(const double ar[], int n);
int main(void)
{double data1[SIZE] = {0}, data2[THIRDSIZE];set_array(data2, THIRDSIZE);puts("values (original data):");show_array(data1, SIZE);memcpy(data1, data2, SIZE * sizeof(double));puts("Using memcpy() (0 - 100):");show_array(data1, SIZE);puts("\nUsing memcpy() (200 - 300):");memcpy(data1, data2 + 200 , SIZE * sizeof(double));show_array(data1, SIZE);return 0;
}
void set_array(double *data, int num)
{for (int i = 0; i < num; i++){data[i] = i;}
}
void show_array(const double ar[], int n)
{int i;for (i = 0; i < n; i++){printf("%g ", ar[i]);if (i % 10 == 9)putchar('\n');}putchar('\n');
}

16.18 编程练习

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

#ifndef NAMES_H_
#define NAMES_H_
#define LENGTH 1000
struct names_st
{char first[LENGTH];char last[LENGTH];
};
typedef struct names_st names;
char* s_gets(char* st, int n);
#endif // !NAMES_H_

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

#include <stdio.h>
#define PR(X, Y) (2.0 / ((1.0/(X))+(1.0/(Y))))
int main(void)
{double numOne, numTwo, result;printf("Please enter two double number:");scanf_s("%lf %lf", &numOne, &numTwo);result = PR(numOne, numTwo);printf("PR(%.1lf, %.1lf) is %.1lf\n", numOne, numTwo, result);return 0;
}

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

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

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

#include <stdio.h>
#include <math.h>
#define PI 3.14
typedef struct polar_v {double magnitude;double angle;
} Polar_V;
typedef struct rect_v {double x;double y;
} Rect_V;
Rect_V polar_to_rect(Polar_V);
int main(void)
{Rect_V result;Polar_V input;puts("Enter magnitude and angle; enter q to quit: ");while (scanf_s("%lf %lf", &input.magnitude, &input.angle) == 2){input.angle = input.angle * (PI / 180.0);result = polar_to_rect(input);printf("x = %0.2f, y = %0.2f\n", result.x, result.y);puts("Enter magnitude and angle; enter q to quit: ");}puts("Bye.");return 0;
}
Rect_V polar_to_rect(Polar_V pv)
{Rect_V rv;rv.x = pv.magnitude * cos(pv.angle);rv.y = pv.magnitude * sin(pv.angle);return rv;
}

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 <stdio.h>
#include <time.h>
void delay(double seconds);
int main(void)
{double seconds;printf("Enter a second to delay:");scanf_s("%lf", &seconds);delay(seconds);return 0;
}
void delay(double seconds)
{clock_t start = clock();printf("Now let's test %.1lf second delay\n", seconds);clock_t now = clock();while (((double)(now - start)) / CLOCKS_PER_SEC < seconds){now = clock();printf("You delay %.1lf second.\n", ((double)(now - start)) / CLOCKS_PER_SEC);}
}

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

#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#define SIZE 100
void select(int data[], int length, int n);
int main()
{int data[SIZE], number;printf("Enter number to selected:");scanf_s("%d", &number);for (int i = 0; i < SIZE; i++) {data[i] = i;}select(data, SIZE, number);return 0;
}
void select(int data[], int length, int n)
{srand((unsigned long)clock());printf("Start to select number.\n");int* marks = (int*)malloc(length * sizeof(int));if (marks == NULL){printf("memory allocation error!\n");return;}for (int i = 0; i < length; i++) {marks[i] = 0;}int index;while (n > 0){index = rand() % length;if (marks[index] != 0)continue;elsemarks[index] = 1;printf("Selected ID: %3d DATA: %3d\n", index, data[index]);n--;}
}

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

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NUM 4
typedef struct {char first[40];char last[40];
}names;
void fillarray(names list[], int n);
void showarray(const names list[], int n);
int mycomp(const void* p1, const void* p2);
int main(void)
{names list[NUM];fillarray(list, NUM);showarray(list, NUM);qsort(list, NUM, sizeof(names), mycomp);puts("\nSorted list:");showarray(list, NUM);return 0;
}
void fillarray(names list[], int n)
{int index;for (index = 0; index < n; index++){printf("Enter the %d stuff name:", index + 1);scanf_s("%s %s", list[index].first, sizeof(list[index].first), list[index].last, sizeof(list[index].last));}
}
void showarray(const names list[], int n)
{int index;for (index = 0; index < n; index++){printf("Stuff No %d %10s.%-10s\n", index + 1, list[index].first, list[index].last);}
}
int mycomp(const void* p1, const void* p2)
{const names* a1 = (const names*)p1;const names* a2 = (const names*)p2;int res = strcmp(a1->last, a2->last);if (res != 0)return res;elsereturn strcmp(a1->first, a2->first);
}

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(void)
{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.0, 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(void)
{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.0, 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 index = 0; index < n; index++)printf("%.2lf ", ar[index]);putchar('\n');
}
double* new_d_array(int n, ...)
{va_list ap;va_start(ap, n);double* pResult = (double*)malloc(n * sizeof(double));if (!pResult){fprintf(stderr, "Memory allocation failed\n");exit(EXIT_FAILURE);}for (int index = 0; index < n; index++)pResult[index] = va_arg(ap, double);va_end(ap);return pResult;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/diannao/58614.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

15分钟学 Go 第 26 天:基本的Web服务

第26天&#xff1a;基本的Web服务 学习目标 在这一节中&#xff0c;我们将学习如何创建一个简单的HTTP服务器。我们将介绍Go语言中的net/http包&#xff0c;具体实现一个基本的Web服务&#xff0c;同时理解HTTP请求和响应的基本概念。 1. Go的HTTP服务器概述 Go语言内置的n…

Linux·进程间通讯(管道)

从本节开始将使用vscode写代码&#xff0c;语言也切换成C&#xff0c;同时OS从centOS换成ubentu。 进程之间可能存在数据传输、资源共享、通知事件、进程控制等需求&#xff0c;但是进程又具有独立性&#xff0c;所以就需要专门的进程间通讯技术(ipc)来满足需求。进程间通讯(IP…

人工智能与伦理:我们应该如何平衡科技与人性?

内容概要 在这个瞬息万变的时代&#xff0c;人工智能的迅猛发展让我们面对前所未有的伦理困境。科技进步带来了便利&#xff0c;但同时也亟需我们反思如何对待人性。尤其是在实现算法透明性时&#xff0c;我们要确保每一个决策背后都能被理解与追溯&#xff0c;这不仅是对技术…

云服务器排查微信支付接口异常

1.官方文章 网络云排查工具安装方法 - 腾讯客服 2.官方文章 网络云排查工具使用常见场景以及排查方法 - 腾讯客服 3.商户平台查看 网络波动和实际接口日志出问题时间对照

前端内存空间(堆、栈、队列、拷贝、垃圾回收)

在了解前端内存空间前&#xff0c;我们先学习三种基本数据结构&#xff1a;堆、栈、队列。 栈 栈是一种线性的数据结构&#xff0c;它遵循后进先出&#xff08;LIFO&#xff09;的原则。栈的特点是只能在栈顶进行插入和删除操作&#xff0c;因此栈的底部是栈中的最小值。 栈是…

浮动+flex布局

一.浮动 1.介绍 2.效果 <style> .one{ width: 100px; height: 100px; background-color: red; float: left; } .two{ width: 200px; height: 200px; background-color: blue; float: right; } </style> </head> <body> <div class"one&quo…

安全日志记录的重要性

1024程序员节不仅是对技术的庆祝&#xff0c;也是我们审视自己工作中责任的重要时刻。在现代信息安全体系中&#xff0c;安全日志记录是最关键的环节之一。它不仅能帮助企业或开发者及时发现安全威胁&#xff0c;还能在事后追踪攻击源、分析事件并采取补救措施。因此&#xff0…

架构师备考-系统分析与设计(结构化方法)

定义 1978年&#xff0c;E.Yourdon 和 L.L.Constantine 提出了结构化方法&#xff0c;即 SASD 方法&#xff0c;也可称为面向功能的软件开发方法或面向数据流的软件开发方法。Yourdon 方法是20世纪80年代使用最广泛的软件开发方法。 结构化方法提出了一组提高软件结构合…

正点原子阿尔法ARM开发板-IMX6ULL(十二)——驱动开发的简单介绍

文章目录 一、前言二、Linux驱动开发思维三、驱动开发分类四、应用程序和驱动的交互原理五、字符设备驱动开发流程 一、前言 也终于是到了这个最是激动人心的时刻了&#xff0c;那个也是从本科&#xff0c;就听说过的词汇&#xff0c;非常的让人神往&#xff0c;这个词对我而言…

人工智能原理实验二:搜索方法

一、实验目的 本实验课程是计算机、智能、物联网等专业学生的一门专业课程&#xff0c;通过实验&#xff0c;帮助学生更好地掌握人工智能相关概念、技术、原理、应用等&#xff1b;通过实验提高学生编写实验报告、总结实验结果的能力&#xff1b;使学生对智能程序、智能算法等…

Chromium 中chrome.fontSettings扩展接口定义c++

一、chrome.fontSettings 使用 chrome.fontSettings API 管理 Chrome 的字体设置。 权限 fontSettings 要使用 Font Settings API&#xff0c;您必须在扩展程序中声明 "fontSettings" 权限 清单。例如&#xff1a; {"name": "My Font Settings E…

npm install | npm ERR! Incorrect or missing password.

前端项目更新&#xff0c;执行npm install 安装依赖的时候&#xff0c;经常会出现一些莫名奇妙的问题&#xff0c;其中由于开发在本地编写的时候&#xff0c;可能会引用一些私有包&#xff0c;部署到服务器时就会出现问题&#xff0c;下面是排查过程。 npm ERR! code E401 npm …

C++——写一函数,将一个3x3的整型矩阵转置。用指针或引用方法处理。

没注释的源代码 #include <iostream> using namespace std; void move(int *p); int main() { int a[3][3],*p; cout<<"please input matrix:"<<endl; for(int i0;i<3;i) { for(int j0;j<3;j) { …

React + SpreadJS 开发时常见问题

在使用React与SpreadJS进行开发时&#xff0c;可能会遇到各种各样的问题。以下是一些常见的问题及其解决建议&#xff1a; 1. SpreadJS初始化失败 问题描述&#xff1a; 有时候SpreadJS的初始化可能会失败&#xff0c;特别是在React组件的生命周期内不当的初始化时机。 解决…

【AI应用】大模型工具如何助力文字创意工作(提示词Prompt+谷歌NotebookLM)

出发点&#xff1a;身处信息碎片和过载的时代&#xff0c;如何在日常工作学习中汇总并高效梳理知识&#xff1f;普通用户又如何激发AI大模型产出高质量的结果呢&#xff1f;本文将给出这两个问题的一些解决思路。 0、提纲&#xff1a; 提示词工程应知应会NotebookLM惊艳登场总…

springboot 使用 weixin-java-pay 支付demo

springboot引入依赖 <dependency><groupId>com.github.binarywang</groupId><artifactId>weixin-java-pay</artifactId><version>4.6.0</version></dependency>配置 wx:pay:appId: *********mchId: ********apiV3Key: ******…

数据安全-接口数据混合加密笔记

接口数据传输安全设计方案 采用非对称加密对称加密混合方式&#xff0c;接口混合加、解密过程梳理&#xff1a; 后端准备sm2公钥和私钥后端将SM2公钥传输到前端前端生成SM4密钥前端使用SM2公钥加密SM4秘钥&#xff0c;获得密文使用SM4秘钥加密数据将密文和加密数据传输至后端…

深入 Prometheus 监控生态 - 第六篇:与 Grafana 实现系统全面监控(健康状态和任务状态看板)

文章目录 前言部署 Grafana 和连接 Prometheus 数据源简单部署 Grafana 构建系统监控看板1. 监控信息查看2. 看板制作&#xff08;表格图&#xff09;配置表格图&#xff08;Line Chart&#xff09; 配置告警规则与通知1. Prometheus 中的告警规则2. Grafana 告警配置&#xff…

剧本杀门店预约小程序,在线一键预约体验

剧本杀作为集社交、角色扮演、休闲娱乐为一体的游戏&#xff0c;吸引了年轻人的目光。当下&#xff0c;随着市场的发展&#xff0c;剧本杀行业正面临挑战&#xff0c;对于门店来说&#xff0c;如何找到新的发展方向&#xff0c;在市场中脱颖而出是重中之重&#xff01; 线上线…

Python自动化数据备份与同步

在日常运维工作中&#xff0c;定期备份重要数据是确保业务连续性和数据安全的关键步骤。本文将介绍如何使用Python的shutil库来复制文件和目录&#xff0c;并结合schedule库实现定时执行备份任务的功能。 1. 环境准备 首先&#xff0c;我们需要安装schedule库&#xff0c;这个…