【理解C语言】为什么要区分传址与传值?

 

目录

什么是传值?

 为什么有传址?

怎么选择传值与传址?

 实例:

传值的优缺点:

传址的优缺点: 


        【理解C语言】栏目主要用来分享水墨对C的一些浅薄理解,在这里你可能会因看到一些困扰你很久的问题的解决思路,从而获得灵感。


什么是传值?

         我们先看一段代码:

e.g.1


#include<stdio.h>

int Add(int x, int y)
{
	int z = 0;

	z = x + y;

	return z;

}


int main()
{
	int a = 10;
	int b = 20;
	int c = 0;

	c = Add(a, b);

	printf("%d ", c);

	return 0;
}

        对于这段代码,我们很容易发现——函数Add只需得到a与b的值,然后相加再返回即可,不需要对a与b本身进行修改操作。

        传值是指数据传递给函数的形参时,实际传递的是数据的copy而不是数据本身。在传值过程中,变量本身的值不会被修改,只是将数据的值复制一份传递给函数的形参,也就是只对数据进行运算,不改变数据。

         就如e.g.1,我们在函数内部对数据进行求和,并不改变  形参  或  实参  的值。(而实际上改变形参对实参并没有影响)

        为什么呢?——>  改变原数据的一份copy,并不对原数据产生影响。

        如果你想要详细理解函数在传参时的操作,可以看:

【C语言】函数栈帧空间的创建与销毁-CSDN博客icon-default.png?t=N7T8https://blog.csdn.net/2301_79465388/article/details/134256464?spm=1001.2014.3001.5501

 为什么有传址?

但实际上一些问题只通过传值是无法解决的,例如:

 

 (交换a与b的值)

         为什么呢?

        当我们按F10开始调试,打开监视:

         我们发现:a与x的地址,b与y的地址,是不同的。(其实很容易理解:因为x是a的拷贝,y是b的拷贝)

        怎么解决这一问题,从而实现a与b的交换呢?

        这时,考虑将a与b的地址传入函数swap():

#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>

void swap(int* pa,int* pb)
{
	int tem = *pa;
	*pa = *pb;
	*pb = tem;
}

int main()
{
	int a = 0;
	int b = 0;
	scanf("%d %d", &a, &b);

	printf("%d %d\n", a, b);

	swap(&a, &b);
		
	printf("%d %d\n", a, b);
	return 0;

}

        这样,就可以实现a与b的交换了:

怎么选择传值与传址?

         其实传址相对于传址好像更特殊,因为它让函数的形参与实参建立了真正的联系,可以在被调用函数中改变主调函数的变量的值,也就是说:

        如果函数中只是需要主调函数的变量的值 来实现计算 ,就可以采用传值调用。

        如果函数内部要修改主调函数中的变量的值,就需要传址调用。

 实例:

e.g.2

        当我们想要解决生活中的问题的时候,我们会编写一个程序,但是为了程序的可读性与整洁型,我们往往建立函数,为函数传递参数:

        其实不仅是解决数学问题,我们自己的一些行为也是函数的传值调用的过程!

        打一个有趣的比方:

        当你拿到数学试题,你不就是一个  “函数”  吗?你从试卷上接受信息,你写下的演算过程,甚至包括你得出的最终答案,不都是根据试卷(实参)的值,来把形参的最终值(形参)返回给阅卷老师(主调函数)吗?

e.g.3

当我们实现对数组的传参的时候,我们的需求大致有两种情况:

        1.不改变数组的值,完成函数的调用;

        2.在完成函数调用的同时,改变数组的值;

但是相信你已经知道,数组传参是传址的。

        在这种情况下,有什么技巧呢?

        第一种情况:

        例如:求数组的长度并返回长度的值,我们可以用const修饰不想要改变的数组名:


#include<stdio.h>

char* my_strcpy(char* p1, const char* p2)
{
	char* s = p1;
	while (*p1++ = *p2++)
	{
		;
	}
	return s;
}


int main()
{
	char str1[20] = "xxxxxxxxxxxxxx";
	char str2[] = "hello";

	char* p = my_strcpy(str1, str2);

	printf("%s\n", p);


	return 0;
}

         代码分析:这段代码模拟实现strcpy函数;

        while语句是一种非常巧妙地写法,一个语句就实现了:

        赋值,自增,判断多个功能。

        (这也正体现了C语言的紧凑严密的风格)


 

        第二种情况:

        也就是正常的得到数组的地址并进行操作的,例如:

        对一个数组进行操作,改变它的元素的值:

        

void initBoard(char Board[ROWS][COLS], int rows, int cols, char set)
{
	for (int i = 0; i < rows; i++)
	{
		for (int j = 0; j < cols; j++)
		{
			Board[i][j] = set;
		}
	}
}

         代码分析:这段代码对二维数组进行初始化,比较容易理解。


传值的优缺点:

优点:

        1.防止意外修改数据,传值的方式可以确保调用者和被调用者使用的是不同的内存空间。

缺点:

        1.内存开销大:传值需要将整个实参的值复制到形参中

        2.效率较低:

        3.无法修改实参

传址的优缺点: 

优点:

        1.函数调用时传递的是地址,节省了内存空间;

        2.可以使函数修改调用它的上下文中的变量的值,更加方便;

缺点:

        1.在函数内部修改变量的值可能会产生想不到的结果,因此使用传址需要谨慎处理;

        (可以定义常变量,常量来避免)

       



未经作者同意禁止转载

  • 10
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

水墨不写bug

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值