9.3 数组与指针
一个数组包含若干个元素(变量),在定义时被分配了一段连续的内存单元。因此,可以用一个指针变量来指向数组的首地址,通过该首地址就可以依次找到其他数组元素,同样指针变量也可以指向数组中的某一个元素。所谓数组的指针是指数组的起始地址,数组元素的指针是各个数组元素的地址。
考点3 移动指针
真考链接
针对考点3 的考查出现在选择题的读程序题,要求考生写出相应的运行结果。考点3 属重点理解重点掌握的内容,难度偏大,其在选择题中的考核概率为30%,在操作题中的考核概率为10%。
移动指针是指当指针变量指向一串连续的存储单元时,对指针变量进行加减运算,或通过赋值运算,使指针变量指向相邻的存储单元。
假定内存中有10个连续的int类型的存储单元,分别用a[0],a[1],…, a[9]表示。此时定义了int类型的指针变量p指向存储单元a[0],则可以通过移动指针变量p来访问a[0]到a[9]的存储单元。例如,p+1指向a[1]存储单元,则*(p+1)为a[1]的值。p+5指向a[5]存储单元,则*(p+5)为a[5]的值。同时可以通过指针变量p来改变其中存储单元的值。例如,经过操作*(p +7)=10后,a[7]存储单元的值被改写为10。
真题精选
【例1】以下选项中,对基类型相同的指针变量不能进行运算的运算符是( )。
A.+ B.- C.-- D.++
【答案】A
【解析】在C语言中,当指针变量指向某一连续存储单元时,可以对该指针变量进行++、--运算或加、减某个整数的算术运算,达到移动指针的目的。此外,当两个基类型相同的指针变量都指向某一连续存储区中的存储单元时,如指向同一组中的两个元素,则这两个指针可以相减,得到的差值(取绝对值)表示两个指针之间的元素个数。
【例2】请补充函数fun(),该函数的功能是:按“0”~“9”统计一个字符串中的奇数数字字符各自出现的次数,结果保存在数组num中。
注意1:不能使用字符串库函数。
例如,输入“x=112385713.456+0.909*bc”,结果为:1=3,3=2,5=2,7=1,9=2。
注意2:部分源程序给出如下。请勿改动main()函数和其他函数中的任何内容,仅在函数fun()的标号处填入所编写的若干表达式或语句。
试题程序
#include <stdlib.h>
#include <stdio.h>
#define N 1000
void fun(char *tt,int num[ ])
{ int i,j;
int bb[10];
char *p=tt;
for(i=0;i<10;i++)
{ num[i] =0;
bb[i] =0;
}
while(【1】)
{ if(*p> = '0'&&*p< = '9')
【2】;
p++;
}for(i=1,j=0;i<10;i=i+2,j++)
【3】;
}
void main()
{ char str[N];
int num[10],k;
printf(" \nPlease enter a char string:");
gets(str);
printf("\n**The original string**\n");
puts(str);
fun(str,num);
printf("\n**The number of letter**\n");
for(k=0;k<5;k++)
{ printf("\n");
printf("% d=% d",2*k+1,num[k]);
}
printf("\n");
}
【答案】【1】*p 【2】 bb[*p-'0 '] ++【3】 num[j] =bb[i]
【解析】标号【1】:通过移动指针p来指向字符串tt中的各个字符,当指针p所指的字符为'\0'时,即指向字符串tt的最后一个字符,while循环结束。
标号【2】:将字符串中的数字字符'0 '~'9 '的个数都保存在数组bb[10]中。*p-'0 '实现将数字字符转换成对应的数字。
标号【3】:由于奇数数字字符的个数存于bb[1]、bb[3]、bb[5]、bb[7]、bb[9]中,所以for循环的目的是将这些元素分别赋给num[0]、num[1]、num[2]、num[3]、num[4]。
考点4 指向数组元素的指针以及通过指针引用数组元素
真考链接
考点4 属于重点理解掌握知识点,其在选择题中是必考内容。在操作题中,针对考点4的考查以修改题和编程题出现,考核概率为20%。涉及字符或数组的处理时,应该首先想到采用指针处理。因为用指针处理这类问题简洁方便。
1.指向数组元素的指针
C语言规定数组名代表数组的首地址,也就是数组中第0号元素的地址。有以下语句:
int c[10]={0};
int*p;
p=c;
则语句p=c;与语句p=&c[0];是等价的。
定义指向数组元素的指针变量的方法,与定义指向变量的指针变量相同。例如:
int c[10],*p;
p=&c[5];
指针变量p指向了数组c中下标为5的那个元素,即p用来保存c[5]的地址。
2.通过指针引用数组元素
按C语言的规定:如果指针变量p已指向数组中的一个元素,则p+1指向同一数组中的下一个元素(而不是将p的值简单加1),这里的加1是指增加一个长度单位(与数组基类型所占存储单元相同)。例如,数组元素是浮点型,每个元素占4个字节,则p+1意味着使p的值(是一个地址)加4个字节,以使它指向下一个元素。
小提示
定义一个指针指向数组,只需将数组第一个元素的地址赋给指针变量即可,而不是将数组名赋给指针变量。
数组c不代表整个数组。上述“p=c;”的作用是把数组c的首地址赋值给指针变量p,而不是把数组c中各元素的值赋给p。
将++和--运算符用于指针变量是十分有效的,可以使用指针变量自动向前或向后移动,指向下一个或上一个数组元素。不过要小心使用,否则会导致内存错误。
真题精选
【例1】若有定义语句:doublex[5] ={1.0,2.0,3.0,4.0,5.0},*p =x,则错误引用x数组元素的是( )。
A.*p B.x[5] C.*(p+1) D.*x
【答案】B
【解析】x[5]说明数组x有5个元素。下标范围为0~4,选项B中x[5]超过了下标范围,故引用错误。
【例2】由N个有序整数组成的数列已放在一维数组中,下列给定程序中函数fun()的功能是:利用折半查找法查找整数m在数组中的位置。若找到,返回其下标值;否则,返回-1。
折半查找的基本算法是:每次查找前先确定数组中待查的范围low和high(low<high),然后用m与中间位置(mid)上元素的值进行比较。如果m的值大于中间位置元素的值,则下一次的查找范围落在中间位置之后的元素中;反之,下一次的查找范围落在中间位置之前的元素中,直到low≥high,查找结束。
请改正程序中的错误,使它能得出正确的结果。
注意:不要改动main()函数,不得增行或删行,也不得更改程序的结构。
试题程序
#include <stdio.h>
#define N 10
/*****found*****/
void fun(int a[],int m)
{ int low=0,high=N-1,mid;
while(low< =high)
{ mid=(low+high)/2;
if(m<a[mid] )
high=mid-1;
/*****found*****/
else If(m > a[mid])
low=mid+1;
else return(mid);
}
return(-1);
}
main()
{ int i,a[N]={-3,4,7,9,13,45,67,89,100,180},k,m;
printf("a数组中的数据如下:");
for(i =0;i <N;i ++)printf("% d ",a [i]);
printf("Enter m:");scanf("% d",&m);
k=fun(a,m);
if(k> =0)printf("m=% d,index=% d\n", m,k);
else printf("Not be found!\n");
}
【答案】(1)intfun(inta[],intm)或fun(inta[],intm)
(2)elseif(m>a[mid])【解析】本题考查:折半查找算法;函数定义;if...else语句。
(1)fun(inta[],intm)函数的返回值为int类型,所以定义函数时,函数的返回类型不能是void,而是int类型。
这里int可以省略,若省略函数类型标识符,系统将默认为int型。
(2)elseIf(m>a[mid])中,关键字if需要区分大小写,大写是错误的。
考点5 用数组名作为函数参数
真考链接
难度适中,属于重点掌握知识点,在选择题中的考核概率为30%。
数组名可以用作函数的形参和实参。当数组名作为参数被传递时,若形参数组中各元素发生了变化,则原实参数组各元素的值也随之变化。因为数组名作为实参时,在调用函数时是把数组的首地址传送给形参,因此实参数组与形参数组共占一段内存单元。而如果用数组元素作为实参的情况就与用变量作为实参时一样,是“值传递”方式,单向传递,即使形参数组元素值发生了变化,原实参的数组元素值也不会受到影响。
再来看一下用变量名作为函数参数和用数组名作为函数参数做比较的情况,见表9.1。
表9.1 函数参数与数组名参数的比较
常见问题
对数组元素的访问,采用下标方式和指针方式有何异同?
采用下标方式和指针方式是等价的,但从C语言系统内部处理机制上讲,指针方式效率更高。需要注意的是,指针方式不如下标方式直观。下标方式可以直截了当地看出要访问的是数组中的哪个元素;而对于指向数组的指针变量,进行运算以后,指针变量的值改变了,其当前指向的是哪一个数组元素不再一目了然。
真题精选
下述程序在数组中同时查找最大元素下标和最小元素下标,分别存放在main()函数的变量max和min中,请填空。
试题程序
#include <stdio.h>
void find(int *a,int n,int *max,int *
min)
{ int i;
*max=*min=0;
for(i=1;i<n;i++)
if(a[i] >a[*max])
______;
else
if(a[i] <a[*min] )
______;
}
main()
{ int a[ ] ={5,8,7,6,2,7,3};
int max,min;
find(______);
printf("\n% d,% d",max,min);
}
【答案】*max=i *min=i a,7,&max,&min或&a[0],7,&max,&min
【解析】初始时,函数find()中的指针变量max和min指向的单元都存放下标0,表示a[0]是临时的最大值和最小值。需要更新时,*max=i,*min=i,因为*max和*min才代表下标变量。函数调用时,传递数组实际地址、数组长度及存放最大、最小下标值的地址。说明:此典型的简单算法经常出现在考试题目中,为此,应该熟悉一些离散数据处理的算法,如排序、查找等。这些程序一般不能脱离循环结构,经常在函数之间传递数组或指针。