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

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

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

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

发现调用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 ( == size)
{
pst = NULL;
return false;
} (*pst) = (char*)malloc(size);
if (NULL == *pst)
{
return false;
}
memset(*pst, , size); return true;
} int use_get_memory()
{
char *pStr = NULL;
char buf[] = "hello world."; if (get_memory(&pStr, ) == false)
{
return -;
}
memcpy(pStr, buf, sizeof(buf)); printf("%s\n", pStr); free(pStr);
pStr = NULL; return ;
}

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

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

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

int** array_init(unsigned int size)
{
int **ppArray = NULL;
if ( == size)
{
return NULL;
} ppArray = (int**)malloc(sizeof(int*) * size);
if (ppArray == NULL)
{
return NULL;
}
memset(ppArray, , sizeof(int*) * size); return ppArray;
} void use_array()
{
int **ppArr = NULL;
int i = ;
ppArr = array_init(); int array[] = { , , , , , , , , , };
for (i = ; i < ; i++)
{
ppArr[i] = &array[i];
} for (int i = ; i < ; 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 */ \
}

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

(十二)C语言双指针的常见用法的更多相关文章

  1. Java开发笔记(四十二)日历工具的常见应用

    前面介绍了日历工具Calendar的基本用法,乍看起来Calendar与Date两个半斤八两,似乎没有多大区别,那又何苦庸人自扰鼓捣一个新玩意呢?显然这样小瞧了Calendar,其实它的作用大着呢,接 ...

  2. python接口自动化(三十二)--Python发送邮件(常见四种邮件内容)番外篇——上(详解)

    简介 本篇文章与前边没有多大关联,就是对前边有关发邮件的总结和梳理.在写脚本时,放到后台运行,想知道执行情况,会通过邮件.SMS(短信).飞信.微信等方式通知管理员,用的最多的是邮件.在linux下, ...

  3. [转]Java程序员从笨鸟到菜鸟之(八十三)细谈Spring(十二)OpenSessionInView详解及用法

    首先我们来看一下什么是OpenSessionInView?    在hibernate中使用load方法时,并未把数据真正获取时就关闭了session,当我们真正想获取数据时会迫使load加载数据,而 ...

  4. 03--(二)编程实践中C语言的一些常见细节

    编程实践中C语言的一些常见细节(转载) 对于C语言,不同的编译器采用了不同的实现,并且在不同平台上表现也不同.脱离具体环境探讨C的细节行为是没有意义的,以下是我所使用的环境,大部分内容都经过测试,且所 ...

  5. C语言语法笔记 – 高级用法 指针数组 指针的指针 二维数组指针 结构体指针 链表 | IT宅.com

    原文:C语言语法笔记 – 高级用法 指针数组 指针的指针 二维数组指针 结构体指针 链表 | IT宅.com C语言语法笔记 – 高级用法 指针数组 指针的指针 二维数组指针 结构体指针 链表 | I ...

  6. C语言库函数大全及应用实例十二

    原文:C语言库函数大全及应用实例十二                                          [编程资料]C语言库函数大全及应用实例十二 函数名: setrgbpalette ...

  7. layui(二)——layer组件常见用法总结

    layer是layui的代表作,功能十分强大,为方便以后快速配置这里对其常见用法做了简单总结 一.常用调用方式 //1.普通消息:alert(content,[options],[yesCallBac ...

  8. C语言第十二讲,文件操作.

    C语言第十二讲,文件操作. 一丶文件操作概述 在操作系统中,我们的文档都称为文件.操作系统也为我们提供了接口进行操作.不同语言都是使用的相同的接口,只不过封装的上层接口不一样 操作文件的步骤 打开文件 ...

  9. Go语言学习笔记十二: 范围(Range)

    Go语言学习笔记十二: 范围(Range) rang这个关键字主要用来遍历数组,切片,通道或Map.在数组和切片中返回索引值,在Map中返回key. 这个特别像python的方式.不过写法上比较怪异使 ...

随机推荐

  1. POJ:2377-Bad Cowtractors

    传送门:http://poj.org/problem?id=2377 Bad Cowtractors Time Limit: 1000MS Memory Limit: 65536K Total Sub ...

  2. 20145202马超 《Java程序设计》第七周学习总结

    Arrays:用于操作数组的工具类. 里面都是静态方法. asList:将数组变成list集合. 把数组变成集合的好处:可以使用集合的思想来操作数组中的元素. 将数组变成集合的时候不可以使用集合的增删 ...

  3. android的dmtracedump工具生成trace文件图片 'dot' 不是内部或外部命令,也不是可运行的程序 或批处理文件。

    http://jingyan.baidu.com/article/c910274bfa6c1fcd361d2df7.html http://www.cnblogs.com/albert1017/p/3 ...

  4. Docker构建nginx+uwsgi+flask镜像(一)

    前言 笔者之前是从事Java方面的工作,自从18年5月左右来到新的公司,接触到Python,被其简单优雅的语法风格深深吸引,同时,新公司也帮助笔者打开Docker世界的大门,让笔者体会到“一次打包,到 ...

  5. Spring 各种注解备注

    Spring 各种注解备注 felix_feng 关注 2016.12.28 10:34* 字数 2092 阅读 790评论 0喜欢 6 转载 (http://blog.csdn.net/sudilu ...

  6. vue-i18n vue-cli项目中实现国际化 多语言切换功能 一

    vue-cli项目中引入vue-i18n 安装: npm install vue-i18n可参考vue-i18n官网文档 main.js中引入: import Vue from 'vue' impor ...

  7. KVO的底层实现原理?如何取消系统默认的KVO并手动触发?

    KVO是基于runtime机制实现的 当某个类的属性对象第一次被观察时,系统就会在运行期动态地创建该类的一个派生类(该类的子类),在这个派生类中重写基类中任何被观察属性的setter 方法.派生类在被 ...

  8. leetcode 【 Remove Duplicates from Sorted List II 】 python 实现

    题目: Given a sorted linked list, delete all nodes that have duplicate numbers, leaving only distinct  ...

  9. selenium初识(二)——之webdriver API

    配置完的环境之后,我们先来写一个小脚本: # __Author__:"Jim_xie" from selenium import webdriver from time impor ...

  10. visio2013密钥

    66DNF-28W69-W4PPV-W3VYT-TJDBQ http://www.xiazaizhijia.com/rjjc/133264.html