dream

一个菜鸟程序员的成长历程

0%

软件工程第二章

编程过程与规范

编程是软件工程师的基本能力

编写优雅的代码是每一个程序员的不懈追求

编程是一门艺术,他能够展示结构之美,构造之美,表达之美

软件变成工作

软件编程是一个复杂而迭代的过程,它不仅仅是编写代码,还应该包括代码审查,单元测试,代码优化,集成调试等一系列工作。

系统模型到源代码

  • 编写代码
  • 代码审查
  • 单元测试
  • 代码优化
  • 系统构建
  • 集成调试

高质量软件开发之道

  • 规范的编码
  • 高质量的设计
  • 有效的测试

软件编程规范

是与特定语言相关的描写如何编写代码的规则集合

目的

  • 提高编码质量,避免不必要的程序错误
  • 增强程序代码的可读性,可重用性和可移植性

学会只编写够用的注释,过犹不及,重视质量而不是数量

  • 好的注释解释为什么,而不是怎么样
  • 不要在注释中重复描述代码
  • 当自己在编写密密麻麻的注释来解释代码时,需要停下来看是否存在更大的问题
  • 想一想在注释中写什么,不要不动脑筋就输入
  • 写完注释之后要在代码得上下文中回顾一下,它们是否包含正确的信息
  • 当修改代码时,维护代码周围的所有注释

命名规范
好的名字一目了然,不需要读者去猜,甚至不需要注释

编写自文档化的代码

  • 唯一能完整并正确的描述代码的文档是代码本身
  • 编写可以阅读的代码,其本身简单易懂

良好的编程实践

看:阅读优秀的代码,学习别人的代码
问:发现问题,提出问题
练:亲自动手编写代码,实践,实践,再实践

高质量的设计

  • 模块化设计:将一个大的程序按功能分拆成一系列小模块
  • 面向抽象编程
  • 错误与异常处理

基于易变与稳定:认识和识别变与不变的部分,并将之科学地分离开
易变:业务逻辑
稳定:通用功能

基于单一职责:类或者函数应该只做一件事,并且做好这件事
单一职责:只有一个引起变化的原因

在模块化设计的基础上,先设计出各个模块的骨架,或者说对各个模块进行抽象,定义它们之间的接口

代码静态检查

代码审查是一种用来确认方案设计和代码实现的质量保证机制,它通过阅读代码来检查源代码与编码规范的符合性以及代码得质量。

代码审查的作用:

  • 检查设计的合理性
  • 互为Backup
  • 分享知识,设计,技术
  • 增加代码可读性
  • 处理代码中的“地雷区”

检查编码规范
面向对象设计
性能方面
资源释放处理
程序流程
线程安全
数据库处理
通讯方面
异常处理
方法
安全方面
其他

代码性能分析

优化师对代码进行等价变换,使得变换后的代码运行结果与变换前的代码运行结果相同,但执行速度加快或存储开销减少

  • 代码性能优化师一门复杂的学问
  • 根据80/20原则,实现程序的重构,优化,扩展以及文档相关的事情通常需要消耗80%的工作量

满足正确性,可靠性,健壮性,可读性等质量因素的前提下,设法提高程序的效率
以提高程序的全局效率为主,提高局部效率为辅
在优化程序效率时,应先找出限制效率的“瓶颈”
先优化数据结构和算法,再优化执行代码

从一开始就要考虑程序性能,不要期待在开发结束后在做一些快速调整
正确的代码要比速度快的代码重要,任何优化都不能破坏代码得正确性

  • 证明需要进行优化
  • 找出优化关键部门
  • 测试代码
  • 优化代码
  • 评测优化后的代码

认真选择测试数据
永远不要在没有执行前后性能评估的情况下尝试对代码进行优化

性能优化的关键是如何发现问题,寻找解决问题的方法
有效的测试是不可缺少的,通过测试找出真正的瓶颈,并分析优化结果
要避免不必要的优化,避免不成熟的优化,不成熟的优化师错误的来源

改进算法,选择合适的数据结构

  • 良好的算法对性能起到关键作用,因此性能改进的首要点是对算法改进

循环优化的基本原则:尽量减少循环过程中的计算量,在多重循环的时候,尽量将内层的计算提到上一层

结对编程

结对编程是由两名程序员在同一台电脑上结对编写解决同一问题的代码

驾驶员:负责用键盘编写程序
领航员:起到领航,提醒的作用

数据库原理第三节

关系数据模型

关系数据结构

码或键:
属性(属性组)的值都能用来唯一标识该关系的元组,则称这些属性为该关系的码或键

超码或超键:
在码中去除某个属性,他仍然是这个关系的码

候选码或候选键:
在码中不能从中移去任何一个属性,否则它就不再是这个关系的码或键。候选码或候选键是这个关系的最小超码或超键

主属性或码属性:

主码或主键:
在若干个候选码中指定一个唯一标识关系的元组(行)

全码或全键:
一个关系模式的所有属性集合是这个关系的主码或主键,这样的主码或主键称为全码或全键

外码或外键:
某个属性不是这个关系的主码或候选码,而是另一个关系的主码

参照关系被参照关系:
参照关系称为从关系,被参照关系称为主关系,它们是指以外码相关联的两个关系

域:
表示属性的取值范围

数据类型:
每个列都有相应的数据类型,它用于限制(或容许)该列中存储的数据

关系模式:
关系模式是,关系是,即关系模式是对关系的描述。

关系模式是静态的,稳定的

关系是动态的,随时间不断变化的。

关系数据库:
所有关系的集合,构成一个关系数据库
以关系模型作为数据的逻辑模型,并采用关系作为数据组织方式的一类数据库,其数据库操作建立在关系代数的基础上

关系数据库对关系的限定/要求:

  • 每一个属性都是不可分解的
  • 每一个关系仅仅有一种关系模式
  • 每一个关系模式中的属性必须命名,属性名不同
  • 同一个关系中不允许出现候选码或候选键值完全相同的元组
  • 在关系中元组的顺序是无关紧要的,可以任意交换
  • 在关系中属性的顺序是无关紧要的,可以任意交换

基本的关系操作

