前面的文章,分析了指针的一些概念,可以说指针是C的灵魂,看起来简单,但是想要理解透彻却是相当难,需要大量的练习,不断的巩固,不断的重复才能尽可能的理解指针,这里做一个简单的阶段总结。

1、指针是地址,而不是具体的标量值,这是指针的精髓,不管是一级指针、二级 指针、 整型指针、浮点数指针、结构体指针等等等等所有类型的指针,内容都是个地址,而指针本身当然也是有地址的,而且容易忽略的是,不管这个指针指向的类型多么复杂,比如一个特别大的结构体,它的指针和一个 char型指针的大小本质上是一样的,因为指针就是起始地址。 正式由于这个原因,(void )型指针才能发挥万能指针的作用。

所谓“地址”的是内存地址,基本上可以认为是虚拟内存地址,程序中不管是变量、函数、进程、线程, 可以说程序的全部, 任意一个元素在内存中都是有对应的地址存在的,只不是有的地址会变化,有的地址不变化而已,一般局部变量的地址会经常改变,因为使用的是“栈”,而函数的开头地址、申请的动态内存地址、静态变量、全局变量的地址则是不变的,不变的地址就意味着我们可以在整个程序中的任何地方,都可以用一定的方式去操作这个指针指向的内容,比如读、写、调用函数等。

2、永远不要使用“野”指针

    前面说了,指针的内容是 地址,是内存地址,一旦你拥有了一个指针,你也就有了权力去通过这个指针名字去访问指针指向的内容了,我们可以打个比方,内存相当于核电站 中控室里的 按钮,指针就是这些 按钮的序号地址(名字),“野”指针(未初始化定义)是没有初始化的,相当于蒙着眼睛去按那些按钮,后果当然也是不确定的,可能运气好, 按到了无关紧要的按钮,假如按到了不该被按的按钮,那后果当然也是不堪设想的,程序员就相当于CPU的上帝,我们一定要清楚的知道程序逻辑是怎么运行的,所以一旦我们定义了一个指针,必须要对指针进行初始化。

3、只要是指针都要初始化

    正如前面所讲,只要是未初始化的指针都是野指针,都不能使用,所以只要是指针都要初始化,不管嵌套多少层,不要漏掉任何一个指针的初始化,比如:

typedef struct{int a;int b;int *p;
}Stype; int main
{Stype *pdev = NULL;pdev = (Stype *)malloc(5*sizeof(Stype));   //第一层指针初始化//pdev[0]初始化pdev[0].a = 1;pdev[0].b = 1;pdev[0].p = (int *)malloc(10*sizeof(int));    //第2层指针也要初始化//pdev[1]初始化......//pdev[2]初始化.....//pdev[3]初始化......//pdev[4]初始化
}

4、指针的初始化方式

   所谓指针的初始化,就是给指针赋值,注意这里的“值”指的是“地址”,这个地址必须是固定的,指针是什么类型,就要赋什么类型的地址值,初始化的方式 基本有以下几种:

① 直接将相同类型变量赋值,比如 int *p = &a;   其他类型变量也是一样的,前提是a是确定的。

② 动态内存分配,比如 int *p = (int *)malloc(10*sizeof(int));  这段代码背后的逻辑是,我们申请了 10个 int 型长度的内存区域。 而p则是起始地址。所以我们可以 通过 p[0]、p[1].....直接访问对应的变量。这里可能会觉得这个例子比较简单,其实其他类型的动态内存也是一样的,比如代码如下:

typedef struct
{int a;int b;int *p;
} Stype;Stype *pdev = (Stype *)malloc(5*sizeof(Stype));pdev[0].a = 1;
pdev[0].b = 2;
pev[0].p = (int *)malloc(3*sizeof(int));

上面的代码理解起来还是有些难度的,但是我们只要牢记两点:指针是地址+指针必须初始化,就能剥茧抽丝,深入理解代码的含义。上面的代码的含义是:pdev是一个结构体指针,这个结构体指针指向了一段内存区域,是这段内存区域的起始地址,这段内存区域又包含了 5 小段内存区域,每小段内存区域的包含了一个整型a,整型吧和一个整型指针。我们可以通过[]操作符,间接操作指针,也就是说pdev[0]是第1小段,pdev[1]是第2小段,以此类推。结构体中包含的整型指针,又被初始化为一小段内存区域,这段内存区域包含了3个整型。至此,我们可以通过p访问n多的信息,上面的代码的实现的结果,在内存中的示意图如下所示:

这里特别说明一下,如果对于"[ ]"操作符不太熟悉的话,可能会有混淆,不严谨的说,“[ ]”其实是等同于 p + i 的, 也就是所谓的通过下标来访问数据,对于简单的标准变量,比如 int a[10];   int *p = a;,我们获得的是10个变量的起始指针, p[i] 实现的是 直接访问数组中 对应序号 i的值。

而 如果这个指针是 指针数组,比如说struct a;    struct a *p = (struct a *)malloc(10*sizeof(struct a));  我们相当于获得了10个结构体起始指针,这个时候,我们使用p[i]则是对应第i个指针。访问结构体变量,需要 用 -> 操作符。

5、void 类型指针,只能用于指针传送,不能直接使用。

    void 型指针绝对是一项特别伟大的发明,可以说, 如果没有void 类型指针,那么程序代码写起来工作量会剧增,比如说我们在创建线程时,需要给线程传递参数,线程参数就是一个void型,这样所有的程序员都可以按照自己的需求传递想要的类型指针,打个比方,这就相当于,当我们想要给线程 们在传传递指针参数时,我们把我们想要的参数指针地址的时候,放到一个一个箱子里,这个箱子是一个万能箱,什么都能装,这样就做到了最大的兼容性。所以我们需要将自己的参数指针强制转换为(void *)型。所以说,void类型指针是 传递参数的利器。

