目录:
前言:
声明:
搭建环境:
专栏:
sqrt函数的参数与返回值:
简单的实践:
问题:
讨论:
改进:
前言:
在日常生活中,我们往往会需要使用到计算机进行庞大的运算,例如求一个数的平方根。在本章中我会教大家编写一个叫”求一个数的平方根“的程序。但我们在没学到C语言sqrt函数之前写这个程序未免有些许困难,但在学完sqrt函数后,我们会大幅度降低编写的难度,所以我们在编写”求一个数的平方根“程序时必须得要学习sqrt函数,但在学习sqrt函数之前我们必须要搭建环境才可使用sqrt函数。为什么做这个程序要学习sqrt函数呢?因为sqrt函数正是求一个数的平方根。
声明:
撰写本文章的作者是一位初一学生,平方根是作者通过预习才得知的,所以文章可能会有一些错误的地方,如有错误,希望路过的读者可以在评论区指正。
搭建环境:
我们在C语言中使用一个函数必须要包含这个函数的头文件,这是毋庸置疑的(相信但凡有一定的C语言基础的读者都会知道)。sqrt函数的头文件是<math.h>(数学头文件),所以我们先要使用“#include”这个宏来包含一个<math.h>的头文件,如下图所示:
#include<math.h>
即便我们包含了sqrt函数的头文件,但我们不单单需要有sqrt函数计算的结果,更需要一个可以输出计算结果的函数,这个函数便是printf函数,printf函数是print format(格式化输出)的缩写,它所包含的头文件是<stdio.h>(标准输入输出),我们还需要包含这个头文件才可输入输出。
#include<math.h>
#include<stdio.h>
随后我们需要搭建一个名为“main”的函数,为何要搭建这个函数呢?因为这是整个C程序的入口函数,所有的语句几乎会在main函数中执行(搭建main函数的详细方法请看作者的“C语言中的putchar函数”。虽然这篇博客重点讲的是putchar函数,但也详细讲解了搭建main函数的方法,有需要的读者请跳转此链接: C语言中的putchar函数 。即便读者不看链接博客对main函数的讲解,我们也还是会在此博客对main函数做出讲解)。
#include<math.h>
#include<stdio.h>int main(void)
{return 0;
}
(以下专栏是对main函数的解释,有经验的读者可跳过)
专栏:
解读main函数
我们创建的main函数的数据类型是int类型,并且没有参数,可在main函数的参数列表里填写“void”或不填写。随后是“{}”,“{}”包裹起来的内容称为函数体,函数体内可包含需要执行的语句。函数体中的”retrun 0;“是在大多数编译器上是可选的,也就是说在main函数中写上“retrun 0;”与不写“retrun 0;”完全等价,但为了避免语言文字的意义不明确(简称歧义),作者在此建议大家在main函数的末尾处加上“return 0;”这个语句。
搭建好环境后我们便可以正式开始学习sqrt函数。
sqrt函数的参数与返回值:
要想正确使用函数,必须正确地传递参数,要想正确地传递参数则需要知道参数的数据类型以及函数所需要的参数个数。在VS编译器中(简称:Microsoft Visual Stduio),我们只需要将鼠标的光标移动至函数之上便可以轻松知道函数所需的参数以及参数的个数,但我们在完成这一步之前必须创建一个项目才行(由于在VS编译器中创建一个项目比较简单,所以作者在这里不再阐述)。
我们将鼠标光标放置在sqrt函数上我们不难发现sqrt函数的参数是一个double类型(双精度浮点型)的变量,并且返回值的类型也是double类型的(注意:我们在传递参数时需要时刻注意参数的数据类型)。我们简单了解完了sqrt函数的参数与返回值后便可以开始下一步操作。
简单的实践:
在这里我们已经开始在制作“求一个数的平方根”的程序了,我们先试着向sqrt函数传递一个参数并输出,看看实际的结果是否与我们理想中的结果一致。譬如我们想要查询根号4的计算结果,我们可以这样做:
#include<math.h>
#include<stdio.h>int main(void)
{printf("%lf",sqrt(4));return 0;
}
我们知道根号4的结果是2,输出结果也应该是2,我们一起看看实际输出的结果是否与我们理想中输出的结果一致。
输出结果:2.000000
答案的的确确是正确的,但不知为何输出的结果小数点后会有如此多的0?这其实无关紧要,我们在意的是输出结果的正确性。上则代码理解起来有一定的难度,不过没关系!我们将会在下文一起讨论。但在讨论之前读者难免会对实例有所疑惑,所以我们在开始讨论前有必要先解答一下初学者的问题:
问题:
Q1:”sqrt函数参数的类型不是双精度浮点型吗?为什么在上文实例中sqrt函数的参数是一个整数,难道不是浮点数吗?这样传参会不会出现问题呢? “
R1:有必要在这里为提出这个问题的读者解答一下:“向sqrt函数传递浮点数是完全正确的,一点错误也没有。当然向sqrt函数传递一个整数也没有问题,因为在sqrt函数内传递一个整型变量会自动转换为双精度浮点型。那我们可不可以避免参数是整型转换为双精度浮点型的过程呢?当然可以。但我们需要对上文中的代码进行一小部分的修改:
#include<math.h>
#include<stdio.h>int main(void)
{printf("%lf",sqrt(4.0));return 0;
}
这样更改便可以避免参数是整型转换为浮点型的过程,同时代码变得更加地准确。
Q2:“printf函数内的第一个参数,也就是那个奇怪字符串(“%lf”),为什么那个奇怪字符串没有输出?取而代之的是一个数字”
R2:这个问题问的非常好!如果你只是单纯地认为这只是个奇怪的字符串似乎也没错,因为如果是第一次接触,难免会感到陌生,这非常正常。但“%lf”并不是一个奇怪的字符串,而是一个占位符,我们日常写C程序时几乎离不开它。您可以这样理解:“printf是’格式化输出‘的意思,您可以把这个占位符理解为“格式化输出”中的格式化”,它可以按照占位符的内容输出后面的参数,譬如在同一个printf函数下,第一个占位符输出的是第二个参数的内容,第二个占位符输出的是第三个参数的内容,以此类推。区分是否是占位符的方法也很简单,看一个段字符串的前面是否出现“%”(百分号),如果有,代表着这是个占位符,如果没有,则代表不是占位符。在C语言中,占位符不仅仅只有“%lf”,还有许许多多的占位符,以下表格是C语言常用的占位符,每个占位符所对应的输入输出格式都是不同的。
%d | 以整型的形式输入输出 |
%f | 以单精度浮点型的形式输入输出 |
%lf | 以双精度浮点型的形式输入输出 |
%s | 以字符串的形式输入输出 |
(如果您对上文中的实例感到疑惑,请在评论区告诉作者,作者会及时回复您并为此文章更新您所问的问题)
讨论:
为了使读者更好地理解,我们可以对上例的代码进行一个粗略的翻译(这里作者将上例的代码“搬运”到了下面当中,这样做的原因是为了避免读者回看上文)。
#include<math.h>
#include<stdio.h>int main(void)
{printf("%lf",sqrt(4.0));return 0;
}
翻译:在程序中先包含两个头文件,它们分别是:math.h(数学头文件)与stdio.h(标准输入输出头文件)。随后我们需要编写main函数,”main“函数的数据类型是int,参数的数据类型是“void”。为什么要编写“main”这个函数呢?因为它是整个C程序的入口,在main函数的函数体内有两条语句,第一条是“printf("%lf",sqrt(4.0));”,它翻译过来的意思是:“以双精度浮点型的形式对sqrt函数的返回值进行输出(注意:当一个函数作为另一个函数的参数时,程序会先将一个函数的返回值计算出来随后再传递给另一个函数的参数)。”最后一条语句是“return 0;”,函数是必须需要一个返回值的,但void类型除外,我们的这个main函数的数据类型是int,并不是void,所以main函数需要一个返回值,虽然在多数编译器是省略main函数的返回值的,但即便如此,最好将返回值加上,这是个良好的习惯!。
(注意:不要将main函数的参数列表中的void看成是main函数的数据类型)
改进:
我们其实不难发现这个程序有许多毛病,譬如说我不想要求再4的平方根了,我想试试求2的平方根,但我如何改变sqrt函数的参数呢?我直接从程序的源代码中对“4”进行更改不就好了吗?但是每求一个数的平方根都必须在程序的源代码上进行更改,这会导致效率大幅度降低,所以从长远来看,这并不是一个好的解决方案。那既然不在程序的源代码上入手,我们为什么不在控制台上入手呢?因为我们输入输出几乎都是在控制台上进行的。所以我们可以将我们要求的平方根数写入进一个变量中,最后将它送入sqrt函数中并使用printf函数输出,显然这是一个好办法,既避免了对程序的源代码上进行更改并且提升了源代码的稳定性。这显然是一个好的解决方案。好!就这么办!
写入的对象是一个变量,所以在此之前我们需要创建一个变量来成为被写入的对象,变量的数据类型需要为double类型,为什么为Double类型呢?因为sqrt函数所需参数类型是Double型的,并且我们要将这个变量送入到sqrt函数当中并使用printf函数输出,输出的格式是以双精度浮点型的形式输出,所以这个变量是双精度浮点型(Double)当之无愧了。我们创建变量的名称叫做“sum”,“sum”的初始值为0。如下代码块所示:
#include<math.h>
#include<stdio.h>int main(void)
{double sum = 0;printf("%lf",sqrt(4.0));return 0;
}
我们采用的写入函数是scanf(格式化输入)函数,它可以根据占位符的内容要求我们输入数据,与printf函数恰恰相反,printf函数是据占位符的内容来输出数据。还是那句老话:“要想正确使用函数,必须正确地传递参数,要想正确地传递参数则需要知道参数的数据类型以及函数所需要的参数个数。”所以我们一起看看scanf函数的参数原型:
咋一看scanf函数的参数需求我们似乎并没有看懂,因为还有一半的参数省略了,但我们大致知道scanf函数所需的参数是一个占位符与一个需要被写入的变量。像下面这样:
scanf("占位符",&被写入数据的变量);
(有部分读者可能会问这个“&”是什么意思?这个我们暂且不管,我们会在下文中说到)
这个“被写入数据的变量”正是我们的“sum”变量,向“sum”变量写入数据我们可以像以下这样表达:
scanf("%lf",&sum);
那这个“&”是什么意思?“&”在C语言中是取地址符,因为我们要在变量所在的地址单元内写入数据所以我们需要获取这个变量的所在的地址单元,只要在第二个参数的变量之前加上取地址符才可以使用scanf函数。
#include<math.h>
#include<stdio.h>int main(void)
{double sum = 0;scanf("%lf",&sum);printf("%lf",sqrt(4.0));return 0;
}
这样只要我们在控制台上输入我们想要变量的值,按下回车后,变量的值就是我们在控制台上写入的。但是有一点需要注意,每个数据类型都有它应有的取值范围,所以输入的数据不可以大于或小于被输入变量的取值范围,不然会出现上溢或下溢的情况。
sqrt函数的参数正是我们输入数据的变量,所以我们直接将变量“sum”送入到sqrt函数中就可以算出我们想要的平方根数。
#include<math.h>
#include<stdio.h>int main(void)
{double sum = 0;scanf("%lf",&sum);printf("%lf",sqrt(sum));return 0;
}
这样我们的“求一个数的平方根”程序就大功告成了,它拥有极高的效率。我们可以先对上面的代码做个测试。假设我们要想求2的平方根,我们需要在程序的控制台上输入2,随后回车。”sum“变量的值赋值为2,随后使用将“sum”的值送入到sqrt函数当中,将sqrt函数的结果返回给printf函数并输出。
输入数据:2
输出结果:1.414214
这个结果虽然对于科研人员不太准确,但对于我们这群普通人而言已经够准确的了。很明显这个程序是成功的。
另外我们还可以在scanf函数之前提示用户下一条语句需要输入一条信息,并且还可以修饰一下输出的结果。
#include<math.h>
#include<stdio.h>int main(void)
{double sum = 0;printf("请输入一个数值,我们会帮助您计算出这个数的平方根");scanf("%lf",&sum);printf("这个数的平方根是:%lf",sqrt(sum));return 0;
}
这样做整个“求一个数的平方根”程序才算完整。