C语言教程(十):C 语言函数详解

一、引言

        在 C 语言中,函数是一组执行特定任务的代码块。通过将复杂的程序逻辑划分为多个函数,不仅能提高代码的可读性、可维护性,还便于代码的复用。无论是简单的数学计算,还是复杂的系统操作,函数都发挥着核心作用。掌握函数的使用方法,是提升 C 语言编程能力的重要环节。

二、函数的定义

  2.1 基本语法:

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

    // 函数体

    语句;

    return 返回值;

}

返回值类型:指定函数执行完成后返回的数据类型,若函数无需返回值,使用void。

函数名:遵循标识符命名规则,用于唯一标识函数。

参数列表:可以包含零个或多个参数声明,参数之间用逗号分隔,若没有参数,使用void或留空。

函数体:由一系列语句组成,是函数执行的具体逻辑。

return 语句:用于终止函数执行,并将返回值传递给调用者。若无返回值,return语句可省略。

  2.2 示例:

        计算两个整数之和的函数:

int add(int a, int b) {int sum = a + b;return sum;
}

        此函数add接收两个int类型参数ab,计算它们的和并返回。

三、函数的声明

  3.1 声明的作用:

        函数声明告知编译器函数的名称、返回值类型和参数类型,使编译器在编译时能够对函数调用进行合法性检查。函数声明通常放在调用函数的代码之前。

  3.2 语法:

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

        声明与定义类似,但函数声明末尾需加分号,且函数体部分省略。例如,上述add函数的声明为:

int add(int a, int b);

  3.3 声明的位置:

        全局声明:在所有函数外部声明,作用域为整个源文件,可被文件内所有函数调用。

        局部声明:在函数内部声明,作用域仅限于该函数内部。一般用于在函数内部调用其他自定义函数时,确保编译器知晓被调用函数的信息。

四、函数的调用

  4.1 调用方式:

        通过函数名后跟一对圆括号来调用函数,若函数有参数,在括号内传入相应参数值。例如调用上述add函数:

int result = add(3, 5);

        此语句将调用add函数,传入参数 3 5,函数返回值赋给result变量。

  4.2 函数调用过程:

        参数传递:将实际参数的值复制给函数定义中的形式参数。

        执行函数体:按照函数体中的语句顺序执行代码。

        返回值处理:遇到return语句时,函数终止执行,将返回值传递给调用处,继续执行调用函数后的代码。

五、函数参数

  5.1 形式参数与实际参数:

        形式参数:函数定义中参数列表里的参数,在函数被调用前并不占用实际内存空间,只有在函数调用时才被分配内存并接收实际参数的值。

        实际参数:函数调用时传递给函数的表达式、变量或常量。例如在add(3, 5)中,3 和 5 就是实际参数。

  5.2 参数传递方式:

        值传递:C 语言默认的参数传递方式。实际参数的值被复制到形式参数中,函数内部对形式参数的修改不会影响实际参数。例如:

void modify(int num) {num = num * 2;
}
int main() {int value = 5;modify(value);// value 仍为 5,未被修改return 0;
}

        指针传递:通过传递变量的地址来实现。函数内部可通过指针修改所指向的实际变量的值。例如:

void modify(int *ptr) {*ptr = *ptr * 2;
}
int main() {int value = 5;modify(&value);// value 变为 10,已被修改return 0;
}

  5.3 可变参数:

        C 语言允许函数接受可变数量的参数,通过<stdarg.h>头文件中的宏来实现。例如printf函数就是典型的可变参数函数。

#include <stdarg.h>
#include <stdio.h>
int sum(int count, ...) {va_list args;va_start(args, count);int result = 0;for (int i = 0; i < count; i++) {result += va_arg(args, int);}va_end(args);return result;
}
int main() {int total = sum(3, 1, 2, 3);// total 为 6return 0;
}

        上述sum函数可接受任意数量的整数参数,并计算它们的和。

