资源预览内容
第1页 / 共44页
第2页 / 共44页
第3页 / 共44页
第4页 / 共44页
第5页 / 共44页
第6页 / 共44页
第7页 / 共44页
第8页 / 共44页
第9页 / 共44页
第10页 / 共44页
亲,该文档总共44页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述
1n地址与指针地址与指针n指针变量的定义和使用指针变量的定义和使用n指针与数组指针与数组n指针数组指针数组n多维数组作为参数的通用函数多维数组作为参数的通用函数n动态存储管理动态存储管理n定义类型定义类型n指向函数的指针指向函数的指针第十四部分指针第十四部分指针3n地址与指针地址与指针n指针变量的定义和使用指针变量的定义和使用n指针与数组指针与数组n指针数组指针数组n多维数组作为参数的通用函数多维数组作为参数的通用函数n动态存储管理动态存储管理n定义类型定义类型n指向函数的指针指向函数的指针第十四部分指针第十四部分指针指针(数值型指针(数值型/字符型)与一维数组字符型)与一维数组(数值型数组(数值型数组/字符串)的关系字符串)的关系43 指针与数组指针与数组C指指针针与与数数组组关关系系密密切切,以以指指针针为为媒媒介介可可以以完完成成各各种数组操作种数组操作 用指针做数组操作同样要用指针做数组操作同样要特别注意特别注意越界错误。越界错误。指指针针和和数数组组的的关关系系是是C语语言言特特有有的的,除除了了由由C派派生生出的语言(如出的语言(如C+),一般语言中没有这种关系。),一般语言中没有这种关系。如何利用指针访问数组。如何利用指针访问数组。5int *p1, *p2, *p3, *p4;int a10 = 1,2,3,4,5,6,7,8,9,10; 指向数组元素的指针指向数组元素的指针可以写:可以写:p1 = &a0; p2 = p1;p3 = &a5; p4 = &a10; 这个地址存在,但写这个地址存在,但写 * *p4 是错误的。是错误的。P4P4没没有指向合法元素有指向合法元素p1 = &a0;可简写为:可简写为: p1 = a;数组名是表示数组首地址的地址常量区别?区别?6当指针当指针p指向数组元素时说指向数组元素时说p指到了数组里指到了数组里。这时由。这时由p可以访可以访问被问被p指的元素,还可访问数组的其他元素。指的元素,还可访问数组的其他元素。例:例:p1 = &a0 ,则则 p1+1合法,为合法,为a1的地址的地址 p1+2、p1+3、也合法,分别为也合法,分别为a2 、a3的地址的地址使用:使用: *(p1 + 2) = 3;/* 给给a2赋值赋值 */ p2 = p1 + 5; /* 使使p2指向指向a5 */ *(p2 + 2) = 5; /* 给给a7赋值赋值 */ *(p2 - 2) = 4; /* 给给a3赋值赋值 */ p2 = p2 - 2; /* 这使这使p2改指向改指向a3 */通过指针访问数组元素时必须保证不越界。通过指针访问数组元素时必须保证不越界。 指针运算指针运算7指针运算原理指针运算原理一一个个指指针针指指向向某某数数组组里里的的元元素素时时,为为什什么么能能算算出出下下一一元元素素位位置置?(这是指针运算的基础)?(这是指针运算的基础)指指针针有有指指向向类类型型,p指指向向数数组组a时时,由由于于p的的指指向向类类型型与与a的的元元素类型一致,数据对象的大小可以确定。素类型一致,数据对象的大小可以确定。p+1的的值值可可根根据据p的的值值和和数数组组元元素素大大小小算算出出。由由一一个个数数组组元元素素位位置置可可以以算算出出下下一一元元素素位位置置,或或几几个个元元素素之之后后的的元元素素位位置置。指指针运算的基础。针运算的基础。通通用用指指针针即即使使指指到到数数组组里里,因因没没有有确确定定指指向向类类型型,因因此此不不能能做做一般指针计算,只能做指针比较。一般指针计算,只能做指针比较。8可进行增可进行增/减量操作(减量操作(指针应指在数组里指针应指在数组里):): p3 = p2; +p3; -p2; p3 += 2;如如果果两两指指针针指指在在同同一一个个数数组组里里,可可以以求求差差,得得到到它它们们间间的的数数组组 元素个数(带符号整数)。元素个数(带符号整数)。 n = p3 p2; /* 也可以求也可以求 p2 p3 */在同一个数组里的指针在同一个数组里的指针可以比较大小:可以比较大小:if (p3 p2) .当当p3所所指指的的元元素素在在p2所所指指的的元元素素之之后后时时条条件件成成立立(值值为为1),否否则则不不成成立立(值值为为0)。两两个个指指针针不不指指在在同同一一数数组组里里时时,比比较较大大小小没有意义。没有意义。其他常用指针运算其他常用指针运算:9两个两个同类型指针同类型指针可用可用 = 和和 != 比较相等或不等;比较相等或不等;任何指针都能与任何指针都能与通用指针通用指针比较相等或不等;比较相等或不等;任何指针可与任何指针可与空指针空指针值(值(0或或NULL)比较相等或不等)比较相等或不等两指针指向两指针指向同一数据同一数据元素,或同为元素,或同为空值空值时它们相等时它们相等。当一个指针指向数组时的数组写法与指针写法:指针当一个指针指向数组时的数组写法与指针写法:指针的两种用法的两种用法设设p1 = &a0,p3 = &a5 p1和和p3相当于数组名相当于数组名 可写:可写:p13 = 5; 相当于相当于*(p1+3)=5;或;或 a3=5; p32 = 8; 相当于相当于*(p3+2)=8;或;或 a7=8; p13称为称为数组写法数组写法,*(p1+3)称为称为指针写法指针写法两类写法有等价效力,可以自由选用。两类写法有等价效力,可以自由选用。10a0a1a2a3a9.aa+9a+1a+2地址元素下标法a0a1a2a9a0a1a2a3a9.pp+9p+1p+2地址元素指针法*p*(p+1)*(p+2)*(p+9) 变址运算符ai *(a+i)ai pi *(p+i) *(a+i)*a*(a+1)*(a+2)*(a+9)p0p1p2p911对数组名求值得到指向数组首元素的指针值对数组名求值得到指向数组首元素的指针值数数组组名名可可以以“看看作作”常常量量指指针针,可可参参与与一一些些指指针针运运算算,与与其其他指针比大小,比较相等与不相等。他指针比大小,比较相等与不相等。通过数组名的元素访问也可以采用指针写法。通过数组名的元素访问也可以采用指针写法。 a3可写为可写为*(a+3)。注意:注意:数组名不是指针变量数组名不是指针变量,特别是不能赋值,不能更改。,特别是不能赋值,不能更改。 若若a为数组,下面操作都是错误的:为数组,下面操作都是错误的:a+;a += 3;a = p;有有些些运运算算虽虽不不赋赋值值但但也也可可能能没没意意义义。如如 a3 不不可可能能得得到到合合法指针值,因其法指针值,因其结果超出数组界限结果超出数组界限12a0a1a2a3a4int main() int a5, *pa, i; for (i = 0; i 5; i+) ai = i + 1; pa = a; for (i = 0; i 5; i+) printf(*(pa+%d):%dn, i, *(pa+i);/通过指针找通过指针找地址法地址法 for (i = 0; i 5; i+) printf(*(a+%d):%dn, i, *(a+i);/通过指针找通过指针找地址法地址法 for(i = 0; i 5; i+) printf(pa%d:%dn, i, pai);/下标法下标法 for (i = 0; i 5; i+) printf(a%d:%dn, i, ai);/下标法下标法 return 0;12345pa例例 数组元素的引用方法(数组元素的引用方法(1)13基于指针的数组程序设计基于指针的数组程序设计指针运算是处理数组元素的一种有效方式。设有指针运算是处理数组元素的一种有效方式。设有int数组数组a和指针和指针p1,p2,下面代码都打印,下面代码都打印a的元素:的元素: for (p1 = a; p1 a+10; +p1) printf(%dn, *p1);for (p1 = a; p1 - a 10; +p1)printf(%dn, *p1);for (p1 = a, p2 = a+10; p1 p2; +p1) printf(%dn, *p1);for (p1 = p2 = a; p1 - p2 10; +p1) printf(%dn, *p1);14数组参数的意义数组参数的意义C规定,数组参数就是相应类型的指针参数:规定,数组参数就是相应类型的指针参数:int f(int n, int d) . .和和int f(int n, int *d) . . 意义相同。意义相同。数组参数就是利用指针实现的!数组参数就是利用指针实现的!这也使采用数组参数的函数能修改实参数组。这也使采用数组参数的函数能修改实参数组。15函数里也可用指针方式做元素访问。函数里也可用指针方式做元素访问。int intsum (int n, int a) int i, m = 0; for (i = 0; i n; +i) m += *(a+i); return m;函数里不能用函数里不能用sizeof确定数组实参大小:确定数组实参大小:函数的数组形参实函数的数组形参实际是指针,求际是指针,求sizeof算出的是指针的大小。算出的是指针的大小。另一方面,另一方面,sizeof的计算是在编译中完成的。实参是动态运的计算是在编译中完成的。实参是动态运行中确定的东西。行中确定的东西。m+=ai;int intsum (int n, int *a) int i, m = 0; for (i = 0; i n; +i) m += *(a+i); return m;16使用数组的一段元素使用数组的一段元素以数组为参数的函数可处理一段元素。求元素和:以数组为参数的函数可处理一段元素。求元素和:double sum(int n, double a);设有双精度数组设有双精度数组b,40个元素已有值:个元素已有值:用用sum可求可求b所有元素之和所有元素之和/前一段元素之和:前一段元素之和:x = sum(40, b);y = sum(20, b);sum不不知知道道b的的大大小小,它它由由参参数数得得到到数数组组首首元元素素地地址址,从从这这里里开开始始求连续求连续40或或20个元素的和。个元素的和。也可用也可用sum求求b中中下标下标12到到24的一段元素之和。的一段元素之和。 z = sum(13, b+12); 17例例1 1 下面的程序的输出结果是什么下面的程序的输出结果是什么? ?#include int a = 2,4,7,8,9;int main() int i,*p = a; for (i = 0; i 4; i+) ai = *(+p); printf(%dn, a2); return 0; 运行结果为:运行结果为:8 818例例2 int a = 1,2,3,4,5,6,7,8,9,10, *p = a, i; 数组元素地址的正确表示:数组元素地址的正确表示:(A)&(a+1) (B)a+ (C)&p (D)&pi数组名是数组名是地址常量地址常量p+,p- ( )a+,a- ( )a+1, *(a+2) ( )19例例 int main() int a = 5,8,7,6,2,7,3; int y, *p = &a1; y = (*-p)+; printf(“%d ”, y); printf(“%d”, a0); return 0; 输出:输出:5 6pp58762730123456a6例例3 注意指针变量的运算注意指针变量的运算*p+ *p+ *(p+)*(p+)*p+*p+、* *+p+p、(*p)+(*p)+作用不同作用不同* *p+p+先取先取p p指向变量的值再指针变量加指向变量的值再指针变量加1 1* *+p+p先使指针变量加先使指针变量加1 1再取再取* *p p(*p)+(*p)+使使p p指向的元素值加指向的元素值加1 120int main() int i, *p ,a7; p = a; for (i = 0; i 7; i+) scanf(%d, p+); printf(n); for (i = 0; i 7; i+, p+) printf(%d, *p); return 0;p = a;pp58762730123456apppppp指针变量可以指到指针变量可以指到数组后数组后的内存单元的内存单元例例4 注意指针的当前值注意指针的当前值21要点:要点:1 1、指针变量可以实现自身值的改变:、指针变量可以实现自身值的改变:如:如:p+;p+;但数组名则不能进行改变:但数组名则不能进行改变:a+a+是错误的用法。是错误的用法。2 2、应注意指针变量的当前值。、应注意指针变量的当前值。3 3、指针变量可以指向数组以后的内存单元。、指针变量可以指向数组以后的内存单元。4 4、注意以下的指针运算:、注意以下的指针运算:若:若:int a10,*p = a;int a10,*p = a;则:则:p+p+ 等价于等价于 &a1&a1 *p+*p+ 等价于等价于 * *(p+)(p+) 但但 * *(p+)(p+)与与* *(+p)(+p)却不同却不同 (* *p p)+等价于等价于 a0+a0+22例例1 1 利用指针,输出利用指针,输出int数组里一段元素:数组里一段元素:void prt_seq(int *begin, int *end) for (; begin != end; +begin) printf(%dn, *begin); prt_seq(a, a+10);prt_seq(a+5, a+10);prt_seq(a, a+3);prt_seq(a+2, a+6);prt_seq(a+4, a+4);prt_seq(a+10, a+10);最后两个调用对应空序列。最后两个调用对应空序列。23“设置设置”函数:函数:void set_seq(int *b, int *e, int v) for (; b != e; +b) *b = v; 把序列中每个元素都用其平方根取代:把序列中每个元素都用其平方根取代:void sqrt_seq (double *b, double *e) for (; b!=e; +b) *b = sqrt(*b); 求平均值:求平均值:double avrg(double *b, double *e) double *p, x = 0.0; if (b = e) return 0.0; for (p = b; p != e; +p) x += *p; return x / (e - b);24数组名作函数参数,是数组名作函数参数,是地址传递地址传递数组名作函数参数,实参与形参的对应关系数组名作函数参数,实参与形参的对应关系实参形参数组名指针变量数组名指针变量数组名数组名指针变量指针变量数组名作函数参数数组名作函数参数25ij 3 7 9 11 0 6 7 5 4 20 1 2 3 4 5 6 7 8 9ijijijji11760594723实参与形参均用数组实参与形参均用数组void inv(int x, int n) int t, i, j, m = (n-1)/2; for (i = 0; i = m; i+) j = n-1-i; t = xi; xi = xj; xj = t; int main() int i, a10 = 3,7,9,11,0,6,7,5,4,2; inv(a, 10); printf(The array has been reverted:n); for (i = 0; i 10; i+) printf(%d, ai); printf(n); return 0;m=4例例5 将数组将数组a中的中的n个整数按相反顺序存放(个整数按相反顺序存放(1)26void inv(int *x, int n) int t,*p,*i,*j, m = (n-1)/2; i = x; j = x+n-1; p = x+m; for(;i = p; i+, j-) t = *i; *i = *j; *j = t; int main() int i,a10 = 3,7,9,11,0,6,7,5,4,2; inv(a, 10); printf(The array has been reverted:n); for (i = 0; i 10; i+) printf(%d, ai); printf(n); return 0;实参用数组实参用数组,形参用指针变量形参用指针变量37911067542a0a1a2a3a4a5a6a7a8a9xp=x+ma数组60711594723ijijijjiji例例5 将数组将数组a中的中的n个整数按相反顺序存放(个整数按相反顺序存放(2)27void inv(int *x, int n) int t,*i,*j,*p,m=(n-1)/2; i=x; j=x+n-1; p=x+m; for(;i=p;i+,j-) t=*i; *i=*j; *j=t; int main() int i, a10, *p = a; for (i = 0; i 10; i+, p+) scanf(%d, p); p=a; inv(p, 10); printf(The array has been reverted:n); for (p = a; p a+10; p+) printf(%d, *p); return 0;实参与形参均实参与形参均用指针变量用指针变量例例5 将数组将数组a中的中的n个整数按相反顺序存放(个整数按相反顺序存放(3)28void inv(int x, int n) int t, i, j, m = (n-1)/2; for (i = 0;i = m; i+) j = n-1-i; t = xi; xi = xj; xj = t; int main() int i, a10, *p = a; for (i = 0; i 10; i+, p+) scanf(%d, p); p = a; inv(p, 10); printf(The array has been reverted:n); for (p = a; p a+10; p+) printf(%d , *p); return 0;实参用指针变量实参用指针变量形参用数组形参用数组例例5 将数组将数组a中的中的n个整数按相反顺序存放(个整数按相反顺序存放(4)29#include #define MAX 5void fun1();void fun2(int );int aMAX;int main() fun1(); fun2(a); printf(n); return 0; void fun1() int k, t = 0; for (k = 0; k MAX; k+, t+) ak = t+t;void fun2(int b) int k; for (k = 0; k MAX; k += 2) printf(%4d, *(b+k);例例6 分析程序写出结果分析程序写出结果运行结果为:运行结果为:0 4 830#include void fun(int *s) static int j = 0; do sj += sj+1; while(+j 2); int main()int k, a10 = 1,2,3,4,5; for (k = 1; k 3; k+) fun(a); for (k = 0; k 5; k+) printf(“%4d”, ak); return 0; 例例7 分析程序写出结果分析程序写出结果运行结果为:运行结果为:3 5 7 4 5 31int *p 与与 int q10 数组名是指针(地址)数组名是指针(地址)常量常量p = q; p+i 是是qi的地址的地址数组元素的表示方法数组元素的表示方法:下标法下标法和和指针法指针法, 即若即若p=q, 则则 pi qi *(p+i) *(q+i) 形参数组形参数组实质上是实质上是指针变量指针变量,即,即int q int *q在定义指针变量(不是形参)时,在定义指针变量(不是形参)时,不能把不能把int *p 写写成成int p;系统只给系统只给p分配能保存一个指针值的内存区分配能保存一个指针值的内存区(一般一般4字字节);而给节);而给q分配分配sizeof(int)*10字节的内存区字节的内存区一级指针变量与一维数组的关系一级指针变量与一维数组的关系32定义字符指针时可用字符串常量初始化,如:定义字符指针时可用字符串常量初始化,如:char *p = Programming;1)定义了指针)定义了指针p2)建立了一个字符串常量,内容为)建立了一个字符串常量,内容为Programming3)令)令p指向该字符串常量。图指向该字符串常量。图(a)char a = Programming; 1)定义了一个)定义了一个12个字符元素的数组个字符元素的数组2)用)用Programming各字符初始化各字符初始化a的元素,图的元素,图(b)字符指针与字符数组字符指针与字符数组常用字符指针指向字符常用字符指针指向字符数组元素数组元素331)指针指针p可重新赋值(可重新赋值(数组不能赋值数组不能赋值:a=“” ):):p = Programming Language C;2)p和和a类型不同,大小不同。类型不同,大小不同。a占占12个字符的空间。个字符的空间。3)a的元素的元素可以重新赋值。如:可以重新赋值。如:a8=e; a9=r; a10=0;a的内容现在变成的内容现在变成“Programmer”34IloveChistring0string1string2string3string4string5string6string7string8string9stringstring10string11string12string13n!a0/字符串用字符数组实现字符串用字符数组实现int main( ) char string = “I love China!”; printf(“%sn”, string); printf(“%sn”, string+7); return 0;/字符串用字符指针实现字符串用字符指针实现int main( ) char *string = “I love China!”; printf(“%sn”, string); string += 7; while (*string) putchar(string0); string+; return 0;I love China!China!35#include int main()char arr = ABCDE; char *ptr; for(ptr = arr; ptr arr+5; ptr+) printf(%sn, ptr);return 0; 运行结果:ABCDE BCDE CDE DE E例例1 分析以下程序的运行结果分析以下程序的运行结果36#include int main()char *p1 = programming, *p2 = language;int i;for (i = 0; i 7; i+)if (*(p1+i) = *(p2+i)printf(%c, *(p1+i);return 0;运行结果:ga例例2 分析以下程序的运行结果分析以下程序的运行结果37例例3 3,输入一行到数组里:,输入一行到数组里:enum NLINE = 256 ;char lineNLINE;int count; char *p;/*-*/p = line;while(plineNLINE-1 & (*p = gerchar()!=n) +p; *p = 0; /* 做成字符串做成字符串 */*-*/for (count = 0, p = line; *p != 0; +p) if (*p = e) +count; /* 统计统计e的个数的个数 */38例例1,用指针方式实现字符串长度函数。,用指针方式实现字符串长度函数。一种方式一种方式:int strLength (const char *s) int n = 0; /*通过局部指针扫描串中字符通过局部指针扫描串中字符*/ while (*s != 0) s+; n+; return n; 另一实现:另一实现:int strLength (const char *s) char *p = s; while (*p != 0) p+; return p - s;参数类型参数类型(char*),实参应是字符串或存字符串的数组实参应是字符串或存字符串的数组指针与数组操作函数实例指针与数组操作函数实例指针使用非常灵活指针使用非常灵活39void strCopy(char *s, const char *t) while (*s = *t) != 0) s+; t+; 把指针更新操作也写在循环测试条件里,把指针更新操作也写在循环测试条件里,void strCopy (char *s, const char *t) while (*s+ = *t+) ; / 空语句空语句赋值表达式有值,赋值表达式有值,0就是就是0,可简化:,可简化:void strCopy(char *s, const char *t) while(*s = *t) s+; t+; 例例2,用指针实现字符串复制函数。,用指针实现字符串复制函数。40例例 用函数调用实现字符串复制用函数调用实现字符串复制(1)用字符数组作参数)用字符数组作参数aIamateaceh0r.fromabyuarasutndetoboet.0Iaaeceh0r.t.0mtavoid copy_string(char from,char to) int i = 0; while (fromi != 0) toi = fromi; i+; toi = 0;int main() char a = I am a teacher.; char b = You are a student.; printf(string_a=%sn string_b=%sn, a, b); copy_string(a, b); printf(nstring_a=%snstring_b=%sn, a, b); return 0;字符指针作函数参数字符指针作函数参数41例例 用函数调用实现字符串复制用函数调用实现字符串复制(2)用字符指针变量作参数)用字符指针变量作参数aIamateaceh0r.fromabyuarasutndetoboet.0Iaaeceh0r.t.0mtavoid copy_string(char *from, char *to) for (; *from != 0; from+, to+) *to = *from; *to = 0;int main() char a = I am a teacher.; char b = You are a student.; printf(string_a=%snstring_b=%sn, a, b); copy_string(a, b); printf(nstring_a=%snstring_b=%sn, a, b); return 0;字符指针作函数参数字符指针作函数参数 char *b = You are a student.;字符串是一个常量,字符串是一个常量,b中存放这个中存放这个常量的首地址。常量不允许被修常量的首地址。常量不允许被修改。改。这里字符串用这里字符串用指针变量会出指针变量会出错错42#include #include void fun(char *);int main()char str = abcdefghi;char *a = str;fun(a);puts(a);return 0;void fun(char *s) int x, y; char c; for (x = 0, y = strlen(s)-1; x y; x+, y-) c = sy; sy = sx; sx = c;运行结果:运行结果:ihgfedcba例例3 分析以下程序的运行结果分析以下程序的运行结果43qchar *cp; 与与 char str20;qstr由若干元素组成,每个元素放一个字符;而由若干元素组成,每个元素放一个字符;而cp中存中存放字符串首地址放字符串首地址q char str20; str=“I love China!”; ( ) char *cp; cp=“I love China!”; ( )qstr是地址是地址常量常量;cp是地址是地址变量变量qcp接受键入字符串时接受键入字符串时,必须必须先开辟存储空间先开辟存储空间例例 char str10; scanf(“%s”, str); ( )而而 char *cp; scanf(“%s”, cp); ( )改为改为: char *cp, str10; cp = str; scanf(“%s”, cp); ( )或为:或为:char *cp; cp = (char *)calloc(10, sizeof(char); scanf(“%s”, cp); ( )字符指针变量与字符数组字符指针变量与字符数组44 Q & A!
网站客服QQ:2055934822
金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号