目录
一、准备工作(C++方面)
1.1 VisualStudio设置
桌面开发 + 用C++开发游戏 ——> 下载并安装需要的组件
1.2 C++程序的编译流程
1.2.1 预处理——Preprocess
去掉注释,展开include
1.2.2 编译——Compile
将预处理阶段的代码转为汇编语言
1.2.3 汇编——Assemble
将汇编转为机器语言
1.2.4 链接——Link
将程序不同部分合并在一起形成可执行文件
1.3 类型转换
1.3.1 宽向转换(绝对安全)
低宽度转为高宽度(例如:char 类型的宽度是8位, 转为short类型16位)
1.3.2 窄向转换(不安全)
高宽度转为低宽度
1.3.3 宽度表格
1、编译系统给int型数据分配的内存可能是2个字节或是4个字节,具体由编译系统自行决定。例如:Turbo C 2.0分配的是2个字节,而Visual C++则分配4个字节。
2、在编程考虑数据规模时,如果记不清楚具体数值范围,可根据十进制位数来决定使用什么类型。例如:当需要存储一个大小为100 000 000 0的数时,可以选择大于等于10位十进制数范围的类型,如long、long long 等。
Integer types:
Name | Size(in bits, on x86) | Range |
bool | 8 (top 7 bits are ignored) | o or 1 |
char | 8 | -128 to 127(signed) or 0-255(unsigned) |
short | 16 | -32768 to 32767(signed) or 0-65535(unsigned) |
int | 32 | -2147483648 to 2147483647(signed) or 0-4294967295(unsigned) |
long | 32(can be 64 on other architectures) | same as int |
long long | 64(this is a non-standard GNU extension) | -9223372036854775808 to 9223372036854775807(signed) or 0-18446744073709551615 |
Floating Point type:
Name | Size(int bits,on x86) | Range | Notes |
float | 32 | +/-1.4023x to 3.4028x | general purpose real-number |
double | 64 | +/-4.9406x to 1.7977x | higher-precision real number |
long double | 96(this is a non-standard GNU extention) | ?? | For numbers with very large ranges and high precision |
1.4 头文件
一个放函数声明的地方。
//函数声明
int Add(int);int Main
{}
//函数定义
int Add(int)
{
}
声明: 告诉编译器,有一个名字Add,返回值和参数需要int的函数
定义: 在内存中拓展出一片空间给该函数分配内存
声明是不开辟内存空间,而定义必须占用内存空间
在C#中定义一个函数后可以直接进行使用,而不用在主体函数体上方声明函数
1.5 指针
1.5.1 指针的基本
具有自己的标识,程序员可见的内存地址,可测量的内存大小。
引用自带非空语义。
&: 取地址运算符
*:间接运算符或取消引用运算符(其实就是取值)
好!人已经开始晕了。刚看到函数指针, 指针函数, 指针的指针。。。
int a;
int *b; //指针变量, 存储地址
int a = 5;
b = &a; // 取a的地址赋值给b 那么在b的地址上存储的是a的地址
//--------------------------------------
// 此时: 输出
cout << a; // 5
cout << &a; // 存a的地址 (0x123)
cout << b; // 由于b存的是a的地址, 所以值是 a的地址(0x123)
cout << *b; // 取这个指针变量, 也就是该指针指向a的变量: 5
// 当*与&同时存在(即*&a)时抹消两个符号,即 *&a = a
// 若修改*b则a的值也会发生变化
*b = 10;
cout << a; // 输出为10
//---------------------------------------
// 数组名 = 数组的首地址 即 arr = &arr[0]
- 下方有解释指向指针的指针, 但是这种多层指针一般不会用到, 指针最常见的用途是构造数据结构和操作内存
- 在64位的操作系统中, 不管是什么类型的指针, 占用的内存都是8字节。
- 在32位的操作系统中, 不管是什么类型的指针, 占用的内存都是4字节。
1.5.2 常量指针,指针常量与常指针常量
1.5.2.1 常量指针(经常使用)
- 语法: const 数据类型 *变量名
- 常量指针不能通过解引用的方法修改内存地址中的值(用原始的变量名是可以修改的)
1.5.2.2 指针常量(不常用)
- 语法: 数据类型 *const 变量名
- 指向的变量(对象)不可改变
- 在定义时必须初始化
- 可通过解引用的方法修改内存地址中的值
- C++编译器将指针常量做了特别处理后,改名引用
1.5.2.3 常指针常量
- 语法: const 数据类型 *const 变量名
- 指向的变量(对象)不可改变, 不能通过解引用的方法修改内存地址中的值
- 新名字——常引用
常量指针: 指针指向可以改, 指向的值不可修改
指针常量: 指针指向不可更改, 指向的值可以改
常指针常量: 指针指向不可更改, 指针指向的值不可更改
1.5.3 void 关键字
- void * 表示接受任意类型的指针, 只关心地址本身, 不关心里边的内容
- 不能用void声明变量, 它不能代表一个真实的变量
- 不能对void *指针直接解引用(需要转换成其他类型的指针)
- 把其他类型的指针赋值给void *指针不需要转换
- 把void *指针赋值给把其它类型的指针需要转换
- 刚开始看到它可能不习惯, 以后每天都能看到它, 看多了就熟了
1.5.4 空指针(0 或 NULL)
- 对空指针解引用, 程序会崩溃
- 对空指针使用delete运算符, 系统会忽略该操作, 不会出现异常。所以内存释放后, 也应把指针指向空
- 在函数中, 应该有判断形参是否为空指针的代码, 目的是保证程序的健壮性
- C++11建议用nullptr表示空指针, 也就是 (void *)0.
- 在Linux平台下, 如果使用 nullptr , 编译需要加 -std=c++11参数
1.5.5 野指针
- 指针指向的不是一个有效(合法)的地址
- 如果访问野指针,可能会造成程序的崩溃
- 出现野指针的情况有三种
- 指针在定义时没有初始化,它的值是不确定的
- 如果用指针指向了动态分配的内存,内存被释放后指针不会置空,但是指向的地址已失效
- 指针指向的变量已超越变量作用域(变量内存空间已被系统回收)
-
int *func() { int a = 3; return &a; } *int main() { int *p = func(); }
- 规避方法
- 指针在定义的时候,如果没有地方指就初始化为 nullptr
- 动态分配的内存被释放后,将其置为 nullptr
- 函数不要返回局部变量的地址
- 使用智能指针
1.5.6 数组
- 指针的数组表示
- C++ 编译器把 数组名[下标] 解释为 *(数组首地址 + 下标)
- C++编译器把 地址[下标] 解释为 *(地址 + 下标)
- 这种方式就可以理解为 p[3] == a[3]。 p[3] == *(p + 3)
-
int a[5] = {3, 6, 5, 8, 9}; int *p = a;
- 一维数组用于函数的参数时,只能传数组的地址,并且必须把数组长度也传进去,除非数组中有最后一个元素的标识
- 动态创建一维数组语法: 数据类型 *指针 = new 数据类型[数组长度];
- 释放语法: delete[] 指针;
- 动态创建的数组没有数组名,不能用 sizeof 运算符
- 可以用数组表示法和指针表示法两种方式使用动态创建的数组
- 必须使用 delete[] 来释放内存(不能只用 delete)
- delete只会释放第0个元素的内存空间
- 不要用 delete[] 来释放不是 new[] 分配的内存
- 不要用 delete[] 释放同一个内存块两次(否则等同于操作野指针)
- 对空指针用 delete[] 是安全的(释放内存后应该把指针置空 nullptr)
- 声明普通数组时数组长度可以用变量,相当于在栈上动态创建数组,并且不需要释放
- 如果内存不足,调用new会产生异常,导致程序终止,如果在new关键字后加(std::nothrow)选项,则返回 nullptr ,不会产生异常
-
int main() { int *a = new (std::nothrow) int[1000000001]; if(a == nullptr) { return; } else { a[1000000000] = 8; delete[] a; } }
- 由于系统会自动跟踪已分配的内存,所以 delete[] 释放数组的时候不需要指定数组大小
- 指针是指针,地址是地址,指针是一个容器,用于存放地址
1.5.7 函数指针
- 声明函数指针
- 让函数指针指向函数的地址
- 通过函数指针调用函数
- (有点像c#中的委托)
void func(int no, string str) { } int main() { int bh = 3; string message = "1111" func(bh, message); void (*pfunc)(int, string); pfunc = func; pfunc(bh, message); }