【计算机本科补全计划】C++ Primer:指针和const限定符

正文之前

今天下午看了一下午的计算机组成与设计,结果好死不死的看到了设计部分--处理器的设计。天哪,我现在还只是一个准备给人装一台电脑做实验田的家伙,连用都不咋会,你还叫我设计!!!虽然我学过数电模电和电路原理,也学过单片机组成和应用,但是不代表我对这些逻辑元件感兴趣啊!!!所以很果断的,我到了晚饭时节就果断的抛弃了第四章跳到第五章--存储层次和并发设计,这才有了点重新活下去的勇气。然后晚间继续看神书--《C++ Primer 第五版》,这里面的只是真的是看得我如痴如醉,配合不少在计算机组成里面看到的原理知识,每天收获最大的就这会时候了!下面是今天的读书笔记,感觉很多都是各大公司招收IT人才的笔试题的选择题类!!

正文

1、 承接上一节的引用讲起
  • 引用只是一个别名,是没有实际的地址和对象的。它只是绑定一个对象,好比是域名指向IP。然而指针不同。关键在于以下几点:
  • 指针本身是一个对象,允许对其复制和拷贝,并且可以直接对指针对象本身进行操作,而不像引用没有对象实体,只能依靠别的对象的苟活。
  • 指针不需要在定义的时候赋初值,因为它自己就是一个对象,是要申请存储空间的,完全不需要在一开始的时候确定指向的对象。
  • 和其他的内置类型一样,如果在块作用域内定义的指针没有被初始化,那么就会是一个不确定的值。
2、 指针的定义的时候,书上有一种说法,如下:
int vdal;
int *pd=&vdal;   // 正确:初始值是int型变量的地址
int *pd1=vdal;    // 正确: 初始值是指向int对象的指针

对于第三行那个说法我是始终存疑的,因为在我的电脑上跑的时候是没法运行的,直接就报错了,所以大家定义指针的时候,还是直接按照第二行那个定义的方法吧,也许是第三行那种玩法太高端,反正现在我的编译器是跑不出来的~ ~

另外声明指针的时候指针类型和指向的对象的类型要一致,不然很容易出错,比如下面的代码:

double dval;
int *pd=&dval;   // Error:int类型的指针不能指向一个double双精度浮点数的对象!!

不过有时候也是有特例的,后面容我慢慢介绍。

3、 指针的值

四种状态:

  • 指向一个对象
  • 指向紧邻对象的所占空间的 下一个位置
  • 空指针,意味着指针没有指向任何对象
  • 无效指针,也就是上述情况外的其他值

试图拷贝或者以其他方式访问无效指针的值都会引发错误。访问的后果无法预计。

4、利用指针访问对象

如果是指向一个变量,那么直接用*p就可以访问,如果指向一个结构体,那么形式有两种:

Struct *Item;
*Item.name="ZZB";
item->name="ZZB";

上面第二行第三行的含义是一样的。第一行是定义一个结构体,结构体内部有一个变量时name,所以如果要访问name的话。两种方式完全相同。 解引用(*)操作仅仅适用于指向了对象的有效指针。 下面几个很有意思,很容易混淆的定义或者是声明方法。我们一起来探讨一下:

int i=42;  //这就是个定义
int &r=i;   // 这就是个引用
int *p;     // 定义一个指针,你看,不一定要初始化对吧
p=&i;      // 给p这个指针对象复赋值 内容是i的地址
*p=i;       // 这个跟上面是一个意思。就是说i赋给解引用后的p指针,等同于把i的地址给p;
int &r2=*p;    // 这一句才是最骚气的,解读的顺序是:p指针解引用后被r2引用

上面透漏出来了一个计算机领域的常识:读一段代码,从右读到左边,按照优先级自己排列。

5、 空指针

空指针不指向任何对象,以下是生成空指针的几个办法:

int *p1=nullptr;
int *p2=0;
#incluede <cstdlib>  int *p3=NULL;

以上三种空指针的定义方法完全等效,最直接的是第一种。在我们编程的过程中,如果实在不知道指针指向何处,那么上面三种任选其一,欢迎选购!

6、 void * 指针

