当前位置: 首页 > news >正文

C语言:函数

C语言:函数

    • 函数的概念
    • 库函数
    • 自定义函数
      • 实参与形参
      • return语句
      • 数组做参数
      • 声明与定义
      • extern
      • static
    • 嵌套调用


函数的概念

在C语言中,存在一个函数的概念,有人也将其翻译为子程序。
在数学中,函数是一个完成特定功能的公式,比如传入x的值,就能输出满足函数的y值。C语言函数也同理,C语言的函数是一个完成某项特定任务的代码段

而我们常见的函数,分为库函数与自定义函数,接下来我一一为大家介绍。


库函数

C语言标准中,规定了一系列常用的函数标准,称为标准库。编译器厂商就会根据这个标准来实现一系列函数,供用户使用,这些函数就称之为库函数。

要注意,库函数不是C语言官方实现的,C语言只制定标准,具体实现是编译器的厂商来完成的,所以不同的编译器下,库函数的实现可能不同,但是用法是一致的。

库函数是在标准库对应的头文件中声明的,所以库函数的使用需要包含对应的头文件。


自定义函数

顾名思义,自定义函数就是用户可以自己设计函数。

语法:

返回类型 函数名(参数)
{//代码
}

返回类型:就是函数结束时返回什么样类型的值,比如我们调用rand函数,其会返回一个整数给我们,那么rand函数的返回类型就是int。
参数:就是用户使用这个函数,需要传入的值。

比如这样一个加法函数:

int add(int x, int y)
{int z = x + y;return z;
}

函数名就是add,而add左侧的int就是函数的返回类型,说明add函数最后会返回一个int类型的数据。
(int x, int y)就是函数的参数,这说明使用这个函数需要传入两个int类型的数据。

在需要使用函数时,可以这样:

add(3, 5);

也就是函数名(参数)的形式。

实参与形参

含函数使用的过程中,我们把参数分为形参和实参。

实参:
在以上的add函数中,我们在调用时add(3, 5)中的35就是实参,它们是传入函数的数据。

形参:
在定义函数时,add函数名后面的(int x, int y)中的x和y就是形参。
为什么叫做形参呢?实际上,如果只是定义了add函数而不去调用的话,xy只是形式上存在的,它们并不会向内存申请空间,不会真实存在,所以叫做形参。

而形参是实参的一份临时拷贝,对形参的改动不会影响实参。

比如下面的函数:

void func(int x)
{x++;
}int main()
{int a = 0;func(a);printf("%d", a);return 0;
}

上述函数中,a就是一个实参,起初a = 0,当我们把a传给函数func,形参x得到a的值。在函数内部对形参进行了x++,此时x = 1,当函数结束时,输出a的值。
最后输出的a = 0,因为x作为形参,x++a没有影响。


return语句

当我们的函数需要返回值的时候,就需要return语句,return后面接着的值,就是函数最后返回给外界的值。

  • return后面可以是数值,也可以是表达式。
  • return后面也可以什么都没有,直接写return;,这种形式适合返回值为void类型。
  • return后面的值类型如果与返回类型不一致,编译器则会将其隐式转化。
  • 如果函数中有分支语句,要保证每种情况都有返回值。

数组做参数

数组也可以做函数的参数,比如这样:

void func(int arr[])
{
}

其中int arr[]就是一个数组类型的参数,其可以接收一个数组。
数组传参时,直接传入数组名即可:

int main()
{int arr[5] = {1, 2, 3, 4, 5};func(arr);return 0;
}
  • 当一维数组做形参时,数组的长度是可以省略的。
  • 当二位数组做形参时,行可以省略,列不可以省略。
  • 当数组做参数,实参和形参是同一个数组,修改形参会对实参造成影响。

声明与定义

C语言的函数声明和定义是定义函数的两个主要部分。

函数定义是指在函数声明的基础上,给出函数的具体实现。函数定义包含函数的返回值类型、函数名、函数的参数列表和函数体。函数定义的目的是为了给出函数的具体实现,也就是函数体中要执行的代码。

函数定义的语法格式如下:

返回类型 函数名(参数)
{// 函数体
}

也就是我们先前讲的基本格式,我们实现函数的功能,就是在函数定义时完成的。

函数声明是指在函数被调用之前,在代码的某个地方提前声明函数的存在。函数声明告诉编译器函数的名称、函数参数的类型和返回值类型。函数声明的目的是为了让编译器在编译过程中能够正确地解析函数的调用。