查询Query:

  • 选择
  • 投影
  • 笛卡尔积
    从上面的基本的组合:
  • 连接

特点:集合操作方式

关系数据语言的分类

关系代数语言

关系演算语言

  • 元组关系演算
  • 域关系演算

SQL结构化查询语言

共同特点:具有完备的表达能力,是非过程化的集合操作语言,功能强,能够独立使用也可以嵌入高级语言中使用。

关系代数的运算符

任何一种操作都包含三大要素

  • 操作对象
  • 操作符
  • 操作结果

传统的集合运算

并,差,交,笛卡尔积

专门的关系运算

选择,投影,连接,除

选择 select:a
a id = 1 (user) //获取id = 1的user表的数据
相当于这个SQL:select * from user where id = 1
a id = 1 ^ name = ‘abc’ (user)
SQL: select * from user where id = 1 and name = ‘abc’

投影 projection:π
projection 关系名(属性名1,。。。) 选出要展示的列
π id,name (id = 1 ^ name = ‘abc’ (user))
SQL: select id,name from (select * from user where id = 1 and name = ‘abc’)

并集 union:union 需要两个表的属性值一样才可以,假设两个表都是id,name字段那么可以,如果一个表有三个字段就不行
t1 union t2, 就是把两个表合并
SQL: (select * from t1) union all (select * from t2) //和union不完全一样

交集 intersection:和union要求一样,选的是交集
t1 intersect t2

差集 difference: 和union要求一样,取得是第一个表出现过第二表没出现的数据
t1 except t2

笛卡尔积 product: 把两个表所有的组合列出来
t1 * t2
SQL: select * from t1 cross join t2

连接 join: 取某个字段值相同的数据,和sql的join差不多
t1 join t2
SQL: select * from t1 natural join t2

数据库原理第四节

关系数据模型

关系的完整性约束

数据库的数据完整性是指数据库中数据的正确性相容性一致性

分类:

  • 实体完整性约束:主码的组成不能为空,主属性不能是空值NULL
  • 参照完整性约束:要么外码等于主码某个元组的主码值,要么为空值
  • 用户定义完整性约束
  • 域完整性约束

执行插入操作检查:

  • 检查实体完整性约束
  • 插入外码表的时候检查参照完整性约束
  • 检查用户定义完整性约束

执行删除操作:
一般只需要对被参照关系检查参照完整性约束

关系数据库的规范化理论

关系模式中可能存在的冗余和异常问题

  • 数据冗余
  • 更新异常
  • 插入异常
  • 删除异常

函数依赖与关键字

设R为任一给定关系,如果对于R中属性X的每一个值,R中的属性Y只有唯一值与之对应,则称X函数决定Y或称Y函数依赖于X,记作X->Y.其中X称为决定因素

分类:

  • 完全函数依赖
  • 部分函数依赖
  • 传递函数依赖

完全函数依赖:
设R为任一给定关系,X,Y为其属性集,若X->Y,且对X中的任何真子集X’,都有X’不依赖Y,则称Y完全函数依赖于X

部分函数依赖:
设R为任一给定关系,X,Y为其属性集,若X->Y,且X中存在一个真子集X’,都有X’->Y,则称Y部分依赖于X

传递函数依赖:
设R为任一给定关系,X,Y,Z为其不同属性子集,若X->Y,Y不决定X,Y->Z,则有X->Z,称为Z传递函数依赖于X。

关键字的定义:
设R为任一给定关系,U为其所含的全部属性集合,X为U的子集,若有完全函数依赖X->U,则X为R的一个候选关键字。

范式与关系规范化过程

一个低一级范式的关系模式通过模式分解可以转换为若干个高一级范式的关系模式的集合,这种过程就叫规范化

第一范式1NF:
设R为任一给定关系,如果R中每个列与行的交点处的取值都是不可再分的基本元素,则R为第一范式

第二范式2NF:
设R为任一给定关系,若R为1NF
且其所有非主属性都完全函数依赖于候选关键字,则R为第二范式。

第三范式3NF:
设R为任一给定关系,若R为2NF
且其每一个非主属性都不传递函数依赖于候选关键字,则R为第三范式。

第三范式的改进形式BCNF:
设R为任意给定关系,X,Y为其属性集,F为其函数依赖集,若R为3NF
且其F中所有函数依赖X->Y(Y不属于X)中的X比包含候选关键字,则R为BCNF

有部分函数依赖就是1NF,没有就是2NF,没有传递函数依赖就是3NF

1NF->2NF
找到候选关键字,看其余的属性是否完全函数依赖候选关键字
是的,与候选关键字一同抄下来形成一个表格
不是的,抄下来,形成第二个表格,并且将候选关键字里能够唯一决定表格2的属性组抄在第一列

2NF->3NF
找到表格中的传递函数依赖关系的三个属性组,设为X,Y,Z
将这三个属性组拆成两个表格
第一个表格为X,Y
第二个表格为Y,Z

3NF->BCNF
列出表格中的所有函数依赖关系
每个关系拆出一个表格

学堂在线C++程序设计第五章学习笔记

类与对象

对象:现实中对象的模拟,具有属性和行为。
类:同一类对象的共同属性和行为

定义对象时:通过构造函数初始化
删除对象时:通过析构函数释放资源

面向对象程序的基本特点

抽象:对同一类对象的共同属性和行为进行概括,形成类

封装:将抽象出的数据,代码封装在一起,形成类

继承:在已有类的基础上,进行扩展形成新的类

多态:同一名称,不同的功能实现方式

类和对象

设计类就是设计类型

  • 此类型的“合法值”是什么
  • 此类型应该有什么样的函数和操作符
  • 新类型的对象该如何被创建和销毁
  • 如何进行对象的初始化和赋值
  • 对象作为函数的参数如何以值传递
  • 谁将使用此类型的对象成员

类定义的语法形式

1
2
3
4
5
6
7
8
9
class 类名称
{
public:
公有成员(外部接口)
private:
私有成员
protected:
保护型成员
}

类的成员函数

  • 在类中声明函数原型
  • 可以在类外给出函数体实现,并在函数名前使用类名加以限定
  • 也可以直接在类中给出函数体,形成内联成员函数
  • 允许声明重载函数和带默认参数值得函数

