【C语言】连接陷阱探秘(3):形参、实参与返回值

目录

一、形参的 “迷障”

1.1. 定义与功能

1.2. 类型不匹配

1.3. 数量不一致

1.4. 顺序不一致

1.5. 数组形参退化

二、实参的 “暗礁”

2.1. 定义与功能

2.2. 求值顺序 “谜题”

2.3. 悬空指针 “深渊”

三、返回值的 “陷阱”

3.1. 定义与功能

3.2. 陷阱与缺陷

3.2.1. 未定义返回值

3.2.2. 类型不匹配

3.2.3. 返回局部变量的地址

3.2.4. 函数返回值覆盖问题

3.2.5. 返回动态分配的内存

3.3. 正确的做法

四、破局之策


在 C 语言的编程世界里,函数是构建复杂程序逻辑的基石,而形参、实参与返回值作为函数机制中的关键要素,它们之间的交互在程序连接过程中暗藏诸多容易被忽视的陷阱。正确理解并避开这些陷阱,对于编写稳定、可靠的 C 语言程序至关重要。

一、形参的 “迷障”

1.1. 定义与功能

形参(形式参数):在函数定义中列出的参数,它们作为占位符,用于在函数调用时接收从调用者传递过来的值。形参在函数被调用时分配内存空间,并在函数调用结束后释放。形参的主要作用是提供函数内部对外部传入数据的访问。

1.2. 类型不匹配

形参在函数定义之初便确定了其数据类型,旨在精准匹配对应传入的值。然而,现实编程中常出现实参与形参类型不一致的状况。C 语言编译器有时会自动施展隐式类型转换 “魔法”,可这魔法未必带来理想结局。

intfloat为例,若有函数void print_number(float num)期望接收浮点数形参,调用时却传入int型变量age = 25(即print_number(age)),编译器会将age隐式转换为float,看似顺利衔接,实则丢失了int作为整数的精度特性。反之,从高精度向低精度转换,像把double型数据传入float形参函数,截断小数部分更是悄无声息改变了数据原貌,在对数据精度要求严苛场景(如金融计算、科学模拟),细微偏差足以酿成大错。

以下是一个具体的C语言示例,展示了从intfloat以及从doublefloat的隐式类型转换可能带来的问题。

#include <stdio.h>// 函数期望接收一个float类型的参数
void print_number(float num) {printf("The number is: %f\n", num);
}int main() {int age = 25;                  // 定义一个int类型的变量double salary = 12345.6789;     // 定义一个double类型的变量// 调用函数,传入int类型的变量,编译器会进行隐式类型转换print_number(age);             // 输出: The number is: 25.000000// 虽然这里看起来没有问题,因为25可以精确表示为浮点数25.0,// 但如果考虑更大的整数或负数,且后续在浮点数运算中可能需要更高精度,// 这种隐式转换就可能隐藏问题。// 调用函数,传入double类型的变量,编译器同样会进行隐式类型转换// 但这次是从double到float,会导致精度丢失print_number((float)salary);   // 输出可能是: The number is: 12345.678125// 注意,这里的输出值可能因为浮点数的表示方式而略有不同,// 但关键是原始double值的小数部分被截断了。// 为了更清楚地看到精度丢失,我们可以直接打印转换后的float值float truncated_salary = (float)salary;printf("Truncated salary: %f\n", truncated_salary); // 输出与上面相同或相近// 如果我们关心精度,应该避免这种隐式转换,或者至少应该意识到它的发生。// 一种方法是使用更精确的类型(如double)来定义函数参数,或者确保在转换前了解可能的精度损失。return 0;
}

在这个示例中:

  • print_number(age)被调用时,age(一个int类型的变量)被隐式转换为float类型,并传递给函数。虽然在这个特定的例子中,转换是精确的(因为25可以精确地表示为浮点数25.0),但在其他情况下,特别是当整数很大或包含负数,并且后续操作需要更高的精度时,这种隐式转换可能会隐藏问题。

  • print_number((float)salary)被调用时,salary(一个double类型的变量)被显式(虽然这里用括号写出了转换,但重点在于理解隐式转换也会发生)转换为float类型。这个转换导致了精度丢失,因为double类型通常比float类型能表示更多的小数位数。

应对策略

  • 编写函数调用时,务必仔细核对实参和形参的类型,确保二者严格匹配。
  • 如果确实需要进行类型转换,尽量使用显式类型转换,让代码意图更加清晰,便于排查错误。
  • 例如,若要把 int 类型的变量当作 double 类型传递给函数,可以写成 print_double_value((double)integer_value),这样能明确体现出是有意进行类型转换的操作。

1.3. 数量不一致

如果在函数调用时提供的实参数量少于函数定义中要求的形参数量,未传递的形参将不会被初始化,其值将是未定义的。这可能导致函数内部使用这些未初始化参数时产生不可预测的结果。