void* 是一种特殊的指针,可以存放任何类型的地址,也就是说你复制的时候随便放一种都可以,相当于搬运车,来者不拒。但是我们也没法通过这个指针查询到任何它所指向的对象的内容,因为你不确定指向的对象是什么类型,那么也就没法准备相对应的类型的寄存器来存放取出来的对象值。

int p=23;
double q=1.2;
void *a=&p;
a=&q;

上面的所有代码都不会报错,因为void指针就是这么溜,可以接受任何形式的对象传递指针给它,但是也就是因为这么6,所以不管你的对象再简单,void也没法调用,从void指针的角度来说,地址就只是指向了一个内存空间,至于里面是啥,我不管,我只是记着这个地址。

所以如果要强制转换一个对象的类型的话,可以尝试用void * 指向。然后调用的时候强制转换指针类型、不知道行不行,待会测试下下面的代码就好了:

int a=12;
void *p=&a;
cout<<(double)*p<<endl;
7、 那些年定义指针踩的坑:
  • 第一种,这两个含义不同吧??
int* p;
int *p;

其实呢,根本没啥不用,只是让你看着很警惕而已。实际上没有任何的不同,只是第一种写法容易让人误会。

  • 第二种,我应该是都定义了两个指针吧?
int *p1,*p2;
int* q1,q2;

然而,现实往往残酷,第一行是定义了两个指针,但是很不幸的第二行是一个指针,一个整形数 ,至于谁是谁,我咋知道,自己猜?!!

8、 指向指针的引用

请客官查看下面代码:

int i = 42 ;  
int *p ;   
int *&r=p;  
r=&i;   
*r=0;
  • 从第三行开始说起: 这里就可初现端倪,还记得前面说过的吗?代码从右边开始读,所以应该是定义了一个对指针的引用。此处r只是p这个指针对象的引用,也就是p的别名,int *是一体的。这时候可以用 cout<<*r<<endl;得到42;
  • 至于第四行,就是定义了这个引用的值,也就是说此处等同于 p=&i;
  • 第五行就不消多说了吧??等同于对i赋值 *p=0ori=0;
9、 const限定符
  • 整的来说,const的意思就是,我定义的这个东西,是雷打不动的,我这个对象,谁都不能动,除了对我进行修改,其他的你随意,但是如果你要通过别的方式妄图修改我,不好意思,你死定了(报错大法好!!)。不过如果里面是个地址,你通过我这个地址找到了另外一个对象,那么随你改,你删了都行,但是不许动这个地址,不然我跟你急!!没错,const的作用就是蛮不讲理的保护定义的这个对象不被修改!!任何威胁到const对象的行为都会被当作错误反馈
  • 还有一点,const必须初始化,不然我保护一个对象,对象都没有被初始化,我保护个蛋哟~~所以const是必须被初始化的,不然就报错。见代码举例:
int  i = 42;
const int j=i;
int k=j;   //Right!!
j=100  //Error!!

很明显的,第三行是代表我可以取出const常量的值,但是第四行就好死不死的妄想去修改常量,这是大大的不对的!

10、 默认状态下,const仅仅在文件内有效

如果想要跑到别的文件里面去:

  • 一种是重复定义,但是这个实际上相当于在不同的文件中定义了很多歌独立的常量,很容易引发错误。所以这正是我们要避免的,只能用另外的办法。
  • 对于const变量,不管是声明还是定义,都加一个extern 就是上次学过的那个。这样就只需要定义一次,然后在别的文件中声明,但是记住,只能一个进行初始化,其他的都只是声明,不然冲突了就爽歪歪了。所以前面说过,为什么extern可以初始化呢?这不是跟定义一样了吗?这就是extern可以初始化的好处了!
11、 对const的引用
  • 初始化和对const的引用
int i=42;
const int &r1=i;

允许把一个常量引用绑定在一个非常量上,但是因为引用本身不是一个对象,所以我们没法通过r1引用限制i是非常量这个事实!

const int &r2=42;

可以的,是一个常量引用!此处42是常量,对常量必须要定义引用也是“常量引用”

const int &r3=r1*2 ;

没问题,r1本身也是常量,定义常量引用绑定一个常量这是理所当然的!

int &r4=r1*2;