构造函数

类中的特殊函数
用于描述初始化算法

作用:

  • 在对象被创建时使用特定的值构造对象,将对象初始化为一个特定的初始状态

形式:

  • 函数名与类名相同
  • 不能定义返回值类型,也不能有return语句
  • 可以有形式参数,也可以没有形式参数
  • 可以是内联函数
  • 可以重载
  • 可以带默认参数值

调用时机

  • 在对象创建时被自动调用
  • 例如:
    Clock myClock(0,0,0)

默认构造函数

  • 调用时可以不需要实参的构造函数
    • 参数表为空的构造函数
    • 全部参数都有默认值的构造函数

隐含生成的构造函数

  • 如果程序中未定义构造函数,编译器将自动生成一个默认构造函数
  • 参数列表为空,不为数据成员设置初始值
  • 如果类内定义了成员的初始值,则使用内类定义的初始值
  • 如果没有定义类内的初始值,则以默认方式初始化
  • 基本类型的数据默认初始化的值是不确定的

复制构造函数

  • 复制构造函数是一种特殊的构造函数,其形参为本类的对象引用。作用是用一个已存在的对象去初始化同类型的新对象。
1
2
3
4
5
6
7
8
class 类名{
public:
类名(const 类名 &对象名); //复制构造函数
}

类名::类(const 类名 &对象名) {
函数体
}

复制构造函数被调用的三种情况

  • 定义一个对象时,以本类另一个对象作为初始值,发生复制构造
  • 如果函数的形参是类的对象,调用函数时,将使用实参对象初始化形参对象,发生复制构造
  • 如果函数的返回值是类的对象,函数执行完成返回主调函数时,将使用return语句中的对象初始化一个临时无名对象,传递给主调函数,此时发生复制构造

隐含的复制改造函数

  • 如果没有为类声明拷贝初始化构造函数,则编译器自己生成一个隐含的复制构造函数
  • 这个构造函数执行的功能是:用初始值对象的每个数据成员,初始化将要建立的对象的对应数据成员

析构函数

  • 完成对象被删除前的一些清理工作。
  • 在对象的生存期结束的时刻系统自动调用它,然后再释放此对象所属的空间。
  • 如果程序中未声明析构函数,编译器将自动产生一个默认的析构函数,其函数体为空。
  • 析构函数的原型:~类名()
  • 析构函数没有参数,没有返回类型

类的组合

  • 类中的成员是另一个类的对象
  • 可以在已有抽象的基础上实现更复杂的抽象

类组合的构造函数设计

  • 原则:不仅要对本类中的基本类型成员数据初始化,也要对对象成员初始化
  • 声明形式:
1
2
3
4
5
类名::类名(对象成员所需的形参,本类成员的形参):
对象1(参数),对象2(参数),...
{
//函数体
}

构造组合类对象时的初始化次序

  • 首先对构造函数初始化列表中列出的成员(包括基本类型和对象成员)进行初始化,初始化次序是成员在类体中定义的次序
    • 成员对象构造函数调用顺序:按对象成员的定义顺序,先声明者先构造
    • 初始化列表中未出现的成员对象,调用默认构造函数(即无形参)的初始化
  • 处理完初始化列表后,再执行构造函数的函数体

结构体

结构体是一种特殊形态的类
与类的唯一区别

  • 类的缺省访问权限是private
  • 结构体的缺省访问权限是public

什么时候用结构体

  • 定义主要用来保存数据,而没有什么操作的类型
  • 人们习惯将结构体的数据成员设为公有,因此这时用结构体更方便

定义

1
2
3
4
5
6
7
struct 结构体名称{
共有成员
protected:
保护型成员
private:
私有成员
}

结构体中可以有数据成员和函数成员

结构体的初始化
如果:

  • 一个结构体的全部数据成员都是公共成员
  • 没有用户定义的构造函数
  • 没有基类和虚函数

这个结构体的变量可以用下面的语法形式初始化
类型名 变量名 = {成员数据1初始值,…}

联合体

定义

1
2
3
4
5
6
7
union 联合体名称{
共有成员
protected:
保护型成员
private:
私有成员
}

特点:

  • 成员共用同一组内存单元
  • 任何两个成员不会同时有效

枚举类

定义
enum class 枚举类型名:底层类型{枚举值列表}
例子:
enum class Type{General,Light}
enum class Type:char{General,Light}

枚举类的优势

  • 强作用域:作用域限制在枚举类中
  • 转换限制:枚举类对象不可以与整型隐式转换
  • 可以指定底层类型

学堂在线C++程序设计第四章学习笔记

函数定义

函数:定义好的可重用功能模块

定义函数:将一个模块的算法用C++描述出来

函数的返回值:需要返回的计算结果

定义函数的语法:

1
2
3
4
类型标识符 函数名(形式参数表)
{
语句
}

形式参数表

  • <类型名> 参数名,…

返回值

  • return 一个计算结果
  • 返回的类型是类型标识符的类型
  • 没有返回值,类型标识符写void

函数调用

调用函数前需要先声明函数原型

函数原型

  • 类型标识符
  • 被调用函数名
  • (类型说明的形参表)

函数调用

  • 函数名(实参列表)

计算x的n次方

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
using namespace std;

double pow(double x, int n) {
double sum = 1.0;
for(int i = 1; i <= n; i++) {
sum = x * sum;
}
return sum;
}

int main() {
double sum = pow(2,4);
cout << sum;
return 0;
}

进制转换

输入一个8位二进制,输出十进制

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <iostream>
using namespace std;

double pow(double x, int n) {
double sum = 1;
for (int i = 1; i <= n; i++) {
sum *= x;
}
cout << "x:"<<x<<"n:"<<n<<endl;
return sum;
}

int main() {
int h = 0;
for (int i = 7; i >= 0; i--) {
char d;
cout << "输入:";
cin >> d;
if (d == '1') {
//转换进制
h += static_cast<int>(pow(2, i));
}
}
cout << h;
return 0;
}

计算圆周率

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <iostream>

using namespace std;

double arctan(double x) {

double sqr = x * x;

double e = x;

double r = 0;

int i = 1;

while (e / i > 1e-15) {

double f = e / i;

r = (i % 4 == 1) ? r + f : r - f;

e = e * sqr;

i += 2;

}

return r;

}

