zoukankan      html  css  js  c++  java
  • C语言----指针形参(指向指针的指针形参)

    一、通过指针形参在子函数改变常量

    大家都知道,C语言子函数的形参,是可以为普通数据类型,也可以为指针的。最初遇到这问题,是在学习STM32的库函数的使用。当初刚接触库函数,对于函数初始化接口,如:

    GPIO_Init(GPIOA, &GPIO_InitStructure);
    为什么要取初始化结构体变量的地址传递进库函数(&GPIO_InitStructure),而不是直接将结构体变量本身(GPIO_InitStructure)传递进去,不甚了解。直到后来,程序中指针用得多了才有所理解,在这里做个记录。先上代码:

    #include <stdio.h>
    void AddNum1(int data)
    {
      data++;
    }
    void AddNum2(int *data)
    {
      (*data)++; //自增运算符“++”优先级高于取值符“*”
      printf("AddNum2()运行结果: *data = %d ", *data);
      printf(" data = 0x%08X ", data);
      printf("&data = 0x%08X ", &data);
    }
    int main(void)
    {
      int Num1 = 1;
      //测试AddNum1
      AddNum1(Num1);
      printf("AddNum1()运行结果: Num1 = %d ", Num1);
      Num1 = 1;
      printf(" ");
      //测试AddNum2
      AddNum2(&Num1);
      printf(" Num1 = %d ", Num1);
      printf("&Num1 = 0x%08X ", &Num1);
      getchar();
    }

    运行结果如图:

    编译环境为VS2015。

    可知,AddNum1没有改变Num1的值,而AddNum2将Num1的值自增了1。分析:

    (1)对于子函数形参的理解:

            主函数中的代码“AddNum1(Num1);”。实质上,它将Num1的值赋值给了子函数的形参“data”。

            可将“AddNum1(Num1);”代码理解为运行了以下代码:

    void AddNum1()
    {
      int data = Num1;
      data++;
    }

    通俗的解释就是,子函数声明了一个整型常量“data”,用“data”缓存“Num1”的值。函数中的其他代码,是针对“data”进行运算的,而“Num1” 除了把它自身的值传递给“data”外没有其他任何操作。所以,“AddNum1();” 这个函数并有没改变“Num1”的值。

    (2)指针形参的作用:

            我们在对常量,或者是指针进行操作的时候,实质上是对其对应的内存进行操作。对“AddNum2(&Num1);”运行结果以 内存分布图诠释如下:

    1、可知,Num1的地址是0x00600FFA0C,”AddNum2(int *data)“;声明了一个指针data,并且将Num1的地址赋值给了指  针 data,相当于执行了”data = 0x00600FFA0C;“,此时”*data“ 等同于”Num1“。

    2、接下来的”(*data)++;“,操作的是指针data指向的内存”0x00600FFA0C“,这行代码使这个内存块上存储的常量自    增了1,所以”*data = 2“。由1可知,”*data“ 等同于 ”Num1“,所以“*data = 2 = Num1”。

     总结:通过将变量地址传递进子函数,在子函数内操作该地址的内存上存储的数据可达到改变变量的目的。

    二、通过指向指针的指针在子函数改变指针的值

    这种情况我用得比较少。不过在调用内存管理函数的时候可能会用到。如下代码:

    主函数声明了一个指向0x00000001地址的char型指针pMemory,并通过子函数申请内存,将申请得到的地址赋值给pMemory

    #include <stdio.h>
    #include <stdlib.h>
    void GetMemory1(char *pAddr)
    {
      pAddr = (char *)malloc(sizeof(char) * 100);
    }
    void GetMemory2(char **pAddr)
    {
      *pAddr = (char *)malloc(sizeof(char) * 100);
      printf(" *pAddr = 0x%08x ", *pAddr);
      printf(" pAddr = 0x%08x ", pAddr);
      printf(" &pAddr = 0x%08x ", &pAddr);
    }

    int main(void)
    {
      char *pMemory = 0x00000001;
      printf(" pMemory = 0x%08x ", pMemory);
      printf("&pMemory = 0x%08x ", &pMemory);
      GetMemory1(pMemory);

      printf("/*******GetMemory1();********/ ");
      printf(" pMemory = 0x%08x ", pMemory);
      printf("&pMemory = 0x%08x ", &pMemory);

      printf("/*******GetMemory2();********/ ");
      GetMemory2(&pMemory);
      printf(" pMemory = 0x%08x ", pMemory);
      printf("&pMemory = 0x%08x ", &pMemory);


      getchar();
    }
    运行结果:

     

    如上,GetMemory1();并不能将地址赋值给pMemory,而GetMemory2();成功将申请得到的地址赋值给pMemory。分析:

    (1)GetMemory1();

            类似于“AddNum1();”,声明了一个指针pAddr,然后将pMemory的值赋值给pAddr。后续代码改变的是pAddr的数据 而没有改变pMemory。所以没有成功地将申请得到的地址赋值给pMemory。

    (2)GetMemory2();

            先上图:

     

      进入函数后,pMemory的地址0x008FF718赋值给了pAddr。malloc();申请得到的内存空间的地址0x02BB4D80赋值给了pAddr所指向的内存“*pAddr”(0x008FF718)。又因为*pAddr = pMemory; ,所以申请得到的内存地址成功赋值给了pMemory。

      综上所述,当数据被传递进子函数,如需通过子函数改变数据的值,需将它的地址作为形参传递进函数(无论常量亦或是指针)。

  • 相关阅读:
    linux ——process
    linux ipc—msgqueue
    JDEclipse源码查看
    用 AXIOM 促进 XML 处理
    使jets3t支持https
    正版太贵了……
    Axis2学习笔记 (Axiom 篇 )
    基于Hadoop的海量文本处理系统介绍
    详解ASP.NET MVC的请求生命周期
    .Net相关的资源连接
  • 原文地址:https://www.cnblogs.com/fengliu-/p/14924317.html
Copyright © 2011-2022 走看看