C程序设计基础(5):函数基础详解(函数定义、调用、原型、参数)
上一节中,我们学习了有关数组和字符串的常用方法。数组和字符串的加持大大降低了我们命名和使用变量的复杂程度,节约了代码量,但这还不够。程序编写过程中,我们往往会遇到一段相似的代码在多个不同的位置出现的情况,虽然依靠复制粘贴和小修改可以缩短编程时间,但还有很大一部分情况中,使用这段代码的次数不定,如果单靠使用循环,将对思考产生非常大的麻烦,这就需要模块化的编程思想。使用函数,将一段代码包装成一个块,使用它时只需要提供对应的参数,就可以方便地调用它并获取它的返回值。下面,就让我们一起来了解一下C语言中函数的详细使用方法。
函数简介
函数,是一组执行一个功能的语句,被包装在一个函数名称中。只需要一个函数名称(必要时加上传递的参数,在函数中,参数可用类似操作变量的方法进行操作),就能调用这个函数。函数隔离于调用它的函数运行,即,函数内部语句执行不影响外部变量(除了按址传递的参数,后面会说到)。一般情况下,除了void
类型。函数都有一个返回值,这时的函数相当于一个值(不可修改),函数执行并返回后的值将取代原来函数的位置,并能够加入运算表达式。(实际上,我们一直在使用的main
就是一个整型函数,这个函数在程序开始运行时被调用,它的返回值就是整个程序的返回值)。下面,将给出一个输出a+b
的例子,具体原理将在下面给出。
#include <stdio.h>int add(int a, int b)
{return (a + b);
}int main()
{int a = 1, b = 2;printf("a + b = %d\n", add(a, b));return (0);
}
样例中,函数add
实现了返回两个参数和的功能,这个返回值被作为函数printf
的参数1,被输出到控制台上
函数调用时,被调用的函数称为被调函数
,调用它的函数称为主调函数
。
函数定义
对函数进行定义是函数的核心内容。它制定了函数的功能以及具体实现方法。函数只有经过定义,才能被其他语句调用。
语法
语法格式中,除了名称类进行了替换,其他标识符,符号等没有改变,使用时应注意语法细节
Function_Type Function_Name(Param1_Type Param1_Name, Param2_Type Param2_Name)
{do-something;return (Return_value);
}
释义
Function_Type
: 函数返回值类型,同变量类型,如果没有返回值,则使用void
(无类型)Function_Name
: 函数名,为函数指定一个名称,在调用函数时会用到。Param_Type
: 参数类型,同变量类型Param_Name
: 参数名称,同变量名称,这个名称将在函数内部作为变量名称被使用Return_value
: 函数的返回值,注意,请返回一个与函数类型相匹配的值,以免对值进行强制类型转换而造成不必要的错误
注意
- 以上语法样例仅提供了两个参数的情况,如果需要多个参数,请在两个参数中间用逗号分隔。如果不需要参数,可在括号中(不能省略括号)填
void
,或是不填 - 不同于C++和其他高级语言,C语言不支持函数重载,这意味着,每个函数拥有唯一的一个名称
示例
下面一个示例展示了最大值函数,函数将返回两个参数中的较大值
int max(int a, int b)
{if (a > b) return a;return b;
}
函数调用
函数调用时,需要指定被调函数名称,并在后面加上函数所要求的参数,即使没有参数,也必须加上括号。如函数有一个返回值,这个值将取代函数的位置,单作为一个语句使用也可。
示例:
int max(int, int);
//此处是函数原型声明,定义在上面已经给出,这里不再重复
//有关函数声明内容,将在下文说到int main()
{printf("%d", max(a, b));return 0;
}
递归调用
在编程中,函数自身调用自身的现象叫做递归调用。下面会讲到,除了按地址传递的参数,两个函数之间不会有任何影响,即使参数和函数内局部变量重名,程序仍然能够进行区分,函数仅能调用当前过程中的局部变量,而不能访问其调用的或是调用它的函数中的局部变量,后者的传递方式一般用全局变量或函数返回值实现。下面求两数最大公约数的辗转相除法程序就是递归调用的很好示例,
int gcd(int a, int b);int main()
{int a, b;scanf("%d %d", &a, &b);printf("%d\n", gcd(a,b));return 0;
}int gcd(int a, int b)
{if (!b) return (a);return (gcd(b, a % b));
}
有关数学知识请自行查阅相关资料,通过几次手推过程和调试,相信你能对递归调用有一个很深刻的了解。
函数原型
功能
在上面的示例中,函数定义在函数调用之前出现,而为了突出维持程序主体结构,我们往往将main
函数作为第一个函数,而将其他函数放在其后。C++
编译器从上到下进行编译,当遇到一个函数调用,但之前没有遇到这个函数的定义时,编译器会报错,这就需要在函数调用之前加上函数原型的声明。声明告诉编译器,存在一个这样的函数,并确定其参数个数与类型,其定义将在文件后面或其他文件中给出。C
编译器不会对一调用而未声明和定义的函数报警,而是默认其已定义,未定义的函数将在链接器阶段报错。
另外,函数原型可以指定函数的参数个数和名称,它将指定参数传递时的类型,如果没有声明原型,参数将升级(promote)传递,而这可能对参数的值产生影响,如果函数原型指定了参数类型,则将不会出现自动转换。(参数默认升级不在这里展开,仅作了解)
语法
函数原型声明与函数定义的第一行类似,只是在函数参数括号后直接用;
结束,并且,可以不需要给出函数参数的名称,而仅给出参数的个数和类型
int max(int, int);int main()
{do-something;return 0;
}//function definition is here
int max(int a, int b)
{if (a > b) return a;return b;
}
函数的参数
作用
在定义函数时,为了方便,我们往往使函数具有完成一类相近任务的功能,而在调用函数时,有了具体环境,我们也需要指定函数完成的具体任务。这些具体需求的指定就依靠参数的传递。它完成了向函数提供更具体需求的功能。
原理
函数声明时就定义了函数的个数和类型。在函数内部,函数的参数就像是对应类型的变量,对参数的所有操作语法与变量完全相同。在调用函数时,主调函数提供被调函数声明所要求的全部参数,这些参数将被推入一个栈中,然后,使用call
命令,系统控制权转交给被调函数,函数将声明对应参数的变量,并将参数栈中的值给它们。
函数参数按照传递方式区分主要分为两种:按值传递
和按址传递
参数,又被称为传值调用
和引用调用
。顾名思义,前者传递的仅仅是一个值,参数在函数内部作为一个复制的变量使用,函数内部对参数的改变对主调函数没有任何影响;后者传递了一个地址,即将那个地址对应的值引用传给被调函数,实际上传递了对应变量地址的一个指针,这两个指针所指向的内存空间是同一个,所以,函数内部对参数有任何变化,到函数外部时,变化仍然有效,参数对应的值被永久改变了。
(在当前阶段,我们一般不会使用指针进行编程,也就不会使用按址传递的参数,故第二段仅作了解即可,有兴趣的读者可以深入研究)
语法
下面仅作按值传递参数的语法介绍,按址传参将在指针节中讲解。
仍用上面的示例,
int max(int, int);int main()
{int a, b;do-something;int max_ab = max(a, b);return 0;
}//function definition is here
int max(int a, int b)
{if (a > b) return a;return b;
}
主函数调用函数max
时,a
和b
参数被传入max
,并在函数执行过程中被使用,即使修改了,也不会对main
函数中的a
和b
变量产生影响。
函数的变量
全局变量
定义在不包含任何一个函数(包括main
函数)中的变量被称为全局变量。这个程序中的所有函数都可以调用并修改它。其优势是方便,减少了指针参数的数量,劣势则是污染了命名空间,造成名称资源浪费。
局部变量
在C中,所有定义在函数中(包括main
函数)的变量都被称为局部变量
。顾名思义,这个变量的作用范围仅限函数内部,即使在外部遇到了相同名称的变量也不影响。其优点是灵活、节约名称空间,而缺点是不能跨函数调用,需要用到按址传递参数。
下面的示例给出了全局变量和局部变量的区别,
#include <stdio.h>
#include <string.h>int a;void init(void);int main()
{int a = 0;init();printf("A private is: %d\n", a);return 0;
}void init(void)
{a = 10;printf("A global is: %d\n", a);
}
冲突
当函数中定义了一个与全局变量名称相同的变量,那么将优先使用局部变量,而不是全局变量。
C程序设计基础(5):函数基础详解(函数定义、调用、原型、参数)相关推荐
- javaScript函数模块详解
javaScript函数模块详解 函数实际上是对象,每个函数都是Function类型的实例,而Function也有属性和方法,和其他引用类型一样 可以将函数名想象成指针,函数想象成对象 注意, ...
- OpenCv中的cv::Mat::create()函数,cvRound(),cvFloor(),cvCeil()函数的详解l
文件说明: cv::create()函数的详解 函数原型: inline void Mat::create(int _rows, int _cols, int _type) inline void M ...
- fgets()函数的详解-使用技巧-C语言基础
这篇文章要探讨的是"fgets()函数的详解以及使用时需要注意的一些细节".涉及fgets()函数的应用和需要注意的问题.属于C语言基础篇(持续更新). fgets()(函数原型: ...
- scanf()函数的详解以及使用时需要注意的一些细节-C语言基础
这篇文章要探讨的是"scanf()函数的详解以及使用时需要注意的一些细节".涉及scanf()函数的应用和需要注意的问题.属于C语言基础篇(持续更新). scanf()(函数原型: ...
- fgets()函数的详解以及使用时需要注意的一些细节-C语言基础
这篇文章要探讨的是"fgets()函数的详解以及使用时需要注意的一些细节".涉及fgets()函数的应用和需要注意的问题.属于C语言基础篇(持续更新). fgets()(函数原型: ...
- 微信小程序详解 php,微信小程序canvas基础详解
canvas 元素用于在网页上绘制图形.HTML5 的 canvas 元素使用 JavaScript 在网页上绘制2D图像.本文主要和大家分享微信小程序canvas基础详解,希望能帮助到大家. 一.了 ...
- C++的get()函数与getline()函数使用详解
点击蓝字 关注我们 来源自网络,侵删 一.C++的get()函数使用详解 1.C++ get()函数 get()函数是cin输入流对象的成员函数,它有3种形式: 无参数的: 有一个参数的: 有3个参数 ...
- 主线剧情03-NXP-i.MX系列的u-boot移植基础详解
u-boot 移植基础详解 本文系广泛撷取.借鉴和整理(相关的内容在网络上有很多,但很多相互抄,或者是版本太老,或者就是不通用的非常有平台针对性的步骤,碎片化泛滥,甚至就是有待分拣的垃圾厂,当然也有一 ...
- 看完之后保证你对socket编程步骤胸有成竹。 C++ Socket网络编程基础详解(TCP)
C++ Socket网络编程基础详解(TCP版) 网络编程,就是编写程序使得两台计算机交换数据,其实从本质上来讲,网络编程最终所实现的功能,和我们文件的输入输出很相似,只是文件输入输出的对象 ...
最新文章
- html后缀的网页怎么复制,如何将HTML格式的文本从Chrome浏览器扩展复制到剪贴板上?...
- mysql大于等于怎么写_数据库中大于等于0小于等于100怎样表达
- [黑金原创教程] FPGA那些事儿《数学篇》- CORDIC 算法
- [LintCode] Wildcard Matching
- 十四、深入Python条件和循坏
- springboot单例模式注入对象_Spring 中经典的 9 种设计模式,打死也要记住啊!
- python合并txt文本_Python实现将目录中TXT合并成一个大TXT文件的方法
- 第四十五期:程序员未来干什么?做架构还是做管理?
- 数据结构:单链表操作之如何判断链表是否带环及相关操作
- 我的新LulzBot Mini 3D打印机入门
- leetcode 82. 删除排序链表中的重复元素 II(Remove Duplicates from Sorted List II)
- 思科交换机基本配置命令
- android phone win10下载,Win10稳定版提供Win10 Your Phone运行Android应用
- 算24点的一般方法及例题
- 手把手教你iPhone 3G手机软件开发 转帖
- 写给自己以及各位程序员,无论你在什么位置,我想你都应该看一下
- 如何阻止你最好的员工辞职
- 中铁员工入职培训心得体会
- 基于C++实现的股票大数据的统计分析与可视化
- 在线招聘软件市场深度分析及发展研究预测报告
热门文章
- python json变为csv具体代码
- Typora Mac版本安装 Pandoc 导出文件为word格式(windows可通用)
- 快讯 | 嘉益仕(Litins)应邀出席2018世界智能制造大会·江宁智能产业地标论坛
- 考研,其实每一步都是算数的
- Excel怎么转换PDF文件?
- 笔记本计算机声音小,笔记本扬声器红色十字形_如果笔记本计算机的扬声器很小但没有声音,该怎么办...
- 【跟晓月学数据库】基于book库的mysql进阶实战
- python 单词拆音节_python去除拼音声调字母,替换为字母的方法
- 数据库系列(5)-数据库设计之规范化理论
- 一条SQL语句统计总数及各状态数