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

【重拾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博客icon-default.png?t=N7T8https://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结构体,包含两个整型成员变量xy
  • printPoint函数,接收一个Point类型的结构体作为参数,并在函数内部打印结构体的坐标值。
  • main函数中,创建一个名为pointPoint结构体变量,并初始化其xy成员变量的值。然后,调用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函数,将&pointpoint的地址)作为参数传递给它
  • 输出结果与方法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请求&#xff0c;并且可以很好地与其他Spring组件集成。WebClient支持同步和异步操作&#xff0c;使得它非常适合用于构建响应式应用程序。 WebClient允…...

IP真人识别方法与代理IP检测技术

随着互联网的发展&#xff0c;IP地址在网络安全和数据分析中扮演着重要的角色。为了维护网络的安全性和识别真实用户&#xff0c;IP地址的真实性和来源成为了一个关键问题。 什么是IP真人识别&#xff1f; IP真人识别是一种技术&#xff0c;旨在确定IP地址背后的用户是否为真实…...

MySQL 面试知识脑图 初高级知识点

脑图下载地址&#xff1a;https://mm.edrawsoft.cn/mobile-share/index.html?uuid18b10870122586-src&share_type1 sql_mode 基本语法及校验规则 ONLY_FULL_GROUP_BY 对于GROUP BY聚合操作&#xff0c;如果在SELECT中的列&#xff0c;没有在GROUP BY中出现&#xff…...

【数据结构】二叉树的链式结构及实现

目录 1. 前置说明 2. 二叉树的遍历 2.1 前序、中序以及后序遍历 2.2 层序遍历 3. 节点个数及高度等 4. 二叉树的创建和销毁 1. 前置说明 在学习二叉树的基本操作前&#xff0c;需先要创建一棵二叉树&#xff0c;然后才能学习其相关的基本操作。由于现在大家对二叉树结构…...

OpenCV4(C++)—— 创建窗口滑动条来调参

文章目录 创建滑动条 —— createTrackbar 创建滑动条 —— createTrackbar createTrackbar是OpenCV中的一个函数&#xff0c;用于创建一个可调节的滑动条&#xff08;Trackbar&#xff09;&#xff0c;以便在图像处理过程中实时调整参数 int cv::createTrackbar(const String…...

深度学习基础知识 学习率调度器的用法解析

深度学习基础知识 学习率调度器的用法解析 1、自定义学习率调度器**&#xff1a;**torch.optim.lr_scheduler.LambdaLR2、正儿八经的模型搭建流程以及学习率调度器的使用设置 1、自定义学习率调度器**&#xff1a;**torch.optim.lr_scheduler.LambdaLR 实验代码&#xff1a; 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对数据预处理

文章目录 数据处理步骤观察数据数据无量纲化缺失值处理处理分类型特征处理连续型特征 数据处理步骤 数据无量纲化缺失值处理处理分类型特征&#xff1a;编码与哑变量处理连续型特征&#xff1a;二值化与分段 观察数据 通过pandas读取数据&#xff0c;通过head和info方法大致查…...

【智慧燃气】智慧燃气解决方案总体概述--终端层、网络层

关键词&#xff1a;智慧燃气、智慧燃气系统、智慧燃气平台、智慧燃气解决方案、智慧燃气应用、智能燃气 智慧燃气解决方案是基于物联网、大数据、云计算、移动互联网等先进技术&#xff0c;结合燃气行业特征&#xff0c;通过智能设备全面感知企业生产、环境、状态等信息的全方…...

Tomcat隔离web原理和热加载热部署

Tomcat 如何打破双亲委派机制 Tomcat 的自定义类加载器 WebAppClassLoader 打破了双亲委派机制&#xff0c;它首先自己尝试去加载某个类&#xff0c;如果找不到再代理给父类加载器&#xff0c;其目的是优先加载 Web 应用自己定义的类。具体实现就是重写 ClassLoader 的两个方法…...

使用ffmpeg和python脚本下载网络视频m3u8(全网最全面)

网上给娃找了些好看的电影和一些有趣的短视频&#xff0c;如何保存下来呢&#xff1f;从网上找各种工具&#xff1f;都不方便。于是想到何不编程搞定&#xff0c;搞个脚本。对程序员来说这都不是事儿。且我有华为云服务器&#xff0c;完全可以把地址记下&#xff0c;后台自动下…...

【考研408常用数据结构】C/C++实现代码汇总

文章目录 前言数组多维数组的原理、作用稀疏数组 链表单向链表的增删改查的具体实现思路约瑟夫环问题&#xff08;可不学&#xff09;双向链表 树二叉搜索树中序线索二叉树哈夫曼树的编码与译码红黑树B树B树 堆顺序与链式结构队列实现优先队列排序算法&#xff08;重点&#xf…...

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…...

信息系统项目管理师第四版学习笔记——项目绩效域

