【C语言必经之路——第6节】函数内容总结

2023-10-19 23:59

本文主要是介绍【C语言必经之路——第6节】函数内容总结,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

一、什么是函数

二、C语言中的函数

1、分类

2、库函数

3、自定义函数

(1)函数的定义

 (2)函数的参数

(3)函数的调用

(4)作用域

(5)声明与定义

三、多维数组作参数

四、函数的嵌套调用和链式访问

1、嵌套调用

2、链式访问

 五、函数的递归与迭代

1、函数递归

2、函数迭代

3、举例


一、什么是函数

程序是由多个零件组合而成的,而函数就是这种“零件”的一个较小的单位。也可以叫子程序。

在计算机科学中,子程序是一个大型程序中的某部分代码, 由一个或多个语句块组成。它负责完成某项特定任务,而且相较于其他代码,具备相对的独立性。一般会有输入参数并有返回值,提供对过程的封装和细节的隐藏。

二、C语言中的函数

1、分类

1. 库函数
2. 自定义函数

2、库函数

在开发过程中常用的基础功能,它们不是业务性的代码,这些在开发的过程中每个程序员都可能用的到,为了支持可移植性和提高程序的效率,所以C语言的基础库中提供了一系列类似的库函数,方便程序员进行软件开发。使用库函数,必须包含 #include 对应的头文件。

C语言常用的库函数都有:

  • IO函数
  • 字符串操作函数
  • 字符操作函数
  • 内存操作函数
  • 时间/日期函数
  • 数学函数
  • 其他库函数

如何学习库函数,在这里笔者推荐几个网站:

www.cplusplus.com
http://en.cppreference.com(英文版)
http://zh.cppreference.com(中文版)

3、自定义函数

自定义函数和库函数一样,有函数名,返回值类型和函数参数。但是不一样的是这些都是我们自己来设计,针对不同的功能用不同的函数来实现。

(1)函数的定义

ret_type fun_name(para1, * )
{
        statement;  //语句项
}

ret_type 返回类型
fun_name 函数名
para1   函数参数

这里我们从一个例子细分析函数的组成

int  max2 ( int a, int b )              ·接收int型的形参a、b。{  if ( a > b)                        ·求较大值。return a;                        else                                  return b;}                                     ·将求得的int型的值返回到调用源。

函数头( function header )
        该部分表示函数的名称和格式。包含返回类型、函数名、形参声明三部分

返回类型( return type )
        函数返回的值——返回值(return value)的类型。上述函数的情况下,返回的是两个int型数值中较大的一个,所以其类型是int。

函数名( function name )
        函数的名称。从其他零件调用函数时,使用函数名。

形参声明( parameter type list )                                                                                                                 小括号括起来的部分,是用于接收辅助性提示的变量——形式参数的声明。像该函数这样接收多个形参的情况下,使用逗号将它们分隔开来。

                       函数max2中,a和b都被声明为了int型的形参。

 函数体( function body )
        函数体是复合语句。仅在某个函数中使用的变量,原则上应在该函数中声明和使用。但要注意不能声明和形参同名的变量,否则会发生变量名冲突的错误。

 (2)函数的参数

实际参数(实参)
        真实传给函数的参数,叫实参。实参可以是:常量、变量、表达式、函数等。无论实参是何种类型的量,在进行函数调用时,它们都必须有确定的值,以便把这些值传送给形
参。
形式参数(形参)
        形式参数是指函数名后括号中的变量,因为形式参数只有在函数被调用的过程中才分配内存单元,所以叫形式参数。形式参数当函数调用完成之后就自动销毁了。因此形式参数只在函数中有
效。形式参数分配内存单元之后其实相当于实参的一份临时拷贝。

 

可以发现形参x,y与实参num1和num2的地址不同,而且第一次调用时主函数内的实参并没有交换,当第二次实参传地址,用形参指针接收时,数值才交换成功。可以看出来形参和实参并不是一个东西,只是将对应的值传给了形参在函数内部进行使用。还可以发现函数内部的“活动”不影响外函数的运行,只有进行传址调用,外函数的值才会与调用函数内部同步变化。

(3)函数的调用

传值调用
函数的形参和实参分别占有不同内存块,对形参的修改不会影响实参。
传址调用
传址调用是把函数外部创建变量的内存地址传递给函数参数的一种调用函数的方式。
这种传参方式可以让函数和函数外边的变量建立起真正的联系,也就是函数内部可以直接操
作函数外部的变量。
笔者的理解
形参是传来了地址,而且函数内容是对其所指的变量进行相关操作,这样就是传址调用,是可以对外部函数进行改变的。形参接收了地址而且函数是对地址操作,或者形参接收变量,函数对变量进行操作,这样就是传值调用,这样的函数对外部函数是不起作用的,操作区域只在函数内部。
三个例子

<1>传入地址,操作地址——不会影响实参

