3.2 库函数
3.2.1 预定义函数和代码复用
软件工程的基本目标是编写无差错代码。代码复用是实现该目标的一种方法,也就是随时重复使用已经存在并测试过的程序片段。简而言之就是“为什么要重打锣另开张?”
C语言通过提供许多预定义函数来鼓励复用,这些函数可以完成数学计算。C语言的标准数学库定义了一个sqrt函数,用于完成平方根的计算。在赋值语句中的函数调用
y= sqrt(x);
|
|||
|
|||
激活函数sqrt的代码,并传递参数x到函数中。通过函数调用可以激活该函数,而在函数执行后,函数返回结果就会取代函数调用。如果x是16.0,那么上面的赋值语句会进行下面的求值运算:
(1) x是16.0,函数sqrt计算,得到4.0。
(2) 函数返回结果4.0被赋值给y。
|

图3-6 函数sqrt作为一个“黑盒子”
如果w是9.0,赋值语句
z = 5.7 + sqrt(w);
将按照下面步骤求值:
(1) w是9.0,函数sqrt计算9.0的平方根,得到3.0。
(2) 将5.7和3.0两个值相加。
(3) z中存储相加值8.7。
例3-1 图3-7中的程序给出了输入的两个数(first和second)的平方根,以及这两个数和的平方根。因此,该程序必须调用C函数sqrt三次:
first_sqrt=sqrt(first);
second_sqrt=sqrt(second);
sum_sqrt=sqrt(first+second);
前两个函数调用中的参数是变量(first和second),而第三个调用说明函数的参数还可以是表达式(first+second)。这三个调用函数sqrt的结果都赋给一个变量。因为标准sqrt函数的定义在标准数学库中,因此程序开头要加上一条#include指令。
|
109. /* 110. * Performs three square root computations 111. */ 112. 113. #include <stdio.h> /* definitions of printf, scanf */ 114. #include <math.h> /* definition of sqrt */ 115. 116. int 117. main(void) 118. { 119. double first, second, /* input - two data values */ 120. first_sqrt, /* output - square root of first */ 121. second_sqrt, /* output - square root of second */ 122. sum_sqrt; /* output - square root of sum */ 123. 124. /* Get first number and display its square root. */ 125. printf("Enter the first number> "); 126. scanf("%lf", &first); 127. first_sqrt = sqrt(first); 128. printf("The square root of the first number is %.2f\n", first_sqrt); 129. /* Get second number and display its square root. */ 130. printf("Enter the second number> "); 131. scanf("%lf", &second); 132. second_sqrt = sqrt(second); 133. printf("The square root of the second number is %.2f\n", second_sqrt); 134. 135. /* Display the square root of the sum of the two numbers. */ 136. sum_sqrt = sqrt(first + second); 137. printf("The square root of the sum of the two numbers is %.2f\n", 138. sum_sqrt); 139. 140. return (0); 141. } Enter the first number> 9.0 The square root of the first number is 3.00 Enter the second number> 16.0 The square root of the second number is 4.00 The square root of the sum of the two numbers is 5.00 |
图3-7 平方根程序
仔细观察图3-7中的程序,会发现每一条语句都包含对库函数的调用(printf、scanf、sqrt)——这里在编写新程序时已经使用了C的预定义函数作为程序的组成部分。
3.2.2 使用灰色区分新结构
在图3-7中,将新结构所在的程序行用灰色标出,这样容易区分。在后面包含程序的图中仍会采用这样的方法。
3.2.3 C库函数
表3-1列出了一些最常用的函数及其说明,以及使用每个函数所需要的包含在#include中的标准头文件名。完整的标准库函数在附录B中列出。
表3-1 部分数学库函数
|
函 数 |
标准头文件 |
说明:示例 |
参 数 |
返回结果 |
|
abs(x) |
<stdlib.h> |
返回整数参数的绝对值:若x=-5,abs(x)=5 |
int |
int |
|
ceil(x) |
<math.h> |
返回不小于x的最小整数值:若x=45.23,ceil(x)=46.0 |
double |
double |
|
cos(x) |
<math.h> |
返回角x的余弦值:若x=0.0,cos(x)=1.0 |
double (弧度) |
double |
|
exp(x) |
<math.h> |
返回ex,其中e=2.71828…:若x=1.0,exp(x)= 2.71828 |
double |
double |
|
fabs(x) |
<math.h> |
返回double型参数的绝对值:若x=-8.432,fabs(x)=8.432 |
double |
double |
|
floor(x) |
<math.h> |
返回不大于x的最大整数:若x=45.23,floor(x)=45.0 |
double |
double |
|
log(x) |
<math.h> |
返回x的自然对数(x>0.0):若x=2.71828,log(x)=1.0 |
double |
double |
|
log10(x) |
<math.h> |
返回x以10为底的对数(x>0.0):若x=100.0,log10(x)=2.0 |
double |
double |
|
pow(x,y) |
<math.h> |
返回xy,若x是负数,y必须是整数:若x=0.16,y=0.5,pow(x,y)=0.4 |
double, double |
double |
|
sin(x) |
<math.h> |
返回角x的正弦值:若x=1.5708,sin (x)=1.0 |
double (弧度) |
double |
|
sqrt(x) |
<math.h> |
返回x的非负平方根(x≥0.0):若x=2.25,sqrt(x)=1.5 |
double |
double |
|
tan(x) |
<math.h> |
返回角x的正切值:若x=0.0,tan(x)=0.0 |
double (弧度) |
double |
如果表3-1中的某个函数被调用时的数值参数并不是参数表中列出的类型,那么该参数在使用前必须转换为要求的类型。int型的值转换为double型没有问题,但是double型的值要转换为int型就会将小数部分丢失,就如同混合类型赋值一样。例如,若以double型值-3.47调用函数abs,那么函数返回结果为int型值3。因此,对double型参数要使用库中的另一个绝对值函数(fabs)。
表3-1中的大部分函数是数学运算函数。函数log和log10的参数必须为正,而函数sqrt的参数必须为非负。函数sin、cos和tan的参数应以弧度表示,而不能以角度表示。
例3-2 利用C函数pow和sqrt计算如下的x的二次方程式的根:
当判别式(b2-4ac)大于0时,方程的两个根定义为
假设判别式大于0,那么可以用下面的赋值语句给root_1和root_2赋值。
/* Compute two roots,root_1 and root_2,for disc>0.0 */
disc=pow(b,2)-4*a*c;
root_1=(-b+sqrt(disc))/(2*a);
root_2=(-b-sqrt(disc))/(2*a);
例3-3 已知一个三角形的两条边b、c,以及它们之间的夹角α,利用下面的公式计算第三条边a(见图3-8):
要使用数学库中的余弦函数(cos),必须将参数角表示为弧度,而不是角度。为此,只要给角度乘以π/180就可以将其转换为弧度。如果用PI表示常数π,那么下面的赋值语句将计算第三边的边长:
a=sqrt(pow(b,2)+pow(c,2)
-2*b*c*cos(a*PI/180.0));