int main() {

double a = 16.0 * arctan(1/5.0);

double b = 4.0 * arctan(1/239.0);

//注意:因为整数相除结果取整,如果参数写1/5,1/239,结果就都是0



cout << "PI = " << a - b << endl;

return 0;

}

求回文

寻找并输出11~999之间的数M,它满足M、M2和M3均为回文数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#include <iostream>
using namespace std;

/**
* 判断是否是回文
*/
bool symm(unsigned int n) {
unsigned int i = n;
unsigned int m = 0;
while (i > 0)
{
/* code */
m = m * 10 + i % 10;
i /= 10;
}
return m == n;
}

int main () {
for (int i = 11; i <= 999; i++) {
if (symm(i) && symm(i * i) && symm(i * i *i)) {
cout << "m = " << i << endl;
cout << "m * m =" << i * i << endl;
cout << "m * m * m = " << i * i*i <<endl;
}
}
return 0;
}

计算分段函数,并输出结果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <iostream>
#include <cmath>
using namespace std;

const double IINY_VALUE = 1e-10;

double tsin(double x) {
double g = 0;
double t = x;
int n = 1;
do {
g += t;
n++;
t = -t * x * x/(2*n-1)/(2 * n -2);
} while (fabs(t) >= IINY_VALUE);
return g;
}

int main() {
double k,r,s;
cout << "r =";
cin >> r;
cout << "s=";
cin >> s;
if (r * r <= s * s) {
k = sqrt(tsin(r) * tsin(r) + tsin(s) * tsin(s));
} else {
k = tsin(r * s) /2;
}
cout << k <<endl;
return 0;
}

摇筛子游戏

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include <iostream>
#include <cstdlib>
using namespace std;

enum gameStatus {WIN,LOSE,PLAYING};

int rollDice() {
unsigned int rand1 = rand() % 6 + 1;
unsigned int rand2 = rand() % 6 + 1;
cout << "rand1 + rand2 = " << rand1 + rand2 << endl;
return rand1 + rand2;
}


int main() {
unsigned int seed, sum, myPoint;
gameStatus status;
cout << "enter is seed:";
cin >> seed;
srand(seed);
sum = rollDice();
switch (sum)
{
case 7:
case 11:
status = WIN;
break;
case 2:
case 3:
case 12:
status = LOSE;
break;
default:
status = PLAYING;
myPoint = sum;
break;
}

while (status == PLAYING)
{
/* code */
sum = rollDice();
if (sum == 7) {
status = LOSE;
} else if (sum == myPoint) {
status = WIN;
}
}

if (status == WIN) {
cout << "WIN";
} else if (status == LOSE) {
cout << "LOSE";
}
return 0;

}

C++程序设计第三章

数据的输入输出

输入输出看成是数据的流动

IO流

  • 将数据从一个对象到另一个对象的流动抽象为
  • 流在使用前要建立,使用后要删除
  • 数据的输入输出是通过IO流来实现的,cin和cout是预定义的流类对象。cin用来处理标准输入,即键盘输入。cout用来处理标准输出,即屏幕输出
  • 从流中获取数据的操作称为

预定义的插入符和提取符

  • << 是预定义的插入符,作用在流对象cout上就可以向标准输出设备输出
  • >> 是预定义的提取符,作用在流对象cin上
  • 可以写多个

常用的IO流类库操纵符

操纵符名 含义
dec 数值数据采用十进制表示
hex 数值数据采用十六进制表示
oct 数值数据采用八进制表示
ws 提取空白符
endl 插入换行符并刷新流
ends 插入空字符
setprecision(int) 设置浮点数的小数位数(包括小数点)
setw(int) 设置域宽

选择结构

if语句

if语句的语法形式

  • if (表达式)语句
    if (x > y) cout << x;
  • if (表达式) 语句1 else 语句2
    if (x < y) cout << x;
    else cout <<y;
  • if (表达式1) 语句1 else if (表达式2) 语句2 else 语句n
1
2
3
4
5
6
if (表达式1) 
语句1
else if (表达式2)
语句2
else
语句n

上面的表达式等同于下面的表达式

1
2
3
4
5
6
7
if (表达式1) 
语句1
else
if (表达式2)
语句2
else
语句n

switch语句

1
2
3
4
5
6
7
8
9
10
switch (表达式1) {
case 常量值1
语句1
break;
case 常量值2
语句2
break;
default:
默认语句
}

表达式和常量值都是int或char型

循环结构

while语句

计算0到10之和

1
2
3
4
5
int sum = 0;
whileint i <= 10) {
sum += i;
i++;
}

执行顺序

  • 先判断while表达式的值,若为true,执行语句
  • 执行完语句在判断while表达式的值,直到为false,不再执行

while里面可以是复合语句,其中必须含有改变条件表达式值得语句

do-while语句

计算0到10之和