函数声明的语法格式如下:

返回值类型 函数名(参数类型1 参数名1, 参数类型2 参数名2, ...)

比如:

int sum(int a, int b);

这就是一个函数的声明,可以理解为函数声明就是函数定义去掉了{}内部的内容。
不过函数声明也可以只有类型,没有形参名称,比如这样:

int sum(int, int);

函数声明和定义的关系是:函数声明是对函数定义的提前声明,函数定义是对函数的具体实现。在实际使用中,通常将函数的声明放在头文件中,将函数的定义放在源文件中。这样做的好处是可以将函数的声明和定义进行分离,方便代码的管理和维护。

需要注意的是,在C语言中,函数的声明和定义可以放在任意顺序,只要在函数被调用之前可以访问到函数的声明即可。


extern

在C语言中,extern关键字用于声明一个全局变量或者函数,但不进行定义。它可以被用于多个源文件中,用于告诉编译器该变量或函数是在其他源文件中定义的

在C语言中,变量的声明和定义是不同的。声明告知编译器该变量的类型和名称,而定义则为该变量分配存储空间并初始化它。如果在一个源文件中声明一个全局变量,那么在其他源文件中访问该全局变量就需要使用extern关键字。

这里是一个例子来说明extern关键字的使用:

假设我们有两个源文件:main.c和helpers.c。我们希望在main.c中使用helpers.c中定义的全局变量count和函数increment()

首先,我们在helpers.c中定义全局变量:

int count = 0;void increment() {count++;
}

然后,在main.c中声明这些全局变量和函数,并使用extern关键字告诉编译器它们是在其他源文件中定义的:

#include <stdio.h>extern int count; // 声明count变量
extern void increment(); //声明increment函数int main() {increment(); // 调用increment函数printf("count: %d\n", count); // 访问count变量return 0;
}

注意,在main.c中,我们需要包含helpers.c中定义的函数的头文件,以便在编译过程中编译器可以知道函数的签名。

编译并运行这些代码,输出将会是count: 1。这是因为我们在increment函数中增加了count变量的值,并在main函数中访问了它。

总结一下,extern关键字是用于在一个源文件中访问另一个源文件中定义的全局变量和函数。它将变量或函数的声明与定义分离,使得代码更加模块化和可扩展。


static

在C语言中,"static"是一个关键字,用于修饰变量和函数。它的行为和作用会根据修饰的对象不同而有所不同。下面分别介绍"static"关键字在变量和函数中的作用,并给出相关案例。

  1. "static"修饰变量:

    • 在函数内部,"static"修饰的局部变量会被赋予静态的存储持续时间。这意味着变量的生命周期将持续到程序结束,而不是在函数执行完后销毁。此外,静态局部变量的作用域仍然是局部的,只能在定义它的函数内部使用

    • 例子:

      #include <stdio.h>void example() {static int count = 0;count++;printf("Count: %d\n", count);
      }int main() {for (int i = 0; i < 5; i++) {example();}return 0;
      }
      

      输出结果:

      Count: 1
      Count: 2
      Count: 3
      Count: 4
      Count: 5
      

      在上面的例子中,静态变量"count"被定义为函数"example()"的局部变量。每次调用"example()"函数时,"count"值递增并打印。由于静态变量的存储持续时间为整个程序,因此每次调用"example()"函数时,"count"的值会保留。

    • 在全局范围内,"static"修饰的全局变量具有内部链接,即只能在当前源文件中访问,其他源文件中不可见。

    • 例子:

      // File1.c
      static int global_var = 10;// File2.c
      #include <stdio.h>extern int global_var;int main() {printf("Global Variable: %d\n", global_var);return 0;
      }
      

      输出结果:

      Global Variable: 10
      

      在上面的例子中,我们在File1.c中声明了一个静态全局变量"global_var"。由于它是静态的,所以只能在同一源文件中访问。然后,在File2.c中通过extern关键字声明"global_var",确保在其他源文件中可见,从而在main函数中进行访问。

  2. "static"修饰函数:

    • 在函数声明前,"static"修饰的函数具有内部链接。这意味着该函数只能在当前源文件中访问,其他源文件中不可见。
    • 例子:
      // File1.c
      static void static_function() {printf("This is a static function.\n");
      }// File2.c
      extern void static_function();int main() {static_function();return 0;
      }
      
      输出结果:
      This is a static function.
      
      在上面的例子中,我们在File1.c中定义了一个静态函数"static_function()“。由于它是静态的,所以只能在同一源文件中访问。然后,在File2.c中通过extern关键字声明"static_function()”,确保在其他源文件中可见,从而在main函数中进行访问。