void型指针只能用于指针的传送,不能直接使用,我们传递完void类型指针后,当我们要具体使用它的时候,必须必须必须将该空指针再转换为它原来的类型,否则我们是无法使用该指针的。这一点也是比较容易理解的,试想,我们让cpu去使用一个void类型指针,cpu绝对会一脸懵逼的说:你丫给了我一个箱子,不给我打开看,我用这个箱子能访问锤子地址。所以将空指针再转换为它原来的指针操作就相当于打开这个箱子,让CPU知道这个指针类型和值。程序代码示例:

void test_fun(void *arg)
{int *p = (int *)arg;   //必须 转换为原来的类型.........}int main(void *arg)
{int a[10];test_fun((void *)a);  // 必须转换为 void *return 0;
}

指针的使用注意事项:空指针、指针赋值、void *指针相关推荐

  1. 指针中NULL(空指针)和void指针

    1:NULL指针 NULL指针一般用在初始化一个存储类型,这个NULL指针不能用于存放数据类型和访问(你用get()得不到一个具体值,但是对于一个指针变量,我们必须要将这个指针的指向说明,要么将这个指 ...

  2. C语言 void 指针 - C语言零基础入门教程

    目录 一.指针简介 二.空指针 NULL 三.void 指针 四.重点总结 五.猜你喜欢 零基础 C/C++ 学习路线推荐 : C/C++ 学习目录 >> C 语言基础入门 一.指针简介 ...

  3. c语言 万能函数指针,C/C++编程笔记:C语言精华解析之void *指针,指针中的万能指针...

    什么是万能指针? 万能指针其实就是void *类型的指针,而void *指针一般被称为通用指针或叫泛指针.它是C语言关于纯粹地址的一种约定.当某个指针是void型指针时,所指向的对象不属于任何类型. ...

  4. c语言中void指针,C 语言 void指针

    C 语言 void指针 到目前为止,我们已经研究了分配给指针的地址应该与指针声明中指定的类型相同. 例如,如果我们声明了int指针,则此int指针不能指向float变量或某种其他类型的变量,即它只能指 ...

  5. c++中的void指针和const指针

    在c++中可以声明指向void类型的指针,指向void类型的指针称为void指针,此外,在声明指针时,还可以用关键字const进行修饰,用关键字const修饰的指针称为const指针. 1.void指 ...

  6. c语言中的void指针,C程序中void指针的概念

    到目前为止,我对void指针的轻描淡写如下. 当使用关键字void声明指针变量时,它将成为通用指针变量.任何数据类型(char,int,float等)的任何变量的地址都可以分配给void指针变量. m ...

  7. 【C/C++】指针的思考与注意:空指针,指针赋值,void*指针,二级指针,结构体指针,指向同一地址的多个指针释放问题

    部分参考自:https://blog.csdn.net/u012351051/article/details/96753703 1. 啥是指针 指针是地址,而不是具体的标量值,这是指针的精髓,不管是一 ...

  8. 空指针与结构体指针赋值操作

    1.测试代码: #include<stdio.h> #include<string.h> struct DATA {int year;int month;int day; }; ...

  9. C++中的空指针和void * 指针

    空指针(null pointer) 空指针不指向任何对象,在使用一个指针前首先要判断是否为空. 用法: int *ptr1=nullptr; //等价于int *ptr1=0; int *ptr2=0 ...

最新文章

  1. 观察者模式及c++实现
  2. 通过Dapr实现一个简单的基于.net的微服务电商系统(九)——一步一步教你如何撸Dapr之OAuth2授权-百度版...
  3. freecodecamp_1000天的freeCodeCamp
  4. 500张思维导图记38000单词_思维导图记单词,环环相扣难遗忘——2020奇速英语夏令营第三天...
  5. 解决jodconverter 2.2.1 版本不支持docx、xlsx、pptx 转换成PDF格式异常
  6. 面试题 04.04. 检查平衡性
  7. 转 - Web新人(偏前端)应该怎样学习(个人观点,勿喷)
  8. 用户名、密码都有值激活提交按钮
  9. 64位浮点数_浮点数误差
  10. 借助Sigar API获取网络信息
  11. (EasyX入门与实战)第五章 添加音乐
  12. IntelliJ IDEA使用教程(动图详解):Mac 系统下安装 IntelliJ IDEA
  13. Maven环境变量配置及是否成功
  14. 笔记本风扇声音大怎么办
  15. Linux搜索日志关键字的2种方法
  16. abb和plcsocket通讯_abb与西门子plc通讯问题
  17. 阿里内核月报2014年2月
  18. iOS 新特性实现 3DTouch 开发
  19. DPC(Defect Point Correction)------坏点校正
  20. ubuntu下bochs的安装和配置

热门文章

  1. 714. 买卖股票的时机含手续费
  2. 数据洞察与数据驱动 | 12月20日TF87
  3. CAN/以太网转换器 CAN与以太网互联互通
  4. Java安全—CommonsCollections7
  5. 潮汕明代皇封御葬古墓毁损严重 文保部门束手无策
  6. java集合Cloneable
  7. 华为机试题及参考答案
  8. 【BBF系列协议】TR157 CWMP的拓展组件对象
  9. 极坐标计算重积分交换积分次序
  10. Leaflet 官方教程-Non-geographical maps 非地理地图