鉴于工作经验有限,目前遇到的双指针的用法有如下几种情况,后续工作中如发现有其他的用法,会更新上去。
1、用作函数的返回值,比较常见的是返回分配的堆内存地址。
下面用一个例子进行说明下:
- /*****************************************************************************/
- /**
- * \brief 分配指定大小size的堆空间
- * \param[out] pst 分配的内存的地址
- * \param[in] size 需要分配的内存大小
- * \return 返回值描述
- * \remarks 其它信息
- ******************************************************************************/
- 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所指向的空间)没发使用,还会导致内存泄露。
正确的用法为
- /*****************************************************************************/
- /**
- * \brief 分配指定大小size的堆空间
- * \param[out] pst 分配的内存的地址
- * \param[in] size 需要分配的内存大小
- * \return 返回值描述
- * \remarks 其它信息
- ******************************************************************************/
- 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\n", 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\n", *(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 */ \
- }