以下为个人学习笔记整理。参考书籍《C++ Primer Plus》
# 复合类型
# 指针、数组、指针算术
# 指针
- 申明: 
typeName * pointerName。 - 赋值:
 
double* pn,pa;  | |
char* pc;  | |
double bubble = 3.2;  | |
pn = &bubble; // 指向 bubble 的地址。  | |
pc = new char; // 分配一个 char 大小的地址空间给 pc  | |
pa = new double[30]; // 分配 30 个 double 大小的地址空间给 pa  | 
取值:
*pointerName。区分指针和指针所指内容:
- 指针存储的是对象地址。
 - 通过 
*获取所指地址内的值。 
数组名:数组名视为数组第一个元素的地址。
int array[10];// array = &array[0]指针算术:
int array[10] = {1,2,3,4,5,6,7,8,9,1}  | |
int* pt = array; // pt = &array[0]  | |
pt += 1; // pt = &array[1]  | |
int* pe = &array[9];  | |
pe -= 1; // pe = &array[8]  | |
int diff = pe - pt; // diff = &array[8] - &array[1] = 7  | 
数组动态联编和静态联编:
- 静态联编,再编译时确定数组长度: 
int array[10]; - 动态联编,在运行时确定数组长度: 
int* array = new [size]; delete[] array;//记得释放内存 
- 静态联编,再编译时确定数组长度: 
 数组表示法和指针表示法:
array[0] == *arrayarray[3] == *(array + 3)
cout对于char*类型的指针,会视作字符串进行输出,知道遇到\0时停止。结构名和结构指针:访问结构对象的成员属性时,有两种方式:
- 如果操作的是结构名,可以用 
.来访问:structName.propty - 如果操作的是结构指针,可以用 
->来访问:pointerStruct->propty - 或者通过指针获得结构体,再进行访问: 
(*pointerStruct).propty 
- 如果操作的是结构名,可以用 
 
# const 修饰符
const type* pointerName(常量指针)。const 修饰的指针不可以修改指向地址内存储的值。
int age = 24;  | |
const int* pt = &age;  | |
int money = 1;  | |
pt = &money; // ok, change pointer  | |
//*pt = 100; // no, change pointer val | 
C++ 禁止将 const 的地址赋给非 const 指针。
type* const pointerName(指针常量)。修饰的指针不可以修改指向,但可以修改所指地址。
int val = 10;  | |
int* const pt = &val;  | |
int val_1 = 100;  | |
*pt = 100; // ok, change pointer val  | |
pt = &val_1; // no, change pointer  | 
const type* const pointerName(指向常量的常量指针)。所指地址不可变,所指地址内存储的值不可变。
int val = 10;  | |
const int* const pt = &val; // 需要在初始化的时候赋值  | |
int val_1 = 100;  | |
*pt = 100; // no, change pointer val  | |
pt = &val_1; // no, change pointer  | 
const type& x和type const& x等效,都表示const类型的引用,不可修改引用内的值。const type* p和type const* p等效,都表示p指向一个类型,并且该类型是const的,不可修改。func() const用作类函数时,表示该类对象需要为const才可以执行该函数。
扩展阅读:传送门
# 尽可能使用 const
- 可以避免由于无意间修改数据而导致的编码错误。
 const修饰的变量,能够接受const和非const的数据。
# 数组的地址
数组名被解释为其第一个元素的地址。
对于数组名取地址操作将视为获得整个数组地址。
int array[2];  | |
array + 1; //array next means 偏移一个 int 4 bytes  | |
&array + 1; //next array means 偏移整个数组 8 bytes  | 
string类型的=赋值是深拷贝。而char*的拷贝只是变更指向地址。
# 函数传参
int main()  | |
{ | |
int arr[10] = { 0 };  | |
int count = 10;  | |
cout << "arr args size = " << sizeof(arr) << endl;  | |
test_args(arr, count);  | |
return 0;  | |
} | |
// 等价于 test_args (int* arr, int count)  | |
// 传递数组参数本质上就是传递数组第一个元素地址 | |
void test_args(int arr[], int count) {  | |
cout << "「test_args」:arr args size = " << sizeof(arr) << endl;  | |
} | 

# 自动存储、静态存储、动态存储
# 自动存储
函数内部定义的变量使用「自动存储空间」。函数调用时,自动产生,结束后自动销毁。
- 自动变量通常存储在「栈」中。拥有先进后出「LIFO」的特性,先创建的后销毁。
 
# 静态存储
整个程序执行过程中都存在的存储方式,存在于程序的整个生命周期。在函数外定义或者申明为 static 类型。
# 动态存储
一段可以由程序自己管控的「自由存储空间」—— 堆。通过 new 和 delete 来申请和释放。和自动存储、静态存储是分开的。
# 数组的替代品
- vector:动态数组
 
vector<int> vi(10);  | 
- array:静态数组
 
array<int, 5> ai = {1,2,3,4,5};  |