210 likes | 321 Views
C 语言程序设计. 同学们好!下面开始讲授 C 语言课程的第 10 讲内容。 第 10 讲 指针( 2 ) 四、指针与数组 五、动态存储分配 六、使用指针和动态存储分配的程序举例 四、指针与数组 1. 指针与一维数组 ( 1 )一维数组名是指向该数组第一个元素的指针常量 int a[7]={12,25,18,30,63,44,50}; * a 表示 a[0] 元素,* a 的值即为 a[0] 的值。 a 的值等于 &a[0] ,类型 int* 。. 第 10 讲 指针( 2 ) 四、指针与数组 五、动态存储分配
E N D
C语言程序设计 同学们好!下面开始讲授C语言课程的第10讲内容。 第10讲 指针(2) 四、指针与数组 五、动态存储分配 六、使用指针和动态存储分配的程序举例 四、指针与数组 1. 指针与一维数组 (1)一维数组名是指向该数组第一个元素的指针常量 int a[7]={12,25,18,30,63,44,50}; *a表示a[0]元素,*a的值即为a[0]的值。 a的值等于&a[0],类型int*。 第10讲 指针(2) 四、指针与数组 五、动态存储分配 六、使用指针和动态存储分配的程序举例
C语言程序设计 a为指针常量,即其值不可修改,所以使用a++是错误的。道理很简单,如果允许修改数组名的值,以后就无法访问该数组了。 (2)数组元素的下标和指针访问方式 a[i]等价于*(a+i),分别为下标和指针访问方式。 *a与a[0],*(a+1)与a[1]等价。 假定int *p=a+i; 则 *p与a[i],*p++与a[i++]等价。 for (i=0; i<7; i++) printf("%5d\n",a[i]);//下标方式 等价于:for (i=0; i<7; i++) printf("%5d\n",*(a+i));//指针方式 等价于:for (p=a; p<a+7; p++) printf("%5d\n",*p);//指针方式 等价于:for (p=a,i=0; i<7; i++) printf("%5d\n",p[i]);//下标方式 //p初始指向数组a中第1个元素,p[i]与a[i]等价,均为*(a+i) 第10讲 指针(2) 四、指针与数组 五、动态存储分配 六、使用指针和动态存储分配的程序举例
C语言程序设计 2. 指针与二维数组 (1)二维数组名是指向该数组第一行元素的指针常量,其值为整个二维数组空间的首地址 int b[3][4]={{1,2,3,4},{2,4,6,8},{3,6,9,12}}; b为指向b[0]行4个元素的指针常量,其值为&b[0],亦即&b[0][0]的值,但类型为int(*)[4],而不是int*。 b[i]为i行元素(一维数组)的数组名,b[i]的值为b[i][0]元素的地址。它们的类型均为int*,即b[i]+1指向i行行首下一元素。 而&b[i]的值虽然也等于b[i][0]元素的地址,但类型为int(*)[4],因为它是该行元素的首地址,即b[i+1]指向i+1行行首元素 。注意b[i]+1与b[i+1]的区别,b[i]+1为指向i行行首的下一个元素指针,即指向b[i][1];而b[i+1]则为指向i的下一行行首元素的指针,即指向b[i+1][0] 。 同一维数组名一样,不允许修改二维数组名的值,如进行b++操作是错误的。 第10讲 指针(2) 四、指针与数组 五、动态存储分配 六、使用指针和动态存储分配的程序举例
C语言程序设计 (2)二维数组名的值可以赋给同类型的指针变量 int (*pb)[4]=b;//把b的值赋给同类型的指针变量pb,pb也指向此数组,//此后pb也可以作为数组名使用,访问任何元素 pb[2][3]等价与b[2][3],值为12。 注意:int (*pb)[4]与int (*pb)[5]不同,因为pb所指向的元素个数不同。 若int *pb[4]则定义pb为含有4个元素的整型指针数组,而不是定义指向含有4个整型元素的数组的指针。 二维数组元素的下标和指针访问方式 b[i][j](*(b+i))[j] 或*(b[i]+j) 或*(*(b+i)+j)//均等价 for (i=0; i<3; i++) { for (j=0; j<4; j++) printf("%d ", b[i][j]);// *(*(b+i)+j) 第10讲 指针(2) 四、指针与数组 五、动态存储分配 六、使用指针和动态存储分配的程序举例
C语言程序设计 printf("\n"); } (3)使用指针和数组的程序举例 例1: #include<stdio.h> void main() { int a[8]={3,5,7,9,11,13,15,17}; int i,*p=a;//p的值为&a[0] for (i=0;i<8;i++) { printf("%5d ",*p++);//先*p,后p的值加1 if ((i+1)%4==0) printf("\n");//输出4个元素后换行 } } 输出结果: 3579 11131517 第10讲 指针(2) 四、指针与数组 五、动态存储分配 六、使用指针和动态存储分配的程序举例
C语言程序设计 例2: #include<stdio.h> void main() { int a[8]={46,38,72,55,24,63,50,37}; int max=*a, min=*a; //a[0]的值赋给max和min int *p; for(p=a+1; p<a+8; p++) { //扫描整个数组 if(*p>max) max=*p; //大放max if(*p<min) min=*p; //小放min } printf("%5d %5d\n", max,min); //输出最大和最小值 } 输出结果:72 24 第10讲 指针(2) 四、指针与数组 五、动态存储分配 六、使用指针和动态存储分配的程序举例
C语言程序设计 五、动态存储分配 1. 动态存储分配的概念 变量和数组在计算机内存中都有对应的存储空间,该存储空间的分配时机有两种:一种在编译阶段,或者说在程序运行前;另一种在程序运行之中。前者称为静态存储分配方式,后者称为动态存储分配方式。 (1)变量的静态存储分配方式 通过一般的变量定义语句定义的变量,采用的是静态存储分配方式。如: int x,y; //x和y分别对应的4个字节的存储空间是静态分配的 int a[10];//数组a所需要的40个字节的存储空间是静态分配的 char b[20],*p=b;//数组b的20个字节和指针变量p的4字节是静态分配的 第10讲 指针(2) 四、指针与数组 五、动态存储分配 六、使用指针和动态存储分配的程序举例
C语言程序设计 double c[M][N]={{0}}; //数组c的M*N*8个字节的存储空间是静态分配的 (2)变量的动态存储分配方式 变量的动态存储分配需要调用在系统头文件stdlib.h中声明的动态存储分配函数来实现,这些函数为malloc()、calloc()和realloc()三种。 2. 动态存储分配函数的原型格式和功能 (1)malloc()函数原型格式 void * malloc(unsigned int k); 功能:调用它时能够分配k个字节的存储空间,并把第1个字节的地址返回,该返回值具有void*类型,可以赋给任一具体类型的指针变量。 第10讲 指针(2) 四、指针与数组 五、动态存储分配 六、使用指针和动态存储分配的程序举例
C语言程序设计 (2)calloc()函数原型格式 void * calloc(unsigned int n, unsigned int k); 功能:调用它时能够分配n*k个字节的存储空间,并把第1个字节的地址返回,该返回值具有void*类型,可以赋给任一具体类型的指针变量。通常用n表示数组长度,k表示元素类型的长度。 (3)realloc()函数原型格式 void * realloc(void* ptr, unsigned int k); 功能: 调用它时能够分配k个字节的存储空间,接着把ptr已经指向的动态分配的存储空间的内容复制到新分配的存储空间中,最后把新分配的存储空间的第1个字节的地址返回。由于该返回值具有void*类型,所以能够赋给任一具体类型的指针变量,通常仍赋给ptr所对应的实参指针变量,使得通过该调用后增加或缩小动态存储空间。 第10讲 指针(2) 四、指针与数组 五、动态存储分配 六、使用指针和动态存储分配的程序举例
C语言程序设计 3. 动态存储分配的调用格式举例 (1)int *px=malloc(sizeof(int)); //分配一个整数存储空间由指针变量px所指向,此动态分配的变量为*px,可用它保存一个整数,如:*px=25; *px+=30; //其值为55 (2)double *pa=calloc(10,sizeof(double)); //分配一个具有10个双精度元素的一维数组空间,由指针变量pa所指向,pa也就是该动态数组的数组名(但有区别,它是变量不是常量) //通过它可以访问该数组中的任何元素。如:*pa=12; 把12赋给 // pa[0]元素;又如:pa[i]<pa[j]进行两元素大小的比较 第10讲 指针(2) 四、指针与数组 五、动态存储分配 六、使用指针和动态存储分配的程序举例
C语言程序设计 (3)pa=realloc(pa,20*sizeof(double)); //增加pa指针所指向的存储空间的大小,由10个双精度元素变为 //20个双精度元素,同时原有的存储内容被复制过来。 (4)int **top=calloc(M+1,sizeof(int*)); //top动态数组含有M+1个元素,每个元素能够存储一个整数的地址。 4. 动态存储分配的优点 允许在程序运行过程中随时确定待使用的存储空间的大小,不必像静态分配那样需要事先确定。 一般定义一个数组时,必须确切给出数组的每一维的尺寸,如: int a[10], b[M][N]; //M和N必须是已经定义的符号常量 第10讲 指针(2) 四、指针与数组 五、动态存储分配 六、使用指针和动态存储分配的程序举例
C语言程序设计 动态分配定义一个数组时,所分配的存储空间的大小可以是常量,也可以是变量。如: (1)int *a=calloc(10,4); //两个参数都为常量 (2)int *a=calloc(x,4); //第1个参数为变量,分配x个整数元素的空间 (3)char *b=malloc(n1+n2); //n1和n2为变量,分配n1+n2个字节的空间 (4)char *c=malloc(sizeof(d)); //根据另一个对象d的大小分配空间 5. 动态存储空间的释放 释放动态存储空间的free()函数的原型格式 void free(void* ptr); 功能:调用它时能够把指针变量ptr所指向的动态存储空间释放掉,即归还给操作系统。 第10讲 指针(2) 四、指针与数组 五、动态存储分配 六、使用指针和动态存储分配的程序举例
C语言程序设计 free()函数原型声明也包含在stdlib.h系统头文件中。 当动态存储空间保存的内容不再使用时,可调用该free()函数及时释放掉,若没有调用它,则一直到程序运行结束时该动态存储空间才被自动释放给操作系统。 对于一般静态分配的变量,其占有的存储空间只能由C语言系统在运行时自动释放,其时机为所在的模块(复合语句)刚执行完毕。 下面看一个程序例子 #include<stdio.h> //支持调用标准输入和输出操作的函数 #include<stdlib.h> //支持调用动态存储分配和释放函数 void main() { int *a=calloc(10,sizeof(int)); //动态分配得到a[10]数组, //为40字节的存储空间,同时静态分配得到a指针变量,4字节 第10讲 指针(2) 四、指针与数组 五、动态存储分配 六、使用指针和动态存储分配的程序举例
C语言程序设计 int i; //静态分配得到i整数变量,4字节 for(i=0; i<10; i++) a[i]=i*i; //给a数组中每个元素赋值 for(i=0; i<10; i++) printf("%d ",a[i]); //输出a中每个元素值 printf("\n"); //输出一个换行符 free(a); //a[10]数组的40个字节的动态存储空间被交还给操作系统 } //此主函数执行结束时,自动把a和i各占有的4字节交还给操作系统 程序运行结果: 0 1 4 9 16 25 36 49 64 81 第10讲 指针(2) 四、指针与数组 五、动态存储分配 六、使用指针和动态存储分配的程序举例
C语言程序设计 六、使用指针和动态存储分配的程序举例 例1:以指针方式访问数组元素的例子 #include<stdio.h> #include<stdlib.h> void main() { int a[5]={3,6,9,12,15}; int *p=a; //把数组a的首地址赋给指针变量p int i; for(i=0;i<5;i++) printf("%5d",*p++); //指针方式访问数组a printf("\n"); //换行 for(p=a+4; p>=a; p--) printf("%5d",*p); //从后向前访问数组元素 printf("\n"); //换行 } 第10讲 指针(2) 四、指针与数组 五、动态存储分配 六、使用指针和动态存储分配的程序举例
C语言程序设计 输出结果: 3691215 1512963 例2:进行简单变量动态存储分配的例子 #include<stdio.h> #include<stdlib.h> void main() { int x=23,y=40,z; int *p1=malloc(sizeof(int));//为*p1动态分配4字节存储空间 int *p2=malloc(sizeof(int));//为*p2动态分配4字节存储空间 第10讲 指针(2) 四、指针与数组 五、动态存储分配 六、使用指针和动态存储分配的程序举例
C语言程序设计 *p1=x; *p2=y;//分别把x值23和y值40赋给动态变量*p1和*p2 printf("%d %d\n",*p1,*p2);//输出*p1和*p2的值为23 40 z=*p1; *p1=*p2; *p2=z;//交换*p1和*p2所保存的值 printf("%d %d\n",*p1,*p2);//输出*p1和*p2的值为40 23 free(p1); free(p2);//释放p1和p2各自所指向的动态存储空间 } 程序运行结果: 23 40 40 23 例3:动态存储分配任意大小的一维数组的例子 #include<stdio.h> #include<stdlib.h> void main() 第10讲 指针(2) 四、指针与数组 五、动态存储分配 六、使用指针和动态存储分配的程序举例
C语言程序设计 int *a,i,sum,n; printf("从键盘给n输入一个正整数(1-10): "); while(1) { scanf("%d",&n); //输入1-10之间的数到n中 if(n>=1 && n<=10) break; else printf("重输: "); } a=calloc(n,sizeof(int)); //动态分配a[n]数组空间,n是变量 a[0]=0; a[1]=1; //给a数组的前2个元素赋值 for(i=2; i<n; i++) a[i]=a[i-1]+a[i-2]; //从元素a[2]起,每个元素值等于前2个元素值之和 //0+1=1, 1+1=2, 1+2=3, 2+3=5,… for(i=0; i<n; i++) { sum+=a[i]; //计算出n个元素之和 printf("%5d",a[i]); //依次输出每个元素值 } 第10讲 指针(2) 四、指针与数组 五、动态存储分配 六、使用指针和动态存储分配的程序举例
C语言程序设计 printf("\n sum=%5d\n", sum);//输出sum的提示信息和值 free(a); } 程序运行结果: 从键盘给n输入一个正整数(1-10): 12 重输: 8 011235813 sum = 33 例4: 动态存储分配二维数组的例子。 #include<stdio.h> #include<stdlib.h> void main() { int i,j; int row,col; 第10讲 指针(2) 四、指针与数组 五、动态存储分配 六、使用指针和动态存储分配的程序举例
C语言程序设计 int** ab;//定义2阶整型指针变量ab,用它指向int*类型的数据 printf("输入一个二维表格数据的行数和列数: "); scanf("%d %d", &row, &col);//输入行、列数到row和col中 ab=calloc(row, sizeof(int*));//得到动态分配的一维指针数组ab[row] for (i=0; i<row; i++)//依次使ab[i]指向包含col个元素的一维数组 ab[i]=calloc(col, sizeof(int)); printf("输入%d行*%d列的二维表格数据:\n", row, col); for (i=0; i<row; i++)//输入数据进入二维数组ab[row][col]中 for (j=0; j<col; j++) scanf("%d",&ab[i][j]);//等价表示: *(ab[i]+j) 第10讲 指针(2) 四、指针与数组 五、动态存储分配 六、使用指针和动态存储分配的程序举例
C语言程序设计 printf("\n"); printf("输出二维表格数据: \n"); for (i=0; i<row; i++) {//按row行和col列输出数据 for (j=0; j<col; j++) printf("%5d",ab[i][j]); printf("\n"); } for (i=0; i<row; i++) free(ab[i]);//释放每个一维数组空间 free(ab);//释放ab所指向的一维数组空间 } 总结:第9、10讲 指针: 指针的概念、变量、运算、指针与数组、动态存储分配 这一讲就到这里,同学们再见! 第10讲 指针(2) 四、指针与数组 五、动态存储分配 六、使用指针和动态存储分配的程序举例