总结:

  • 在C语言中,"static"关键字的作用取决于其修饰的对象。它可以用于修饰局部变量和全局变量,以及函数声明。
  • 对于局部变量,"static"赋予了它们静态存储持续时间和保留其值的能力。
  • 对于全局变量,"static"给予了它们内部链接特性,使其只能在同一源文件中访问。
  • 对于函数声明,"static"使其具有内部链接特性,使其只能在同一源文件中访问。

嵌套调用

在C语言中,函数的嵌套调用指的是在一个函数中调用另一个函数,而被调用的函数又可以继续调用其他函数。这种嵌套调用的方式可以实现代码的模块化,提高代码的可读性和可维护性。

下面以一个简单的例子来说明函数的嵌套调用:

#include <stdio.h>int func2(int num)
{printf("In func2\n");return num * num;
}int func1(int num)
{printf("In func1\n");int result = func2(num);return result + 1;
}int main()
{int number = 3;int result = func1(number);printf("Result: %d\n", result);return 0;
}

在上面的例子中,有三个函数:mainfunc1func2main函数是程序的入口,func1func2是被调用的函数。

main函数中定义了一个整型变量number,并将其赋值为3。然后调用func1函数,将number作为参数传递给func1。在func1函数中,可以看到它调用了func2函数,并将num作为参数传递给func2func2函数执行完毕后,返回结果给func1,最后func1将其结果加1并返回给main函数。

运行上述代码,输出结果如下:

In func1
In func2
Result: 10

从结果可以看出,main函数调用func1函数,func1函数又调用了func2函数,实现了函数的嵌套调用。通过函数的嵌套调用,可以将代码按照功能划分为若干个小模块,提高代码的可读性和可维护性。


相关文章:

C语言:函数

C语言&#xff1a;函数 函数的概念库函数自定义函数实参与形参return语句数组做参数声明与定义externstatic 嵌套调用 函数的概念 在C语言中&#xff0c;存在一个函数的概念&#xff0c;有人也将其翻译为子程序。 在数学中&#xff0c;函数是一个完成特定功能的公式&#xff0…...

jmeter-问题一:关于线程组,线程数,用户数详解

文章目录 jmeter参数介绍1.线程数2.准备时长(Ramp-up)3.循环次数4.same user on each iteratio5.调度器 场景一&#xff1a;当你的线程组中线程数为1,循环为1场景二&#xff1a;当你的线程组中线程数为2&#xff0c;循环为1场景三&#xff1a;当你的线程组中线程数为1&#xff…...

golang 通过 cgo 调用 C++ 库

思路 将 C 库包装成 C 库 -> golang 通过 cgo 调用 C 库 C 相关文件 目录列表 include/ some.h C 库头文件some_wrapper.h < 用于将 C 库包装成 C 库的头文件 lib/ libsome.a C 库 src/ some_wrapper.cpp < 用于将 C 库包装成 C 库的源码文件 源码示例 some.h…...

使用 IDEA 开发一个简单易用的 SDK

目录 一、什么是 SDK 二、为什么要开发 SDK 三、开发 SDK 的详细步骤 四、导入 SDK 进行测试 附&#xff1a;ConfigurationProperties 注解的介绍及使用 一、什么是 SDK 1. 定义&#xff1a;软件开发工具包 Software Development Kit 2. 用于开发特定软件或应用程序的工…...

CSS transition(过渡效果)详解

CSS过渡效果&#xff08;Transition&#xff09;是一种在CSS3中引入的动画效果&#xff0c;它允许开发者在元素状态变化时&#xff08;如鼠标悬停、类更改等&#xff09;平滑地改变CSS属性值&#xff0c;从而创建出平滑的动画效果。过渡效果可以应用于多种CSS属性&#xff0c;如…...

Android13多媒体框架概览

Android13多媒体框架概览 Android 多媒体框架 Android 多媒体框架旨在为 Java 服务提供可靠的接口。它是一个系统&#xff0c;包括多媒体应用程序、框架、OpenCore 引擎、音频/视频/输入的硬件设备&#xff0c;输出设备以及一些核心动态库&#xff0c;比如 libmedia、libmedi…...

一文读懂:MybatisPlus从入门到进阶