#include <stdio.h> 
void fun(int *a,int *b)
{int *c;c=a;a=b;b=c;
}
int main()
{int x=3, y=5,*p=&x, *q=&y;fun(p, q);printf("%d %d\n", *p, *q);fun(&x, &y);printf("%d %d\n", *p, *q);
}

 <2>传入变量值,操作变量——不会影响实参

#include <stdio.h>
void Swap1(int x, int y)
{int tmp = 0;tmp = x;x = y;y = tmp;
}int main()
{int num1 = 1;int num2 = 2;Swap1(num1, num2);printf("Swap1::num1 = %d num2 = %d\n", num1, num2);return 0;
}

 <3>传入地址,操作变量——能够影响实参

#include<stdio.h>void Swap2(int* px, int* py)
{int tmp = 0;tmp = *px;*px = *py;*py = tmp;
}int main()
{int num1 = 1;int num2 = 2;Swap2(&num1, &num2);printf("Swap2::num1 = %d num2 = %d\n", num1, num2);return 0;
}

(4)作用域

        赋给变量的标识符,它的名称都有一个通用的范围,称为作用域
        在程序块(复合语句)中声明的变量的名称,只在该程序块中通用,在其他区域都无效也就是说,变量的名称从变量声明的位置开始,到包含该声明的程序块最后的大括号为止,这一区间内通用。这样的作用域称为块作用域
        而在函数外声明的变量标识符,其名称从声明的位置开始,到该程序的结尾都是通用的。这样的作用域称为文件作用域

(5)声明与定义

#include <stdio.h>
#define NUMBER 5                 /*学生人数 */int tensu[NUMBER];              /*数组定义*/int top(void);                 /*函数top的函数原型声明*/
int main()
{extern int tensu[];int i;printf("请输入%d名学生的分数。\n",NUMBER);for (i = 0; i < NUMBER; i++){printf("%d: ", i + 1);scanf("%d", &tensu[i]);}printf("最高分 = %d\n", top( ));return 0;
}
int top(void)
{extern int tensu[];        /*数组的声明(可以省略)*/int i;int max = tensu[0];for (i = 1; i < NUMBER; i++)if (tensu[i] > max)max = tensu[i];return max;
}

<1>  编译器在读取数据时,也是按照从头到尾的顺序依次读取的。因为本程序中函数top的函数定义在main函数后,所以要想在main函数中调用top函数,编译器就需要知道函数top是什么。因此需要使用第七行的声明(函数top无需参数,并且会返回int型的值)。
        像这样明确记述了函数的返回类型,以及形参的类型和个数等的声明称为函数原型声明。
        需要注意的是该声明要以分号结尾。
        函数原型声明只声明了函数的返回值和形参等相关信息,并没有定义函数的实体。

 <2>  21行开始就是top函数的定义声明,包含函数体,是对函数的定义。

        另外,如果函数top的需求(返回值的类型和形式参数等)发生了改变,那么函数定义和函数原型声明两部分都必须进行修改。
但是,在编写程序的时候,如果把函数top的函数定义放在main函数之前,就不用特意使用函数原型声明了。

三、多维数组作参数

接收多维数组的函数,可以省略相当于开头下标的n维的元素个数。但是,(n - 1)维之下的元素个数必须使用常量。
下面是接收一维数组~三维数组的参数的声明示例:

void funcl(int v[ ],int n);                  /*元素类型为int、元素个数随意(n)。*/
void func2(int v[ ][3], int n);              /*元素类型为int[3]、元素个数随意(n)。*/
void func3(int v[ ][2][3],int n) ;       /*元素类型为int [2] [3]、元素个数随意(n)。*/

所接收的数组的元素类型必须固定,但元素个数是自由的。

四、函数的嵌套调用和链式访问

函数和函数之间可以根据实际的需求进行组合的,也就是互相调用的。

1、嵌套调用

函数可以嵌套调用,但是不能嵌套定义。下面代码就是主函数main调用three_line()函数,three_line()函数内调用new_line()函数。

#include <stdio.h>
void new_line()
{
printf("hello world\n");
}
void three_line()
{int i = 0;
for(i=0; i<3; i++){new_line();}
}
int main()
{
three_line();
return 0;
}

2、链式访问

链式访问就是把A函数的返回值作为B函数的参数。

void A()
{
    /*函数体*/
}
void B()
{
    A();
}
int main()
{
    B();
}

#include <stdio.h>
int main()
{printf("%d\n", printf("%d\n", printf("%d\n", 43)));return 0;
}

 五、函数的递归与迭代

1、函数递归

一个过程或函数在其定义或说明中有直接或间接调用自身的编程技巧称为递归。递归的主要思想在于:把大事化小。从字面意思可以理解为重复“递推”和“回归”的过程,当“递推”到达底部时就会开始“回归”。
递归的两个必要条件
存在限制条件,当满足这个限制条件的时候,递归便不再继续。
每次递归调用之后越来越接近这个限制条件。

