原创 深入了解指向指针的指针

2008-1-20 10:23 4028 6 7 分类: MCU/ 嵌入式

编程的时候,看到下面的一个函数:


eMBErrorCode
eMBASCIIReceive( UCHAR * pucRcvAddress, UCHAR ** pucFrame, USHORT * pusLength )
{
    eMBErrorCode    eStatus = MB_ENOERR;


    ENTER_CRITICAL_SECTION(  );
    assert( usRcvBufferPos < MB_SER_PDU_SIZE_MAX );
    
    /* Length and CRC check */
    if( ( usRcvBufferPos >= MB_SER_PDU_SIZE_MIN )
        && ( prvucMBLRC( ( UCHAR * ) ucASCIIBuf, usRcvBufferPos ) == 0 ) )
    {
        /* Save the address field. All frames are passed to the upper layed
         * and the decision if a frame is used is done there.
         */
        *pucRcvAddress = ucASCIIBuf[MB_SER_PDU_ADDR_OFF];


        /* Total length of Modbus-PDU is Modbus-Serial-Line-PDU minus
         * size of address field and CRC checksum.
         */
        *pusLength = ( USHORT )( usRcvBufferPos - MB_SER_PDU_PDU_OFF - MB_SER_PDU_SIZE_LRC );


        /* Return the start of the Modbus PDU to the caller. */
        *pucFrame = ( UCHAR * ) & ucASCIIBuf[MB_SER_PDU_PDU_OFF];
    }
    else
    {
        eStatus = MB_EIO;
    }
    EXIT_CRITICAL_SECTION(  );
    return eStatus;
}


当看到UCHAR ** pucFrame的时候就优点晕了。不就是传出一个地址吗?干吗还要用指向指针的指针?于是,顺手修改了程序,将那个形参变成了UCHAR * pucFrame,具体的函数也变成了下面的样子:


eMBErrorCode
eMBASCIIReceive( UCHAR * pucRcvAddress, UCHAR * pucFrame, USHORT * pusLength )
{
    eMBErrorCode    eStatus = MB_ENOERR;


    ENTER_CRITICAL_SECTION(  );
    assert( usRcvBufferPos < MB_SER_PDU_SIZE_MAX );
    
    /* Length and CRC check */
    if( ( usRcvBufferPos >= MB_SER_PDU_SIZE_MIN )
        && ( prvucMBLRC( ( UCHAR * ) ucASCIIBuf, usRcvBufferPos ) == 0 ) )
    {
        /* Save the address field. All frames are passed to the upper layed
         * and the decision if a frame is used is done there.
         */
        *pucRcvAddress = ucASCIIBuf[MB_SER_PDU_ADDR_OFF];


        /* Total length of Modbus-PDU is Modbus-Serial-Line-PDU minus
         * size of address field and CRC checksum.
         */
        *pusLength = ( USHORT )( usRcvBufferPos - MB_SER_PDU_PDU_OFF - MB_SER_PDU_SIZE_LRC );


        /* Return the start of the Modbus PDU to the caller. */
        pucFrame = ( UCHAR * ) & ucASCIIBuf[MB_SER_PDU_PDU_OFF];
    }
    else
    {
        eStatus = MB_EIO;
    }
    EXIT_CRITICAL_SECTION(  );
    return eStatus;
}


    编译后运行,却得不到自己想要的结果。只得回来再分析这个函数。首先搜索到CSDN上的一篇文章;http://dev.csdn.net/author/kgdiwss/477390ddb16b44faa06b6c7014908469.html,里面又好好地对指针做了分析。我下面就把自己的理解再写一遍,以加深印象。


1,指针在编译的时候会变成什么?


    如果我们如下声明变量:


    char a;


    shourt int i;


   short int *pi;


    那么编译的时候,编译器会在内存空间的某处为上面的变量开辟存储空间,下面是一个可能的示意图:


    内存地址 1      2       3        4       5        6       7       8        9          10


------------------------------


                 |int a |short int i    |short int *pi  |


    如上所示,int a 占用一个字节,short int i 占用2个字节, short int *pi 占用2个字节。当我们做了如下的赋值的时候:


    i = 88;


    pi = &a;


    内存映象会得到改变:


                 |int a   |     88        |      2        |


    从上面可以看到,pi是个指针,他的值是2,是变量 i 的内存的起始地址。当我们对 *pi 进行操作的时候,其实就是对变量i 进行操作。如 *pi = 66; ,则等价 i = 66;。下面我们再分析指向指针的指针。指针变量本身跟其他变量一样也是在某个内存地址中存储的,我们也可以让一个指针指向这个地址(指针)。看如下代码:


    short int  **ppi;


    ppi = &pi;


    首先声明了一个指向指针的指针变量ppi,这个ppi是用来存储一个short int *类型指针变量的地址的。第二句的意思是pi的地址赋值给ppi,就是将地址值4给ppi,如下图表示:


                 |int a   | short int i  |short int *pi|short int **ppi |


                 |int a   |     88        |      2          |            4         |


    这样,ppi的值为4,就是pi在内存中的起始地址


    *ppi的值为2,是pi的值


    **ppi的值是88,是i的值,也是*pi的值


    有了上面的分析,我们在看上面那个错误的函数:


