1.指针数组与二维数组的区别:
指针数组不是按行进行存放的,二维数组是按行存放的,二维数组存放完第一行紧接着存放第二行,但是指针数组的每一行存放的时候并不是连续的,如下图所示:
指针数组与二维数组的定义:
int num1[]={1,2,3};
int num2[]={4,5,6,7};
int num3[]={8,9,10,2,3};
//定义长度为3的指针数组,数组的元素是一维数组首元素的地址
int *num[3]={num1,num2,num3};
指针数组相对于普通数组的优点:普通数组如果是二维数组,每一行的长度都必须是一样的,但是指针数组可以使得每一行的长度都不一样。
函数说明:static_cast:取浮点数的整数部分:
参考:static_cast
2.常量指针:指针所指向的是一个常量,表示该元素在实参到形参的传递过程中它的值不希望被修改
const int N=10;
const int *a=&N;
3.指针类型的函数
希望调用函数时,返回的类型是指针类型,需要注意的基点:
- 不能将非静态局部地址作为函数的返回值
应该返回的是到了主调函数中依然合法有效的地址
还有一种情况返回的地址是有效的:如果在被调用的函数中使用new动态分配的一块地址空间,它可以作为返回值进行返回,因为new的地址空间不会在函数调用完以后主动的释放,除非delete,但是不要忘了释放内存,防止内存泄漏。
4.指向函数的指针
指针里面存放的是函数代码的起始地址
定义形式:存储类型 返回值类型 (*函数名)(参数列表)
5.对象指针
定义形式:对象类型 *对象名
6.this指针
指向对象自己的指针
7.动态内存分配与释放
分配:new 类型名T(初始化列表)
释放:delete 指针p
特别注意:delete不是删除这个指针本身,而是释放他所指的空间,如下面的例子:
delete ptr1以后,下面又继续用ptr1,说明delete仅仅释放的是其指向的空间,该指针还是存在的。
分配和释放动态数组:
分配:new 类型名T[数组长度]
释放:delete[] 数组名
特别提醒:用new分配的空间一定要释放
多维数组的指针+1会跳跃整个空间,如下所示:
动态数组封装成类
element函数的返回值是一个左值引用,目的是在主函数中进行move的时候改变的不是其副本,而是其本身。
8.智能指针
9.vector类型的定义
定义:vector<类型名> 数组对象名(大小)
10.浅层复制与深层复制
浅层复制:实现对象的一 一对应的复制
深层复制:被复制的数据成员是指针类型,而不是该成员本身,是该指针所指的对象
pointArray1中需要desctructor两次,因为该数组里面有两个元素,同样pointArray2也需要desctructor两次,它是poingArray1的浅层拷贝。
上面运行出错了?
原因如下:
pointArray2只是复制了pointArray1的内容,并没有复制一块新的空间,所以这里当pointArray1 descructor以后数组的空间已经被释放,当pointArray2再准备释放的时候就已经没有可释放的资源了。
自己编写构造函数来实现深层复制:
11.移动构造
移动构造是从复制衍生出的,有些时候,我们并不需要完全的复制一个对象,而是“转移”,从一个对象转移到另一个对象。简而言之,就是将源对象资源的控制权转移到目标对象
方法一:复制构造
简单来说明下运行结果:
- 在主函数中首先调用getNum()函数,在调用该函数时,会定义IntNum类型的元素a,这时候打印第一行“Calling constructor”;
- 在该函数中返回a的时候会将a的空间释放,但在释放之前会拷贝一下使之能够返回到主函数中,就有了“Calling copy constructor”
- 然后再释放空间“Destructing”
- 回到主函数中,调用getInt(),将返回的值打印
- 打印完,程序运行结束,将空间释放掉
方法二:移动构造
注意移动构造函数和复制构造函数的区别,移动构造函数里面将传递来的参数的定义成右值引用,移动完成将其指针置为NULL
12.字符串
cin输入字符串的时候以空格作为结束,如果想输入带空格的字符串用getline