C语言函数传参的机制:值传递还是引用传`递?

C专家编程--指针和数组(三) 值传递 指针传递 引用传递 http://blog.youkuaiyun.com/yusiguyuan/article/details/12357381 http://blog.youkuaiyun.com/yusiguyuan/article/details/12357457 而关于值传递,指针传递,引用传递这几个方面还会存在误区, 所有我觉的有必要在这里也说明一下~ 下文会通过例子详细说明哦 值传递: 形参是实参的 阅读详情

C语言函数传参的机制:值传递还是引用传`递?

在C语言中,函数是程序的基本构建块之一。在调用函数时,如何将参数传递给函数?这一问题是每个C语言开发者在编写程序时都会遇到的。在C语言中,函数参数传递的机制主要有两种:值传递和引用传递。理解这两者的区别对于编写高效的C程序至关重要。

本文将深入探讨C语言中的函数传参机制,详细解析值传递和引用传递的不同之处,并通过丰富的代码示例帮助大家深入理解。

一、函数传参的基本概念

在C语言中,函数调用时的参数传递机制,决定了函数如何接收到调用方的数据。C语言中的函数传参有两种主要方式:值传递和引用传递。

值传递

值传递是将实际参数的值复制一份,传递给函数的形式参数。也就是说,函数内部的形参是实际参数的副本,对形参的修改不会影响到外部的实际参数。

引用传递(通过指针)

引用传递,或者说通过指针传递,是将实际参数的地址传递给函数,使得函数能够直接操作该内存地址,从而修改实际参数的值。对于引用传递来说,形参是实际参数的地址,对形参的修改会直接影响实际参数。

二、值传递:原理与示例

在值传递中,函数接收的是实参的副本。由于传递的是副本,函数内部的操作不会改变外部变量的值。

值传递的示例

#include <stdio.h>

void modifyValue(int a) {
    a = 20;  // 修改形参a的值
}

int main() {
    int num = 10;
    printf("Before modifyValue: num = %d\n", num);
    modifyValue(num);  // 传递num的副本
    printf("After modifyValue: num = %d\n", num);  // num的值不变
    return 0;
}
输出:
Before modifyValue: num = 10
After modifyValue: num = 10

在上面的例子中,modifyValue函数修改了形参a的值,但由于是值传递,num的值在main函数中没有改变。函数内部修改的是a的副本,而不是num。

值传递的优缺点

优点:

  1. 简单易理解,避免了指针的复杂性。
  2. 函数的副作用较少,不会直接修改外部数据。

缺点:

  1. 由于是传递副本,可能会消耗额外的内存,尤其是对于大型数据结构(如数组或结构体)。
  2. 对于大型数据结构,传递副本的效率较低。

三、引用传递:原理与示例

引用传递的本质是传递变量的地址(即指针),这样函数内部可以直接访问并修改原始数据。

引用传递的示例

#include <stdio.h>

void modifyValue(int *a) {
    *a = 20;  // 修改a指针所指向的值
}

int main() {
    int num = 10;
    printf("Before modifyValue: num = %d\n", num);
    modifyValue(&num);  // 传递num的地址
    printf("After modifyValue: num = %d\n", num);  // num的值被修改
    return 0;
}
输出:
Before modifyValue: num = 10
After modifyValue: num = 20

在这个例子中,modifyValue函数通过指针参数a修改了num的值,因为传递的是num的地址,函数内部的操作直接影响了外部的num。

引用传递的优缺点

优点:

  1. 修改的是原始数据,效率高,特别是对于大数据结构,避免了复制的开销。
  2. 适用于需要修改外部数据的场景,能够直接改变实参的值。

缺点:

  1. 需要使用指针,代码相对复杂。
  2. 可能会导致副作用,函数外部的变量值被修改,可能会引发不易察觉的错误。

四、值传递与引用传递的区别

在C语言中,值传递和引用传递有以下主要区别:

特性值传递引用传递
传递的内容传递实际参数的副本传递实际参数的地址(指针)
修改实参的影响不会修改实参会修改实参
内存消耗可能需要额外的内存用于存储副本不需要额外内存
效率对于大数据结构效率较低对于大数据结构效率较高
代码复杂度较低,简单易懂较高,需要使用指针
应用场景不需要修改实参的场景需要修改实参或者传递大数据结构的场景