2、函数迭代

从初始状态开始,每次迭代都更新状态,多次迭代直到到达结束状态。说白了迭代就是一个循环,从初始值进入,不断的计算变化成新的值,最后在末状态输出。

3、举例

//递归法求n的阶乘
int factorial1(int n)
{if (n <= 1)return 1;elsereturn n * factorial1(n - 1);
}//迭代法求n的阶乘
int factorial2(int n)
{int result = 1;while (n > 1){result *= n;n -= 1;}return result;
}int main()
{int n = 5;printf("%d\n", factorial1(n));printf("%d\n", factorial2(n));
}

今天的分享就到这啦😉


如果我的文章对您有帮助,

请 “点赞” “收藏” “关注” 一键三连哦!

想了解更多知识请前往故里♡927的博客

如果以上内容有什么问题,欢迎留言,大家一起学习,共同进步。


我们下期见😉~~

这篇关于【C语言必经之路——第6节】函数内容总结的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/243226

相关文章

C++统计函数执行时间的最佳实践

《C++统计函数执行时间的最佳实践》在软件开发过程中,性能分析是优化程序的重要环节,了解函数的执行时间分布对于识别性能瓶颈至关重要,本文将分享一个C++函数执行时间统计工具,希望对大家有所帮助... 目录前言工具特性核心设计1. 数据结构设计2. 单例模式管理器3. RAII自动计时使用方法基本用法高级用法

Python中logging模块用法示例总结

《Python中logging模块用法示例总结》在Python中logging模块是一个强大的日志记录工具,它允许用户将程序运行期间产生的日志信息输出到控制台或者写入到文件中,:本文主要介绍Pyt... 目录前言一. 基本使用1. 五种日志等级2.  设置报告等级3. 自定义格式4. C语言风格的格式化方法

Spring 依赖注入与循环依赖总结

《Spring依赖注入与循环依赖总结》这篇文章给大家介绍Spring依赖注入与循环依赖总结篇,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录1. Spring 三级缓存解决循环依赖1. 创建UserService原始对象2. 将原始对象包装成工

GO语言短变量声明的实现示例

《GO语言短变量声明的实现示例》在Go语言中,短变量声明是一种简洁的变量声明方式,使用:=运算符,可以自动推断变量类型,下面就来具体介绍一下如何使用,感兴趣的可以了解一下... 目录基本语法功能特点与var的区别适用场景注意事项基本语法variableName := value功能特点1、自动类型推

GO语言中函数命名返回值的使用

《GO语言中函数命名返回值的使用》在Go语言中,函数可以为其返回值指定名称,这被称为命名返回值或命名返回参数,这种特性可以使代码更清晰,特别是在返回多个值时,感兴趣的可以了解一下... 目录基本语法函数命名返回特点代码示例命名特点基本语法func functionName(parameters) (nam

Python Counter 函数使用案例

《PythonCounter函数使用案例》Counter是collections模块中的一个类,专门用于对可迭代对象中的元素进行计数,接下来通过本文给大家介绍PythonCounter函数使用案例... 目录一、Counter函数概述二、基本使用案例(一)列表元素计数(二)字符串字符计数(三)元组计数三、C

MySQL中查询和展示LONGBLOB类型数据的技巧总结

《MySQL中查询和展示LONGBLOB类型数据的技巧总结》在MySQL中LONGBLOB是一种二进制大对象(BLOB)数据类型,用于存储大量的二进制数据,:本文主要介绍MySQL中查询和展示LO... 目录前言1. 查询 LONGBLOB 数据的大小2. 查询并展示 LONGBLOB 数据2.1 转换为十

Java使用正则提取字符串中的内容的详细步骤

《Java使用正则提取字符串中的内容的详细步骤》:本文主要介绍Java中使用正则表达式提取字符串内容的方法,通过Pattern和Matcher类实现,涵盖编译正则、查找匹配、分组捕获、数字与邮箱提... 目录1. 基础流程2. 关键方法说明3. 常见场景示例场景1:提取所有数字场景2:提取邮箱地址4. 高级

Go语言连接MySQL数据库执行基本的增删改查

《Go语言连接MySQL数据库执行基本的增删改查》在后端开发中,MySQL是最常用的关系型数据库之一,本文主要为大家详细介绍了如何使用Go连接MySQL数据库并执行基本的增删改查吧... 目录Go语言连接mysql数据库准备工作安装 MySQL 驱动代码实现运行结果注意事项Go语言执行基本的增删改查准备工作

C#高效实现Word文档内容查找与替换的6种方法

《C#高效实现Word文档内容查找与替换的6种方法》在日常文档处理工作中,尤其是面对大型Word文档时,手动查找、替换文本往往既耗时又容易出错,本文整理了C#查找与替换Word内容的6种方法,大家可以... 目录环境准备方法一:查找文本并替换为新文本方法二:使用正则表达式查找并替换文本方法三:将文本替换为图