上一节中,我们学习了有关数组和字符串的常用方法。数组和字符串的加持大大降低了我们命名和使用变量的复杂程度,节约了代码量,但这还不够。程序编写过程中,我们往往会遇到一段相似的代码在多个不同的位置出现的情况,虽然依靠复制粘贴和小修改可以缩短编程时间,但还有很大一部分情况中,使用这段代码的次数不定,如果单靠使用循环,将对思考产生非常大的麻烦,这就需要模块化的编程思想。使用函数,将一段代码包装成一个块,使用它时只需要提供对应的参数,就可以方便地调用它并获取它的返回值。下面,就让我们一起来了解一下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时,ab参数被传入max,并在函数执行过程中被使用,即使修改了,也不会对main函数中的ab变量产生影响。


函数的变量

全局变量

定义在不包含任何一个函数(包括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):函数基础详解(函数定义、调用、原型、参数)相关推荐

  1. javaScript函数模块详解

    javaScript函数模块详解 ​ 函数实际上是对象,每个函数都是Function类型的实例,而Function也有属性和方法,和其他引用类型一样 可以将函数名想象成指针,函数想象成对象 ​ 注意, ...

  2. OpenCv中的cv::Mat::create()函数,cvRound(),cvFloor(),cvCeil()函数的详解l

    文件说明: cv::create()函数的详解 函数原型: inline void Mat::create(int _rows, int _cols, int _type) inline void M ...

  3. fgets()函数的详解-使用技巧-C语言基础

    这篇文章要探讨的是"fgets()函数的详解以及使用时需要注意的一些细节".涉及fgets()函数的应用和需要注意的问题.属于C语言基础篇(持续更新). fgets()(函数原型: ...

  4. scanf()函数的详解以及使用时需要注意的一些细节-C语言基础

    这篇文章要探讨的是"scanf()函数的详解以及使用时需要注意的一些细节".涉及scanf()函数的应用和需要注意的问题.属于C语言基础篇(持续更新). scanf()(函数原型: ...

  5. fgets()函数的详解以及使用时需要注意的一些细节-C语言基础

    这篇文章要探讨的是"fgets()函数的详解以及使用时需要注意的一些细节".涉及fgets()函数的应用和需要注意的问题.属于C语言基础篇(持续更新). fgets()(函数原型: ...

  6. 微信小程序详解 php,微信小程序canvas基础详解

    canvas 元素用于在网页上绘制图形.HTML5 的 canvas 元素使用 JavaScript 在网页上绘制2D图像.本文主要和大家分享微信小程序canvas基础详解,希望能帮助到大家. 一.了 ...

  7. C++的get()函数与getline()函数使用详解

    点击蓝字 关注我们 来源自网络,侵删 一.C++的get()函数使用详解 1.C++ get()函数 get()函数是cin输入流对象的成员函数,它有3种形式: 无参数的: 有一个参数的: 有3个参数 ...

  8. 主线剧情03-NXP-i.MX系列的u-boot移植基础详解

    u-boot 移植基础详解 本文系广泛撷取.借鉴和整理(相关的内容在网络上有很多,但很多相互抄,或者是版本太老,或者就是不通用的非常有平台针对性的步骤,碎片化泛滥,甚至就是有待分拣的垃圾厂,当然也有一 ...

  9. 看完之后保证你对socket编程步骤胸有成竹。 C++ Socket网络编程基础详解(TCP)

    C++ Socket网络编程基础详解(TCP版) ​    网络编程,就是编写程序使得两台计算机交换数据,其实从本质上来讲,网络编程最终所实现的功能,和我们文件的输入输出很相似,只是文件输入输出的对象 ...

最新文章

  1. html后缀的网页怎么复制,如何将HTML格式的文本从Chrome浏览器扩展复制到剪贴板上?...
  2. mysql大于等于怎么写_数据库中大于等于0小于等于100怎样表达
  3. [黑金原创教程] FPGA那些事儿《数学篇》- CORDIC 算法
  4. [LintCode] Wildcard Matching
  5. 十四、深入Python条件和循坏
  6. springboot单例模式注入对象_Spring 中经典的 9 种设计模式,打死也要记住啊!
  7. python合并txt文本_Python实现将目录中TXT合并成一个大TXT文件的方法
  8. 第四十五期:程序员未来干什么?做架构还是做管理?
  9. 数据结构:单链表操作之如何判断链表是否带环及相关操作
  10. 我的新LulzBot Mini 3D打印机入门
  11. leetcode 82. 删除排序链表中的重复元素 II(Remove Duplicates from Sorted List II)
  12. 思科交换机基本配置命令
  13. android phone win10下载,Win10稳定版提供Win10 Your Phone运行Android应用
  14. 算24点的一般方法及例题
  15. 手把手教你iPhone 3G手机软件开发 转帖
  16. 写给自己以及各位程序员,无论你在什么位置,我想你都应该看一下
  17. 如何阻止你最好的员工辞职
  18. 中铁员工入职培训心得体会
  19. 基于C++实现的股票大数据的统计分析与可视化
  20. 在线招聘软件市场深度分析及发展研究预测报告

热门文章

  1. python json变为csv具体代码
  2. Typora Mac版本安装 Pandoc 导出文件为word格式(windows可通用)
  3. 快讯 | 嘉益仕(Litins)应邀出席2018世界智能制造大会·江宁智能产业地标论坛
  4. 考研,其实每一步都是算数的
  5. Excel怎么转换PDF文件?
  6. 笔记本计算机声音小,笔记本扬声器红色十字形_如果笔记本计算机的扬声器很小但没有声音,该怎么办...
  7. 【跟晓月学数据库】基于book库的mysql进阶实战
  8. python 单词拆音节_python去除拼音声调字母,替换为字母的方法
  9. 数据库系列(5)-数据库设计之规范化理论
  10. 一条SQL语句统计总数及各状态数