五、C语言中如何使用值传递和引用传递

使用值传递的场景

  1. 不需要修改外部数据:例如函数只是为了计算某个值并返回,不需要修改外部数据。
  2. 传递基本数据类型:如int、char等简单类型时,使用值传递更为高效。
#include <stdio.h>

int add(int x, int y) {
    return x + y;  // 只需要计算并返回值
}

int main() {
    int a = 5, b = 3;
    int result = add(a, b);  // 使用值传递
    printf("Result = %d\n", result);
    return 0;
}

使用引用传递的场景

  1. 需要修改外部数据:如函数需要修改传入参数的值。
  2. 传递较大的数据结构:如数组、结构体等,使用引用传递避免了大量的内存复制,提高效率。
#include <stdio.h>

void swap(int *x, int *y) {
    int temp = *x;
    *x = *y;
    *y = temp;  // 交换x和y的值
}

int main() {
    int a = 5, b = 10;
    printf("Before swap: a = %d, b = %d\n", a, b);
    swap(&a, &b);  // 使用引用传递
    printf("After swap: a = %d, b = %d\n", a, b);
    return 0;
}

六、结论

C语言中的函数传参机制是编程中至关重要的一个概念。值传递和引用传递各自有不同的应用场景和优缺点,掌握它们的使用方式对于编写高效和易于维护的程序至关重要。在实际应用中,我们应根据具体问题选择合适的传参方式。

  • 值传递:适用于不需要修改外部数据的场景,简洁明了,但可能导致不必要的内存开销。
  • 引用传递:适用于需要修改外部数据或者传递大数据结构的场景,避免了复制开销,但代码复杂度较高。

希望通过本文的讲解,你能够更好地理解C语言函数传参的机制,并能根据实际需求灵活选择传参方式,从而提高程序的性能和可维护性。

C语言入门系列:从内存原理看函数的值传递和引用传递 函数参数用于向函数传递数据,C语言支持两种传递方式:值传递和引用传递。 阅读详情

相关推荐

C语言实现栈算法学习心得

在用C语言实现栈相关算法的过程中,加深了对C语言的理解。 C语言中,函数的形参是通过值传递,接受实参的值,形参的数据类型只是规定了传进来的实参的数据类型,无法改变其值。 在主函数中调用函数时,传入的实参必须与形参的数据类型一致。例如: 定义如下的栈初始化函数 #define STACK_INIT_SIZE 5 #define STACKINCREMENT 1 typedef

a251844314的博客 1863

C语言函数参数传递的两种方式:值传递和引用传递(包括整型变量和字符串变量)

C语言函数参数传递的两种方式:值传递和引用传递1 值传递1.1 实实在在的值传递1.2 指针传递2 引用传递3 字符串变量的函数传递与指针传递3.1 错误示范参考 1 值传递 值传递包括实实在在的值传递和指针传递,指针传递参数本质上是值传递的方式,它所传递的是一个地址值,传递的都是实参的一个拷贝。 1.1 实实在在的值传递 #include <iostream> #include <vector> using namespace std; void function(int

紫芝的博客 2万+

C++引用从别名到绑定:高效传参、避免拷贝与实战避坑指南

在C++编程中,引用是一种为已存在变量创建别名的机制,它本质上是在编译期建立的不可重新绑定的对象关联。理解引用的核心原理,关键在于区分它与指针的本质差异:引用必须初始化、不可为空、且无法更改绑定对象,这为编译器优化和代码安全性提供了基础。从技术价值看,引用能显著提升程序性能,尤其在函数参数传递时,通过避免不必要的对象拷贝,大幅减少内存和计算开销。在应用场景上,左值引用常用于函数参数和返回值设计,实现高效的数据修改与访问;const引用则作为万能接收器,能安全绑定临时对象并延长其生命周期,同时接受更广泛的输入

weixin_29237635的博客 235

【C语言】函数的传参

函数的传参是我们经常会碰到的,一般在我们常用的是三种传参方式:传值、传址和引用传递

m0_72594605的博客 3504

锐捷交换机配置SSH

