指针,用来描述内存地址,并通过提供指针操作来实现与内存相关的程序功能。
1. 定义
<类型>* <指针变量>;
类型决定了指向的内存空间的大小。
指针变量也是一种变量,有着自己的内存空间,该空间上存储的是另一个变量的内存空间。
可以使用typedef取别名来减少定义变量时的一些麻烦,如typedef int* Pointer;
2. 操作
1)取地址
‘&’
int* p; int x; p = &x;//p指向x的地址,p的类型是int*, &x的类型也是int*
2)间接访问
对于一般的指针变量,访问格式是:*<指针变量>
结构类型的指针变量,访问格式是:(*<指针变量>).<结构成员> 或 <指针变量>-><结构成员>
3)赋值
任何类型的指针都能赋给void *类型的指针变量,而非void * 类型的指针变量只能接受同类型的赋值。
4)指针运算
一个指针加上或减去一个整型值:<数据类型>* <指针变量>; int a; <指针变量>+a;可以理解为数组中下标的变化,
<指针变量> = <指针变量>+(a*sizeof(<数据类型>))
两个同类型的指针相减:结果是整型值,对应的是存储空间中元素的个数,可用于求数组的大小。
两个同类型的指针比较:比较的是存储内容(也就是内存地址)的大小,可用于数组求和等。
5)指针的输出
非char *类型的指针变量:cout<<p;//输出的是p存储内容(内存地址) cout<<*p;//输出的是p存储内容上的内容
char *类型的指针变量:cout<<p;//输出的是以p为起始地址的字符串,这种用法在字符串变化中很常见 cout<<*p;//输出的是p上的一个字符
3. 指向常量的指针变量
const <类型> *<指针变量>;
含义:不能改变指向的地址上的值(无论该地址上是常量还是变量),但是该变量的值是可以改变的。
4. 指针与动态变量
动态变量是在程序运行时才产生,并在程序结束前消亡。动态变量跟局部变量不同,在程序运行前编译程序就知道了局部变量的存在
创建:
new <类型名>; 如:int *p; p=new int; *p=1;
new <类型名>[<整型表达式1>]…[<整型表达式n>]; 如:int (*q)[20]; int n=5;q=new int[n][20];
void *malloc(unsigned int size); 如:double *q; int n=2; q=(double *)malloc(sizeof(double)*n);
撤销:因为动态变量不能自动消亡,需要显示撤销其内存空间。
delete <指针变量>; 如:int *p=new int; delete p;
delete []<指针变量>; 如:int *p=new int[20]; delete []p;
void free(void *p); 如:int *p=(int *)malloc(sizeof(int)*6)
应用:动态数组、链表
5. 指针 VS 无符号整数
指针从形式上看属于无符号数,但是指针可以关联到程序实体(变量或函数),指针指向某个内存地址,无符号整数的某些运算不能实施在指针上(如乘法和除法就不能)。
6. new VS malloc
1)new 自动计算所需分配的空间大小,而malloc需要显示指出。
2)new自动返回相应类型的指针,而malloc要做强制类型转换。
3)new会调用相应对象类的构造函数,而malloc不会。
对于new 和 malloc,如果程序的堆区没有足够的空间可供分配,则产生bad_alloc异常(会返回空指针NULL)。
7. delete VS free
1)delete会调用析构函数,free不会。
2)delete或free一个指针时,其实只是从编译器释放了这个地址的内存,但指针仍然指向该地址,此时的指针叫做悬浮指针,悬浮指针不为空指针,依据可以用来赋值或者和使用,所以会产生语义错误。(怎么解决呢?在delete或free后将指针设置为NULL)。
3)如果没有进行delete或free操作,就将指针指向别处,之前分配的内存空间就会一直存在但不能再被使用,也就是说造成了内存泄漏。
8. 函数指针
函数指针就是指向函数的指针。
定义格式:<返回类型> (*<指针变量>)(<形式参数表>); 如:double (*fp)(int); double fun(int x); fp=&fun;
或 typedef <返回类型> (*<函数指针类型名>)(<形式参数表>); <函数指针类型名> <指针变量>; 如:typedef double (*FP)(int); FP fp;
使用:(*<指针变量>)(<形式参数表>); 如 (*fp)(10); 相当于 fun(10);
为什么使用函数指针:可以实现多态,一个函数指针指向不同的函数就可以实现不同的功能,可以结合设计模式理解。
可以向函数传递函数,如:int func(int (*fp)(int)){};
9. 指针与数组
对数组元素的访问通常是通过下标来实现的,但是频繁地采用这种方式,有时效率不高,因为每次访问都要先通过下标计算数组元素的地址(就是上面的提到的指针变量加上一个整型数)。
10. 多级指针
指针除了可以指向一般类型的变量外,还可以指向指针类型的变量。指针变量要初始化后才能使用。
如果一个指针变量没有初始化或者赋值,访问它所指向的变量将会导致运行时刻的严重错误。
int x;
int *p;
int **q;
*p=1; //Error, p未初始化,p指向的空间不知道是什么
*q=&x; //Error,q未初始化
q=&p; //OK
**q=2; //Error, q指向的变量p未初始化
11. 指向常量的指针类型 VS 指针类型的常量
指向常量的指针类型:不能改变指向的内容。如:const int *p;
指针类型的常量:指向的地址不能发生改变,内容可以改变,但是必须要初始化。如 int x; int *const q=&x;
两者结合:const int*const r;
今天的文章C++ 指针类型分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/29826.html