【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

相关文章

Oracle的to_date()函数详解

《Oracle的to_date()函数详解》Oracle的to_date()函数用于日期格式转换,需要注意Oracle中不区分大小写的MM和mm格式代码,应使用mi代替分钟,此外,Oracle还支持毫... 目录oracle的to_date()函数一.在使用Oracle的to_date函数来做日期转换二.日

Android数据库Room的实际使用过程总结

《Android数据库Room的实际使用过程总结》这篇文章主要给大家介绍了关于Android数据库Room的实际使用过程,详细介绍了如何创建实体类、数据访问对象(DAO)和数据库抽象类,需要的朋友可以... 目录前言一、Room的基本使用1.项目配置2.创建实体类(Entity)3.创建数据访问对象(DAO

C语言线程池的常见实现方式详解

《C语言线程池的常见实现方式详解》本文介绍了如何使用C语言实现一个基本的线程池,线程池的实现包括工作线程、任务队列、任务调度、线程池的初始化、任务添加、销毁等步骤,感兴趣的朋友跟随小编一起看看吧... 目录1. 线程池的基本结构2. 线程池的实现步骤3. 线程池的核心数据结构4. 线程池的详细实现4.1 初

Java向kettle8.0传递参数的方式总结

《Java向kettle8.0传递参数的方式总结》介绍了如何在Kettle中传递参数到转换和作业中,包括设置全局properties、使用TransMeta和JobMeta的parameterValu... 目录1.传递参数到转换中2.传递参数到作业中总结1.传递参数到转换中1.1. 通过设置Trans的

C# Task Cancellation使用总结

《C#TaskCancellation使用总结》本文主要介绍了在使用CancellationTokenSource取消任务时的行为,以及如何使用Task的ContinueWith方法来处理任务的延... 目录C# Task Cancellation总结1、调用cancellationTokenSource.

C++11的函数包装器std::function使用示例

《C++11的函数包装器std::function使用示例》C++11引入的std::function是最常用的函数包装器,它可以存储任何可调用对象并提供统一的调用接口,以下是关于函数包装器的详细讲解... 目录一、std::function 的基本用法1. 基本语法二、如何使用 std::function

HarmonyOS学习(七)——UI(五)常用布局总结

自适应布局 1.1、线性布局(LinearLayout) 通过线性容器Row和Column实现线性布局。Column容器内的子组件按照垂直方向排列,Row组件中的子组件按照水平方向排列。 属性说明space通过space参数设置主轴上子组件的间距,达到各子组件在排列上的等间距效果alignItems设置子组件在交叉轴上的对齐方式,且在各类尺寸屏幕上表现一致,其中交叉轴为垂直时,取值为Vert

学习hash总结

2014/1/29/   最近刚开始学hash,名字很陌生,但是hash的思想却很熟悉,以前早就做过此类的题,但是不知道这就是hash思想而已,说白了hash就是一个映射,往往灵活利用数组的下标来实现算法,hash的作用:1、判重;2、统计次数;

hdu1171(母函数或多重背包)

题意:把物品分成两份,使得价值最接近 可以用背包,或者是母函数来解,母函数(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v)(1 + x^v+x^2v+.....+x^num*v) 其中指数为价值,每一项的数目为(该物品数+1)个 代码如下: #include<iostream>#include<algorithm>

科研绘图系列:R语言扩展物种堆积图(Extended Stacked Barplot)

介绍 R语言的扩展物种堆积图是一种数据可视化工具,它不仅展示了物种的堆积结果,还整合了不同样本分组之间的差异性分析结果。这种图形表示方法能够直观地比较不同物种在各个分组中的显著性差异,为研究者提供了一种有效的数据解读方式。 加载R包 knitr::opts_chunk$set(warning = F, message = F)library(tidyverse)library(phyl