锐捷交换机配置ssh 一、组网需求 通过ssh功能可以远程登录管理设备 二、配置步骤 全局开启ssh服务,并且指定ssh版本 Ruijie>enable Ruijie#configure terminal Ruijie(config)#enable service ssh-server ------>开启SSH服务,默认关闭 Ruijie(config)#ip ssh version 2 ------>默认1.99版本,设置为版本2 添加登

Loners_fan的博客 1万+

基于BQ24610的24V电池充电板

转自我的博客 本文的主要目的在于传播基本的阅读datasheet的能力,以及PCB设计需要注意的基本问题。 本次需要设计的是24V动力锂电池充电电路。 原理图设计 参考官方参考电路 为了快速设计电路,自然是参考官方参考电路,选择Typical Application。 做细微的参数调整 由于我们的需求是给24V的电池充电,所以需要稍微修改一下原理图,接下来需...

greedyhao的博客 1万+

函数参数传递的两种方式——值传递和引用传递

参考原文详细说明:https://www.cnblogs.com/codingmengmeng/p/5865510.html 一、值传递 值传递包括实实在在的值传递以及指针传递(指针传递参数本质上是值传递的方式,它所传递的是一个地址值),传递的都是实参的一个拷贝。 1、实实在在的“值”传递 #include &lt;iostream&gt; #include &lt;vector&gt;...

Magnum的博客 2万+

K-means在关键词聚类中的尝试

K-means在文本聚类中的尝试 K-means算法是无监督的聚类算法。它的算法思想是:先随机选取K个对象作为初始的聚类中心。然后计算每个对象与各个种子聚类中心之间的距离,把每个对象分配给距离它最近的聚类中心。聚类中心以及分配给它们的对象就代表一个聚类。一旦全部对象都被分配了,每个聚类的聚类中心会根据聚类中现有的对象被重新计算。 K-means算法的关键点在于: 初始k个聚类中心的选择 距离的计...

BigPig_LittleTail的博客 5572

揭秘C语言函数传参玄机:const指针如何避免数据泄露和程序崩溃

掌握C语言const指针的函数参数传递技巧,有效防止数据泄露与程序崩溃。适用于接口设计与库函数开发,通过只读限定保障实参安全,提升代码健壮性与可维护性,值得收藏。

LogicPlex的博客 939

【上海大学计算机组成原理实验报告】一、数据传送实验

将58H写入A寄存器//将6BH写入W寄存器//将C3H写入R1寄存器//将C3H写入R1寄存器//了解实验仪器数据总线的控制方式//掌握数据传送的基本原理//掌握各寄存器的结构、工作原理及其控制方法//数据传送实验

HackerKevon的博客 3509

【新华三】通过路由复制实现Public与VRF路由互通

如上图所示,S6900设备里有两张表,一张是public路由表,默认所有的路由都存放在public路由表里;除此之外还创建了VRF test,因此此设备还有VRF test路由表。通过路由复制实现Public路由和VRF路由互通,默认情况下VRF里的路由单独一张路由表,默认情况下与public路由表相互隔离,两张表之间不可互访。此时的public路由表里面并没有test的路由表。public路由表与VRF路由表之间相互隔离。此时VRF test里的路由也没有其他VRF或Public里的路由,相互隔离。

五大连池的镜子 5276

指针及指针传参

运行后你会发现,`&a`和`p`打印出来的地址完全一致,这就说明p确实精准指向了a的内存位置。3. **数组传参退化为指针**:把数组传入函数时,数组会自动退化为指向首元素的指针,函数内部用`sizeof`计算数组大小,得到的只是指针的大小,永远得不到原始数组的总长度,所以传数组时必须额外传入一个长度参数。指针传参从来不是什么“高级技巧”,它本质上就是C语言给我们的一个“直接操作内存”的通道:用地址代替数据副本,既可以避免大块数据的复制开销,又能突破值传递的限制,让子函数拥有修改主函数数据的能力。

2601_96617673的博客 587

Codex 100个真实案例 - 用AI做在线考试系统(自动组卷+防作弊)

