用指针传递参数

   交换a,b的值:

#include<stdio.h>

void Swap(int a, int b)
{
	int tmp = a;
	a = b;
	b = tmp;
        //a=a+b;
        //b=a-b;
        //a=a-b;
}

int main()
{
	int a = 10;
	int b = 20;
	printf("%d %d\n", a, b);
	Swap(10, 20);
	printf("%d %d\n", a, b);

	return 0;
}

上述代码并未交换a,b的值,因为 Swap函数中的a,b都是局部变量, 他们的修改并未修改主函数中的a,b的值;

为了解决在Swap函数中修改主函数中的参数,我们引入指针变量:

void Swap2(int *p1, int *p2)
{
        //p1->a,p2->b
	int tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}

int main()
{
	int a = 10;
	int b = 20;
	printf("%d %d\n", a, b);
	Swap2(&a, &b);
	printf("%d %d\n", a, b);

	return 0;
}

看看错误使用指针:

void Swap2(int *p1, int *p2)
{
	//p1->a,p2->b

	//1.未对指针解引用
	//int tmp = p1;
	//p1 = p2;
	//p2 = tmp;

	//2.定义了野指针tmp;我们没有 权限 改写 tmp指针所指向的值
	//int *tmp;
	//*tmp= *p1;
	//*p1 = *p2;
	//*p2 = *tmp;

	//3.正确使用指针
    int tmp = *p1;
	*p1 = *p2;
	*p2 = tmp;
}

                                                            。。。。。。。。。。。。。

                                                            。。。。。。。。。。。。。

注:

    1.子函数的改变能影响到父函数,一定要使用指针和解引用,两者缺一不可;

    2.NULL 空指针 唯一一个标识当前指针是一个无效指针;

    3.数组名arr表示整个数组,只在如下两种情况

       (1).在定义数组的函数中,求sizeof

       (2).在定义数组的函数中,&arr+1

       其他情况下数组名都表示数组首元素的地址;

                        * *关于在函数中修改指针**

#include <stdio.h>

void Fun1(int *p)
{
	p = NULL;
}

void Fun2(int **p)
{
	*p = NULL;
}

int main()
{
	int a = 10;
	int *p = &a;

	//p = NULL;
	//printf("%d\n", *p);
	//输出空指针指向的值使得程序崩溃

	//调用一个函数 希望程序也崩溃,如Fun1(),
	//  Fun1(p);
	//  printf("%d\n", *p);
	//但调用Fun1()并未达到预期。
	//  1、为什么不崩溃,2、如何改

	//  答:原因是要在函数中修改一个指针的值,要给函数传递指针的指针
	//修改如下:
	Fun2(&p);
	printf("%d\n", *p);
	
	return 0;
}

 

