c语言的形参和实参传递的区别详解

参数传递,是在程序运行过程中,实际参数就会将参数值传递给相应的形式参数,然后在函数中实现对数据处理和返回的过程。参数传递有3种方式:

  • 值传递
  • 地址传递
  • 引用传递

tips:

  1. 被调用函数的形参只有函数被调用时才会临时分配存储单元,一旦调用结束占用的内存便会被释放
  2. 值传递和地址传递,传递的都是实参的一个拷贝
  3. C语言中实参和形参之间的数据传递是单向的“值传递”,单向传递,只能由实参传给形参,反之不行
  4. 输出格式并没有选择%p而是选择了%d,因为十进制的数看起来更直观

1 值传递

如果只是传递值的话:

#include <stdio.h>

//值传递:传值
void swap( int x, int y);

int main()
{
  int a=2,b=3;
  printf("before:实参为a,b\na=%d,地址为%d\nb=%d,地址为%d\n\n",a,&a,b,&b);
  swap(a,b);
  printf("after:实参为a,b\na=%d,地址为%d\nb=%d,地址为%d\n\n",a,&a,b,&b);
  return 0;
}

void swap(int x,int y)
{
  int tmp;
  tmp=x;
  x=y;
  y=tmp;
  printf("inside:形参为x,y\nx=%d,地址为%d\ny=%d,地址为%d\n\n",x,&x,y,&y);
}

执行结果:从形参x和y的地址来看,传递的是实参a和b的拷贝。对拷贝的修改不会改变实参的值。。

如果值传递,传递的是地址呢?

#include <stdio.h>

//值传递:传地址
void swap( int *x, int *y);

int main()
{
  int a=2,b=3;
  printf("before:实参为&a,&b\na=%d,地址为%d\nb=%d,地址为%d\n\n",a,&a,b,&b);
  swap(&a,&b);
  printf("after:实参为&a,&b\na=%d,地址为%d\nb=%d,地址为%d\n\n",a,&a,b,&b);
  return 0;
}

void swap(int *x,int *y)
{
  int *tmp= NULL;
  tmp=x;
  x=y;
  y=tmp;
    printf("inside:形参为*x,*y\n*x=%d,x=%d,地址为%d\n*y=%d,y=%d,地址为%d\n\n",*x,x,&x,*y,y,&y);
}

执行结果:形参是a和b的地址,但通过a和b的地址(即x和y)访问到的是a和b的拷贝。直接交换a和b的地址失败。

2地址传递

#include <stdio.h>

//地址传递
void swap( int *x, int *y);

int main()
{
  int a=2,b=3;
  printf("before:实参为&a,&b\na=%d,地址为%d\nb=%d,地址为%d\n\n",a,&a,b,&b);
  swap(&a,&b);
  printf("after:实参为&a,&b\na=%d,地址为%d\nb=%d,地址为%d\n\n",a,&a,b,&b);
  return 0;
}

void swap(int *x,int *y)
{
  int tmp;
  tmp=*x;
  *x=*y;
  *y=tmp;
    printf("inside:形参为*x,*y\n*x=%d,x=%d,地址为%d\n*y=%d,y=%d,地址为%d\n\n",*x,x,&x,*y,y,&y);
}

执行结果为: 形参是a和b的地址,但通过a和b的地址(即x和y)访问到的是a和b的拷贝。虽然不能直接交换a和b的地址,但是可以修改a和b的地址(即x和y)指向的值。也就是说,不能直接修改指针,但是可以修改指针指向的值。所以这一次a和b的值交换了。

3 引用传递

#include <stdio.h>

//引用传递
void swap( int &x, int &y);

int main()
{
  int a=2,b=3;
  printf("before:实参为a,b\na=%d,地址为%d\nb=%d,地址为%d\n\n",a,&a,b,&b);
  swap(a,b);
  printf("after:实参为a,b\na=%d,地址为%d\nb=%d,地址为%d\n\n",a,&a,b,&b);
  return 0;
}

void swap(int &x,int &y)
{
  int tmp;
  tmp=x;
  x=y;
  y=tmp;
    printf("inside:形参为&x,&y\nx=%d,地址为%d\ny=%d,地址为%d\n\n",x,&x,y,&y);
}

void swap( int &x, int &y); //表示传递进去的是实参,而不是拷贝。

执行结果为: 传递的是实参,而不是实参的拷贝。对实参的修改,将会成功的改变其中的值。

补充