1
2
3
4
5
6
int sum = 0;
int i = 0;
do {
sum += i;
i++;
} while ( i <= 10

执行顺序

  • 先执行语句
  • 执行完语句判断while表达式的值,如果为true,那么接着执行语句
  • 执行完语句后再次判断while表达式的值,直到为false
  • 语句至少会执行一次

for语句

输入一个整数,求出他的所有因子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <iostream>
using namespace std;

int main() {
int n;
cin >> n;
cout << "Number:" << n << "Factors\n";
for (int k = 1;k <= n;k++) {
if (n % k == 0) {
cout << k << endl;
}
}
cout << "end" << endl;
return 0;
}

嵌套的控制结构

输入一系列整数,统计出正整数个数i和负整数个数j,读入0则结束

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
using namespace std;

int main() {
int n;int z = 0;int f = 0;
cin >> n;
while (n != 0)
{
/* code */
if (n > 0) {
z++;
} else if (n < 0) {
f++;
}
cin >> n;
}
cout << "n:" << n << endl;
cout << "正数数量:" << z << endl;
cout << "负数数量:" << f << endl;

return 0;
}

自定义类型

类型别名:为已有类型另外命名

  • typedef 已有类型名 新类型名表
  • 例子:typedef double area
  • using 新类型名 = 已有类型名
  • 例子:using area = double

枚举类型:

  • 定义方式:
    将全部可取值列出来
  • 语法形式:
    enum 枚举类型名 {变量值列表}
  • 例子
    enum week {1,2,3,4,5,6,7}

C++包含两种枚举类型:

  • 不限定作用域
  • 限定作用域

不限定作用域枚举类型

  • 枚举元素是常量,不能赋值
  • 枚举元素具有默认值,依次为0,1,2,3
  • 也可以在声明时另行指定枚举元素的值
  • 枚举值可以进行关系运算
  • 整数值不能赋值为枚举变量,如需要,应该进行强制转换
  • 枚举可以给整形赋值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <iostream>
using namespace std;

enum GameResult {WIN,LOSE,TIE,CANCEL};

int main() {
GameResult Result;
enum GameResult omit = CANCEL;
for (int count = WIN; count <= CANCEL; count++) {
Result = GameResult(count);
if (Result == omit) {
cout << "The game was canceld" << endl;
} else {
cout << "The game was played" << endl;
if (Result == WIN) cout << "and we Win" << endl;
if (Result == LOSE) cout << "and we lose" << endl;
}

}

return 0;
}

auto 类型 与 decltype类型

  • auto :编译器通过初始值自动推断变量的类型
    例如:auto val = val1 + val2
    如果val1 val2是int,那么val是int
    如果val1 val2是double,那么val是double
  • decltype:定义一个变量与某一表达式的类型相同,单并不用该表达式初始化变量
    例如:decltype(i)j = 2;
    表示j 用 2 作为初始值,但是类型和i一致

C++程序设计第二章

C++简单程序设计

C++的基本数据类型

  • 整数类型
  • 实数类型
  • 字符类型
  • 布尔类型

C++的基本运算

  • 算术运算
  • 逻辑运算

程序要能输入数据,输出数据

C++的输入输出可以调用预定义的功能模块实现

程序的执行流程不总是顺序的因此程序要能够

  • 对执行流程进行选择(选择/开关语句)
  • 反复用同一算法依次处理大批量数据(循环语句)

基本数据类型能表示的有限

程序员要能够自定义类型

枚举类型

  • 通过列出所有可取值来定义一种新类型

C++特点和程序实例

  • 从C语言发展而来,最初称为带类的C
  • 1983年正式取名为C++;
  • 1998年11月被国际标准化组织(ISO)批准为国际标准;
  • 2003年10月15日发布第2版C++标准ISO/IEC 14882:2003;
  • 2011年8月12日ISO公布了第三版C++标准C++11,包含核心语言的新机能、扩展C++标准程序库。
  • 2014年8月18日ISO公布了C++14,其正式名称为”International Standard ISO/IEC 14882:2014(E) Programming Language C++”。
  • C++14作为C++11的一个小扩展,主要提供漏洞修复和小的改进。

C++的特点

  • 兼容C,支持面向过程的程序设计
  • 支持面向对象的方法
  • 支持泛型程序设计方法

命名空间

  • 避免命名冲突
  • std是C++标准库的命名空间名
  • using namespace std 表示打开std命名空间

输出Hello

1
2
3
4
5
6
7
8
#include <iostream>
using namespace std;

int main() {
cout << "Hello!" << endl;
cout << "Welcome to C++!" << endl;
return 0;
}

C++字符集和词法记号

词法记号

  • 关键字
    C++预定义的单词
  • 标志符
    程序员声明的单词,它命名程序正文中的一些实体
  • 文字
    在程序中直接使用符号表示的数据
  • 分隔符
    (){};:,用于分隔各个词法记号或程序正文
  • 运算符(操作符)
    用于实现各种运算的符号
  • 空白符
    空格, 制表符,垂直制表符,换行符,回车符和注释的总称

标识符的构成规则

  • 以大写字母,小写字母或下划线开始
  • 可以由大写字母,小写字母,下划线或数字组成
  • 大写字母和小写字母代表不同的标识符
  • 不能是C++关键字或操作符

基本数据类型,常量,变量

程序中的数据

  • 常量
    在源程序中直接写明的数据
    其值在整个程序运行期间不可改变
  • 变量
    在程序运行过程中可以改变

整数类型

  • 基本的INT型
  • 按照符号分
    • 有符号
    • 无符号
  • 按照数据范围分
    • 短整数 short
    • 长整数 long
    • 长长整数 longlong

字符类型

  • 字符容纳单个字符的编码
  • 实质上存储的也是整数

浮点数类型

  • 单精度 float
  • 双精度 double
  • 扩展精度 long double

字符串类型

  • 有字符串常量
  • 基本类型中没有字符串变量
  • 采用字符数组存储字符串
  • 标准C++库中的String类

布尔类型

  • 只有两个值,真 true 假 false

常量

  • 在程序运行中不可改变的量
  • 直接使用符号(文字)表示的值
  • 例如:12,3.5,’A’都是常量

整数常量

  • 十进制
  • 八进制
  • 十六进制

后缀

  • L = long
  • LL = longlong
  • U = 无符号

浮点数常量

  • 以文字形式出现的实数
  • 默认double ,如果后缀F可以指定成float

C风格字符串

  • 一对双引号的字符
  • 在内存中按串中字符的排列次序顺序存放,每个字符占一个字节
  • 在末尾添加’\0’作为结尾标记

变量

在程序运行过程中可改变的量

变量定义

  • 类型 变量名

在定义变量的同时可以初始化

C++多种初始化

  • int a = 0;
  • int a(0)
  • int a = {0}
  • int a{0}

列表初始化

  • 使用大括号的初始化方式
  • 不允许信息的丢失

符号常量

常量定义语句的形式:

  • const 数据类型说明符 常量名 = 值
  • 数据类型说明符 const 常量名 = 值

符号常量定义一定需要初始化,在程序中不能改变值

程序举例

读入并显示整数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
using namespace std;

int main() {
int radius;
cout << "Please enter the radius\n";
cin >> radius;
cout << "The radius is:" << radius << "\n";
cout << "PI is:" << 3.14 << "\n";
cout << "Please enter a different radius\n";
cin >> radius;
cout << "Now the radius is changed to:" << radius <<"\n";
return 0;
}

运算与表达式

算术运算与赋值运算

基本算术运算

  • +-*/(整数相除,结果为整数)
  • %取余运算(结果为整数)

优先级与结合性

  • 先乘除,后加减,同级自左至右

自增自减操作

赋值操作
通过赋值运算符=赋值给变量

复合赋值运算符有10种

  • +=, -=, *=, /=, <<=, >>=, &=, ^=, |=

符号运算,关系运算,逻辑运算和条件运算

逗号运算和逗号表达式

  • 格式
    表达式1,表达式2
  • 求解顺序及结果
    先求解表达式1,在求解表达式2
    用表达式2的结果作为结果
  • 例子
    a = 3 * 5, a * 4 最终结果为60

赋值运算符优先级比逗号低

关系运算

  • 优先级
    高的:< <= >= >
    低的:== !=
  • 关系表达式是一种最简单的逻辑表达式
  • 结果是布尔类型,true or false

逻辑运算符

  • 优先级从高到低:! && ||
  • 结果是布尔类型
  • && 的运算规则
    • 两侧表达式都为真,结果为真
    • 有一侧表达式为假,结果为假
  • || 的运算规则
    • 两侧表达式都为假,结果为假
    • 有一侧表达式为真,结果为真

&& 的短路特性

  • 先求解表达式1,
  • 若表达式1的值为false,则最终结果为false,不再求解表达式2
  • 若表达式1的值为true,则求解表达式2,以表达式2的结果作为最终结果

|| 的短路特性

  • 先求解表达式1
  • 若表达式1的值为true,则最终结果为true,不在求解表达式2
  • 若表达式1的值为false,则求解表达式2,以表达式2的结果作为最终结果

条件运算符

  • 一般形式
    • 表达式1 ? 表达式2 : 表达式3
    • 表达式1必须是bool类型
  • 执行顺序
    • 先求解表达式1
    • 若表达式1的值为true,则求解表达式2,表达式2的结果作为最终结果
    • 若表达式1的值为false,则求解表达式3,表达式3的结果作为最终结果
  • 条件运算符优先级高于赋值运算符,低于逻辑运算符

sizeof运算,位运算

sizeof运算符

  • 语法形式
    sizeof(类型名) 或 sizeof 表达式
  • 结果值
    类型名 所指定的类型,或 表达式 的结果类型所占的字节数

按位与

  • 运算规则
    将两个运算量的每一个位进行逻辑与操作
  • 例子
    计算 3 & 5
    0000 0011
    0000 0101
    结果0000 0001
  • 用途,将某一位置0,取出某一位

按位或

  • 运算规则
    将两个运算量的每一个位进行逻辑或操作
  • 用途,将某一位置1

按位异或

  • 运算规则
    两个操作数进行异或
    若对应位相同,结果为0
    若对应位不同,结果为1
  • 计算 071 ^ 052
    0011 1001
    0010 1010
    结果 0001 0011
  • 用途,特定位翻转

按位取反

  • 运算规则
    0 变 1, 1 变 0

移位操作

  • 左移后,低位补0,高位舍弃
  • 右移后,低位舍弃,高位无符号数补0,有符号为补符号位

运算优先级,类型转换

一些运算符要求数据类型一致
隐含转换的基本原则是低类型转换到高类型

浮点数换成整数,小数部分直接丢弃
整数换成浮点数,小数为0,可能丢失精度

显示转换

  • 类型说明符(表达式)
  • (类型说明符)表达式
  • 类型转换操作符 <类型说明符> (表达式) C++的转换方式
    • 类型转换操作符:const_cast,dynamic_cast ,reinterpret_cast,static_cast

软件工程

软件无处不在

软件是软件工程的研究对象,也是软件工程的产品形态与客观存在

工程是将理论和知识应用于实践的科学,其目的是经济有效的解决实际问题

软件的本质特性

软件 = 程序 + 数据 + 文档

  • 程序:计算机可以接受的一系列指令,运行时可以提供所要求的的功能和性能
  • 数据:使得程序能够适当地操作信息的数据结构
  • 文档:描述程序的研制过程,方法和使用的图文资料

软件具有

  • 复杂性
  • 一致性
  • 可变性
  • 不可见性

上面是软件开发困难的根本原因

一致性

  • 软件不能独立存在,需要依附于一定的环境(如硬件,网络以及其他软件)
  • 软件必须遵从人为的惯例并适应已有的技术和系统
  • 软件需要随接口不同而改变,随时间推移而变化,而这些变化是不同人设计的结果

可变性

  • 软件一直在变化更新
  • 人们总认为软件是容易修改的,但忽视了修改的副作用
  • 不断的修改最终导致软件的退化,从而结束其生命周期

不可见性

  • 软件是一种看不见摸不着的逻辑实体,不具有空间的形体特征
  • 开发人员可以直接看到程序代码,但是源代码并不是软件本身
  • 软件是以机器代码得形式运行,但是开发人员无法看到源代码是如何执行的

软件所具有的复杂性,一致性,可变性,不可见性等特性,使得软件开发过程变得难以控制,开发团队如同在焦油坑中挣扎的巨兽

软件工程的产生与发展

软件开发面临的挑战

  • 客户不满意
    • 交付的许多功能不是客户需要的
    • 交付的日期没有保障
    • 客户使用时发现许多bug
  • 项目过程失控
    • 客户需求变化频繁,无力应对
    • 无法预见软件的交付质量
    • 对流程盲目遵从,忽视客户业务价值
  • 风险与成本问题
    • 开发团队专注技术,忽视风险
    • 无能力预测成本,导致预算超支
  • 无力管理团队
    • 无法评估开发人员能力及工作进度
    • 困扰于如何提升团队的能力与效率

软件工程一直致力于探索软件开发问题的解决之道

1968年,北大西洋公约组织提出软件工程概念和术语

软件工程的基本概念

软件工程

  • 将系统的,规范的,可定量的方法应用与软件的开发,运行和维护,即工程化应用到软件上
  • 对1中所述方法的研究

好的软件

  • 较低的开发成本
  • 按时完成开发任务并及时交付
  • 实现客户要求的功能
  • 具有良好性能,可靠性,可扩展性,可移植性等
  • 软件维护费用低

软件工程的基本要素

  • 过程
    支持软件开发各个环节的控制和管理
  • 方法
    完成软件开发任务的技术手段
  • 工具
    为软件开发方法提供自动或半自动的软件支撑环境

软件开发的基本策略

  • 软件复用
  • 分而治之
  • 逐步演进
  • 优化折中

软件工程的wasserman规范

  • 抽象
  • 软件建模方法
  • 用户界面原型化
  • 软件体系结构
  • 软件过程
  • 软件复用
  • 度量
  • 工具与集成环境

软件质量实现

什么是好的软件

  • 功能质量
    • 软件符合指定需求
    • 软件几乎没有缺陷
    • 软件性能正常
    • 软件容易上手,操作方便
  • 结构质量
    • 代码可测试性
    • 可维护性
    • 可读性
    • 代码效率:高效管理资源
    • 代码安全:可预防常见威胁
  • 过程质量
    • 软件按时交付
    • 软件满足预算
    • 可复用的开发过程,确保交付质量

产品质量维度

  • 性能
  • 特色
  • 可靠性
  • 符合型
  • 耐久性
  • 可服务性
  • 审美
  • 感知

ISO9126质量模型

  • 功能性
    • 适合性:当软件在指定条件下使用,其满足明确和隐含要求功能的能力
    • 准确性:软件提供给用户功能的精确度是否符合目标
    • 互操作性:软件与其他系统进行交互的能力
    • 安全性:软件保护信息和数据的安全能力
  • 可靠性
    • 成熟性:软件产品避免因软件错误发生而导致失效的能力
    • 容错性:防止外部接口错误扩散而导致系统失效的能力
    • 可恢复性:系统失效后,重新恢复原有的功能和性能的能力
  • 易用性
    • 易理解性
    • 易学习性
    • 易操作性
    • 吸引性
  • 效率
    • 时间特性
    • 资源利用
  • 可维护性
    • 易分析性
    • 易改变性
    • 稳定性
    • 易测试性
  • 可移植性
    • 适应性
    • 易安装性
    • 共存性
    • 替换性

数据库系统原理第二节

关系数据库

客户服务器结构

客户端,前台或表示层主要完成与数据库使用者的交互任务

服务器,后台或数据层主要负责数据管理

单机方式
网络方式

浏览器服务器结构

一种基于Web应用的客户/服务器结构,也称为三层客户/服务器结构

三层

  • 表示层
  • 处理层(中间层)
  • 数据层

数据模型

模型是现实世界特征的模拟和抽象表达

数据模型是对现实世界数据特征的抽象,描述的是数据的共性内容

数据的特征

静态特征

  • 数据的基本结构
  • 数据间的联系
  • 数据取值范围的约束

动态特征

  • 指对数据可以进行符合一定规则的操作

数据模型组成要素

数据结构描述的是系统的静态特征,即数据对象的数据类型内容,属性以及数据对象之间的联系

数据操作描述的是系统的动态特征

数据约束描述数据结构中数据间的语法和语义关联

数据模型的分类

数据模型是模型化数据和信息的工具,也是数据库系统的核心和基础

满足三点:

  • 比较真实地模拟现实世界
  • 容易为人们理解
  • 便于在计算机上实现

概念层数据模型

概念层是数据抽象级别的最高层。概念层数据模型,也称为数据的概念模型信息模型,这类模型主要用于数据库的设计阶段

信息世界涉及的基本概念

实体
属性
码或键

实体型
实体集
联系

数据模型中有两个概念

型 是表头,字段名称
值 是内容,字段值

逻辑层数据模型

逻辑层是数据抽象级别的中间层,逻辑层数据模型,也称为数据的逻辑模型。任何DBMS都是基于某种逻辑数据模型。

逻辑模型的类型

层次模型

  • 最早使用的一种数据模型
  • 有且仅有一个结点没有父结点,称作根结点
  • 其他结点有且仅有一个父结点

网状模型

  • 以网状结构表示实体与实体间的联系
  • 允许结点有多与一个父结点
  • 可以有一个以上的结点没有父结点

关系模型

  • 二维表结构来表示实体间的联系
  • 建立在严格的数学概念的基础上,概念单一
  • 存取路径对用户透明,有更高的数据独立性,更好的安全保密性

面向对象模型 = 面向对象方法 & 数据库

  • 既是概念模型又是逻辑模型
  • 表达能力丰富,对象可复用,维护方便

物理层数据模型

物理模型

最底层的抽象

设计目标是提高数据库性能有效利用存储空间

简述概念模型,逻辑模型,物理模型之间的关系

这三个不同的数据模型之间既相互独立,又存在着关联。从现实世界到概念模型的转换是由数据库设计人员完成的。
从概念模型到逻辑模型的转换可以由数据库设计人员完成,也可以用数据库设计工具协助设计人员完成;
从逻辑模型到物理模型的转换主要用数据库管理系统完成。

关系数据库

关系数据库概述

关系数据库的历史

1970 提出了关系模型
20世纪70年代末 重大突破
1981年 证实了关系数据库的优点:高级的非过程语言接口,较好的数据独立性
20世纪80年代后 网状模型和层次模型与底层实现的紧密结合,关系模型具有坚实理论基础,成为主流数据模型

关系数据模型的组成要素

关系数据结构
关系操作集合
关系完整性约束

关系数据结构

关系的三种类型

实际存在的表

基本关系(基本表,基表)
查询表
视图表 导出的虚表

关系数据模型

列 也称为 字段 或 属性

属性 = 列

8元 = 8度 = 8列

分量 = 具体的数据项
元组(行)中的一个属性值,称为分量

C++程序设计第一章

计算机语言

程序员与计算机沟通的语言
描述解决问题的方法和相关数据

计算机语言的级别

  • 二进制代码得机器语言
  • 使用助记符的汇编语言
  • 使用类似英语单词和语句的高级语言

C++是面向对象的高级语言

  • 封装
  • 消息通信

C++支持的程序设计方法

  • 面向过程的程序设计方法
  • 面向对象的程序设计方法
  • 泛型程序设计方法

C++程序的开发过程

  • 算法设计
  • 源程序编辑
  • 编译
  • 连接

信息在计算机中的表示存储

  • 计算机中的数据都是二进制的
  • 逻辑数据,字符数据也用二进制码表示

计算机系统简介

  • 输入设备
  • 内存储器
  • 外存储器
  • CPU
  • 输出设备

计算机的工作需要人来指挥

  • 计算机解决问题是软件控制的
  • 软件的程序就是操作步骤
  • 程序要使用语言来表达

计算机能识别的是机器语言
机器语言指令是由0和1编码的
例如:
加法指令可能是 0001

计算机指令系统

  • 机器硬件能够识别的语言(机器语言)的集合
  • 它是软件和硬件的主要界面

计算机软件:

  • 应用软件
  • 系统软件 操作系统
  • 中间件 提供系统软件和应用软件之间链接的软件

软件 = 程序 + 文档

计算机程序

  • 指令的序列
  • 描述解决问题的方法和数据

计算机语言和程序设计方法的发展

机器语言

  • 由二进制代码构成
  • 计算机硬件可以识别
  • 可以表示简单的操作
  • 例如:
    加法,减法,数据移动等等

最初的计算机语言–机器语言和人类的自然语言之间存在巨大鸿沟

汇编语言

  • 将机器指令映射为一些助记符。如ADD,SUB,MOV等
  • 抽象层次低,需要考虑机器细节

高级语言

  • 关键字,语句容易理解
  • 有含义的数据命名和算式
  • 抽象层次高,例如 A + B
  • 屏蔽了机器的细节,例如 count << a + b + c

C++语言

  • 是高级语言
  • 支持面向对象的观点和方法
  • 将客观事物看做对象
  • 对象间通过消息传送进行沟通
  • 支持分类和抽象

程序设计方法和发展历程

面向过程的程序设计方法

  • 机器语言,汇编语言,高级语言都支持
  • 最初的目的,用于数学计算
  • 主要工作,设计求解问题的过程

大型复杂的软件,难以用面向过程的方式编写

面向对象的程序设计方法

  • 面向对象的高级语言支持
  • 一个系统有对象构成
  • 对象与对象之间通过消息通信

面向对象的基本概念

对象(Object)

  • 一般意义上的对象:
    是现实世界中一个实际存在的事物
  • 面向对象方法中的对象:
    是系统中用来描述客观事物的一个实体

抽象与分类

  • 分类所依据的原则–抽象
  • 抽象出同一类对象的共同属性和行为,形成类

类与对象的关系

  • 类型与实例的关系

封装

  • 隐蔽对象的内部细节
  • 对外形成一个边界
  • 只保留有限的对外接口
  • 使用方便,安全性好

继承

  • 软件复用
  • 改造,扩展已有类行成新的类

多态

  • 同样的消息作用在不同对象上有可能引起不同的行为

程序的开发过程

高级语言 要翻译成 机器语言

源程序

  • 用源语言写的,有待翻译的程序

目标程序

  • 源程序通过翻译加工以后生成的机器语言程序

可执行程序

  • 连接目标程序以及库中的某些文件,生成的可执行程序

三种不同类型的翻译程序

  • 汇编程序
    将汇编语言源程序翻译成目标程序
  • 编译程序
    将高级语言源程序翻译成目标程序
  • 解释程序
    将高级语言源程序翻译成机器指令,是边翻译边执行

JAVA语言是半编译半解释的,目的是为了跨平台

C++程序是直接编译成本地机器语言代码

C++程序开发过程

  • 算法与数据结构设计
  • 源程序编辑
  • 编译
    先做语法检查
    编译
  • 连接
  • 测试
  • 调试

信息的表示和存储

计算机中的信息与存储单位

计算机中的基本功能

  • 算术运算
  • 逻辑运算

计算机中的信息

  • 控制信息
    指挥计算机操作
  • 数据信息

信息的存储单位

  • 位 bit
    数据的最小单位
  • 字节 Byte
    8位二进制 1Byte = 8bit
  • 千字节
    1KB = 1024B
  • 兆字节
    1MB = 1024KB
  • 吉字节
    1GB = 1024MB

计算机的数字系统

数字系统是二进制系统,基本符合0,1

三个二进制 = 一个八进制 四个二进制 = 一个十六进制

R进制 转 十进制:

  • 各位数字与他的权相乘,其积想加

例如:
11111111.11 = 1 * 27 + 1 * 26 + 1 * 25 + 1 * 24 + 1 * 23 + 1 * 22 + 1 * 21 + 1 * 20 + 1 * 2-1 + 1 * 2-2
= 255.75

十进制 转 R进制:

  • 除以R 取余

十进制小数 转 R进制小数:

  • 乘以R 取整

数据的编码表示

0 表示正数
1 表示负数

原码:

  • 符号 – 绝对值 表示的编码
  • 缺点
    • 0的表示不唯一
    • 进行四则运算时,符号位需单独处理且运算规则复杂

补码:

  • 0的表示唯一
  • 符号位可作为数值参加运算
  • 补码运算结果还是补码

模数:
n位二进制整数的模数为2的n次方
n位小数的模数是2

补数:
一个数减去另一个数(加上一个负数)
等于第一个数加第二个数的补数

例如:
8 + (-2) = 8 + 10 (mod 12) = 6

补码的计算规则

反码:作为中间码

反码的计算规则:
负整数

  • 原码符号位不变(仍是1)
  • 其余各位取反(0 变 1 , 1 变 0)

例如:
X = -1100110
原码 = 11100110
反码 = 10011001

正整数
原码就是反码就是补码

补码的计算规则

  • 反码作为中间码
  • 负数补码 = 反码 + 1
  • 正数补码 = 原码 = 反码

如果负数之和得正数或正数之和为负数说明运算结果溢出

小数的表示

浮点方案

N = M * 2E

E:2的幂次,称数N的阶码,反映了该浮点数所表示的数据范围
M:N的尾数 位数反映了数据的精度

字符的表示

字符在计算机中通过编码表示

  • ASCII码:
    常用的西文字符编码,7位二进制表示一个字符,最多可表示 2的7次方 = 128个字符
  • 汉字编码
    中国国家标准