<think>我们正在讨论指针作为函数参数传递的原理和使用方法。根据引用内容,我们可以总结出以下几点关键信息: 1. **值传递的本质**:所有函数参数传递在C/C++中都是值传递(passby value)。这意味着当指针作为参数传递时,传递的是指针变量存储的地址值的一个副本,而不是原始指针变量本身(引用[2]和[4])。2.**通过指针修改数据**:虽然传递的是指针的副本,但副本和原始指针指向同一个内存地址。因此,通过解引用操作(如`*p`)可以修改该内存地址存储的数据,从而影响函数外部的变量(引用[1]和[4])。 3. **不能修改原始指针本身**:由于函数内部得到的是指针副本,所以在函数内部修改指针副本的值(即改变指针指向的地址)不会影响函数外部的原始指针(引用[4]中的例子)。4.**需要修改指针本身的情况**:如果需要在函数内部修改指针本身(例如,为指针分配新的内存并改变其指向),则需要传递指针指针(即二级指针`**`)或者使用指针的引用(在C++中)(引用[3])。 5. **返回指针**:另一种动态分配内存并返回指针的方法是使用函数返回值(引用[3])。但要注意不要返回指向栈内存的指针,因为函数结束后栈内存会被释放。 接下来,我将逐步解释指针参数传递的原理,并给出使用示例。###指针参数传递的原理在C/C++中,函数参数传递机制是值传递。这意味着:-当传递一个变量时,函数会获得该变量的一个副本。-对于指针变量,传递的是指针的值(即一个内存地址),而不是指针变量本身。因此,在函数内部:-我们可以通过这个地址访问和修改该地址所指向的数据(因为原始数据和副本指向同一块内存)。 -但是,如果我们在函数内部改变了指针副本的值(即让它指向另一个地址),这个改变不会影响到函数外部的原始指针,因为改变的是副本。 ###使用示例####示例1:通过指针修改数据```c#include<stdio.h>void modifyValue(int*p) {*p =100; //修改指针所指向的内存的值} intmain(){int num=10;int*ptr= &num;printf("Before: %d\n", num); //输出10modifyValue(ptr);printf("After: %d\n", num);//输出100return0;} ```在这个例子中,我们传递指针`ptr`(它存储了`num`的地址)给函数`modifyValue`。函数内部通过解引用修改了`num`的值。####示例2:试图修改指针本身(失败)```c#include<stdio.h>void changePointer(int*p) {intnewValue =200;p =&newValue;//改变指针副本的指向,但函数结束后newValue的内存不再有效} intmain(){int num=10;int*ptr= &num;printf("Before: %d\n", *ptr);//输出10changePointer(ptr);printf("After:%d\n",*ptr);//输出10,指针ptr没有改变return0; }``` 注意:在`changePointer`函数中,我们将指针副本指向了局部变量`newValue`,但函数结束后`newValue`的内存被释放,而且`ptr`并没有改变。 ####示例3:通过二级指针修改指针本身```c#include <stdio.h> #include<stdlib.h>void allocateMemory(int**p) {*p =(int*)malloc(sizeof(int)); //通过二级指针分配内存,修改一级指针的指向**p=100;//设置分配的内存的值}int main() {int*ptr= NULL;allocateMemory(&ptr); //传递ptr的地址if (ptr !=NULL){printf("Value:%d\n",*ptr); //输出100free(ptr);}return0; }``` 这里,我们传递指针`ptr`的地址(即二级指针)给函数`allocateMemory`,这样函数内部就可以修改`ptr`本身,使其指向新分配的内存。 ###总结-使用指针作为函数参数,可以实现对指针所指向数据的修改。 -如果需要修改指针本身(如动态分配内存后改变指针指向),则需要传递指针指针(二级指针)或使用指针的引用(C++中为`int*&`)。-注意避免返回指向局部变量的指针,因为局部变量在函数结束后会被销毁。 §§相关问题§§1.指针传递和引用传递在C++中有什么区别? 2.为什么在C语言中传递指针可以修改数据,而传递普通变量不能? 3.如何避免在使用指针参数时出现内存泄漏?4.在C++中,除了使用二级指针,还有哪些方法可以在函数内部分配内存并改变指针的指向?</think>### 指针参数传递的原理及使用方法 #### 一、基本原理 1. **值传递的本质** 所有函数参数传递(包括指针)都是值传递(pass by value)。当传递指针时,实际传递的是指针变量存储的**地址值的副本**,而非原始指针本身[^2][^4]。 $$ \text{函数调用}:f(p) \Rightarrow \text{系统复制} p \text{的值到新内存} $$ 2. **内存访问机制** - 形参指针和实参指针指向**同一内存地址** - 通过解引用操作(`*p`)可直接修改原始数据 - 修改形参指针的**指向**(地址值)不影响实参指针[^4] #### 二、关键特性 | 操作类型 | 是否影响实参 | 原因说明 | |----------------|-------------|----------------------------| | 修改 `*p` 的值 | ✅ | 直接操作原始内存 | | 修改 `p` 的指向 | ❌ | 仅改变副本的地址值 | #### 三、使用场景与示例 1. **修改目标数据(推荐)** ```c void swap(int *a, int *b) { int temp = *a; // 通过解引用修改原始数据 *a = *b; *b = temp; } ``` **调用方式**:`swap(&x, &y)` ✅ 直接修改原始变量值 2. **动态内存分配(需二级指针)** ```c void alloc(int **p) { *p = malloc(sizeof(int)); // 通过二级指针修改一级指针的指向 **p = 100; } ``` **调用方式**:`int *ptr; alloc(&ptr);` ✅ 使`ptr`指向新内存 3. **错误示范(无效修改)** ```c void wrong_alloc(int *p) { p = malloc(sizeof(int)); // 仅修改副本的指向 } // 调用后实参ptr仍为NULL ``` #### 四、核心原则总结 1. **数据修改**:通过 `*p` 操作可修改原始数据 2. **指针重定向**:需传递指针的地址(二级指针) 3. **const保护**:用 `const int *p` 防止意外修改数据[^2] 4. **内存安全**:动态分配的内存需手动释放,避免泄漏 ### 常见问题解答 **Q:为何指针传递能修改数据?** A:因形参与实参指向相同内存地址,解引用操作直接操作原始内存[^4]。 **Q:何时需要二级指针?** A:当需要在函数内改变指针本身的指向时(如动态内存分配)[^3]。 **Q:值传递指针传递矛盾吗?** A:不矛盾,指针传递本质仍是值传递传递地址值副本)[^2]。 > 示例验证:引用[4]中代码显示,函数内修改 `*p` 影响实参,但修改 `p` 的指向仅影响副本。
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值