📄 第5章 变量和常量.htm
字号:
<P>字符串是由一个个字符排列而成,所以在C/C++中,字符串在内存中的存储方式,我想你可以想象得出。每个字符占用一个字节,一个接一个排列。但是,双引号本身并不存储,因为双引号是为了表达方便,并不是实际内容。下面是示意图:</P>
<P>(为了简单,我们选了例子中最短的字符串)</P>
<P><IMG height=197 src="第5章 变量和常量.files/ls05.h3.gif" width=188
border=0></P>
<P>不过,字符串的存储工作还有一点点事情需要做。举一个直观的例子。如果在上图中的
Hello后,内存地址为120006正好还存放一个字符:‘o’。那么,程序就会把 Hello 和
o连起来认作是一个字符串“Helloo”。为什么呢?</P>
<P>前面我们讲字符类型,整型,等变量或常量时,根据数据类型的不同,它们都有已知的,固定的大小。字符串是由字符组成的,虽然每个字符的大小固定1个字节,但字符串的大小却是可变的。所以必须有一个方法来表示一个字符串在哪里结束。</P>
<P>空字符(值为0字符)担起这个责任。因为空字符没有任何输出效果,所以正常的字符串中是不会出现空字符的。因此,用它来表示一个字符串的结束,再合适不过了。以下是带有字符串在真正的内存存储示意图。</P>
<P><IMG height=192 src="第5章 变量和常量.files/ls05.h4.gif" width=187
border=0></P>
<P>记住,空字符用 '\0'表示。</P>
<P> </P>
<P>有两个字符串:</P>
<P>"Hello"</P>
<P>"What"</P>
<P>假设二者在内存中存储的位置正好是连续的,那么内存示意就为:</P>
<P>(为了结束版本,我这里横向表示,并且不再写出仅用于示意的内存地址)</P>
<TABLE cellSpacing=1 borderColorDark=#ffffff width="100%"
borderColorLight=#000000 border=1>
<TBODY>
<TR>
<TD width="7%">H</TD>
<TD width="7%">e</TD>
<TD width="6%">l</TD>
<TD width="7%">l</TD>
<TD width="7%">o</TD>
<TD width="7%">\0</TD>
<TD width="7%">W</TD>
<TD width="6%">h</TD>
<TD width="7%">a</TD>
<TD width="7%">t</TD>
<TD width="6%">\0</TD></TR></TBODY></TABLE>
<P>从表中,我们可以看出空字符 '\0'是如何起到标志一个字符结束的作用。</P>
<P> </P>
<H4><A name=5.3.2>5.3.2</A> 用宏表示常数</H4>
<P>假如我们要写一个有关圆的种种计算的程序,那么∏(3.14159)值会被濒繁用到。我们显然没有理由去改∏的值,所以应该将它当成一个常量对待,那么,我们是否就不得不一遍一遍地写3.14159这一长串的数呢?</P>
<P>必须有个偷懒的方法,并且要提倡这个偷懒,因为多次写3.14159,难免哪次就写错了。</P>
<P>这就用到了宏。宏不仅可以用来代替常数值,还可以用来代替表达式,甚至是代码段。(宏的功能很强大,但也容易出错,所以其利弊大小颇有争议。)今天我们只谈其中代替常数值的功能。</P>
<P>宏的语法为:</P>
<P> </P>
<P>#define 宏名称 宏值</P>
<P> </P>
<P>比如要代替前面说到的∏值,应为:</P>
<P> </P>
<P>#define PAI 3.14159</P>
<P> </P>
<P>注意,宏定义不是C或C++严格意义上的语句,所以其行末不用加分号结束。</P>
<P> </P>
<P>宏名称的取名规则和变量名一样,所以我们这里用PAI来表示∏,因为C、C++不能直接使用∏字符。有了上面的语句,我们在程序中凡是要用到3.14159的地方都可以使用PAI这个宏来取代。</P>
<P>作为一种建议和一种广大程序员共同的习惯,宏名称经常使用全部大写的字母。</P>
<P> </P>
<P>假设原来有一段代码:</P>
<P> </P>
<P>double zc = 2 * 3.14159 * R; //求圆周长,其中R是代表半径的变量</P>
<P>double mj = 3.14159 * R * R; //求圆面积</P>
<P> </P>
<P>在定义了宏PAI以后,我们就可以这样使用:</P>
<P>#define PAI 3.14159</P>
<P> </P>
<P>double = 2 * PAI * R; //求圆周长,其中R是代表半径的变量</P>
<P>double = PAI * R * R; //求圆面积</P>
<P> </P>
<P>用宏来取代常数,好处是:</P>
<P> </P>
<P>1)让代码更简洁明了</P>
<P>当然,这有赖于你为宏取一个适当的名字。一般来说,宏的名字更要注重有明确直观的意义,有时宁可让它长点。</P>
<P>2)方便代码维护</P>
<P>就如前面说的3.14159。哪天你发现这个∏值精度不够,想改为3.1415926,那么你只修改一处宏,而不是修改代码中的所有宏。</P>
<P>原来的宏:</P>
<P>#define PAI 3.14159</P>
<P>修改后的宏:</P>
<P>#define PAI 3.1415926</P>
<P>
<P>对宏的处理,在编译过程中称为“预处理”。也就是说在正式编译前,编译器必须先将代码出现的宏,用其相应的宏值替换,这个过程有点你我在文字处理软件中的查找替换。完成预处理后,所有原来的“PAI”都成了立即数3.1415926。所以在代码中使用宏表达常数,归根结底还是使用了立即数,并没有明确指定这个量的类型。这容易带来一些问题,所以C++使用另一更稳妥的方法来代替宏的这一功能。
<H4><A name=5.3.3>5.3.3</A> 常量定义</H4>
<P>常量定义的格式为:
<P>
<P>const 数据类型 常量名 = 常量值;
<P>
<P>相比变量定义的格式,常量定义必须以 const 开始,另外,常量必须在定义的同时,完成赋值。
<P>
<P>const float PAI = 3.1415926;
<P>
<P>const 的作用就是指明这个量(PAI)是常量,而非变量。
<P>常量必须一开始就指定一个值,然后,在以后的代码中,我们不允许改变PAI的值,比如:
<P>
<P>const float PAI = 3.14159;
<P>double zc = 2 * PAI * R;
<P>PAI = 3.1415926;
//错误!,PAI不能再修改。
<P>double mj = PAI * R * R;
<P>
<P>如果一个常量是整型,可以省略指出数据类型,如:
<P>const k = 100;
<P>相当于
<P>const int k = 100;
<P>
<P>反过来说,如果不指定数据类型,则编译器将它当成整型。比如:
<P>const k = 1.234;
<P>虽然你想让k等于一个实型数,然而,最终k的值其实是1。因为编译器把它当成整型常量。
<P>我们建议在定义变量时,明确指出类型,不管它是整型或其它类型。
<P>
<P>const int i = 100;
<P>const double di = 100.0;
<P>
<H4><A name=5.3.4>5.3.4</A> 枚举常量</H4>
<H5><A name=5.3.4.1>5.3.4.1</A> 为什么需要枚举类型</H5>
<P>生活中很多信息,在计算机中都适于用数值来表示,比如,从星期一到星期天,我们可以用数字来表示。在西方,洋人认为星期天是一周的开始,按照这种说法,我们定星期天为0,而星期一到六分别用1到6表示。
<P>现在,有一行代码,它表达今天是周3:
<P>int today = 3;
<P>很多时候,我们可以认为这已经是比较直观的代码了,不过可能在6个月以后,我们初看到这行代码,会在心里想:是说今天是周3呢,还是说今天是3号?。其实我们可以做到更直观,并且方法很多。
<P>第一种是使用宏定义:
<P>
<P>#define SUNDAY 0
<P>#define MONDAY 1
<P>#define TUESDAY 2
<P>#define WEDNESDAY 3
<P>#define THURSDAY 4
<P>#define FRIDAY 5
<P>#define SATURDAY 6
<P>
<P>int today = WEDNESDAY;
<P>
<P>第二种是使用常量定义:
<P>
<P>const int SUNDAY = 0;
<P>const int MONDAY = 1;
<P>const int TUESDAY = 2;
<P>const int WEDNESDAY = 3;
<P>const int THURSDAY = 4;
<P>const int FRIDAY = 5;
<P>const int SATURDAY = 6;
<P>
<P>int today = WEDNESDAY;
<P>
<P>第三种方法就是使用枚举。
<P>
<P>枚举也是我们将学习的第二种用户自定义数据类型的方法。上回我们学过typedef。typedef通过为原有的数据类型取一别名来获得一新的数据类型。枚举类型的原有数据只能是int或char类型(有些编译器则只支持int,如VC)。
枚举类型是在整数的取值范围中,列出需要的个值作为新数据类型的取值范围。
<P>这就像bool类型,其实它是char类型,但它只需要0或1来代表false或true。
<P>这里的例子中,我们用整型来表示周一到周日。整型的取值范围是多少来的?反正很大,可我们只需0到6,并且我们希望这7个值可以有另外一种叫法,以直观地表示星期几。
<H5><A name=5.3.4.2>5.3.4.2</A> 定义枚举类型的基本语法</H5>
<P>enum 枚举类型名 {枚举值1,枚举值2,…… };
<P>
<P>enum : 是定义枚举类型的关键字。
<P>枚举类型名 :我们要自定义的新的数据类型的名字。
<P>枚举值 :可能的个值。
<P>
<P>比如:
<P>enum Week {SUNDAY,MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY};
<P>
<P>这就定义了一个新的数据类型:Week。
<P>Week数据类型来源于int类型(默认)。
<P>Week类型的数据只能有7种取值,它们是:SUNDAY,MONDAY,TUESDAY……SATURDAY。
<P>其中SUNDAY = 0,MONDAY = 1……SATURDAY = 6。也就是说,第1个枚举值代表0,第2个枚举值代表1,这样依次递增1。
<P>不过,也可以在定义时,直接指定某个或某些枚举值的数值。比如,对于中国人,可能对于用0表示星期日不是很好接受,不如用7来表示星期天。这样我们需要的个值就是
1,2,3,4,5,6,7。可以这样定义:
<P>
<P>enum Week {MONDAY =
1,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY,SUNDAY};
<P>我们希望星期一仍然从1开始,枚举类型默认枚举值从0开始,所以我们直接指定MONDAY等于1,这样,TUESDAY就将等于2,直接到SUNDAY等于7。
<P>
<P>枚举值,我们就称为格举常量,因为它一经定义以后,就不可再改变,以下用法是错误的!
<P>TUESDAY = 10; //错误!我们不能改变一个枚举值的数值。
<P>
<P>用枚举常量来完成表达今天是星期三:
<P>
<P>Week today = TUESDAY;
<P>
<P>再举一例。在计算机中,颜色值也是使用整数来表示的。比如红色用 255 表示,绿色用 65280
表示,而黄色则用65535表示。(在自然界中,红 + 绿 = 黄,在计算机中也一样,你注意到了吗?)
<P>假设我们在交警队工作,需要写一个有关红绿灯的程序,我们可以这样定义一个颜色的枚举类型:
<P>
<P>enum TLightColor { Red = 255, Green = 65280, Yellow = Red + Green };
<H5><A name=5.3.4.3>5.3.4.3</A> 关于枚举常量的输出效果</H5>
<P>bool 类型,其实就是个地道的枚举类型。我们已经在前面程序中试过它的输出效果:false 输出 0,true 输出 1。假设我们有一个
TLightColor 类型的变量:
<P>
<P>TLightColor redLamp = Red;
<P>
<P>然后我们输出 redLamp:
<P>
<P>cout << redLamp << endl;
<P>
<P>很多学员可能会猜出,输出结果是 “255” 。
显然他们比笔者聪明。当时我学习枚举类型,就天真地认为屏幕会打出“Red”。(呵呵,别嘲笑我,其实,有时候,比起聪明来,天真更难得……)
<P>我不在课程里给出如何定义,如何使用,如何输出枚举常量的例程了。我想,学到今天,你应该有兴趣,也有能力自已新建一个控制台工程,然后自已写代码实现这一切了。
<P>别发愣,歇上10分钟,你是要再看看本章课程,还是启动CB,写个例程,自已决定吧。
</P></TD></TR></TBODY></TABLE></CENTER>
<P align=center>[<A
href="http://www.d2school.com/bcyl/bhcpp/newls/ls05.htm#页首">到页首</A>]</P></BODY></HTML>
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -