C语言基础篇3:函数

news2024/11/19 17:47:54

1 函数简介

        C源程序是由函数组成的,一个程序往往由多个函数组成,函数是程序实现模块化变成的基本的单元,一般是为了完成某一个特定的功能,相当于其他语言中的子程序。一个较大程序的各项功能都是由各个子程序共同完成的,或者说C程序的全部工作都是由各式各样的函数完成的。

1.1 概述

        一个完整的C程序是通过函数之间互相调用实现的。通过对函数模块的调用,可以实现相应的功能。在进行程序设计时,会将一些常用的功能模块编写成函数,放在函数库中供公共使用。有些函数是按照ANSI C的要求随C语言编译器提供的,这种函数称为库函数。像printf、scanf等,都属于库函数。

        每个程序的入口和出口都是位于main函数中。编写程序时,并不是将所有的内容都放在main方法中。为了方便规划、组织、编写和调试,一般的做法是将一个程序划分为若干个程序模块,每个程序模块都完成一部分功能。这样不同的程序模块可以由不同的人来完成,从而提高软件开发效率。

        也就是说,main函数可以调用其他的函数,其他函数也可以互相调用。在main函数中调用其他的函数,这些函数执行完毕后又返回到man函数中。通常把这些被调用的函数称为下层函数。函数调用发生时,立即执行被调用的函数,而调用者则进入等待的状态,直到被调用函数执行完毕。函数可以由参数和返回值。

【注意】C程序中所有的函数都是平行的,即在定义函数时是互相独立的,在一个函数中不能嵌套定义另一个函数,函数间可以互相调用,但main函数是不能被调用的。

【示例1.1】在主函数中调用其他函数

#include <stdio.h>
void Move();
void Build();
void Paint();
int main(){
    Move();
    Build();
    Paint();
    return 0;
}
void Move(){
    printf("=============================\n");
    printf("==========执行move函数===================\n");
    printf("=============================\n");
}
void Build(){
    printf("=============================\n");
    printf("==========执行Build函数===================\n");
    printf("=============================\n");
}
void Paint(){
    printf("=============================\n");
    printf("==========执行Paint函数===================\n");
    printf("=============================\n");
}

        下面分析一下这个程序:

        首先,一个源文件是由一个或多个函数组成。一个源程序文件是一个编译单位,即以源程序为单位进行编译,而不是以函数为单位进行编译。

        函数库由C系统提供,用户无须定义,在调用函数之前也不必再程序中作类型说明,只需在程序前包含有该函数原型的头文件即可在程序中直接调用。例如,在上面的程序中用于控制台显示信息的printf函数,之前应在程序开始部分包含stdio.h头文件;又如,要使用其他字符串操作函数strlen、 strcmp等时,也应在程序开始部分包含string.h。

        用于自定义函数,就是用户自己编写的用来实现特定功能的函数,如上面程序中的Move函数等。

        在该程序中,要是printf函数首先要包含stdio.h头文件,之后声明3个自定义函数,最后在主函数中调用3个函数。 

1.2 函数的定义与声明

        1、函数的定义形式

        在程序中编写函数时,函数的定义是让编译器知道函数的功能。函数一般包括用户自己定义和系统提供的标准函数两种。如果是系统提供的标准函数,那么不需要进行定义即可使用,如果是用户自己定义的函数,那么必须遵守“先定义,后使用”的原则。函数的定义分两部分:函数头和函数体。函数的定义语法:

函数返回值的类型名     函数名(形式参数列表) --函数头

 {

        声明部分

        语句部分                                                         --函数体

        return 表达式

}

函数头分三个部分:

        返回值类型:返回值可以是某个C数据类型。

        函数名:函数名也就是函数的标识符,函数名在程序中必须是唯一的。

        参数列表:形式参数列表简称为形参,可以没有变量也可以有多个变量,在进行函数调用时,实际参数将被复制到这些变量中。有时,函数定义中没有形参,叫做无参函数,无参函数一般不用写返回值类型。

函数体:

        函数体位于函数头下方,由一对大括号括起来,大括号决定了函数体的范围。函数体包括局部变量和函数的可执行代码。声明部分包括函数声明、变量定义和变量声明,函数要实现的特定功能,都是在函数体部分通过代码完成。最后通过return返回函数执行的结果。

        2、函数的定义与声明

        在程序中编写函数时,要先对函数进行声明,然后再对函数进行定义。函数的声明是让编译器知道函数的名称、参数、返回值类型等信息。函数的定义是让编译器知道函数的功能。

        函数的声明格式由函数返回值类型、函数名、参数列表和分号4部分组成。例如:

