vs行尾不一致,是否将行尾标准化的问题

现象

在打开vs的工程文件的时候,刚打开就出现下面的对话框,这是什么原因?是/否?
在这里插入图片描述

产生的原因分析

直接原因

  你的程序中有一部分是从网页上或其他地方拷贝来的,不是自己在vs上写的。一般从网站上直接拷贝代码会碰到这种问题,可能是代码里有中文的空格,或者看似空格,其实是一些乱七八糟的字符的原因。
查看你当前的vs文件的源代码。
https://www.cnblogs.com/smallidea/p/5501014.html
这位作者是如何做到的?直接借用他的图吧。
在这里插入图片描述
通过读取源文件,发现换行都使用的是“\n”。

根本原因

  这是由Windows和Unix不同的标准引起的…即“回车”和“换行”的问题。“回车”和“换行”是ASCII字符集中两个不可见的控制符。

符号ASCII码意义
\n10换行NL
\r13回车CR

回车和换行的来源
  在计算机还没有出现之前,有一种叫做电传打字机(Teletype Model 33)的玩意,每秒钟可以打10个字符。但是它有一个问题,就是打完一行换行的时候,要用去0.2秒,正好可以打两个字符。要是在这0.2秒里面,又有新的字符传过来,那么这个字符将丢失。于是,研制人员想了个办法解决这个问题,就是在每行后面加两个表示结束的字符。一个叫做“回车”,告诉打字机把打印头定位在左边界;另一个叫做“换行”,告诉打字机把纸向下移一行。到了GUI时代光标都是自由移动的不再有回车的意义。
  后来,计算机发明了,这两个概念也就被般到了计算机上。那时,存储器很贵,一些科学家认为在每行结尾加两个字符太浪费了,加一个就可以。于是,就出现了分歧。
  在Windows中:
  ‘\r’ 回车,回到当前行的行首,而不会换到下一行,如果接着输出的话,本行以前的内容会被逐一覆盖;
  ‘\n’ 换行,换到当前位置的下一行,而不会回到行首;
  前面组合在一起才是我们通常希望的换行,Windows 中的换行符"\r\n";
关于这一点,存疑的地方在于我们用C/C++写代码的时候,都是用\n作为换行符的,也是换到下一行的行首,难道是因为下一行本来就是空的?可以用文件写入的方式试试。以后有机会了试验后再补充。
为了验证windows下的回车效果,在win7的vs2015下做如下验证:

#include <iostream>
using namespace std;
int main()
{
	cout << "this is the first line\n";
	cout << "this is the second line123\r";
	cout << "this is the third line\n";
	cout << "this is the fouth line\r";
	cout << "this is the fifth line\n";
	cout << "this is the sixth line\r\n";
	cout << "this is the seventh line\n";
	cout << "end";
	system("pause");
	return 0;
}

输出结果为:
在这里插入图片描述

  Unix系统中:
  每行结尾只有“<换行>”,即"\n";Windows系统里面,每行结尾是“<回车><换行>”,即“\r\n”;Mac系统里,每行结尾是“<回车>”,即"\r";。一个直接后果是,Unix/Mac系统下的文件在Windows里打开的话,所有文字会变成一行;而Windows里的文件在Unix/Mac下打开的话,在每行的结尾可能会多出一个^M符号。
  Linux中遇到换行符("\n")会进行回车+换行的操作,回车符反而只会作为控制字符("^M")显示,不发生回车的操作。而windows中要回车符+换行符("\r\n")才会回车+换行,缺少一个控制符或者顺序不对都不能正确的另起一行。
  所以基于Windows开发标准的文本编辑器Visual Studio才会提醒你当前编辑的文本不符合Windows行尾标准。

1.Windows 中的换行符"\r\n"
2.Unix/Linux 平台换行符是 "\n"。
3.MessageBox.Show() 的换行符为 "\n"
4.Console 的换行符为 "\n"

换行符还因平台差异而不同。


解决办法:

1.去掉去行尾的检查,或者修改行尾的内容为统一的一种。
2.如果出现乱码可能是因为编码的问题,可以启用UTF-8的检测,在工具->选项->文本编辑器->自动检测不带签名的UTF-8编码,勾选
3.把行尾格式化一下:把文件的内容全部复制到记事本或者文本编码工具中,然后再复制到vs.net里。这样就可以全部格式化行尾的格式了。
4.VSS版本太低 VS.net绑定到VSS 要求VSS的版本在6.0C以上的版本。如果VSS的版本是6.0C以下的版本就可能出现这种情况,建议升级VSS到6.0d的版本。即可解决该问题。


下面是原作者的解决方案,我目前还看不懂,等能看懂了再来看,先记录下来。

  1. 为保持平台的通用性,可以用系统默认换行符System.Environment.NewLine。
  2. 替换所有的非标准换行符。
class Program_Utf8
   {
       static void Main(string[] args)
       {
           String folderPath = @"E:\文件夹路径\";

           ParseDirectory(folderPath, "*.cs", (filePath) =>
           {
               string text = "";
               using (StreamReader read = new StreamReader(filePath, Encoding.Default))
               {
                   string oldtext = read.ReadToEnd();
                   text = oldtext;
                   text = text.Replace("\n", "\r\n");
                   text = text.Replace("\r\r\n", "\r\n"); // 防止替换了正常的换行符      
                   if (oldtext.Length == text.Length)
                   {
                       Console.WriteLine(filePath.Substring(filePath.LastIndexOf("\\") + 1) + " 不需要标准化");
                       return; // 如果没有变化就退出                  
                   }
               }
               File.WriteAllText(filePath, text, Encoding.UTF8); //utf-8格式保存,防止乱码

               Console.WriteLine(filePath.Substring(filePath.LastIndexOf("\\") + 1) + " 行尾标准化完成");
           });

           Console.ReadKey();
       }

       /// <summary>递归所有的目录,根据过滤器找到文件,并使用委托来统一处理</summary>
       /// <param name="info"></param>
       /// <param name="filter"></param>
       /// <param name="action"></param>
       static void ParseDirectory(string folderPath, string filter, Action<string> action)
       {
           if (string.IsNullOrWhiteSpace(folderPath)
               || folderPath.EndsWith("debug", StringComparison.OrdinalIgnoreCase)
               || folderPath.EndsWith("obj", StringComparison.OrdinalIgnoreCase)
               || folderPath.EndsWith("bin", StringComparison.OrdinalIgnoreCase))
               return;

           Console.WriteLine("读取目录:" + folderPath);

           // 处理文件
           string[] fileNameArray = Directory.GetFiles(folderPath, filter);
           if (fileNameArray.Length > 0)
           {
               foreach (var filePath in fileNameArray)
               {
                   action(filePath);
               }
           }
           else
           {
               Console.WriteLine("未发现文件!");
           }

           Console.WriteLine("====================================");

           //得到子目录,递归处理
           string[] dirs = Directory.GetDirectories(folderPath);
           var iter = dirs.GetEnumerator();
           while (iter.MoveNext())
           {
               string str = (string)(iter.Current);
               ParseDirectory(str, filter, action);
           }
       }
   }View Code

在这里插入图片描述
感谢原文2位原作者。
本文来源于参考:
https://blog.csdn.net/xiaofei2010/article/details/8458605