eMBErrorCode
eMBASCIIReceive( UCHAR * pucRcvAddress, UCHAR * pucFrame, USHORT * pusLength )
{
    eMBErrorCode    eStatus = MB_ENOERR;


    ENTER_CRITICAL_SECTION(  );
    assert( usRcvBufferPos < MB_SER_PDU_SIZE_MAX );
    
    /* Length and CRC check */
    if( ( usRcvBufferPos >= MB_SER_PDU_SIZE_MIN )
        && ( prvucMBLRC( ( UCHAR * ) ucASCIIBuf, usRcvBufferPos ) == 0 ) )
    {
        /* Save the address field. All frames are passed to the upper layed
         * and the decision if a frame is used is done there.
         */
        *pucRcvAddress = ucASCIIBuf[MB_SER_PDU_ADDR_OFF];


        /* Total length of Modbus-PDU is Modbus-Serial-Line-PDU minus
         * size of address field and CRC checksum.
         */
        *pusLength = ( USHORT )( usRcvBufferPos - MB_SER_PDU_PDU_OFF - MB_SER_PDU_SIZE_LRC );


        /* Return the start of the Modbus PDU to the caller. */
        pucFrame = ( UCHAR * ) & ucASCIIBuf[MB_SER_PDU_PDU_OFF];
    }
    else
    {
        eStatus = MB_EIO;
    }
    EXIT_CRITICAL_SECTION(  );
    return eStatus;
}


    重点关注这个语句:pucFrame = ( UCHAR * ) & ucASCIIBuf[MB_SER_PDU_PDU_OFF];,这句话的意思是将形式参数的值进行改变。
    当调用具体函数的时候eMBASCIIReceive( rcvaddress, pFrame, plen )的时候,首先将实参的值等于形参的值,然后函数体内又对形参值进行了改变,而实参pFrame并没有得到改变。如果将形参变量变成了UCHAR ** pucFrame,我们再来分析:


    当函数调用的时候,变成了eMBASCIIReceive( rcvaddress, pFrame, &plen );那么


    pucFrame = &pFrame;


    在函数体内,pucFrame 指向pFrame。对*pucFrame 进行修改,就是对pFrame的值进行修改。


    所有,这儿要传递地址必须采用指向指针的指针才形。

PARTNER CONTENT

文章评论1条评论)

登录后参与讨论

用户557863 2008-4-25 20:08

一次没得再加油就好了啊!!!!!!!我也和你一样的。

用户10415 2008-3-15 16:50

我的小车发挥部分做出来了,基本部分没做好!!也是成功参赛奖。现在想想真好笑,哈哈。

用户129951 2008-1-22 20:19

用户88114 2007-9-30 15:51

楼主是做的什么题目啊?

郁闷!我也是成功参赛奖。

 

用户93051 2007-9-21 23:19

祝贺你
我得的是 终身遗憾奖 哈哈
很遗憾没参加

用户93841 2007-9-21 20:11

结果不重要,重要的是过程.下次要努力哟
相关推荐阅读
用户1008175 2010-10-19 16:53
差不多一年没有写日志了,再重新拾起来吧
去年9月份到现在都没写过,期间也很少登陆,都不像个做技术的人了。...
用户1008175 2009-09-22 16:22
PCF8563使用不当产生的问题
PCF8563具有中断输出的功能,当设置的定时器减为0的时候,int管脚电平拉低。在一个应用中,我将int管脚连接到MSP430F1611的一个引脚中断上,期望int管脚不断地产生中断。运行起来后发现...
用户1008175 2009-08-25 09:54
74HC04使用不当导致XTR111电压输出产生问题
74HC04应用不当导致XTR111电压输出问题<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office"...
用户1008175 2009-06-17 15:18
4~20mA电流输出(电流环)应用笔记
最近查了一些4~20mA输出的电路。结合自己的实践做了一下总结。大部分内容来自网上(链接见参考部分)。感兴趣的可以下载看看。...
用户1008175 2009-06-11 09:47
ATmega168的SPI发送完寄存器SPIF不置位的问题
利用ATmega168的硬件SPI驱动74HC595来扩展串行接口。把MOSI和SCK设置为输出,然后设置好寄存器。,具体如下:static void vSpi595Init(void){  DDRB...
用户1008175 2009-02-20 23:46
小问题大智慧
1,100/101跟101/102相比,哪个数大?     能快速回答上来吗?口算比较难了,但是,可以根据特点做个大胆推断,分子比分母小1,是不是相当于比较1/2和2/3谁大哪?显然是后者大。我们再用...
我要评论
1
6
关闭 站长推荐上一条 /3 下一条