一些须要知道的基础知识点:数组
在程序代码中是经过变量名对内存单元进行存取操做的,可是代码通过编译后将变量名转换为该变量在内存中的存放地址,对变量值的存取都是经过地址进行的。好比i+j的运算,若是i等于3,j等于4,程序是先根据变量名与地址的对应关系,找到变量i的地址,从第一个地址开始顺序读取四个字节数据放到CPU寄存器中;再找到j的地址,依次读取四个放到寄存器中,而后经过CPU的加法中断计算出结果。函数
在低级的汇编语言中都是直接经过地址来访问内存单元的,而在高级语言中才使用变量名访问内存单元,C语言做为高级语言却提供了经过地址来访问内存单元的方法,C++也继承了这一特性。地址能够形象地称为指针,意思是经过指针能找到内存单元,由于本来是经过地址找到内存单元的,因此一个变量的地址称为该变量的指针。若是有一个变量专门存放另外一个变量的地址,它就是指针变量。在C++语言中,专门用来存放内存单元地址的变量类型,称为指针类型。spa
指针是一种数据类型,一般所说的指针就是指针变量,是专门用来存放地址的变量。而变量的指针说的就是变量在内存中的地址。变量地址在编写代码时没法得到,只有在程序运行时才能够获得。指针
指针跟常规的变量为赋值相同,没有具体指向的指针不会致使编译出错,可是可能会致使难以预料的错误,因此一旦定义指针,必定要让它有一个具体的指向,也就是说要有一个地址赋给它。blog
另外,定义指针变量的时候,跟其余常规变量为了区分,要加*号,但其实真正的指针变量是没有*号的,在使用的时候要注意。继承
指针进行运算其实就是地址进行运算,指针的加减运算是跟指针的类型有关的,好比int类型的指针加1,地址值并非加1而是加4,由于int类型占四个字节。内存
※指针还能够指向空类型void。空类型指针能够接受任何类型的数据,例如void *p = NULL作用域
这里有点问题,NULL代替空指针存在二义性,因此后来用nullptr来代替空指针。总之,只要记住nullptr表明空指针就能够了,而NULL在C++中都把它理解为0就能够了。字符串
※const int *p = &i 表示这个指针是指向常量的指针,只能用来“读”内存数据,没法经过*p的方式更改内存的内容,即更改变量的值,可是能够改变自身的地址值,就是指向别的内存地址;编译器
※int* const p = &i 表示这个指针是一个常量指针,什么意思呢,觉得指针变量里存放的是地址,定义为常量指针的话,说明这个指针变量存放的地址值是不能够改变的,可是呢,能够经过*p的方式改变内存的数据;
※const int* const p = &i 表示这个指针是指向常量的常量指针,有点拗口,跟上面的对比,反正就是只能用来“读”内存数据,也没法经过*p的方式更改内存的内容,也没法改变自身的地址值。
指针和一维数组
一维数组和二维数组在内存中的存放结构都是线性的。数组第一元素的地址就是整个数组的存储首地址,该地址存放在数组名中,看吧,其实数组名就至关于一个指针变量了,里头存放的是数组的首地址。访问数组元素的方式有下标法和指针法。用数组名[i]这个方式能够访问数组内容,其实也能够经过*(a+i)的方式,固然咱们也能够再单独定义一个指针变量,将数组的首地址存放到这个指针变量中,固然了,能够用&a[0]也能够直接用a即数组名,由于咱们说过了数组名原本就存放的是数组的首地址。
*(p++)至关于a[i++],先对p进行*运算,再使p自增。
指针与二维数组
a[0]是二维数组第一个元素的地址,能够赋值给一个指针变量。
a表明二维数组的地址,经过指针运算符能够获取数组中的元素。
a+n表示第n行的首地址;
&a[0][0]既能够看作数组0行0列的首地址,还能够看作是二维数组的首地址;
&a[0]是第0行的首地址;
a[0]+n是第0行第n个元素的地址;
*(*(a+n)+m)表示第n行第m列元素;
*(a[n]+m)表示第n行第m列元素。
数组指针和指针数组
这个尚未理解好,尤为是数组指针,指针数组还好理解,就是存储指针变量的数组。
指针和字符数组
字符数组就是一个字符串,经过字符指针能够指向一个字符串,而后经过地址的加减实现读取。
传递地址
以前接触的函数都是实参传递进函数体后,生成的是实参的副本,函数体内改变副本的值并不会影响到实参,可是若是传递进去的是指针,即便是副本指针,指向的地址仍是同样的,所以能够改变指针指向地址的内容。
指向函数的指针
指针变量也能够指向一个函数。一个函数在编译时被分配给了一个入口地址,这个地址能够理解为存放在函数名中,能够定义函数指针,指向这个函数,经过指针来调用函数。
好比:
int sum(int x, int y)
int *a(int, int);
a = sum;
调用的时候这样:
int c,d;
(*a)(c,d);
还能够定义指针函数,返回值是指针,也就是地址了。
空指针调用函数
空类型指针指向任意类型函数或者将任意类型的函数指针赋值给空类型指针都是合法的。使用空指针调用自身所指向的函数仍然按照强制转换的形式使用。
指针数组
构造数据类型
结构体
C++ struct结构体变量其实跟数组有点像,只不过数组是相同类型元素的集合,而结构体变量能够是不一样类型数据的集合。
定义结构体变量有两种方式:一、在定义结构体的时候定义;二、定义完以后定义。
struct PersonInfo { int index; char name[30]; short age; }XiaoMing; 或者 struct PersonInfo { int index; char name[30]; short age; } PersonInfo XiaoMing;
引用方式:1.使用成员运算符.来引用;2.定义结构体指针变量以后,使用指向运算符->来引用
结构体还能够进行嵌套,结构体的大小通常状况下都是结构体内成员的大小之和。
使用typedef能够给一个复杂的数据类型定义一个别名,好比int(*)(int i)很复杂,就能够用一个别名来代替。
枚举类型enum的应用
枚举类型就是用大括号将不一样标识符放到一块儿,变量的值只能取自括号内的值,在定义时,编译器默认将标识符自动赋上整形常数。还能够自行修改整形常数的值,说白了就是一个标识符对应一个常数,用于一些判断或者什么,用起来方便一些。赋值的时候,不能直接赋整型数,可是能够经过强制类型转换来赋值。枚举类型的变量,实质实际上是整型的数字,因此能够进行比较和运算。
结构体
结构体变量还能够作函数的参数,还可使用结构体指针,使用结构体指针减小了时间和空间上的开销,可以提升程序的运行效率。
结构体还能够建立结构体数组,跟建立结构体变量同样,在定义结构体时建立或者定义完了以后用结构体名这种数据类型建立。能够定义结构体指针,指向数组,使用指向符号->进行读取,可是要注意,指针加1,指向的就是数组里的下一个结构体了。
共用体
共用体union数据类型其实和结构体很像,声明共用体数据类型变量和声明共用体变量同样,都有三种方式,前两种应该知道,第三种是省略了共用体数据类型变量名,在定义共用体以后接着声明变量。
要注意共用体跟结构体最大的区别在于内存方面。共用体变量所占的内存长度等于最长的成员的长度,一个共用体变量不能同时存放多个成员的值,某一时刻只能存放其实一个成员的值,这就是最后赋予他的值。
共用体的特色是:1.使用共用体变量的目的是但愿用同一个内存段存放几种不一样类型的数据,可是某个瞬间只能存放一种,而不是同时存放几种;2.可以被访问的是最后一个被赋值的变量,对新的赋值后原来的就失去做用了;3.共用体变量的地址和它的各成员的地址都是同一地址。4.不能对共用体变量名赋值,不能引用变量名来获得哦一个值,不能在定义共用体变量时对它初始化,不能做为函数参数。
自定义数据类型
跟前面的数据类型重命名同样的,使用typedef标识符进行类型的重命名,或者说是自定义数据类型,实际上是为了写起来方便或者用特定的单词表明特殊的意思。
宏定义
使用#define 能够对程序中常常出现的参数进行宏定义,这样在以后写代码的时候就能够用宏定义替换,必定程度上减轻了写代码的复杂度,程序在编译的时候自动进行替换,好比PI,通常标识符习惯用大写字母表示,以和变量名进行区分,要注意宏定义不是C语言,不须要在后面加分号,还能够定义数组和运算,定义运算的时候,括号建议都加上,以防止出现错误。若是字符串长于一行,能够在该行末尾用反斜杠\来续行。通常来说,定义只有,做用域即有效范围指的是定义命令以后到此源文件结束,但也可经过#undef命令终止宏定义的做用域。