Error: 不行!!r4这个引用不是常量引用,意味着外界可以改变通过改变r4来改变它绑定的对象,但是你想绑定常量?做梦!报错!!!

  • 结论
    1. 要引用常量,本身必须是常量引用或者是常量指针;
    1. 常量引用对象不一定要是常量,可以是非常量,见上面第二行
12、 指针和const

指针是对象,引用不是,所以允许定义指针本身是一个常量而不是常量引用。所以 !!常指针必须初始化,必须给出一个地址赋给常指针对象。不变的是指针本身的值,而不是指针所指向的那个值

int numb=0;
int *const err=&numb;
const double pi=3.14;
const double *const pip=&pi
  • 看第二行,从err这个对象的定义出发,从右到左看,首先遇到一个const 那么说明它是个常量,然后是* 说明它是个常量指针,然后遇到了int 也就是说它是一个指向int对象的常量指针,那么它初始化是啥?没错,numb的地址,完美符合!!
  • 看第四行,从pip出发从右往左看,const --常量,* -- 指针, double - 指向double类型的常量指针,const 说明指向一个常量。所以通篇读下来,不仅仅pip本身是一个double类型常量指针,所指向的对象也是一个double类型的常量!

那么我们的如下操作都是合法的:

*err=100;
cout<<numb<<endl;  //output:100而不是0;
cout<<*pip<<endl;  //output:3.14
cout<<pi<<endl;  //output:3.14

所以啊,总结下里,const就是一个傲娇属性爆棚的家伙!自己是完全不能改变的,一旦有这个趋势,立马拉整个程序下水,报错!!如果自己指向别人,不管对方是不是常量,但是如果别人指向自己,那么就要求对方一定要是常量!!不过,我怎么这么喜欢这玩意呢???

正文之后

要睡了,今晚有点浪,明天继续看书,不过晚上想看看《羞羞的铁拳》 不知道是不是跟别人说的那样笑点十足,再改改睡觉!

原文发布于微信公众号 - 工科狗和生物喵(gh_3507b116a1f8)

原文发表时间:2017-11-06

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Python爬虫与数据挖掘

Python正则表达式初识(四)

普天同庆的日子里,送出最真的祝福,祝祖国繁荣昌盛,祝朋友事业有成,祝父母身体健康,祝大家永远开心,祝所有人幸福平安~~

623
来自专栏较真的前端

关于数组的前端面试题,你是否都能答对?

3073
来自专栏noteless

[五]java函数式编程归约reduce概念原理 stream reduce方法详解 reduce三个参数的reduce方法如何使用

java8 流相关的操作中,我们把它理解 "累加器",之所以加引号是因为他并不仅仅是加法

2423
来自专栏GIS讲堂

面向对象思想

类:描述了具有相同特性(属性)和相同行为(操作方法)的对象。在程序中,类就是数据类型。

1214
来自专栏iKcamp

全本 | iKcamp翻译 | 《JavaScript 轻量级函数式编程》|《你不知道的JS》姊妹篇

原文地址:Functional-Light-JS 原文作者:Kyle Simpson - 《You-Dont-Know-JS》作者 本书主要探索函数式编程[1]...

30510
来自专栏编程

自学Python笔记(二)

作为最最基础的初学者,尤其是面对中小学生学习Python我想大概了解一下Python,能编个小程序,能看懂一般的程序就可以,如果想深一步的学习还是需要静下心来好...

2087
来自专栏数说工作室

统计师的Python日记【第1天:谁来给我讲讲Python?】

统计师的Python日记 【第一天】谁来给我讲讲Python? 我是一名数据分析师,曾在漫长的岁月中使用SAS、Matlab和R(使用频率依次递减)。其他如...

4396
来自专栏数据结构与算法

P3370 【模板】字符串哈希

题目描述 如题,给定N个字符串(第i个字符串长度为Mi,字符串内包含数字、大小写字母,大小写敏感),请求出N个字符串中共有多少个不同的字符串。 友情提醒:如果真...

2864
来自专栏Play & Scala 技术分享

为Play初学者准备的Scala基础知识

3456
来自专栏Java帮帮-微信公众号-技术文章全总结

第五天 方法【悟空教程】

2007

扫码关注云+社区