指针的概念
◆
1、“存储器”的概念 文件柜-->文件柜上的抽屉-->抽屉上的编号
对应于:
存储器----->存储单元----->存储单元的地址
◆
2、存储器的使用 1)定义变量时,系统为变量分配相应的存储单元,通过变量名可以直接使用该存储单元。例如:
int x=5,y;
y=15; // y可以理解成该存储单元的当前名字
2) 通过存储单元的地址来使用该存储单元,这就需要有表示存储单元地址的量——指针型变量。例如:
int *ip; // ip是一个指针(变量)
ip=&y; // ip是存储空间y的地址
cout<< ip<< &y<< y<< *ip; //结果?
◆
3、指针的定义 按变量的地址直接存取变量的方法称为“
直接访问”方式。存贮变量的内存空间的首地址称为该
变量的地址。如果将一个变量的地址放在另一个变量中,则存放地址的变量称为
指针(Pointer)型变量。由于指针变量中的值是另一个变量的地址,我们习惯上形象地称为指针变量指向该变量。
存取变量也可以间接地由指针变量取得该变量的地址进行,称为“
间接访问”方式。
指针变量中的值简称为指针,所以指针就是地址。 取地址运算符& :作用于内存中一个可寻址的数据(如变量、对象和数组元素等等),操作的结果是获得该数据的地址。
间接引用运算符* :作用于一个指针类型的变量,访问该指针所指向的变量。例如:
int a=5, *pointer;
pointer=&a; //pointer指向a
*pointer=10; //间接访问,相当于a=10
◆
4、指针定义的语法 指针类型变量定义语句格式如下:
《存贮类型》 类型 *变量名1《,*变量名2…》; 例如:
int *lp1,*lp2; //定义整型指针变量lp1,lp2
float *fp1, fp2; //实型指针flp1,实型变量fp2
所谓指针类型,按指针指向的变量的类型区分。基本类型和派生类型都有对应的指针类型,包括类(class),甚至还有指针类型(指向指针的指针,二级指针)。
指针变量的赋值、初始化与简单应用
◆
1、对指针赋值 对指针赋值有三种情况 :
- 取变量地址:使指针指向该变量。
- 指针相互赋值:使两指针指向同一变量。(查看动画演示)
- 指针赋NULL:空指针,指针悬空。不同于指针未赋值。
注意:不能给指针变量随意赋一个地址值,只能取一个已经分配了内存的变量的地址赋给指针变量。变量或对象的内存地址是由编译系统来分配的。 【例5.6】指针赋值实例:
#include <iostream.h>
void main()
{
int age1=18, age2=20, *p_age;
p_age=&age1;
cout<<"age of wang ping is"<<*p_age<<endl;
p_age=&age2;
cout<<"age of zhang ling is"<<*p_age<<endl;
}
◆
2、指针变量初始化 例如: int age , *p_age=&age; //p_age初始化为指向整型量age。
任何类型指针都可以赋以0值(NULL),称
空指针,
表示该指针不指向该类型的任何一个变量(对象)。注意不是指向地址为0的内存空间。
常量是不可寻址的,但常变量是可寻址的,如:
p_age=&20; //错误
const float PI=3.14159;
float *pointer=&PI; //正确
◆
3、指针使用时注意 - 指针类型可以强制转换,有特殊应用,例如:
int m, *pm=&m;
char *p1=(char*)&m, *p2=(char*)pm;
用pm读的是整型数,用p1,p2读的是整型数的第一个字节。 - 同类型的指针可以相互赋值,如有说明:
int val1=18, val2=20, *p_val1=&val1, *p_val2=&val2;
// p_val1指向val1,p_val2指向val2
执行 p_val1=p_val2; 后,则p_val1也指向val2,而没有指针指向val1了。(查看动画演示) - 必须谨慎使用指针,一旦使用不当会产生灾难性的后果。
例如,局部指针变量在定义时其中的值为随机数,即指针指向了一个无意义的地址,也可能偶然指向了一个非常重要数据的地址。如果对所指的内存进行不当操作,其中的数据就丢失了。
再如,全局指针变量,原指向一个局部变量,后来该内存又重新分配了,我们再对该指针所指地址进行操作,同样会发生不可预知的错误。 - 对指针变量决不可以任意赋一个内存地址,结果甚至是灾难性的。如:
int *P=(int *)0xaf80;
把指针变量P的初始置为0xaf80,我们并不知道那个内存单元放的是什么数据,这在一般程序中是非常危险的。 - 如果通过指向对象或结构变量的指针变量来访问其公有成员时,则只要在指针变量名后加箭头号(箭头操作符“->”),再加公有成员名就可以了。
【例5.7】通过结构指针来访问结构成员。
#include<iostream>
#include<cstring>
using namespace std;
struct student{
char name[20];
char id[10];//学号最好用字符串,当学号以0开头,整数会丢失0甚至认为是八进制
int age;
float score;
char address[30];
};
int main(){
student st1,*prst;
prst=&st1;
cout<<"请输入学生的姓名:"<<endl;
cin.getline(st1.name,20);//cin.getline可输入空格
cout<<"请输入学号、年龄和入学成绩:"<<endl;
cin>>st1.id>>st1.age>>st1.score;
cin.get();//吸收掉换行回车符
cout<<"请输入家庭住址:"<<endl;
cin.getline(st1.address,30);
cout<<"姓名"<<'/t'<<prst->name<<'/n';
cout<<"学号"<<'/t'<<prst->id<<'/n';
cout<<"年龄"<<'/t'<<prst->age<<'/n';
cout<<"入学成绩"<<'/t'<<prst->score<<'/n';
cout<<"家庭住址"<<'/t'<<prst->address<<endl;
return 0;
} - 指针常量是固定指向一个对象的指针,即指针本身是常量:
char ch=’a’,ch1=’x’;
char * const ptr=&ch; //注意const放在类型说明之后,变量名之前
*ptr=’b’;//正确
ptr=&ch1;//错误
ptr本身在初始化时所指向的地址是不可改变的,但它指向的目标ch的值是可以改变的。 - 常量指针是指向“常量”的指针,即指针本身可以改指向别的对象,但不能通过该指针修改对象。该对象可以通过其他方式修改,常用于函数的参数,以免误改了实参。类似于在“运算符重载”一节中引用参数前加const。
char ch=’a’,ch1=’x’;
const char * ptr1=&ch; //ptr1是常量指针
*ptr1=’b’; //错误,只能做ch=’b’
ptr1=&ch1; //正确