如果提供的实参数量多于函数定义中要求的形参数量,额外的实参将被忽略,但这通常不会导致编译错误。然而,这种不一致性可能会使代码难以理解和维护。

示例代码

#include <stdio.h>// 函数定义有两个形参
void add_numbers(int num1, int num2) {printf("The sum is: %d\n", num1 + num2);
}int main() {int a = 3;// 只传递了一个实参,与函数定义的形参数量不符add_numbers(a); return 0;
}

在 add_numbers 函数定义中明确要求有两个 int 类型的形参,用于接收两个数并求和输出。但在 main 函数调用该函数时,只传递了一个实参 a。对于某些宽松的编译器,可能不会直接阻止编译,但函数内部在尝试获取第二个参数时,就会读取到不确定的内存数据,最终导致求和结果完全错误,甚至程序可能因为访问了非法内存而崩溃。

应对策略:仔细检查函数调用语句,保证实参的个数与函数定义的形参个数完全一致。同时,可以通过良好的代码风格,比如在函数声明和定义处详细注释参数的含义及个数要求,方便在编写调用代码时进行核对࿰

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

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

相关文章

阿里云私服地址

1.解压apache-maven-3.6.1-bin 2.配置本地仓库&#xff1a;修改conf/dettings.xml中的<localReoisitory>为一个指定目录。56行 <localRepository>D:\apache-maven-3.6.1-bin\apache-maven-3.6.1\mvn_repo</localRepository> 3.配置阿里云私服&#xff1a;…

STM32-- 调试- 延时、编译空循环

编译对空循环的处理&#xff0c;会影响堵塞延时效果&#xff0c;具体怎么处理的还不知道&#xff0c;只知道结果和现象。 模拟串口输出字符&#xff0c;用到延时函数&#xff0c;同样的延时函数&#xff0c;会有正常和不正常输出的情况&#xff1b;具体现象如下&#xff0c; /…

小狐狸AI数字人分身声音克隆形象克隆口播口型同步SAAS系统源码

AI数字人软件系统的未来趋势和用途正朝着多模态交互和智能化方向发展。 1. **多模态交互**&#xff1a;AI数字人技术正在从单一的文本或语音交互&#xff0c;转变为更加自然的多模态交互方式&#xff0c;包括语言对话、行为互动和自主学习能力。这种技术的提升使得数字人能够更…

Idea忽略提交文件、Idea设置文件隐藏、Idea提交时隐藏部分文件、git提交时忽略文件

文章目录 一、在idea中commit文件时隐藏文件方式一&#xff1a;创建.gitignore文件&#xff08;推荐&#xff09;方式二&#xff1a;‌通过File Types设置隐藏文件方式三&#xff1a;通过Git配置忽略文件‌&#xff08;不推荐&#xff09;总结 二、可能遇到的问题2.1、.gitigno…

FastGPT 和 DiffYAI 算不算ANGENT

FastGPT 和 DiffYAI 这类应用从某种程度上来说&#xff0c;可以算是“智能体&#xff08;Agent&#xff09;”&#xff0c;但其具体性质和智能体的定义范围有关。以下是详细分析&#xff1a; 什么是智能体&#xff08;Agent&#xff09;&#xff1f; 智能体是一种能够感知环境…

ARM 架构(Advanced RISC Machine)精简指令集计算机(Reduced Instruction Set Computer)

文章目录 1、ARM 架构ARM 架构的特点ARM 架构的应用ARM 架构的未来发展 2、RISCRISC 的基本概念RISC 的优势RISC 的应用RISC 与 CISC 的对比总结 1、ARM 架构 ARM 架构是一种低功耗、高性能的处理器架构&#xff0c;广泛应用于移动设备、嵌入式系统以及越来越多的服务器和桌面…

如何使用Jest测试你的React组件

在本文中&#xff0c;我们将了解如何使用Jest&#xff08;Facebook 维护的一个测试框架&#xff09;来测试我们的React组件。我们将首先了解如何在纯 JavaScript 函数上使用 Jest&#xff0c;然后再了解它提供的一些开箱即用的功能&#xff0c;这些功能专门用于使测试 React 应…

10 —— Webpack打包模式

开发模式&#xff1a;development &#xff1b;场景&#xff1a;本地开发 生产模式&#xff1a;production &#xff1b; 场景&#xff1a;打包上线 设置&#xff1a; 方式1.webpack.config.js 配置文件设置mode选项 module.exports { mode:production }; 方式2.在packa…

健康养生点点滴滴