本案例使用 Codex 从零搭建一个功能完整的在线考试系统。涵盖题库管理(单选/多选/判断/填空)、智能随机组卷、考试倒计时、自动判分、成绩统计分析、以及多维度防作弊机制(切屏检测、禁止复制粘贴、IP限制等)。前端使用 Vue 3 + Element Plus 构建考试界面,后端使用 Node.js + Express + MySQL 提供 API 服务。全程用自然语言驱动 Codex 完成开发,最终交付一个可直接部署的在线考试平台。

yueyeguzhuo的专栏 77

C语言数组传参的致命误区,99%的人都没意识到的指针退化问题

掌握C语言数组传参本质,避开常见陷阱。详解C语言数组名作为函数参数退化为指针的机制,涵盖实际应用场景与正确使用方法,提升代码健壮性与效率。理解这一关键特性,避免长度误判与越界访问,值得收藏。

IterLoom的博客 1099

【11】科曼医疗——科曼医疗 嵌入式--面试,校招,面试问答记录

科曼医疗嵌入式校招面试记录:3位面试官分别考察应用层技术、底层技术和HR面。技术问题涵盖C++特性(多态、虚函数、指针与引用区别)、内存管理(malloc与new对比)、嵌入式基础(51最小系统、IIC/SPI协议)及项目经验(智能黑板擦专利项目)。同时考察了Linux使用经验、STM32开发及嵌入式操作系统认知。最后环节应聘者询问了开发环境及面试流程。面试内容全面覆盖嵌入式开发核心知识点。

程序员,他们想的是什么?他们想的永远都是技术,他们崇尚的也永远都是技术。 1248

【GameFramework框架内置模块】8、文件系统(File System)

最近好忙,鸽了好久。不能颓废了,继续发力。今天分享的是GF框架的文件系统。首先,引用比较官方的说法:GF的FileSystem虚拟文件系统,使用类似磁盘存储的感念对零散的文件进行集中管理,优化资源加载时产生的内存分配,也可以对资源进行局部片段加载,极大的提升了资源加载的性能。通俗点讲就是,我这个模块就是加载磁盘文件的,优化加载时产生的内存分配。那么,它是怎么优化的呢?

优快云博客专家,Unity3D高级软件工程师,《Unity 3D从入门到实战》作者。 2448

【Go语言-Day 9】指针基础:深入理解内存地址与值传递

许多初学者闻“指针”色变,认为它复杂难懂。但实际上,Go 语言的指针相比 C/C++ 已经做了很多简化和安全限制,理解它将为你打开一扇通往更高阶编程世界的大门。本篇作为指针系列的上篇,将拨开云雾,带你从最基础的内存地址概念入手,彻底搞懂指针是什么、如何使用以及为何要使用它。

吴师兄大模型的博客 861

jdk-8u144-linux-x64.tar.gz.

该资源为搭建Linux系统Java环境用,资源的后缀为tar.gz格式的压缩包

引用与引用作为函数的参数