返回值类型   函数名(参数列表);

        【注意】如果将函数的定义放在调用函数之前,那么就不需要进行函数的声明。此时函数的定义就包含了函数的声明。

        定义:实在编译器内创建了一个对象,为这个对象分配一块内存,并且给对象取一个名字,取得名字就是经常说的变量名或对象名。

        声明:告诉编译器这个名字已经分配到一块内存里,并且这个名字现在归此声明所用,其他地方不允许再用这个名字。

        定义和声明的最大区别:定义创建了对象,并给对象分配内存;声明没有为对象分配内存。

【示例2.1】计算任意两个整数的积

#include <stdio.h>
int mul(int x,int y){
    int z;
    z = x * y;
    return z;
}
int main(){
    int a,b,c;
    printf("请输入a和b :\n");
    scanf("%d,%d",&a,&b);
    c = mul(a,b);
    printf("a 和 b 的乘积是:%d\n",c);
    return 0;
}

      

2 函数参数

        在调用函数时,大多数情况下,主调函数和被调用函数之间有数据传递关系,这就是前面提到的函数形式。函数参数的作用是传递数据给函数使用,函数利用接收的数据进行具体的操作处理

2.1 形式参数和实际参数

        在使用函数时,通常会涉及两种参数,形式参数和实际参数,两者之间既有联系又有区别。

        形式参数:在定义函数时,函数名后面括号中的变量名称为“形式参数”。在函数调用之前,传递给函数的值将被复制到这些形参中。

        实际参数:在调用一个函数时,也就是真正使用一个函数时,函数后面括号中的参数为“实际参数”。

        在通常情况下,形式参数简称为形参,实际参数简称为实参。

        形参和实参的特点和注意事项如下:

        形参变量只有在被调用时才分配内存单元,在调用结束时,会释放所分配的内存单元。因此,形参只有在函数内部有效。函数调用结束返回主调函数后则不能在使用该形参变量。

        实参可以是常量、变量、表达式和函数等,不论是什么类型的数据,只要是实参,再到用进行调用时,这个类型量必须是确定的值,以便把这些值传递给形参。为了避免发生“类型不匹配”的错误,实参和形参的类型、数量、书写顺序都必须要保持一致。

        C语言固定,实参变量对形参变量的数值传递是单向传递,即只能由实参传递给形参。

2.2 数组作为函数参数

        上面介绍了,在传递函数参数时,将变量作为函数的参数,除此之外还有一种特殊的情况,即数组作为函数参数。因为将数组作为函数参数进行传递,不同于标准的赋值调用的参数传递方法。下面将介绍数组作为函数参数时的参数传递方法。

        当数组作为函数的参数时,只传递数组的地址,而不是将整个数组赋值到函数中去。当用数组作为实参调用函数时,指向该数组的第一个元素的指针就被传递到函数中。        

        例如:定义一个具有10个元素的整型数组:int array[10] ;

注意:在C语言中,没有任何下标的数组名就是一个指向该数组第一个元素的指针。其中的代码没有下标的数组名array与指向第一个元素的指针*array是相同的。

        由于实参可以是表达式形式,数组元素可以是表达式的组成部分,因此数组元素可以作为函数的实参,与用变量作为函数实参一样,是单向传递。

【示例2.2.1 数组元素作为函数参数】

        

#include <stdio.h>
void showMembers(int i);
int main(){
    int array[10];
    int i ;
    for(i = 0;i<10;i++){
        array[i] = i;
    }
    for(i = 0;i < 10;i++){
        showMembers(array[i]);
    }
    return 0;
}
void showMembers(int i){
    printf("显示的元素是:%d\n" ,i);
}

3 函数调用

        函数的调用方式有3种:函数语句调用、函数表达式和函数参数调用。

        如果自定义函数在主函数的前面时,就不需要在引用头文件后再进行声明,如果自定义函数在主函数的后面时,就需要在引用头文件时进行提前声明。

      3.1  函数语句调用

        把函数的调用作为一个语句就叫函数语句调用。函数语句调用是最长使用的调用函数的方式。

        【示例3.1】函数语句调用:

#include <stdio.h>
void disPlay(){
    printf("hello,world!\n");
}
int main(){
    disPlay();//函数语句调用
    return 0;
}

        3.2 函数表达式调用

        函数出现在一个表达式中,这时要求函数的带回一个确定的值,这个值参加表达式的运算。

        【示例3.2】函数表达式调用

        

