【重拾C语言】九、再论函数(指针、数组、结构体作参数;函数值返回指针、结构体;作用域)
目录
前言
九、再论函数
9.1 参数
9.1.1 参数的传递规则
9.1.2 指针作参数
9.1.3 数组作参数
9.1.4 结构体作参数
a. 直接用结构体变量作函数参数
b. 用指向结构体变量的指针作函数参数
9.2 函数值
9.2.1 返回指针值
9.2.2 返回结构体值
a. 返回结构体值
b. 返回结构体指针
9.3 作用域
9.3.1 局部量和全局量
9.3.2 作用域
a. 文件作用域(全局作用域)
b. 函数作用域
c. 块作用域
d. 函数原型作用域
e. 代码示例
前言
【重拾C语言】五、模块化程序设计——函数(定义、调用、参数传递、结果返回、函数原型;典例:打印字符图形、验证哥德巴赫猜想)_QomolangmaH的博客-CSDN博客
https://blog.csdn.net/m0_63834988/article/details/133580009?spm=1001.2014.3001.5501 前文介绍了函数的基础知识,包括如何定义函数、函数的调用形式和过程、函数结果的返回以及函数原型的使用等。本文将再论函数,主要介绍指针、数组、结构体等作参数;函数值返回指针、结构体,以及C语言作用域相关知识。
九、再论函数
9.1 参数
9.1.1 参数的传递规则
C语言只有一种参数类别——值参。值参意味着:
- 参数要求:赋值兼容
- 形实结合:
- 计算实参表达式的值;
- 把实参值按赋值转换规则,转换成形参的类型;
- 把转换后的实参值送入形参变量中。
- 执行函数:
- 值参表示形参本身,它是函数内的一个局部变量,已经与实参脱离关系(无关)了。在函数内对形参的赋值不影响实参。
- 结束返回: 实参值无任何变化,还是调用函数之前的值。
#include <stdio.h>void square(int num) {num = num * num; // 修改形参的值printf("Inside the function: %d\n", num);
}int main() {int number = 5;printf("Before the function call: %d\n", number);square(number); // 调用函数并传递实参printf("After the function call: %d\n", number);return 0;
}

9.1.2 指针作参数
一般意义上,如果函数的形参是指针类型,对应调用时,相应实参也应是指针类型表达式
#include <stdio.h>void square(int *num) {*num = (*num) * (*num); // 修改形参指针所指向的值printf("Inside the function: %d\n", *num);
}int main() {int number = 5;printf("Before the function call: %d\n", number);square(&number); // 调用函数并传递实参的地址printf("After the function call: %d\n", number);return 0;
}
输出:

使用指针作为形参来传递实参的地址。在函数内部,通过解引用指针并修改指针所指向的值,实现了对实参的修改。
9.1.3 数组作参数
在C语言中,数组名实际上是一个指针,表示数组首元素的地址。因此,当将数组名作为实参传递给函数时,实际上传递的是数组名的指针值。
在函数调用时,数组名作为实参传递给函数的形参,只传递了数组名的值,也就是数组的首地址。函数内部并不会为形参开辟数组的存储空间,而只会为形参开辟一个指针变量的空间,用于存储传递进来的实参数组的地址。
#include <stdio.h>void printArraySize(int arr[]) {printf("Size of the array inside the function: %lu\n", sizeof(arr));for (int i = 0; i < 5; i++) {printf("%d ", arr[i]);}printf("\n");
}int main() {int array[] = {1, 2, 3, 4, 5};printf("Size of the array in the main function: %lu\n", sizeof(array));printArraySize(array);return 0;
}
输出:

将数组array作为实参传递给printArraySize函数,可以看到,在printArraySize函数内部,sizeof(arr)的结果是8(64位系统上),而不是数组的实际大小。这是因为在函数调用过程中,只传递了数组名的指针值,而不是整个数组的值。
如上述代码所示,数组作为形参时,可以省略数组形式参数最外层的尺寸
错误示例:
void printMatrix(int matrix[][], int rows)
void printMatrix(int matrix[3][], int rows)
void printMatrix(int matrix[3][][3], int rows)
正确示例:
#include <stdio.h>void printMatrix(int matrix[][3], int rows) {for (int i = 0; i < rows; i++) {for (int j = 0; j < 3; j++) {printf("%d ", matrix[i][j]);}printf("\n");}
}int main() {int matrix[][3] = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};int rows = sizeof(matrix) / sizeof(matrix[0]);printf("Matrix elements in the main function:\n");printMatrix(matrix, rows);return 0;
}