在当下纷扰忙碌的尘世中&#xff0c;养生宛如一支灵动的画笔&#xff0c;精心地为人们勾勒出健康生活的绚丽图景。它绝非仅是对躯体的片面保养&#xff0c;更是对精神世界的深度润泽&#xff0c;一种执着于身心交融、契合无间的生活美学。 饮食养生&#xff0c;仿若画卷中那细…

《TCP/IP网络编程》学习笔记 | Chapter 15:套接字与标准 I/O

《TCP/IP网络编程》学习笔记 | Chapter 15&#xff1a;套接字与标准 I/O 《TCP/IP网络编程》学习笔记 | Chapter 15&#xff1a;套接字与标准 I/O标准 I/O 函数标准 I/O 函数的两个优点标准 I/O 函数和系统函数之间的性能对比标准 I/O 函数的几个缺点 使用标准 I/O 函数利用 fd…

「Mac玩转仓颉内测版29」基础篇9 - 数组类型详解

本篇将介绍 Cangjie 中的数组类型&#xff0c;包括数组的定义、创建、访问、常见操作以及在数据管理中的应用&#xff0c;帮助开发者熟练掌握数组的使用。 关键词 数组类型定义数组创建数组访问数组操作应用场景 一、数组类型概述 在 Cangjie 中&#xff0c;数组是一种用于存…

[面试]-golang基础面试题总结

文章目录 panic 和 recover**注意事项**使用 pprof、trace 和 race 进行性能调试。**Go Module**&#xff1a;Go中new和make的区别 Channel什么是 Channel 的方向性&#xff1f;如何对 Channel 进行方向限制&#xff1f;Channel 的缓冲区大小对于 Channel 和 Goroutine 的通信有…

鸿蒙进阶-状态管理

大家好啊&#xff0c;这里是鸿蒙开天组&#xff0c;今天我们来学习状态管理。 开始组件化开发之后&#xff0c;如何管理组件的状态会变得尤为重要&#xff0c;咱们接下来系统的学习一下这部分的内容 状态管理机制 在声明式UI编程框架中&#xff0c;UI是程序状态的运行结果&a…

深度学习每周学习总结J6(ResNeXt-50 算法实战与解析 - 猴痘识别)

&#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 | 接辅导、项目定制 目录 0. 总结ResNeXt基本介绍 1. 设置GPU2. 导入数据及处理部分3. 划分数据集4. 模型构建部分5. 设置超参数&#xff1a;定义损失函数&…

IDEA 2024.3 版本更新主要功能介绍

IDEA 2024.3 版本提供的新特性 IntelliJ IDEA 2024.3 的主要新特性&#xff1a; AI Assistant 增强 改进的代码补全和建议更智能的代码分析和重构建议Java 支持改进 支持 Java 21 的所有新特性改进的模式匹配和记录模式支持更好的虚拟线程调试体验开发工具改进 更新的 UI/UX 设…

java基础概念37:正则表达式2-爬虫

一、定义 【回顾】正则表达式的作用 作用一&#xff1a;校验字符串是否满足规则作用二&#xff1a;在一段文本中查找满足要求的内容——爬虫 二、本地爬虫VS网络爬虫 2-1、本地爬虫 示例&#xff1a; 代码优化&#xff1a; public static void main(String[] args) {// 大…

嵌入式AI之rknn yolov5初探

本文主要记录在RK3588上跑通RKNUP的rknn_yolov5_demo的过程,并且对rknn_yolov5_demo的代码进行修改,实现在显示器上同步播放rknn_yolov5_demo视频流检测结果。 首先,是RKNUP SDK的编译,参考官方SDK中的README.md文档,下载好对应的sdk编译工具链,我这边使用的是debian系统…

【数据库批量删除】MySql通过 Procedure 循环删除数据

一、问题描述 在日常使用运维中&#xff0c;一些特殊情况需要批量删除陈旧或异常数据。 如果通过 delete from 【表名】 where 【条件】 直接删除&#xff0c;可能会由于数据量过大&#xff0c;事务执行时间过长&#xff0c;造成死锁。 二、解决方案 通过 Procedure 使用循环…

AmazonS3集成minio实现https访问

最近系统全面升级到https&#xff0c;之前AmazonS3大文件分片上传直接使用http://ip:9000访问minio的方式已然行不通&#xff0c;https服务器访问http资源会报Mixed Content混合内容错误。 一般有两种解决方案&#xff0c;一是升级minio服务&#xff0c;配置ssl证书&#xff0c…

JavaWeb——Mybatis

6. Mybatis MyBatis是一款优秀的持久层框架&#xff0c;用于简化JDBC的开发 6.1. Mybatis入门 6.1.1. 入门程序 6.1.2. JDBC 6.1.3. 数据库连接池 6.1.4. Lombok 6.2. Mybatis基础操作 6.2.1. 删除 6.2.1.1. 根据主键删除 6.2.1.2. 预编译SQL #{id}在编译过程中会替换成?…