六、函数的返回值

  6.1 返回值类型:

        函数的返回值类型在函数定义和声明时指定。返回值类型必须与return语句后表达式的类型兼容。若不兼容,编译器会进行类型转换。例如:

double divide(int a, int b) {return (double)a / b;
}

该函数将两个整数相除,并返回double类型的结果。

  6.2 无返回值函数:

        若函数无需返回值,使用void作为返回值类型。例如:

void printMessage() {printf("Hello, World!\n");
}

        此类函数执行完函数体后,直接返回调用处,无需return语句。若使用return,其后不能有返回值表达式。

七、函数指针

  7.1 定义与使用:

        函数指针是指向函数的指针变量。通过函数指针可以调用函数,常用于实现回调函数等功能。

// 定义函数指针类型
typedef int (*FuncPtr)(int, int);
int add(int a, int b) {return a + b;
}
int main() {FuncPtr ptr = add;int result = ptr(3, 5);// result 为 8return 0;
}

        上述代码中,FuncPtr是一个指向返回值为int,接受两个int类型参数的函数指针类型。通过FuncPtr定义指针变量ptr,并使其指向add函数,然后通过ptr调用add函数。

  7.2 函数指针作为参数:

        函数指针可作为其他函数的参数,用于将一个函数的行为传递给另一个函数。例如:

int operate(int a, int b, int (*func)(int, int)) {return func(a, b);
}
int add(int a, int b) {return a + b;
}
int subtract(int a, int b) {return a - b;
}
int main() {int result1 = operate(5, 3, add);int result2 = operate(5, 3, subtract);// result1 为 8,result2 为 2return 0;
}

        operate函数接受两个整数和一个函数指针作为参数,通过函数指针调用不同的函数进行计算。

八、递归函数

  8.1 递归的概念:

        递归函数是指在函数内部调用自身的函数。递归通常用于解决可以分解为更小、相似问题的场景。递归函数必须有终止条件,否则会导致无限递归,最终耗尽系统资源。

  8.2 示例:

        计算阶乘的递归函数:

int factorial(int n) {if (n == 0 || n == 1) {return 1;} else {return n * factorial(n - 1);}
}

        当n01 时,函数返回 1 作为终止条件;否则,通过递归调用factorial(n - 1)计算n的阶乘。

九、函数的作用域与存储类

  9.1 作用域:

        函数的作用域从函数定义处开始,到文件末尾结束。函数内部定义的变量为局部变量,作用域仅限于函数内部;在函数外部定义的变量为全局变量,作用域为整个源文件。若在函数内部定义了与全局变量同名的局部变量,在函数内部局部变量会覆盖全局变量。

  9.2 存储类:

        自动存储类(auto):函数内定义的局部变量默认是自动存储类,存储在栈中,函数执行结束时,变量所占用的内存被释放。

        静态存储类(static):若将局部变量声明为static,其生命周期会延长至程序结束,且在函数多次调用间保持值不变。静态局部变量存储在静态存储区。例如:

void increment() {static int count = 0;count++;printf("Count: %d\n", count);
}

        每次调用increment函数,count的值都会递增并保留。

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

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

相关文章

力扣面试150题--有效的字母异位词和字母异位词分组

Day 24 题目描述 思路 初次思路&#xff1a;如果两个字符串为异位词&#xff0c;说明它们长度相同并且字母出现的次数相同&#xff0c;于是有以下做法&#xff1a; 定义一个map&#xff0c;来保存s中每个字符的出现次数处理特殊情况&#xff0c;如果长度不同&#xff0c;直接…

数理逻辑(Mathematical Logic)综论与跨学科应用

李升伟 整理 数理逻辑&#xff08;Mathematical Logic&#xff09;是现代逻辑学与数学交叉的核心学科&#xff0c;以严格的数学方法研究逻辑推理的形式与规律。其发展深刻影响了数学基础、计算机科学、语言哲学等领域。以下从多个维度综论数理逻辑&#xff1a; 1. 核心分支 命…