9.1.4 结构体作参数
a. 直接用结构体变量作函数参数
#include <stdio.h>struct Point {int x;int y;
};void printPoint(struct Point p) {printf("Point coordinates: (%d, %d)\n", p.x, p.y);
}int main() {struct Point point = {3, 5};printf("Point coordinates in the main function:\n");printPoint(point);return 0;
}
Point结构体,包含两个整型成员变量x和y。printPoint函数,接收一个Point类型的结构体作为参数,并在函数内部打印结构体的坐标值。main函数中,创建一个名为point的Point结构体变量,并初始化其x和y成员变量的值。然后,调用printPoint函数,将point作为参数传递给它。- 输出:

b. 用指向结构体变量的指针作函数参数
#include <stdio.h>struct Point {int x;int y;
};void printPoint(struct Point* p) {printf("Point coordinates: (%d, %d)\n", p->x, p->y);
}int main() {struct Point point = {3, 5};printf("Point coordinates in the main function:\n");printPoint(&point);return 0;
}
printPoint函数,接收一个指向Point类型结构体的指针作为参数- 在
main函数中,调用printPoint函数,将&point(point的地址)作为参数传递给它 - 输出结果与方法a相同:

9.2 函数值
9.2.1 返回指针值
函数可以返回指针作为其返回值,这样可以在函数外部访问函数内部创建的变量或数据。
函数返回类型不允许是数组类型和函数类型、共用体类型,除此之外允许一切类型, 当然允许指针类型,带回指针值的函数的函数定义说明符形式是:
类型名 *函数名( 形参列表 )
#include <stdio.h>int* getArray() {static int arr[] = {1, 2, 3, 4, 5};return arr;
}int main() {int* ptr = getArray();for (int i = 0; i < 5; i++) {printf("%d ", *(ptr + i));}return 0;
}
输出:
9.2.2 返回结构体值
函数的计算结果可能是一个结构体值。在C语言中,有两种途径能够把该结构体值通过函数名字带回到主调函数。
a. 返回结构体值
- 函数的结果类型是结构体类型
- 直接把一个结构体值带回调用函数的主程序
#include <stdio.h>struct Point {int x;int y;
};struct Point createPoint(int x, int y) {struct Point point;point.x = x;point.y = y;return point;
}int main() {struct Point p = createPoint(3, 4);printf("Point coordinates: (%d, %d)\n", p.x, p.y);return 0;
}

b. 返回结构体指针
- 函数的结果类型是指向结构体类型变量的指针类型
#include <stdio.h>
#include <stdlib.h>struct Point {int x;int y;
};struct Point* createPoint(int x, int y) {struct Point* point = malloc(sizeof(struct Point));point->x = x;point->y = y;return point;
}int main() {struct Point* p = createPoint(3, 4);printf("Point coordinates: (%d, %d)\n", p->x, p->y);free(p);return 0;
}
- 函数
createPoint()接受两个参数,并动态分配内存来创建一个Point类型的结构体变量。然后,它将给定的坐标值分配给结构体的成员,并返回指向该结构体的指针。 - 在
main()函数中,调用createPoint()函数来创建一个Point结构体,并使用指针访问结构体的成员来打印坐标值。最后,使用free()函数释放了动态分配的内存,以避免内存泄漏。

9.3 作用域
9.3.1 局部量和全局量
- 局部变量(Local Variables)是在函数内定义的变量,包括形参。它们的作用范围限定在所属的函数内部。另外,定义在复合语句内部的变量的作用范围则限定在该复合语句内部。
- 全局变量(Global Variables)则是在函数以外定义的变量,它们不从属于任何特定的函数。全局变量的作用范围从定义处开始,一直延伸到整个源文件的结束,包括各个函数。
#include <stdio.h>// 全局变量
int globalVariable = 10;void myFunction()
{// 局部变量int localVar = 20;printf("局部变量:%d\n", localVar);printf("全局变量:%d\n", globalVariable);
}int main()
{myFunction();// 尝试访问局部变量和全局变量// 这里不能访问局部变量localVar,会导致编译错误printf("全局变量:%d\n", globalVariable);return 0;
}

