C语言中函数的认识

发布时间:2026/6/9 4:09:43

C语言中函数的认识 函数的初识一、函数的概念二、C语言中函数的分类1.库函数1.1 标准库和头文件1.2库函数的使用方法2.自定义函数2.1函数的语法形式2.2例子三、形式参数形参和实际参数实参1.实参2.形参3.两者之间的关系四、return语句1.2.3.4.5.6.7.五、数组做函数参数六、嵌套调用和链式访问1.嵌套调用2.链式访问七、函数的声明和定义1.单个文件2.多个文件3.extern和static3.1static修饰局部变量3.2 static 修饰全局变量3.3static修饰函数一、函数的概念在数学中我们都了解过函数的概念C语言引用函数function的概念有时候称作子程序在C语言中函数是一段完成特定任务的一小段代码。它有特殊的写法和调用方法。C语言的程序其实是由无数个小的函数组合而成。这种方式提高了代码的可读性、可维护性和可重用性提高了效率。二、C语言中函数的分类1.库函数1.1 标准库和头文件C语言的国际标准ANSIC规定了一些常用的函数的标准被称为标准库那不同的编译器厂商根据ANSI提供的C语言标准就给出了⼀系列函数的实现。这些函数就被称为库函数.我们刚开始学的printf、scanf函数都是库函数。有了库函数一些常见的功能就不需要程序员自己实现了一定程度提升了效率同时库函数的质量和执行效率上都更有保证。各种编译器的标准库中提供了一系列的库函数这些库函数根据功能的划分都在不同的头文件中进行了声明。库函数相关头文件1.2库函数的使用方法库函数的学习和查看工具很多比如C/C官方的链接中文版cplusplus.com比如说sqrt这个函数这个是函数的声明这个是函数的作用不会翻译的话可以利用ai网站下面有例子展示库函数是在标准库中对应的头文件中声明的所以库函数的使用务必包含对应的头文件不包含是可能会出现⼀些问题的。#includemath.h//需要包含的头文件doublex;//定义变量doublesqrt(x);//sqrt是函数名x是是函数的参数//表⽰调⽤sqrt函数需要传递⼀个double类型的值//double是返回值的类型表示函数计算的结果是double类型2.自定义函数2.1函数的语法形式ret_typefun_name(形式参数){}//ret_type是函数的返回类型有时候返回类型可以是void 表⽰什么都不返回//fun_name是函数的名字//括号里放的是形式参数//{}是函数体原材料1工厂原材料2产品参数1函数参数2计算结果我们可以把函数想象成为一个小型加工厂工厂需要将原材料进行加工才能有产品。函数也类似函数一般输入一些值可以是0个也可以是多个经函数计算得出结果。函数的参数就相当于工厂中送进去的原材料函数的参数也可以是void 明确表示函数没有参数。如果有参数要交代清楚参数的类型和名字以及参数个数2.2例子我们举个简单的例子来说比如说加法函数#includestdio.hintAdd(intx,inty)//根据功能可以知道我们需要接收两个参数所以定义int xint y写明参数类型//函数名要具有一定的意义让人比较了解这个是干嘛的{returnxy;}intmain(){inta0;intb0;scanf(%d,%d,a,b);//调用加法函数完成a和b的相加//像这个scanf里面写的什么形式就要跟它相同才能输入//像这个我就要写43intrAdd(a,b);printf(%d,r);return0;}函数的参数部分需要交代清楚参数个数每个参数的类型是啥形参的名字叫啥。三、形式参数形参和实际参数实参在函数的使用过程中将参数分为实参和形参1.实参实参是调用函数时实际传入的具体值或变量在上面代码中我们先写了Add函数有了函数后再调用函数。在调用函数时传递给函数时的参数a,b成为实际参数简称实参。实际参数就是真实传递给函数的参数。2.形参形参定义函数时写在函数名后面括号里的变量。比如在定义函数Add的时候括号里面的xy就是形式参数简称形参叫形式参数的原因它强调的是名义上存在不会向内存申请空间不会真实存在的所以叫形式参数。形式参数只有在函数被调用的过程中为了存放实参传递过来的值才向内存申请空间这个过程就是形参的实例化。3.两者之间的关系虽然我们提到了实参是传递给形参的他们之间是有联系的但是形参和实参各⾃是独⽴的内存空间。我们可以通过调试观察。首先没有输入值之前a的地址b的地址a,b的地址如下输入数字后的变化运行到到15行然后调用函数创建变量x,y可以看到x和y确实得到了a和b的值但是x,y和a,b地址不同所以我们可以理解为形参是实参的⼀份临时拷拷贝。形参会有单独空间。对形参的修改是不会影响实参。四、return语句在函数的设计中函数中经常会出现return语句也可能没有return语句。return注意事项1.return后边可以是⼀个数值也可以是⼀个表达式如果是表达式则先执行表达式再返回表达式的结果。2.return后边也可以什么都没有直接写return;这种写法适合函数返回类型是void的情况。3.return语句执行后函数就彻底返回后边的代码不再执行。4.return返回的值和函数返回类型不⼀致系统会自动将返回的值隐式转换为函数的返回类型。5.如果函数中存在if等分支的语句则要保证每种情况下都有return返回否则会出现编译错误。比如说这个代码会产生这个警告6.函数的返回值如果不写编译会默认函数的返回类型是Int.(注意这是C89的老行为C99已经废除)7.函数写了返回值但函数中没有使用return返回值那么函数的返回值是未知的。五、数组做函数参数在使用函数时我们难免会将数组作为参数传递给函数在函数内部对数组进行操作。例子一个班级有若干名学生老师需要录入成绩后统一加分比如每科加 5 分作为平时分打印成绩单这里的 add_bonus 函数要能够对成绩进行加分就得把成绩数组作为参数传递给函数同时函数内部在遍历每个成绩的时候需要知道有多少名学生。所以我们需要给 add_bonus 传递 2 个参数一个是数组另外一个是学生的个数。仔细分析 print_scores 也是一样的只有拿到了数组和学生个数才能遍历打印每个学生的成绩。我们已知数组作为参数传递给了函数了那这两个函数应该如何设计呢我们先要学习数组传参的知识1.函数的形式参数要和函数的实参个数匹配像这个样子add_bonus(scores1, n); add_bonus(scores1, n, 5, 0);像这种多了少了会报错2. 函数的实参是数组形参也是可以写成数组形式的3.形参如果是⼀维数组数组大小可以省略不写4.形参如果是⼆维数组行可以省略但是列不能省略5.数组传参形参是不会创建新的数组的比较特殊因为数组同一个所以一维数组不用写大小六、嵌套调用和链式访问1.嵌套调用嵌套调用就是函数之间的互相调用每个函数就像⼀个乐高零件正是因为多个乐高的零件互相无缝的配合才能搭建出精美的乐高玩具也正是因为函数之间有的互相调用最后写出来了相对大型的程序。例子计算某年某月有几天我们需要有两个函数在设计函数的时候我们最好一个函数就为一个功能第一是根据年份判断这一年是否为闰年的函数Is_leap_year第二是根据月份来判断有几天 get_days_of_month就比如这段代码中判断二月前先要判断是否为闰年调用了Is_leap_year这个函数判断。像平常main 函数调⽤scanfprintf 函数未来的稍微大一些代码都是函数之间的嵌套调用但是函数是不能嵌套定义的。2.链式访问所谓链式访问就是将一个函数的返回值作为另外一个函数的函数像链条一样将函数串起来就是函数的链式访问。经典例子printf 的返回值printf(%d\n,printf(%d\n,printf(%d\n,123)));执行结果为12332原因printf 返回值是成功打印的字符数首先正常打印123最内层 printf(“%d\n”, 123) 打印 123 换行 4 字符返回 4中层 printf(“%d\n”, 4) 打印 4 换行 2 字符返回 2外层 printf(“%d\n”, 2) 打印 2 换行 2 字符七、函数的声明和定义1.单个文件这个部分是函数的定义这个是函数的调用我们一般写把定义放在调用前是没有啥问题但是一把定义放在调用后面就会出现警告怎么解决这个问题呢就是函数调用之前先声明一下is_leap_yearis_leap_year这个函数声明函数只要交代清楚函数名函数的返回类型和函数的参数。int is_leap_year(int y)这就是函数声明函数声明中参数只保留类型省略掉名字也是可以的函数的调用一定要满足先声明后使用函数的定义也是⼀种特殊的声明所以如果函数定义放在调⽤之前也是可以的。2.多个文件一般我们写功能复杂的代码时行数比较多我们不会所有代码放在一个文件里会根据功能将拆分代码放入多个文件里⼀般情况下函数的声明、类型的声明放在头文件.h中函数的实现是放在源文件.c⽂件中。test.cdate_utils.cdate_utils.h像这样3.extern和staticstatic 和extern 都是C语言中的关键字。讲解这两个之前先讲作用域和生命周期作用域scope是程序设计概念通常来说一段程序代码中所用到的名字并不总是有效可用的而限定这个名字的可用性的代码范围就是这个名字的作用域。局部变量的作用域是变量所在的局部范围。全局变量的作用域是整个工程项目。生命周期指的是变量的创建(申请内存)到变量的销毁(收回内存)之间的一个时间段。局部变量的生命周期是进入作用域变量创建生命周期开始出作用域生命周期结束。全局变量的生命周期是整个程序的生命周期。我们往往会根据程序的功能将代码拆分放在多个文件中。3.1static修饰局部变量下面通过两段代码理解static局部变量修饰的意义代码1像这个代码的结果为代码2改为局部变量后结果为1 2 3 4 5代码1 test函数变量i 每次进入test函数时都会创建变量生命周期开始并赋值为0然后自增打印出函数的时候变量生命周期将要结束释放内存。代码2中其实test函数中的i创建好后出函数的时候是不会销毁的重新进入函数也就不会重新创建变量直接上次累积的数值继续计算。原因static修饰局部变量改变了变量的生命周期生命周期改变的本质是改变了变量的存储类型本来一个局部变量是存储在内存的栈区的但是被static 修饰后存储到了静态区。存储在静态区的变量和全局变量是一样的生命周期就和程序的生命周期一样了只有程序结束变量才销毁内存才回收。但是作用域不变的。使用建议未来⼀个变量出了函数后我们还想保留值等下次进入函数继续使⽤就可以使⽤static修饰。3.2 static 修饰全局变量比如说在add.c源文件写全局变量int a 50;在test.cexterninta0;extern是用来声明外部符号的如果⼀个全局的符号在A文件中定义的在B文件中想使用就可以使用extern 进行声明然后使用。但是在add.c写static int a 50;导致在test.c也是识别不到变量a所以⼀个全局变量被static修饰使得这个全局变量只能在本源文件内使用不能在其他源文件内使用。本质原因是全局变量默认是具有外部链接属性的在外部的文件中想使⽤只要适当的声明就可以使用但是全局变量被static 修饰之后外部链接属性就变成了内部链接属性只能在自己所在的源文件内部使用了其他源文件即使声明了也是无法正常使用的。3.3static修饰函数add.cintAdd(intx,inty){returnxy;}test.c#includestdio.hexternintAdd(intx,inty);intmain(){printf(%d\n,Add(2,3));return0;}static修饰后staticintAdd(intx,inty){returnxy;}代码会出现链接错误被static修饰后只能在文件内部使用其他文件无法正常的链接使用。本质是因为函数默认是具有外部链接属性具有外部链接属性使得函数在整个工程中只要适当的声明就可以被使用。使⽤建议⼀个函数只想在所在的源文件内部使用不想被其他源文件使用就可以使用static修饰。

相关新闻