以下为个人学习笔记整理。参考书籍《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] == *array
array[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}; |