用交换函数来理解指针

写一个函数,交换a和b的值
#include<stdio.h>
void swap1(int a,int b)
{
 int tmp=a;
 a=b;
 b=tmp;
}

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

  return 0;
}

如果调用这个函数,会交换值吗?


值并没有改变,为什么呢?
因为我们只是在交换函数内部改变了a和b的值,一旦这个函数调用结束,函数内部的变量也就销毁了,并不会传到主函数中,这就是我们经常说的值传递。相当于只是拷贝了一个副本放在交换函数中,但是这个副本的改变不会影响主函数中的值。主函数和交换函数中的a,b并不是相同的变量。所以交换函数a和b的变化并不会影响到主函数中的a和b。
如果想看是不是相同的变量,只需要看他们的地址是不是相同的,地址相同才是相同的变量。

void swap2(int *a,int *b)
{
 int *tmp;
 tmp=a;
 a=b;
 b=tmp;
}
既然值传递不能进行交换,那我们传递地址呢?
调用swap2函数来试一下

调用了swap2函数,还是没有改变它们的值,又是为什么呢?
因为当我们把a,b的地址传进去的时候,指针变量*a,*b 就保存了主函数a,b的地址,但是我们赋值的时候,实质上我们只是把地址互相交换了,只是改变了原来指针的指向,并不会改变a,b里面存放的值。想要改变里面的值,要对指针变量解引用,才能修改指针变量所指的地址里面的值。

void swap3(int *a,int *b)
{
 int *tmp;
 *tmp=*a;
 *a=*b;
 *b=*tmp;
}
既然没有解引用,发生了错误,那我们就解引用,看看是不是正确的
调用swap3函数,看一下是不是正确的
当我们调用这个函数的时候,不仅没有出现交换,程序还直接崩溃了,这是为什么呢?
这里要引入一个新的概念:野指针。野指针又称悬挂指针,是没有指向有效地址的指针,或者说没有访问权限的地址。
当我们定义tmp的时候,并没有初始化,所以它是一个野指针,可能随机指向了某一个地址,当我们将a解引用赋值给tmp解引用的时候,是导致系统崩溃的原因。a解引用以后是20,但是tmp由于没有初始化,它指向的地址空间并不允许它访问或者修改里面存放的值。因为没有访问权限,所以系统直接崩溃了。
但是野指针编译器不能预防,因为可能那个地址就是实际存在的。例如: int *tmp=(int *)10000;  *tmp=100; 这里编译不会有错,因为这个地址就是实际存在的,但是运行的时候会崩溃,因为这个地址10000你是没有访问权限的。所以野指针防不胜防,我们使用的时候要避免使用野指针,可以加一个断言,防止野指针。

void swap(int *a,int *b)
{
 int tmp;
 tmp=*a;
 *a=*b;
 *b=tmp;
}
去掉野指针以后能不能交换值呢?调用swap函数试一试

终于将值交换了,这个程序为什么成功了呢?
首先定义两个指针变量是没有错误的,我们想要通过指针变量去改变值,必须要解引用,当我们把a解引用时,其实就是将a指向的地址的值取出来,赋给了变量tmp;然后*a=*b 这一句就是将b指向的内存单元的值拿出来,放到a指向的内存单元。*b=tmp就是将tmp保存的变量拿出来放到b所指向的内存单元中,即a内存单元的值保存到了b内存单元,通过这个过程就可以将a,b的值进行交换了。

int main()
{
 int a=10;
 int b=20;
 printf("%d,%d\n",a,b);
 //swap1(a,b);
 //swap2(a,b);
 //swap3(&a,&b);
 swap(&a,&b);
 printf("%d,%d\n",a,b);
 return 0;
}

通过以上的测试,可以看出:
父函数调用子函数,子函数能修改父函数中的内容,或者子函数的改变能够影响父函数,需要两个条件:
1.传指针   
2.解引用
但是有这两个条件也不一定改变值,可能会有野指针出现,要预防野指针。必要非充分条件

  • 7
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
好的,下面我来举三个例子帮助理解指针。 1. 指针作为函数参数传递 指针最常见的用法之一是作为函数参数传递。这种用法可以实现对函数外部变量的修改,比如: ```c++ #include<iostream> using namespace std; void swap(int* a, int* b) { int temp = *a; *a = *b; *b = temp; } int main() { int a = 1, b = 2; cout << "before swap: a = " << a << ", b = " << b << endl; swap(&a, &b); cout << "after swap: a = " << a << ", b = " << b << endl; return 0; } ``` 在这个例子中,我们定义了一个`swap()`函数,它接受两个指向整型变量的指针作为参数。函数内部通过指针操作来交换变量的值,从而实现了对函数外部变量的修改。 2. 指针作为数组名 指针还可以被用来表示数组名。当我们定义一个数组时,实际上是在内存中开辟了一段连续的空间,并将数组名指向这段空间的首地址。因此,我们可以通过指针对数组进行访问,比如: ```c++ #include<iostream> using namespace std; int main() { int arr[5] = {1, 2, 3, 4, 5}; int* p = arr; // 指针指向数组首地址 for(int i=0; i<5; i++) { cout << *(p+i) << " "; // 输出数组元素 } return 0; } ``` 在这个例子中,我们定义了一个包含5个元素的整型数组`arr`,并将指针`p`指向了数组的首地址。然后我们使用指针对数组进行访问,输出了数组中的所有元素。 3. 动态内存分配 指针还可以用于动态内存分配。动态内存分配是指程序在运行时根据需要申请一定大小的内存空间,以供程序使用。在C++中,可以使用`new`操作符来实现动态内存分配,比如: ```c++ #include<iostream> using namespace std; int main() { int* p = new int; // 动态申请一个整型变量的内存空间 *p = 1; // 对动态申请的内存空间进行赋值 cout << *p << endl; // 输出动态申请的内存空间的值 delete p; // 释放动态申请的内存空间 return 0; } ``` 在这个例子中,我们使用`new`操作符动态申请了一个整型变量的内存空间,并将其赋值为1。然后我们输出了这个内存空间的值,并使用`delete`操作符释放了这个内存空间。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值