高性能内存kv数据库Redis(续)

目录 四.主从同步与对象模型 1.Redis 淘汰策略 2.Redis 如何做到 持久化 2.1 redis为什么要实现持久化 2.2fork进程的写时复制机制 2.3大Key的影响 2.4redis做持久化的方式 2.5 aof 2.6 rdb 2.7 redis 持久化方式的优缺点 3.redis里面的高可用体现在哪里&#xff1f; 3.1r…

泛型算法——只读算法(一)

在 C 标准库中&#xff0c;泛型算法的“只读算法”指那些 不会改变它们所操作的容器中的元素&#xff0c;仅用于访问或获取信息的算法&#xff0c;例如查找、计数、遍历等操作。 accumulate std::accumulate()是 C 标准库**numeric**头文件中提供的算法&#xff0c;用于对序列…

SvelteKit 最新中文文档教程(21)—— 最佳实践之图片

前言 Svelte&#xff0c;一个语法简洁、入门容易&#xff0c;面向未来的前端框架。 从 Svelte 诞生之初&#xff0c;就备受开发者的喜爱&#xff0c;根据统计&#xff0c;从 2019 年到 2024 年&#xff0c;连续 6 年一直是开发者最感兴趣的前端框架 No.1&#xff1a; Svelte …

健康养生:开启活力生活的密钥

当我们在健身房看到年逾六旬却身形矫健的老人&#xff0c;在公园偶遇精神矍铄、步伐轻快的长者&#xff0c;总会惊叹于他们的健康状态。其实&#xff0c;这些都得益于长期坚持科学的养生之道。健康养生并非遥不可及的玄学&#xff0c;而是融入生活细节的智慧。​ 在饮食的世界…

Linux信号三部曲:产生机制、处理方式与内核接口

Linux系列 文章目录 Linux系列前言一、背景知识铺垫1.1 信号的基本概念1.2 进程对信号的处理 二、信号的产生2.1 前台进程和后台进程2.2 键盘组合键2.3 kill 命令2.4 系统调用2.4.1 signal()接口2.4.2 kill()接口2.4.3 raise()接口2.4.4 abort()接口 总结 前言 Linux中&#x…

win7/win10/macos如何切换DNS,提升网络稳定性

本篇教程教您如何在Windows10、Windows8.1、Windows7、MacOS操作系统切换DNS&#xff0c;以提升系统的稳定性&#xff0c;获得更好的操作体验。 Windows10及Windows8.1 1、右键单击“此计算机”&#xff0c;然后选择“属性”。进入Windows系统界面后&#xff0c;选择左侧的“…

移动硬盘突然打不开紧急救援指南:从排查到完整恢复‌

突发状况的典型特征‌ 当移动硬盘突然打不开时&#xff0c;用户常会遇到多种异常表现&#xff1a;接入电脑后硬盘指示灯虽亮但无法识别、系统反复提示“设备未连接成功”或弹出“磁盘结构损坏”的警告。部分情况下&#xff0c;资源管理器中的盘符虽可见&#xff0c;但双击后显示…

华为OD机试真题——统计匹配的二元组个数(2025A卷:100分)Java/python/JavaScript/C++/C语言/GO六种最佳实现

2025 A卷 100分 题型 本文涵盖详细的问题分析、解题思路、代码实现、代码详解、测试用例以及综合分析&#xff1b; 并提供Java、python、JavaScript、C、C语言、GO六种语言的最佳实现方式&#xff01; 2025华为OD真题目录全流程解析/备考攻略/经验分享 华为OD机试真题《统计匹配…

半导体制造如何数字化转型

