1 对于变量x,其地址可以写成________;对于数组y[10],其首地址可以写成________或__________;对于数组元素y[3],其地址可以写成__________或_________。
【分析】变量的地址可以写成“&变量名”。数组的首地址就是数组名,也可以写成第 1个元素的地址“&数组名[0]”。数组元素的地址可以写成“&数组元素”,也可以写成“数组首地址十下标”。
【 答案】 &x
y
&y[0]
&y[3]
y+3
2 设有定义语句“int k,*p1=&k,*p2;”,能完成表达式“p2=&k”功能的表达式可以写成_______________。
【分析】注意原来表达式“p2=&k”的主要功能是将变量k的地址存放到指针变量p2中。现
在变量k的地址已经存放在指针变量pl中,所以完成“p2=&k”功能的表达式是:p2=p1.
【答案】p2=p1
3 设有两条语句“int a,*p=&a;”和“*p= a;”,则下列说法中正确的是()
①两条语句中的“*p”含义完全相同
②两条语句中的“*p=&a”和“*p=a”功能完全相同
③第 1条语句中的“*p=&a”是定义指针变量 p并对其初始化
④第2条语句中的“*p=a”是将a的值赋予变量p
【分析】分析备选答案①:第1条语句是数据定义语句,其中的“*p”表示定义的变量p是指针型变量;第2条语句是赋值语句,其中的“*p”代表它所指向的变量a,所以该备选答案是错误的,不符合题意。分析备选答案②:第 1条语句中的“*p= &a”是将变量 a的地址以初值方式赋予指针变量 p;而第 2条语句中的“*p=a”是将变量 a中的值赋予指针变量 P指向的变量(注意也是 a,即该语句的作用和 a= a完全相同),显然该备选答案是错误的,不符合题意。再分析备选答案③:显然该答案是正确的,符合题意。至于备选答案④,显然是错误的“*p”是代表指针变量p指向的变量,不能代表指针变量p。
【答案】③
4 设有定义语句“ int x,*p= &x;”,则下列表达式中错误的是()
①*&x ②&*x ③*&p ④&*p
【分析】注意“*”和“&”运算将是同一优先级别的,结合性是自有向左。接着来分报备选答案①:&x代表变量x的地址,*(&x)代表“&x”地址对应的变量,即变量X,一股说“*&变量”就是该变量,所以该答案是正确的,不符合题意。备选答案②中的“*x”是错误的,因为x是普通变量,不是指针型变量,而运算符“*”的运算对象必须是地址,所以该答案符合题意。显然备选答案③和④都是正确的。我们来分析一下。备选答案③的格式属于“*&变量”,所以其结果为指针型变量p,是正确的。备选答案④中的“*P”代表指针变量P指向的变量x,(*p)代表变量X的地址,也是正确的。一般说“&*指针变量”,则代表指针变量指向的变量的址。
【答案】 ②
5 设有定义语句“float s[10],*p1=s,*p2=s+5;”,下列表达式中错误的是()
① p1= 0xffff ② p2-- ③ p1-p2 ④ p1<=p2
【分析】当两个指针变量指向同一个数组时,每个针变量都可以进行增 l、减 1运算,两个指针变量之间可以进行减法运算和关系运算。显然备选答案②、③。④是正确的,不符合题意,只有备选答案①才是错误的,符合题意。对备选答案①的分析也很简单,因为C语言规定,所以的地址表达式中,不允许使用具体的整数来表示地址。
【答案】①
6 有下列定义语句“char s[]={"12345"},*p=s;”,下列表达式中错误的是()
①*(p+2) ②*(s+2) ③ p="ABC" ④ s="ABC"
【分析】分析备选答案①:指针变量p已经指向数组s首地址,则p+2代表数组元素s[2]的地址,*(p+2)就是代表数组元素s[2],所以是正确的,不符合题意。分析备选答案②:s是数组名,代表数组首地址,s+ 2代表数组元素 a[2]的地址,*(S+ 2)代表数组元素s[2],和备选答案①一样,也不符合题意。分析备选答案③:C语言规定,在程序中可以使用赋值运算符将字符串常量直接赋予字符型指针变量,所以该备选答案也是正确的,不符合题意。只有备选答案④是错误的,符合题意。原因是C语言规定,在程序中不允许将字符串常量以赋值语句方式直接赋予字符型数组。
【答案】④
7 设有语句“float x[4][10],*p=x;”,则下列表达式中不属于合法地址的表达式是()
①&x[1][2] ②*(p+1* 10+2)
③x[1] ④ p+1* 10+2
[分析]分析备选答案①:x[1][2]是合法的数组元素,所以“&x[1][2]”表示数组元素 x[l][2]的地址。分析备选答案②:由于指针变量指向二维数组首地址,“*(指针变量十行下标*列长度十列下标)”是表示数组元素“数组名[行下标][列下标]”的,不表示地址,所以该答案符合题意。至于备选答案③,x[l]代表数组 X中行下标为 1的所有元素组成的一维数组名,即该一维数组的首地址,所以是一个地址表达式。备选答案④中的表达式是代表数组元素x[1][2]的地址的,具体分析可以参看上面备选答案②中的分析。
【答案】②
8 设有定义语句“double d[3][5]= {{1},{2},{3}},(*p)[5]=d;”,则下列表达式中值不为0.0的表达式是()
①*&d[1][2] ②p[1][2]
③*(p+1*5+2) ④*(*(p+l)+2)
【分析】首先看看数组d中各元素的初值,显然d[0][0]的初值为1.0、d[l][0]的初值为2.0.
d[2][0]的初值为3.0,其余元素的初值均为0.0。接着分析备选答案①:*&d[1][2]就是d[l][2],所以其值为0.0,不符合题意。分析备选答案②:p[1][2]就是d[1][2],显然其值为 0.0,不符合题意。再分析备选答案③:该表达式运算后的结果相当于*(p+7),由于指针变量p是指向长度为5的一维数组的,所以,这个表达式代表地址,其值不是0.0,符合题意。显然备选答案④中表达式的值为0.0 ;因为该表达式相当于数组元素d[1][2]。
【答案】 ③
9 设有定义语句“char s[3][20],(*p)[20]=s;”,则下列语句中错误的是()
① scanf("%s", s[2]); ② gets(*(p+2));
③ scanf("%s",(p+2)+0); ④ gets(s[2][0]);
【分析】分析备选答案①、③,都是通过scanf()函数输入一个字符串,该函数中的第2个参数要求是地址。备选答案①中的S[2]是一个地址,表示输入的字符串存人字符数组s的第2行,所以是正确的。由于指针变量p是指向长度为20的一维数组,所以备选答案③中的*(p+2)+0相当于s[2][0] 的地址,也是正确的。备选答案②、④是通过gets()输入字符串的,该函数的参数也是地址。分析备选答案②中的*(p+2)字符数组s的第2行组成的一维数组的首地址,所以是正确的。备选答案④中的s[2][0]是数组元素,不是地址,所以是错误的。
【答案】 ④
10 设有下列程序段,该程序段输出的结果是
int k[2]={5,4},*P[2];
p[o]=k,p[l]=k+l;
prinif("%d",*p[1]);
【分析】从定义语句中可以看出,p是一个指针型数组,共有两个数组元素:p[0]和p[1]。两个赋值表达式组成的逗号表达式使得p[0]指向整型数组元素k[0],其值为5;p[1]指向整型元素 k[l],其值为4。输出语句中的输出表达式“*P[1]”是代表指针数组元素p[l]指向的整型数组元素k[1]的,其值为4。
【答案】 4
11 设有下列定义语句,则表达式“**p2”的值是_______________,表达式“*(*p2+l)”的值是_________________。
int x[3]={1,2,3},*p1= x,**p2=&p1;
【分析】从定义语句中可以看出,pl是指向整型数组 X首地址的一级指针变量,p2是指向一级指针变量pl的二级指针变量。从运算符“*”的结合性是自右向左的来看,表达式**p2相当于肝*(*p2),*p2相当于p1,所以**p2相当于*pl,由于一级指针变量p1指向的是数组X的首地址,即x[0]的地址,所以其值为x[0]的值,等于1。第2个表达式*(*p2+1)相当于*(p1+1),而pl+l相当于数组元素x[1]的地址,所以该表达式的值就是数组元素x[1]的值,等于2.
【答案】 1
2
12 设有下列程序,假定该程序运行后的输出是:234。请填写程序中缺少的语句成份。
main()
{ char *p="12345678";
while(____________)
{ printf("%c",*p+1);
p++;
}
}
【分析】从数据定义语句中看出,字符型指针变量指向字符串"12345678",即指针变量p指向
第1个字符'l'。由于程序所缺少的是控制循环的条件,假定第1次执行循环体时条件成立,输出的结果是"*p+1",即是指向字符'l'的,'1'+1的结果是字符'2',输出结果为2,与题目要求一致,然后执行p++,使p指向第2个字符'2'。显然第2次执行循环体输出结果为字符'3',符合题目要求。第3次执行循环体输出字符是'4',也符合题目要求。注意此时p已经指向字符串中的第4个字符'4',显然不能再执行循环体了,否则将输出字符'5'。可以看出,所缺少的控制循环条件是当p指向字符串中第4个字符'4'时必须退出循环。这个条件很容易写成“p指向的字符不是'4'”。具体来说,这个条件表达式可以写成“*p!='4'”,也可以写成“*p<'4'”或者“*p<='3'”等等。
【答案】*p='4'或者*p<'4'或者即*p<='3'
13 下列程序的功能是输入一个字符串存入字符数组a中,然后将其中的所有字符'\ DOWN'删除后再存入字符数组b,最后将字符数组b中的字符串输出。请填写程序中缺少的语句。
# include”string. h”
main()
{ char a[81],b[8l],*p1=a,*p2=b;
gets(p1);
while(*p1='\0')
if(*p1==‘\\')
___________________
else
*p2++=*p1++;
puts(b);
}
【分析】程序中的当型循环是完成删除数组a中存放的字符串中字符'\'的,分析控制这个循环的条件可知,这是依次处理存放在字符数组a中每个字符的标准程序段。循环体中是一条双分支语句,条件是当前字符(*p1)是否等于字符'\',如果不是'\'字符,则“将数组a中当前字符(*pl)复制到数组b的当前位置(*p2),然后再修改p1和p2两个指针变量(各加1,使其指向后一个字符的位置)。如果上述条件不成立(当前字符是‘\'),按照题目中给出的处理要求,这个字符不复制到数组 b中,显然不需要执行“*p2=*p1”,此外,指向数组b的指针变量p2也不需要加1,但是,指向数组a的指针变量p1需要加1,使其指向当前的'\'字符后面的字符,所以,这个地方缺少的语句应该是完成“p1加1”任务的,显然这个语句可以是“p1++”,或者“p1+=1”或者“p1=p1+1”。
【答案】p1++:或者 p1+=l;或者 p1=p1+1;
14 阅读下列程序,写出程序运行的输出结果。
main()
{ char a[20]={”1A2B3C”},b[20],*p1=a,*p2=b;
do{if (!((*p1>='O' &&*p1<='9'))
{*p2=*p1;
p2++;
*p2=*p1;
}
else
*p2=*p1;
p1++,p2++;
}
while(*p1='\0');
*p2=*p1;
printf(” % s\n”, b);
}
【分析】首先搞清楚数据定义语句中数组a和指针变量 p1和 p2的初值。程序的第 1条语句j 是do-while语句。控制该循环的条件是“*p1=‘\0'”,即当前指针变量 p1指向的字符不是字符串结束标记,则进行循环。考虑到循环体中有 p1++,显然这个循环是利用指针变量p1来依次处理存放在数组a中的字符串中每个字符的标准程序段。现在来看循环体,循环体中前一条语句是双分支语句,其控制条件“!(*p>='0'&&*pl<'9')”的含义是当前字符不是数字字符。当这个条件成立时,执行三条语句:第1条赋值语句是将p1指向的当前字符复制到p2指向的数组b中;第2条语句是修改指针变量p2(加1),使其指向后一个位置;第3条赋值语句和第1条赋值语句完全相同,即把p1指向的当前字符再次复制到p2指向的数组b的当前位置上。显然是将
p1指向的字符复制两次到p2指向的数组 b中。这个双分支语句的条件不成立时,执行“*p2=*p1”是将当前字符复制到数组b中,仅复制1次。循环体的第2条语句是逗号表达式构成的语句,其功能是修改pl和p2(加1),使其分别指向数组。和数组b的后一个位置。退出循环后执行的“*p2=*p1”是将数组a中当前字符('\0')复制到数组b中,即给数组b中增加一个字符串结束标记,以便组成字符串。最后一条语句是输出数组b中的字符串。
综合上述分析,可以得出关于程序功能的下列结论:将存放在数组a中的字符串复制到数组b中,复制的规则如下:当前字符是数字字符,则该字符仅复制l次;当前字符不是数字字符,则当前字符要复制两次。因此,很容易直接写出程序运行的输出结果。
【答案】1AA2BB3CC
15 阅读下列程序,写出程序运行的输出结果。
main()
{ int x[10]={1,7,4,3,5},*p,*q, i;
for(p=q=x,1=0;i<10;i++,p++)
if(*q<*p)q=p;
printf(”%d\n”,q-x);
}
【分析】首先分析数据定义语句中数组x各个元素的初值,依次为 1、7、4、3.5、0、…、0。下面用记录各个变量值的方式来获得最终输出结果,记录如下:
p指向x[0],q指向x[0],i=0,条件“i<10”满足,进入循环体
第 1次执行循环体:*q=1,*p=1,条件“*q<*p”不成立,不执行 q=p;执行 i++,i= 1;执行 p++,p指向x1],继续循环。
第2次执行循环体:*q=1,*p=7,条件“*q<*p”成立,执行q=P,q指向x[1],执行i++, i=2;执行p++,p指向x[2],继续循环。
第3次执行循环体:*q=7, *p= 4,条件“*q<*p”不成立,不执行 q=p;执行i++,i=3;执行p++,p指向x[3],继续循环。
第4次执行循环体:*q= 7,*p= 3,条件“*q<*p”不成立,不执行 q= p;执行 i++, i= 4;执行 p++,p指向x[4],继续循环。
第5次执行循环体:*q=7,*p=5,条件“*q<*p”不成立,不执行q=p;执行i++,i=5;执行p++,p指向x[5],继续循环。
第6次执行循环体:*q=7,*p=0,条件“*q<*p”不成立,不执行q=p;执行 i++,i= 6;执行 p++,p指向 x[6],继续循环。
第 7次执行循环体:*q=7,*p=0,条件“*q<*p”不成立,不执行 q=p;执行 i++,i= 7;执行 p++,p指向 x[7],继续循环。
第 10次执行循环体:*q= 7,*p=0,条件“*q< *p”不成立,不执行 q=p;执行 i++, i= 10;执行 p++, p指向 x[ 10]。
此时,控制循环的条件“i<10”不成立,退出循环。
执行输出语句,输出结果是q-x,由于指针变量q指向x[1],而x是数组首地址,代表数组元素x[0]的地址,所以q-x的值是整数1。
注意,本程序输出的实际上是教组x中最大值的下标。
【答案】 1
16 阅读下列程序,写出程序的主要功能。
# include”string.h”
main()
{ char s[5][81],*pl[5],**p2,**p3;
int i;
for( i= 0; i< 5; i++)
{ p1[i]=&s[i][0];
gets(p1[i]);
}
for(p3=p2=p1,i=0;i<5;i++, p2++)
if(strcmp(*p3,*p2)<0)p3=p2;
puts(*p3);
}
【分析】从数据定义语句可知,定义了一个二维字符型数组 s和一个一级指针数组 p1、两个二级指针变量p2、p3。接下来的单重次数型循环执行5次,循环体中的第1条语句是将二维数组中的第i行首地址存入指针数组元素p1[i]中,第2条语句是输入一个字符串存入p[i]所指向的字符数组中第i个一维数组中。也就是说,输入的5个数组存放在二维数组s的5行中,同时,指针数组p1的5个元素分别指向这5个字符串。
第2个循环语句也是循环5次的次数型循环。循环的开始,先让二级指针变量p2和p3都指向一级指针数组首地址,即p2指向pl[0](注意*p2就是pl[0]),p3指向p1[0](注意*p3就是pl[0])。循环体中利用函数strcmp()来比较*p2(第1次循环时*p2等于p1[0])和*p3(第1次循环时等于pl【0])指向的字符串的大小。如果*p3指向的字符串比*p2指向的字符串小,则将p2存入p3中保存。这个工作显然是用p3来保存5个字符串中最大字符串的地址。最后的输出语句是输出*p3所指向的字符串。
综上所述,本程序的功能很容易总结出来。
分析本程序时,要注意 p2和 p3是二级指针变量,它们的初值等于一级指针数组p1的数组名,即这两个二级指针变量是指向一级指针数组元素pl[0]的。此时,*p2和*p3都等于pl[0],而pl[0]是指针数组元素,其中存放的地址是字符型二维数组s中第0行第0列元素的地址,即s[0][0]的地址。如果当作字符率来理解的话,p1[0]是指向从s[0][0]开始存放的字符串。
【答案】输入 5个字符串,输出其中最大的字符串。
17 编一个程序,取出一个字符串的左边n个字符组成新的字符率并输出。原字符率及n从键盘输入。本题要求用指向字符的指针来处理字符率中的字符。
【分析】取出某个字符串左边n个字符的算法是一个次数型循环结构,可以使用for循环来实现次数型循环结构,用指针变量来处理具体的单个字符。
【答案】# include"string.h"
main()
{ char a[l00],b[100],*p_a= a,*p_b= b;
int n,i;
gets(p_a);
scanf("%d", &n);
for(i=0;i<n;i++)
*(p_b+i)=*(p_a+i);
*(p_b+i)='\0';
puts(p_b);
}
18 编一个程序,从键盘上输入一串符号(以回车换行键为结束),将其以字符率形式存入一维字符型数组,然后再输出该字符型数组中的字符串。本题要求用指向字符的指针来处理字符型数组中的字符。
【分析】本程序的结构可以这样来设计,输入一个字符,如果是回车换行符,则结束输入,否则
存入某字符型数组。反复进行直到输入的字符是回车换行符,这段程序是标准的当型循环结构。输入结束后,在字符数组的当前位置上(最后一个有效字符之后)置一个字符串结束标记。
【答案】main()
{ char s[100],*p=s,ch;
scanf("%c",&ch);
while(ch!='\n')
{ *p=ch;
p++;
scanf("%c",&ch);
}
*p='\0';
p=s;
printf("%s\n”,p);
}