C语言值传递和地址传递详解

目录
  • 一. 值传递
  • 二.地址传递
  • 总结

一. 值传递

我们举一个例子:

写一个函数找出两个整数中的最大值。

#include<stdio.h>

//get_max函数
int get_max(int x,int y)
{
  return (x>y)?x:y;
}

int main()
{
  int num1 = 10;
  int num2 = 20;
  int max = get_max(num1,num2);
  printf("max = %d\n",max);
  return 0;
}

运行结果是:

max = 20

我们来分析一下这个函数调用过程:

num1,num2作为实参传入get_max()函数,形参x,y被实例化(分配内存单元),num1和num2的值按照函数形参表顺序对应地传给了x和y,也就是x=10,y=20,然后函数将x和y中较大的一个的值返回。函数调用完毕,x和y被自动销毁。

我们看一下函数的特征,如果函数的形参和实参一致,这就是值传递。

二.地址传递

再举一个例子:

写一个函数交换两个整形变量的内容。

很多初学者一看觉得太简单了,按照值传递我们来写一遍。

#include <stdio.h>
//值传递
void Swap1(int x, int y) {
    int tmp = 0;
    tmp = x;
    x = y;
    y = tmp;
}
int main()
{
	int num1 = 1;
	int num2 = 2;

  printf("交换前::num1 = %d num2 = %d\n",num1,num2);
  Swap1(num1, num2);
	printf("swap1::num1 = %d num2 = %d\n", num1, num2);
	return 0;
}

但此时的结果是什么呢?

num1,num2值并没有变啊,并没有交换啊,为什么呢?

因为当实参传给形参的时候,形参是实参的一份临时拷贝,对形参的修改不会影响实参

我们来打印一下各变量的地址

