📄 ex6.cpp
字号:
///第6章指针与数组
// [例6.1]指针作为函数的形参,指针形参可改变其指向的实参变量。
#include <stdio.h> //注意&符号在不同位置的作用
typedef long type,*ptype; //声明type是long的别名, ptype是long*的别名
void f(type* x,ptype y){*x+=1;*y+=2;} //x,y是long*型的指针形参
void main() //f函数对间接变量*x,*y 分别执行加1和加2的运算
{ long a=1,*pa=&a; // 定义a为long型变量, pa为long*型指针,指向a。
type b=2,&rb=b; //定义b为long型变量,声明rb为b的引用
long*& qa=pa; //声明引用qa为指针pa的别名
ptype pb(&b),&qb=pb; //定义指针pb初始化&b, 声明引用qb为指针pb的别名
printf("%d,%d\t",*pa,*pb); //*pa,*pb分别是a,b的间接变量
f(pa,qb); //函数调用f(pa,qb);相当于*pa+=1; *pb+=2;
*qa+=1; rb+=2; f(&a,&b); //虚实结合导致x=&a,y=&b
printf("%d,%d\t",a,b); //对引用rb,qa,qb的操作是对相关左值b,pa,pb的等价操作
} //输出:1,2 4,8
// [例6.2]指针自增运算访问数组元素
# include<stdio.h> //if(e) s;格式中的条件表达式e首先完成求值计算和副作用
void main(void) //本例题中if所属的语句为空语句,if(e) ; 相当于e;
{ int a[ ]={1,2,3,4}; // if(r=p++);相当于 r=p++;等,基本上不用if(e) ;格式
int y, z,*r, *p=a;
if(r=p++); /*r=&a[0], p=&a[1]*/ printf("r=%p,a=%p,p=%p\n",r,a,p);
y=*p++; /*y=a[1], p=&a[2]*/ printf("a[0]=%d,a[1]=%d,%p\t",*r,y,p);
if(z=(*p)++); /*z=a[2], a[2]+=1;*/ printf("a[2]=%d,a[2]=%d,%p\t",z,a[2],p);
*p++=*r++; /*a[2]=a[1];p=&a[3]*/ printf("a[2]=%d,a[3]=%d,%p\n",a[2],*p,p);
}
// [例6.3]数组形参的大小形同虚设,p是指针变量,而a表示数组首元素的右值地址
#include<stdio.h>
void f(double p[8]){ printf("sizeof(p)=%d;",sizeof(p)); p++; }
void main (void) //输出:sizeof(p)=4; sizeof(a)=64
{ double a[8]; f(a); printf("sizeof(a)=%d\n",sizeof(a)); }
// [例6.4] 求内存空间连续n个元素的和
#include<stdio.h>
long sum(long x[],int n);//函数原型为一维数组形参,n动态界定寻址内存空间的大小
long sum(long [8],int);//函数原型中的8不起作用
void main() // sum(a,n) 求区间{1,2,3,4}的和10
{ long a[]={1,2,3,4}; // sum(q,n-1)求区间{2,3,4}的和9
const int n=sizeof(a)/ sizeof(*a); // sum(&a[2],n-2) 求区间{3,4}的和7
long *q=&a[1]; //函数调用sum(a,n+1),sum(q,n)导致越界
printf("[%d%,%d,%d]\n", sum(a,n),sum(q,n-1),sum(&a[2],n-2));
} //输出:[10,9,7]
long sum(long *p,int n) //函数定义为一级指针形参
{ long s=0 ; //p++指向long型数组的下一个元素
for(int i=0;i<n;p++,i++) s+=*p;//*p得到该位置元素的值
return s; //s+=*p累积地加上这个元素
} //sum返回以入口指针定位的其后n个元素的和
// [例6.5]将数组 反序排放为存放
#include<stdio.h>
void swap(long s[],int n,int i) { long t=s[i];s[i]=s[n-1-i];s[n-1-i]=t;}//s为数组形参
void inverse(long p[],long *e) //p为数组形参,e为指针形参。
{ for(; p<e;p++,--e ) //访问指针形式将数组逆序存放,p<e是指针的关系比较
{ long t=*p;*p=*e;*e=t;} //循环体swap(p,e)依次交换间接变量的值
} //标题头void inverse(long p[],long *e)可以等价写为void inverse(long *p,long e[])
void main() //数组形参与指针形参是等价的
{ long s[]={1,2,3,4,5,6,7,8,9};
const int n=sizeof(s)/sizeof(s[0]);
int i ;for( i=0;i< n/2;i++) //下标寻址方式将数组逆序存放
swap(s, n,i); // swap(s, n,i);相当于{ long t=s[i];s[i]=s[n-1-i];s[n-1-i]=t;}
for( i=0;i<n;i++) printf("%d,",s[i]); //下标法显示数组元素的值
inverse(s,&s[n-1]);//在调用点inverse函数形参p,e获得初始值p=&s[0],e=s+n-1。
long *p=&s[0];
for(i=0;i<n;i++,p++) printf("%d;",*p); //访问指针形式显示数组元素的值
} //输出结果:9,8,7,6,5,4,3,2,1,1;2;3;4;5;6;7;8;9;
//[例6.6]固定指针和只读指针(固定指针和只读指针都可指向普通(非只读)的数组)
void intcpy(int *p,const int*q,int n) //只读指针形参q表示*q在函数体中为右值。
{ for(int k=0;k<n; p++,q++,k++) *p=*q; }//左边的函数体与下面程序块等价
# include<iostream.h> // { int k=0; while(k<n){*p=*q; p++;q++;k++; } }
const int c[5]={1,2,3,4,5}; //定义只读全局数组,每一个数组元素c[k]为右值
void main(void) // c+1,&c[0]等是const int*型的表达式
{ int a[10]; //a+1,&a[0]等是int*型的表达式
int * const s=a; //定义固定指针s,初始化为数组名a
const int *r=c; //定义只读指针r,初始化指向只读数组
int k=0;
for (;k<5;k++,r++) //循环将数组c的5个元素拷贝给数组a的相应元素
s[k]=*r; // r++表示只读指针r向后遍历,*r表示读取当前所指位置的内容
intcpy(a+5,a,5); //将数组a的前5个元素分别拷贝到后5个元素
for (k=0;k<10;k++) cout<<"-"<<a[k];
} //输出结果: -1-2-3-4-5-1-2-3-4-5
//[例6.7]指针的强制类型转换攻击只读数据区 // swap函数实现指针的固定寻址
#include <stdio.h> //固定指针形参s交换数组相邻元素的值
void swap(int*const s){int t=*s;*s=s[1];s[1]=t;}//s本身不变,间接变量变动
void main() /* int*型的实参可匹配int*const型的形参,反之亦然*/
{ const int a[2]={1,2}; printf("%d,%d;",a[0],*(a+1));
int* p=(int*)(a+1); // const int*型地址a+1强制地映射给int*型指针p
printf("%d,%d-",p[-1]=3,*p=4);// p[-1]=3相当于a[0]=3
swap((int*)&a[0]); //(int*)&a[0]表示cons int*型的地址&a[0]转换int*型的地址
printf("%d,%d",*a,a[1]); //输出:1,2;3,4-4,3
} /*本质上int*型的右值地址严格地具有int*const型属性*/
//[例6.8] 从二维数组中查找第一个出现的负数
# include<iostream.h>
void main()
{ const int n=3,m=2;
int d[n][m];//定义二维数组
cout<<"input "<<n*m<<" integers:";
int j; int i;
for(i=0;i<n;i++) for(j=0;j<m;j++) cin>>d[i][j];
for(i=0;i<n;i++)
for(j=0;j<m;j++) /*if(d[i][j]<0) 等价于if(*(*(d+i)+j)<0) */
if(*(*(d+i)+j)<0) goto found;
cout<<"not found!"<<endl; goto end;
found:cout<<"d["<<i<<"]["<<j<<"]="<< d[i][j]<<endl;
end:;
}
// [例6.9]同一个地址对应不同类型的地址属性
#include <stdio.h>
void main()
{ int b[3][2][2]; //int (*p)[2][2]=b;int (*q)[2]=b[0];int * r=b[0][0];
printf("%p,%p,%p\t",b,b[0],b[0][0]);
} //输出:0066FDC8, 0066FDC8, 0066FDC8
//[例6.10]指向二维数组的指针与二维数组
# include<iostream.h>
void f(float (*q)[4],int m) //q是float (*)[4]型数组指针形参
{ for (int k=0;k<m;k++) // q[k] 是float*的右值地址
{ float* p=q[k]; //定义指针p,初始化为p=q[k]
for( int j=0;j<4;j++) //通过指针简化了重复的寻址计算
cout<<p[j]<<"," ; // p[j]= q[k][j]
} //标题头 void f(float (*q)[4],int m) 可以等价地改为void f(float q[][4],int m)
} // float q[][4]为二维数组形参,它等价于数组指针形参float (*q)[4]
void main(void) //函数调用f(d,M+1), f(d+1,M)导致越界
{ float d[ ][4]={0,1,2,3,4,5,6,7}; //定义浮点型二维数组d[2][4]
int const M=sizeof(d)/sizeof(*d); //d,d+1具有类型属性float (*)[4]
f(d,M); //实参d 初始化指针形参q,f(d,M)访问内存区间{0,1,2,3,4,5,6,7}
f(d+1,M-1);// d+1初始化指针形参q,f(d+1,M-1)访问内存区间{4,5,6,7}
} //输出:0,1,2,3,4,5,6,7, 4,5,6,7,
// [例6.11]数组指针形参或二维数组形参实现求数组空间的和
#include<stdio.h>
double sum(double q[][3],int n); //函数原型为二维数组形参
void main(void)
{ double b[2][3]={1,2,3,4,5,6}; // sum(b+1,1)求区间{4,5,6}的和
printf("%2.0f,%2.0f\n",sum(b,2),sum(b+1,1)); //输出:21,15
double a[]={1,2,3,4,5,6,7}; //(QA)a是强制类型转换,匹配形参的类型
typedef double (*QA)[3]; //声明double (*)[3]型的别名QA
printf("%2.0f,%2.0f\n",sum((QA)a,2),sum((QA)(a+4),1)); //输出:21,18
} //sum((QA)a,2)求内存区间{1,2,3,4,5,6}之和;sum((QA)(a+4),1)求内存区间{5,6,7}之和
double sum(double (*q)[3],int n) // 函数定义为数组指针形参
{ double s=0 ;int i,j;double *p;
for( i=0;i<n;i++,q++) //q++指向内存空间的下一行,即前移3*8=24个字节。
for(j=0,p=*q;j< 3;j++,p++) // p=*q得到该当前行的首地址,*q的值等于q的值。
s+=*p; //p++指向double型数组的下一个元素
return s; //*p得到该位置元素的值
}//sum函数与sum1函数完成相同的功能,但sum的效率高,sum1简洁。
double sum1(double (*q)[3],int n) // 函数定义为数组指针形参
{ double s=0 ; //下标法求数组的和
for(int i=0;i<n;i++) for(int j=0;j<3;j++) s+=q[i][j];
return s;
}
//[例6.12] typedef简化数组定义
# include <iostream.h>
const int L=2,M=2,N=2;//声明全局性的整型常数L,M,N
typedef int ALMN[L][M][N]; typedef int (*PMN)[M][N]; typedef int (*PN)[N];
void main(void)
{ int j, k;
ALMN v= {1, 2,3, 4,5,6,7,8}; //定义三维数组v[L][M][N]同时初始化
PMN d=v; // 相当于 int (*d)[M][N]=v;
PN a= v[1]; //相当于int (*a)[N]=v[1];
for (j=0;j<M;j++) for (k=0;k<N; k++) cout<<d[1][j][k]<<"," ;
for (j=0;j<M;j++) for(k = 0; k <N; k++) cout<<a[j][k]<<";" ;
} ///输出结果: 5 ,6 ,7 ,8, 5 ;6 ;7 ;8;
//[例6.13] 指针数组的元素指向维数大小不同的一维数组
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -