1 / 17

第五章 指针和自定义数据类型

pst=pst+1;. pst. 第五章 指针和自定义数据类型. 5.1 指针及其运算 5.1.1 指针的算术运算. struct student{ int number; char name[4]; } student *pst;. 指针运算是地址的运算( T *px) px+n, px-n —— 将指针从当前位置向前或向后移动 n 个 数据单位 ,而不是 n 个字节。 这取决于指针所指向的数据类型( T)。

carina
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. pst=pst+1; pst 第五章 指针和自定义数据类型 5.1 指针及其运算 5.1.1 指针的算术运算 struct student{ int number; char name[4]; } student *pst; 指针运算是地址的运算( T *px) px+n, px-n ——将指针从当前位置向前或向后移动n个数据单位,而不是n个字节。 这取决于指针所指向的数据类型(T)。 pxn的结果为: pxnsizeof(T) px-py求出的是两指针位置之间的数据个数,而不是地址差。 px-py的结果为:( px-py) / sizeof(T) y= px++——y=  ( px++ ), 注意优先级和结合顺序 y=  ++ px——y= ( ++ px) 问题:y= px++和y= (px)++的意义

  2. 5.1.3 指针的关系运算 是对两个相同类型的指针的运算,如px<py,当px所指位置在py之前时,表达式的值为 1,否则为0。px==0, px!=0用来判断px是否为空指针。 不同类型的指针以及指针和一般整数间的关系运算是无意义的。 5.1.4 指针的赋值运算 赋的值必须是地址常量或变量,而不能是普通整数,有以下几种形式: 1. 变量地址赋予指向相同数据类型的指针 char c, *pc; pc=&c; 2.指针赋予相同数据类型的另一指针 int *p, *q; p=q; 3.其它形式 int *p, *q, n; p=q+n; p+=n;

  3. 5.2 指针和数组 5.2.1 指针与数组的关系 可以用指针代替数组下标来访问数组: f ( ) { int a[5]; int *pa; *(pa+3)=10; pa[3]=10; *(a+3)=10; a[3]=10; } 指针与数组的差异:指针是地址变量,可任意改变它的值;而数组名是地址常量,其值不能改变。 5.2.2 字符指针与字符数组 可用字符数组表示字符串,也可用字符指针指向字符串的首址。 指针表示字符串可以赋多个串值,只要将字符串的首址赋给它。 字符数组是常量不能赋值。

  4. ex. 1 include<iostream.h> main ( ) { static char str[ ]=“string”; char *ps; ps=str; while ( *ps !=‘\0’) { cout<<*ps; ps++; } cout<<endl; } 5.2.3 指针数组 指向同一类型对象的指针组成的数组。每个数组元素都是一指针变量。 存储类型 数据类型 * 指针数组名[元素个数]

  5. ex. 2 void main ( ) { int a[2][3], *pa[2]; pa[0]=a[0]; pa[1]=a[1]; for ( int i=0; i<3; i++ ) *( pa[0]+i)=i; for ( i=0; i<3; i++ ) *( pa[1]+i)=i; } 5.3 指针和函数 5.3.1 指针函数(指针作为函数的返回值) 存储类型 数据类型 * 函数名(参数表)

  6. static ex. 3 char *string_name ( int n ) { char * string[ ]={ “illegal string”, “string 1”, “string 2”, “string 3” } return ( n<1 || n>3 ) ? string[0]: string[n]; } 返回的是变量地址,必须保证函数返回后,这个变量仍然存在。要返回函数中局部变量的地址,应声明为静态的。 问题: char sname[20]; sname=string_name(n);

  7. 5.3.1 函数指针(函数的入口地址可赋给指针) 虽然函数不是变量,仍占存储空间,此空间的首地址——函数入口地址。 存储类型 数据类型 (* 函数指针名)(参数表) ex. 4 int (*fp)_( char ); //fp为一函数指针, 此函数 的返回值为int,参数为char 要将函数指针指向一具体的函数,用赋值语句: ex. 5 int f( char ); fp=&f; 与普通变量指针不同,函数指针指向程序代码区,而不是数据存储区。 int i= (*fp) (‘a’); int i=f (‘a’) ; 要保证函数指针的参数和返回值与所指向的函数正好匹配。 ex. 6 void (*fp) ( char * ); void f1(char * ); int f2( char * ); void f3( int * ); void f( ) { fp=&f1; fp=&f2; fp=&f3; (* fp) (“asdf”); (* fp) (1); int i=(*fp) (“qwer”); }

  8. C++不能把函数当作参数传递,但传递函数指针允许。C++不能把函数当作参数传递,但传递函数指针允许。 ex. 7 void sort ( void * base, unsigned int n, unsigned int sz, int (*cmp) (void*, void* )) { //把n个元素的向量base按升序排列,向量每个元素大小sz for(int i=0; i<n-1;i++) for (int j=n-1; i<j; j--) { char *pj=(char * ) base+j*sz; //b[j] char *pj1=pj-sz; //b[j-1] if((*cmp)(pj,pj1)<0) { for( int k=0; k<sz; k++) { char temp=pj[k]; pj[k]=pj1[k]; pj1[k]=temp; } } } } void * 性质:任何类型的指针都可以赋给它。作为参数传入指向任何类型的指针都可与它匹配。

  9. 两个比较函数: #include <string.h> int cmp_int ( void *p, void *q) { if ( * (int *) p < * (int *) q ) return –1; else if ( * (int *) p == * (int *) q ) return 0; else return 1; } int cmp_str ( void *p, void *q ) { return strcmp ( * (char **) p, * (char **) q ); } 主程序: #include <iostream.h> int main ( ) { static int ii [ ] ={ 3,9,5,4}; static char * str [ ] ={ “compare”, “the”, “string” }; sort ( ii, 4, sizeof (int), &cmp_int ); sort ( str, 3, sizeof ( char *) , &cmp_str ); cout<<“The result of sort string:”<<endl; for ( int i=0; i<3; i++) cout<<str [i]<<“ “; }

  10. 5.4 指针、引用、常量和复杂类型 5.4.1 指针与常量 C++函数可重载,在函数指针赋值时要注意二义性。 ex. 8 int f (int i); int f (char c); int (*fp1) (int)=&f; int (*fp2) (char)=&f; int (*fp3) (double)=&f; int (*fp4) (…)=&f; 注意:不能把一个const变量的地址赋给指向非const的指针,否则会无形中改变常量的值 ex. 9 const int n=1; int *pInt; pInt=&n; *pInt=2;

  11. 5.5 结构、联合、和用户自定义类型 5.5.1 结构的定义和声明 struct person { char name[20]; char sex; char addr[50]; double salary; }; 结构的成员可以是变量,数组,也可是指针和函数。 使用结构要创建对象:person LiMing; person *p=new person; 结构嵌套(结构的成员是另一结构对象): struct date struct person { { int day; char name[20]; char month[5]; char sex; int year; char addr[50]; }; double salary; date birthday; }

  12. 5.5.2 对结构的操作 运算符 . 按对象访问成员; 运算符 -> 按指针访问成员。 如:LiMing. Salary=1200.56; p->sex=‘M’; 5.5.3 结构、指针和数组 结构名 结构数组名[元素个数]; 结构名 *结构指针名; ex. 10 person company[52]; person *pperson=company; cout<<(*(pperson+3)).name<<endl; 结构中成员指针的类型没有任何限制,可以是基本类型,也可以是结构,甚至可以定义引用自身的结构。 ex. 11 struct inode{ int data; inode *next; };

  13. 举例:70%的学生通过考试,从键盘输入学生姓名和成绩,按分数高低输出,并用pass或fail表示是否通过考试举例:70%的学生通过考试,从键盘输入学生姓名和成绩,按分数高低输出,并用pass或fail表示是否通过考试 ex. 12 #include<string.h> #include<iostream.h> struct STUDENT { char name[30]; int grade; }; void sortclass(STUDENT st[ ], int nst); void swap(STUDENT &ps1, STUDENT &ps2); void main( ) { STUDENT *classes; int ns; cout<<“Number of students:\n”; cin>>ns; classes=new STUDENT[ns]; cout<<“Enter name and grade for each student\n”; for (int i=0; i<ns; i++) cin>>classes[i].name>>classes[i].grade; sortclass(classes, ns); const int cutoff=(ns*7)/10-1; for( i=0; i<ns; i++) { cout<<classed[i].name<<“ “<<class[i].grade; if(i<=cutoff) cout<<“pass\n”; else cout<<“fail\n”; } }

  14. void sortclass(STUDENT st[ ], int nst) { for( int i=0; i<(nst-1); i++) { int pick=i; for(int j=i+1; j<nst; j++) { if( st[j].grade>st[pick].grade ) pick=j; } swap(st[i], st[pick]); } } void swap(STUDENT &ps1, STUDENT &ps2) { STUDENT temp; strcpy(temp.name, ps1.name); temp.grade=ps1.grade; strcpy(ps1.name, ps2.name); ps1.grade=ps2.grade; strcpy(ps2.name, temp.name); ps2.grade=temp.grade; }

  15. 在特定时刻,联合只有一个成员被保存,而不提供其它成员的信息。在特定时刻,联合只有一个成员被保存,而不提供其它成员的信息。 5.5.5 联合 union 联合名 { 数据类型 成员名1; 数据类型 成员名2; …… 数据类型 成员名n; }; 成员1、成员2、……成员n共享内存,编译器总是按联合中最大成员类型分配内存。 5.5.6 枚举(一个有名字的整数集合) enum 枚举名{ 标识符1,标识符2,… ,标识符n } 例如:enum color { red, white, black}; //red=0, white=1, black=2 color chair; //chair 的取值只能是red, white或black 枚举的使用: ex. 13 viod f( ) { color suit=white; int i=red; suit=i; //错, suit=color(i); //正确,把整数赋给枚举类型要强制类型转换 i=suit; suit=4; //错 }

  16. STRING str; 标识符的值也可以自己定义: 例如:enum color { red, white=7, black=2}; 匿名枚举表示一组常量: 例如:enum { ASM,AUTO,BREAK}; const int ASM=0; const int AUTO=1; const int BREAK=2; 5.5.7 类型定义 typedef (为数据类型定义新名) typedef char * STRING; char *str; typedef char (*PFC) (int, char *); PFC f1;

  17. 作用域分辨符 5.6 结构与函数 5.6.1 结构用作函数参数和返回值 多个成员的参数传递效率低,一般用结构指针或引用。 尽管不允许函数返回数组,但返回整个结构是可以的。效率低的问题仍然可 通过指针或引用解决,但只能用全局变量和静态变量。 5.6.2 成员函数(函数作为结构的成员) 成员函数在结构内定义缺省是内联的。也可把成员函数放在结构外定义: ex. 14 struct c1 { char *val; int i; void print( ); }; inline void c1::print( ) { cout<<“member function”<<endl; }

More Related