半导体制造的数字化转型正通过技术融合与流程重构&#xff0c;推动着这个精密产业的全面革新。全球芯片短缺与工艺复杂度指数级增长的双重压力下&#xff0c;头部企业已构建起四大转型支柱&#xff1a; 1. 数据中枢重构产线生态 台积电的「智慧工厂4.0」部署着30万物联网传感器…

[Spark]深入解密Spark SQL源码:Catalyst框架如何优雅地解析你的SQL

本文内容组织形式 总结具体例子执行语句解析层优化层物理计划层执行层 猜你喜欢PS 总结 先写个总结&#xff0c;接下来会分别产出各个部分的源码解析&#xff0c;Spark SQL主要分为以下五个执行部分。 具体例子 接下来举个具体的例子来说明 执行语句 SELECT name, age FR…

【数据结构】4.单链表实现通讯录

在上一篇文章我们学会了用单链表来实现各种方法&#xff0c;在这一篇文章我们将在单链表的基础上实现通讯录。 0、准备工作 实现通讯录之前&#xff0c;我们还需要在单链表的基础上添加2个文件&#xff0c;头文件Contact.h和源文件Contact.c。Contact.c来实现通讯录方法的声明…

【bash】.bashrc

查看当前路径文件数量 alias file_num"ls -l | grep ^- | wc -l"查看文件大小 alias file_size"du -sh"alias ll alias ll"ls -ltrh"cd的同时执行ll alias cdcdls; function cdls() {builtin cd "$1" && ll }自定义prompt…

微信小程序实战案例 - 餐馆点餐系统 阶段 2 – 购物车

阶段 2 – 购物车&#xff08;超详细版&#xff09; 目标 把“加入购物车”做成 全局状态&#xff0c;任何页面都能读写在本地 持久化&#xff08;关闭小程序后购物车仍在&#xff09;新建 购物车页&#xff1a;数量增减、总价实时计算、去结算入口打 Git Tag v2.0‑cart 1. …

从红黑树到哈希表:原理对比与典型场景应用解析(分布式以及布隆过滤器)

在数据结构的世界里&#xff0c;红黑树一直以「自平衡二叉查找树」的身份备受赞誉。凭借红黑节点的精妙设计&#xff0c;它能将插入、删除、查找的时间复杂度稳定控制在 ( log ⁡ n ) (\log n) (logn)&#xff0c;成为处理有序数据的经典方案。然而&#xff0c;当业务场景对「…

游戏报错?MFC140.dll怎么安装才能解决问题?提供多种MFC140.dll丢失修复方案

MFC140.dll 是 Microsoft Visual C 2015 运行库的重要组成部分&#xff0c;许多软件和游戏依赖它才能正常运行。如果你的电脑提示 "MFC140.dll 丢失" 或 "MFC140.dll 未找到"&#xff0c;说明系统缺少该文件&#xff0c;导致程序无法启动。本文将详细介绍 …

《电子类专业:通往科技未来的钥匙》

一、电子类专业全景概览 在当今科技飞速发展的时代,电子类专业无疑占据着现代科技体系中基础与核心的重要地位。从我们日常生活中不可或缺的智能手机、电脑,到推动社会进步的人工智能、大数据技术,再到探索宇宙奥秘的航天航空设备,电子类专业的身影无处不在。它就像一把万…

Java--批量删除

前端部分 前端代码主要负责收集用户选择的学生记录的 id&#xff0c;并将这些 id 发送给后端的 DeleteMoreServlet 进行处理。 批量删除按钮绑定点击事件 $(".deleteMore").on("click",function(){// ... }); 当用户点击 “批量删除” 按钮时&#xff…

2025年4月份生活有感

今天在5000B培训的下午&#xff0c;一起入所来的小伙伴&#xff0c;有个申请了深圳大学的博士&#xff0c;已录取。哎&#xff0c;想起了当年申博时候信心和决心不足&#xff0c;导致后面匆匆的拿了offer去工作。看到同事的选择还是非常羡慕&#xff0c;想到自己5月份的婚礼&am…