图 上泽充通大¥ C+程序设计与实践 第5讲指针与引用 上海交通大学 机械与动力工程学院 2014.9-2015.1 上海京通大学 1.指针概念 2.数组与指针 3. 字符串与指针 4.const:指针类型 5.引用 6.动态内存分配 1 1
1 1/48 第5讲 指针与引用 C++程序设计与实践 上海交通大学 机械与动力工程学院 2014.9-2015.1 2/48 1. 指针概念 2. 数组与指针 3. 字符串与指针 4. const指针类型 5. 引用 6. 动态内存分配
储存单元的地址 1. 计算机的内存被划分成一个个存储单元,每个存 储单元的大小为一个字节。每个存储单元都有唯 一的编号,这个编号就是存储单元地址。 2.计算机就是通过这种地址编号的方式管理内存数 据读写的准确性。 3.当一个变量被声明,系统就会根据这个变量的类 型为这个变量在内存分配一个存储空间,大小由 变量类型决定。 地址 数据 址 数据 器 国上海文大修 变量在内存空间中的实现 int a=1,b=2; 内存地址 内存空间 口系统为变量a,b分配内存空间 0x0019F898 0x01 变量名a是指从0x19F898 到0x19F89B,大小为4 0x0019F899 0x00 变量a 个字节的一段内存,变量 0x0019F89A 0x00 值1就放在这段内存中。 >变量名b是指从0x19F8A4 0x0019F89B 0x00 到0x19F8A7,大小为4 个字节的一段内存,变量 值2就放在这段内存中。 0x0019F8A4 0x02 0x0019F8A5 0x00 变量b 0x0019F8A6 0x00 0x0019F8A7 0x00 国上泽1大学 2
2 3 储存单元的地址 1. 计算机的内存被划分成一个个存储单元,每个存 储单元的大小为一个字节。每个存储单元都有唯 一的编号,这个编号就是存储单元地址。 2. 计算机就是通过这种地址编号的方式管理内存数 据读写的准确性。 3. 当一个变量被声明,系统就会根据这个变量的类 型为这个变量在内存分配一个存储空间,大小由 变量类型决定。 地址 地 址 译 码 器 数据 数据 4 变量在内存空间中的实现 0x01 0x00 0x00 0x00 0x02 0x00 0x00 0x00 变量a 变量b 0x0019F898 0x0019F899 0x0019F89A 0x0019F89B 0x0019F8A4 0x0019F8A5 0x0019F8A6 0x0019F8A7 int a=1,b=2; 内存地址 内存空间 系统为变量a,b分配内存空间 变量名a是指从0x19F898 到0x19F89B ,大小为4 个字节的一段内存,变量 值1就放在这段内存中。 变量名b是指从0x19F8A4 到0x19F8A7 ,大小为4 个字节的一段内存,变量 值2就放在这段内存中。 … …
符号表一变量名和地址之间的桥梁 口变量名是一个标志符(identifier),是用来标识内存中一 段区域,便于人们阅读; 口地址是CPU对内存单元进行读写的依据; 口编译器在对程序编译时产生了一个符号表,使变量名和地 址产生了一一对应; 口在可执行的.exe程序中,没有变量名,只有对变量所对应 的地址的操作。 地址 变量名 编译符号表 (intel 变量名地址 大小(字节)类型 0x0019F8984 int oe2 6 0x0019F8A44 int 周上海文大学 5 如何获取变量的地址? 口C++中提供了取地址运算符& >int a; >a的地址为&a; #include using namespace std; C:\Windows\system... int main() a=1b=2 a= 8019F8A4 &h=0019F898 int a=1,b=2; 清按任意键继续。·· cout<<"a="<<a<<\t<<"b="< <b<<endl; cout<<"&a="<<&a<<t'<<"& b"<<&b<<endl; return 0; 国上泽1大学 6 3
3 5 符号表—变量名和地址之间的桥梁 编译符号表 变量名 地址 大小(字节) 类型 a 0x0019F898 4 int b 0x0019F8A4 4 int 变量名是一个标志符(identifier) ,是用来标识内存中一 段区域,便于人们阅读; 地址是CPU对内存单元进行读写的依据; 编译器在对程序编译时产生了一个符号表,使变量名和地 址产生了一一对应; 在可执行的.exe程序中,没有变量名,只有对变量所对应 的地址的操作。 地址 变量名 6 如何获取变量的地址? C++中提供了取地址运算符& int a; a的地址为&a; #include using namespace std; int main() { int a=1,b=2; cout<<"a="<<a<<'\t'<<"b="< <b<<endl; cout<<"&a="<<&a<<'\t'<<"& b"<<&b<<endl; return 0; }
地址在生活中的应用:房号、房间、旅客 C++HOTEL 201 202 203 204 101 102 103 104 1)旅客住在不同的房间中; 2)每个房间都有房号; 3)」 房间有不同的类型:单人房,双人房 国上海文大等 7 地址在生活中的应用:在酒店中找人 寻找Tom 假设Tom在201房 是否知道Tom 是 的房号 否 找人的两种方式: 1. 直接导找: 通过前台了解Tom的房号 知道房号 2.间接寻找: 先找前台,从前台得到房号 在201房找到Tom 国上泽通大学 8 4
4 7 地址在生活中的应用:房号、房间、旅客 C + + HOTEL 1) 旅客住在不同的房间中; 2)每个房间都有房号; 3)房间有不同的类型:单人房,双人房 201 202 203 204 101 102 103 104 8 地址在生活中的应用:在酒店中找人 寻找Tom 是否知道Tom 的房号 在201房找到Tom 假设Tom在201房 通过前台了解Tom的房号 是 否 找人的两种方式: 1. 直接寻找: 知道房号 2. 间接寻找: 先找前台,从前台得到房号
二者对比 储存空间 空间地址 空间中内容储存单元类型 房间 房号 客人 客房类型(单人、双人间) 内存单元指针(地址) 变量值 变量类型(int,char,double,float) 怎样在内存中找变量值呢? 国上海文大等 9 访问变量的两种方式 直接访问: 按变量地址存取变量的值。ci>>i;实际上放到定义1单元的地 址中。 2000 ©间接访问: ·将变量地址放在另一单元i_pointer,通过i_pointer取出变量 的地址,再针对变量操作。 i pointer 2000 2000 ·一个变量的地址称为该变量的指针。1是变量,2000是的在内存 中的地址,是i的指针。2000本身存放在i_pointer中 国上海大学 10 5
5 9 二者对比 储存空间 空间地址 空间中内容 储存单元类型 房间 房号 客 人 客房类型(单人、双人间) 内存单元 指针(地址) 变量值 变量类型(int, char, double, float) 10 访问变量的两种方式 直接访问: • 按变量地址存取变量的值。cin>>i; 实际上放到定义 i 单元的地 址中。 间接访问: • 将变量地址放在另一单元i_pointer,通过 i_pointer 取出变量 的地址,再针对变量操作。 • • 一个变量的地址称为该变量的指针。i是变量,2000是i的在内存 中的地址,是i的指针。2000本身存放在i_pointer中 i 2000 2000 2000 i 3 i_pointer
不同变量在内存中的存放 ·系统根据程序中定义的变量定义,分配一定长度的空间; ·内存中每个字节都有编号,称为地址。 变量i_pointerr中存放着变量i的地址 内存用户数据区 2000 3 变量i 数据类型 长度(byte) 2004 6 变量j char 1 2008 9 变量k int 4 float g double 8 3010 2000 变量i pointer 国上海文通大等 11 指针与指针变量 ▣指针 ·指针就是变量在内存中的地址。 ·用&获取变量的地址:&i 2000 口指针变量 ·指针变量是用来存放变量地址的变量; i_pointer *i pointer 2000 3 ·i_pointer是一个指针变量,*i_pointer表示i_pointer 所指向的变量; i1=3; 是等价的。 *i_pointer=3; 国上海大学 12 6
6 11 不同变量在内存中的存放 • 系统根据程序中定义的变量定义,分配一定长度的空间; • 内存中每个字节都有编号,称为地址。 • 变量i_pointer中存放着变量i的地址 数据类型 长度(byte) char 1 int 4 float 4 double 8 变量i_pointer 9 6 3 … 内存用户数据区 2000 变量i 变量j 变量k 2000 2004 2008 3010 12 指针与指针变量 指针 • 指针就是变量在内存中的地址。 • 用&获取变量的地址:&i 指针变量 • 指针变量是用来存放变量地址的变量; • i_pointer是一个指针变量,*i_pointer表示i_pointer 所指向的变量; • 是等价的。 i_pointer i=3; *i_pointer=3; 2000 *i_pointer 3 i 2000 i
指针变量 口指针变量是一种特殊的变量; ▣和其他类型的变量(int,float,,double,char)不 同,里面存放的是其他变量的地址; 口一个指针变量所占空间为4个字节。 i pointer int i=3; 3010 int *i pointer=&i; 3011 2000 3012 2000 3013 2001 3 2002 3010~3013中存放着变量i的地址 2003 2000-2003中存放着变量i的值3 倒上泽文1大华 13 指针变量的定义与赋值 ▣指针变量定义的一般形式为: ·类型标识符 *变量名; int *pointer_1,pointer_2; 口指针变量的赋值: 必须有*,否则是定义整型变量 int i,*i_pointer; i_pointer=&i: ·也可以在定义时给指针变量赋初值: int i; int *i pointer =&i: ·不能用一个整数给指针变量赋值: int*pointer._1=2000;/错误,2000被认为整型数,不是地址 国上海支大等 14 7
7 13 指针变量 指针变量是一种特殊的变量; 和其他类型的变量(int, float, double, char) 不 同,里面存放的是其他变量的地址; 一个指针变量所占空间为4个字节。 int i=3; int * i_pointer=&i; i_pointer 3010 3011 3012 3013 i 2000 2001 2002 2003 3010~3013中存放着变量i的地址 2000~2003中存放着变量i的值3 3 2000 14 指针变量的定义与赋值 指针变量定义的一般形式为: • 类型标识符 *变量名; • int *pointer_1, * pointer_2; 指针变量的赋值: • 也可以在定义时给指针变量赋初值: • 不能用一个整数给指针变量赋值: 必须有*,否则是定义整型变量 int i, *i_pointer; i_pointer = &i; int i; int * i_pointer = &i; int * pointer_1 = 2000; //错误,2000被认为整型数,不是地址
指针变量的基类型 口指针变量的基类型:该指针变量指向的变量的类 型。 p11000 2000 3000 p3 char p1; int p2; double*p3; 2003 所指变量 所古空间 *p1 1000 3007 *p2 2000-2003 *p3 3000-3007 口为什么指针变量必须指定基类型? 指针变量只是记录了所指变量的第一个字节的地址。 。 不同类型变量的所占的字节数不同,存储的方式也不同。 国上海文大 15 为什么要用指针?(1) 指针(内存地址)可以让我们对数据进行更灵活的 操作,对数据内存地址的操作比对数据本身的操作 更加有效率。 使用指针,可以有如下一些优点: 1.调用函数时,可以进行对象地址的传递,而不是进行对 象值的传递; 2. 对复杂数据结构进行有效率的处理,比如结构体,类; 3. 国上泽1大学 16 8
8 15 指针变量的基类型 指针变量的基类型: 该指针变量指向的变量的类 型。 为什么指针变量必须指定基类型? • 指针变量只是记录了所指变量的第一个字节的地址。 • 不同类型 变量的所占的字节数不同,存储的方式也不同。 char * p1; int * p2; double* p3; p1 1000 2000 p2 2003 3000 p3 3007 所指变量 所占空间 *p1 1000 *p2 2000~2003 *p3 3000~3007 16 为什么要用指针?(1) 1. 调用函数时,可以进行对象地址的传递,而不是进行对 象值的传递; 2. 对复杂数据结构进行有效率的处理,比如结构体,类; 3. …… 指针(内存地址)可以让我们对数据进行更灵活的 操作,对数据内存地址的操作比对数据本身的操作 更加有效率。 使用指针,可以有如下一些优点:
为什么要用指针?(2) 1. 函数调用中的值传递 int fun1(inta,intb;∥函数原型 int main(){ 实参 int x=1,y=2,z; 值传递 z=fun1(x,y); return 0; 形参 2 } ⊙ b 1.fun1有两个输入,只能有一个返回值; 2. 调用函数时,系统需要为形参在内存中开辟 空间来存放由实参传递过来的值,占用资源; 3. 虚实结合的方式适合参数较少的情况。 周上海文大华 17 为什么要用指针?(3) 2.函数调用中使用地址传递,速度快 a 2000H a[o] 如果有1000个数据需要处理: 2004H a1)] void fun2(int*a,int size);l∥函数原型 2008H a[2] 8相银 int main() 1. 只需要把数组a的首地址 200CH a[3] (a代表数组的首地址) int a [1000]; 和数组的大小(1000)传 E 给fun20即可; fun2(a,1000); 2. 在fun20中,无需为数组a return 0; 开辟新的内存空间,占资 2F94H a[997] 源少,速度快: } 3. 函数结束后,函数对数组 2F98H [998] a所有元素操作的结果得 2F9CH a[999] 以保留,而函数只能返回 一个值。 国上海支大等 18 9
9 17 为什么要用指针?(2) 1. 函数调用中的值传递 int fun1(int a,int b); //函数原型 ……. int main(){ int x=1,y=2,z; z = fun1(x,y); return 0; } 1 x 2 y 1 a 2 b 1. fun1有两个输入,只能有一个返回值; 2. 调用函数时,系统需要为形参在内存中开辟 空间来存放由实参传递过来的值,占用资源; 3. 虚实结合的方式适合参数较少的情况。 值传递 实参 形参 18 为什么要用指针?(3) int main() { int a [1000]; ……. fun2(a,1000); return 0; } 如果有1000个数据需要处理: void fun2(int *a, int size); //函数原型 …... 2.函数调用中使用地址传递,速度快 2F9CH 2F98H 2F94H 200CH 2008H 2004H 2000H a[999] a[998] a[997] a[3] a[2] a[1] a[0] a ...... ...... 1. 只需要把数组a的首地址 (a代表数组的首地址), 和数组的大小(1000)传 给fun2()即可; 2. 在fun2()中,无需为数组 a 开辟新的内存空间,占资 源少,速度快; 3. 函数结束后,函数对数组 a所有元素操作的结果得 以保留,而函数只能返回 一个值
指针变量的使用 口两个与指针变量有关的运算符: 运行结果: >&取地址运算符 10010 >*指针运算符(或称间接访问运算符) 10010 void main(void) a int a,b; int *pointer 1,*pointer 2; 100 10 pointer 1=&a: pointer 2=&b: pointer 1=100;*pointer 2=10: cout<<a<<\t'<<b<<endl; &3 &b cout<<*pointer 1<<t'<<*pointer2< <endl: pointer 1 pointer_2 周上海文大华 19 指针变量须先赋值,再使用 当指针变量未赋值时,指针指向未知地址! void main(void) 通过指针对未知 地址变量赋值 int a,b; int *pl,*p2; *pl=10;*p2=100; 随机 随机 cout<<a<<t'<<b<<endl; cout<<*pl<<\t'<<*p2<<endl; int i,*pl; 用指针变量前,必须对指 pl=&i; 针变量赋值 国上泽大学 20 10
10 19 指针变量的使用 两个与指针变量有关的运算符: & 取地址运算符 * 指针运算符(或称间接访问运算符) void main(void) { int a, b; int *pointer_1, *pointer_2; pointer_1=&a; pointer_2=&b; *pointer_1=100; *pointer_2=10; cout<<a<<‘\t’<<b<<endl; cout<<*pointer_1<<‘\t’<<*pointer2< <endl; } 100 10 &a &b a b pointer_1 pointer_2 运行 结果: 100 10 100 10 20 指针变量须先赋值,再使用 void main(void) { int a, b; int *p1, *p2; *p1=10; *p2=100; cout<<a<<‘\t’<<b<<endl; cout<<*p1<<‘\t’<<*p2<<endl; } a b p1 p2 随机 随机 int i, *p1; p1=&i; 通过指针对未知 地址变量赋值 用指针变量前,必须对指 针变量赋值 当指针变量未赋值时,指针指向未知地址!