回 帖 发 新 帖 刷新版面

主题:[原创]理解C++ — 变量与常量(1)

变量与常量(1)

程序运行时,所用的数据首先要被放在内存。内存有两个最基本的属性,一个是它的地址(编号),另一个就是它存储的数据。就如一堆小箱子,编号用来区分到底是用到哪个箱子,数值就如箱子里面放着的东西。

数据放在内存,我们给它一个名字,名字只不过是个符号,符号本身都是没有什么意义的,符号代表的东西才有意义。取了名字之后可以根据名字来方便取回我的数就行了。名字到最后都会影射到地址。可以说,名字是只是给人看的,那个人最可能是你自己,所以为了自己, 也为了别人幸福,请花点心思去取个好名字。

数据放在内存之后,可以分为变量与常量,常者,不变也;量者,数值也。前面已经说了,内存有地址和存储的数据两个最基本的属性,因此常量与变量当然也有两个最基本的属性了,一是它分配到的内存地址,另一个就是地址所指内存里面的数值。常量与变量就是从地址所标内存里面的数值可否变化来区分的。程序执行时数值可变为变量,不可变为常量。常量的数值在程序执行之前已经确定下来的了。当然变量与常量还有其它的要素,比如名字和类型。名字最终会影射到地址,类型可以决定它们的大小和行为。类型有其自身的意义。

从内存里面的数值是否可变可以区分变量与常量。那么从分配的内存地址来看呢,又可以将变量与常量分为 静态(static),动态(dynamic),自动(auto)三种不相同的状态。C++中,关键字const含义为不变(常), 关键字static含义为固定(静)。照我理解(注意,是我自己的理解),常和静,变和动,都是一个意思,指变化和不变化,只不过常和变是对于内存存储的数而言,静和动是对于内存地址而言。

好啦。现在看看静态,动态,和自动到底是什么含义,怎么去区分? 当程序刚启动,系统会分配些栈啊,程序控制块啊,各个段啊之类,这可以算一个准备阶段,在这个准备阶段,程序代码还没有正式执行,常量与常量所需的内存已经分配好了,地址已经确定下来,这就为静态。当程序代码已经执行,才去分配内存,内存地址还没有确定,为动态或者自动。要是代码正在执行,需要内存分配,这一个分配行为由系统全部完成,不用你去操心,就为自动;要是需要程序员自己决定分配的时机,显式调用malloc,new 之类的分配函数,就为动态。概括的说,程序执行之前已经分配好内存,决定好内存地址,为静态; 程序执行之时再分配,分两种情况,1)系统自动完成,为自动类型。2)需要显式调用分配函数,自己决定时机,为动态。

将属性关联到数据的过程,叫做绑定(binding)。如果在程序执行之前,变量与常量的属性已经确定了,就叫静态绑定;要是要等到程序执行之时,属性才被关联,被确定,就叫动态绑定。看看C++的书籍,静态,动态,绑定的概念会老是出现的, 到这里应该有大概的理解了,主要是以属性确立的时机来区分。其实不单是变量,常量,有时候调用什么函数(也就是函数的地址)也需要在程序执行之时才能确定。这时候可以先将函数地址先存起来,或者做成一个表。可能有人问,怎么函数地址也可以放起来的吗? 当然了,函数也需要内存来放,既然放在内存,为了找回它,就一定要得回它的位置,也就地址。对于计算机来说,所有东西都是101010之类的数值,什么都已经没有区别了。既然如此,函数,代码,浮点,对象,跟int之类的整型没有什么两样。int可以先放着,函数为什么不可以?

===================================================================
C++中,const是个很重要的关键字,施加了一种约束。有约束其实不是件坏事情,无穷的权利意味着无穷的灾难。应用了const之后,就不可以改变变量的数值了,要是一不小心改变了编译器就会报错,你就容易找到错误的地方。不要害怕编译器报错,正如不要害怕朋友指出你的缺点,编译器是写程序人的朋友,编译时期找到的错误越多,隐藏着的错误就会越少。所以,只要你觉得有不变的地方,就用const修饰,用得越多越好。比如你想求圆的周长,需要用到Pi, Pi不会变的,就加const,const double Pi = 3.1415926; 比如你需要在函数中传引用,只读,不会变的,前面加const; 比如函数有个返回值,返回值是个引用,只读,不会变的,前面加const; 比如类中有个private数据,外界要以函数方式读取,不会变的,加const, 这个时候就是加在函数定义末尾,加在末尾只不过是个语法问题。其实语法问题不用太过注重,语法只不过是末节,记不住了,翻翻书就可以了,接触多了,自然记得,主要是一些概念难以理解。你想想,const加在前面修饰函数返回值,这时候const不放在末尾就没有什么地方放了。

