zoukankan      html  css  js  c++  java
  • (十二)C语言双指针的常见用法

    1、用作函数的返回值,比较常见的是返回分配的堆内存地址。

    下面用一个例子进行说明下:

    /*****************************************************************************/
    /**
    * rief       分配指定大小size的堆空间
    * param[out]  pst      分配的内存的地址
    * param[in]   size        需要分配的内存大小
    * 
    eturn      返回值描述
    * 
    emarks     其它信息
    ******************************************************************************/
    bool get_memory(char *pst, unsigned int size)
    {
        if (0 == size)
        {
            pst = NULL;
            return false;
        }
    
        pst = (char*)malloc(size);
        if (NULL == pst)
        {
            return false;
        }
        memset(pst, 0, size);
    
        return true;
    }
    
    int use_get_memory()
    {
        char *pStr = NULL;
        char buf[] = "hello world.";
        get_memory(pStr, 1024);
    
        memcpy(pStr, buf, sizeof(buf));
    
        return 0;
    }

    当我们运行这段程序的时候,会发现程序崩溃了,出错的原因是对内存的非法访问,为什么会出现这种情况呢,我们明明已经分配了内存的啊,那我们就进行调试一下,看看问题究竟出现在哪里。

    发现调用get_memory函数之后,pStr所指向的内存竟然是空的,可见问题就出现在这里。

    函数参数的传递是按值传递的,指针类型的参数其实也是按值进行传递的,只不过传递的是变量的地址,按值传递会进行拷贝。

    调用get_memory后,pStr参数会进行拷贝传给get_memory,这里假设拷贝之后的参数为_pStr,执行malloc之后,_pStr指向的是分配的堆空间,而pStr指向的仍然是NULL,所以使用pStr进行操作的时候,会报内存非法访问的错误,而此时,get_memory返回后,新分配的内存(_pStr所指向的空间)没发使用,还会导致内存泄露。

    正确的用法为

    /*****************************************************************************/
    /**
    * rief       分配指定大小size的堆空间
    * param[out]  pst      分配的内存的地址
    * param[in]   size        需要分配的内存大小
    * 
    eturn      返回值描述
    * 
    emarks     其它信息
    ******************************************************************************/
    bool get_memory(char **pst, unsigned int size)
    {
        if (0 == size)
        {
            pst = NULL;
            return false;
        }
    
        (*pst) = (char*)malloc(size);
        if (NULL == *pst)
        {
            return false;
        }
        memset(*pst, 0, size);
    
        return true;
    }
    
    int use_get_memory()
    {
        char *pStr = NULL;
        char buf[] = "hello world.";
    
        if (get_memory(&pStr, 1024) == false)
        {
            return -1;
        }
        memcpy(pStr, buf, sizeof(buf));
    
        printf("%s
    ", pStr);
    
        free(pStr);
        pStr = NULL;
    
        return 0;
    }

    传入的是pStr的地址,进入函数后进行解引用操作,就是对pStr实际地址进行操作。

    2、用于申请动态一维数组,只是这个一维数组中存储的是指针类型。

    一维数组中的每个指针又可以动态分配一个一维数组,即最终可以形成一个二维数组。

    int** array_init(unsigned int size)
    {
        int **ppArray = NULL;
        if (0 == size)
        {
            return NULL;
        }
    
        ppArray = (int**)malloc(sizeof(int*) * size);
        if (ppArray == NULL)
        {
            return NULL;
        }
        memset(ppArray, 0, sizeof(int*) * size);
    
        return ppArray;
    }
    
    void use_array()
    {
        int **ppArr = NULL;
        int i = 0;
        ppArr = array_init(10);
        
        int array[] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
        for (i = 0; i < 10; i++)
        {
            ppArr[i] = &array[i];
        }
    
        for (int i = 0; i < 10; i++)
        {
            printf("%d
    ", *(int*)(ppArr[i]));
        }
    
    }

    3、表示指针的地址,即指向指针的指针。

    这里举个双向队列TAILQ的结构定义中使用的双指针。

    #define TAILQ_ENTRY(type)                        
    struct {                                
        struct type *tqe_next;    /* next element */            
        struct type **tqe_prev;    /* address of previous next element */    
    }

    这是TAILQ对两个指向前后两个元素指针的抽象,抽象为TAILQ_ENTRY结构体:tqe_next是指向下一个元素的指针,tqe_prev是一个二级指针,指针变量的地址,是前一个元素的tqe_next的地址,解引用(*tqe_prev)之后就是本元素的内存地址。

  • 相关阅读:
    AcWing 1018. 最低通行费
    蓝桥杯赛第10届省赛
    P5745 【深基附B例】区间最大和
    P3383 【模板】线性筛素数
    第12届蓝桥杯赛国赛 小蓝买瓜子
    P4715 【深基16.例1】淘汰赛
    AcWing 1015. 摘花生
    第12届蓝桥杯赛省赛 种菜的最大价值
    linq to sql初步
    汇编语言学习笔记接收鼠标消息
  • 原文地址:https://www.cnblogs.com/zhangshenghui/p/6486453.html
Copyright © 2011-2022 走看看