指针
用结构类型的指针变量来访问成员,方法有二
- (*结构变量).结构成员
- 结构变量->结构成员
当一个指针与一个整型值进行加减运算时,实际加减的值由指针类型决定。
- 如 double *p;p-=4;//p的值减4*sizeof(double)
int a[10];
int *p;
p=&a[0];
//则可用p[0],p[1],p[2]来访问数组元素,等价于*(p+0),*(p+1),*(p+2)
两个同类型的指针可以相减,通常用以计算两个指针所指向的数组元素之间有多少个元素
两个同类型的指针之间可以比较大小,比较的是所对应的内存地址的大小
//用指针求数组元素之和
int a[10],*p=&a[0],*q=&a[9],sum=0;
while(p<=q){
sum+=*p;
p++;}
- 指针的输出
int a,*p=&a;
cout<<p;//输出p的值即a的地址
cout<<*p;//输出p指向的值,即a
//例外
char c[]="ABCD",*q=&c[0];
cout<<q;//输出的不是q的值,而是q指向的字符串:ABCD
cout<<*q;//输出q指向的字符:A
cout<<(void *)q;//输出字符串ABCD的内存首地址
//要输出一个字符指针的值,则需要将指针强制类型转换成一个其他类型的指针
char str[]="ABCD";
char *p=&str[0];
cout<<p<<endl;//输出ABCD
cout<<p+1<<endl;//输出BCD
cout<<p+2<<endl;//输出CD
cout<<*p<<endl;//输出A
cout<<*(p+1)<<endl;//输出B
cout<<*(p+2)<<endl;//输出C
指针的主要用法
指针作为参数传递
指针与动态变量
参数
数组作为函数参数传递时,实际传递的是实参数组在内存中的首地址,函数的形参数组不再另外分配内存空间,而是共享实参数组的内存空间。在函数中能够通过形参数组改变实参数组的值。
C++的默认参数传递方式是值传递(数组除外)
用指针参数实现实参数值的交换:
void swap(int *x,int *y)
{
int temp;
temp=*x;
*x=*y;
*y=temp;
}
- 向函数传递实参的地址主要作用是为了提高参数传递的效率
e.g
struct A
{
int no;
char name[20];};
void f(A *p){//p为指向结构类型的指针
...
}
int main()
{
A a;
f(&a);//把结构变量的地址传给函数f
...
}
- 在C++中把指针作为形参的类型可以产生两个效果:
- 提高参数传递效率
- 通过形参改变实参的值
第二种效果用于把函数的计算结果(有多个)通过参数返回给调用者。
- 想要避免这种效果,可以把形参定义为指向常量的指针,使得函数无法通过指针类型的形参来改变形参的值
e.g
const <类型> *<指针变量>//指向常量的指针类型的定义格式
//const的含义是不能改变指针变量所指向的数据的值
//指向常量的指针也可以指向变量
const int *p;//p是指向常量的指针
const int x=0;
p=&x;//OK
*p=1;//ERROR
//p能指向变量y,但不能通过p改变y的值
//指向变量的指针不可以指向常量
const int x=0;
int *p;
p=&x;//ERROR
void f(const int p[],int num)//或const int *p
//在函数f中不能改变数组元素的值
指针类型的常量
int x=0,y;
int *const p=&x;//p是一个指向变量的指针常量,指针常量必须要初始化。
*p=1//OK,*p是一个变量
p=&y;//ERROR,p是一个常量
const int x=0;
const int * const p=&x;//不仅指向常量,指针本身也是一个常量
- 注意:不能把局部量的地址作为指针返回给调用者,因为当函数返回后,其局部变量的内存空间已被收回。
- 如果调用者在使用这个内存空间中的值之前又调用了某个函数,则该空间将被新调用的函数所使用并拥有了新的值。这样调用者就得不到原来的值了。
指针与动态变量
动态变量需要在程序中显式地创建和撤销,局部变量则是自动生成和消亡的。动态变量的内存空间分配在程序的堆区,局部变量栈区。
动态变量的创建
c++提供了两种创建动态变量的 机制操作符 new和库函数malloc,格式为:
new <类型名>//new操作在程序的堆区产生一个指定类型的动态变量,操作的结果为该动态变量的地址(或指针)。
int *p;
p=new int;//产生一个动态的整型变量,p指向该变量
*p=1;//只能通过指针变量来访问该整型变量
- new操作的结果是有类型的
- new int[n1][n2][n3],其中只有n1可以不是常量或常量表达式
new返回数组首地址
//产生一维动态数组
int *p;
int n;
p=new int[n];
二维:
//产生二维动态数组
int (*q)[20];//q为一个指向由20个int型元素构成的一维数组的指针
//等价于typedef int A[20];A *q;
int n;
q=new [n][20];//等价于q=new A[n];
- malloc
void *malloc(unsigned int size);//函数malloc在stdlib.h或cstdlib中声明
//在程序的堆区中分配一块大小为size的内存空间,并返回该内存空间的首地址,类型为void *
//若该空间用于存储某个具体类型的数据,则需对返回值强制类型转换
new与malloc的主要区别
- new自动计算所需分配空间的大小,malloc需要显式指出
- new自动返回相应类型的指针,malloc需要强制类型转换
若创建的是动态对象,new需要去调用相应对象类的构造函数,malloc不会
对两者,若堆中没有足够空间,则产生bad_alloc异常(或返回空指针NULL)
动态变量的撤消
- 作符delete
- 库函数free
int *p=new int;
...
delete p;
//撤消指针变量所指向的动态数组变量
int *p=new int[20];
...
delete []p;
//释放p所指向的内存空间
void free(void *p)
int *p=(int *)malloc(sizeof(int));
int *q=(int *)malloc(sizeof(int)*20);
......
free(p);//撤消p所指向的动态变量
free(q);//撤消q所指向的动态数组
- 不能用free和delete撤消非动态变量,会产生程序异常错误
delete 和free的主要区别
- 如果p指向的是对象(或对象数组),则delete p(或delete []p)会去调用对象类的析构函数,free(p)不会。
- delete或free撤消动态变量后,C++编译程序一般不会把指向它的指针置为NULL,这时就会出现一个“悬浮指针”,它指向一个不可用空间。