1、&S是引用,S和传入的形参变量共用同一个存储空间,相当于别名。 2、*S是指针,S是指针变量,它是有自己的存储空间的,只是它的存储空间存的是形参变量的地址。   对一个数据建立一个“引用”,他的作用是为一个变量起一个别名。这是C++对C语言的一个重要补充。 如何建立一个引用 ` int a = 5; int &b = a; cout<&lt...

chongchujianghu3的博客 1164

jre9下载 jdk9

(Java SE Runtime Environment 9.0) 9.0u175 官方最新版 【x86|x64】

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

C语言数组传参详解:从内存原理到实战避坑指南

在C语言编程中,函数参数传递的核心机制是值传递,这意味着传递给函数的是实参值的副本。对于基本数据类型,传递的是数值本身;而对于数组,情况则更为特殊。由于数组名在大多数表达式中会退化为指向其首元素的指针,因此数组传参的本质是传递该指针的地址值。这一机制使得函数内部可以通过指针直接操作原始数组的内存,实现了类似引用的效果,但也带来了无法在函数内直接获取数组长度等限制。理解这一原理对于编写高效、安全的C代码至关重要,尤其是在处理一维、二维数组以及动态内存分配时。通过合理使用指针、const修饰符以及结构体封装等技

weixin_30580341的博客 399

SIMATIC S7-1200, S7-1500 PID 控制[手册]

SIMATIC S7-1200, S7-1500 PID 控制[手册]

鸿蒙5:自定义构建函数

本文详细介绍了鸿蒙ArkTS语言中的自定义构建函数功能,主要包括: @Builder基础用法,通过构建函数复用UI元素 构建函数的参数传递方式(值传递和引用传递) 使用@BuilderParam实现UI插槽功能,在子组件中接收父组件传递的UI结构 通过Tabs组件案例展示@Builder的实际应用 尾随闭包的使用场景和注意事项 文章还提供了多个实践案例代码,如自定义TabBar、商品列表组件等,帮助开发者掌握如何灵活运用构建函数来优化鸿蒙应用开发。

qq_56760790的博客 1170

C语言速通秘籍——函数

库函数 & 自定义函数 语法形式;实参和形参(调用结束会销毁,传值时要注意一下);函数的声明和定义 `return`语句:后面可以跟着值/表达式;`void`返回类型时可以后面不跟着返回值;返回值和返回类型不一致时,会将返回值隐式转换成函数的返回类型(拓:`printf`的按格式强行读取指定字节数,这个需注意) 数组做函数参数:数组传参实际是指针的形式;形参和实参都是同一个数组(地址相同);传数组时需要传数组的大小,因为其在形参时作为指针的,指针的大小根据编译器的系统位数决定(x86:4字节;x64:8

2402_89218457的博客 220

【超详细】C语言【初阶】笔记【已完结】

本文涵盖了C语言的基本语法、数据类型、运算符、控制结构(如if语句、循环)、函数、数组和指针等概念

隼玉的博客 1211

C 语言函数和数组

函数可为任务命名,实现代码复用;数组则支持批量传递同类型数据,便于统一处理。但数组传入函数时存在关键特性:数组名会退化为首地址,其长度信息无法一同传入,函数无法自动获知数组有效长度。因此在开发中,通常需要额外传入长度参数,保障遍历与读写安全。理解这一规则,是掌握数组传参、指针相关逻辑的基础,也能规避越界访问等常见程序错误。

by20999的博客 1072

Python如何安全传参给C函数?这4种类型转换方法你必须掌握

掌握Python调用C函数的安全传参技巧,详解C语言Python类型转换的4种核心方法。涵盖字符串、数值与指针转换场景,确保数据安全高效交互。方法实用可靠,适配ctypes与C扩展开发,值得收藏。

InstrFun的博客 1190

函数栈帧的创建和销毁

函数栈帧的创建和销毁是C语言程序运行时的重要机制,它保证了函数的正确调用、参数传递和返回等操作,理解这一过程对于深入理解C语言的函数调用机制以及调试程序中的一些错误(如栈溢出等)非常有帮助。这个示例只是一个简单的示意,实际的函数栈帧创建和销毁过程在编译器和底层硬件的处理下要复杂得多,但通过这个示例可以对其基本原理和涉及的关键操作有一个初步的理解。所占用的存储空间清理(在这个简单示例中,主要是释放其占用的栈空间),然后将返回值传递给。函数中,当函数被调用时,会在其栈帧内为局部变量。函数内部,对应的形参。

lxy370198409的博客 1044

Python赋值机制深度解析:从变量引用到深拷贝实战

在编程语言中,变量与数据的关系是核心基础概念。Python采用基于对象的引用模型,变量实质上是对象的标签而非存储容器。这一机制决定了数据在内存中的共享方式,直接影响程序的正确性与性能。理解可变与不可变对象的差异是关键,可变对象(如列表、字典)的赋值会导致多个变量引用同一内存地址,修改时可能引发意外的副作用。为获得独立的数据副本,需掌握浅拷贝与深拷贝技术:浅拷贝仅复制最外层对象,内层子对象仍共享引用;深拷贝则递归复制所有层级,实现完全的数据隔离。在函数参数传递、循环闭包及数据处理等工程实践中,精准运用赋值与拷

diandingyin9417的博客 355
上一篇: 深入理解C语言内存管理:堆与栈的区别
下一篇: 用AIGC创作诗歌、小说和剧本:创作者的未来助手
set_one
博客等级 码龄2年 332粉丝 43原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值