9.3.2 作用域
作用域是指在程序中标识符有效的区域。在C语言中,每个源程序编译单位(例如源文件),每个函数定义、函数原型以及复合语句都构成一个作用域区域。在一个标识符的作用域内,可以使用该标识符,并且使用的是相应声明的标识符。这意味着在不同的作用域中可以使用相同名称的标识符,因为它们处于不同的作用域,互相之间不会产生冲突。
a. 文件作用域(全局作用域)
在函数之外定义的标识符具有文件作用域,它们在整个源文件中可见,在文件中的任何位置都可以使用这些标识符。
b. 函数作用域
在函数内部定义的标识符具有函数作用域,它们只在函数内部可见,在函数外部无法使用这些标识符。
c. 块作用域
在复合语句(代码块)内部定义的标识符具有块作用域,它们只在该代码块内可见。当代码块执行完毕后,其中定义的标识符就不再可见。
d. 函数原型作用域
函数原型中声明的标识符具有函数原型作用域,它们只在函数原型所在的作用域中可见。函数原型作用域主要用于函数声明中的参数。
e. 代码示例
#include <stdio.h>// 文件作用域(全局作用域)
int globalVariable = 10;void function1()
{// 函数作用域int localVariable = 20;printf("Local variable: %d\n", localVariable);printf("Global variable: %d\n", globalVariable);
}void function2()
{// 函数作用域int localVariable = 30;printf("Local variable: %d\n", localVariable);printf("Global variable: %d\n", globalVariable);
}int main()
{// 块作用域{int blockVariable = 40;printf("Block variable: %d\n", blockVariable);}function1();function2();return 0;
}

