目录
1.函数概论
- 函数本质上是一段可以被重复调用,功能相对独立的程序段。
- 函数引用的目的:便于结构化、模块化编程(对代码进行整理总结,使之条理化),解决代码的重复使用问题,防止代码冗余(减少同一类代码的使用)。
- 函数是C程序的基本组成单元,所有的C语言程序都由一个或多个函数构成。最开始我们只是单独使用main函数去解决问题,但随着程序的复杂化,我们就需要用到多个函数。
2.库函数
在了解自定义函数前,我们需要先了解一下库函数(我们用的stdio.h\math.h都是库函数)
我们知道scanf函数、printf函数等都是stdio.h库函数内的函数,math.h内包含了许多数学方面的函数,但是除此之外还有其他库函数 我们怎么办呢?
在网上有很多文档可以帮助我们解决这个问题,比如这篇:http://t.csdn.cn/6s7mo
当然你也可以在以下网页中去查找你需要的函数:
1.MSDN
2.www.cplusplus.com
3.函数定义
C语言中的库函数都是编译系统事先定义好的,使用时无需再定义,但是我们的自定义函数是我们自己创造的,编译器是不认识的,所以我们一定要“先定义后使用”。
而定义有两种情况:
先定义后调用:
fun函数是在main函数上边,我先定义了fun函数,然后在main函数中调用了它。
先声明再调用再定义
二者结果是完全相同的,怎么选择也看你个人。
注意:函数定义是互相平行的,不可以在一个函数里定义另一个函数
了解局部变量和全局变量
变量定义的位置不同,其作用域也不同,从变量的作用域来说,分为局部变量和全局变量
局部变量:在函数内部定义的变量,其作用域仅限于该函数内
注意:
1.不同函数内可以使用相同的变量名,但他们内存中占不同的空间,不是同一个变量
2.X函数内不能使用使用Y函数内定义的变量,局部变量只能在定义自己的函数中使用
3.形参也属于局部变量,在函数调用时为其分配空间,退出函数时释放空间
全局变量:在函数之外也可以定义变量,这样的变量称为全局变量
有效范围从全局变量开始到该源文件结束(整个.c文件)
注意:
1.全局变量的定义:同一作用域范围内只能定义一次,位置在所有函数之外
2.如果全局变量与局部变量同名,在局部变量作用范围内,全局变量不起作用
3.全局变量越少越好(可以被多个函数直接引用,在不同函数中都可能改变全局变量的值)
5.函数调用
一张图让你明白函数嵌套调用
先赋予n的值,进入two函数中计算6+n,然后进入jieg函数求出最终结果2*(6+n),先返回two函数,最后回到main函数。
那么我们接下来看一下函数内参数的传递来真正理解函数调用:
可以看到swap函数中的a,b值在我们的要求下交换了数值,而main函数中的a,b值没有发生改变。这是因为我们采用的是按值传递,顾名思义就只是传递给它一个数值。另外还有按地址传递。
我有一个好朋友,他家有一片苹果林,按值传递与按地址传递的区别就是:我从他那里得到了两个苹果,他因为家里苹果还没熟透,在街上买了两个苹果给我,这是按值传递(的确给了我苹果,但没有改变他家果园的苹果数量)而按地址传递是我跑到他家里,不管苹果熟没熟,自己上树上去摘了两个苹果(我也是得到了两个苹果,但是影响到了他家里果园的苹果数量,少了两个)
简单来说就是这样
通常我们采用的都是按值传递,不会影响main函数中参数原来的数值,但当我们遇到函数的形参是数组或者接下来的指针函数时,我们就要用到按地址传递,由于传递的是地址,形参与实参共享相同的存储单元,这样通过改变形参可以直接改变实参的值。
5.递归函数
自己调用自己,就是递归调用。
构造递归函数的关键:1.满足递归的表达式
2.有结束的条件(循环有出口)。
进入递归后每一次语句的执行前都会进行条件判断,知道不满足条件退出递归调用。
递归分为递推和回归
例子:输出斐波拉契数列的第n项,递推公式如下:
很明显,用递归会比用普通方法更简单方便。
6.数组做函数的参数
数组作函数参数有两种形式:一是把数组元素作为实参使用,二是把数组名作为函数的形参和实参使用
数组元素与常量元素的区别:
(1)数组是具有相同类型的一组变量
(2)数组名是数组元素的起始地址
数组名作为函数参数调用函数的格式为:函数名(数组名)。(数组名后边不能有[])
-------------------------------------------------------------------------------------------------------------
在这之前补充一下数组的知识
数组——一组相同类型元素的集合。
1.一维数组
注意一下数组的大小一定为常数(不推荐变长数组)
对于数组中的数组元素,我们进行赋值时,又分为完全赋值和不完全赋值。
完全赋值就是给每一个数组元素都赋予我们指定的值。
如图,我在arr数组中输入了10个数,那么按照顺序,就会依次把我输入的值赋给arr[0]-arr[9]。这就是完全赋值。
那么不完全赋值很明显就是没有给每个数组元素都赋值了
我给10个数组元素只赋了6个值,而没赋值的元素呢?它们会被默认赋值为0。
那么我把下标运算符内的数字去掉后,arr[]={1,2,3,4,5,6}和arr[10]={1,2,3,4,5,6}是不是相同的呢?
答案是不同的。如果我们没有规定数组元素的个数但在后边赋值的话,系统会根据所赋值元素的个数指定数组元素个数。(你写了几个数,它就认为有几个元素)
明显它只有6个数组元素。
对于不同的数组类型都是适用的。
但要注意字符型数组,数组元素大小要比元素个数多一位,它结尾需要\0来收尾,否则你就会看到“烫烫烫”了。
另外要知道一维数组在内存中连续存放,也就是说他们的地址是连续的,你只需要知道第一个元素的地址就可以访问整个数组(而数组名就是数组第一个元素的地址,这个知识点你这段时间会经常用到的,因为函数后边就是该死的指针部分)。数组中数组元素的大小由数组元素类型决定,int型就是1个元素占4个字节了。
数组还有一个重要的就是下标,下标从0开始,到n-1(n为数组元素个数)
注意:这个不能在函数中应用,要用到main函数中
函数形参接收的是数组的地址,这时sizeof(arr)计算的是一个地址的大小,在我的图里的话就是4,所以size结果会变成1。直接错了
2.二维数组
int arr[]是一维数组,后边有一个下标运算符;而二维数组就是再加上一个int arr [] [],如你所见,这就是二维的了。
一维数组在内存中是连续存放的,那么二维数组呢?
因为二维的说法,会让人觉得是X ,Y轴那样有个长和宽,但是实际上它在内存中还是连续存放
你看,它每一行最后一个元素和下一行第一个元素地址上相差了个4,说明它和其他元素一样在内存中都是连续存放的
二维数组的初始化遵从:自上而下,先左后右 。
3.数组作函数参数
举几个例子看一下:
例1:
例2:运用冒泡排序将数组按由大到小排序
冒泡排序思想:相邻元素进行比较,满足条件互相交换
main函数里的东西都能看懂,说一下reslt函数,i指的是我们已经放置到位置上的元素的个数(从0开始,每放置好一个元素就+1),而j很明显就是对应元素的比较个数了,第一个元素需要和除自身外即(sz-1)个元素比较,第二个需要和(sz-1-i)个元素比较,i个元素放好后,不再需要比较。
具体没有什么可写的,到了题里边,具体情况具体分析。