#include <stdio.h>
int addNum(int num1,int num2);
int main(){
    int result;
    int num3 = 10;
    result = num3 * addNum(3,5);
    printf("计算的结果是: %d  \n",result);
    return 0;
}
int addNum(int num1,int num2){
    int result;
    result = num1 + num2;
    return result;
}

 

3.3 函数参数调用

        函数调佣可以作为一个函数的实参,将函数返回值作为实参传递到函数中进行使用。函数出现在一个表达式中,这时要求函数带回一个确定的值,这个值参加表达式的运算。

【示例3.3】函数参数调用:

#include <stdio.h>
int addNum(int num1,int num2);
int main(){
    int result;
    result = addNum(20, addNum(3,2));
    printf("result: %d  \n",result);
    return 0;
}
int addNum(int num1,int num2){
    int result;
    result = num1 + num2;
    return result;
}

 

4 函数嵌套

        在C语言中,函数的定义都是互相平行、独立的。也就是说在定义函数时,一个函数体内不能包含定义另一个函数。但是可以嵌套调用函数,也就是说,在一个函数体内可以调用另一个函数。

【示例4】函数嵌套调用

#include <stdio.h>
void a();
void b();
void c();
int main(){
    a();
    return 0;
}
void a(){
    printf("a方法可以调用b方法\n");
    b();
}
void b(){
    printf("b方法可以调用c方法 \n");
    c();
}
void c(){
    printf("c方法被b方法调用 \n");
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1199784.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Seata源码学习 】 AT模式 第一阶段 @GlobalTransaction的扫描

1. SeataAutoConfiguration 自动配置类的加载 基于SpringBoot的starter机制&#xff0c;在应用上下文启动时&#xff0c;会加载SeataAutoConfiguration自动配置类 # Auto Configure org.springframework.boot.autoconfigure.EnableAutoConfigurationio.seata.spring.boot.aut…

Zabbix SNMPv3

一、Snmpv3简述 SNMPv3是Simple Network Management Protocol version 3&#xff08;简单网络管理协议第三版&#xff09;的缩写。它是一种网络管理协议&#xff0c;用于监控和管理网络中的设备、系统和应用程序。 相对于之前的版本&#xff0c;SNMPv3具有更强的安全性和扩展…

NGINX三种虚拟主机的配置

基于IP的配置 首先在原本基础上增加两个IP地址 [rootlocalhost conf.d]# nmcli connection modify ens33 ipv4.addresses 192.168.38.140 [rootlocalhost conf.d]# nmcli connection modify ens33 ipv4.addresses 192.168.38.150 [rootlocalhost conf.d]# nmcli connection u…

SharePoint 是什么

SharePoint 平台使您能够以在线方式和本地方式轻松地管理和协调业务数据。因为其灵活性和易使用性&#xff0c;公司可以快速采用SharePoint来管理其业务数据。 SharePoint Microsoft 365 一种基于云的服务&#xff0c;由 Microsoft 托管&#xff0c;适用于各种规模的企业。 任何…

vue2 数字软键盘 封装 可拖动 使用简单

1、效果图 2、使用方式 <Keyboard v-if"show" close"show false" :inputDom"$refs.input" /> 封装的数字键盘 Keyboard.vue 组件代码 <template><divclass"keyboard"ref"keyboard":style"{ left: …

CS224W6.2——深度学习基础

在本文中&#xff0c;我们回顾了深度学习的概念和技术&#xff0c;这些概念和技术对理解图神经网络至关重要。从将机器学习表述为优化问题开始&#xff0c;介绍了目标函数、梯度下降、非线性和反向传播的概念。 文章目录 1. 大纲2. 优化问题2.1 举例损失函数 3. 如何优化目标函…

matlab Silink PID 手动调参

&#xff08;业余&#xff09;PID即比例积分微分&#xff0c;它将给定值r(t)与实际输出值y(t)的偏差的比例(P)、积分(I)、微分(D)通过线性组合形成控制量&#xff0c;对被控对象进行控制。我们先用matlab Silink弄一个简易的PID例子&#xff1a; 中间三条就是比例&#xff0c;积…

【Python】一篇带你掌握数据容器之列表

目录 前言&#xff1a; 一、列表 1.列表的定义 2.列表的下标索引 3.列表的常用操作 &#xff08;1&#xff09;index方法&#xff1a;查找某元素的下标 (2)修改特定位置下标的元素 &#xff08;3&#xff09;insert&#xff08;下标&#xff0c;元素&#xff09;方法&a…

C/C++调试工具 - gdb详解

C/C调试工具 -gdb详解 1 简介 2 常用的命令 3 使用的条件 4 程序调试 4.1 直接运行程序 4.2 断点调试(在某一行) 4.3 断点调试(在函数入口处打断点) 5 调试core文件 5.1 生成core文件的方法 5.2 调试core文件 1 简介 GDB是Linux下非常好用且强大的调试工具。GD…

Linux组调度

为什么引入组调度可以参考这篇文章的讨论。核心原因是基础的调度算法都是基于任务的&#xff0c;如果用户A有10个任务&#xff0c;用户B只有1个任务&#xff0c;假设这些任务的优先级都相同&#xff0c;那么用户A得到的CPU时间将是用户B的10倍&#xff0c;这样从任务的角度看虽…

Mac Qt 5.13.2无法加载文件

在Mac OS 14.0系统上&#xff0c;离线安装了Qt5.13.2&#xff0c;但是新建一个工程&#xff0c;却无法正常使用&#xff0c;只能加载出pro文件&#xff0c;其他文件都加载不出来&#xff0c;提示错误&#xff1a;Project ERROR: failed to parse default search paths from com…

手机号验证码登录

登录入口 1.app 正常登录入口 2.app 网页登录&#xff0c;比如分享直播卡片时&#xff0c;进入直播间需要先进行登录 3.pc 登录 一&#xff0c;app常见的登录方式 1.手机号验证码登录 2.用户名密码登录 3.一键登录 二&#xff0c;手机验证码登录示意图 三&#xff0c;流程 0.登…

No178.精选前端面试题,享受每天的挑战和学习

🤍 前端开发工程师(主业)、技术博主(副业)、已过CET6 🍨 阿珊和她的猫_CSDN个人主页 🕠 牛客高级专题作者、在牛客打造高质量专栏《前端面试必备》 🍚 蓝桥云课签约作者、已在蓝桥云课上架的前后端实战课程《Vue.js 和 Egg.js 开发企业级健康管理项目》、《带你从入…

已解决:java.net.BindException: 地址已在使用

解决zookeeper报错&#xff1a;java.net.BindException: 地址已在使用&#xff0c;是因为端口被占用。显示Starting zookeeper ... STARTED&#xff0c;jps没有QuorumPeerMain进程。 问题截图&#xff1a; 看似Starting zookeeper ... STARTED&#xff0c;实则集群并没有启动…

Linux 程序开发流程 / 基本开发工具 / Vim / GCC工具链 / Make 工具 / Makefile 模板

编辑整理 by Staok。 本文部分内容摘自 “100ask imx6ull” 开发板的配套资料&#xff08;如 百问网的《嵌入式Linux应用开发完全手册》&#xff0c;在 百问网 imx6ull pro 开发板 页面 中的《2.1 100ASK_IMX6ULL_PRO&#xff1a;开发板资料》或《2.2 全系列Linux教程&#xf…

华为ensp:rip宣告

ip全部配置好 R1 进入r1视图模式 rip network 192.168.1.0 network 1.0.0.0 R2 进入r2视图模式 rip network 192.168.2.0 network 1.0.0.0 这样就完成了宣告 display ip routing-table 查看路由表

Java基础——数组(一维数组与二维数组)

文章目录 一维数组声明初始化与赋值内存图解 二维数组声明初始化与赋值内存图解 数组练习 数组是多个相同类型的数据按一定顺序排列的集合。 说明&#xff1a; 数组是引用数据类型&#xff0c;数组的元素是同一类型的任何数据类型&#xff0c;包括基本数据类型和引用数据类型…

基于YOLOv8的输电线路异物识别算法应用

基于 YOLOv8 的输电线路异物识别算法应用 输电线路作为电力系统的重要一环&#xff0c;保证其安全稳定运行是十分必要的。由于长期暴露于室外&#xff0c;线路所面临的不安全因素繁多&#xff0c;异物入侵便是其中之一。异物可能会引起线路短路甚至诱发火灾&#xff0c;因此要加…

使用3D Touch,让你左右逢源,操作更自然

本文介绍了如何在苹果设备上使用3D Touch&#xff0c;以及哪些应用程序支持该工具。3D Touch在Apple Watch上也称为Force Touch&#xff0c;在iPhone XR上也称为Haptic Touch。 如何改变3D触摸的灵敏度 按照以下步骤调整3D Touch的灵敏度&#xff1a; 1、打开“设置”应用程…

docker安装AWVS 23.9.231005181

本文声明仅AWVS用作学习使用 将镜像文件secfa_awvs.tar复制到目标机器上。 我的百度网盘文件路径&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1frbOH4UZlMz9bMXyZs1o0g 提取码&#xff1a;na6y –来自百度网盘超级会员V6的分享 在目标机器上&#xff0c;使用以下命…