相关文章:
【重拾C语言】九、再论函数(指针、数组、结构体作参数;函数值返回指针、结构体;作用域)
目录 前言 九、再论函数 9.1 参数 9.1.1 参数的传递规则 9.1.2 指针作参数 9.1.3 数组作参数 9.1.4 结构体作参数 a. 直接用结构体变量作函数参数 b. 用指向结构体变量的指针作函数参数 9.2 函数值 9.2.1 返回指针值 9.2.2 返回结构体值 a. 返回结构体值 b. 返回…...
Spring WebClient 基于响应式编程模型的HTTP客户端
一、简介 WebClient是一个非阻塞的、可扩展的、基于Reactive Streams规范的HTTP客户端。它提供了一种简洁的方式来进行HTTP请求,并且可以很好地与其他Spring组件集成。WebClient支持同步和异步操作,使得它非常适合用于构建响应式应用程序。 WebClient允…...
IP真人识别方法与代理IP检测技术
随着互联网的发展,IP地址在网络安全和数据分析中扮演着重要的角色。为了维护网络的安全性和识别真实用户,IP地址的真实性和来源成为了一个关键问题。 什么是IP真人识别? IP真人识别是一种技术,旨在确定IP地址背后的用户是否为真实…...
MySQL 面试知识脑图 初高级知识点
脑图下载地址:https://mm.edrawsoft.cn/mobile-share/index.html?uuid18b10870122586-src&share_type1 sql_mode 基本语法及校验规则 ONLY_FULL_GROUP_BY 对于GROUP BY聚合操作,如果在SELECT中的列,没有在GROUP BY中出现ÿ…...
【数据结构】二叉树的链式结构及实现
目录 1. 前置说明 2. 二叉树的遍历 2.1 前序、中序以及后序遍历 2.2 层序遍历 3. 节点个数及高度等 4. 二叉树的创建和销毁 1. 前置说明 在学习二叉树的基本操作前,需先要创建一棵二叉树,然后才能学习其相关的基本操作。由于现在大家对二叉树结构…...
OpenCV4(C++)—— 创建窗口滑动条来调参
文章目录 创建滑动条 —— createTrackbar 创建滑动条 —— createTrackbar createTrackbar是OpenCV中的一个函数,用于创建一个可调节的滑动条(Trackbar),以便在图像处理过程中实时调整参数 int cv::createTrackbar(const String…...
深度学习基础知识 学习率调度器的用法解析
深度学习基础知识 学习率调度器的用法解析 1、自定义学习率调度器**:**torch.optim.lr_scheduler.LambdaLR2、正儿八经的模型搭建流程以及学习率调度器的使用设置 1、自定义学习率调度器**:**torch.optim.lr_scheduler.LambdaLR 实验代码: i…...
【JUC系列-12】深入理解PriorityQueue的底层原理和基本使用
JUC系列整体栏目 内容链接地址【一】深入理解JMM内存模型的底层实现原理https://zhenghuisheng.blog.csdn.net/article/details/132400429【二】深入理解CAS底层原理和基本使用https://blog.csdn.net/zhenghuishengq/article/details/132478786【三】熟练掌握Atomic原子系列基本…...
Paddle安装
Paddle安装参考 docs/tutorials/INSTALL_cn.md PaddlePaddle/PaddleDetection - Gitee.comhttps://gitee.com/paddlepaddle/PaddleDetection/blob/release/2.6/docs/tutorials/INSTALL_cn.md # 不指定版本安装paddle-gpu python -m pip install paddlepaddle-gpu# 测试安装 …...
配置XP虚拟机和Win 10宿主机互相ping通
文章目录 一、关闭虚机和宿主机的防火墙1、关闭虚拟机的防火墙1.1方式一1.2方式二 2、关闭宿主机的防火墙 二、设置XP和宿主机VMnet8的IP地址、网关和DNS1、获取VMWare的虚拟网络配置信息2、设置XP的VMnet8的IP地址、网关和DNS3、设置宿主机VMnet8的IP地址、网关和DNS 三、获取…...
【机器学习】sklearn对数据预处理
文章目录 数据处理步骤观察数据数据无量纲化缺失值处理处理分类型特征处理连续型特征 数据处理步骤 数据无量纲化缺失值处理处理分类型特征:编码与哑变量处理连续型特征:二值化与分段 观察数据 通过pandas读取数据,通过head和info方法大致查…...
【智慧燃气】智慧燃气解决方案总体概述--终端层、网络层
关键词:智慧燃气、智慧燃气系统、智慧燃气平台、智慧燃气解决方案、智慧燃气应用、智能燃气 智慧燃气解决方案是基于物联网、大数据、云计算、移动互联网等先进技术,结合燃气行业特征,通过智能设备全面感知企业生产、环境、状态等信息的全方…...
Tomcat隔离web原理和热加载热部署
Tomcat 如何打破双亲委派机制 Tomcat 的自定义类加载器 WebAppClassLoader 打破了双亲委派机制,它首先自己尝试去加载某个类,如果找不到再代理给父类加载器,其目的是优先加载 Web 应用自己定义的类。具体实现就是重写 ClassLoader 的两个方法…...
使用ffmpeg和python脚本下载网络视频m3u8(全网最全面)
网上给娃找了些好看的电影和一些有趣的短视频,如何保存下来呢?从网上找各种工具?都不方便。于是想到何不编程搞定,搞个脚本。对程序员来说这都不是事儿。且我有华为云服务器,完全可以把地址记下,后台自动下…...
【考研408常用数据结构】C/C++实现代码汇总
文章目录 前言数组多维数组的原理、作用稀疏数组 链表单向链表的增删改查的具体实现思路约瑟夫环问题(可不学)双向链表 树二叉搜索树中序线索二叉树哈夫曼树的编码与译码红黑树B树B树 堆顺序与链式结构队列实现优先队列排序算法(重点…...
Flink学习笔记(二):Flink内存模型
文章目录 1、配置总内存2、JobManager 内存模型3、TaskManager 内存模型4、WebUI 展示内存5、Flink On YARN 模式下内存分配6、Flink On Yarn 集群消耗资源估算6.1、资源分配6.2、Flink 提交 Yarn 集群的相关命令6.3、Flink On Yarn 集群的资源计算公式 1、配置总内存 Flink J…...
信息系统项目管理师第四版学习笔记——项目绩效域
干系人绩效域 干系人绩效域涉及与干系人相关的活动和职能。在项目整个生命周期过程中,有效执行本绩效域可以实现的预期目标主要包含:①与干系人建立高效的工作关系;②干系人认同项目目标;③支持项目的干系人提高了满意度…...
PyTorch 深度学习之加载数据集Dataset and DataLoader(七)
1. Revision: Manual data feed 全部Batch:计算速度,性能有问题 1 个 :跨越鞍点 mini-Batch:均衡速度与性能 2. Terminology: Epoch, Batch-Size, Iteration DataLoader: batch_size2, sheffleTrue 3. How to define your Dataset 两种处…...
小谈设计模式(26)—中介者模式
小谈设计模式(26)—中介者模式 专栏介绍专栏地址专栏介绍 中介者模式分析角色分析抽象中介者(Mediator)具体中介者(ConcreteMediator)抽象同事类(Colleague)具体同事类(C…...
7种设计模式
1. 工厂模式 优点:封装了对象的创建过程,降低了耦合性,提供了灵活性和可扩展性。 缺点:增加了代码的复杂性,需要创建工厂类。 适用场景:当需要根据不同条件创建不同对象时,或者需要隐藏对象创建…...
MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...
智慧医疗能源事业线深度画像分析(上)
引言 医疗行业作为现代社会的关键基础设施,其能源消耗与环境影响正日益受到关注。随着全球"双碳"目标的推进和可持续发展理念的深入,智慧医疗能源事业线应运而生,致力于通过创新技术与管理方案,重构医疗领域的能源使用模式。这一事业线融合了能源管理、可持续发…...
基于当前项目通过npm包形式暴露公共组件
1.package.sjon文件配置 其中xh-flowable就是暴露出去的npm包名 2.创建tpyes文件夹,并新增内容 3.创建package文件夹...
Java - Mysql数据类型对应
Mysql数据类型java数据类型备注整型INT/INTEGERint / java.lang.Integer–BIGINTlong/java.lang.Long–––浮点型FLOATfloat/java.lang.FloatDOUBLEdouble/java.lang.Double–DECIMAL/NUMERICjava.math.BigDecimal字符串型CHARjava.lang.String固定长度字符串VARCHARjava.lang…...
Cinnamon修改面板小工具图标
Cinnamon开始菜单-CSDN博客 设置模块都是做好的,比GNOME简单得多! 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...
EtherNet/IP转DeviceNet协议网关详解
一,设备主要功能 疆鸿智能JH-DVN-EIP本产品是自主研发的一款EtherNet/IP从站功能的通讯网关。该产品主要功能是连接DeviceNet总线和EtherNet/IP网络,本网关连接到EtherNet/IP总线中做为从站使用,连接到DeviceNet总线中做为从站使用。 在自动…...
大语言模型(LLM)中的KV缓存压缩与动态稀疏注意力机制设计
随着大语言模型(LLM)参数规模的增长,推理阶段的内存占用和计算复杂度成为核心挑战。传统注意力机制的计算复杂度随序列长度呈二次方增长,而KV缓存的内存消耗可能高达数十GB(例如Llama2-7B处理100K token时需50GB内存&a…...
Go 语言并发编程基础:无缓冲与有缓冲通道
在上一章节中,我们了解了 Channel 的基本用法。本章将重点分析 Go 中通道的两种类型 —— 无缓冲通道与有缓冲通道,它们在并发编程中各具特点和应用场景。 一、通道的基本分类 类型定义形式特点无缓冲通道make(chan T)发送和接收都必须准备好࿰…...
Netty从入门到进阶(二)
二、Netty入门 1. 概述 1.1 Netty是什么 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty是一个异步的、基于事件驱动的网络应用框架,用于…...
push [特殊字符] present
push 🆚 present 前言present和dismiss特点代码演示 push和pop特点代码演示 前言 在 iOS 开发中,push 和 present 是两种不同的视图控制器切换方式,它们有着显著的区别。 present和dismiss 特点 在当前控制器上方新建视图层级需要手动调用…...
