小议指向指针的指针

       指针变量本身与其它变量一样也是在某个内存地址中的,我们也可能让某个指针指向这个地址。

     下面提供2个来自于网络的案例分析。

     案例一:

下是经典程序(载自林锐的从c\c++高质量编程)
void GetMemory(char *p,int num)
{
      p=(char*)malloc(sizeof(char)*num);       //p是形参指向的地址。
}
void main()
{
     char *str=NULL;
     GetMemory(str,100);                            //str是实参指向的地址,不能通过调用函数来申请内存
     strcpy(str,"hello");
}
      结果是编译能通过,却不能运行,为什么呢?
      先说一下指针作为函数参数的意义:当将指针作为参数时,实参向形参传递的是地址,在函数执行过程中,既可以对该参数指针进行处理,也可以对该参数指针所指向的数据进行处理,(以上程序段来说就是可以对p或*p进行处理)。由于此时形参和实参都是指向同一个存储单元,因此当形参指针所指向的数据改变时,实参指针所指向的数据也作相应的改变,因此这时的形参可以作为输出参数使用。
       按照上面的说法,这个程序应该没有问题的啊,实参str和形参p指向同一个存储单元,给形参分配的内存单元应该也给实参分配了才对啊,问题就是在这里。
       实参和形参是指向同一个地址,它们只是指向相同,但它们自身的地址不是同时申请的,就是说p在申请内存时,str并不可以通过调用Getmemory同时申请内存,所以尽管str调用了GetMemory,但它仍然是个空指针,所以进行strcpy是就不能运行。
      要使程序可以运行,只要小小的改动就行了(用指向指针的指针):
void GetMemory(char **p,int num)
{
     *p=(char*)malloc(sizeof(char)*num);       //此时*p就变成了是形参本身的地址
}
void main()
{
     char *str=NULL;
     GetMemory(&str,100);                            //&str是实参的地址,所以实参和形参之间就可以直接调用
     strcpy(str,"hello");
     free(str); 
}
    程序就会如你所愿,输出hello了。
     总结:当变量作为函数的参数时,函数内修改的是形参,实参不变化;(swap(int a, int b))
    当指针作为函数的参数时,函数内:若修改指针变量,实参指针指向变量不变。若修改指针指向,实参指针指向的变量变化。(swap(int *a, int *b))
     当二级指针为函数的参数时,函数内,修改一级指针式,实参一级指针变化!

    案例二:


      设计一个函数:void find1(char array[], char search, char * pa) 
   要求:这个函数参数中的数组array是以0值为结束的字符串,要求在字符串array中查找字符是参数search里的字符。如果找到,函数通过第三个参数(pa)返回值为array字符串中第一个找到的字符的地址。如果没找到,则为pa为0。 
   解答:依题意,实现代码如下。 

void find1(char [] array, char search, char * pa) 
{ 
    int i; 
    for (i=0;*(array+i)!=0;i++) 
    { 
       if (*(array+i)==search) 
       { 
         pa=array+i 
         break; 
       } 
       else if (*(array+i)==0) 
       { 
         pa=0; 
         break; 
       } 
    } 
} 

我下面调用这个函数作测试:

void main() 
{ 
   char str[]={“afsdfsdfdf\0”};  //待查找的字符串 
   char a=’d’;   //设置要查找的字符 
   char * p=0;  //如果查找到后指针p将指向字符串中查找到的第一个字符的地址。 
   find1(str,a,p);  //调用函数以实现所要操作。 
   if (0==p ) 
   { 
      printf (“没找到!\n”);//1.如果没找到则输出此句 
   } 
   else 
   { 
      printf(“找到了,p=%d”,p);  //如果找到则输出此句 
   } 
} 

  分析: 
上面代码,你认为会是输出什么呢? 
    运行试试。 
    唉!怎么输出的是:“没有找到!” 
    明明a值为’d’,而str字符串的第四个字符是’d’,应该找得到呀! 
再看函数定义处:void find1(char [] array, char search, char * pa) 
    看调用处:find1(str,a,p); 
    依我在第五篇的分析方法,函数调用时会对每一个参数进行一个隐含的赋值操作。 
整个调用如下: 

 array=str; 
    search=a; 
    pa=p;    //请注意:以上三句是调用时隐含的动作。 
    int i; 
    for (i=0;*(array+i)!=0;i++) 
    { 
       if (*(array+i)==search) 
       { 


         pa=array+i //此处改变的是指针本身,在函数find1()运行结束返回后,并不会保存这种改变;如果改变的是指针所指 的对象(*P),则函数find1()运行结束后会返回这种改变,注意两者的不同。

         break; 
       } 
       else if (*(array+i)==0) 
       { 
         pa=0; 
         break; 
       } 
    } 
哦!参数pa与参数search的传递并没有什么不同,都是值传递嘛(小语:地址传递其实就是地址值传递嘛)!所以对形参变量pa值(当然值是一个地址值)的修改并不会改变实参变量p值,因此p的值并没有改变(即p的指向并没有被改变)。 
(如果还有疑问,再看一看《第五篇:函数参数的传递》了。) 
修正: 
void find2(char [] array, char search, char ** ppa) 
{ 
    int i; 
    for (i=0;*(array+i)!=0;i++) 
    { 
       if (*(array+i)==search) 
       { 
         *ppa=array+i 
         break; 
       } 
       else if (*(array+i)==0) 
       { 
         *ppa=0; 
         break; 
       } 
    } 
} 
主函数的调用处改如下: 
   find2(str,a,&p);  //调用函数以实现所要操作。 
再分析: 
这样调用函数时的整个操作变成如下: 
    array=str; 
    search=a; 
    ppa=&p;    //请注意:以上三句是调用时隐含的动作。 
    int i; 
    for (i=0;*(array+i)!=0;i++) 
    { 
       if (*(array+i)==search) 
       { 
         *ppa=array+i 
         break; 
       } 
       else if (*(array+i)==0) 
       { 
         *ppa=0; 
         break; 
       } 
    } 


 

看明白了吗? 
ppa指向指针p的地址。 
对*ppa的修改就是对p值的修改。 
你自行去调试。 

经过修改后的程序就可以完成所要的功能了。 


总结,在指针做参数传递给函数的时候:只能保留指针指向的对象(*P)改变的值。不能保留指针本身(P)所做得修改。在需要修改指针本身的时候,需使用指向指针的指针作为参数,也便是传值与传址的差别所在。

 

     总结,在指针做参数传递给函数的时候:只能保留指针指向的对象(*P)改变的值。不能保留指针本身(P)所做得修改。在需要修改指针本身的时候,需使用指向指针的指针作为参数,也便是传值与传址的差别所在。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值