快速入门 简介 在项目开发中&#xff0c;Mybatis已经为我们简化了代码编写。 但是我们仍需要编写很多单表CURD语句&#xff0c;MybatisPlus可以进一步简化Mybatis。 MybatisPlus官方文档&#xff1a;https://www.baomidou.com/&#xff0c;感谢苞米豆和黑马程序员。 Mybat…...

C语言--------指针(1)

0.指针&指针变量 32位平台&#xff0c;指针变量是4个字节&#xff08;32bit/84)--------x86 64位平台&#xff0c;指针变量是8个字节&#xff08;64bit/88)--------x64 编号指针地址&#xff1b;我们平常讲的p是指针就是说p是一个指针变量&#xff1b; ************只要…...

Vite 下一代的前端工具链,前端开发与构建工具

一、Vite 简介 官方中文网站&#xff1a;Vite | 下一代的前端工具链 官方定义&#xff1a; Vite&#xff0c;下一代的前端工具链&#xff0c;为开发提供极速响应。 Vue3.4版本&#xff0c;Vue新版本使用Vite构建、开发、调试、编译。 Vite的优势 极速的服务启动 使用原生…...

【SpringBoot】FreeMarker视图渲染

目录 一、FreeMarker 简介 1.1 什么是FreeMarker&#xff1f; 1.2 Freemarker模板组成部分 1.3 为什么要使用FreeMarker 二、Springboot集成FreeMarker 2.1 配置 2.2 数据类型 2.2.1 字符串 2.2.2 数值 2.2.3 布尔值 2.2.4 日期 2.3 常见指令 2.3.2 assign 2.3…...

巴尔加瓦算法图解:算法运用。

树 如果能将用户名插入到数组的正确位置就好了&#xff0c;这样就无需在插入后再排序。为此&#xff0c;有人设计了一种名为二叉查找树(binary search tree)的数据结构。 每个node的children 都不大于两个。对于其中的每个节点&#xff0c;左子节点的值都比它小&#xff0c;…...

Docker的镜像和容器的区别

1 Docker镜像 假设Linux内核是第0层&#xff0c;那么无论怎么运行Docker&#xff0c;它都是运行于内核层之上的。这个Docker镜像&#xff0c;是一个只读的镜像&#xff0c;位于第1层&#xff0c;它不能被修改或不能保存状态。 一个Docker镜像可以构建于另一个Docker镜像之上&…...

忘记 RAG:拥抱Agent设计,让 ChatGPT 更智能更贴近实际

RAG&#xff08;检索增强生成&#xff09;设计模式通常用于开发特定数据领域的基于实际情况的ChatGPT。 然而&#xff0c;重点主要是改进检索工具的效率&#xff0c;如嵌入式搜索、混合搜索和微调嵌入&#xff0c;而不是智能搜索。 这篇文章介绍了一种新的方法&#xff0c;灵感…...

利用路由懒加载和CDN分发策略,对Vue项目进行性能优化

目录 一、Vue项目 二、路由懒加载 三、CDN分发策略 四、如何对Vue项目进行性能优化 一、Vue项目 Vue是一种用于构建用户界面的JavaScript框架&#xff0c;它是一种渐进式框架&#xff0c;可以用于构建单页应用&#xff08;SPA&#xff09;和多页应用。Vue具有简单易学、灵…...

【Scala】1. 变量和数据类型

1. 变量和数据类型 1.1 for begining —— hello world 新建hello.scala文件&#xff0c;注意object名字与文件名一致。 object hello { def main(args:Array[String]): Unit { println("hello world!") } }运行后打印结果如下&#xff1a; hello world!Pr…...

何时以及如何选择制动电阻

制动电阻的选择是优化变频器应用的关键因素 制动电阻器在变频器中是如何工作的&#xff1f; 制动电阻器在 VFD 应用中的工作原理是将电机减速到驱动器设定的精确速度。它们对于电机的快速减速特别有用。制动电阻还可以将任何多余的能量馈入 VFD&#xff0c;以提升直流母线上的…...

消息中间件:Puslar、Kafka、RabbigMQ、ActiveMQ

消息队列 消息队列&#xff1a;它主要用来暂存生产者生产的消息&#xff0c;供后续其他消费者来消费。 它的功能主要有两个&#xff1a; 暂存&#xff08;存储&#xff09;队列&#xff08;有序&#xff1a;先进先出 从目前互联网应用中使用消息队列的场景来看&#xff0c;…...

