值传递与地址传递的区别

以下内容源于网络资源的学习与整理,欢迎交流。

总结

值传递,只是把原参的复制品传给形参,在子函数中修改这个形参,不会改变主函数中的原参。

地址传递,由于形参和原参表示同一个内容,在子函数中修改形参,也会改变主函数中的原参。

代码示例1

#include<stdio.h>

void F1(int *pp)
{
	pp++;
	*pp = 9;
}

void F2(int **pp)
{
	(*pp)++;
}

int* F3(int *pp)
{
	pp++;
	return pp;
}
//以上函数中,接收数据的参量都是pp,而不会是*pp或者**pp

int main(void)
{
	int *p;
	int a[2] = { 4,5 };
	p = a;
	printf("1--------%d\n", *p);//开始值为4

	F1(p);
	printf("2--------%d\n", *p);//4
	//由于只是传值,在子函数F1的内部改变复制品的值,并不会改变原品p的值
	//可以理解为用两个变量指向同一个地址,即形参pp和实参p指向同一个地址
	//其中形参pp++,另外一个实参p并不会受影响
	//但是可以修改指针所指的值,如F1代码中将a[1]的值改为9;
    //经过F1(p)函数后,p依然指向指向a[0],但原来的a[1]=5被修改成a[1]=9
	printf("2`-------%d\n", a[1]);//9


	F2(&p);
	printf("3--------%d\n", *p);//9
	//传址,pp=&p(指针的地址,即pp是指向指针的指针),pp=&p,则*pp=*(&p)=p;
	//如果要修改指针p,则应该传入指针p的地址(&p),\
    //此时进行(*pp)++操作,其实是对实参指针p进行操作

	getchar(); getchar();
	return 0;
}

代码示例2 

#include <stdio.h> 
#include <stdlib.h> 
#include<string.h>
/*void getmemory(char **p)
{
	*p = (char *)malloc(100);
	strcpy(*p, "helloworld");
}

int main()
{
	char* str = NULL;
	getmemory(&str);
	printf("%s", str);
	free(str);
	getchar();
	return 0;
}*/


char* getmemory(char *p)
{
	p = (char *)malloc(100);
	strcpy(p, "helloworld");
	return p;
}
int main()
{
	char* str = NULL;
	str = getmemory(str);
	printf("%s", str);
	free(str);
	getchar();
	return 0;
}

分析说明

如果要在子函数中修改主函数传过来的指针的指向,那么主函数应该向子函数传入指针的地址(而非指针本身);此时在子函数中进行*操作后可以获得原来指针,而不是原来指针的复制品,之后可以根据需要修改指针。

或者,将返回值类型改为指针类型,然后返回修改后的指针,给原来主函数的指针。比如代码示例1中的F3函数,此时在主函数中需要添加p=F3(p)代码;又比如代码示例2。

C语言中,有两种主要的方式将变量值传送给函数,分别是值传递(也称为值拷贝)和地址传递(也称为引用)。这两种方法各有特点,适用于不同情况。 ### 值传递 (Pass by Value) 当你使用值传递时,实际上只是在函数内部创建了一个本地变量的副本,该副本与原始变量在内存中的位置无关。换句话说,如果函数试图更改这个参数的值,这些变化不会影响原来的变量。值传递主要用于小型简单类型的数据,如整型、浮点型、字符型和指针常量等。 **优点**: - 简单易懂,无需担心数据副作用。 - 可以减少数据安全性问题的风险,特别是当涉及到敏感信息或隐私保护需求时。 **缺点**: - 使用大量计算资源,尤其是在处理大型数据类型时,每次调用都会产生额外的内存分配和复制开销。 ### 地址传递 (Pass by Address / Pass by Reference) 地址传递允许你在函数中直接操作原始变量的存储位置,即使用的是参数的真实内存地址,而非复制一份其值。这样做的结果是,如果函数内部对参数值进行修改,则会直接影响到原始变量。这种传递方式更适合于结构体、数组和其他大型数据类型,以及需要动态数据管理的情况。 **优点**: - 更高效地管理和使用大型数据结构,减少了不必要的复制。 - 允许更自然地编写算法和函数,比如排序、搜索或更新数组等操作。 **缺点**: - 存在潜在的安全性和一致性问题,如数据的竞争条件。 - 开发人员需要更加小心,以防止无意间破坏其他部分的代码状态。 ### 实践示例 考虑下面的例子,演示值传递地址传递区别: ```c #include <stdio.h> // 值传递示例 void incrementValue(int value) { value++; } // 地址传递示例 void modifyAddress(int *valuePtr) { *valuePtr++; // 注意这里的语法差异,这等价于(*valuePtr)++; } int main() { int a = 10; printf("Before modification with value pass: %d\n", a); incrementValue(a); printf("After modification with value pass: %d\n", a); // 显示10,因为a未变 int b = 10; printf("Before modification with address pass: %d\n", b); modifyAddress(&b); printf("After modification with address pass: %d\n", b); // 显示11,因为b已变 return 0; } ``` 在这段代码中,`incrementValue` 和 `modifyAddress` 分别使用了值传递地址传递。你可以观察到两者之间结果的不同,从而理解两者的区别和应用场景。 ### 相关问题: 1. **如何确定何时使用值传递还是地址传递?** 主要考虑数据的规模和是否需要对数据进行原位修改。小规模数据适合值传递,以保证安全性;大规模数据或需要修改时则应选择地址传递,提高性能。 2. **如何解决地址传递带来的安全性和一致性问题?** 通过使用诸如互斥锁或原子操作等同步技术,可以在并行环境中确保数据的一致性和防止意外的数据损坏。 3. **在哪些场景中,值传递优于地址传递?** 涉及数据安全性高、数据不可变或需要频繁复制的场景,使用值传递更为合适。例如,处理敏感用户数据时就需要谨慎选择传递方式。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

天糊土

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

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

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

打赏作者

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

抵扣说明:

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

余额充值