C语言应该怎么玩——函数
C语言应该怎么玩——函数
- 一、函数的分类
- 1、库函数
- 2、自定义函数
- 二、函数参数
- 1、实际参数
- 2、形式参数
- 三、函数调用
- 1、传值调用
- 2、传址调用
- 四、函数的嵌套调用和链式访问
- 1、嵌套调用
- 2、链式访问
- 五、函数的声明和定义
- 1、函数声明
- 2、函数定义
- 六、函数递归
- 1、递归的两个必要条件
- 2、栈溢出
一、函数的分类
1、库函数
为什么会有库函数?
比如将信息按照一定的格式打印到屏幕上(printf)、做一些字符串的拷贝工作(strcpy)、计算某个数的某次方的运算(pow)等,描述的这些基础功能,他们不是业务性的代码,但在开发的过程中每个程序员都可能用得到。为了支持可移植性和提高程序的效率,C语言的基础库中提供了一系列类似的库函数,方便程序员进行软件开发。
注意:库函数必须知道的一个秘密:
使用库函数,必须包含 #include 对应的头文件。
这些库函数在不同的头文件中声明。比如:
math.h头文件中有:sin(x),cos(x),exp(x)(求e^x),fabs(x)(求x的绝对值)等库函数。
stdio.h头文件中有:scanf(),printf(),gets(),puts(),getchar(),putchar()等库函数。
string.h头文件中有:strcmp(),strcpy(),strcat(),strlen()等库函数。
2、自定义函数
库函数功能这么强大,为什么还要有自定义函数呢?
如果库函数能干所有的事情,那还要程序员干什么?所以更加重要的是自定义函数。
自定义函数和库函数一样,有函数名,返回值类型和函数参数,但是不一样的是这些都是我们自己来设定,这给我们一个很大的发挥空间。
函数的组成:
ret_type fun_name (para1 )
{
statement;
}
下面提供中文版:
返回值类型 函数名 (函数参数)
{
语句项;
}
下面用代码来演示一下:
要求:写一个函数,可以找出两个整数中的最大值。
#include <stdio.h>int get_max(int x, int y)
{if (x > y)return x;elsereturn y;
}int main()
{int n1 = 10;int n2 = 20;printf("max = %d\n", get_max(n1, n2));//显示及结果为max = 20return 0;
}
这里我们再看一个代码:
要求:写一个函数,交换两个整型变量的值。
void Swap(int x, int y)
{int c = 0;c = x;x = y;y = c;
}int main()
{int a = 10;int b = 20;printf("交换前:a=%d b=%d\n", a, b);Swap(a, b);printf("交换后:a=%d b=%d\n", a, b);return 0;
}
//显示结果为 交换前:a=10 b=20
//显示结果为 交换后:a=10 b=10
我们发现这个函数并没有完成交换两个值的任务,这是为什么呢?
先不着急,我们先来介绍一下函数参数和函数调用的概念。
二、函数参数
1、实际参数
实际参数又叫实参。真实传给函数的参数叫实参。实参可以是:常量、变量、表达式、函数等,无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传给形参。
2、形式参数
形式参数又叫形参。形式参数是函数名后括号中的变量,因为形式参数只有在函数被调用的过程中才实例化(分配内存单元),所以叫形式参数。形式参数当函数调用完成之后就自动销毁了(生命周期跟局部变量是一样的)。因此形式参数只在函数中有效。
形参实例化以后相当于实参的一份临时拷贝。
三、函数调用
1、传值调用
传值调用是把实参的数值传给形参。
函数的形参和实参分别占有不同的内存块,如果进行传值调用,对形参的修改不会影响实参。
2、传址调用
传址调用是把函数外部创建变量的内存地址传递给函数参数的一种调用函数的方式。
这种传参方式可以让函数和函数外边的变量建立起真正的联系,也就是函数内部的变量可以直接操作函数外部的变量。
了解完函数参数和函数调用的概念后,我们再来看之前那个要交换两个整型变量的值的函数。
传值调用的形式:
void Swap(int x, int y)
{int c = 0;c = x;x = y;y = c;
}int main()
{int a = 10;int b = 20;printf("交换前:a=%d b=%d\n", a, b);Swap1(a, b);printf("交换后:a=%d b=%d\n", a, b);return 0;
}
//显示结果为 交换前:a=10 b=20
//显示结果为 交换后:a=10 b=20
传址调用的形式:
void Swap2(int* pa, int* pb)
{int c = 0;c = *pa;*pa = *pb;*pb = c;
}int main()
{int a = 10;int b = 20;printf("交换前:a=%d b=%d\n", a, b);Swap2(&a, &b);printf("交换后:a=%d b=%d\n", a, b);return 0;
}
//显示结果为 交换前:a=10 b=20
//显示结果为 交换后:a=20 b=10
我们发现传址调用完成了交换的任务。
因为形参在实例化的时候才分配内存空间,这个空间与实参所在的空间的相互独立的。形参是实参的一份临时拷贝,如果进行传值调用,只把值传给形参,那函数交换的也只是形参所在内存空间里的值,与实参所在的内存空间没关系;如果进行传址调用,把实参的地址传过去,在函数内部进行解引用操作时,就是可以根据形参所在内存空间中存放的地址找到实参,也就是可以通过形参来操作实参。
四、函数的嵌套调用和链式访问
1、嵌套调用
void new_line()
{printf("hehe ");
}void three_line()
{int i = 0;for (i = 0; i < 3; i++){new_line();}
}int main()
{three_line();return 0;
}
//显示结果为hehe hehe hehe
函数可以嵌套调用,但是不能嵌套定义。
2、链式访问
把一个函数的返回值作为另一个函数的参数。
#include <stdio.h>
#include <string.h>int main()
{printf("%d\n", strlen("abc"));return 0;
}
//显示结果为3
五、函数的声明和定义
1、函数声明
1、告诉编译器有一个函数叫什么,参数是什么,返回类型是什么。但是具体是不是存在,无关紧要。
2、函数的声明一般出现在函数的使用之前。要满足 :先声明,后使用。
3、函数的声明一般要放在头文件中。
2、函数定义
函数的定义是指函数的具体实现,交代函数的功能实现。
六、函数递归
什么是递归?
程序调用自身的编程技巧称为递归。
递归作为一种算法在程序设计语言中广泛应用。一个过程或函数在其定义或说明中有直接或间接调用自身的一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。递归的主要思考方式在于:把大事化小。
1、递归的两个必要条件
1、存在限制条件,当满足这个限制条件后,递归便不再继续。
2、每次递归调用之后越来越接近这个限制条件。
代码演示:
要求:按照顺序,打印一个整型值的每一位。
void print(int n)
{if (n > 9){print(n / 10);}printf("%d ", n % 10);
}int main()
{int n = 1234;print(n);return 0;
}
//显示结果为1 2 3 4
2、栈溢出
讲栈溢出之前,还是先进行代码演示:
void test(int n)
{if (n < 10000){test(n + 1);}
}int main()
{test(1);return 0;
}
在调试这个代码的时候就会发现这个栈溢出的问题。
在解释这个栈溢出的问题之前,我们先简单介绍一点关于内存的知识:
为了避免栈溢出,在写递归的时候要注意:
1、不能死递归,要有跳出条件,每次递归都要逼近这个跳出条件。
2、递归层次不能太深。
C语言应该怎么玩——函数相关推荐
- C语言第七讲,函数入门.
C语言第七讲,函数入门. 一丶了解面向过程和面向对象的区别. 为什么要先讲面向过程和面向对象的区别? 面向过程,就是什么都要自己做. 比如你要吃饭. 那么你得自己做饭. 面向对象, 面向对象就是我要 ...
- R语言使用download.file函数下载网络文件到本地(Download File from the Internet)
R语言使用download.file函数下载网络文件到本地(Download File from the Internet) 目录 R语言使用download.file函数下载网络文件到本地(Down ...
- R语言stringr包str_dup函数字符串多次复制实战
R语言stringr包str_dup函数字符串多次复制实战 目录 R语言stringr包str_dup函数字符串多次复制实战 #导入stringr包 #仿真数据
- R语言stringr包str_count函数计算字符串匹配个数实战
R语言stringr包str_count函数计算字符串匹配个数实战 目录 R语言stringr包str_count函数计算字符串匹配个数实战 #导入stringr包 #仿真数据
- R语言使用R原生函数plot和lines可视化线图、并使用lty参数自定义线条类型、lwd自定义设置线条的粗细、col参数自定义线条颜色(Change R base plot line types)
R语言使用R原生函数plot和lines可视化线图.并使用lty参数自定义线条类型.lwd自定义设置线条的粗细.col参数自定义线条颜色(Change R base plot line types) ...
- R语言ggpubr包ggsummarystats函数可视化分组条形图(自定义分组颜色、添加抖动数据点jitter、误差条)并在X轴标签下方添加分组对应的统计值(样本数N、中位数、四分位数的间距iqr)
R语言ggpubr包ggsummarystats函数可视化分组条形图(自定义分组颜色.添加抖动数据点jitter.误差条error bar)并在X轴标签下方添加分组对应的统计值(样本数N.中位数med ...
- R语言使用t.test函数计算两组独立数据的t检验(Independent t-test)
R语言使用t.test函数计算两组独立数据的t检验(Independent t-test) 目录 R语言使用t.test函数计算两组独立数据的t检验(Independent t-test) #仿真数据
- R语言plyr包round_any函数将向量数据近似到任意精度实战
R语言plyr包round_any函数向量将数据近似到任意精度实战 目录 R语言plyr包round_any函数向量将数据近似到任意精度实战 #导入plyr包 #仿真数据
- R语言ggplot2使用geom_line函数geom_point函数可视化哑铃图、并对哑铃图进行排序(reorder dumbbell plot)
R语言ggplot2使用geom_line函数geom_point函数可视化哑铃图.并对哑铃图进行排序(reorder dumbbell plot) 目录
最新文章
- 驾校计算机岗位管理制度,驾校计算机的规章制度.doc
- postgres 显示变量_postgre 查询时 postgres=# 变成 ! ! 要怎么解决?
- [转]数据结构:图的存储结构之邻接矩阵
- 8.QT的事件循环与事件发送相关类
- machine learn in python 第二章2.1.1
- cmd的rd命令简单解析
- lwIP ARP协议分析
- CF235D-Graph Game【LCA,数学期望】
- Unity3d远程连接Hololens提示Cannot connect without a remote machine address specified
- Win10蓝牙鼠标老是断连卡顿的解决方法
- 那些不知所措的运算符优先级
- css 主页模版 搜索技巧
- Python+SSM懂车帝汽车数据分析平台 爬虫代码实例分析
- 《近世代数》课程感想
- 计算机在机械工程中的应用英语作文,关于机械工程英语作文
- ZoomIt 屏幕放大 缩小 屏幕画笔 演示 手写笔迹 倒计时 秒变白板 pointofix
- 当tomcat启动遇到(你的项目名字) is required and cannot be removed from the server(不能部署到server上)
- 上海计算机一级和四六级,大学英语六级比四级难多少?985学长含泪告诉你!
- 文章/网站分享工具——百度分享
- django学习笔记(六)-----模型
热门文章
- 初学者编写python用什么软件
- MATLAB热障涂层成像,一种涡轮叶片热障涂层模拟试验过程中损伤实时检测方法与流程...
- Cesium 体积测量支持倾斜模型(不支持地形)
- 2013年4月通信概论答案
- 计算机一级考试试题理论,计算机一级考试理论试题(A—H)及答案.doc
- NB-IOT(BC26)相关AT指令——UDP/TCP传输
- 使用WebView加载HTML代码
- 华为mate8手机计算机能在哪里,华为Mate8怎么解锁 华为Mate8成功解锁图文教程【详解】...
- 【算法面试必刷Java版八】链表中倒数最后k个结点
- 路考计算机系统评判,白露塘科目三路考系统计算机评判考生考试流程