主要内容:

1、一级指针和二级指针

2、函数指针传递的例子

3、什么时候需要传递二级指针?

4、二级指针在链表中的使用

1、一级指针和二级指针

一级指针:即我们一般说的指针,就是内存地址;

二级指针:指向指针的指针,就是地址的地址;

如:

int a=1;

int *p=&a;  // p为a变量的地址,通过*p可以得到a的值

int **q=&p;   // q为p指针的地址,通过**q可以得到a的值

2、函数指针传递的例子

程序1:

#include<stdio.h>

void  fun(int  *p){
int b=100;
p=&b;
} int main(){
int a=10;
int *q;
q=&a;
printf("%d\n",*q);
fun(q);
printf("%d\n",*q);
return 0;
}

运行结果:

10

10

程序2:

#include<stdio.h>

void  fun(int  **p){
int b=100;
*p=&b;
} int main(){
int a=10;
int *q;
q=&a;
printf("%d\n",*q);
fun(&q);
printf("%d\n",*q);
return 0;
}

运行结果:

10

100

程序3:

#include<stdio.h>
#include<stdlib.h> void myMalloc(char *s){
s=(char*)malloc(100);
} int main()
{
char *p=NULL;
myMalloc(p);
if(p==NULL)
printf("P is not changed!\n");
else{
printf("P has been changed!\n");
free(p);
}
return 0;
}

运行结果:

P is not changed!

程序4:

#include<stdio.h>
#include<stdlib.h> void myMalloc(char **s){
*s=(char*)malloc(100);
} int main()
{
char *p=NULL;
myMalloc(&p);
if(p==NULL)
printf("P is not changed!\n");
else{
printf("P has been changed!\n");
free(p);
}
return 0;
}

运行结果:

P has been changed!

3、什么时候需要传递二级指针?

通过上述例子,我们可以看到,在某些情况下,函数参数传递一级指针时,在函数体内对指针做变动,也不会对原始指针产生变化,而传递二级指针时,则可以,这是为什么呢?

在传递一级指针时,只有对指针所指向的内存变量做操作才是有效的;

在传递二级指针时,只有对指针的指向做改变才是有效的;

下面做简单的分析:

在函数传递参数时,编译器总会为每个函数参数制作一个副本,即拷贝;

例如:

void fun(int *p),指针参数p的副本为_p,编译器使_p=p,_p和p指向相同的内存空间,如果在函数内修改了_p所指向的内容,就会导致p的内容也做相应的改变;

但如果在函数内_p申请了新的内存空间或者指向其他内存空间,则_p指向了新的内存空间,而p依旧指向原来的内存空间,因此函数返回后p还是原来的p。

这样的话,不但没有实现功能,反而每次都申请新的内存空间,而又得不到释放,因为没有将该内存空间的地址传递出来,容易造成内存泄露。

void fun(int **p),如果函数参数是指针的地址,则可以通过该参数p将新分配或新指向的内存地址传递出来,这样就实现了有效的指针操作。

如果觉得二级指针比较难理解,也可以通过函数返回值的形式来传递动态内存(切记不能返回栈内存),如:

#include<stdio.h>
#include<stdlib.h> char* myMalloc(){
char *s=(char*)malloc(100);
return s;
} int main()
{
char *p=NULL;
p=myMalloc();
if(p==NULL)
printf("P is not changed!\n");
else{
printf("P has been changed\n");
free(p);
}
return 0;
}

知道了上述这些,就不难理解上面四个小程序的执行结果了。

4、二级指针在链表中的使用

在链表或者树的操作中,也需要用到二级指针,

比如创建链表的头指针:

在初始化链表函数中,传入头指针,并在函数中为该指针分配空间,此时就应该使用二级指针,如void initLinklist(Node **head);

而在添加删除结点的过程中,我们并没有改变函数参数指针的指向,而是通过传入的指针如Node *head,找到要删除结点的位置,并未对该指针做改变,因此退出函数后,该指针无影响。

最新文章

  1. .net 下新版highcharts本地导出图片bug处理
  2. sscanf提取字符串中的数据php
  3. 搭建企业内部yum仓库(centos6+centos7+epel源)
  4. discuz 二次开发
  5. VS2013_QT255开发相关技巧理解心得
  6. VC与JavaScript交互(三) --- CWebPage类调用javascript函数(给js函数传参,并取得返回值)
  7. Ubuntu下配置samba服务器实现文件共享
  8. 基础:c++中引用与java中的引用
  9. mysql update from 子查询
  10. 在同个类中non-const插入const来减少重复
  11. tomcat oracle 连接池配置
  12. Android 高级控件(七)——RecyclerView的方方面面
  13. Python 扫盲
  14. windows下局域网文件共享,不需要登录账号密码
  15. Centos6.8安装redis(一)
  16. 主机-配件-接口-整机-3c-2
  17. URL分发(URLConf)
  18. linux系统部署Java程序获取ip时报Caused by: java.net.UnknownHostException: XXXXXXXXXX: XXXXXXXXXX: Name or service not known
  19. thinkPHP5 引入模板
  20. 锐浪报表 导出 PDF ANSI码 乱码 问题解决

热门文章

  1. 初识GeneXus产品
  2. js基本数据类型 BigInt 和 Number 的区别
  3. braft初探
  4. 执行Shell脚本的4种方法及区别介绍(转)
  5. hdu 1069 动规 Monkey and Banana
  6. PHP定义字符串
  7. android 捕获所有异常 未捕获的异常
  8. bzoj 3757 树上莫队
  9. asp.net调用存储过程2
  10. CentOS6永久修改主机名称