int x=1;
int *y=&x; //用于指针传递,y有自己独立的内存地址,存储的内容是x的地址,*y是x的值
int &z=x; //用于引用传递,可以理解为z就是x,x就是z,只不过名字不一样

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • C语言中形参和实参详解及实例代码

    形式参数和实际参数 函数的参数分为形参和实参两种.在本小节中,进一步介绍形参.实参的特点和两者的关系.形参出现在函数定义中,在整个函数体内都可以使用,离开该函数则不能使用.实参出现在主调函数中,进入被调函数后,实参变量也不能使用.形参和实参的功能是作数据传送.发生函数调用时,主调函数把实参的值传送给被调函数的形参从而实现主调函数向被调函数的数据传送. 函数的形参和实参具有以下特点: 1.形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的内存单元.因此,形参只有在函数内部有效.函

  • c语言的形参和实参传递的区别详解

    参数传递,是在程序运行过程中,实际参数就会将参数值传递给相应的形式参数,然后在函数中实现对数据处理和返回的过程.参数传递有3种方式: 值传递 地址传递 引用传递 tips: 被调用函数的形参只有函数被调用时才会临时分配存储单元,一旦调用结束占用的内存便会被释放 值传递和地址传递,传递的都是实参的一个拷贝 C语言中实参和形参之间的数据传递是单向的"值传递",单向传递,只能由实参传给形参,反之不行 输出格式并没有选择%p而是选择了%d,因为十进制的数看起来更直观 1 值传递 如果只是传递值

  • C语言 自增自减运算的区别详解及实例

    自增自减 ++自增运算符:如a++,++a都等价于a = a + 1: –自减运算符:如a–,–a都等价于 a = a -1: ++a和a++的区别 虽然++a和a++等价的结果一样,但是运算过程不同,a++ 是先使用a的值,然后再对a做加1处理,++a是先对a作加1处理,然后再使用a的值. 例子 #include <stdio.h> int main() { //int m = 10, n1, n2; //n1 = m++;先将m的值赋给n1,然后m再做自增运算,所以此时,n1=10,m=1

  • Java必踩的坑之方法中形参、实参传递

    首先亮明Java中方法参数传递的规则,这两点很重要: 如果实参是基本类型(包括包装类型)或者String,则实参不会变(传的是值): 如果实参是对象集合或者数组,则实参会改变(传的是引用). 上面这两条比较简单,笔者就不展开说了,这里只说一点,关于方法中引用的传递,很多人会踩坑,如下: 我们先以数组举例,如下代码,很简单的几行,大家猜一下会最终输出的结果是什么样子的呢? public class PassByValueDemo { public static void main(String[]

  • C语言*与&在操作线性表的作用详解

    在数据结构线性表一章,对线性表有这些操作方法(Operation): /*Operation*/ Initlist(*L);/*初始化操作,建立一个空的线性表L*/ ListEmpty(L):/*判断线性表是否为空表,若线性表为空,返回值为true,否则返回false*/ ClearList(*L):/*将线性表清空*/ GetElem(L,i,*e):/*性表L中的第i个位置元素值返回给e*/ LocateElem(L,e):/*在线性表L中查找与给定值e相等的元素,如果查找成功,返回该元素在

  • Go语言学习之函数的定义与使用详解

    目录 1.函数定义 2.多值返回 3.引用传递 4.函数作为实参使用 5.匿名函数 1.函数定义 函数的定义和java一样,使用{}进行包裹,并且要明确入参类型以及返回类型. 样例代码如下: func min(num1, num2 int) int { if num1 <= num2 { return num1 } else { return num2 } } func main() { fmt.Printf("max = %d\n", min(10, 12)) } 执行结果 m

  • C++之值传递&指针传递&引用传递的示例详解

    目录 1.函数基础 2.值传递 3.指针传递 4.引用传递 1.函数基础 一个函数由以下四部分组成: 返回类型 函数名 参数(0个或多个) 函数体 其中,函数的参数叫做形参,函数执行的操作的语句块叫做函数体 2.值传递 像一个这样swap函数,调用的时候,会用实参初始化swap函数对应的形参 void Swap(int a, int b) { int tmp = a; a = b; b = tmp; } 在内存中会拷贝一份实参的值,但是修改形参的值并不影响实参的值 测试用例 #include <

  • C语言实现进制转换函数的实例详解

    C语言实现进制转换函数的实例详解 前言: 写一个二进制,八进制,十六进制转换为十进制的函数 要求: 函数有两个参数,参数(1)是要转换为十进制的进制数,参数(2)是标示参数(1)是什么进制(2,8,16标示二进制,八进制,十六进制). 要有报错信息,比如参数是1012,但参数(2)是2,显然是进制数表示有错误. 系统表 pg_proc 存储关于函数的信息 内部函数在编译之前需要先定义在 pg_proc.h 中,src/include/catalog/pg_proc.h CATALOG(pg_pr

  • C语言静态与动态通讯录的实现流程详解

    目录 静态通讯录 contact.h contact.c test.c 动态通讯录 contact.h contact.c qsort.c test.c 本次通讯录的代码已经放到我的Gitee仓库中,感兴趣的小伙伴可以去看看 Gitee 静态通讯录 在我们学习完C语言的结构体.指针以及动态内存管理之后,我们就可以实现一些有意思的小项目了,通过这些小项目可以加深我们对于相关知识的理解. 静态通讯录主要要求有 静态大小,可以记录10个人的信息(大小自己定) 记录的信息如下:名字.性别.年龄.电话.住

  • C语言动态内存管理malloc柔性数组示例详解

    目录 1.1为什么存在动态内存管理 1.2动态内存管理函数 1.2.1malloc 1.2.2free 1.2.3calloc 1.2.4realloc 1.3动态内存管理函数易错点 1.3.1对NULL指针的解引用操作 1.3.2对动态开辟空间的越界访问 1.3.3对非动态开辟内存使用free释放 1.3.4使用free释放一块动态开辟内存的一部分 1.3.5对同一块动态内存多次释放 1.3.6动态开辟内存忘记释放(内存泄漏) 2.1常见相关笔试题 2.2C/C++语言中的内存开辟 2.3柔性

  • Go语言通过WaitGroup实现控制并发的示例详解

    目录 与Channel区别 基本使用示例 完整代码 特别提示 多任务示例 完整代码 与Channel区别 Channel能够很好的帮助我们控制并发,但是在开发习惯上与显示的表达不太相同,所以在Go语言中可以利用sync包中的WaitGroup实现并发控制,更加直观. 基本使用示例 我们将之前的示例加以改造,引入sync.WaitGroup来实现并发控制. 首先我们在主函数中定义WaitGroup var wg sync.WaitGroup 每执行一个任务,则调用Add()方法 wg.Add(1)

随机推荐