函数实参与形参的区别

简介: 函数实参与形参的区别

一、C语言



程序清单1


#include <stdio.h>
void swap(int x, int y) {
  int tmp = x;
  x = y;
  y = tmp;  
}
int main() {
  int a = 3;
  int b = 5;
  printf("a = %d b = %d\n", a, b);
  swap(a, b);
  printf("a = %d b = %d\n", a, b);
  return 0;
}


输出结果:


ee394fb90da344b9bc11fc7be95c65a3.png


分析:


在程序清单1中,a, b 为实参,x, y 为形参。


当 a 和 b 传入 swap( ) 函数的时候,x 和 y 确实能拿到 3 和 5 这两个值,但 x 和 y 本身与 a 和 b拥有不同的地址,这就造成一个结果:在swap() 函数中,只交换了形参 x 和 y 的值,对于实参 a 和 b 来说,毫无影响。


4238684218a149fab1346a9bc3a3318d.png



程序清单2


#include <stdio.h>
void swap(int* pa, int* pb) {
  int tmp = *pa; // 解引用
  *pa = *pb;
  *pb = tmp;
}
int main() {
  int a = 3;
  int b = 5;
  printf("a = %d b = %d\n", a, b);
  swap(&a, &b);
  printf("a = %d b = %d\n", a, b);
  return 0;
}


输出结果:


b14261812cd9468e8416b1a1feeac44b.png


分析:


在程序清单2 中,当我们实参传的是 a 和 b 的地址时,情况就完全不一样了,在 swap( ) 函数中,我们形参拿整型指针类型来接收地址,最后再通过解引用符号 " * " 来拿到地址对应的值,即可交换。


这里需要注意: pa 和 pb 存的值是 a 和 b 的地址,然而 pa 和 pb 本身是一个指针变量,既然是变量,它们也有属于自己的地址,前者后者不能搞混了。


99924f74720f435f87e2302374137afc.png


二、Java



程序清单3


public class Test {
    public static void main(String[] args) {
        int a = 3;
        int b = 5;
        System.out.println("a = " + a + " b = " + b);
        swap(a,b);
        System.out.println("a = " + a + " b = " + b);
    }
    public static void swap(int a, int b){
        int temp = a;
        a = b;
        b = temp;
    }
}


输出结果:


a2d0b4c5e47046b495b723f8962584cf.png


在程序清单3中,现在我们就可以理解了 swap() 函数中的 a 和 b 和 main 函数中的 a 和 b 是不一样的。


程序清单4


public class Test {
    public static void main(String[] args) {
        int[] arr = {3, 5};
        System.out.println("a = " + arr[0] + " b = " + arr[1]);
        swap(arr);
        System.out.println("a = " + arr[0] + " b = " + arr[1]);
    }
    public static void swap(int[] arr) {
        int tmp = arr[0];
        arr[0] = arr[1];
        arr[1] = tmp;
    }
}


输出结果:


086aeeeafceb4b2d90a4e38edb190d2c.png


在 Java 中,我们拿不到局部变量的地址,或者说是拿不到栈区的地址。所以在程序清单4中,如果想要利用函数进行交换值,我们只能通过改变堆区的值来进行交换。


9f5e47b6c29a43a6850e8b5e508df974.png


三、总结



① 形参是实参的一份临时拷贝,其只在当前函数中有效,出了当前函数,即被销毁,所以改变形参本质上不会影响实参的状态。


② 在 C 语言中,我们可以利用指针接收地址,从而拿到地址对应的值来直接进行改变实参。


③ 在 Java 中,形参依然是实参的一份临时拷贝。但情况又有不同,因为栈区存放的局部变量对应的地址,我们无法获得,所以我们只能通过数组改变堆区上的某个值,这样一来,也可以完成交换的逻辑。而数组本身就是一个引用类型,这样一来,就是和地址有关联了。



目录
相关文章
|
文字识别 小程序 测试技术
网易私有云新增的测试驱动力,Airtest-ocr文字识别点击真香!
网易私有云新增的测试驱动力,Airtest-ocr文字识别点击真香!
726 0
|
1月前
|
安全 Java 数据安全/隐私保护
Spring Security 核心技术解析与实践指南
本文档深入探讨 Spring Security 框架的核心架构、关键组件和实际应用。作为 Spring 生态系统中负责安全认证与授权的关键组件,Spring Security 为 Java 应用程序提供了全面的安全服务。本文将系统介绍其认证机制、授权模型、过滤器链原理、OAuth2 集成以及最佳实践,帮助开发者构建安全可靠的企业级应用。
124 0
|
7月前
|
移动开发 前端开发 JavaScript
React音频播放列表组件:常见问题、易错点与解决方案
本文介绍了在React中实现音频播放列表时常见的挑战及解决方案。通过基础实现、常见问题分析和最佳实践,帮助开发者避免状态管理、生命周期控制和事件处理中的陷阱。关键点包括使用`useRef`操作音频元素、`useState`同步播放状态、全局状态管理防止多音频同时播放、以及通过`useEffect`清理资源。还提供了代码示例和跨浏览器兼容性处理方法,确保高效实现功能并减少调试时间。
243 30
|
开发框架 前端开发 JavaScript
ASP.NET Core+Element+SQL Server开发校园图书管理系统(二)
ASP.NET Core+Element+SQL Server开发校园图书管理系统(二)
268 0
|
Cloud Native Java 对象存储
面向未来的架构设计:Spring Cloud和Netflix OSS在云原生环境下的发展趋势
面向未来的架构设计:Spring Cloud和Netflix OSS在云原生环境下的发展趋势
200 1
|
运维 监控 Kubernetes
中间件故障转移自动切换
【7月更文挑战第25天】
239 2
|
前端开发 异构计算 API
探索Stable Diffusion:从零开始的代码接入创意图像生成指南
探索Stable Diffusion,了解这一图像生成技术,适用于创意设计、内容生成和前端应用。本文从基本概念到实战,教你如何用Python和相关库搭建环境,通过GPU加速,生成基于文本提示的图像。学习多样性和风格融合技巧,解决实践中遇到的问题,如内存溢出和图像模糊。前端开发者可将模型部署为API,实现实时动态图像生成,提升用户体验。一起发掘Stable Diffusion在艺术和设计领域的无限潜力!
631 2
|
Cloud Native 算法 API
AI问题之在互联网应用中,Agent如何使用Tools
AI问题之在互联网应用中,Agent如何使用Tools
|
自然语言处理 语音技术
语言大模型和文本大模型的区别
【2月更文挑战第16天】语言大模型和文本大模型的区别
679 2
语言大模型和文本大模型的区别
|
设计模式 负载均衡 前端开发
常见的体系架构模式
本文介绍了10种常见的架构模式,包括分层模式(降低耦合,易扩展)、客户端-服务器模式(职责明确,支持多用户)、主从设备模式(负载均衡,读写分离)、管道-过滤器模式(灵活处理,并行处理)、代理模式(控制访问,安全优化)、点对点模式(去中心化,高容错)、事件总线模式(松耦合,异步处理)、模型-视图-控制器模式(界面分离,可维护性)、黑板模式(解决复杂问题)和解释器模式(用于语言解释器)。每种模式都有其优缺点,适用于不同的场景。其他如事件驱动、微服务等也在探讨之列。详细内容可参考《软件架构理论与实践》。
312 1