关于“指针的指针”的认识(值传递、指针传递区分)

【摘要】对于C语言的参数传递通常都是值传递,当传传递一个指针给函数的时,其实质上还是值传递。我们可以看以下常见的面试题:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void function1(int *v)
{
	 v = (int *)malloc(sizeof(int));
	 *v = 100;
}

void main()
{
	 int *v = NULL;
	 function1(v);
	 printf("%d\n",*v);
}

分析:指针其实本质就是一个变量,存放的是地址,不过也是一个值罢了,只不过特殊一点。本段函数的被调函数就把这个值(也就是地址)拷贝了下来。被调函数执行了 v = (int *)malloc(sizeof(int)); 之后,这样一条语句主动申请一块内存,并把这块内存的地址返回给v ,悄然把地址修改啦。这时主函数和被调函数中的指针指向的东西没有半毛关系了,主函数中v还是NULL,所以……

1、指针传递与值传递

我们再来看以一个交换2个数的值的函数调用的代码:

void swap ( int *a, int *b ){
    int c;
    c = *a;
    *a = *b;
    *b = c;
}
int main(int argc, char **argv){
    int a,b;
    a = 16;
    b = 32;
    swap( &a, &b);
    return ( a - b );
}

分析:能够正常交换a,b的值,被调函数操作的*a变量解引用一下,其实它的地址和主调函数a是一样的。因此它们操作是在同一块内存区域,可以实现数值的交换。

下面贴出一个错误的代码:

void swap ( int *a, int *b ){
    int *temp;
    temp = NULL;
    temp = a;
    a = b;
    b = temp; 
}
int main ( int argc, char **argv ){
    int a,b;
    a = 16;
    b = 32;
    swap(&a, &b);
    return ( a - b );
}

分析:这种方式按照理论上来说,是想通过调用swap函数,在swap函数内部,实现将交换&a,&b,即交换a和b的地址来达到目的。但是被调函数只是对a,b的地址进行拷贝,简单一点说其实就相当于值传递,即使被调函数再一次对a,b地址进行修改,对主调函数实参a,b地址是没有任何影响的。所以根本没有起到值交换目的的。所以上述代码是错误的,无法实现你想要的功能。

2、指针的指针

当我们用二级指针来实现上述功能的时候有就可以达到效果。

#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

void swap ( int **a, int **b ){
    int *tmp = NULL;
    tmp = *a;
    *a = *b;
    *b = tmp;
}

int main ( int argc, char **argv ){ 
 
	int x = 16; 
	int y = 32; 
	int *a = &x;
	int *b = &y;

	swap(&a, &b); 

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

	return 0; 

} 

分析:这个时候,你会发现就能实现达到交换的目的。我们通过操作中间桥梁(一级指针 *a)通过交换它们的值,实现数值交换。

3、指针的指针常见用途

双指针主要用在但我们想向一个A函数传递参数的时候,但是我们希望在A内部对参数做任何修改都能保存起来,那么就是用双指针吧。

举个例子;
我们在做链表的时候,我们肯定希望在用一个函数creatLink(…)函数来增加链表节点。那么我们可以有2种方法来实现
第一种,用一级指针

typedef struct node{
    ...
    ...
}list;
node *create(list *l){
   list *head;
   head = l;
   malloc...//为节点申请内存空间
   ...
   ...
   //操作
   return head;
}
int main(...){
    ...
    ...
    list *listhead
    createList(listhead);
    ....
    //以后的任何操作,我们都要考虑,我们是否拿到的是链表头指针,到底哪
    是链表波的头指针,我们是否要return下来返回链表头指针??
}

分析:这样做可以达到增加节点的目的,但是,在任何情况下,我们的操作都得死死地抓住头指针,也即是我们增加节点后,任何对链表长度的修改,**我们都要 链表头指针返回,即 return head;**所以,我们要通过这个函数最后获得头指针,抓住他,死死地抓住他,然后操作。

第二种方法:用双指针,也即是二级指针。

typedef struct node{
    ...
    ...
}list;
void create(list **l){
   list *head;
   head = l;
   malloc...//为节点申请内存空间
   ...
   ...
   //操作   
}

int main(...){
    ...
    ...
    list *st
    createList(st)
    ....
    ..
//以后的任何操作,不管是删除还是插入,我们不需要考虑,我们是否已经return head了,不需要,我们在任何情况下,对链表的操作都只需要使用st来完成,因为,st就是链表的头指针,不变,因为在申明st的时候,已经为st分配 一个地址空间,它是存在的,一直存在,直到main函数结束
}

这里有关于指针的指针两篇不错的博客,推荐给大家
深入理解双指针的两种用法
重新认识二级指针(Pointers to Pointers)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

狂奔的乌龟

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

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

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

打赏作者

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

抵扣说明:

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

余额充值