第8章指针【练习8-1】如果有定义”intm,n=5,*p=&m;”与m=n等价的语句是B。A.m=*p;B.*p=*&n;C.m=&n;D.m=**p;解答:A:p是指向m的指针变量,所以*p等价于m。即m=m。B:&n是n的地址,*&n是n的值,即把n的值赋给p指向的值m。即m=n。C:&n是n的地址。即把n的地址赋给m。D:**p是指p指向的指针所指向的值,在此无意义。故选B。【练习8-2】调用函数求两个数的和与差:计算输入的两个数的和与差,要求自定义一个函数sum_diff(floatop1,floatop2,float*psum,float*pdiff),其中op1和op2是输入的两个数,*psum和*pdiff是计算得出的和与差。解答:#includestdio.hvoidsum_diff(floatop1,floatop2,float*psum,float*pdiff);intmain(void){floatop1,op2,sum,diff;printf(Inputop1andop2:);scanf(%f%f,&op1,&op2);sum_diff(op1,op2,&sum,&diff);printf(%f+%f=%f;%f-%f=%f\n,op1,op2,sum,op1,op2,diff);return0;}voidsum_diff(floatop1,floatop2,float*psum,float*pdiff){*psum=op1+op2;*pdiff=op1-op2;}【练习8-3】两个相同类型的指针变量能不能相加?为什么?解答:不能。因为指针变量是一种特殊的变量,指针变量的值存放的是所指向变量的地址,两个地址相加并不能保证结果为一个有效的地址值,因而在C语言中指针变量相加是非法的。【练习8-4】根据表8.2所示,这组数据的冒泡排序其实循环到第6遍(即n-2)时就已经排好序了,说明有时候并不一定需要n-1次循环。请思考如何改进冒泡排序算法并编程实现(提示:当发现一遍循环后没有数据发生交换,说明已经排好序了)。解答:设置一个标志变量flag,进入一轮循环前设置为0,在循环中有发生数据交换就改写flag值为1。当该轮循环结束后检查flag值,如果变为1说明发生了数据交换,还没有排好序,如果为0说明没有发生交换,已经排好序。#includestdio.hvoidbubble(inta[],intn);intmain(void){intn,i,a[8];printf(Entern(n=8):);scanf(%d,&n);printf(Entera[%d]:,n);for(i=0;in;i++)scanf(%d,&a[i]);bubble(a,n);printf(Aftersorted,a[%d]=,n);for(i=0;in;i++)printf(%3d,a[i]);return0;}voidbubble(inta[],intn){inti,j,temp,flag;for(i=1;in;i++){flag=0;for(j=0;jn-i;j++)if(a[j]a[j+1]){temp=a[j];a[j]=a[j+1];a[j+1]=temp;flag=1;}if(flag==0)break;}}【练习8-5】重做例8-9,要求使用选择排序算法。解答:#includestdio.hvoidbubble(inta[],intn);intmain(void){inti,n,a[8];printf(Entern(n=8):);scanf(%d,&n);printf(Entera[%d]:,n);for(i=0;in;i++)scanf(%d,&a[i]);bubble(a,n);printf(Aftersorted,a[%d]=,n);for(i=0;in;i++)printf(%3d,a[i]);return0;}voidbubble(inta[],intn){inti,j,temp,index;for(i=0;in-1;i++){index=i;for(j=i+1;jn;j++)if(a[j]a[index])index=j;temp=a[i];a[i]=a[index];a[index]=temp;}}8.4电码加密【练习8-6】在使用scanf()函数时,输入参数列表需要使用取地址操作符&,但当参数为字符数组名时并没有使用,为什么?如果在字符数组名前加上取地址操作符&,会发生什么?解答:因为字符数组名的值是一个特殊的固定地址,可以看作是常量指针,因此不需要再使用取地址符来获取该数组的地址。如果在字符数组名str前加上取地址操作符&,那么对其取地址&str可以看做是这个数组的第一个元素的地址,由于数组地址和数组第一个元素的地址相同,所以&str表示地址值和str表示的地址值是相等的。对scanf()的变长参数列表的话,编译器只负责参数传递,怎么解释后边的几个地址的含义,是由前边的字符串确定的。所以使用scanf(“%s”,str)和scanf(“%s”,&str)都能通过编译且正常执行。【练习8-7】C语言不允许用赋值表达式直接对数组赋值,为什么?解答:数组名可以看作是常量指针,因为不可以对一个常量进行赋值,所以不允许用赋值表达式直接对数组进行赋值。【练习8-8】输入一个字符串,把该字符串的前3个字母移到最后,输出变换后的字符串。比如输入“abcdef”,输出为“defabc”。解答:#includestdio.h#includestring.h#defineMAXLINE100intmain(void){charline[MAXLINE],str[4];inti;printf(Inputthestring:);gets(line);if(strlen(line)3){printf(字符串长度小于3,不符合要求!\n);}for(i=0;i3;i++)str[i]=line[i];str[i]='\0';for(i=3;line[i]!='\0';i++)line[i-3]=line[i];line[i-3]='\0';strcat(line,str);printf(%s%s\n,Afterchanging:,line);return0;}【练习8-9】使用动态内存分配的方法实现例8-9的冒泡排序。解答:#includestdio.h#includestdlib.hvoidbubble(inta[],intn);intmain(void){intn,j,*a,i,temp;printf(Entern(n=8):);scanf(%d,&n);if((a=(int*)calloc(n,sizeof(int)))==NULL){printf(Notabletoallocatememory.\n);exit(1);}printf(Entea[%d]:,n);for(i=0;in;i++)scanf(%d,a+i);bubble(a,n);printf(Aftersorted,a[%d]=,n);for(i=0;in;i++)printf(%3d,*(a+i));free(a);return0;}voidbubble(inta[],intn){inti,j,temp;for(i=1;in;i++)for(j=0;jn-i;j++)if(*(a+j)*(a+j+1)){temp=*(a+j);*(a+j)=*(a+j+1);*(a+j+1)=temp;}}习题8一、选择题1.下列语句定义x为指向int类型变量a的指针,其中哪一个是正确的B。A.inta,*x=a;B.inta,*x=&a;C.int*x=&a,a;D.inta,x=a;2.以下选项中,对基本类型相同的指针变量不能进行运算的运算符是A。A.+B.-C.=D.==3.若有以下说明,且0=i10,则对数组元素的错误引用是C。inta[]={0,1,2,3,4,5,6,7,8,9},*p=a,i;A.*(a+i)B.a[p-a+i]C.p+iD.*(&a[i])4.下列程序的输出结果是B。intmain(void){inta[10]={0,1,2,3,4,5,6,7,8,9},*p=a+3;printf(“%d”,*++p);return0;}A.3B.4C.a[4]的地址D.非法5.对于下列程序,正确的是A。voidf(int*p){*p=5;}intmain(void){inta,*p;a=10;p=&a;f(p);printf(“%d”,(*p)++);return0;}A.5B.6C.10D.11二、填空题1.下列函数在一维数组a中将x插入到下标为i(i=0)的元素前。如果i=元素的个数,则x插入到末尾。原有的元素个数存放在指针n所指向的变量中,插入后元素个数加1。请填空。voidinsert(doublea[],int*n,doublex,inti){intj;if_(i*n)_for(j=*n-1;_j=i_;j--)_a[j+1]_=a[j];elsei=*n;a[i]=_x_;(*n)++;}2.下列程序先消除输入字符串的前后空格,再判断是否是“回文”(即字符串正读和倒读都是一样),若是则输出YES,否则输出NO。请填空。#includestdio.h#includestring.hintmain(void){chars[80],ch,*p,*q;inti,j,n;gets(s);p=_s_;while(*p==’’)_p++_;n=strlen(s);q=_s+n-1_;while(*q==’’)_q--_;while(_pq_&&*p==*q){p++;_q--_;}if(pq)printf(“NO\n”);elseprintf(“YES\n”);return0;}3.下列程序在数组中同时查找最大元素和最小元素的下标,分别存放在main()函数的fmax和min变量中。请填空。voidfind(int*,int,int*,int*);intmain(void){intmax,min,a[]={5,3,7,9,2,0,4,1,6,8};find(_a,10,&max,&min_);printf(“%d,%d\n”,max,min);return0;}voidfind(int*a,intn,int*max,int*min){inti;*max=*min=0;for(i=1;in;i++){if(a[i]a[*max])_*max=i_;if(a[i]a[*min])_*min=i_;}}4.写出下列程序的执行结果001224002346#includestdio.hintmain(void){inta[10],b[10],*pa,*pb,i;pa=a;pb=b;for(i=0;i3;i++,pa++,pb++){*pa=i;*pb=2*i;printf(“%d\t%d\n”,*pa,*pb);}pa=&a[0];pb=&b[0];for(i=0;i3;i++){*pa=*pa+i;*pb=*pb+i;printf(“%d\t%d\n”,*pa++,*pb++);}return0;}三、程序设计题1.拆分实数的整数与小数部分:要求定义一个函数voidsplitfloat(floatx,int*intpart,float*fracpart),其中x是被拆分的实数,*intpart和*fracpart分别是将实数x拆分出来的整数部分与小数部分。编写主函数,并在其中调用函数splitfloat()。试编写相应程序。解答:#includestdio.hvoidsplitfloat(floatx,int*intpart,float*fracpart);intmain(void){floatx,fracpart;intintpart;prin