https://www.cnblogs.com/smallidea/p/5501014.html

  • 31
    点赞
  • 61
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
庆丰人事考勤工资软件是一款集人力资源、考勤、薪资为一体的办公软件。软件严格按照国家计算机软件产品开发标准与规范进行规划设计和开发,图形化导航,智能化设计,一致的界面风格,功能强大,操作简便,通用性强,性能稳定,数据准确,运算快速,系统安全可靠。可以为登录用户设定不同的权限,权限细分至访问、修改、导出及打印权限。多窗口操作,每月为一个帐套,支持备份与还原。已广泛应用于电子、塑胶、五金、制衣、印刷、电器等工厂、企业、酒店、学校等各个行业。 人事模块可以记录人事的基本信息和照片,支持二代身份证阅读器采集身份证信息,还可以记录教育程度、专业训练、工作经验、家庭成员、调动记录、奖惩记录、培训记录、扫描件、保险、劳动合同等。还有离职和复职,绩效管理、车辆管理功能。可以方便地按部门、籍贯、职务等查询,可以按拼音首字母快速查找,可以导入excel人事资料,系统中没有的人事项目,可以添加自定义字段。可以按自己选定的字段和顺序进行显示。整个软件中的表格资料都可以按显示的样式进行导出,打印预览,导出的格式有Excel、网页格式、文本文件等。按用户指定的纸张、字体、抬头、输出字段、宽度等预览打印后还可以保存为不同的报表供以后直接使用。软件可以按部门人数,人员地区分布,性别人数、年度招聘人数、年龄结构、学历人数、离职率等进行柱形图、饼形图的图表及表格统计。系统还具备试用到期、离职到期、生日到期、合同到期、汽车保险到期、汽车年检到期等自动提醒功能。 宿舍管理可以自定义宿舍、房间和床位,可以方便地安排人员入住,图形化树形结构的界面很直观地显示各房间的入住情况,还可以录入各房间的水电用量,并根据入职日期自动计算各员工应负担的水电费,水电费和人事中的奖惩金额一样可以进入工资项目中。 考勤模块可以定义一段班和两段班的班次,支持跨天,中午的刷卡可以浮动(上午有事忙,晚一点下班,吃了饭后又立即打下午的上班卡),可以指定是否扣除中午的吃饭时间,可以设定班次中间的休息时间。可以按精确班次和模糊班次计算考勤,精确班次可以指定默认班次或直接按日期排班,推荐使用模糊班次,软件自动按刷卡时间与班次智能匹配。可以外接考勤机,支持按Excel或文本文件导入刷卡记录,可以计算出正班工时、出勤工时,加班小时、迟到早退分钟及次数,夜班补助,休息日加班,节日加班,签卡次数等并进行汇总,自动显示缺卡、迟到早退、旷工等异常,异常可以用自定义颜色显示,在此基础上,还增加了迟到、早退刷卡时间的叠加颜色显示效果,一行中可以对多种异常原因进行提示,如:迟到+早退+旷工,让你对异常洞察秋毫。自动识别节日、直落、休息、调休、调班、外勤、请假、旷工、加班控制等情况,有考勤日报表和月报表及考勤项目统计。考勤结果细致、准确。系统具有AB账验厂功能。 打卡资料可以按照设定的时间实现自动采集, 可以对多个考勤机执行指令:如连接、断开、同步时间,上传指纹人脸、下载记录等。可以在机器端和电脑端将人员进行对比,如果人员的信息不一致,以红色显示,通过对指纹数和人脸数的统计,可以清楚地知道哪些人没录指纹,哪些人还没有上传指纹等情况。软件全面支持中控的各种型号的考勤机。 工资模块可以因工资项目结构及计算公式的不同而对不同人员集合设定不同的工资帐套,工资项目的类型有录入项、所得税项、计算项,支持尾数扣零,人事、考勤的项目可以作为数学或逻辑表达式参与计算公式,“如果”、“那么”、“或者”、“否则”等中文式逻辑标识符更符合中国人的表达习惯,丰富的内嵌函数等的使用使得工资运算不再麻烦和可怕,理论上不存在解决不了的事情。计算公式是否正确还可以验证。录入项目录入好后,其他的项目自动计算得到,所见即所得,准确自动、智能简便。工资条和工资表可以按照纸张、字体、选择的字段、对象之间的距离等自动排版和呈现。抬头支持双行叠加。整个工资模块从结构定义到打印报表全程都让你DIY。银行代发也是可以自定义不同银行的格式,并按格式输出文档。
第 一 章 概述 1-1 简述计算机程序设计语言的发展历程。 解: 迄今为止计算机程序设计语言的发展经历了机器语言、汇编语言、高级语言等阶段,C++语言是一种面向对象的编程语言,也属于高级语言。 1-2 面向对象的编程语言有哪些特点? 解: 面向对象的编程语言与以往各种编程语言有根本的不同,它设计的出发点就是为了能更直接的描述客观世界中存在的事物以及它们之间的关系。面向对象的编程语言将客观事物看作具有属性和行为的对象,通过抽象找出同一类对象的共同属性(静态特征)和行为(动态特征),形成类。通过类的继承与多态可以很方便地实现代码重用,大大缩短了软件开发周期,并使得软件风格统一。因此,面向对象的编程语言使程序能够比较直接地反问题域的本来面目,软件开发人员能够利用人类认识事物所采用的一般思维方法来进行软件开发。C++语言是目前应用最广的面向对象的编程语言。 1-3 什么是结构化程序设计方法?这种方法有哪些优点和缺点? 解: 结构化程序设计的思路是:自顶向下、逐步求精;其程序结构是按功能划分为若干个基本模块;各模块之间的关系尽可能简单,在功能上相对独立;每一模块内部均是由顺序、选择和循环三种基本结构组成;其模块化实现的具体方法是使用子程序。结构化程序设计由于采用了模块分解与功能抽象,自顶向下、分而治之的方法,从而有效地将一个较复杂的程序系统设计任务分解成许多易于控制和处理的子任务,便于开发和维护。 虽然结构化程序设计方法具有很多的优点,但它仍是一种面向过程的程序设计方法,它把数据和处理数据的过程分离为相互独立的实体。当数据结构改变时,所有相关的处理过程都要进行相应的修改,每一种相对于老问题的新方法都要带来额外的开销,程序的可重用性差。 由于图形用户界面的应用,程序运行由顺序运行演变为事件驱动,使得软件使用起来越来越方便,但开发起来却越来越困难,对这种软件的功能很难用过程来描述和实现,使用面向过程的方法来开发和维护都将非常困难。 1-4 什么是对象?什么是面向对象方法?这种方法有哪些特点? 解: 从一般意义上讲,对象是现实世界中一个实际存在的事物,它可以是有形的,也可以是无形的。对象是构成世界的一个独立单位,它具有自己的静态特征和动态特征。面向对象方法中的对象,是系统中用来描述客观事物的一个实体,它是用来构成系统的一个基本单位,由一组属性和一组行为构成。 面向对象的方法将数据及对数据的操作方法放在一起,作为一个相互依存、不可分离的整体--对象。对同类型对象抽象出其共性,形成类。类中的大多数数据,只能用本类的方法进行处理。类通过一个简单的外部接口,与外界发生关系,对象与对象之间通过消息进行通讯。这样,程序模块间的关系更为简单,程序模块的独立性、数据的安全性就有了良好的保障。通过实现继承与多态性,还可以大大提高程序的可重用性,使得软件的开发和维护都更为方便。 面向对象方法所强调的基本原则,就是直接面对客观存在的事物来进行软件开发,将人们在日常生活中习惯的思维方式和表达方式应用在软件开发中,使软件开发从过分专业化的方法、规则和技巧中回到客观世界,回到人们通常的思维。 1-5 什么叫做封装? 解: 封装是面向对象方法的一个重要原则,就是把对象的属性和服务结合成一个独立的系统单位,并尽可能隐蔽对象的内部细节。 1-6 面向对象的软件工程包括哪些主要内容? 解: 面向对象的软件工程是面向对象方法在软件工程领域的全面应用,它包括面向对象的分析(OOA)、面向对象的设计(OOD)、面向对象的编程(OOP)、面向对象的测试(OOT)和面向对象的软件维护(OOSM)等主要内容。 1-7 简述计算机内部的信息可分为几类? 解: 计算机内部的信息可以分成控制信息和数据信息二大类;控制信息可分为指令和控制字两类;数据信息可分为数值信息和非数值信息两类。 1-8 什么叫二进制?使用二进制有何优点和缺点? 解: 二进制是基数为2,每位的权是以2 为底的幂的进制,遵循逢二进一原则,基本符号为0和1。采用二进制码表示信息,有如下几个优点:1.易于物理实现;2.二进制数运算简单;3.机器可靠性高;4.通用性强。其缺点是它表示数的容量较小,表示同一个数,二进制较其他进制需要更多的位数。 1-9 请将以下十进制数值转换为二进制和十六进制补码: (1)2 (2)9 (3)93 (4)-32 (5)65535 (6)-1 解: (1) (2)10 = (10)2 = (2)16 (2) (9)10 = (1001)2 = (9)16 (3) (93)10 = (1011101)2 = (5D)16 (4) (-32)10 = (11100000)2 = (E0)16 (5) (65535)10 = (11111111 11111111)2 = (FFFF)16 (6) (-1)10 = (11111111 11111111)2 = (FFFF)16 1-10 请将以下数值转换为十进制: (1)(1010)2 (2)(10001111)2 (3)(01011111 11000011)2 (4)(7F)16 (5)(2D3E)16 (6)(F10E)16 解: (1)(1010)2 = (10)10 (2)(10001111)2 = (143)10 (3)(01011111 11000011)2 = (24515)10 (4)(7F)16 = (127)10 (5)(2D3E)16 = (11582)10 (6)(F10E)16 = (61710)10 1-11 简要比较原码、反码、补码等几种编码方法。 解: 原码:将符号位数字化为 0 或 1,数的绝对值与符号一起编码,即所谓"符号──绝对值表示"的编码。 正数的反码和补码与原码表示相同。 负数的反码与原码有如下关系: 符号位相同(仍用1表示),其余各位取反(0变1,1变0)。 补码由该数反码的最末位加1求得。 第 二 章 C++简单程序设计 2-1 C++语言有那些主要特点和优点? 解: C++语言的主要特点表现在两个方面,一是全面兼容C,二是支持面向对象的方法。C++是一个更好的C,它保持了C的简洁、高效、接近汇编语言、具有良好的可读性和可移植性等特点,对C的类型系统进行了改革和扩充,因此C++比C更安全,C++的编译系统能检查出更多的类型错误。 C++语言最重要的特点是支持面向对象。 2-2 下列标识符哪些是合法的? Program, -page, _lock, test2, 3in1, @mail, A_B_C_D 解: Program, _lock, test2, A_B_C_D是合法的标识符,其它的不是。 2-3 例2.1中每条语句的作用是什么? #include void main(void) { cout<<"Hello!\n"; cout<<"Welcome to c++!\n"; } 解: #include //指示编译器将文件iostream.h中的代码 //嵌入到该程序中该指令所在的地方 void main() //主函数名,void 表示函数没有返回值 { //函数体标志 cout<<"Hello!\n"; //输出字符串Hello!到标准输出设备(显示器)上。 cout<<"Welcome to c++!\n"; //输出字符串Welcome to c++! } 在屏幕输出如下: Hello! Welcome to c++! 2-4 使用关键字const而不是#define语句的好处有哪些? 解: const定义的常量是有类型的,所以在使用它们时编译器可以查错;而且,这些变量在调试时仍然是可见的。 2-5 请写出C++语句声明一个常量PI,值为3.1416;再声明一个浮点型变量a,把PI的值赋给a。 解: const float PI = 3.1416; float a = PI; 2-6 在下面的枚举类型中,Blue的值是多少? enum COLOR { WHITE, BLACK = 100, RED, BLUE, GREEN = 300 }; 解: Blue = 102 2-7 注释有什么作用?C++中有哪几种注释的方法?他们之间有什么区别? 解: 注释在程序中的作用是对程序进行注解和说明,以便于阅读。编译系统在对源程序进行编译时不理会注释部分,因此注释对于程序的功能实现不起任何作用。而且由于编译时忽略注释部分,所以注释内容不会增加最终产生的可执行程序的大小。适当地使用注释,能够提高程序的可读性。在C++中,有两种给出注释的方法:一种是延用C语言方法,使用"/*"和"*/"括起注释文字。另一种方法是使用"//",从"//"开始,直到它所在行的行尾,所有字符都被作为注释处理。 2-8 什么叫做表达式?x = 5 + 7是一个表达式吗?它的值是多少? 解: 任何一个用于计算值的公式都可称为表达式。x = 5 + 7是一个表达式,它的值为12。 2-9 下列表达式的值是多少? 1. 201 / 4 2. 201 % 4 3. 201 / 4.0 解: 1. 50 2. 1 3. 50.25 2-10 执行完下列语句后,a、b、c三个变量的值为多少? a = 30; b = a++; c = ++a; 解: a:32 ; b:30 ; c:32; 2-11 在一个for循环中,可以初始化多个变量吗?如何实现? 解: 在for循环设置条件的第一个";"前,用,分隔不同的赋值表达式。 例如: for (x = 0, y = 10; x < 100; x++, y++) 2-12 执行完下列语句后,n的值为多少? int n; for (n = 0; n < 100; n++) 解: n的值为100 2-13 写一条for语句,计数条件为n从100到200,步长为2;然后用while和do…while语句完成同样的循环。 解: for循环: for (int n = 100; n <= 200; n += 2); while循环: int x = 100; while (n <= 200) n += 2; do…while循环: int n = 100; do { n += 2; } while(n y) x = y; else // y > x || y == x y = x; 2-17 修改下面这个程序中的错误,改正后它的运行结果是什么? #include void main() int i int j; i = 10; /* 给i赋值 j = 20; /* 给j赋值 */ cout << "i + j = << i + j; /* 输出结果 */ return 0; } 解: 改正: #include int main() { int i; int j; i = 10; // 给i赋值 j = 20; /* 给j赋值 */ cout << "i + j = " << i + j; /* 输出结果 */ return 0; } 程序运行输出: i + j = 30 2-18 编写一个程序,运行时提示输入一个数字,再把这个数字显示出来。 解: 源程序: #include int main() { int i; cout <> i; cout << "您输入一个数字是" << i << endl; return 0; } 程序运行输出: 请输入一个数字:5 您输入一个数字是5 2-19 C++有哪几种数据类型?简述其值域。编程显示你使用的计算机中的各种数据类型的字节数。 解: 源程序: #include int main() { cout << "The size of an int is:\t\t" << sizeof(int) << " bytes.\n"; cout << "The size of a short int is:\t" << sizeof(short) << " bytes.\n"; cout << "The size of a long int is:\t" << sizeof(long) << " bytes.\n"; cout << "The size of a char is:\t\t" << sizeof(char) << " bytes.\n"; cout << "The size of a float is:\t\t" << sizeof(float) << " bytes.\n"; cout << "The size of a double is:\t" << sizeof(double) << " bytes.\n"; return 0; } 程序运行输出: The size of an int is: 4 bytes. The size of a short int is: 2 bytes. The size of a long int is: 4 bytes. The size of a char is: 1 bytes. The size of a float is: 4 bytes. The size of a double is: 8 bytes. 2-20 打印ASCII码为32~127的字符。 解: #include int main() { for (int i = 32; i<128; i++) cout << (char) i; return 0; } 程序运行输出: !"#$%G'()*+,./0123456789:;?@ABCDEFGHIJKLMNOP_QRSTUVWXYZ[\]^'abcdefghijklmnopqrstuvwxyz~s 2-21 运行下面的程序,观察其输出,与你的设想是否相同? #include int main() { unsigned int x; unsigned int y = 100; unsigned int z = 50; x= y - z; cout << "Difference is: " << x; x = z - y; cout << "\nNow difference is: " << x <<endl; return 0; } 解: 程序运行输出: Difference is: 50 Now difference is: 4294967246 注意,第二行的输出并非 -50,注意x、y、z的数据类型。 2-22 运行下面的程序,观察其输出,体会i++与++i的差别。 #include int main() { int myAge = 39; // initialize two integers int yourAge = 39; cout << "I am: " << myAge << " years old.\n"; cout << "You are: " << yourAge << " years old\n"; myAge++; // postfix increment ++yourAge; // prefix increment cout << "One year passes...\n"; cout << "I am: " << myAge << " years old.\n"; cout << "You are: " << yourAge << " years old\n"; cout << "Another year passes\n"; cout << "I am: " << myAge++ << " years old.\n"; cout << "You are: " << ++yourAge << " years old\n"; cout << "Let's print it again.\n"; cout << "I am: " << myAge << " years old.\n"; cout << "You are: " << yourAge << " years old\n"; return 0; } 解: 程序运行输出: I am 39 years old You are 39 years old One year passes I am 40 years old You are 40 years old Another year passes I am 40 years old You are 41 years old Let's print it again I am 41 years old You are 41 years old 2-23 什么叫常量?什么叫变量? 解: 所谓常量是指在程序运行的整个过程中其值始终不可改变的量,除了用文字表示常量外,也可以为常量命名,这就是符号常量;在程序的执行过程中其值可以变化的量称为变量,变量是需要用名字来标识的。 2-24 变量有哪几种存储类型? 解: 变量有以下几种存储类型: auto存储类型:采用堆栈方式分配内存空间,属于一时性存储,其存储空间可以被若干变量多次覆盖使用; register存储类型:存放在通用寄存器中; extern存储类型:在所有函数和程序段中都可引用; static存储类型:在内存中是以固定地址存放的,在整个程序运行期间都有效。 2-25 写出下列表达式的值: 1. 2 < 3 && 6 < 9 2. ! ( 4 5) || (6 > 2 解: 1. 1 2. -1 3. 0 4. 0 2-28 编写一个完整的程序,实现功能:向用户提问"现在正在下雨吗?",提示用户输入Y或N。若输入为Y,显示"现在正在下雨。"; 若输入为N,显示"现在没有下雨。";否则继续提问"现在正在下雨吗?" 解: 源程序: #include #include void main() { char flag; while(1) { cout <> flag; if ( toupper(flag) == 'Y') { cout << "现在正在下雨。"; break; } if ( toupper(flag) == 'N') { cout << "现在没有下雨。"; break; } } } 程序运行输出: 现在正在下雨吗?(Yes or No):x 现在正在下雨吗?(Yes or No):l 现在正在下雨吗?(Yes or No):q 现在正在下雨吗?(Yes or No):n 现在没有下雨。 或: 现在正在下雨吗?(Yes or No):y 现在正在下雨。 2-29 编写一个完整的程序,运行时向用户提问"你考试考了多少分?(0~100)",接收输入后判断其等级,显示出来。规则如下: 解: #include void main() { int i,score; cout <> score; if (score>100 || score<0) cout << "分数值必须在0到100之间!"; else { i = score/10; switch (i) { case 10: case 9: cout << "你的成绩为优!"; break; case 8: cout << "你的成绩为良!"; break; case 7: case 6: cout << "你的成绩为中!"; break; default: cout << "你的成绩为差!"; } } } 程序运行输出: 你考试考了多少分?(0~100):85 你的成绩为良! 2-30 (1)实现一个简单的菜单程序,运行时显示"Menu: A(dd) D(elete) S(ort) Q(uit), Select one:"提示用户输入,A表示增加,D表示删除,S表示排序,Q表示退出,输入为A、D、S时分别提示"数据已经增加、删除、排序。"输入为Q时程序结束。要求使用if … else语句进行判断,用break、continue控制程序流程。 解: #include #include void main() { char choice,c; while(1) { cout <> c; choice = toupper(c); if (choice == 'A') { cout << "数据已经增加. " << endl; continue; } else if (choice == 'D') { cout << "数据已经删除. " << endl; continue; } else if (choice == 'S') { cout << "数据已经排序. " << endl; continue; } else if (choice == 'Q') break; } } 程序运行输出: Menu: A(dd) D(elete) S(ort) Q(uit), Select one:a 数据已经增加. Menu: A(dd) D(elete) S(ort) Q(uit), Select one:d 数据已经删除. Menu: A(dd) D(elete) S(ort) Q(uit), Select one:s 数据已经排序. Menu: A(dd) D(elete) S(ort) Q(uit), Select one:q (2)实现一个简单的菜单程序,运行时显示"Menu: A(dd) D(elete) S(ort) Q(uit), Select one:"提示用户输入,A表示增加,D表示删除,S表示排序,Q表示退出,输入为A、D、S时分别提示"数据已经增加、删除、排序。"输入为Q时程序结束。要求使用Switch语句。 解: 源程序: #include #include void main() { char choice; while(1) { cout <> choice; switch(toupper(choice)) { case 'A': cout << "数据已经增加. " << endl; break; case 'D': cout << "数据已经删除. " << endl; break; case 'S': cout << "数据已经排序. " << endl; break; case 'Q': exit(0); break; default: ; } } } 程序运行输出: Menu: A(dd) D(elete) S(ort) Q(uit), Select one:a 数据已经增加. Menu: A(dd) D(elete) S(ort) Q(uit), Select one:d 数据已经删除. Menu: A(dd) D(elete) S(ort) Q(uit), Select one:s 数据已经排序. Menu: A(dd) D(elete) S(ort) Q(uit), Select one:q 2-31 用穷举法找出1~100间的质数,显示出来。分别使用while,do-while,for循环语句实现。 解: 源程序: 使用while循环语句: #include #include void main() { int i,j,k,flag; i = 2; while(i <= 100) { flag = 1; k = sqrt(i); j = 2; while (j <= k) { if(i%j == 0) { flag = 0; break; } j++; } if (flag) cout << i << "是质数." << endl; i++; } } 使用do…while循环语句: #include #include void main() { int i,j,k,flag; i = 2; do{ flag = 1; k = sqrt(i); j = 2; do{ if(i%j == 0) { flag = 0; break; } j++; }while (j <= k); if (flag) cout << i << "是质数." << endl; i++; }while(i <= 100); } 使用for循环语句: #include #include void main() { int i,j,k,flag; for(i = 2; i <= 100; i++) { flag = 1; k = sqrt(i); for (j = 2; j <= k; j++) { if(i%j == 0) { flag = 0; break; } } if (flag) cout << i << "是质数." << endl; } } 程序运行输出: 2是质数. 3是质数. 5是质数. 7是质数. 11是质数. 13是质数. 17是质数. 19是质数. 23是质数. 29是质数. 31是质数. 37是质数. 41是质数. 43是质数. 47是质数. 53是质数. 59是质数. 61是质数. 67是质数. 71是质数. 73是质数. 79是质数. 83是质数. 89是质数. 97是质数. 2-32 比较Break语句与Continue语句的不同用法。 解: Break使程序从循环体和switch语句内跳出,继续执行逻辑上的下一条语句,不能用在别处; continue 语句结束本次循环,接着开始判断决定是否继续执行下一次循环; 2-33 定义一个表示时间的结构体,可以精确表示年、月、日、小时、分、秒;提示用户输入年、月、日、小时、分、秒的值,然后完整地显示出来。 解: 源程序见"实验指导"部分实验二 2-34 在程序中定义一个整型变量,赋以1~100的值,要求用户猜这个数,比较两个数的大小,把结果提示给用户,直到猜对为止。分别使用while、do…while语句实现循环。 解: //使用while语句 #include void main() { int n = 18; int m = 0; while(m != n) { cout <> m; if (n > m) cout << "你猜的值太小了!" << endl; else if (n < m) cout << "你猜的值太大了!" << endl; else cout << "你猜对了!" << endl; } } //使用do…while语句 #include void main() { int n = 18; int m = 0; do{ cout <> m; if (n > m) cout << "你猜的值太小了!" << endl; else if (n < m) cout << "你猜的值太大了!" << endl; else cout << "你猜对了!" << endl; }while(n != m); } 程序运行输出: 请猜这个数的值为多少?(0~~100):50 你猜的值太大了! 请猜这个数的值为多少?(0~~100):25 你猜的值太大了! 请猜这个数的值为多少?(0~~100):10 你猜的值太小了! 请猜这个数的值为多少?(0~~100):15 你猜的值太小了! 请猜这个数的值为多少?(0~~100):18 你猜对了! 2-35 定义枚举类型weekday,包括Sunday到Saturday七个元素在程序中定义weekday类型的变量,对其赋值,定义整型变量,看看能否对其赋weekday类型的值。 解: #include enum weekday { Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday }; void main() { int i; weekday d = Thursday; cout << "d = " << d << endl; i = d; cout << "i = " << i << endl; d = (weekday)6; cout << "d = " << d << endl; d = weekday( 4 ); cout << "d = " << d << endl; } 程序运行输出: d = 4 i = 4 d = 6 d = 4 2-36口袋中有红、黄、蓝、白、黑五种颜色的球若干个,每次从口袋中取出三个不同颜色的球,问有多少种取法。 解: #include using namespace std; int main() { enum color{red,yellow,blue,white,black}; enum color pri; int n,loop,i,j,k; char c; n=0; for(i=red;i<=black;i++) for(j=red;j<=black;j++) if(i!=j) { for(k=red;k<black;k++) if((k!=i)&&(k!=j)) { n=n+1; cout.width(4); cout<<n; for(loop=1;loop<=3;loop++) { switch(loop) { case 1: pri=(enum color)i; break; case 2: pri=(enum color)j; break; case 3: pri=(enum color)k; break; default: break; } switch(pri) { case red:cout<<"red";break; case yellow:cout<<"yellow";break; case blue:cout<<"blue";break; case white:cout<<"white";break; case black:cout<<"black";break; default: break; } } cout<<endl; } } cout<<"total:"<<n<<endl; } 2-37输出九九算表 #include #include using namespace std; int main() { int i,j; for(i=1;i<5;i++) cout<<setw(4)<<i; cout<<endl; cout<<endl; for(i=1;i<5;i++) { for(j=1;j<5;j++) cout<<setw(4)<<(i*j); cout<<endl; } } 第三章 函数 3-1 C++中的函数是什么?什么叫主调函数,什么叫被调函数,二者之间有什么关系?如何调用一个函数? 解: 一个较为复杂的系统往往需要划分为若干子系统,高级语言中的子程序就是用来实现这种模块划分的。C和C++语言中的子程序就体现为函数。调用其它函数的函数被称为主调函数,被其它函数调用的函数称为被调函数。一个函数很可能既调用别的函数又被另外的函数调用,这样它可能在某一个调用与被调用关系中充当主调函数,而在另一个调用与被调用关系中充当被调函数。 调用函数之前先要声明函数原型。按如下形式声明: 类型标识符 被调函数名 (含类型说明的形参表); 声明了函数原型之后,便可以按如下形式调用子函数: 函数名(实参列表) 3-2 观察下面程序的运行输出,与你设想的有何不同?仔细体会引用的用法。 源程序: #include int main() { int intOne; int &rSomeRef; = intOne; intOne = 5; cout << "intOne:\t\t" << intOne << endl; cout << "rSomeRef:\t" << rSomeRef << endl; int intTwo = 8; rSomeRef = intTwo; // not what you think! cout << "\nintOne:\t\t" << intOne << endl; cout << "intTwo:\t\t" << intTwo << endl; cout << "rSomeRef:\t" << rSomeRef << endl; return 0; } 程序运行输出: intOne: 5 rSomeRef: 5 intOne: 8 intTwo: 8 rSomeRef: 8 3-3 比较值调用和引用调用的相同点与不同点。 解: 值调用是指当发生函数调用时,给形参分配内存空间,并用实参来初始化形参(直接将实参的值传递给形参)。这一过程是参数值的单向传递过程,一旦形参获得了值便与实参脱离关系,此后无论形参发生了怎样的改变,都不会影响到实参。 引用调用将引用作为形参,在执行主调函数中的调用语句时,系统自动用实参来初始化形参。这样形参就成为实参的一个别名,对形参的任何操作也就直接作用于实参。 3-4 什么叫内联函数?它有哪些特点? 解: 定义时使用关键字 inline的函数叫做内联函数; 编译器在编译时在调用处用函数体进行替换,节省了参数传递、控制转移等开销; 内联函数体内不能有循环语句和switch语句; 内联函数的定义必须出现在内联函数第一次被调用之前; 对内联函数不能进行异常接口声明; 3-5 函数原型中的参数名与函数定义中的参数名以及函数调用中的参数名必须一致吗? 解: 不必一致,所有的参数是根据位置和类型而不是名字来区分的。 3-6 重载函数时通过什么来区分? 解: 重载的函数的函数名是相同的,但它们的参数的个数和数据类型不同,编译器根据实参和形参的类型及个数的最佳匹配,自动确定调用哪一个函数。 3-7 编写函数,参数为两个unsigned short int型数,返回值为第一个参数除以第二个参数的结果,数据类型为short int;如果第二个参数为0,则返回值为-1。在主程序中实现输入输出。 解: 源程序: #include short int Divider(unsigned short int a, unsigned short int b) { if (b == 0) return -1; else return a/b; } typedef unsigned short int USHORT; typedef unsigned long int ULONG; int main() { USHORT one, two; short int answer; cout <> one; cout <> two; answer = Divider(one, two); if (answer > -1) cout << "Answer: " << answer; else cout << "Error, can't divide by zero!"; return 0; } 程序运行输出: Enter two numbers. Number one:8 Number two:2 Answer: 4 3-8 编写函数把华氏温度转换为摄氏温度,公式为:C = (F - 32) * 5/9; 在主程序中提示用户输入一个华氏温度,转化后输出相应的摄氏温度。 解: 源程序见"实验指导"部分实验三 3-9 编写函数判断一个数是否是质数,在主程序中实现输入、输出。 解: #include #include int prime(int i); //判一个数是否是质数的函数 void main() { int i; cout <> i; if (prime(i)) cout << i << "是质数." << endl; else cout << i << "不是质数." << endl; } int prime(int i) { int j,k,flag; flag = 1; k = sqrt(i); for (j = 2; j <= k; j++) { if(i%j == 0) { flag = 0; break; } } if (flag) return 1; else return 0; } 程序运行输出: 请输入一个整数:1151 1151是质数. 3-10 编写函数求两个整数的最大公约数和最小公倍数。 解: 源程序: #include #include int fn1(int i,int j); //求最大公约数的函数 void main() { int i,j,x,y; cout <> i ; cout <> j ; x = fn1(i,j); y = i * j / x; cout << i << "和" << j << "的最大公约数是:" << x << endl; cout << i << "和" << j << "的最小公倍数是:" << y << endl; } int fn1(int i, int j) { int temp; if (i < j) { temp = i; i = j; j = i; } while(j != 0) { temp = i % j; i = j; j = temp; } return i; } 程序运行输出: 请输入一个正整数:120 请输入另一个正整数:72 120和72的最大公约数是:24 120和72的最小公倍数是:360 3-11 什么叫作嵌套调用?什么叫作递归调用? 解: 函数允许嵌套调用,如果函数1调用了函数2,函数2再调用函数3,便形成了函数的嵌套调用。 函数可以直接或间接地调用自身,称为递归调用。 3-12 在主程序中提示输入整数n,编写函数用递归的方法求1 + 2 + … + n的值。 解: #include #include int fn1(int i); void main() { int i; cout <> i ; cout << "从1累加到" <<i << "的和为:" << fn1(i) << endl; } int fn1(int i) { if (i == 1) return 1; else return i + fn1(i -1); } 程序运行输出: 请输入一个正整数:100 从1累加到100的和为:5050 3-13 编写递归函数GetPower(int x, int y)计算x的y次幂, 在主程序中实现输入输出。 解: 源程序: #include long GetPower(int x, int y); int main() { int number, power; long answer; cout <> number; cout <> power; answer = GetPower(number,power); cout << number << " to the " << power << "th power is " <<answer <2; fib(1) = fib(2) = 1;观察递归调用的过程。 解: 源程序见"实验指导"部分实验三 3-15 用递归的方法编写函数求n阶勒让德多项式的值,在主程序中实现输入、输出; 解: #include float p(int n, int x); void main() { int n,x; cout <> n; cout <> x; cout << "n = " << n << endl; cout << "x = " << x << endl; cout << "P" << n << "(" << x << ") = " << p(n,x) << endl; } float p(int n, int x) { if (n == 0) return 1; else if (n == 1) return x; else return ((2*n-1)*x*p(n-1,x) - (n-1)*p(n-2,x)) /n ; } 程序运行输出: 请输入正整数n:1 请输入正整数x:2 n = 1 x = 2 P1(2) = 2 请输入正整数n:3 请输入正整数x:4 n = 3 x = 4 P3(4) = 154 第 四 章 类 4-1 解释public和private的作用,公有类型成员与私有类型成员有些什么区别? 解: 公有类型成员用public关键字声明,公有类型定义了类的外部接口;私有类型的成员用private关键字声明,只允许本类的函数成员来访问,而类外部的任何访问都是非法的,这样,私有的成员就整个隐蔽在类中,在类的外部根本就无法看到,实现了访问权限的有效控制。 4-2 protected关键字有何作用? 解: protected用来声明保护类型的成员,保护类型的性质和私有类型的性质相似,其差别在于继承和派生时派生类的成员函数可以访问基类的保护成员。 4-3 构造函数和析构函数有什么作用? 解: 构造函数的作用就是在对象被创建时利用特定的值构造对象,将对象初始化为一个特定的状态,使此对象具有区别于彼对象的特征,完成的就是是一个从一般到具体的过程,构造函数在对象创建的时候由系统自动调用。 析构函数与构造函数的作用几乎正好相反,它是用来完成对象被删除前的一些清理工作,也就是专门作扫尾工作的。一般情况下,析构函数是在对象的生存期即将结束的时刻由系统自动调用的,它的调用完成之后,对象也就消失了,相应的内存空间也被释放。 4-4 数据成员可以为公有的吗?成员函数可以为私有的吗? 解: 可以,二者都是合法的。数据成员和成员函数都可以为公有或私有的。但数据成员最好定义为私有的。 4-5 已知class A中有数据成员int a,如果定义了A的两个对象A1、A2,它们各自的数据成员a的值可以不同吗? 解: 可以,类的每一个对象都有自己的数据成员。 4-6 什么叫做拷贝构造函数?拷贝构造函数何时被调用? 解: 拷贝构造函数是一种特殊的构造函数,具有一般构造函数的所有特性,其形参是本类的对象的引用,其作用是使用一个已经存在的对象,去初始化一个新的同类的对象。在以下三种情况下会被调用:在当用类的一个对象去初始化该类的另一个对象时;如果函数的形参是类对象,调用函数进行形参和实参结合时;如果函数的返回值是类对象,函数调用完成返回时; 4-7 拷贝构造函数与赋值运算符(=)有何不同? 解: 赋值运算符(=)作用于一个已存在的对象;而拷贝构造函数会创建一个新的对象。 4-8 定义一个Dog 类,包含的age、weight等属性,以及对这些属性操作的方法。实现并测试这个类。 解: 源程序: #include class Dog { public: Dog (int initialAge = 0, int initialWeight = 5); ~Dog(); int GetAge() { return itsAge;} // inline! void SetAge (int age) { itsAge = age;} // inline! int GetWeight() { return itsWeight;} // inline! void SetWeight (int weight) { itsAge = weight;} // inline! private: int itsAge, itsWeight; }; Dog::Dog(int initialAge, int initialWeight) { itsAge = initialAge; itsWeight = initialWeight; } Dog::~Dog() //destructor, takes no action { } int main() { Dog Jack(2,10); cout << "Jack is a Dog who is " ; cout << Jack.GetAge() << " years old and"; cout << Jack.GetWeight() << " pounds weight.\n"; Jack.SetAge(7); Jack.SetWeight(20); cout << "Now Jack is " ; cout << Jack.GetAge() << " years old and"; cout << Jack.GetWeight() << " pounds weight."; return 0; } 程序运行输出: Jack is a Dog who is 2 years old and 10 pounds weight. Now Jack is 7 years old 20 pounds weight. 4-9 设计并测试一个名为Rectangle的矩形类,其属性为矩形的左下角与右上角两个点的坐标,能计算矩形的面积。 解: 源程序: #include class Rectangle { public: Rectangle (int top, int left, int bottom, int right); ~Rectangle () {} int GetTop() const { return itsTop; } int GetLeft() const { return itsLeft; } int GetBottom() const { return itsBottom; } int GetRight() const { return itsRight; } void SetTop(int top) { itsTop = top; } void SetLeft (int left) { itsLeft = left; } void SetBottom (int bottom) { itsBottom = bottom; } void SetRight (int right) { itsRight = right; } int GetArea() const; private: int itsTop; int itsLeft; int itsBottom; int itsRight; }; Rectangle::Rectangle(int top, int left, int bottom, int right) { itsTop = top; itsLeft = left; itsBottom = bottom; itsRight = right; } int Rectangle::GetArea() const { int Width = itsRight-itsLeft; int Height = itsTop - itsBottom; return (Width * Height); } int main() { Rectangle MyRectangle (100, 20, 50, 80 ); int Area = MyRectangle.GetArea(); cout << "Area: " << Area << "\n"; return 0; } 程序运行输出: Area: 3000 Upper Left X Coordinate: 20 4-10 设计一个用于人事管理的People(人员)类。考虑到通用性,这里只抽象出所有类型人员都具有的属性:number(编号)、sex(性别)、birthday(出生日期)、id(身份证号)等等。其中"出生日期"定义为一个"日期"类内嵌子对象。用成员函数实现对人员信息的录入和显示。要求包括:构造函数和析构函数、拷贝构造函数、内联成员函数、带缺省形参值的成员函数、聚集。 解: 本题用作实验四的选做题,因此不给出答案。 4-11 定义一个矩形类,有长、宽两个属性,有成员函数计算矩形的面积 解: #include class Rectangle { public: Rectangle(float len, float width) { Length = len; Width = width; } ~Rectangle(){}; float GetArea() { return Length * Width; } float GetLength() { return Length; } float GetWidth() { return Width; } private: float Length; float Width; }; void main() { float length, width; cout <> length; cout <> width; Rectangle r(length, width); cout << "长为" << length << "宽为" << width << "的矩形的面积为:" << r.GetArea () << endl; } 程序运行输出: 请输入矩形的长度:5 请输入矩形的宽度:4 长为5宽为4的矩形的面积为:20 4-12 定义一个"数据类型" datatype类,能处理包含字符型、整型、浮点型三种类型的数据,给出其构造函数。 解: #include class datatype{ enum{ character, integer, floating_point } vartype; union { char c; int i; float f; }; public: datatype(char ch) { vartype = character; c = ch; } datatype(int ii) { vartype = integer; i = ii; } datatype(float ff) { vartype = floating_point; f = ff; } void print(); }; void datatype::print() { switch (vartype) { case character: cout << "字符型: " << c << endl; break; case integer: cout << "整型: " << i << endl; break; case floating_point: cout << "浮点型: " << f << endl; break; } } void main() { datatype A('c'), B(12), C(1.44F); A.print(); B.print(); C.print(); } 程序运行输出: 字符型: c 整型: 12 浮点型: 1.44 4-13 定义一个Circle类,有数据成员半径Radius,成员函数GetArea(),计算圆的面积,构造一个Circle的对象进行测试。 解: #include class Circle { public: Circle(float radius){ Radius = radius;} ~Circle(){} float GetArea() { return 3.14 * Radius * Radius; } private: float Radius; }; void main() { float radius; cout <> radius; Circle p(radius); cout << "半径为" << radius << "的圆的面积为:" << p.GetArea () << endl; } 程序运行输出: 请输入圆的半径:5 半径为5的圆的面积为:78.5 4-14 定义一个tree类,有成员ages,成员函数grow(int years)对ages加上years,age()显示tree对象的ages的值。 解: #include class Tree { int ages; public: Tree(int n=0); ~Tree(); void grow(int years); void age(); }; Tree::Tree(int n) { ages = n; } Tree::~Tree() { age(); } void Tree::grow(int years) { ages += years; } void Tree::age() { cout << "这棵树的年龄为" << ages << endl; } void main() { Tree t(12); t.age(); t.grow(4); } 程序运行输出: 这棵树的年龄为12 这棵树的年龄为16 第 五 章 C++程序的基本结构 5-1 什么叫做作用域?有哪几种类型的作用域? 解: 作用域讨论的是标识符的有效范围,作用域是一个标识符在程序正文中有效的区域。C++的作用域分为函数原形作用域、块作用域(局部作用域)、类作用域和文件作用域. 5-2 什么叫做可见性?可见性的一般规则是什么? 解: 可见性是标识符是否可以引用的问题; 可见性的一般规则是:标识符要声明在前,引用在后,在同一作用域中,不能声明同名的标识符。对于在不同的作用域声明的标识符,遵循的原则是:若有两个或多个具有包含关系的作用域,外层声明的标识符如果在内层没有声明同名标识符时仍可见,如果内层声明了同名标识符则外层标识符不可见。 5-3 下面的程序的运行结果是什么,实际运行一下,看看与你的设想有何不同。 #include void myFunction(); int x = 5, y = 7; int main() { cout << "x from main: " << x << "\n"; cout << "y from main: " << y << "\n\n"; myFunction(); cout << "Back from myFunction!\n\n"; cout << "x from main: " << x << "\n"; cout << "y from main: " << y << "\n"; return 0; } void myFunction() { int y = 10; cout << "x from myFunction: " << x << "\n"; cout << "y from myFunction: " << y << "\n\n"; } 解: 程序运行输出: x from main: 5 y from main: 7 x from myFunction: 5 y from myFunction: 10 Back from myFunction! x from main: 5 y from main: 7 5-4 假设有两个无关系的类Engine和Fuel,使用时,怎样允许Fuel成员访问Engine中的私有和保护的成员? 解: 源程序: class fuel; class engine { friend class fuel; private; int powerlevel; public; engine(){ powerLevel = 0;} void engine_fn(fuel &f); }; class fuel { friend class engine; private; int fuelLevel; public: fuel(){ fuelLevel = 0;} void fuel_fn( engine &e); }; 5-5 什么叫做静态数据成员?它有何特点? 解: 类的静态数据成员是类的数据成员的一种特例,采用static关键字来声明。对于类的普通数据成员,每一个类的对象都拥有一个拷贝,就是说每个对象的同名数据成员可以分别存储不同的数值,这也是保证对象拥有自身区别于其它对象的特征的需要,但是静态数据成员,每个类只要一个拷贝,由所有该类的对象共同维护和使用,这个共同维护、使用也就实现了同一类的不同对象之间的数据共享。 5-6 什么叫做静态函数成员?它有何特点? 解: 使用static关键字声明的函数成员是静态的,静态函数成员属于整个类,同一个类的所有对象共同维护,为这些对象所共享。静态函数成员具有以下两个方面的好处,一是由于静态成员函数只能直接访问同一个类的静态数据成员,可以保证不会对该类的其余数据成员造成负面影响;二是同一个类只维护一个静态函数成员的拷贝,节约了系统的开销,提高程序的运行效率。 5-7 定义一个Cat类,拥有静态数据成员HowManyCats,记录Cat的个体数目;静态成员函数GetHowMany(),存取HowManyCats。设计程序测试这个类,体会静态数据成员和静态成员函数的用法。 解: 源程序: #include class Cat { public: Cat(int age):itsAge(age){HowManyCats++; } virtual ~Cat() { HowManyCats--; } virtual int GetAge() { return itsAge; } virtual void SetAge(int age) { itsAge = age; } static int GetHowMany() { return HowManyCats; } private: int itsAge; static int HowManyCats; }; int Cat::HowManyCats = 0; void TelepathicFunction(); int main() { const int MaxCats = 5; Cat *CatHouse[MaxCats]; int i; for (i = 0; i<MaxCats; i++) { CatHouse[i] = new Cat(i); TelepathicFunction(); } for ( i = 0; i<MaxCats; i++) { delete CatHouse[i]; TelepathicFunction(); } return 0; } void TelepathicFunction() { cout << "There are " << Cat::GetHowMany() << " cats alive!\n"; } 程序运行输出: There are 1 cats alive! There are 2 cats alive! There are 3 cats alive! There are 4 cats alive! There are 5 cats alive! There are 4 cats alive! There are 3 cats alive! There are 2 cats alive! There are 1 cats alive! There are 0 cats alive! 5-8 什么叫做友元函数?什么叫做友元类? 解: 友元函数是使用friend关键字声明的函数,它可以访问相应类的保护成员和私有成员。友元类是使用friend关键字声明的类,它的所有成员函数都是相应类的友元函数。 5-9 如果类A是类B的友元,类B是类C的友元,类D是类A的派生类,那么类B是类A的友元吗?类C是类A的友元吗?类D是类B的友元吗? 解: 类B不是类A的友元,友元关系不具有交换性; 类C不是类A的友元,友元关系不具有传递性; 类D不是类B的友元,友元关系不能被继承。 5-10 静态成员变量可以为私有的吗?声明一个私有的静态整型成员变量。 解: 可以,例如: private: static int a; 5-11 在一个文件中定义一个全局变量n,主函数main(),在另一个文件中定义函数fn1(),在main()中对n赋值,再调用fn1(),在fn1()中也对n赋值,显示n最后的值。 解: #include #include "fn1.h" int n; void main() { n = 20; fn1(); cout << "n的值为" <<n; } // fn1.h文件 extern int n; void fn1() { n=30; } 程序运行输出: n的值为30 5-12 在函数fn1()中定义一个静态变量n,fn1()中对n的值加1,在主函数中,调用fn1()十次,显示n的值。 解: #include void fn1() { static int n = 0; n++; cout << "n的值为" << n <<endl; } void main() { for(int i = 0; i i =+10; } void Y::g(X* x) { x->i ++; } class Z { public: void f(X* x) { x->i += 5; } }; #endif // MY_X_Y_Z_H 程序运行输出:无 5-14 定义Boat与Car两个类,二者都有weight属性,定义二者的一个友元函数totalWeight(),计算二者的重量和。 解: 源程序: #include class Boat; class Car { private: int weight; public: Car(int j){weight = j;} friend int totalWeight(Car &aCar;, Boat &aBoat;); }; class Boat { private: int weight; public: Boat(int j){weight = j;} friend int totalWeight(Car &aCar;, Boat &aBoat;); }; int totalWeight(Car &aCar;, Boat &aBoat;) { return aCar.weight + aBoat.weight; } void main() { Car c1(4); Boat b1(5); cout << totalWeight(c1, b1) << endl; } 程序运行输出: 9 第 六 章 数组、指针与字符串 6-1 数组A[10][5][15]一共有多少个元素? 解: 10×5×15 = 750 个元素 6-2 在数组A[20]中第一个元素和最后一个元素是哪一个? 解: 第一个元素是A[0],最后一个元素是A[19]。 6-3 用一条语句定义一个有五个元素的整型数组,并依次赋予1~5的初值。 解: 源程序: int IntegerArray[5] = { 1, 2, 3, 4, 5 }; 或:int IntegerArray[] = { 1, 2, 3, 4, 5 }; 6-4 已知有一个数组名叫oneArray,用一条语句求出其元素的个数。 解: 源程序: nArrayLength = sizeof(oneArray) / sizeof(oneArray[0]); 6-5 用一条语句定义一个有5×3个元素的二维整型数组,并依次赋予1~15的初值。 解: 源程序: int theArray[5][3] = { 1,2,3,4,5,6,7,8,9,10,11,12,13,14,15 }; 或:int theArray[5][3] = { {1,2,3}, {4,5,6}, {7,8,9}, {10,11,12},{13,14,15} }; 6-6 运算符*和&的作用是什么? 解: *称为指针运算符,是一个一元操作符,表示指针所指向的对象的值;&称为取地址运算符,也是一个一元操作符,是用来得到一个对象的地址。 6-7 什么叫做指针?指针中储存的地址和这个地址中的值有何区别? 解: 指针是一种数据类型,具有指针类型的变量称为指针变量。指针变量存放的是另外一个对象的地址,这个地址中的值就是另一个对象的内容。 6-8 定义一个整型指针,用new语句为其分配包含10个整型元素的地址空间。 解: 源程序: int *pInteger = new int[10]; 6-9 在字符串”Hello,world!”中结束符是什么? 解: 是NULL字符。 6-10 定义一个有五个元素的整型数组,在程序中提示用户输入元素值,最后再在屏幕上显示出来。 解: 源程序: #include int main() { int myArray[5]; int i; for ( i=0; i<5; i++) { cout << "Value for myArray[" << i <> myArray[i]; } for (i = 0; i<5; i++) cout << i << ": " << myArray[i] << "\n"; return 0; } 程序运行输出: Value for myArray[0]: 2 Value for myArray[1]: 5 Value for myArray[2]: 7 Value for myArray[3]: 8 Value for myArray[4]: 3 0: 2 1: 5 2: 7 3: 8 4: 3 6-11 引用和指针有何区别?何时只能使用指针而不能使用引用? 解: 引用是一个别名,不能为NULL值,不能被重新分配;指针是一个存放地址的变量。当需要对变量重新赋以另外的地址或赋值为NULL时只能使用指针。 6-12 声明下列指针:float类型变量的指针pFloat,char类型的指针pString和struct customer型的指针prec。 解: float *pfloat; char *pString; struct customer *prec; 6-13 给定float类型的指针fp,写出显示fp所指向的值的输出流语句。 解: cout << "Value == " << *fp; 6-14 程序中定义一个double类型变量的指针。分别显示指针占了多少字节和指针所指的变量占了多少字节。 解: double *counter; cout << "\nSize of pointer == "sizeof(counter); cout << '\nSize of addressed value == "<<sizeof(*counter); 6-15 const int * p1 和 int * const p2的区别是什么? 解: const int * p1 声明了一个指向整型常量的指针p1,因此不能通过指针p1来改变它所指向的整型值;int * const p2声明了一个指针型常量,用于存放整型变量的地址,这个指针一旦初始化后,就不能被重新赋值了。 6-16 定义一个整型变量a,一个整型指针p,一个引用r,通过p把a的值改为10,通过r把a的值改为5 解: void main() { int a; int *p = &a; int &r = a; *p = 10; r = 5; } 6-17 下列程序有何问题,请仔细体会使用指针时应避免出现这个的问题。 #include int main() { int *p; *pInt = 9; cout << "The value at p: " << *p; return 0; } 解: 指针p没有初始化,也就是没有指向某个确定的内存单元,它指向内存中的一个随机地址,给这个随机地址赋值是非常危险的。 6-18 下列程序有何问题,请改正;仔细体会使用指针时应避免出现的这个问题。 #include int Fn1(); int main() { int a = Fn1(); cout << "the value of a is: " << a; return 0; } int Fn1() { int * p = new int (5); return *p; } 解: 此程序中给*p分配的内存没有被释放掉。 改正: #include int* Fn1(); int main() { int *a = Fn1(); cout << "the value of a is: " << *a; delete a; return 0; } int* Fn1() { int * p = new int (5); return p; } 6-19 声明一个参数为整型,返回值为长整型的函数指针;声明类A的一个成员函数指针,其参数为整型,返回值长整型。 解: long (* p_fn1)(int); long ( A::*p_fn2)(int); 6-20 实现一个名为SimpleCircle的简单圆类,其数据成员int *itsRadius为一个指向其半径值的指针,设计对数据成员的各种操作,给出这个类的完整实现并测试这个类。 解: 源程序: #include class SimpleCircle { public: SimpleCircle(); SimpleCircle(int); SimpleCircle(const SimpleCircle &); ~SimpleCircle() {} void SetRadius(int); int GetRadius()const; private: int *itsRadius; }; SimpleCircle::SimpleCircle() { itsRadius = new int(5); } SimpleCircle::SimpleCircle(int radius) { itsRadius = new int(radius); } SimpleCircle::SimpleCircle(const SimpleCircle & rhs) { int val = rhs.GetRadius(); itsRadius = new int(val); } int SimpleCircle::GetRadius() const { return *itsRadius; } int main() { SimpleCircle CircleOne, CircleTwo(9); cout << "CircleOne: " << CircleOne.GetRadius() << endl; cout << "CircleTwo: " << CircleTwo.GetRadius() << endl; return 0; }程序运行输出: CircleOne: 5 CircleTwo: 9 6-21 编写一个函数,统计一个英文句子中字母的个数,在主程序中实现输入、输出。 解: 源程序: #include #include int count(char *str) { int i,num=0; for (i=0; str[i]; i++) { if ( (str[i]>='a' && str[i]='A' && str[i]<='Z') ) num++; } return num; } void main() { char text[100]; cout << "输入一个英语句子:" << endl; gets(text); cout << "这个句子里有" << count(text) << "个字母。" << endl; } 程序运行输出: 输入一个英语句子: It is very interesting! 这个句子里有19个字母。 6-22 编写函数int index(char *s, char *t),返回字符串t 在字符串s中出现的最左边的位置,如果在s中没有与t匹配的子串,就返回-1。 解: 源程序: #include int index( char *s, char *t) { int i,j,k; for(i = 0; s[i] != '\0'; i++) { for(j = i, k = 0; t[k] != '\0' && s[j] == t[k]; j++, k++) ; if (t[k] =='\0') return i; } return -1; } void main() { int n; char str1[20],str2[20]; cout <> str1; cout <> str2; n = index(str1,str2); if (n > 0) cout << str2 << "在" << str1 << "中左起第" << n+1 << "个位置。"<<endl; else cout << str2 << "不在" << str1 << "中。" << endl; } 程序运行输出: 输入一个英语单词:abcdefgh 输入另一个英语单词:de de在abcdefghijk中左起第4个位置。 6-23 编写函数reverse(char *s)的倒序递归程序,使字符串s倒序。 解: 源程序: #include #include void reverse(char *s, char *t) { char c; if (s < t) { c = *s; *s = *t; *t = c; reverse(++s, --t); } } void reverse( char *s) { reverse(s, s + strlen(s) - 1); } void main() { char str1[20]; cout <> str1; cout << "原字符串为:" << str1 << endl; reverse(str1); cout << "倒序反转后为:" << str1 << endl; } 程序运行输出: 输入一个字符串:abcdefghijk 原字符串为:abcdefghijk 倒序反转后为:kjihgfedcba 6-24 设学生人数N=8,提示用户输入N个人的考试成绩,然后计算出平均成绩,显示出来。 解: 源程序: #include #include #define N 8 float grades[N]; //存放成绩的数组 void main() { int i; float total,average; //提示输入成绩 for(i = 0; i < N; i++ ) { cout << "Enter grade #" <<(i +1) <> grades[i]; } total = 0; for (i = 0; i < N; i++) total += grades[i]; average = total / N; cout << "\nAverage grade: " << average << endl; } 程序运行输出: Enter grade #1: 86 Enter grade #2: 98 Enter grade #3: 67 Enter grade #4: 80 Enter grade #5: 78 Enter grade #6: 95 Enter grade #7: 78 Enter grade #8: 56 Average grade: 79.75 6-25 设计一个字符串类MyString,具有构造函数、析构函数、拷贝构造函数,重载运算符+、=、+=、[],尽可能地完善它,使之能满足各种需要。(运算符重载功能为选做,参见第8章) 解: #include #include class MyString { public: MyString(); MyString(const char *const); MyString(const MyString &); ~MyString(); char & operator[](unsigned short offset); char operator[](unsigned short offset) const; MyString operator+(const MyString&); void operator+=(const MyString&); MyString & operator= (const MyString &); unsigned short GetLen()const { return itsLen; } const char * GetMyString() const { return itsMyString; } private: MyString (unsigned short); // private constructor char * itsMyString; unsigned short itsLen; }; MyString::MyString() { itsMyString = new char[1]; itsMyString[0] = '\0'; itsLen=0; } MyString::MyString(unsigned short len) { itsMyString = new char[len+1]; for (unsigned short i = 0; i<=len; i++) itsMyString[i] = '\0'; itsLen=len; } MyString::MyString(const char * const cMyString) { itsLen = strlen(cMyString); itsMyString = new char[itsLen+1]; for (unsigned short i = 0; i<itsLen; i++) itsMyString[i] = cMyString[i]; itsMyString[itsLen]='\0'; } MyString::MyString (const MyString & rhs) { itsLen=rhs.GetLen(); itsMyString = new char[itsLen+1]; for (unsigned short i = 0; i<itsLen;i++) itsMyString[i] = rhs[i]; itsMyString[itsLen] = '\0'; } MyString::~MyString () { delete [] itsMyString; itsLen = 0; } MyString& MyString::operator=(const MyString & rhs) { if (this == &rhs;) return *this; delete [] itsMyString; itsLen=rhs.GetLen(); itsMyString = new char[itsLen+1]; for (unsigned short i = 0; i itsLen) return itsMyString[itsLen-1]; else return itsMyString[offset]; } char MyString::operator[](unsigned short offset) const { if (offset > itsLen) return itsMyString[itsLen-1]; else return itsMyString[offset]; } MyString MyString::operator+(const MyString& rhs) { unsigned short totalLen = itsLen + rhs.GetLen(); MyString temp(totalLen); for (unsigned short i = 0; i<itsLen; i++) temp[i] = itsMyString[i]; for (unsigned short j = 0; j<rhs.GetLen(); j++, i++) temp[i] = rhs[j]; temp[totalLen]='\0'; return temp; } void MyString::operator+=(const MyString& rhs) { unsigned short rhsLen = rhs.GetLen(); unsigned short totalLen = itsLen + rhsLen; MyString temp(totalLen); for (unsigned short i = 0; i<itsLen; i++) temp[i] = itsMyString[i]; for (unsigned short j = 0; j<rhs.GetLen(); j++, i++) temp[i] = rhs[i-itsLen]; temp[totalLen]='\0'; *this = temp; } int main() { MyString s1("initial test"); cout << "S1:\t" << s1.GetMyString() << endl; char * temp = "Hello World"; s1 = temp; cout << "S1:\t" << s1.GetMyString() << endl; char tempTwo[20]; strcpy(tempTwo,"; nice to be here!"); s1 += tempTwo; cout << "tempTwo:\t" << tempTwo << endl; cout << "S1:\t" << s1.GetMyString() << endl; cout << "S1[4]:\t" << s1[4] << endl; s1[4]='x'; cout << "S1:\t" << s1.GetMyString() << endl; cout << "S1[999]:\t" << s1[999] << endl; MyString s2(" Another myString"); MyString s3; s3 = s1+s2; cout << "S3:\t" << s3.GetMyString() << endl; MyString s4; s4 = "Why does this work?"; cout << "S4:\t" << s4.GetMyString() << endl; return 0; } 程序运行输出: S1: initial test S1: Hello World tempTwo: ; nice to be here! S1: Hello World; nice to be here! S1[4]: o S1: Hellx World; nice to be here! S1[999]: ! S3: Hellx World; nice to be here! Another myString S4: Why does this work? 6-26 编写一个3×3矩阵转置的函数,在main()函数中输入数据。 解: #include void move (int matrix[3][3]) { int i, j, k; for(i=0; i<3; i++) for (j=0; j<i; j++) { k = matrix[i][j]; matrix[i][j] = matrix[j][i]; matrix[j][i] = k; } } void main() { int i, j; int data[3][3]; cout << "输入矩阵的元素" << endl; for(i=0; i<3; i++) for (j=0; j<3; j++) { cout << "第" << i+1 << "行第" << j+1 <> data[i][j]; } cout << "输入的矩阵的为:" << endl; for(i=0; i<3; i++) { for (j=0; j<3; j++) cout << data[i][j] << " "; cout << endl; } move(data); cout << "转置后的矩阵的为:" << endl; for(i=0; i<3; i++) { for (j=0; j<3; j++) cout << data[i][j] << " "; cout << endl; } } 程序运行输出: 输入矩阵的元素 第1行第1个元素为:1 第1行第2个元素为:2 第1行第3个元素为:3 第2行第1个元素为:4 第2行第2个元素为:5 第2行第3个元素为:6 第3行第1个元素为:7 第3行第2个元素为:8 第3行第3个元素为:9 输入的矩阵的为: 1 2 3 4 5 6 7 8 9 转置后的矩阵的为: 1 4 7 2 5 8 3 6 9 6-27 编写一个矩阵转置的函数,矩阵的维数在程序中由用户输入。 解: #include void move (int *matrix ,int n) { int i, j, k; for(i=0; i<n; i++) for (j=0; j<i; j++) { k = *(matrix + i*n + j); *(matrix + i*n + j) = *(matrix + j*n + i); *(matrix + j*n + i) = k; } } void main() { int n, i, j; int *p; cout <> n; p = new int[n*n]; cout << "输入矩阵的元素" << endl; for(i=0; i<n; i++) for (j=0; j<n; j++) { cout << "第" << i+1 << "行第" << j+1 <> p[i*n + j]; } cout << "输入的矩阵的为:" << endl; for(i=0; i<n; i++) { for (j=0; j<n; j++) cout << p[i*n + j] << " "; cout << endl; } move(p, n); cout << "转置后的矩阵的为:" << endl; for(i=0; i<n; i++) { for (j=0; j<n; j++) cout << p[i*n + j] << " "; cout << endl; } } 程序运行输出: 请输入矩阵的维数:3 输入矩阵的元素 第1行第1个元素为:1 第1行第2个元素为:2 第1行第3个元素为:3 第2行第1个元素为:4 第2行第2个元素为:5 第2行第3个元素为:6 第3行第1个元素为:7 第3行第2个元素为:8 第3行第3个元素为:9 输入的矩阵的为: 1 2 3 4 5 6 7 8 9 转置后的矩阵的为: 1 4 7 2 5 8 3 6 9 6-28 定义一个Employee类,其中包括表示姓名、街道地址、城市和邮编等属性,包括chage_name()和display()等函数;display()使用cout语句显示姓名、街道地址、城市和邮编等属性,函数change_name()改变对象的姓名属性,实现并测试这个类。 解: 源程序: #include #include class Employee { private: char name[30]; char street[30]; char city[18]; char zip[6]; public: Employee(char *n, char *str, char *ct, char *z); void change_name(char *n); void display(); }; Employee::Employee (char *n,char *str,char *ct, char *z) { strcpy(name, n); strcpy(street, str); strcpy(city, ct); strcpy(zip, z); } void Employee::change_name (char *n) { strcpy(name, n); } void Employee::display () { cout << name << " " << street << " "; cout << city << " "<< zip; } void main(void) { Employee e1("张三","平安大街3号", "北京", "100000"); e1.display(); cout << endl; e1.change_name("李四"); e1.display(); cout << endl; } 程序运行输出: 张三 平安大街3号 北京 100000 李四 平安大街3号 北京 100000 第 七 章 继承与派生 7-1 比较类的三种继承方式public公有继承、protected保护继承、private私有继承之间的差别。 解: 不同的继承方式,导致不同访问属性的基类成员在派生类中的访问属性也有所不同: 公有继承,使得基类public(公有)和protected(保护)成员的访问属性在派生类中不变,而基类private(私有)成员不可访问。 私有继承,使得基类public(公有)和protected(保护)成员都以private(私有)成员身份出现在派生类中,而基类private(私有)成员不可访问。 保护继承中,基类public(公有)和protected(保护)成员都以protected(保护)成员身份出现在派生类中,而基类private(私有)成员不可访问。 7-2 派生类构造函数执行的次序是怎样的? 解: 派生类构造函数执行的一般次序为:调用基类构造函数;调用成员对象的构造函数;派生类的构造函数体中的内容。 7-3 如果在派生类B已经重载了基类A的一个成员函数fn1(),没有重载成员函数fn2(),如何调用基类的成员函数fn1()、fn2()? 解: 调用方法为: A::fn1(); fn2(); 7-4 什么叫做虚基类?有何作用? 解: 当某类的部分或全部直接基类是从另一个基类派生而来,这些直接基类中,从上一级基类继承来的成员就拥有相同的名称,派生类的对象的这些同名成员在内存中同时拥有多个拷贝,我们可以使用作用域分辨符来唯一标识并分别访问它们。我们也可以将直接基类的共同基类设置为虚基类,这时从不同的路径继承过来的该类成员在内存中只拥有一个拷贝,这样就解决了同名成员的唯一标识问题。 虚基类的声明是在派生类的定义过程,其语法格式为: class 派生类名:virtual 继承方式 基类名 上述语句声明基类为派生类的虚基类,在多继承情况下,虚基类关键字的作用范围和继承方式关键字相同,只对紧跟其后的基类起作用。声明了虚基类之后,虚基类的成员在进一步派生过程中,和派生类一起维护一个内存数据拷贝。 7-5 定义一个Shape基类,在此基础上派生出Rectangle和Circle,二者都有GetArea()函数计算对象的面积。使用Rectangle类创建一个派生类Square。 解: 源程序: #include class Shape { public: Shape(){} ~Shape(){} virtual float GetArea() { return -1; } }; class Circle : public Shape { public: Circle(float radius):itsRadius(radius){} ~Circle(){} float GetArea() { return 3.14 * itsRadius * itsRadius; } private: float itsRadius; }; class Rectangle : public Shape { public: Rectangle(float len, float width): itsLength(len), itsWidth(width){}; ~Rectangle(){}; virtual float GetArea() { return itsLength * itsWidth; } virtual float GetLength() { return itsLength; } virtual float GetWidth() { return itsWidth; } private: float itsWidth; float itsLength; }; class Square : public Rectangle { public: Square(float len); ~Square(){} }; Square::Square(float len): Rectangle(len,len) { } void main() { Shape * sp; sp = new Circle(5); cout << "The area of the Circle is " <GetArea () << endl; delete sp; sp = new Rectangle(4,6); cout << "The area of the Recta
本科生期末试卷十一 一.选择题(每小题1分,共10分) 1.目前大多数集成电路生产中,所采用的基本材料为___a___。 A.单晶硅 B.非晶硅 C.锑化钼 D.硫化镉 2. 用16位字长(其中一位符号位)表示定点小数时,所能表示的数值范围是___c___。 A.0≤│N│≤1-2-(16+1) B.0≤│N│≤1-2-16 C.0≤│N│≤1-2-(16-1) D.0≤│N│≤1 3. 运算器虽有许多部件组成,但核心部件是___b___。 A.数据总线 B.算术逻辑运算单元 C.多路开关 D.累加寄存器 4. 某计算机字长32位,其存储容量为4MB,若按字编址,它的寻址范围是___a___。 A.0--1M B.0--4MB C.0--4M D.0-¬-1MB 5. 常用的虚拟存贮系统由___a___两级存贮器组成,其中辅存是大容量的磁表面存贮器。 A.主存-辅存 B.快存-主存 C.快存-辅存 D.通用寄存器-主存 6. 单地址指令中为了完成两个数的算术运算,除地址码指明的一个操作数以外,另一个数常需采用___c___。 A.堆栈寻址方式 B.立即寻址方式 C.隐含寻址方式 D.间接寻址方式 7. 为确定下一条微指令的地址,通常采用断定方式,其基本思想是___c___。 A.用程序计数器PC来产生后继微指令地址 B.用微程序计数器μPC来产生后继微指令地址 C.通过微指令顺序控制字段由设计者指定或由设计者指定的判别字段控制产生后继微指令地址 D.通过指令中指定一个专门字段来控制产生后继微指令地址 8. 描述PCI总线中基本概念不正确的句子是___c_d__。 A.PCI总线是一个与处理器无关的高速外围总线 B.PCI总线的基本传输机制是猝发式传送 C.PCI设备一定是主设备 D.系统中只允许有一条PCI总线 9. 为了使设备相对独立,磁盘控制器的功能全部转移到设备中,主机与设备间采用____a__接口。 A.SCSI B.专用 C.ESDI D.RISC 10. I/O标准接口SCSI中,一块主适配器可以连接___b___台具有SCSI接口的设备。 A.6 B.7 C.8 D.10 二.填空题(每小题3分,共24分) 1.IEEE754标准,一个浮点数由A___符号位___、阶码E、尾数M三个域组成。其中阶码E的值等于指数的B___真值___加上一个固定C___偏移量___。 2. 相联存储器不按地址而是按A___内容___访问的存储器,在cache中用来存放B___行地址表___,在虚拟存储器中用来存放C___页表快表___。 3. 指令操作码字段表征指令的A___操作特性和功能___,而地址码字段指示B___操作数地址___。微小型机中多采用C___二地址 单地址 0地址___混合方式的指令格式。 4. CPU从A___存储器___取出一条指令并执行这条指令的时间和称为B___取指周期___。由于各种指令的操作功能不同,各种指令的时间和是不同的,但在流水线CPU中要力求做到C___一致___。 5. 微型计算机的标准总线从16位的A___ISA___总线发展到32位的B___eisa___总线,又进一步发展到64位的C___pci___总线。 6. 显示适配器作为CRT和CPU的接口由A___刷新___存储器、B___显示___控制器、C___rombios___三部分组成。 7. 根据地址格式不同,虚拟存贮器分为A___页式___、B___段式___和C___段页式___三种。 8. CPU从主存取出一条指令并执行该指令的时间叫做A___取指周期___,它常用若干个B___机器周期___来表示,而后者又包含有若干个C___时钟周期___。 三.应用题 1.(11 分)图B11.1为某ALU部件的内部逻辑图,图中S0、S1为功能选择控制端,Cin为最低位的进位输入端,A(A1-A4)和B(B1-B4)是参与运算的两个数,F(F1-F4)为输出结果,试分析在S0,S1,Cin各种组合条件下输出F和输入A,B,Cin的算术关系。 图B11.1 2.(11分)设有两个浮点数x=2Ex×Sx,y=2Ey×Sy,Ex=(-10)2,Sx=(+0.1001)2,Ey=(+10)2,Sy=(+0.1011)2。若尾数4位,数符1位,阶码2位,阶符1位,求x+y=?并写出运算步骤及结果。 3.(11分)机字长32位,常规设计的存储空间≤32M,若将存储空间扩展到256M, 请提出一种可能方案。 4.(11分)今有4级流水线分别完成取值、指令译码并取数、运算、送结果四步操作, 今假设完成各步操作的时间依次为100ns,100ns,80ns,50ns。 请问:(1)流水线的操作周期应设计为多少? (2)若相邻两条指令发生数据相关,而且在硬件上不采取措施,那么第二条指令要推迟多少时间进行。 (3)如果在硬件设计上加以改进,至少需推迟多少时间? 5.(11分)画出PCI总线结构框图,说明HOST总线、PCI总线、LAGACY总线的功能。 6.(11分)若设备的优先级依次为CD-ROM、扫描仪、硬盘、磁带机、打印机,请用标 准接口SCSI进行配置,画出配置图。
一、单项选择题(本大题共10小题,每小题1分,共10分) 在每小题列出的四个备选项中只有一个是符合题目要求的,请将其代码填写在题后的括号内.错选、多选或未选均无分. 1.速率为fb的NRZ码经4B1H码型变换后,其线路码的速率为(  ) A.1.25fb B.1.2fb C.fb D.0.8fb ? 2.通常,影响光接收机灵敏度的主要因素是(  ) A.光纤色散 B.噪声 C.光纤衰减 D.光缆线路长度 3.STM-1一帧的字节数为(  ) A.9×270×N B.9×261×N C.9×270 D.9×261 4.在薄膜波导中,导波的轴向相位常数k1z=(  ) A.k0sinθ1 B.k0n1θ1 C.n1θ1 D.k0n1sinθ1 5.在阶跃型光纤中,当导波处于截止的临界状态时,其特性参数(  ) A.W=0 B.β=0 C.V=0 D.U=0 ? 6.目前,掺铒光纤放大器噪声系数可低至(  ) A.-3dB~0dB B.0dB~3dB C.3dB~4dB D.10dB~15dB 7.不属于半导体激光器特性参数的是(  ) A.输出光功率 B.阈值电流 C.转换效率 D.消光比 光发射机的 8.光纤衰减系数的单位是(  ) A.dB B.dBm C.dBm/km D.dB/km ? 9.在EDFA中,用于降低放大器噪声的器件是(  ) A.光耦合器 B.波分复用器 C.光滤波器 D.光隔离器 10.薄膜波导中,导波的基模是(  ) A.TE0 B.TM0 C.TE1 D.TM1 二、填空题(本大题共20小题,每小题1分,共20分) 请在每小题的空格中填上正确答案.错填、不填均无分. 11.在光纤通信系统中起主导作用的是光源、__光电检测器___?和光缆线路等三种部件. 12.在光(电磁波)的传播形态中,TEM波的含义是__在传播方向上没有电场和磁场分量__(横电磁波)______. 13.在薄膜波导中,可能产生的三种类型的波是导波、__衬底辐射模_和敷层辐射模. 14.对称薄膜波导中截止波长的表达式为_2∏d/m 乘以根号下N12-N22_________. 15.光纤中的传输信号由于受到光纤衰减和色散的影响,使得信号的幅度受到衰减,波形_畸变___? 16.所谓光纤的最佳折射指数分布是指__能够产生自聚焦现象的折射率分布. 17.常用通信光缆的缆芯结构有层绞式、单位式、_带状式_和骨架式等几种. 18.激光器主要由能够产生激光的工作物质、__泵浦源_和光学谐振腔等三部分组成. 19.光发射机的消光比过大,会使接收机的_灵敏度 ?特性变坏. 20.光发射机中,光源过流保护电路_的作用是使光源不至于因通过的电流过大而损坏. 21.半导体P-N结上外加负偏电压产生的电场方向与_内建电场__方向一致,这有利于耗尽层的加宽. 22.光接收机的灵敏度和__动态范围_是光接收机的两个重要特性指标. 23.光定向耦合器的主要特性参数有:插入损耗、分光比和___隔离度(A)等. 24.利用光纤来传输光纤通信系统的监控信号时,通常可采用时分复用和_频分复用_两种传输模式. 25.SDH网由一系列_SDH网络单元_组成,是一个高度统一的、标准的智能化网络. 26.STM-1帧结构中信息净负荷区域的位置是第1~9行,第_10~270_列. 27.管理单元AU是SDH的一种信息结构,它是由一个相应的高阶VC和一个相应的管理单元指针构成的. 28.目前EDFA采用的泵浦光波长为0.98μm和_1.48um_两种. 29.EDFA的主要特性指标有:功率增益、输出饱和功率和_噪声系数__等. 30.EDFA作前置放大器使用时,其作用为__提高接收机的灵敏度. 三、名词解释题(本大题共5小题,每小题3分,共15分) 31.光纤的时延 设一个单一的载频f0,携带一个调制信号,当光波频率很高,相对调制带宽很窄时,它在传输过程中的速度可用群速vg表示,则它传输每一单位长度时,所需要的时间T就称作每单位长度的时延。T=1/vg 32.受激辐射 处于高能级E2的电子,当受到外来光子的激发而跃迁到低能级E1,同时放出一个能量为hf的光子,由于这个过程是在外来光子的激发下产生的,因此叫受激辐射。 33.光电检测器的响应时间 是指半导体光电二极管产生的光电流跟随入射光信号变化快慢的状态。 34.单位间隔(UI) 就是一个比特传输信息所占的时间。 35.网络自愈 指在无需人为干涉情况下,网络能在极短的时间内,从失效的故障状态自动恢复传输所携的业务 四、画图题(本大题共2小题,36小题7分,37小题8分,共15分) 36.画出半导体激光器(LD)数字信号的直接调制原理图. 解: 37.画出光接收机自动增益控制的工作原理框图. 光信号~光电检测器~前置放大器~主放大器~均衡器~~。~~判决器~ 。 。 APD高压电路~~•~~~AGC放大器~峰值检波器 五、简答题(本大题共4小题,每小题5分,共20分) 38.何为单模光纤的截止波长λc?写出在阶跃型光纤中λc的计算公式. 答:光纤的单模传输条件是以第一高次模(LP11模)的截止频率而给出的。归一化截止频率为VC= /λ.对应着归一化截止频率的波长为截止波长,用λc表示, λc= λc= /2.40483 39.简述光源直接调制方式的主要优缺点. 答:优点:简单方便,成本低,技术成熟(可以适当发挥);缺点:会使得激光器的动态谱线增宽,造成在传输时色散加大,从而限制了通信容量和传输速率。在调制速率上相对较低。 40.在数字光接收机电路中,为什么要采用均衡器?答 在数字光纤通信系统中,调制好的矩形脉冲数字信号从光发射机到接收机主放大器输出的脉冲形状将不再会是矩形了。将可能出现很长的拖尾,这种拖尾现象将会是前后码元的波形重叠产生码间干扰,严重时,造成判决电路误判,产生误码。而均衡器恰使经过均衡的波形成为有利于判决的波形。 41.在数字光纤通信系统中,线路码型应满足哪些条件? 答;1)避免在信码流中出现长“0”和长“1”;2)能进行不中断业务的误码监测;3)尽量减少信码流中直流分量的起伏。 六、计算题(本大题共2小题,每小题10分,共20分) 计算结果保留两位小数. 42.弱导波阶跃型光纤的纤芯折射率为n1=1.50,相对折射率差Δ=0.25,纤芯的半径a=5μm,工作波长λ=1.31μm. 计算:(1)该光纤的数值孔径NA; NA=n1*…. (2)光纤中传输模式的数量; M= V2/2 (3)为保证光纤的单模传输,光纤的芯径应取多大? 解:1)NA=n1 =1.50* 。。。。。 2)v=n1a M= =n21a2 。。。。。 3)阶跃光纤单模传输条件为0<v<2.40483 而V=n1a 0<a< 。。。。。 43.某工程采用单模光纤通信系统,其发射机光源的入纤光功率为0.5mW,接收机的灵敏度为1μW,全程光纤平均接头损耗为0.1dB/km,系统富裕度为6dB.现要求该系统的中继传输距离达65km,请核算选用单位长度损耗为0.27dB/km的光纤是否满足传输的要求. 解:L=(PT——PMIN——M)/(0.1+A) 灵敏度SR=10logPmin/10-3 (dBm) Pmin的单位瓦,10-3的单位是指1mw的光功率。 A=

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值