干系人绩效域 干系人绩效域涉及与干系人相关的活动和职能。在项目整个生命周期过程中&#xff0c;有效执行本绩效域可以实现的预期目标主要包含&#xff1a;①与干系人建立高效的工作关系&#xff1b;②干系人认同项目目标&#xff1b;③支持项目的干系人提高了满意度&#xf…...

PyTorch 深度学习之加载数据集Dataset and DataLoader(七)

1. Revision: Manual data feed 全部Batch&#xff1a;计算速度&#xff0c;性能有问题 1 个 &#xff1a;跨越鞍点 mini-Batch:均衡速度与性能 2. Terminology: Epoch, Batch-Size, Iteration DataLoader: batch_size2, sheffleTrue 3. How to define your Dataset 两种处…...

小谈设计模式(26)—中介者模式

小谈设计模式&#xff08;26&#xff09;—中介者模式 专栏介绍专栏地址专栏介绍 中介者模式分析角色分析抽象中介者&#xff08;Mediator&#xff09;具体中介者&#xff08;ConcreteMediator&#xff09;抽象同事类&#xff08;Colleague&#xff09;具体同事类&#xff08;C…...

7种设计模式

1. 工厂模式 优点&#xff1a;封装了对象的创建过程&#xff0c;降低了耦合性&#xff0c;提供了灵活性和可扩展性。 缺点&#xff1a;增加了代码的复杂性&#xff0c;需要创建工厂类。 适用场景&#xff1a;当需要根据不同条件创建不同对象时&#xff0c;或者需要隐藏对象创建…...

Leetcode 3576. Transform Array to All Equal Elements

Leetcode 3576. Transform Array to All Equal Elements 1. 解题思路2. 代码实现 题目链接&#xff1a;3576. Transform Array to All Equal Elements 1. 解题思路 这一题思路上就是分别考察一下是否能将其转化为全1或者全-1数组即可。 至于每一种情况是否可以达到&#xf…...

从深圳崛起的“机器之眼”:赴港乐动机器人的万亿赛道赶考路

进入2025年以来&#xff0c;尽管围绕人形机器人、具身智能等机器人赛道的质疑声不断&#xff0c;但全球市场热度依然高涨&#xff0c;入局者持续增加。 以国内市场为例&#xff0c;天眼查专业版数据显示&#xff0c;截至5月底&#xff0c;我国现存在业、存续状态的机器人相关企…...

学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1

每日一言 生活的美好&#xff0c;总是藏在那些你咬牙坚持的日子里。 硬件&#xff1a;OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写&#xff0c;"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...

select、poll、epoll 与 Reactor 模式

在高并发网络编程领域&#xff0c;高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表&#xff0c;以及基于它们实现的 Reactor 模式&#xff0c;为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。​ 一、I…...

Redis数据倾斜问题解决

Redis 数据倾斜问题解析与解决方案 什么是 Redis 数据倾斜 Redis 数据倾斜指的是在 Redis 集群中&#xff0c;部分节点存储的数据量或访问量远高于其他节点&#xff0c;导致这些节点负载过高&#xff0c;影响整体性能。 数据倾斜的主要表现 部分节点内存使用率远高于其他节…...

初探Service服务发现机制

1.Service简介 Service是将运行在一组Pod上的应用程序发布为网络服务的抽象方法。 主要功能&#xff1a;服务发现和负载均衡。 Service类型的包括ClusterIP类型、NodePort类型、LoadBalancer类型、ExternalName类型 2.Endpoints简介 Endpoints是一种Kubernetes资源&#xf…...

面向无人机海岸带生态系统监测的语义分割基准数据集

描述&#xff1a;海岸带生态系统的监测是维护生态平衡和可持续发展的重要任务。语义分割技术在遥感影像中的应用为海岸带生态系统的精准监测提供了有效手段。然而&#xff0c;目前该领域仍面临一个挑战&#xff0c;即缺乏公开的专门面向海岸带生态系统的语义分割基准数据集。受…...

redis和redission的区别

Redis 和 Redisson 是两个密切相关但又本质不同的技术&#xff0c;它们扮演着完全不同的角色&#xff1a; Redis: 内存数据库/数据结构存储 本质&#xff1a; 它是一个开源的、高性能的、基于内存的 键值存储数据库。它也可以将数据持久化到磁盘。 核心功能&#xff1a; 提供丰…...

Django RBAC项目后端实战 - 03 DRF权限控制实现

项目背景 在上一篇文章中&#xff0c;我们完成了JWT认证系统的集成。本篇文章将实现基于Redis的RBAC权限控制系统&#xff0c;为系统提供细粒度的权限控制。 开发目标 实现基于Redis的权限缓存机制开发DRF权限控制类实现权限管理API配置权限白名单 前置配置 在开始开发权限…...

高效的后台管理系统——可进行二次开发

随着互联网技术的迅猛发展&#xff0c;企业的数字化管理变得愈加重要。后台管理系统作为数据存储与业务管理的核心&#xff0c;成为了现代企业不可或缺的一部分。今天我们要介绍的是一款名为 若依后台管理框架 的系统&#xff0c;它不仅支持跨平台应用&#xff0c;还能提供丰富…...