1 / 68

第三章

手机移动设备嵌入式 C++. 第三章. 对 象(续). 回顾. 类对象 构造函数 析构函数 拷贝构造函数. 目标. 指针的概念 指针的使用 指针的运算 指向类成员的指针 指向类静态成员的指针 对象指针、 数组指针、 常指针 等 对象的其它知识. 内存. 0. …. 2000. 2001. 2002. 2003. 2005. …. 指针的概念. 内存中每个字节有一个编号 ----- 地址. 程序中 : int i; float k;. i. 编译或函数调用时为其分配内存单元. k.

thai
Download Presentation

第三章

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. 手机移动设备嵌入式C++ 第三章 对 象(续)

  2. 回顾 • 类对象 • 构造函数 • 析构函数 • 拷贝构造函数

  3. 目标 • 指针的概念 • 指针的使用 • 指针的运算 • 指向类成员的指针 • 指向类静态成员的指针 • 对象指针、数组指针、常指针等 • 对象的其它知识

  4. 内存 0 …... 2000 2001 2002 2003 2005 …... 指针的概念 内存中每个字节有一个编号-----地址 程序中: int i; float k; i 编译或函数调用时为其分配内存单元 k 变量是对程序中数据 存储空间的抽象

  5. …... 整型变量i 2000 10 2001 2002 2003 变量i_pointer 2004 2005 变量地址(指针) 指针变量 2006 地址存入 指针变量 指向 …... 变量值 变量 指针的概念 • 指针:一个变量的地址 • 指针变量:专门存放变量地址的变量叫~ 指针 变量的内容 变量的地址 2000 指针变量

  6. *i_pointer i_pointer 10 2000 &i_pointer i …... 整型变量i 2000 10 2001 2002 2003 变量i_pointer 2004 2000 指针变量 2005 2006 …... 指针的概念 含义:取指针所指向变量的内容 单目运算符 优先级: 2 结合性:自右向左 含义: 取变量的地址 单目运算符 优先级: 2 结合性:自右向左 两者关系:互为逆运算 理解 &与*运算符 含义 i_pointer &i &(*i_pointer) i *i_pointer *(&i) i_pointer=&i=&(*i_pointer) i=*i_pointer =*(&i) i_pointer-----指针变量,它的内容是地址量 *i_pointer----指针的目标变量,它的内容是数据 &i_pointer---指针变量占用内存的地址

  7. 指针的定义 指针是一个变量,在程序中使用时,必须先声明,后使用。在指针声明的同时也可以进行初始化。 指针的定义 指针的定义指出了指针的存储类型和数据类型,定义的语法形式如下: 存储类型数据类型 *指针变量名 例如: int *p1; static int *p2; char *da; 上面定义了名为p1,p2和da的三个不同类型指针。

  8. 指针的定义(续) 具有相同存储类型和数据类型的指针可以在一行中说明,它们也可以和同类型的普通变量在一起说明。 例如: int *p1, *p2, *p3; char m, *da; 在上例中,第一行声明了三个int型指针p1,p2,p3;第二行声明了一个char型变量m和一个指针da。 注意:当在一行中定义多个同一类型的指针时,用逗号隔开各指针变量标识符,并且每个变量前都要加上星号“*”。

  9. 指针的使用 指针的使用 定义了一个指针后,在使用此指针前,必须首先给它赋一个合法的值。否则,程序中对指针的使用就有可能导致系统崩溃。可以在定义指针的同时,通过初始化来给指针赋值,也可以在使用之前给指针赋值。下面首先来了解指针的初始化。 由于指针是保持地址的变量,所以初始化时赋予它的初值必须是地址量。指针初始化的一般形式是: 存储类型数据类型 *指针名=初始地址值; 例如: int a,*pa=&a; 将变量a 的内存地址作为初始值赋予int型指针pa。

  10. 指针的使用(续) 上面这种写法与下面的写法是等价的: int a; int *pa=&a; 当把一个变量的内存地址作为初始值赋给指针时,该变量必须在指针初始化之前已经说明过。其道理很简单,变量只有在说明之后才被分配一定的内存地址。此外,该变量的数据类型必须与指针的数据类型一致。

  11. 指针的使用(续) 下面的例子是把一个指针初始化为空指针。 int *px=0; 这个语句将指针px的值初始化为0。值为0的指针叫作空指针。 为了使用安全起见,一般来说,在定义指针时,最好初始化,哪怕是初始化为空指针。

  12. 指针的使用(续) 如果在定义指针时,指针初始化为0或者根本没有初始化。那么在使用此指针前,就必须给它赋有意义的值。 例如: int n,*p1; //定义指针p1时没有初始化 p1=&n; //给指针p1赋值为int型变量n的地址 或者: int n,*p1=0; //定义指针p1时初始化为0 p1=&n; //给指针p1赋值为int型变量n的地址 都是正确的。

  13. 指针的使用(续) 也可以向一个指针赋初值为另一个指针变量,即把另一个已经初始化的指针赋予一个指针。这时,这两个指针指向同一变量的内存地址。如下例所示:例如: int n; int *p1=&n; //指针p1的值初始化为变量n的地址 int *p2=p1; //指针p2的值初始化为指针变量p1 上面这种写法与下面的写法是等价的: int n; int *p1=&n; //指针p1的值初始化为变量n的地址 int *p2=&n; //指针p2的值初始化为变量n的地址

  14. 指针的使用(续) 也可以定义一个指向数组的指针。由于数组名表示的是该数组的首地址,所以如果定义一个指针指向数组,则可如下例声明: 例如: int a[10],*pa=a; 这个语句定义了一个指针pa,并把pa初始化为指向数组int a[10]的指针,即指针pa指向数组的第一个元素。这时,不需要使用取地址运算符“&”。 上述声明方式与下面的语句等价: int a[10],*pa=&a[0]; “&a[0]”表示数组a中第一个元素所在的内存地址值。

  15. 指针的使用(续) 如果说明了一个指针,并使其值为某个变量的地址,则可以通过这个指针间接地访问在这个地址中存储的值。 利用指针来访问变量值需要使用间接访问运算符“*”。 例如: int a=1,*pa=&a; cout<<*pa; 用cout语句输出的是变量a的值1,即“*pa”就是代表变量a。上面的“cout<<*pa;”语句与“cout<<a;”语句的作用相同。

  16. 指针的使用(续) 同样,在利用指针访问变量的值时,也可以通过指针给变量间接赋值。 例如: int a=1,*pa=&a; *pa=2; cout<<a; 用cout语句输出的是变量a的值2,而不是1。

  17. 说明 经过上面部分的学习已知,在C++语言中有两个有关指针的特别运算符: • & 运算符:为取地址运算符,&x的值为x的地址。 • * 运算符:指针运算符,或指向运算符,也称间接运算符,*p代表p所指向的变量。 • 指针要初始化

  18. px *px &px 说明 由于引进了指针的概念,读者在程序中要注意区分下面三种表示方法所具有的不同意义。例如,有一个指针px , • px ----- 指针变量,它的内容是地址量。 • *px --- 指针的目标变量,它的内容是数据。 • &px -- 指针变量占用的存储区域的地址。 *px和&px的意义

  19. 指针运算

  20. 指针运算 指针运算是以指针变量所持有的地址值为运算量进行的运算。因此,指针运算的实质是地址的计算。 由于指针是持有地址量的变量这一特性,指针的运算与普通变量的运算在种类上和意义上都是不同的。指针运算的种类是有限的,它只能进行算术运算、关系运算和赋值运算。

  21. 指针的算术运算 指针的算术运算 指针的算术运算是按C++语言地址计算规则进行的,这种运算与指针指向的数据类型有密切关系,也就是C++语言的地址计算与地址中存放的数据长度有关。 设px和py是指向具有相同数据类型的一组若干数据的指针,n是整数,则指针可以进行的算术运算有如下几种: px+n, px-n, px++, ++px, px--, --px, px-py 注意:p1+p2 无意义

  22. 加减运算 1. 指针与整数的加减运算:(px+n,px-n) 指针作为地址量加上或减去一个整数n,其意义是指针当前指向位置的前方或后方第n个数据的位置。由于指针可以指向不同数据类型,即数据长度不同的数据,所以这种运算的结果值取决于指针指向的数据类型。

  23. 加减运算 由此,对于某种数据类型的指针p来说: p+n的实际操作是:(p)+n*sizeof(数据类型); p-n的实际操作是:(p)-n*sizeof(数据类型); 其中,(p)表示指针p中的地址值,而不是&p,sizeof(数据类型)的长度单位为字节。 在C++语言中,指针加减运算一般用在对数组元素进行操作的场合。通过对指向数组的指针进行加减运算,可以使指针指向数组中不同的元素。此时也必须注意越界问题。

  24. a数组 p a[0] p+1,a+1 a[1] a[2] a[3] a[4] p+i,a+i a[5] a[6] a[7] a[8] p+9,a+9 a[9] 加减运算示例 例 p指向float数,则 p+1  (p)+1 4 例 p指向int型数组,且p=&a[0]; 则p+1 指向a[1] 1 例 int a[10]; int *p=&a[2]; p++; *p=1; 例 int a[10]; int *p1=&a[2]; int *p2=&a[5]; 则:p2-p1=3;

  25. 指针的关系运算 指针的关系运算 在两个指向相同类型变量的指针之间可以进行各种关系运算。两指针之间的关系运算表示它们指向的地址位置之间的关系。比如: int a; int *p=&a,*q=p; 若上面声明的两个指针作p==q运算,其结果为1(true),也即指针p、q指向同一个变量。两指针相等的概念是两指针指向同一位置。

  26. 指针的关系运算 假设数据在内存中的存储逻辑是由前向后,那么指向后方的指针大于指向前方的指针。对于两指针p和q之间的关系表达式: p<q 若p指向位置在q指向位置的前方,则该表达式的结果值为1,反之为0。 • 指向不同数据类型的指针之间的关系运算是没有意义的, • 指针与非0整数之间的关系运算也是没有意义的。 但是指针可以和零之间进行等于或不等于的关系运算,即: p==0 或 p!=0 它们用于判断指针p是否为一空指针。

  27. 指针的关系运算示例 若p1和p2指向同一数组,则 • p1<p2 表示p1指的元素在前 • p1>p2 表示p1指的元素在后 • p1==p2 表示p1与p2指向同一元素

  28. 指针的赋值运算 指针的赋值运算 当向指针变量赋值时,赋的值必须是地址常量或变量,不能是普通整数。指针赋值运算常见的有以下几种形式。 • 把一个变量的地址赋予一个指向相同数据类型的指针,例如: char a, *p; p=&a; • 把一个指针的值赋予相同数据类型的另外一个指针,例如: int *p, *q; p=q;

  29. 指针的赋值运算 • 把数组的地址赋予指向相同数据类型的指针。例如: char a[10], *pa; pa=a; • 此外,还经常使用下列赋值运算: int *p, *q, n; p=q+n; p=q-n; p+=n; p-=n;

  30. 指针的运算示例 #include<iostream.h> int strlen(char a[]); void main(){ char s[]="abcdefg"; char *p; int n=strlen(s); for(p=s+n-1;p+1!=s;p--) cout<<*p; cout<<endl; } int strlen(char a[]) { char *p=a; int i=0; while (a[i++]!='\0') p++; return p-a; }

  31. 面向对象元素与指针 指向类成员的指针 : • 指向数据成员的指针: <类型说明符><类名>::*<指针名>

  32. 示例 #include <iostream.h> class Test { private: int a; public: Test(int i) {a = i;} int c; int fun(int b){return a * c + b;} }; void main(){ int Test::*pc = &Test::c; Test object1(1); object1.*pc = 8; cout<<"object1.c is"<<object1.c<<endl; }

  33. 静态类成员指针 • 静态类成员是属于该类的全局对象和函数。 • 指向静态成员的指针,声明的方式和普通指针完全一样,只是赋值的时候,还得加上类的限定符:

  34. 示例 #include<iostream.h> class myclass { public: // 构造函数,每定义一个对象, 静态数据成员i加1 myclass() { ++i; } static int i; // 声明静态数据成员i }; int myclass::i=0; // 静态数据成员i初始化, 不必在前面加static void main() { int *count=&myclass::i; // 声明一个int型指针,指向类的静态成员 myclass ob1,ob2,ob3,ob4; cout<<"myclass::i= "<<*count<<endl; // 通过指针直接访问静态数据成员 }

  35. 指向成员函数的指针 • 指向数据成员的指针: <类型说明符>(<类名>::*<指针名>)(<参数表>)

  36. 示例 #include <iostream.h> class Test { private: int a; public: Test(int i) {a = i;} int c; int fun(){return a+ c;} }; void main(){ Test object1(1); int (Test::*pfun) (); pfun = &Test::fun; object1.c = 8; int x=1; cout<<"object1.*pfun is"<<(object1.*pfun)()<<endl; }

  37. 对象指针 1.用指针访问单个对象成员 声明对象指针的一般语法形式为: 类名* 对象指针名; 当用指向对象的指针来访问对象成员时, 要用“->”操作符。

  38. 示例 #include<iostream.h> class exe{ public: void set_a(int a){ x=a; } void show_a(){ cout<<x<<endl; } private: int x; }; int main() { exe ob,*p; // 声明类exe的对象ob和类exe的对象指针p ob.set_a(2); ob.show_a(); // 利用对象名访问对象的成员 p=&ob; // 将对象ob的地址赋给对象指针p p->show_a(); // 利用对象指针访问对象的成员 return 0; }

  39. 对象指针 2. 用对象指针访问对象数组 上例的main()改写为: int main() { exe ob[2],*p; ob[0].set_a(10); ob[1].set_a(20); p=ob; p->show_a(); p++; p->show_a(); return 0; }

  40. this指针 • This 指针是指向对象的指针,它隐含在类成员函数中,用来指向成员函数所属类的正在被操作的对象。 • 编译器会把对象的地址赋给成员函数中的this指针。确保访问到的数据成员属于这个对象 Date::Date(int y,int m,int d) { this -> year = y; this -> month = m; this -> day = d; } 注:静态成员函数没有this 指针

  41. this的用法 class person{ private: int age; public: void display(); }; void Person::display(){ this -> age = 25; // 与age = 25一样 cout << this -> age; // 与cout << age一样 cout << endl; }; int main(){ Person Jack; Jack.display(); return 0; }

  42. 对象数组 定义:对象数组是指数组元素为对象的数组,该数组中若干个元素必须是同一个类的若干个对象 。 对象数组定义格式如下: <类名><数组名>[<大小>] 比如:Date dates1[7];

  43. 示例 class Date { public: Date(int m, int d, int y); void Printf(); private: int m_month, m_day, m_year; }; Date dates[4]={ Date (4,22,2006),Date (4,23,2006), Date (4,24,2006),Date (4,25,2006)}

  44. 指针与数组 对于二维数组,又是如何用指针访问其中的每个数组元素的呢? 例如,定义了一个二维数组a: int a[3][5]; a是以一个3*5的二维数组,它有三行,每一行都有其起始地址。 C++语言规定以a[0],a[1],a[2]分别表示第0行,第1行,第2行的起始地址,即该行第0列元素的地址。注意a[0],a[1],a[2]并不是一个元素,而是一行首地址,正如同一维数组名是数组起始地址一样,a[0]的值等于&a[0][0],a[1]的值等于&a[1][0],a[2]的值等于&a[2][0]。在同一行中是同样的类推方式,比如:a[0]+1的值等于&a[0][1],a[1]+2的值等于&a[1][2],……。

  45. 数组指针 数组指针与指针数组 在C++语言中,数组指针就是一个指向数组的指针;指针数组就是其元素为指针的数组。在学习C++语言时,要注意对它们进行区分,不能等同起来。 1. 数组指针 数组指针是一个指向一维数组的指针变量,定义数组指针的格式为: 数据类型 (*指针名)[常量表达式];

  46. 数组指针 例如: int (*p)[5]; 上面这个语句定义了一个数组指针p,它指向一个包含5个元素的一维数组,数组元素为整型。注意,*p两侧的圆括号不能省略,它表示p先与星号“*”结合,是指针变量。如果省略了圆括号,即写成*p[5]的形式,由于方括号的优先级比星号高,则p先与方括号[ ]结合,是数组类型,那么语句int *p[5];是定义了一个指针数组。

  47. 指向对象数组的指针 指向对象数组的指针定义格式如下: <类名>(*PL)[4]; 其中,PL是指向数组的指针名,该指针是一个指向一维对象数组的指针,该数组中有4个元素,每个元素是指定<类名>的对象

  48. 指针数组 2. 指针数组 指针数组就是其元素为指针的数组。它是指针的集合,它的每一个元素都是指针变量,并且它们具有相同的存储类型和指向相同的数据类型。 说明指针数组的语法格式为: 数据类型 *指针数组名[常量表达式]; 其中,数据类型式指数组中各元素指针所指向的类型,同一指针数组中各指针元素指向的类型相同;指针数组名也即数组的首地址,是一个标识符;常量表达式指出这个数组中的元素个数。 例如:下面定义了几个指针数组。 int *p1[6]; float *p2[3][4];

  49. void指针 void指针 一般来说,只能用指向相同类型的指针给另一个指针赋值,而在不同类型的指针之间进行赋值是错误的。比如: int a,b; int *p1=&a,*p2=p1; //正确 而: int a; int *p1=&a; double *p2=p1; //错误 上述语句中的两个指针p1,p2指向的类型不同,因此,除非进行强制类型转换,否则它们之间不能相互赋值。但是void指针是一个特例。

  50. void指针 C++语言允许使用空类型(void)指针,即不指定指针指向一个固定的类型,它的定义格式为: void *p; 表示指针变量p不指向一个确定的类型数据,它的作用仅仅是用来存放一个地址。 void指针它可以指向任何类型的C++数据。也就是说,可以用任何类型的指针直接给void指针赋值。不过,如果需要将void指针的值赋给其他类型的指针,则需要进行强制类型转换。比如: int a; int *p1=&a; void *p2=p1; int *p4=(int *)p2;

More Related