★ 存储程序概念和内存
内存是电存储,与CPU直接通过地址总线连接,所以速度特别快,且能随机访问。它的缺陷是掉电或程序关闭后,数据会丢失。所以数据持久化需要输出到文件存储到辅助存储器(如硬盘)。
内存能随机访问是因为其有内存地址对应,如32位机就是有32条地址总线连接内存与CPU。32位的电脑可以访问4G的内存(2^32=2^10*2^10*2^10*2*2=2^30*4)
★ 编程与分治法
面向过程:函数分解。
面向对象:类与对象分解,在类的内部再分解出多个成员函数。
所以面向对象相对于面向过程而言,其颗粒度要高,就像生产一个产品,面向对象是组件装配,而面向过程是零件装配。
类如同数组、结构体一样,也是一种复合数据类型,复合数据类型有时可以作为一个集合整体操作。复合数据类型的引入就是为了增加编程的颗粒度。
★ 代码重用和标识符重用
函数、类及其重载、模板,标识符的作用域(不同作用域可以使用相同变量)、存续期,以及命名空间的语法定义。
重载是利用其函数的签名不同而产生动态绑定,而模板是一个强类型下的泛型编程。另外,模板也是可以重载的。
★ 函数库和类库
为了将出现频次高的常用代码标准化,引入后直接按接口要求调用即可。就如同用半成品直接组装成品。
★ 强类型的泛型编程
函数模板和类函数。
★ 使用转义字符的两种方式:
普通字符转义为特殊字符;
特殊字符转义为普通字符;
★ 数据表示
数据表示是指事物的数字化、二进制化;
十进制数字、字符、图像、声音都用二进制表示,二进制数字0、1用晶体管的开关来表示。
十进制数字可以直接转换为二进制数字;
字符用ASCII或Unicode等编码方案,用一个或多个存储位(Byte)来表示一个字符。
图像是一些像素点的集合,每一个像素点都可以数字化为一个RGB(255,255,255)的值。
声音可以用一定时间间隔取样的振幅来数字化。
★ 浮点数的精确度
如3.45E+16,表示3.45*10^16,浮点的点是指小数点可以浮动,相应改变指数就行。
转换成二进制的形式就是:1.xxx*2^n,尾数部分就可以表示为xxxx,第一位都是1,可以将小数点前面的1省略,所以23bit的尾数部分,可以表示的精度却变成了24bit。
在内存中的存储形式为:
图片描述(最多50字)
float:2^23 = 8388608,一共七位,这意味着最多能有7位有效数字,但绝对能保证的为6位,也即float的精度为6~7位有效数字;
double:2^52 = 4503599627370496,一共16位,同理,double的精度为15~16位。
浮点型的数据为什么会精度丢失, 或者说精度不精确呢? 其实是由于我们码农在程序里写的十进制小数,而计算机内部只能用二进制的小数, 所以无法精确的表达。对于二进制小数,小数点右边能表达的值是 1/2, 1/4, 1/8, 1/16, 1/32, 1/64, 1/128 … 1/(2^n)。所有这些小数都是一点一点的拼凑出来的一个近似的数值, 所有才会不准确的。
★ 提倡多使用全局常量,少使用全局变量
全局的数据是整个程序可见、也可以共享,全局变量还可以全局更新。全局常量的语法要求是声明的同时进行初始化,只能只读访问,不能通过重新赋值来修改。全局变量的全局更新的特点,是当程序较大时,任何地方都可以修改它,会容易失控。
全局常量:一处定义,多处访问,一处修改,多处修改;
全局变量:多处定义,多处使用,一处修改,影响全局。
(外部变量:一处初始化,多处引用(使用external),多处使用,影响全局。)
★ 变量左值、赋值与初始化
变量的左值用于赋值和初始化。变量出现在表达式右边时是以值的形式出现的,变量出现在左边时是被更新存储的值。变量可以多次更新,但初始化是第一次赋值,没有初始化的变量的值是一个不确定的值。
★ 理解预处理指令
相当于普通文档的查找、替换操作。Include是用一个文件去替换,define是用定义的值去替换。
(内联函数你也可以理解为一种查找替换,因为较短的函数产生的调用开支反而不划算。)
★ 常见错误或逻辑错误
1 溢出:基本数据类型都是有值域的,超出值域就会产生溢出。
2 数组越界:如当数组大小是10时,数据下标不能超过9(数据下标从0开始),否则就会产生越界。
3 指针未初始化,使用未初始化的指针去更新一个值时,更改的是一个不确定的内存单元的值,可能会产生意想不到的错误。
long * p;
*p = 123;
假设恰p的地址值是变量var的地址,你用*p = 123;就会修改var的值,而这不是你的初衷。
4 流的挂起:如一个整型输入的是一个字符。或文件中的一个字符读给了一个整形变量。或打开的文件不存在、路径错误、文件写保护、磁盘已满。
5 内存泄漏:如new的内存单元在使用完后一定需要delete掉,否则会耗费内存资源。
★操作符优先级和结合律
int (*pf)(int);
上面的代码要按运算符的优先级去理解,()的优先级最高,所以上面*pf加上前面的int表示是一个int指针的声明,后面跟的(int)表示是函数,则int (*pf)(int)是指一个int类型的函数指针。
单目、赋值或复合赋值运算符都是右结合,其它是左结合。
理解++i和i++的区别:
用正常的写法去考虑这种简写。
n=i++ 相当于 n=i; i = i + 1
n=++i 相当于 i = i + 1; n = i;
运算符优先级与结合律参照:http://c.biancheng.net/view/161.html
★上下文(context)的概念
不管是中文还是西文都有一词多义的情况,需要在上下文的语境中去理解。编程语言的语法虽然不允许有语义的歧义性,但同样有上下文语境的概念。如*即可以是乘法运算符,还可以用于定义指针,又可以解引用指针(引用指针指向的值)。编译器需要在上下文语境中去理解其具体含义:
int i = 5 * 4; //*用作乘法,因为其两个操作数是整型
int *p; //*用作指针声明
p = &i;
*p = 45; //*用作指针的解引用
当*前面有数据类型时,*是指针声明,如果前面没有数据类型,后跟一标识符时,是解引用。
函数的重载,编译器也需要在上下文中(函数签名,也就是函数声明)去理解。类中对象的多态也是如此,往父类方向调用最近同名方法。
上下文语境的存在,是因为毕竟操作符有限,另外,尽量不使用太多的关键字,如static,既可用于定义静态变量(延长变量的存续期),又可用来定义一个变量的作用域(限制全局变量的作用空间)。
★ 程序的输入、输出
程序是对数据的表示、存储和处理,而输入、输出也是其很重要的组成部分。程序的整体是如此(如控制台程序使用输入输出函数,GUI图形用户界面程序使用窗体、菜单和工具栏、事件驱动),程序的组成模块(函数和类)也是哪些,可以用输入、数据处理、输出三个部分去有机构造。
文件的读写相对于内存来说也是一种输入输出。
图片描述(最多50字)
★ 有了比较运算符为什么还需要逻辑运算符
在分支选择和循环结构中需要使用这两种运算符。而逻辑运算符的非运算可以取反,其它的逻辑运算符可以组合多个逻辑条件。
★ C语言的整型与字符型、布尔值、枚举类型变量值
C语言中的字符是用整形数据来表示的(以整数的形式存储在内存,输入输出时进行转换),区别在于使用的存储位不同,二都可以进行转换操作。
C语言中没有布尔类型,用0表示布尔值false,用非0表示布尔值true。
枚举类型定义的变量的取值都是命名整型常量。
★ 循环类型
1 计数控制的循环
一般使用for循环来实现计数控制循环:
for(expression1; expression2; expression3)
statement
在expression中可以使用逗号运算符,可以包含一个或多个计数器变量。expression1一般用于计数器变量的初始化,expression2用作条件判断,expression3一般用做计数器变量的更新,其数值变化的方向与expression2判断的值相一致,以确保能退出循环。)
2 事件控制的循环
2.1 基于哨兵或旗帜;
2.2 基于文件尾;
★ 汇编语言没有控制结构如何实现分支选择与循环?
使用JUMP指令实现跳转,机器语言直接进行地址跳转;
★ 函数的值传递、指针传递、引用传递
int k = 12;
int * p;
p = &k;
int &r = k;
int f1(k);
int f2(k); //int f2(int &k);
int f3(r);
首先,在未调用前,k、p都会在栈内存中分配存储单元。调用后,不管是那一种形式的调用,又会在被调用函数的作用域对应的栈内存中分配存储单元。对于值传递而言,两个空间没有任何联系,所以彼此的更新不会相互影响。而指针传递就不同,两块内存是通过指针连接的,被调函数修改的不是指针存储的地址值,而是其地址值对应的值。对于引用传递而言,形参定义的是一个变量的别名(一个变量两个名字),本身并不分配内存空间,操作的是别名对应的变量。
图片描述(最多50字)
★ 作用域和生命周期
存储空间节省的考量和标识符重用的考虑。
★ 驱动函数和哑元函数
函数要被调用后才能运行,所以一般用main作为主函数去调用其它函数,main主函数就叫驱动,驱动函数有时也叫客户端。
哑元函数是一个复杂的函数未完整实现前先用一行简单的return语句代替,用于平衡开发进度或与其它函数联调时测试用。
★ break语句和continue语句
当需要在循环体中根据具体情况来确定退出某一次或整个循环时,需要用这两个语句与if语句一起使用来变更循环走向。
★ typedef一般用于提高程序的移植性或简化书写
Typedef const double * cdp;
Typedef int bool; //C语言中没有定义bool类型,C语言中是用0表示false,非零表示right。
★ 结构体的集合操作
1 允许的情形:参数传递和函数返回;
2 不允许的情形:输入输出、加减乘除、比较运算。
(类也是一个数据集合,同样不允许一些运算符的集合操作,但可以重载运算符。)
★ 类与对象的this指针
class Time
{
int hrs;
int mins;
int secs;
Set(int hours, int minutes, int secs)
{
hrs = hours; //相当于this->hrs = hours
mins = minutes;
this->secs = secs; //形参与数据成员重名时不能省略this
}
};
★ 三种定义数组的方式
1 定义静态数组:数组的下标只能是常量或常量表达式;
2 定义动态数组
int n;
cin>>n;
int *arr = new int[n];
(arr可以直接当做数组使用,如果是stru *s = new stru[n],stru是一个结构体,则是申请了一个动态结构体数组。)
3 使用STL的vector结构
(C11还可以使用<array>模板类)
★ 数组的集合操作
1 作为函数参数或返回值的引用传递。
2 字符数组的输入输出
char str[] = {'h','i','/0'};
char str[] = "hi";
cout<<str;
★ 多维数组
在计算机底层是行优先的一维线性的内存存储。
二维数组可以理解为一个行列式。
数组名相当于一个常量指针。
★ 定义指针为什么还要定义类型
不管哪个类型的指针,其长度是一样的,还要考虑定义类型的原因主要是:
1 C++是强类型语言,操作符两边类型要一致;
2 解引用时如果没有定义类型,无法确定需要读取多少存储空间;
3 指针偏移(加法运算)时无法确定在内存中的偏移量,如double类型的指针在做加1的运算时,实际上是在内存中偏移了8个存储位。
★ 汇编语言没有控制结构如何实现分支选择与循环?
汇编语言用JUMP指令跳转。指令语言直接实现地址跳转。
★ 常量指针
常量指针中并没有常量,只是表示你不能指针去修改或更新指向的数据。
int i =16;
int j = 12;
const int* pi = &i;
//int const* pi = &i;
//*pi = 22; //l-value specifies const object
pi = &j; //允许,指针不是常量,可以更新
i = i+20; //允许,只是不能用指针常量去修改,可以直接通过变量右值来更新左值
cout<<*pi<<endl;
cout<<i<<endl;
指针常量是指你不能使用指针去修改其指向的对象,如*pi = 22;这样做是不允许的。但你可以直接使用变量去更新其值,如上面的i=20;
另外,int const* pi与const int* pi没有区别。
★ C++的结体体和类
两者除了成员变量的访问控制不同以外,其它方面的功能完全一样。
★ 开关循环(switch)一般使用枚举类型做为标签
枚举类型可以定义有限个变量,这些变量的取值都是命名整型常量。
#include <iostream>
// create named constants for 0 - 6
enum {red, orange, yellow, green, blue, violet, indigo};
int main()
{
using namespace std;
cout << "Enter color code (0-6): ";
int code;
cin >> code;
while (code >= red && code <= indigo)
{
switch (code)
{
case red : cout << "Her lips were red.\n"; break;
case orange : cout << "Her hair was orange.\n"; break;
case yellow : cout << "Her shoes were yellow.\n"; break;
case green : cout << "Her nails were green.\n"; break;
case blue : cout << "Her sweatsuit was blue.\n"; break;
case violet : cout << "Her eyes were violet.\n"; break;
case indigo : cout << "Her mood was indigo.\n"; break;
}
cout << "Enter color code (0-6): ";
cin >> code;
}
cout << "Bye\n";
return 0;
}
参考:鲍钰《通俗易懂C++》
-End-
本页共201段,6367个字符,14360 Byte(字节)