不过const修饰指针就需要注意一下了。要是修饰的类型不是指针,比如int之类,const放在int之前和int之后是一样的,比如
const int a = 2;
int const a = 2;
有着同样的效果。我自己偏向于第一种写法,其实想想,第二种写法更为合理,表示修饰变量a本身,所以a的值不可变。
当类型为指针时,以星号*为界, const加在左右两边,有不同的意思。
1) const int* pa = &a; (可以写成 int const* pa = &a; 注意是以星号为界)
2) int* const pa = &a;
写法1)表示pa所指向的变量,也就是a的值不可变。写法2)表示pa的指向,也就是pa本身的值不可以变,不可以现在指向a, 跟着指向b.
=======================================
int a = 2;
int b = 3;
const int* pt = &a;
//*pa = 1;            Error
pa = &b;              OK  

===================================== 
int a = 2;
int b = 3;
int* const pt = &a;
*pa = 1;             OK
//pa = &b;           Error   

==================================
前面已经说过了,const用来指示内存中的数值不会变。指针本质上是一个地址(编号), 这个编号也需要放在内存。所以pa这个变量放在内存,数值是一个地址。当const在*右边,const直接修饰pa, 表示pa的数值不会变,所以也就不可以改变指向。当const在*左边,就修饰指向的变量,故*pa的值不能变。要是const int* const pa = &a; a的值不可变,pa的指向也不可变。请仔细想一想。这个问题困惑了我很久的了。

(注: 以上是个人观点,有理无理,回帖评论)
                                                              

回复列表 (共34个回复)

沙发

就算没有功劳也有苦劳了,帮你顶了~没空去看~

板凳

楼主写的这篇和上篇都是我一直想写的题材,没想让楼主抢先了。
^_^
楼主继续努力。

3 楼

C++中的const是一个很麻烦的东西。

要说清楚的话,你这点字数是不够的。

感情上,怎么觉得你写的的是C的const呢?

4 楼

无责任预测:
下一篇应该是指针与数组。
^_^

5 楼

下一篇还会是 变量与常量, 写static, auto, dynamic 各自内存具体的分配。本来不应该分开的,不过发觉太长啦。

要是有时间还会写下去。

刚开始多数还会是C方面的内容,因为C是C++的一个子部分,还有C部分相对简单点。要是可以一直写下去,慢慢的会涉及到对象,虚函数,构造函数等等。前提是有时间,还要有心情,还要自己先理解好。我不敢承诺什么,很可能写着写着就不见人了。尽量保持独立成篇,不用连着来看。

至于const, 本来主题都不是说const的。真要说明白const很难。只不过说到常量,不顺便说说const有点不对头。其实有很多问题我都一直困惑过,到最近才有点慢慢想通。当然,是自己觉得自己想通,觉得而已,不知道是不是真的理解了。所以,帖子的内容都是个人观点,要甄着来看。

6 楼

希望lz继续 我会篇篇看的!   对我大有帮助啊!!!

7 楼

[quote]C++中的const是一个很麻烦的东西。

要说清楚的话,你这点字数是不够的。

感情上,怎么觉得你写的的是C的const呢?[/quote]

[em28][em28][em28]

const只是利用了cache使变量(只指基础数据类型,复杂类型没有深究过)的只具有只读性,编译器并不能保证const变量的内存存储空间上的值不被改变。

8 楼


常和静,变和动,都是一个意思,指变化和不变化,只不过常和变是对于内存存储的数而言,静和动是对于内存地址而言。


对于我这种初学者而言,这么一句至少胜过我读几本书了!

感谢楼主!

9 楼

静与动,常与变,总结得很好[em1]

10 楼

花了时间的劳动,顶~~

我来回复

您尚未登录,请登录后再回复。点此登录或注册