Rust开发WASM,浏览器运行WASM

首先需要安装wasm-pack cargo install wasm-pack 使用cargo创建工程 cargo new --lib mywasm 编辑Cargo.toml文件&#xff0c;修改lib的类型为cdylib&#xff0c;并且添加依赖wasm-bindgen [package] name "mywasm" version "0.1.0" edition "…...

Vue3编写简单的App组件(二)

一、Vue3页面渲染基本流程 1、入口文件 <!DOCTYPE html> <html lang"en"><head><meta charset"UTF-8"><link rel"icon" href"/favicon.ico"><meta name"viewport" content"widthde…...

java Servlet 云平台教学系统myeclipse定制开发SQLServer数据库网页模式java编程jdbc

一、源码特点 JSP 云平台教学系统是一套完善的web设计系统&#xff0c;对理解JSP java编程开发语言有帮助 系统采用serlvet dao bean&#xff0c;系统具有完整的源代码和数据库 &#xff0c;系统主要采用B/S模式开发。开发 环境为TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据…...

.Net框架,除了EF还有很多很多......

文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...

遍历 Map 类型集合的方法汇总

1 方法一 先用方法 keySet() 获取集合中的所有键。再通过 gey(key) 方法用对应键获取值 import java.util.HashMap; import java.util.Set;public class Test {public static void main(String[] args) {HashMap hashMap new HashMap();hashMap.put("语文",99);has…...

质量体系的重要

质量体系是为确保产品、服务或过程质量满足规定要求&#xff0c;由相互关联的要素构成的有机整体。其核心内容可归纳为以下五个方面&#xff1a; &#x1f3db;️ 一、组织架构与职责 质量体系明确组织内各部门、岗位的职责与权限&#xff0c;形成层级清晰的管理网络&#xf…...

在四层代理中还原真实客户端ngx_stream_realip_module

一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡&#xff08;如 HAProxy、AWS NLB、阿里 SLB&#xff09;发起上游连接时&#xff0c;将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后&#xff0c;ngx_stream_realip_module 从中提取原始信息…...

有限自动机到正规文法转换器v1.0

1 项目简介 这是一个功能强大的有限自动机&#xff08;Finite Automaton, FA&#xff09;到正规文法&#xff08;Regular Grammar&#xff09;转换器&#xff0c;它配备了一个直观且完整的图形用户界面&#xff0c;使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决

Spring Cloud Gateway 中自定义验证码接口返回 404 的排查与解决 问题背景 在一个基于 Spring Cloud Gateway WebFlux 构建的微服务项目中&#xff0c;新增了一个本地验证码接口 /code&#xff0c;使用函数式路由&#xff08;RouterFunction&#xff09;和 Hutool 的 Circle…...

Unity UGUI Button事件流程

场景结构 测试代码 public class TestBtn : MonoBehaviour {void Start(){var btn GetComponent<Button>();btn.onClick.AddListener(OnClick);}private void OnClick(){Debug.Log("666");}}当添加事件时 // 实例化一个ButtonClickedEvent的事件 [Formerl…...

水泥厂自动化升级利器:Devicenet转Modbus rtu协议转换网关

在水泥厂的生产流程中&#xff0c;工业自动化网关起着至关重要的作用&#xff0c;尤其是JH-DVN-RTU疆鸿智能Devicenet转Modbus rtu协议转换网关&#xff0c;为水泥厂实现高效生产与精准控制提供了有力支持。 水泥厂设备众多&#xff0c;其中不少设备采用Devicenet协议。Devicen…...

【深度学习新浪潮】什么是credit assignment problem?

Credit Assignment Problem(信用分配问题) 是机器学习,尤其是强化学习(RL)中的核心挑战之一,指的是如何将最终的奖励或惩罚准确地分配给导致该结果的各个中间动作或决策。在序列决策任务中,智能体执行一系列动作后获得一个最终奖励,但每个动作对最终结果的贡献程度往往…...

热门Chrome扩展程序存在明文传输风险,用户隐私安全受威胁

赛门铁克威胁猎手团队最新报告披露&#xff0c;数款拥有数百万活跃用户的Chrome扩展程序正在通过未加密的HTTP连接静默泄露用户敏感数据&#xff0c;严重威胁用户隐私安全。 知名扩展程序存在明文传输风险 尽管宣称提供安全浏览、数据分析或便捷界面等功能&#xff0c;但SEMR…...