170 likes | 268 Views
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)。
E N D
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)。 pxn的结果为: pxnsizeof(T) px-py求出的是两指针位置之间的数据个数,而不是地址差。 px-py的结果为:( px-py) / sizeof(T) y= px++——y= ( px++ ), 注意优先级和结合顺序 y= ++ px——y= ( ++ px) 问题:y= px++和y= (px)++的意义
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;
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 字符指针与字符数组 可用字符数组表示字符串,也可用字符指针指向字符串的首址。 指针表示字符串可以赋多个串值,只要将字符串的首址赋给它。 字符数组是常量不能赋值。
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 指针数组 指向同一类型对象的指针组成的数组。每个数组元素都是一指针变量。 存储类型 数据类型 * 指针数组名[元素个数]
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 指针函数(指针作为函数的返回值) 存储类型 数据类型 * 函数名(参数表)
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);
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”); }
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 * 性质:任何类型的指针都可以赋给它。作为参数传入指向任何类型的指针都可与它匹配。
两个比较函数: #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]<<“ “; }
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;
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; }
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; };
举例: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”; } }
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; }
在特定时刻,联合只有一个成员被保存,而不提供其它成员的信息。在特定时刻,联合只有一个成员被保存,而不提供其它成员的信息。 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; //错 }
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;
作用域分辨符 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; }