一、数组指针和指针数组:
独家记忆:可以在这两个名字的中间都加上“的”,即“数组的指针”和“指针的数组”。这样就好理解了,因为“数组的指针”,那肯定是一个指针,指向了一个数组;而“指针的数组”,就是一个数组,而数组中的元素的类型就是指针。
例子:区分 int *p1[10] 和 int (*p2)[10];
分析:第一个int 后面直接有*,所以它是一个指针,是一个指向了一个数组的指针,所以是“数组的指针”,即数组指针。
第二个int后面没有直接的*,所以它是一个数组,而这个数组中存放的是指针,所以是“指针的数组”,即指针数组。(如果进一步探究,每个元素即指针的类型,则可以由int得到指针是整型指针)
难点:第一种不可以进行加以操作,即不存在p1++。原因是p1不是元素的名字。而第二种可以进行加一操作,即存在p2++,原因是p2可以看成是指向第一个元素的指针。
二、函数指针和指针函数:
独家记忆:都加上一个“的”,变成“函数的指针”和“指针的函数”,“函数的指针”比较好理解,就是一个指针指向了一个函数;“指针的函数”就要换一种说法,再加几个字变成“返回值是指针的函数”,这样就好理解了。
例子:int *f(int,int) 和int (*f)(int, int)
分析:第一个函数名是f,返回值是int*,也就是返回值是一个指针,所以是返回值是指针的函数,即指针函数。
第二个*f是指针,这个指针是一个函数的指针,这个函数参数是两个int,返回值是int,所以是函数的指针,即函数指针。
三、指针常量和常量指针:
独家记忆:都加上一个“的”,变成“指针的常量和“常量的指针”,“指针的常量”也不是很好理解,再加两个字“指针修饰的常量”,这样就好理解了,它是一个常量,这个常量用指针修饰。“常量的指针”也就是“指向常量的指针”。
例子: int const* p和const int* p和int* const p
分析:这个相对简单一点,先不用管int的位置,只需要把const翻译成常量,然后按照const和*的顺序从左向右读出来即可。比方说,第一个:整型常量指针;第二个,常量整型指针;第三个,整型指针常量。
难点:
//-------常量指针------- const int *p1 = &a; a = 300; //OK,仍然可以通过原来的声明修改值, //*p1 = 56; //Error,*p1是const int的,不可修改,即常量指针不可修改其指向地址 p1 = &b; //OK,指针还可以指向别处,因为指针只是个变量,可以随意指向; //-------指针常量-------// int* const p2 = &a; a = 500; //OK,仍然可以通过原来的声明修改值, *p2 = 400; //OK,指针是常量,指向的地址不可以变化,但是指向的地址所对应的内容可以变化 //p2 = &b; //Error,因为p2是const 指针,因此不能改变p2指向的内容 //-------指向常量的常量指针-------// const int* const p3 = &a; //*p3 = 1; //Error //p3 = &b; //Error a = 5000; //OK,仍然可以通过原来的声明修改值
四、空指针,野指针和内存泄露:
独家记忆:空指针就是保存地址为空的指针,使用指针时必须先判断是否空指针,很多问题都是这一步导致的。野指针是在delete掉指针之后,没有置0,导致指针随意指向了一个内存地址,如果继续使用,会造成不可预知的内存错误。
//-------空指针-------// int *p4 = NULL; //printf("%d",*p4); //运行Error,使用指针时必须先判断是否空指针 //-------野指针(悬浮、迷途指针)-------// int *p5 = new int(5); delete p5; p5 = NULL; //一定要有这一步 printf("%d", *p5); //隐藏bug,delete掉指针后一定要置0,不然指针指向位置不可控,运行中可导致系统挂掉 //-------指针的内存泄漏-------// int *p6 = new int(6); p6 = new int(7); //p6原本指向的那块内存尚未释放,结果p6又指向了别处,原来new的内存无法访问,也无法delete了,造成memory leak
五、数组和指针的区别:
1、数组要么在静态存储区被创建(如全局数组),要么在栈上被创建。指针可以随时指向任意类型的内存块。
2、数组对应着一块内存区域,而指针是指向一块内存区域。其地址和容量在生命期里不会改变,只有数组的内容可以改变;而指针却不同,它指向的内存区域的大小可以随时改变,而且当指针指向常量字符串时,它的内容是不可以被修改的,否则在运行时会报错。
3、用运算符sizeof可以计算出数组的容量(字节数),而用sizeof却无法计算指针所指内存的容量,用sizeof(p)得到的结果永远是4或者2(即指针变量所占内存单元的字节数,一般情况下指针变量占2个或4个字节的内存单元)。在进行参数传递时,数组会自动退化为同类型的指针。
六、指针和引用的区别:
1、 引用必须被初始化,指针不必。
2、引用初始化以后不能被改变,指针可以改变所指的对象。
3、不存在指向空值的引用,但是存在指向空值的指针。
七、结构体和联合的区别:
1、结构和联合都是由多个不同的数据类型成员组成, 但在任何同一时刻, 联合中只存放了一个被选中的成员(所有成员共用一块地址空间), 而结构的所有成员都存在(不同成员的存放地址不同)。
2、 对于联合的不同成员赋值, 将会对其它成员重写, 原来成员的值就不存在了, 而对于结构的不同成员赋值是互不影响的。