为了正常的体验网站,请在浏览器设置里面开启Javascript功能!

二进制、八进制、十六进制转换

2019-02-26 46页 doc 112KB 15阅读

用户头像

is_686908

暂无简介

举报
二进制、八进制、十六进制转换 第五章 变量和常量 5.1 从类型到变量 5.1.1 公孙龙的“白马非马” 5.1.2 定义变量 5.1.3 如何为变量命名 5.1.4 如何初始化变量 5.1.4.1 什么时候需要给变量初始化? 5.1.4.2 初始化变量的两个时机 5.1.4.3 通过计算得到初始值 5.1.4.4 变量的取值范围 5.2 变量与内存地址 5.3 常量 5.3.1 几种数据类型常数的表达方法 5.3.1.1 整型常数的表达 5.3.1.2 实型常数的表达 5.3.1.3 字符常量的表达 5.3.1.4 字符串...
二进制、八进制、十六进制转换
第五章 变量和常量 5.1 从类型到变量 5.1.1 公孙龙的“白马非马” 5.1.2 定义变量 5.1.3 如何为变量命名 5.1.4 如何初始化变量 5.1.4.1 什么时候需要给变量初始化? 5.1.4.2 初始化变量的两个时机 5.1.4.3 通过计算得到初始值 5.1.4.4 变量的取值范围 5.2 变量与内存地址 5.3 常量 5.3.1 几种数据类型常数的表达方法 5.3.1.1 整型常数的表达 5.3.1.2 实型常数的表达 5.3.1.3 字符常量的表达 5.3.1.4 字符串常量 5.3.2 用宏表示常数 5.3.3 常量定义 5.3.4 枚举常量 5.3.4.1 为什么需要枚举类型 5.3.4.2 定义枚举类型的基本语法 5.3.4.3 关于枚举常量的输出效果 5.1 从类型到变量 5.1.1 公孙龙的“白马非马”  (该版课程的内容更新及订正均已停止) 旧版课程打包下载 ---------------------------------- [想看涵盖“面向对象”、“图形编程”、“泛型编程”…… 的“最新2008年版 白话C++”课程,请点击!] (另有: 博客版) 故事是春秋时的公孙龙先生说的。 城门上告示:“马匹不得入城”。公孙龙同志骑白马而来,遭拒入。公孙龙一脸正色:“告示上写的是‘马’,而我骑的是‘白马’,难道 ‘马’等于 ‘白马’吗?” 守门士兵觉得白马还真不是马,于是放行。 依公孙龙先生的理论认为:如果白马是马,黑马也是马,那么岂不白马等于黑马,所以,不能说白马是马。“白马非马”是中国哲学史上的一桩公案。不过,若是我们从程序的角度上说,可以认为:马在这里表示一种类型,而白马,黑马它们的类型都是马。 白马,黑马具有相同的“数据类型”,但它们都相对独立的个体。从这点说,别说有白黑之分,就算同样是白马,这一匹和哪一匹白马,也是相对独立的个体。 在程序中,“类型”和“变量”的关系正是“马”和“白马”的关系。 如果C或C++有这种数据类型: Horse,那么,定义一匹“白马”的变量应该这样: Horse AWhiteHorse; 以后我们说不定真的有机会自已定义Horse,不过现在,我们在上一章的学的数据类型是: char,int,bool 等等。 假设我们需发使用一个有关年龄的变量,在C或C++中是这样定义的: int age; 现在让我们来事先建立一个空的工程,随着本章课程的进展,我们需要不断地在工程中加入零星的代码,及时实践。 仍然是一个空的控件台程序。方法是……以前我们讲过,忘了就看前面章节吧。 代码文件Unit1.cpp中,手工加入以下的黑体部分: //--------------------------------------------------------------------------- #include #pragma hdrstop //--------------------------------------------------------------------------- #pragma argsused int main(int argc, char* argv[])] { getchar(); return 0; } //--------------------------------------------------------------------------- 5.1.2 定义变量 语法: 数据类型 变量名; “张三”既可以指张三这个人,也可以是张三的名字。同样,上面的“变量名”,其实也就是变量本身。 举上一节的例子: int age; 其中,int 是数据类型(整型),而 age 是变量名,更多的时候,我们就说是变量 age。最后是一人分号。它表示定义一变量在C或C++里一句完整的语句。因为C++的语言总是以分号结束。 如果要声明一个字符类型变量: char letter; 声明一个bool类型的变量: bool do_u_love_me; 其它类型,除了void不能直接定义一个变量以外,都是一样的。 void avoid; //错!void 类型无法直接定义一个变量。 有时同一时候同一数据类型需要多个变量,此时可以分别定义,也可以一起定义: int a; int b; int c; 下面采用一起定义,会更省事: int a,b,c; 一起定义多个同类型变量的方法是:在不同变量之间以逗号(,)分隔,最后仍以分号(;)结束。 让我们来试试变量定义,另外,我们还要趁此机会,看看一个变量在仅仅进行定义之后,它的值会是什么。 继续上一小节的代码。仍然是加入黑体部分,当然 // 及其后面的内容是注释,你可以不输入。 ...... int main(int argc, char* argv[])] { /////////////////定义变量////////////////////////////////////////////////// //以下定义三个变量:a,b,c int a; double b,c; //a,b,c仅仅被定义,它的值会是什么?我们用 cout 输出三个变量: cout << "a = " << a << " b = " << b << " c = " << c << endl; getchar(); return 0; } 最好先保存代码文件和工程文件。然后按F9运行。以下是笔者机器得到结果。 a 是1,b和c都像天文数字?嗯,从这里我们学到一个C,C++编程极其重要知识:未初始化的变量,它的值将是未确定的。所谓“未初始化”,就是指这个变量只有定义代码,而没有赋值。 (立即重复执行这段代码,得到结果可能都一样,但这并不说明这些值就是可以确定不变。) 5.1.3 如何为变量命名 C/C++的变量的名字中只能有以下字符:大小写字母、阿拉伯数字(但不能做为开头)、下划线 _。 汉字不能成为变量名。 不过,就算允许,又有谁会这么累呢,用汉字作变量名? 不能或不要 不能取名为C、C++的保留字。 如: int char; //不行 这是不被允许的。char 是一个保留字。我们不能再拿来做变量。 不能超过250个字符。 这在BCB里有规定。是一个可以调整的值。 不能以数字开头 int 100; //不行 int 100ren; //不行 不能夹有空格 bool do you love me; //不行 你可以用下划线代替空格: bool do_you_love_me; //OK 不能在同一作用范围内有同名变量 (仅C++) 比如: int abc; int abcd; int abc; //不行 在C里, 上面重复定义变量 abc是被允许的。 关于作用范围,我们以后会讲到。 不要和C、C++中已有的全局变量,函数,类型名取相同的名字。 double sin; 这不合适。因为C库为我们提供了计算正弦值的函数,名字就叫 sin; 不要太长。 是的,250个字符其实太长了。如果有个变量名长达30个字母,我看不仅你自已写得累,别人看着也会觉得是在读外国小说,主人公的名字太长,烦人。 不要太短 这个我们放到后面说。 以上几点中,凡标为“不能”,意味如果你违反了,你的程序便会在编译时出错。而“不要”则仅属建议内容。真要这么做,程序也没错。 另外,我们还建议要为每个变量取一个有意义的名字。比如 NumberOfStudents,这个变量一看就明白是为“学生的人数”定义的。而如果定义为 aaa,cc,之类,就容易混淆。当然,有一些约定成俗的用法,如字母i,j,等常用来作循环流程中的计数变量。再者,有意义的名字并不是指一定要把变量所要代表的意思用英文句子写出,一般可以用简写,如 NumOfStudent,它同样意义明了,但更简短。而且,如果我们英文一般,那么有时也可以使用拼音。这里就不举例了,因为笔者连拼音都很次。 前面说到取名不要太短,说的就是避免像 aaa,cc之类的图输入方便,但毫无意义,不可读的变量命名习惯。 (你很快就会在教程中发现,笔者似乎自已违反了这个规定,用一些a,b,c作为变量名。这不能说是笔者的错。因为会有些时候变量的意义并不重要) 最后,C,C++是区要大小写的语言,所以变量 Num 和变量 num 完全是两个变量。大家在定义,使用变量要注意到这一点。 关于变量的命名,我们不做实践。下面附加说说编程中命名的一些风格。 附:关于命名变量的几种风格。 较早以前,现在仍流行于UNIX、Linux编程界,程序员喜欢用全部小写的单词来命名变量,如果两个单词,比如my car,常用的命名方法有两种:my_car或myCar。my_car自然看起清楚,不过输入频繁地下划线是件累事(根据指法,下划线必须使用小指头按)。后一种方法被称为“驼峰表示法”,原因是大写字母看起来想凸起的驼峰。 之所以不使用MyCar,原因是C/C++允许程序自定义数据类型,所以有必要从一个名字上很快地区分它是变量或是数据类型。方法是让自定义的数据类型都用大写开头。比如前面的说的“马”是程序员自定的数据类型,那么如果采用这里的命名,则应取名为:Horse,而“一匹白马”是变量,所以取名为:aWhiteHorse。 Horse aWhiteHorse; 在C++ Builder里,并没有限制大家如何为变量取名。所以为了仍可以很明显的做到上述的区分,CB的方法是对用户自定义的数据类型在前头加一个字母T(Type的首字母)。仍如 Horse,则改名为:THorse。前面我们写Windows版的hello world时,使用了一个Label控件,其实,检查代码你会发现,它的类名就叫:TLabel。 最后还有一种方法是匈牙利标记法(Hungarian notation)。该法要求在每人变量的前面加上若干个用于表示该变量的数据类型的小写字母。如iMyCar表示这个变量是整型(i表示int);而倘若是cMyCar,则表示这个变量是char类型。该法经过一段时间的训练熟悉以后,会带来一些好处。问是如果对自定义的数据类型也按这种方法进行,就不是经过训练就能熟悉了。比如hoWhite,这个名字中的ho表示“马”,真有点强人所难。举上实际存在的例子,在Windows API中,如果你看到: LPCITEMIDLIST pidlRoot; 想要一眼看明白 pidRoot,必须的要求是你很明白 ITEMIDLIST 是什么玩意儿了。 是的,Windows的API使用的是最后一种方法。在大多数情况下,它的变量的名字都看上去怪怪的。 在本部教程中,我们在正式程序中,最常使用的方法是简单的“驼峰”法。 5.1.4 如何初始化变量 5.1.4.1 什么时候需要给变量初始化? int a; 声明了一个整型变量a。但这变量的值是多少?a等于0吗?还是等于100?我们都不知道。“不知道”的意思是:a 有值,但这个值的大小是随机的,所以我们无法确定。 无法确定一个变量值是常有的事,比如我们要求用户输入他的年龄。我们需要声明一个整型变量来存储用户年龄,但在用户输 入之前,我们是无法确认它的值。 但有些时候,我们可以事先给一个变量初始时的值。同样是年龄的问题,虽然我们不知道用户到底几岁,但我们知道他不可能是 0 ,所以我们把年龄一开始设为0。为什么要这样?用户有时不小心忘了输入年龄(就像我们在网上填表一样),我们就可以检查年龄是否为0来发现了。另外一种相反的用法是,我们发现大都数用户是8岁(比如一个小学生入学),这时我们初始化年龄变量为8,目的是为了方便用户了。 那么,如果为一个变量赋值呢? 答案就像我们初中的代数:设 x = 10, y = 100。用等号。请记住:现实生活中,等号(=)有两个意义,但在C/C++里,= 只用来给一个变量赋值。 5.1.4.2 初始化变量的两个时机 1. 在定义时初始化变量 int a = 0; 通过一个等号,我们让a的值等于0; 同时定义多个变量时也一样: int a = 0, b= 1; 当然也可以根据需要,只给部分变量初始化。 int a = 0, b; 或: int a,b = 1; 2. 在定义以后赋值 int a; a = 100; 5.1.4.3 通过计算得到初始值 给变量赋值,除了给一个直接的值以外,还可以通过计算获得。如: int a = -3 + 200 - 5; 或者如: int a = 9; int b = 3; int c = a / b; (/ 表示除号) 现在来试试给变量赋值的几种方法。 ...... int main(int argc, char* argv[])] { /////////////////定义变量////////////////////////////////////////////////// //以下定义三个变量:a,b,c int a; double b,c; //用 cout 输出三个变量: cout << "a = " << a << " b = " << b << " c = " << c << endl; /////////////////初始化变量//////////////////////////////////////////////// int d = 0; float e = 1.234, f; f = 567.8 + 0.2; cout << "d = " << d << " e = " << e << " f = " << f << endl; getchar(); return 0; } 5.1.4.4 变量的取值范围 1). 变量允许取值范围 = 变量数据类型的范围 关于赋值的最后一个需要注意的是:变量的取值范围。 变量的取值范围?变量是有类型的,变量的允许的取值范围等同于其数据类型的范围。比如一个整型数,那么它的取值范围就是:-2147483648 ~ 2147483647。而如果是一个字符类型,它的取值就不能是 -129。 以下是示例: int a = 3000000000; //错误! char b = -129; //错误! 我们来写代码实践一下。由于char类型计算机在输出将直接输出字符,我们不好观察结果,所以我们选择了int类型。 ...... int main(int argc, char* argv[])] { /////////////////定义变量////////////////////////////////////////////////// //以下定义三个变量:a,b,c int a; double b,c; //用 cout 输出三个变量: cout << "a = " << a << " b = " << b << " c = " << c << endl; /////////////////初始化变量////////////////////////////////////////////////int d = 0; float e = 1.234, f; f = 567.8 + 0.2; cout << "d = " << d << " e = " << e << " f = " << f << endl; /////////////////变量值越界////////////////////////////////////////////////// int g = 3000000000; //给g赋值超过int允许的范围,所以g的值不可能如愿等于3000000000 cout << "g = " << g <标准
码。) 值 符号 值 符号 值 符号 0 空字符 44 , 91 [ 32 空格 45 - 92 \ 33 ! 46 . 93 ] 34 " 47 / 94 ^ 35 # 48 ~ 57 0 ~ 9 95 - 36 $ 58 : 96 ` 37 % 59 ; 97 ~ 122 a ~ z 38 & 60 < 123 { 39 ' 61 = 124 | 40 ( 62 > 125 } 41 ) 63 ? 126 ~ 42 * 64 @ 127 DEL (Delete键) 43 + 65 - 90 A ~ Z             (其中,0~31都是一些不可见的字符,所以这里只列出值为0的字符,值为0的字符称为空字符,输出该字符时,计算机不会有任何反应。我们以后会学习0字符的特殊作用。) 4). 转义符的使用 根据前面的说法,单引号应该表达为: char c = ''';  但这是错误的。C、C++不认识 ''',因为它容易引起歧义。 另外,有一些字符属于不可见的字符,无法直接写出,比如键盘上大大的回车键,在输入文档时,用它可以输入一个回车换行,显然我们不能这样在C/C++里表示一个回车换行: char c = ' ' 在第一个'和第二个'之间夹了一个换行,这样的表示方法不仅不方便,C和C++也不认。 类似这样的问题还有制表符(键盘上的Tab键)等等。 解决的方法是使用转义符.C/C++使用反斜杠'\'作为转义符。如: '\'' : 表示单引号; '\"' : 表示双引号; '\n' : 表示换行(n : line); 下面列出常用的C、C++特殊字符: 字符 数值 意义 '\a' 7 响铃(输出该字符时,屏幕无显示,但喇叭发音) '\n' 10 换行(n: line) '\t' 9 制表符(横向跳格) '\r' 13 回车(return) '\\' 92 输出转义符 '/' 本身 '\"' 34 双引号 '\'' 39 单引号       这里顺便解释一下“回车换行”是什么,尽管我们对这个词耳熟得很。 “回车换行”是“回车”加“换行”。 换行好理解,但什么叫“回车”呢?它和“换行”又有什么关系? 原来,“回车换行”的概念源于早先的打字机。类似于现在打印机中有一个打印头,这个打印头平常停在打印机内的某一端。在打印一行时,则需要向外移动,打印一行结束后,打印头需要回到原来位置。由于打印头在英文中用“车”来表示,所以这个动作就称为“回车”,用金山词霸的中的解释就是:“将打印或显示位置移到同行起始位置的运动。” 所以对于打印机,假设有两行字,两行之间若光有“回车”,那么这两行字将重叠在一起(对于控制台程序的屏幕,则将回到行首)。如果光有“换行”,则第二行将不从起始位置打起,样子如下: 这是第一行 这是第二行。 只有既输出“回车”又输出“换行”,才是我们常见的换行结果。当然,对于当今的大都软件,往往都把单独的回车或换行直接解释于二者的结合。 转义符的另外一种用法是直接接数值。但必须采用8进制或16进制。这里暂不讲解。 如果需要使用数值表示,最直接的还是使用类似: c = 120; 的方法。比如要让变量c的值为单引号,我们至少可以有以下2种方法: char c = '\''; //使用转义符 char c = 39;   //直接赋给字符的ASCII的值。 转义符的内容,看上去怪怪的?不过,多用几次我们就会明白。 /////////////////char 类型/////////////////////////////////////////////////// int k = 120; char j = 120; cout << "k(int) = " << k << " j(char) = " << j << endl; char l = 'A'; char m = l + 1; cout << "l = " << l << " m = " << m << endl; /////////////////转义符////////////////////////////////////////////////////// cout << "TAB:" << '\t' << "AA" << endl; cout << "换行:" << '\n' << "AA" << endl; cout << "回车:" << '\r' << "AA" << endl; cout << "听到BEEP声了吗?" << '\a' << endl; cout << '\'' << endl; cout << '\"' << endl; cout << '\\' << endl; getchar(); ...... 在执行之前,有必要稍作解释。 首先那是“AA"做什么用。因为制表符、回车、换行等特殊字符,其输出效果是改变光标位置,所以我们需要一些上下文来显示出光标位置改变效果,这里就随便写个“AA”了事。 然后是在cout语句中,平常我们叫是使用双引号输出一行话,但如果当前要输出只是一个字符,我们也可以使用单引号。 至于所谓“BEEP”声,你可别抱太多期望,它只是计算机内置的小喇叭短促一个声音,听起来并不美妙。 现在来看结果(请只关心转义符部分): 关于输出结果的几点说明: 1、需要注意的是 '\t' 在控制台窗口的输出效果,如果前面的字符长度已超过一个制表位,那么后面的第一个'\t'将是没有效用的。(要理解这一点,你可以将代码中“TAB”加长一点,如"TABTAB")。 2、“AA车” 的输出结果是怎么来的呢?请大家考虑考虑。 试验程序在这里结束。 5.2 变量与内存地址 前面讲到“白马、黑马”时,我们说一匹白马和一匹黑马具有共同的数据类型“马”,但二者是相对独立的个体。现在我们以共熟悉的“人”来继续这个话题,最终引出变量与内存地址的关系。 张三和李四的数据类型都是“人类”。但张三和李四显然是独立的量:张三吃了两块蛋糕,李四不可能因此就觉和肚子饱了;而李四在下班的路上捡到一个钱包,虽然正好是张三的,两人似乎通过钱包有了点关系,但谁得谁失仍然不容混淆。 这一切都很好理解。张三和李四之所以是不同的个体,根本原因在于两人有着不同的肉身。如果是一对连体婴儿,虽然也是两个人,但当左边的婴儿被蚊子咬一口时,右边婴儿是否也会觉得痒,就不好说了。 现在我们困难的是,如何理解两个不同的变量,也是互相独立的呢? 答案就在“内存地址”,“内存地址”就是变量的肉身。不同的变量,拥有不同的内存地址。譬如: char a; char b; 上面有两个字符类型的变量a和b,a拥有自已的内存地址,b也拥有自已的内存地址,二者绝不相同。而a、b只不过分别是那两个内存地址的“名字”,恰如“张三、李四”。 让我们看图解: 看,内存就像是开宾馆的。不过这有宾馆有点怪。首先它每一个“房间”的大小都是一个字节(因此,计算机能单独处理的最小内存单位为字节)。它的门牌号也不叫房号,而是叫内存地址。 在左图中,“房客”,变量a住在内存地址为1000002的内存中,而变量b则住在它的隔壁,地址为100003的内存中。另外,如果你足够细心,你还会发现:内存地址由下往上,从小到大排列。 变量的内存地址是在程序运行时,才由操作系统决定。这就好像我们住宾馆。我们预定一个房间,但房间号由宾馆根据情况决定, 我们可以改变变量的值,但变量的地址我们无法改变。对照宾馆一说,就是我们订了房间,可以不去住,还可以决定让谁去住在那个房间里。(当然,现实生活中宾馆可能不会允许你这么做)。 在前面图示的例子中,a、b是字符(char)类型。各占用1个字节。如果是 int类型,那么应该占4个字节。这4个字节必须是连续的。让我们再来看一个例子: int a; int b; char c; 这回,我们声明了两个int类型和一个char类型的变量。同时和上面一样,我们事实上是假设了这三个变量被依次序分配在相邻的内存地址上(真实情况下,这和其它因素,如指定的字节对齐方式等有关)。从右图中可以看到整型变量a占用了1000001~1000004这4个字节。 在我们已学习的数据类型中,long double占用10个字节,是占用内存空间最大的一种数据类型。以后我们学习数组,或者用户自定数据类型,则可能要求占用相当大的,并且同样必须是连续的空间。因此,如果操作系统仅仅通过简单的“按需分配”的原则进行内存管理,内存很快就会宣告不足。事实上,操作系统的内存管理相当复杂。幸好,一个普通的程序员并不要求去了解这些内幕。更多的有关内存管理的知识,我们会在下一部课程中学习。但是本章中有关内存的内容却相当重要。 让我们来看看我们学了什么: 1、不同的变量,存入在不同的内存地址,所以变量之间相互独立。 2、变量的数据类型决定了变量占用连续的多少个字节。 3、变量的内存地址在程序运行时得以确定。变量的内存地址不能改变。 除了这些以外,我们现在还要增加几点: 现在,我们可以明白,为什么需要变量,显然,这又是一个讨好人类的做法。在汇编和机器语言,就是只对内存进行直接操作。但你也看到了,内存地址是一堆长长的数,不好记忆;另外,管理内存复杂易错,让程序员直接管理内存显示不可能。而通过变量,不仅让内存地址有了直观易记的名字,而且程序员不用直接对内存操作,何乐而不为呢?事实上,这是所有高级语言赖于实现基础。 既然变量只不过是内存地址的名称,所以: 4、对变量的操作,等同于对变量所在地址的内存操作。 第五点是反过来说: 5、对指定内存地址的内存操作,等同对相应变量的操作。 尽管这简直就是在重复。但这一条却是我们今后理解C、C++语言相对于其它很多高级语言的,最灵活也最难学的“指针”概念的基石。 5.3 常量 说完变量,我们来学常量。 看一段代码片段。省略号表示可能会有的其它操作。 int a = 3; .... a = 100; 代码中,a 是变量。一开始我们初始化为3。后来出于什么需要,我们又将它赋值为100。a的值也就从3变成了100。 代码中,3 和 100就是一种常量。像这种直接在代码写出大小的量,称为立即数,也称为常数,而常数是常量的一种。 常量的定义:常数,或代表固定不变值的名字。 5.3.1 几种数据类型常数的表达方法 5.3.1.1 整型常数的表达 用10进制表示,当然是最常用也是最直观的了。如:7,356,-90,等等。 C,C++语言还允许我们使用8进制或16进制表示。这里且不讲。至于2进制形式,虽然它是计算机中最终的表示方法,但它太长,而且完全可以使用16进制或8进制方便地表达,所以计算机语言不提供用2进制表达常数的方法。 有时,你也会看到一些老的代码中,在一些整型常后面加一个大写或小写的 L 字母。如:989L 这是什么意思呢?原来,一个常数如果其范围允许,那么计算机默认将其认为是 int 类型的,那么要让计算机把某个数认为是 long int类型,就可以在其后面加 L 或 l。不过,这在以前的16位机器才有意义了。现在,我们的机器都是32位,long int 和 int 完全一样,都是占用4个字节,所以,我们没有必要这样用了。 5.3.1.2 实型常数的表达 实型常数一般只用10进制表示。比如 123.45,或 .123。后者是 0.123的简写。不过我个人认为,少写一个0的代价是很容看错。 实型数还可以使用科学计数法,或曰指数形式,如:123e4、或123E4 都表示 123 * 104,即 1230000。 我们学过的实数数据类型有:float,double,long double。在C++中,默认的常数类型是double。比如你写: 1.234; 那么,C++按double类型为这个数分配内存,也就是说为它分配8个字节。如果要改变这一点,可以通过加后缀字母来实现。 加 f 或 F,指定为float类型。 加 l 或 L, 指定为double类型。 以下示例: 12.3f  //float类型 12.3   //默认类型(double) 12.3L  //long double类型 12.3e400  //long double类型,因为值已不在double类型的取值范围内 5.3.1.3 字符常量的表达 关于字符的表示方法,我们已经在 5.1.3.4 节中的第3点讲过。这里简单重复。 字符常量用单引号括起来的一个字符,如:'a','b','c',' ','A'。等。 可以用转义符来表示一些无法打出的符号,如 '\n','\r','\t'。 这里补充一点:值为0的字符,称为空字符,或零字符。它用 '\0' 表示。注意,它和阿拉伯数字字符 '0'完全是两个数。(请大家查一前面常用字符ASCII值表中,后者的值是多少) 5.3.1.4 字符串常量 字符串由字符组成。在C/C++语言中,字符串的是由一对双引号括起的来的字符序列。如: "Hello, world!" "How do you do?" "Hello" 上面3行都是字符串常量。注意,双引号是英文字符。 字符串是由一个个字符排列而成,所以在C/C++中,字符串在内存中的存储方式,我想你可以想象得出。每个字符占用一个字节,一个接一个排列。但是,双引号本身并不存储,因为双引号是为了表达方便,并不是实际内容。下面是示意图: (为了简单,我们选了例子中最短的字符串) 不过,字符串的存储工作还有一点点事情需要做。举一个直观的例子。如果在上图中的 Hello后,内存地址为120006正好还存放一个字符:‘o’。那么,程序就会把 Hello 和 o连起来认作是一个字符串“Helloo”。为什么呢? 前面我们讲字符类型,整型,等变量或常量时,根据数据类型的不同,它们都有已知的,固定的大小。字符串是由字符组成的,虽然每个字符的大小固定1个字节,但字符串的大小却是可变的。所以必须有一个方法来表示一个字符串在哪里结束。 空字符(值为0字符)担起这个责任。因为空字符没有任何输出效果,所以正常的字符串中是不会出现空字符的。因此,用它来表示一个字符串的结束,再合适不过了。以下是带有字符串在真正的内存存储示意图。 记住,空字符用 '\0'表示。 有两个字符串: "Hello" "What" 假设二者在内存中存储的位置正好是连续的,那么内存示意就为: (为了结束版本,我这里横向表示,并且不再写出仅用于示意的内存地址) H e l l o \0 W h a t \0                       从表中,我们可以看出空字符 '\0'是如何起到标志一个字符结束的作用。 5.3.2 用宏表示常数 假如我们要写一个有关圆的种种计算的程序,那么∏(3.14159)值会被濒繁用到。我们显然没有理由去改∏的值,所以应该将它当成一个常量对待,那么,我们是否就不得不一遍一遍地写3.14159这一长串的数呢? 必须有个偷懒的方法,并且要提倡这个偷懒,因为多次写3.14159,难免哪次就写错了。 这就用到了宏。宏不仅可以用来代替常数值,还可以用来代替表达式,甚至是代码段。(宏的功能很强大,但也容易出错,所以其利弊大小颇有争议。)今天我们只谈其中代替常数值的功能。 宏的语法为: #define 宏名称 宏值 比如要代替前面说到的∏值,应为: #define PAI 3.14159 注意,宏定义不是C或C++严格意义上的语句,所以其行末不用加分号结束。 宏名称的取名规则和变量名一样,所以我们这里用PAI来表示∏,因为C、C++不能直接使用∏字符。有了上面的语句,我们在程序中凡是要用到3.14159的地方都可以使用PAI这个宏来取代。 作为一种建议和一种广大程序员共同的习惯,宏名称经常使用全部大写的字母。 假设原来有一段代码: double zc = 2 * 3.14159 * R; //求圆周长,其中R是代表半径的变量 double mj = 3.14159 * R * R; //求圆面积 在定义了宏PAI以后,我们就可以这样使用: #define PAI 3.14159 double = 2 * PAI * R; //求圆周长,其中R是代表半径的变量 double = PAI * R * R; //求圆面积 用宏来取代常数,好处是: 1)让代码更简洁明了 当然,这有赖于你为宏取一个适当的名字。一般来说,宏的名字更要注重有明确直观的意义,有时宁可让它长点。 2)方便代码维护 就如前面说的3.14159。哪天你发现这个∏值精度不够,想改为3.1415926,那么你只修改一处宏,而不是修改代码中的所有宏。 原来的宏: #define PAI 3.14159 修改后的宏: #define PAI 3.1415926 对宏的处理,在编译过程中称为“预处理”。也就是说在正式编译前,编译器必须先将代码出现的宏,用其相应的宏值替换,这个过程有点你我在文字处理软件中的查找替换。完成预处理后,所有原来的“PAI”都成了立即数3.1415926。所以在代码中使用宏表达常数,归根结底还是使用了立即数,并没有明确指定这个量的类型。这容易带来一些问题,所以C++使用另一更稳妥的方法来代替宏的这一功能。 5.3.3 常量定义 常量定义的格式为: const 数据类型 常量名 = 常量值; 相比变量定义的格式,常量定义必须以 const 开始,另外,常量必须在定义的同时,完成赋值。 const float PAI = 3.1415926; const 的作用就是指明这个量(PAI)是常量,而非变量。 常量必须一开始就指定一个值,然后,在以后的代码中,我们不允许改变PAI的值,比如: const float PAI = 3.14159; double zc = 2 * PAI * R; PAI = 3.1415926;        //错误!,PAI不能再修改。 double mj = PAI * R * R;  如果一个常量是整型,可以省略指出数据类型,如: const k = 100; 相当于 const int k = 100; 反过来说,如果不指定数据类型,则编译器将它当成整型。比如: const k = 1.234; 虽然你想让k等于一个实型数,然而,最终k的值其实是1。因为编译器把它当成整型常量。 我们建议在定义变量时,明确指出类型,不管它是整型或其它类型。 const int i = 100; const double di = 100.0; 5.3.4 枚举常量 5.3.4.1 为什么需要枚举类型 生活中很多信息,在计算机中都适于用数值来表示,比如,从星期一到星期天,我们可以用数字来表示。在西方,洋人认为星期天是一周的开始,按照这种说法,我们定星期天为0,而星期一到六分别用1到6表示。 现在,有一行代码,它表达今天是周3: int today = 3; 很多时候,我们可以认为这已经是比较直观的代码了,不过可能在6个月以后,我们初看到这行代码,会在心里想:是说今天是周3呢,还是说今天是3号?。其实我们可以做到更直观,并且方法很多。 第一种是使用宏定义: #define SUNDAY 0 #define MONDAY 1 #define TUESDAY 2 #define WEDNESDAY 3 #define THURSDAY 4 #define FRIDAY 5 #define SATURDAY 6 int today = WEDNESDAY; 第二种是使用常量定义: const int SUNDAY = 0; const int MONDAY  = 1; const int TUESDAY = 2; const int WEDNESDAY = 3; const int THURSDAY = 4; const int FRIDAY = 5; const int SATURDAY = 6; int today = WEDNESDAY; 第三种方法就是使用枚举。 枚举也是我们将学习的第二种用户自定义数据类型的方法。上回我们学过typedef。typedef通过为原有的数据类型取一别名来获得一新的数据类型。枚举类型的原有数据只能是int或char类型(有些编译器则只支持int,如VC)。 枚举类型是在整数的取值范围中,列出需要的个值作为新数据类型的取值范围。 这就像bool类型,其实它是char类型,但它只需要0或1来代表false或true。 这里的例子中,我们用整型来表示周一到周日。整型的取值范围是多少来的?反正很大,可我们只需0到6,并且我们希望这7个值可以有另外一种叫法,以直观地表示星期几。 5.3.4.2 定义枚举类型的基本语法 enum 枚举类型名 {枚举值1,枚举值2,…… }; enum : 是定义枚举类型的关键字。 枚举类型名 :我们要自定义的新的数据类型的名字。 枚举值 :可能的个值。 比如: enum Week {SUNDAY,MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY}; 这就定义了一个新的数据类型:Week。 Week数据类型来源于int类型(默认)。 Week类型的数据只能有7种取值,它们是:SUNDAY,MONDAY,TUESDAY……SATURDAY。 其中SUNDAY = 0,MONDAY = 1……SATURDAY = 6。也就是说,第1个枚举值代表0,第2个枚举值代表1,这样依次递增1。 不过,也可以在定义时,直接指定某个或某些枚举值的数值。比如,对于中国人,可能对于用0表示星期日不是很好接受,不如用7来表示星期天。这样我们需要的个值就是 1,2,3,4,5,6,7。可以这样定义: enum Week {MONDAY = 1,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY,SUNDAY}; 我们希望星期一仍然从1开始,枚举类型默认枚举值从0开始,所以我们直接指定MONDAY等于1,这样,TUESDAY就将等于2,直接到SUNDAY等于7。 枚举值,我们就称为格举常量,因为它一经定义以后,就不可再改变,以下用法是错误的! TUESDAY = 10; //错误!我们不能改变一个枚举值的数值。 用枚举常量来完成表达今天是星期三: Week today = TUESDAY; 再举一例。在计算机中,颜色值也是使用整数来表示的。比如红色用 255 表示,绿色用 65280 表示,而黄色则用65535表示。(在自然界中,红 + 绿 = 黄,在计算机中也一样,你注意到了吗?) 假设我们在交警队工作,需要写一个有关红绿灯的程序,我们可以这样定义一个颜色的枚举类型: enum TLightColor { Red = 255, Green = 65280, Yellow = Red + Green }; 5.3.4.3 关于枚举常量的输出效果 bool 类型,其实就是个地道的枚举类型。我们已经在前面程序中试过它的输出效果:false 输出 0,true 输出 1。假设我们有一个 TLightColor 类型的变量: TLightColor redLamp = Red; 然后我们输出 redLamp: cout << redLamp << endl; 很多学员可能会猜出,输出结果是 “255” 。 显然他们比笔者聪明。当时我学习枚举类型,就天真地认为屏幕会打出“Red”。(呵呵,别嘲笑我,其实,有时候,比起聪明来,天真更难得……) 我不在课程里给出如何定义,如何使用,如何输出枚举常量的例程了。我想,学到今天,你应该有兴趣,也有能力自已新建一个控制台工程,然后自已写代码实现这一切了。 别发愣,歇上10分钟,你是要再看看本章课程,还是启动CB,写个例程,自已决定吧。   第六章 二进制、八进制、十六进制 6.1 为什么需要八进制和十六进制? 6.2 二、八、十六进制数转换到十进制数 6.2.1 二进制数转换为十进制数 6.2.2 八进制数转换为十进制数 6.2.3 八进制数的表达方法 6.2.4 八进制数在转义符中的使用 6.2.5 十六进制数转换成十进制数 6.2.6 十六进制数的表达方法 6.2.7 十六进制数在转义符中的使用 6.3 十进制数转换到二、八、十六进制数 6.3.1 10进制数转换为2进制数 6.3.2 10进制数转换为8、16进制数 6.4 二、十六进制数互相转换 6.5 原码、反码、补码 6.6 通过调试查看变量的值 6.7 本章小结 这是一节“前不着村后不着店”的课。不同进制之间的转换纯粹是数学上的计算。不过,你不必担心会有么复杂,无非是乘或除的计算。 生活中其实很多地方的计数方法都多少有点不同进制的影子。 比如我们最常用的10进制,其实起源于人有10个指头。如果我们的祖先始终没有摆脱手脚不分的境况,我想我们现在一定是在使用20进制。 至于二进制……没有袜子称为0只袜子,有一只袜子称为1只袜子,但若有两袜子,则我们常说的是:1双袜子。 生活中还有:七进制,比如星期。十六进制,比如小时或“一打”,六十进制,比如分钟或角度…… (该版课程的内容更新及订正均已停止) 旧版课程打包下载 ---------------------------------- [想看涵盖“面向对象”、“图形编程”、“泛型编程”…… 的“最新2008年版 白话C++”课程,请点击!] (另有: 博客版) 6.1 为什么需要八进制和十六进制? 编程中,我们常用的还是10进制……必竟C/C++是高级语言。 比如: int a = 100,b = 99; 不过,由于数据在计算机中的表示,最终以二进制的形式存在,所以有时候使用二进制,可以更直观地解决问题。 但,二进制数太长了。比如int 类型占用4个字节,32位。比如100,用int类型的二进制数表达将是: 0000 0000 0000 0000 0110 0100 面对这么长的数进行思考或操作,没有人会喜欢。因此,C,C++ 没有提供在代码直接写二进制数的方法。 用16进制或8进制可以解决这个问题。因为,进制越大,数的表达长度也就越短。不过,为什么偏偏是16或8进制,而不其它的,诸如9或20进制呢? 2、8、16,分别是2的1次方,3次方,4次方。这一点使得三种进制之间可以非常直接地互相转换。8进制或16进制缩短了二进制数,但保持了二进制数的表达特点。在下面的关于进制转换的课程中,你可以发现这一点。 6.2 二、八、十六进制数转换到十进制数 6.2.1 二进制数转换为十进制数 二进制数第0位的权值是2的0次方,第1位的权值是2的1次方…… 所以,设有一个二进制数:0110 0100,转换为10进制为: 下面是竖式: 0110 0100 换算成 十进制 第0位 0 * 20  =  0 第1位 0 * 21  =  0 第2位 1 * 22  =  4 第3位 0 * 23  =  0 第4位 0 * 24  =  0 第5位 1 * 25  = 32 第6位 1 * 26  = 64 第7位 0 * 27  =  0     + --------------------------- 100   用横式计算为: 0 * 20 + 0 * 21 + 1 * 22 + 1 * 23 + 0 * 24 + 1 * 25 + 1 * 26 + 0 * 27 = 100 0乘以多少都是0,所以我们也可以直接跳过值为0的位: 1 * 22 + 1 * 23 +  1 * 25 + 1 * 26 = 100 6.2.2 八进制数转换为十进制数 八进制就是逢8进1。 八进制数采用 0~7这八数来表达一个数。 八进制数第0位的权值为8的0次方,第1位权值为8的1次方,第2位权值为8的2次方…… 所以,设有一个八进制数:1507,转换为十进制为: 用竖式表示: 1507换算成十进制。 第0位 7 * 80 = 7 第1位 0 * 81 = 0 第2位 5 * 82 = 320 第3位 1 * 83 = 512   + -------------------------- 839 同样,我们也可以用横式直接计算: 7 * 80 + 0 * 81 + 5 * 82 + 1 * 83 = 839 结果是,八进制数 1507 转换成十进制数为 839 6.2.3 八进制数的表达方法 C,C++语言中,如何表达一个八进制数呢?如果这个数是 876,我们可以断定它不是八进制数,因为八进制数中不可能出7以上的阿拉伯数字。但如果这个数是123、是567,或12345670,那么它是八进制数还是10进制数,都有可能。 所以,C,C++规定,一个数如果要指明它采用八进制,必须在它前面加上一个0,如:123是十进制,但0123则表示采用八进制。这就是八进制数在C、C++中的表达方法。 由于C和C++都没有提供二进制数的表达方法,所以,这里所学的八进制是我们学习的,CtC++语言的数值表达的第二种进制法。 现在,对于同样一个数,比如是100,我们在代码中可以用平常的10进制表达,例如在变量初始化时: int a = 100; 我们也可以这样写: int a = 0144; //0144是八进制的100;一个10进制数如何转成8进制,我们后面会学到。 千万记住,用八进制表达时,你不能少了最前的那个0。否则计算机会通通当成10进制。不过,有一个地方使用八进制数时,却不能使用加0,那就是我们前面学的用于表达字符的“转义符”表达法。 6.2.4 八进制数在转义符中的使用 我们学过用一个转义符'\'加上一个特殊字母来表示某个字符的方法,如:'\n'表示换行(line),而'\t'表示Tab字符,'\''则表示单引号。今天我们又学习了一种使用转义符的方法:转义符'\'后面接一个八进制数,用于表示ASCII码等于该值的字符。 比如,查一下第5章中的ASCII码表,我们找到问号字符(?)的ASCII值是63,那么我们可以把它转换为八进值:77,然后用 '\77'来表示'?'。由于是八进制,所以本应写成 '\077',但因为C,C++规定不允许使用斜杠加10进制数来表示字符,所以这里的0可以不写。 事实上我们很少在实际编程中非要用转义符加八进制数来表示一个字符,所以,6.2.4小节的内容,大家仅仅了解就行。 6.2.5 十六进制数转换成十进制数 2进制,用两个阿拉伯数字:0、1; 8进制,用八个阿拉伯数字:0、1、2、3、4、5、6、7; 10进制,用十个阿拉伯数字:0到9; 16进制,用十六个阿拉伯数字……等等,阿拉伯人或说是印度人,只发明了10个数字啊? 16进制就是逢16进1,但我们只有0~9这十个数字,所以我们用A,B,C,D,E,F这五个字母来分别表示10,11,12,13,14,15。字母不区分大小写。 十六进制数的第0位的权值为16的0次方,第1位的权值为16的1次方,第2位的权值为16的2次方…… 所以,在第N(N从0开始)位上,如果是是数 X (X 大于等于0,并且X小于等于 15,即:F)表示的大小为 X * 16的N次方。 假设有一个十六进数 2AF5, 那么如何换算成10进制呢? 用竖式计算: 2AF5换算成10进制: 第0位:  5 * 160 = 5 第1位:  F * 161 = 240 第2位:  A * 162 = 2560 第3位:  2 * 163 = 8192  + ------------------------------------- 10997  直接计算就是: 5 * 160  + F * 161 + A * 162 + 2 * 163 = 10997 (别忘了,在上面的计算中,A表示10,而F表示15) 现在可以看出,所有进制换算成10进制,关键在于各自的权值不同。
/
本文档为【二进制、八进制、十六进制转换】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。 本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。 网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。

历史搜索

    清空历史搜索