先来看这样一个例子,这里出现了指针来引用数组的操作
//输入十个数,从大到小输出 #includevoid sort(int x[],int n); int main(void){ int i,*p,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++; } printf("n"); return 0; } void sort(int x[],int n){ int t;//空变量 for(int i=0;i 我们知道,数组里面每一个元素都有自己的地址,利用指针,可以很快地实现数组元素的引用
上面的例子中是一个较为简单的一维数组,先让p=a,(p=&a)要引用下一个元素,只需p++,这样相当于地址加一,自然可以取到下一个元素的地址,好,那么我们再看一下这种表达式
#includeint main(void) { int a[] = { 1,2,3,4 }; printf("%d", *a); return 0; } //*a=*&a 很明显,这里的数组名前加了*,因为数组名代表第一个元素的地址 ,所以加*,变打出了第一个元素的值,即*a=*&a
再来看下面的表达式
t=*(x+j);*(x+j)=*(x+j+1);*(x+j+1)=t;这里与例子中表达式的作用一样,可以看到x[j]=*(x+j),数组中第j个元素可以用指针来表示,可以这么理解,x是数组的首地址,为0,假如j=3,x[2]是数组中第三个元素的值,(x+2)是第三个元素的地址,再加"*"取值,两式相等。
上面我们简单看了一下一个一维数组的指针应用,好,接下来看一下多维数组
int a[][4]={{1,3,5,7},{9,11,13,15},{17,19,21,23}};定义了一个三行四列的二维数组
二维数组里每一个元素的地址怎么用指针表示?
举例:找5,第一行第三个
#includeint main(void) { int a[][4] = { {1,3,5,7},{9,11,13,15},{17,19,21,23} }; printf("%d",*(*(a+0)+2 ));//a[0][2] *(a[0]+2 ) return 0; } 可以看到*(*(a+0)+2)=*(a[0]+2)=a[0][2]
a[0][2]不必过多解释,就是数组的一般方法
*(a[0]+2) a[0]是第一行的首地址,+2就是列变化,往右移动2个地址,也就是第三个元素的地址
*(*(a+0)+2) 先看*(a+0),是a第一行的首地址+0,行变换+0,也就是第一行的首地址,再+2,就是第一行第三个元素的首地址
printf("%d", *(*(a + 1)+2));像这样输出的结果是13,因为*(a+1)是行+1,也就是第二行的首地址
我们可以得出这样一个标准形式:*(*(a+i)+j) 这里面,+i就是在做行变化,+j就是在做列变化,可以这样来找到二维数组中每一个元素的地址
如果不便理解,这里有转换记忆的公式:
*(*(a+i)+j) ==*(*&a[i]+j)==*(a[i]+j)==*&a[i][j]==a[i][j]
好,大家思考一下下面这些表达式的输出结果是什么
#includeint main(void) { int a[][4] = { {1,3,5,7},{9,11,13,15},{17,19,21,23} }; printf("%d,%dn", a,*a ); printf("%d,%dn", a[0], *(a+0)); printf("%d,%dn", &a[0], &a[0][0]); printf("%d,%dn", a[1], a+1); printf("%d,%dn", &a[1][0], *(a+1)+0); printf("%d,%dn", a[2], *(a+2)); printf("%d,%dn", &a[2], a+2); printf("%d,%dn", a[1][0], *(*(a+1)+0)); printf("%d,%dn", *a[2], *(*(a+2)+0)); return 0; } 答案:
我们逐一分析:(首先明确a在定义时是这样的:a[][4])
1.a是数组的首地址,打出的是地址,是随机值,*a可不是取首地址中的值,*a就是a首地址的值,所以输出结果也是随机值
2.a[0]是地址 *a[0]才是地址中的值,*(a+0)=*a,同上
3.&a[0]也是地址,&a[0][0],a[0][0]是正确的写法,可是前面加个&相当于再次取了地址
4.a+1很明显是地址的加减,即a[0]+1=&a[0][1]
5-7.道理同上
8.前文标准方法
9.*a[2]=*(a[2]+0),即第三行首地址中的值
我们一定要熟知这些表达式所代表的意义,不然在之后看代码,打代码的操作中吃亏,考试也考不好(别问我怎么知道的)
好,接下来小试牛刀
通过指针引用多维数组示例一:
#includeint main(void) { int a[][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);//4是宽度,要求对齐 } return 0; } 结果:
上面利用一个指针输出了数组的全部元素,要是要准确输出某一行某一列的元素,我们要利用数组指针,看这个例子:
#includeint main(void) { int a[][4] = { {1,3,5,7},{9,11,13,15},{17,19,21,23} }; int (*p)[4],i,j;//定义数组指针(*p)[4] p = a; scanf("%d%d", &i, &j); printf("%d", *(*(p + i) + j)); return 0; } p是一个指向有四个整型元素的数组的指针,很多初学者(我)搞不清什么指针,数组指针,指针数组,别急,试一试,想一想
下面是一个错误的代码
#includeint main(void) { int a[][4] = { {1,3,5,7},{9,11,13,15},{17,19,21,23} }; int *p,i,j; p = a; scanf("%d%d", &i, &j); printf("%d", *(*(p + i) + j)); return 0; } 报错显示
仔细想一想,指针,数组之间的关系,数组名是一个指针,上面的代码完全可以这样:
#includeint main(void) { int a[][4] = { {1,3,5,7},{9,11,13,15},{17,19,21,23} }; int i,j; scanf("%d%d", &i, &j); printf("%d", *(*(a + i) + j)); return 0; } 而现在,要求用指针去引用,我只定义一个*p这样的指针,令p=a,这样,p相当于一个一维数组,用它来引用应该是这样的:
#includeint main(void) { int a[][4] = { {1,3,5,7},{9,11,13,15},{17,19,21,23} }; int i,*p; p = a; scanf("%d", &i); printf("%d", *(p+i)); return 0; } 如果我要找21这个数,我要输入10,才能输出21,这就达不到几行几列这样的要求,所以我们现在应该明白:数组指针对应的是二维数组
上面用的是数组指针,也就是(*p)[4],是个指针
下面用到指针数组,*p[4],是个数组
(上面(*p)[4],*p[4]的不同本质是优先级()>[ ]>*)
#includeint main(void) { int a[] = { 100,200,300 }; int i, *p[3];//定义指针数组*p[3] for (i = 0; i < 3; i++) p[i] = &a[i]; for (i = 0; i < 3; i++) printf("a[%d]=%dn", i, *p[i]); return 0; } 这算是一个最简单的指针数组的例子,初看这个代码,可能有人会问,这个定义的p什么玩意,不就是个数组吗,然后把数组a中的元素给了p,不对不对,指针数组中的每一个元素都是指针类型,这叫什么,不是一家人不进一家门,这一屋里全是指针类型的,于是p[i] = &a[i];就是把a中某元素的地址给了一个指针,哦,到这你就明白了,这不就是指针最原始的样子吗,把地址给它而已,然后,*p[i]就是把这个指针所指向地址里的元素的值打印出来。
再来看一个char类型的指针数组
#includeint main(void) { char* name[] = { "a","b","c","d" }; for (int i = 0; i < 4; i++) { printf("name[%d]=%sn", i, name[i]); } return 0; } 输出结果:
好,我们要注意,char类型,一个字符占一个字节,int 类型,一个占4字节,在这里i每次加一name[i]取的是每一个字符的首地址也就是说,我把a,b,c,d换成长一点的单词,打印出来的是那四个单词
接下来我们再看加入函数后的例子:
//这是三个同学的四科成绩,要求打印三个人所有成绩的平均值,并打印第三个学生的四科成绩 #includevoid average(float* p, int n);//声明函数 void search(float(*p)[4], int n); int main(void) { float score[][4] = { {65,66,70,60},{80,87,90,81},{90,99,100,98} }; average(*score, 12);//引用函数 search(score, 2); return 0; } void average(float* p, int n) { float* p_end; float sum = 0, aver; p_end = p + n - 1;//在main函数中n=12,一共十二项成绩,在main函数中p就是score,这里是首地址,因为本身就占了一项,所以要-1 for (; p <= p_end; p++) sum = sum + (*p);//把所有成绩加起来 aver = sum / n;//求平均值 printf("average=%5.2fn", aver);//保留两位小数 } void search(float(*p)[4], int n) { for (int i = 0; i < 4; i++)//打印这个学生的四科成绩 printf("%5.2f ", *(*(p + n) + i));//这里就是标准的引用方法,上文已经重点强调 printf("n"); } 打印结果:
好,这一章就讲到这里,如有疏漏,错误,还请指正,谢谢。