图3-8 具有未知边a的三角形
3.2.4 本节目标
C语言中还可以编写自己的函数。假设我们已经编写过函数find_area和find_circum:
函数find_area(r)返回半径为r的圆的面积。
函数find_circum(r)返回半径为r的圆的周长。
在本章前面的两个程序(见图3-3和图3-5)中可以复用这两个函数。图3-3中的程序计算圆面积和周长。语句
area=find_area(radius);
circum=find_circum(radius);
可以求出数值。每个赋值语句的表达式部分都是一个带参数radius(圆半径)的函数调用。每个函数调用后的返回值都存储在程序的输出变量中(area或circum)。
在平垫圈程序中(图3-5),可以使用语句
rim_area=find_area(edge_radius)-find_area(hole_radius);
计算垫圈的环形面积。这条语句比原来的程序语句(39~40行)更清晰一些。
练习
自测
1. 用C函数编写下列数学表达式。
a. b. loge(xy)
c. d. |xy-w/z|
2. 求出下面表达式的值:
a. floor(15.8)
b. floor(15.8+0.5)
c. ceil(-7.2)*pow(4.0,2.0)
d. sqrt(floor(fabs(-16.8)))
e. log10(1000.0)
编程
1. 编写语句,要求实现计算并显示两个double型变量x和y(|x-y|)的绝对差。
2. 编写完整的C程序,提示用户输入两个点(x1, y1)和 (x2, y2)的直角坐标,利用下面的公式计算它们之间的距离并显示:







