1 / 80

10.3 数组与指针

10.3 数组与指针. 一个变量有地址,一个数组包含若干元素,每个数组元素都在内存中占用存储单元,它们都有相应的地址。指针变量既然可以指向变量,当然也可以指向数组元素(把某一元素的地址放到一个指针变量中)。. 所谓 数组元素的指针就是数组元素的地址 。. 10.3.1 指向数组元素的指针. 定义一个指向数组元素的指针变量的方法,与以前介绍的指向变量的指针变量相同。 例如: int a[10] ; // 定义a为包含 10 个整型数据的数组 int* p; // 定义p为指向整型变量的指针变量. 对该指针变量赋值: p=&a[0] ;  p=a;

giles
Download Presentation

10.3 数组与指针

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. 10.3 数组与指针 一个变量有地址,一个数组包含若干元素,每个数组元素都在内存中占用存储单元,它们都有相应的地址。指针变量既然可以指向变量,当然也可以指向数组元素(把某一元素的地址放到一个指针变量中)。 所谓数组元素的指针就是数组元素的地址。

  2. 10.3.1 指向数组元素的指针 定义一个指向数组元素的指针变量的方法,与以前介绍的指向变量的指针变量相同。 例如:int a[10];//定义a为包含10个整型数据的数组 int*p; //定义p为指向整型变量的指针变量 对该指针变量赋值: p=&a[0];  p=a; 把a[0]元素的地址赋给指针变量p。也就是使p指向a数组的第0号元素,如图:

  3. 10.3.2通过指针引用数组元素 引用一个数组元素,可以用: (1) 下标法,如a[i]形式; (2) 指针法,如*(a+i)或*(p+i)。 其中a是数组名,p是指向数组元素的指针变量,其初值p=a。 p+i  a+i  &a[i] *(p+i)  *(a+i)  a[i] p[i] 即以下几个语句等效: a[i]=10; *(p+i)=10; *(a+i)=10; p[i]=10;

  4. 假设有一个a数组,整型,有10个元素。要输出各元素的值有三种方法: 例10.5 输出数组中的全部元素。 (1)下标法。 (2) 通过数组名计算数组元素地址,找出元素的值。 (3)用指针变量指向数组元素。 可否用多种方法读入数组元素值?如何实现?

  5. 从键盘输入10个数到数组a: int a[10],i,*p=a,s=0; for(i=0;i<10;i++) scanf(“%d”,&a[i]); for(i=0;i<10;i++) scanf(“%d”,a+i); for(i=0;i<10;i++) scanf(“%d”,p+i);

  6. 累加求和的各种用法: for(i=0;i<10;i++)s+=a[i]; for(i=0;i<10;i++)s+=*(a+i); for(i=0;i<10;i++)s+=*(p+i); for(i=0;i<10;i++)s+=p[i]; for(i=0;i<10;i++)s+=*p++; 等效于*(p++) for(p=a;p<a+10;p++)s+=*p;注意不能使用a++ 后两种用法效率高。

  7. 例10.6 通过指针变量输出a数组的10个元素。 #include <stdio.h> void main() {int*p,i,a[10];  p=a; for(i=0;i<10;i++) scanf(″%d″,p++); printf(″\n″); p=a;//指针重新指向数组的第一个元素 for(i=0;i<10;i++,p++ ) printf(″%d″,*p); }

  8. 10.3.3 用数组名作函数参数 在第8章8.7节中介绍过可以用数组名作函数的参数 如:void main() { if(int arr[ ],int n); int array[10]; … f(array,10); … } void f(int arr[ ],int n) { … }

  9. 例10.7 将数组a中n个整数按相反顺序存放。

  10. #include <stdio.h> void main() { void inv(int x[ ],int n); int i,a[10]={3,7,9,11,0,6,7,5,4,2}; printf(″The original array:\n″); for(i=0;i<10;i++) printf (″%d,″,a[i]); printf(″\n″); inv(a,10); printf(″The array has been in verted:\n″); for(i=0;i<10;i++) printf (″%d,″,a[i]); printf (″\n″); }

  11. A void inv(int x[ ],int n) /*形参x是数组名*/ {int temp,i,j,m=(n-1)/2; for(i=0;i<=m;i++) { j=n-1-i; temp=x[i]; x[i]=x[j]; x[j]=temp; } return; } 运行情况如下: The original array: 3,7,9,11,0,6,7,5,4,2 The array has been inverted: 2,4,5,7,6,0,11,9,7,3

  12. a与x共用同一片内存单元

  13. 对刚才的程序可以作一些改动。将函数inv中的形参x改成指针变量。对刚才的程序可以作一些改动。将函数inv中的形参x改成指针变量。 B void inv(int *x,int n) /*形参x为指针变量*/ {int*p,temp,*i,*j,m=(n-1)/2; i=x;j=x+n-1;p=x+m; for(;i<=p;i++,j--) {temp=*i;*i=*j;*j=temp;} return; } int temp,*i,*j; i=x;j=x+n-1; for(;i<j;i++,j--) {temp=*i;*i=*j;*j=temp;} return; 实际上,C编译都是将形参数组名作为指针变量来处理的。以上两种(A、B)形参表写法本质是等价的。

  14. 如果有一个实参数组,想在函数中改变此数组中的元素的值,实参与形参的对应关系有以下4种情况: (1) 形参和实参都用数组名,如: void main() void f(int x[],int n) { int a[10]; { … … f(a,10); } }

  15. (2) 实参用数组名,形参用指针变量。如: void main() void f(int *x,int n) {int a[10]; { … … f(a,10); } } (3)实参形参都用指针变量。例如: void main() void f(int *x,int n) {int a[10] , *p=a; { … … f(p,10); } }

  16. (4) 实参为指针变量,形参为数组名。如: void main() void f(int x[ ],int n) {int a[10] ,*p=a; { … … f (p,10); } } 如果用指针变量作实参,必须先使执针变量有确定值,指向已定义的单元。p240 以上四种方法,实质都是地址传递。

  17. 例10.9 用选择法对10个整数按由大到小顺序排序。 #include <stdio.h> void main() { void sort(int x[ ],int n); int*p,i,a[10]; p=a; for(i=0;i<10;i++) scanf(″%d″,p++); p=a; sort(p,10); for(p=a,i=0;i<10;i++) {printf(″%d″,*p);p++;} }

  18. void sort(int x[ ],int n) { int i,j,k,t; for(i=0;i<n-1;i++)  {k=i; for(j=i+1;j<n;j++)   if(x[j]>x[k])  k=j;   if(k!=i)   {t=x[i]; x[i]=x[k]; x[k]=t;}   } } 分段排序? main() { int a[10],j; for(j=0;j<10;j++)scanf(“%d”,a+j); sort(a,5); sort(a+5,5); for(j=0;j<10;j++)printf(“%5d”,a[j]); }

  19. 10.3.4 多维数组与指针 用指针变量可以指向一维数组中的元素,也可以指向多维数组中的元素。从本质上说,多维数组的指针与一维数组的指针相同,但在概念上和使用上,多维数组的指针比一维数组的指针要复杂一些。 1. 多维数组元素的地址 例 : 定义int a[3][4]={{1,3,5,7},{9,11,13,15},{17,19,21,23}}; 则二维数组a是由3个一维数组所组成的。设二维数组的首行的首地址为2000 ,则

  20. 例10.10 输出二维数组有关的值 #include <stdio.h> #define FROMAT″%d,%d\n″ void main() { int a[3][4]={1,3,5,7,9,11,13, 15,17,19,21,23}; printf(FORMAT,a,*a); printf(FORMAT,a[0] , *(a+0)); printf(FORMAT,&a[0],&a[0][0]); printf(FORMAT,a[1],a+1); printf(FORMAT,&a[1][0],*(a+1)+0); printf(FORMAT,a[2],*(a+2)); printf(FORMAT,&a[2],a+2); printf(FORMAT,a[1][0],*(*(a+ 1)+0)); }

  21. 某一次运行结果如下: 158,158 (0行首地址和0行0列元素地址) 158,158 (0行0列元素地址) 158,158 (0行0首地址和0行0列元素地址) 166,166 (1行0列元素地址和1行首地址) 166,166 (1行0列元素地址) 174,174 (2行0列元素地址) 174,174 (2行首地址) 9,9 (1行0列元素的值)

  22. 例:求数组a的所有元素之和,可有多种用法: for(i=0;i<3;i++) for(i=0;i<3;i++) for(j=0;j<4;j++) for(j=0;j<4;j++) s+=a[i][j]; s+=*(a[i]+j); for(i=0;i<3;i++) for(j=0;j<4;j++) s+=*(*(a+i)+j);

  23. 2 . 指向多维数组元素的指针变量 (1) 指向数组元素的指针变量 例10.11 用指针变量输出二维数组元素的值 #include <stdio.h> void main() { int a[3][4]={1,3,5,7,9,11,13,15,17,19,21,23}; int*p; for(p=a[0];p<a[0]+12;p++) {if((p-a[0])%4==0) printf(″\n″); printf(″%4d″,*p); } }   运行结果如下: 1 3 5 7 9 11 13 15 19 21 23

  24. (2) 指向由m个元素组成的一维数组的指针变量 例10.13 输出二维数组任一行任一列元素的值 #include <stdio.h> void main ( ) { int a[3][4]={1,3,5,7,9,11, 13,15,17,19,21,23}; int (*p)[4],i,j; p=a; scanf(″ i=%d,j=%d″,&i,&j); printf(″a[%d,%d]=%d\n″,i, j,*(*(p+i)+j)); } 运行情况如下: i=1,j=2↙(本行为键盘输入) a[1,2]=13

  25. 3. 用指向数组的指针作函数参数 例10.13 有一个班,3个学生,各学4门课,计算总平均分数以及第n个学生的成绩。这个题目是很简单的。只是为了说明用指向数组的指针作函数参数而举的例子。用函数average求总平均成绩,用函数search找出并输出第i个学生的成绩。

  26. 思考两个形参p的区别,各自的应用场合及其优缺点???思考两个形参p的区别,各自的应用场合及其优缺点??? #include <stdio.h> void main() { void average(float *p,int n); void search(float (*p)[4],int n); float score[3][4]={{65,67,70,60},{80, 87,90,81},{90,99,100,98}}; average(*score,12);/*求12个分数的平均分*/ search(score,2);/*求序号为2的学生的成绩*/ } 必须为常量

  27. void average(float *p,int n) { float*p_end; float sum=0,aver; p_end=p+n-1; for(;p<=p_end;p++) sum=sum+(*p); aver=sum/n; printf(″average=%5.2f\n″,aver); }

  28. void search(float (*p)[4],int n) / * p是指向具有4个元素的一维数组的指针 */{int i; printf(″the score of No. %d are:\n″,n); for(i=0;i<4;i++) printf(″%5.2f ″,*(*(p+n)+i)); } p[n][i] 程序运行结果如下: average=82.25 The score of No.2 are: 90.00 99.00 100.00 98.00

  29. 例10.14 在上题基础上,查找有一门以上课程不及格的学生,打印出他们的全部课程的成绩。 #include <stdio.h> void main() {void search(float (*p)[4],int n);/*函数声明*/ float score[3][4]={{65,57,70,60},{58,87, 90,81},{90,99,100,98}}; search(score,3); } 注意形参与实参类型的一致性

  30. 程序运行结果如下: No.1 fails, his scores are: 65.0 57.0 70.0 60.0 No.2 fails, his scores are: 58.0 87.0 90.0 81.0 void search(float (*p)[4],int n) {int i,j,flag; for(j=0;j<n;j++) {flag=0; for(i=0;i<4;i++) if(*(*(p+j)+i)<60)flag=1; if(flag==1) { printf("No.%d fails,his scores are:\n",j+1); for(i=0;i<4;i++) printf(″%5.1f″,*(*(p+j)+i) ); printf(″\n″);    } } } p[j][i]

  31. 10.4 字符串与指针 10.4.1字符串的表示形式 (1) 用字符数组存放一个字符串。例 10.15 (2) 用字符指针指向一个字符串。例10.16 #include <stdio.h> void main() {char * string=″I love China!″; printf(″%s\n″,string); printf( ″%c\n ″,*(string+3)); }

  32. 例10.17 将字符串a复制为字符串b。  也可以设指针变量,用它的值的改变来指向字符串中的不同的字符。 例10.18 用指针变量来处理例10.17问题。 #include <stdio.h> void main() {char a[ ] =″I am a boy. ″,b[20],*p1,*p2; int i;   p1=a;p2=b; for(;*p1!=′\0′;p1++,p2++)

  33. *p2=*p1; *p2=′\0′; printf(″string a is:%s\n″,a); printf(″string b is:″); for(i=0;b[i]!=′\0′;i++) printf(″%c″,b[i]); printf(″\n″); } 程序必须保证使p1和p2同步移动

  34. 10.4.2 字符指针作函数参数 (1) 用字符数组作参数 例10.19 用函数调用实现字符串的复制 #include <stdio.h> void main() { void copy_string(char from[ ], char to[ ]); char a[ ]=″I am a teacher.″; char b[ ]=″you are a student.″; printf(“string a=%s\n string b=%s\n″,a,b); printf(“copy string a to string b:\n ”); copy_string (a,b); printf("\nstring a=%s\nstring b=%s\n",a,b); }

  35. void copy_string(char from[ ], char to[ ]) { int i=0; while(from[i]!=′\0′)  {to[i]=from[i];i++;} to[i]=′\0′; } 程序运行结果如下: string a=I am a teacher. string b=you are a student. copy string a to string b: string a =I am a teacher. stringb=I am a teacher.

  36. (2) 形参用字符指针变量 #include <stdio.h> void main() { void copy_string(char * from, char *to); char *a=″I am a teacher .″; char *b=″you are a student .″; printf("string a=%s\nstring b=%s\n″,a,b); printf("copy string a to string b:\n "); copy_string(a,b); printf("\nstring a=%s\nstring b=%s\n" ,a ,b);  }

  37. void copy_string(char *from,char *to) { for(;*from!=′\0′;from++,to++)    *to=*from;   *to=′\0′; } (3) 对copy_string函数还可作简化 将copy_string函数改写为 void copy_string (char *from,char *to) {while((*to=*from)!=′\0′) {to++;from++;} }

  38. • copy_string函数的函数体还可改为 { while((*to++=*from++)!=′\0′); } •copy_string函数的函数体还可写成 { while(*from!=′\0′)   *to++=*from++;   *to=′\0′; }

  39. •上面的while语句还可以进一步简化为下面的while语句:•上面的while语句还可以进一步简化为下面的while语句: while(*to++=*from++); 它与下面语句等价: while((*to++=*from++)!=′\0′); 将*from赋给*to,如果赋值后的*to值等于′\0′则循环终止(′\0′已赋给*to) •函数体中while语句也可以改用for语句: for(;(*to++=*from++)!=0;); 或 for(;*to++=*from++;);

  40. •也可用指针变量,函数copy_string可写为 void copy_string (char from[ ],char to[ ]) {char*p1,*p2; p1=from;p2=to; while((*p2++=*p1++)!=′\0′); } •甚至,函数copy_string可写为 void copy_string (char from[ ],char to[ ]) {while((*to++=*from++)!=′\0′); }

  41. 10.4.3 对使用字符指针变量和字符数组的讨论 字符数组和字符指针变量二者之间的区别: (1) 字符数组由若干个元素组成,每个元素中放一个字符,而字符指针变量中存放的是地址(字符串第1个字符的地址),决不是将字符串放到字符指针变量中。 (2)赋值方式。对字符数组只能对各个元素赋值,不 能用以下办法对字符数组赋值。 char str[14]; str=″I love China!″; 而对字符指针变量,可以采用下面方法赋值: char*a; a=″I love China!″;

  42. (3)对字符指针变量赋初值: char *a=″I love China!″;等价于 char*a; a=″I love Chian!″; 而对数组的初始化: char str[14]={″I love China!″}; 不能等价于 char str[14]; str[ ]=″I love China!″;

  43. (4) 定义了一个字符数组,在编译时为它分配内存单元,它有确定的地址。而定义一个字符指针变量时,给指针变量分配内存单元,在其中可以放一个字符变量的地址。 例如:char str[10]; scanf(″%s″,str); 没有特定的指向 例如:char *a; scanf(″%s″,a); ×

  44. (5) 指针变量的值是可以改变的,例如: 例10.20 改变指针变量的值 #include <stdio.h> void main() {char*a=″I love China!″; a=a+7; printf(″%s″,a); }

  45. 若定义了一个指针变量,并使它指向一个字符串,就可以用下标形式引用指针变量所指的字符串中的字符。例10.21: (6)用指针变量指向一个格式字符串,可以用它替代printf中的格式字符串。

  46. 内存空间的动态分配 在程序设计中,对于要处理的批量数据,我们往往是选用数组作为存放这些数据的数据结构,然而,数组有一个明显的缺点,就是在定义数组时,其长度必须是常值,无法根据需要动态地定义。这样,在很多情况下,不是定义的数组长度不够,就是定义太长以至于浪费。 采用动态分配可以克服这一缺点,并且可以随时释放。

  47. 动态分配内存空间步骤: ①定义一指针变量。 ②申请一片内存空间,并将其首地址赋给指针变量。此时便可通过指针变量访问这片内存。 ③用完后释放这片内存空间。 int *p; p=malloc(byte); …… free(p); //malloc函数的原形在stdio.h中。 //void * malloc(unsigned size);

  48. 例:对n个学生的分数排序后输出。 #include “stdio.h” void sort(int *a, int n) { ……} main() { int *a,j,n; scanf(“%d”,&n); a=malloc(n*sizeof(int)); if(!a) exit(0); for(j=0;j<n;j++) scanf(“%d”,a+j); sort(a,n); for(j=0;j<n;j++) printf(“%5d”,a[j]); free(a); }

More Related