可以看到,实参有自己的地址,形参也有自己的地址,实参只把自己的值传给了形参,地址各有各的,实参的地址上放的值并没有变啊,并且形参在函数调用完后就自动销毁了,也就是说函数内与函数外的变量并没有建立真正的实质的联系。就想象你copy了一个自己的仿生人,他吃了东西,进你的胃了吗?肯定他吃他饱,跟你毫无相关是吧(狗头

那么这个问题怎么解决呢?地址传递

#include <stdio.h>
//值传递
void Swap1(int x, int y) {
    int tmp = 0;
    tmp = x;
    x = y;
    y = tmp;
}
int main()
{
	int num1 = 1;
	int num2 = 2;

  printf("交换前::num1 = %d num2 = %d\n",num1,num2);
  Swap1(num1, num2);
	printf("swap1::num1 = %d num2 = %d\n", num1, num2);
	return 0;
}

​ 我们来看一下结果

地址传递做了什么?

做地址传递时 函数参数是指针变量,指针变量里面装着的就是地址嘛,所以实参直接就把自己的地址传过去了,px里放的num1地址,py里放的num2地址, *px就是num1本身, *py就是num2本身,实参本身进行了赋值交换,这次不是你的仿生人了,就是你自己体验人生。

我们看一下函数特征:如果传入的实参是形参的指针,那就是地址传递。

其实有一个问题我好久才想明白:

为什么上一个例子(返回两数中较大的一个)没有用地址传递也成功了呢?这两种方式使用的界限是什么呢?

后来这个疑问终于被解答了:

因为第一个例子里num1,num2的值并不需要改变,函数中x,y比较后如果返回x,x的值和a的值是一样的,这个对结果是不影响的,也就是说,这种问题不需要改变实参的值,形参和实参不需要建立那么实质的联系

但要搞清楚的是,函数返回的是num1本身吗?是num1地址上的值吗?不,只是num1的拷贝x地址上的值。

综上,在需要改变实参的值时一定要使用地址传递才行。

总结

到此这篇关于C语言值传递和地址传递详解的文章就介绍到这了,更多相关C语言值传递 地址传递内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • C语言中 值传递和指针传递实例详解

    C语言中 值传递和指针传递实例详解 在C语言中,函数的参数和返回值的传递方式有两种:值传递和指针传递. 值传递和指针传递初学者总会有一种朦胧的感觉,所以建议把指针传递的概念摸透,才能熟练应用. 值传递示例:x其实是n的一份临时拷贝,所以并不会改变n的值. #include <stdio.h> #include <windows.h> void Fun(int x) { x = 1; } int main() { int n = 2; Fun(n); printf("%d\

  • C语言值传递和地址传递详解

    目录 一. 值传递 二.地址传递 总结 一. 值传递 我们举一个例子: 写一个函数找出两个整数中的最大值. #include<stdio.h> //get_max函数 int get_max(int x,int y) { return (x>y)?x:y; } int main() { int num1 = 10; int num2 = 20; int max = get_max(num1,num2); printf("max = %d\n",max); return

  • 详解java的值传递、地址传递、引用传递

    详解java的值传递.地址传递.引用传递 一直来觉得对值传递和地址传递了解的很清楚,刚才在开源中国上看到一篇帖子介绍了java中的值传递和地址传递,看完后感受颇深.下边总结下以便更容易理解. 按照以前的理解,java中基本数据类型是值传递,对象是地址(引用)传递.给大家看个例子: public class ObjectTrans { public static void main(String[] args) { String name = "123"; SChange(name);

  • vue组件中使用props传递数据的实例详解

    在 Vue 中,父子组件的关系可以总结为 props向下传递,事件向上传递.父组件通过 props 给子组件下发数据,子组件通过事件给父组件发送消息.看看它们是怎么工作的.  一.基本用法 组件不仅仅是要把模板的内容进行复用,更重要的是组件间要进行通信. 在组件中,使用选项props 来声明需要从父级接收的数据, props 的值可以是两种, 一种是字符串数组,一种是对象. 1.1 字符串数组: <div id="app4"> <my-component4 messa

  • vuejs动态组件给子组件传递数据的方法详解

    通过子组件定义时候的props可以支持父组件给子组件传递数据,这些定义的props在子组件的标签中使用绑定属性即可,但是如果使用的是<component>动态组件,这个时候就没有显式的子组件标签,要给子组件传递数据需要在<component> 中进行绑定 <div class="app" id="deviceready"> <component :is="currentView" :user_name.s

  • C语言数据输入与输出实例详解

    C语言数据输入与输出实例详解 1 概论 C语言提供了跨平台的数据输入输出函数scanf()和printf()函数,它们可以按照指定的格式来解析常见的数据类型,例如整数,浮点数,字符和字符串等等.数据输入的来源可以是文件,控制台以及网络,而输出的终端可以是控制台,文件甚至是网页. 2 数据输出 从第一个c语言程序中,就使用了跨平台的库函数printf实现将一段文字输出到控制台,而实际上,printf()不仅可以将数据按照指定的格式输出到控制台,还可以是网页或者是指定的文件中,printf()函数执

  • C语言ASM汇编内嵌语法详解

    3 GCC Inline ASM GCC 支持在C/C++代码中嵌入汇编代码,这些汇编代码被称作GCC Inline ASM--GCC内联汇编.这是一个非常有用的功能,有利于我们将一些C/C++语法无法表达的指令直接潜入C/C++代码中,另外也允许我们直接写 C/C++代码中使用汇编编写简洁高效的代码. 1.基本内联汇编 GCC中基本的内联汇编非常易懂,我们先来看两个简单的例子: __asm__("movl %esp,%eax"); // 看起来很熟悉吧! 或者是 __asm__(&q

  • C语言 指针的初始化赋值案例详解

    目录 1.指针的初始化 2.指针的赋值 3.指针常量 4.指针初始化补充 5.void *型指针 6.指向指针的指针 1.指针的初始化 指针初始化时,"="的右操作数必须为内存中数据的地址,不能够是变量,也不能够直接用整型地址值(可是int*p=0;除外,该语句表示指针为空).此时,*p仅仅是表示定义的是个指针变量,并没有间接取值的意思. 比如: int a = 25; int *ptr = &a; int b[10]; int *point = b; int *p = &am

  • go语言结构体指针操作示例详解

    目录 指针 go指针操作 不能操作不合法指向 new函数 指针做函数的参数 数组指针 结构体指针变量 结构体成员普通变量 结构体成员指针变量 结构体比较和赋值 结构体作为函数参数 指针 指针是代表某个内存地址的值.内存地址储存另一个变量的值. 指针(地址),一旦定义了不可改变,指针指向的值可以改变 go指针操作 1.默认值nil,没有NULL常量 2.操作符“&”取变量地址,“*“通过指针(地址)访问目标对象(指向值) 3.不支持指针运算,不支持“->”(箭头)运算符,直接用“.”访问目标成

  • Go语言学习之链表的使用详解

    目录 1. 什么是链表 2. 单项链表的基本操作 3. 使用 struct 定义单链表 4. 尾部添加节点 5. 头部插入节点 6. 指定节点后添加新节点 7. 删除节点 1. 什么是链表 链表是一种物理存储单元上非连续.非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的. 链表由一系列结点(链表中每一个元素称为结点)组成,结点可以在运行时动态生成.每个结点包括两个部分:一个是存储数据元素的数据域,另一个是存储下一个结点地址的指针域. 使用链表结构可以避免在使用数组时需要预先知

  • Go语言中的数据竞争模式详解

    目录 前言 Go在goroutine中通过引用来透明地捕获自由变量 切片会产生难以诊断的数据竞争 并发访问Go内置的.不安全的线程映射会导致频繁的数据竞争 Go开发人员常在pass-by-value时犯错并导致non-trivial的数据竞争 消息传递(通道)和共享内存的混合使用使代码变得复杂且易受数据竞争的影响 Add和Done方法的错误放置会导致数据竞争 并发运行测试会导致产品或测试代码中的数据竞争 小结 前言 本文主要基于在Uber的Go monorepo中发现的各种数据竞争模式,分析了其

随机推荐