C程序设计(谭浩强)第五版课后题答案 第八章
1. 输入3个整数,要求按由小到大的顺序输出。
#include <stdio.h> int main() { int a,b,c,*p_a=&a,*p_b=&b,*p_c=&c; void f(int *,int *); printf("请输入三个数字: \n"); scanf("%d%d%d",p_a,p_b,p_c); if(*p_a>*p_b) f(p_a,p_b); if(*p_a>*p_c) f(p_a,p_c); if(*p_b>*p_c) f(p_b,p_c); printf("数字从小到大排序为:%d %d %d\n",*p_a,*p_b,*p_c); return 0; } void f(int *p_a,int *p_b) { int t=*p_a; *p_a=*p_b; *p_b=t; }
2. 输入3个字符串,要求按由小到大的顺序输出。
#include <stdio.h> #include<string.h> #define N 3 int main() { char str[N][40]; char *p[N]; int i,j; void f(char *,char *); printf("请输入三个字符串: \n"); for(i=0;i<N;i++) { scanf("%s",str[i]); p[i]=str[i]; } for(i=0;i<N-1;i++) for(j=i+1;j<N;j++) if(strcmp(p[i],p[j])>0) f(p[i],p[j]); printf("字符串从小到大排序为:%s %s %s\n",p[0],p[1],p[2]); return 0; } void f(char *p1,char *p2) { char p3[N]; strcpy(p3,p2); strcpy(p2,p1); strcpy(p1,p3); }
3. 输入10个整数,将其中最小的数与第一个数对换, 把最大的数与最后一个数对换。
写3个函数:
①输入10个数;
②进行处理;
③输出10个数。
#include <stdio.h> #define N 10 int main() { int n[N]; void in1(int *); void maxmin1(int *); void out1(int *); printf("请输入%d个数字:\n",N); in1(n); maxmin1(n); out1(n); return 0; } void in1(int *arr) { int i; for(i=0;i<N;i++) scanf("%d",&arr[i]); } void maxmin1(int *arr) { int i,tmp,max1=arr[0],min1=arr[0]; int *p_max=NULL,*p_min=NULL; for(i=1;i<N;i++) { if(max1<arr[i]) { max1=arr[i]; p_max=&arr[i]; } if(min1>arr[i]) { min1=arr[i]; p_min=&arr[i]; } } tmp=*p_min; *p_min=arr[0]; arr[0]=tmp; tmp=*p_max; *p_max=arr[N-1]; arr[N-1]=tmp; } void out1(int *arr) { int i; for(i=0;i<N;i++) printf("%d ",arr[i]); }
4. 有n个整数,使前面各数顺序向后移m个位置,最后m个数变成最前面m个数
写一函数实现以上功能,在主函数中输人n个整数和输出调整后的n个数。
解题思路: 找出倒数第m个数据,从这里开始保存倒数第m位置的数据,因为倒数第m位置的数据要放到数组最前方,将m之前的数据向后偏移一位,然后将数组第一个位置的数据替换为保存的m位的数据,逐个往后递增即可。
#include <stdio.h> int main() { int i,n,m; int num[100]={0}; void move(int *,int,int); printf("请输入数字的个数:\n"); scanf("%d",&n); printf("请依次输入数字:\n"); for(i=0;i<n;i++) scanf("%d",&num[i]); printf("请输入要后移的距离:\n"); scanf("%d",&m); move(num,n,m); for(i=0;i<n;i++) printf("%d",num[i]); printf("\n"); return 0; } void move(int *arry[],int n,int m) { int i,j,end=n-m,temp; //end为倒数第m个数的位置 int *p; for(i=0;i<m;i++) { p=arry+end+i; //p指向数组第m+i的地址,即后m个数要前移的数的地址 temp=*p; //用temp记下要前移的数 for(j=i+end;j>i;j--) //把前n-m个数依次后移一个单位 { *p=*(p-1); p--; } *(arry+i)=temp; //把后m个数移到数组前m的位置 } }
5. 有n个人围成一圈,顺序排号。从第1个人开始报数(从1到3报数),凡报到3的人退出圈子,问最后留下的是原来第几号的那位。
解题思路: 从第一个人开始,逐个报数,谁报3就退出,并且重置报数,直到最后一个人后,又重新从第一个人继续报数,直到最终只剩一个人的时候退出即可。
#include <stdio.h> int main() { int i,n,remain,num=0; int *p; int people[200]={0}; printf("请输入人数:\n"); scanf("%d",&n); for(i=0;i<n;i++) people[i]=i+1; remain=n; while(remain>1) { p=people; //当数组遍历一遍时,再从头遍历 while(p!=people+n) { if((*p)!=0) { num++; if(num==3) { *p=0; num=0; remain--; } } p++; } } for(i=0;i<n;i++) { if(people[i]!=0) printf("最后剩的人的序号是%d号\n",people[i]); } return 0; }
6. 写一函数,求一个字符串的长度。在main函数中输入字符串,并输出其长度。
解题思路: 字符串以\0作为结尾,则从第一个字符开始向后移动遇到\0认为字符串结束。
#include <stdio.h> int main() { char a[240]; int count(char *str); printf("请输入字符串:\n"); scanf("%s",a); printf("字符串的长度是%d\n",count(a)); return 0; } int count(char *str) { char *p=str; int num=0; while((*(p++))!='\0') num++; return num; }
7. 有一字符串,包含n个字符。写一函数,将此字符串中从第m个字符开始的全部字符复制成为另一个字符串。
#include <stdio.h> #include<string.h> int main() { int m; char a[240]={0}; char b[240]={0}; void copy(char str1[],char str2[],int n); printf("请输入字符串:\n"); scanf("%s",a); printf("请输入要复制字符串的起始位置:"); scanf("%d",&m); copy(a,b,m); printf("复制后的字符串为:%s\n",b); return 0; } void copy(char str1[],char str2[],int n) { char *p; int i; p=str1+n-1; for(i=0;i<=strlen(str1)-n;i++) str2[i]=*(p++); }
8. 输入一行文字,找出其中大写字母、小写字母、空格、数字以及其他字符各有多少。
#include <stdio.h> int main() { char b[240]={0}; int a=0,A=0,num=0,space=0,other=0; char *p; p=b; printf("请输入字符串:\n"); gets(b); while(*p!='\0') { if(*p>='a' && *p<='z') a++; else if(*p>='A' && *p<='Z') A++; else if(*p>='0' && *p<='9') num++; else if(*p==' ') space++; else other++; p++; } printf("小写字母个数:%d\n大写字母个数:%d\n数字个数:%d\n空格个数:%d\n其它字符个数:%d\n",a,A,num,space,other); }
9. 写一函数,将一个3x3的整型矩阵转置。
解题思路: 矩阵转置就是行变列,列变行,就是 arry[i][j] 转换为 arry[j][i] ; 但是需要注意的是,
一. 因为行列个数可能并非相同,转换后行数或者列数变多了或者变少,因此不能直接转换。需要重新申请空间存储转换后的数据。
二. 二维数组是线性扁平化存储的,无法确定列数的情况下传参后,在函数中使用时需要头指针向后偏移 列数*第n行 才能访问到第n行的数据。例如在函数中访问 arry[i][j] ,需要通过arry + col_num*i + j 方式进行访问。
#include <stdio.h> #define M 3 #define N 3 int main() { int i,j; int d[M][N]; void chang(int str[][M],int row,int line); //二维数组做形参时,列不能省 printf("请输入一个%dx%d数组:\n",M,N); for(i=0;i<M;i++) for(j=0;j<N;j++) scanf("%d",&d[i][j]); printf("\n"); chang(d,M,N); printf("转置后的数组为:\n"); for(i=0;i<N;i++) { for(j=0;j<M;j++) printf("%d",d[i][j]); printf("\n"); } return 0; } void chang(int str[][M],int row,int line) { int i,j; int **p; p=str; p=(int **)malloc(sizeof(int *)*line); for(i=0;i<line;i++) p[i]=(int *)malloc(sizeof(int)*row); for(i=0;i<line;i++) for(j=i;j<row;j++) { int t; t = *(*(str)+line*j+i); *(*(str)+line*j+i) = *(*(str)+row*i+j); *(*(str)+row*i+j) = t; } //二维数组的存储是扁平化的, 访问第j行第i列的数据,应该是 arry + j*列数 + i //j是原数组的行 }
10. 将一个5x5的矩阵中最大的元素放在中心,4个角分别放4个最小的元素(顺序为从左到右,从上到下依次从小到大存放),写一函数实现之。用main函数调用。
解题思路: 将二维数组当做一维数组进行处理比较方便,而二维数组本身就是扁平化存储,所以直接使用首地址即可。
先遍历找到最大值,将其与中间数字交换,而中间数字的下标就是数字总数除以2;
其次寻找四次最小值,每次寻找的时候将最小值的下标记录起来,前提是这个数字如果已经是选中的最小数字之一,则需要跳过,也就是只跟剩余的数字作比较。(第二次开始遍历找最小数字的时候,千万不能与第一个最小数进行比较,否则永远都只有一个最小数)。
#include <stdio.h> #define M 5 #define N 5 int main() { int i,j; int d[M][N]; void chang(int str[][N],int row,int line); //二维数组做形参时,列不能省 printf("请输入一个%dx%d数组:\n",M,N); for(i=0;i<M;i++) for(j=0;j<N;j++) scanf("%d",&d[i][j]); printf("\n"); chang(d,M,N); printf("转变后的数组为:\n"); for(i=0;i<M;i++) { for(j=0;j<N;j++) printf("%5d",d[i][j]); printf("\n"); } return 0; } void chang(int str[][N],int row,int line) { int i,j,t,k,tmp,min_id[4],min_tmp; int *p; int *pmax,*pmin; p=&str[0][0]; pmax=p; pmin=p; for(i=0;i<row;i++) for(j=0;j<line;j++) if(*pmax<*(p+line*i+j)) pmax=p+line*i+j; tmp=*(p+line*row/2); //行列相乘的总数除以2加一即为中心的位置,注意数组下标是从0开始的 *(p+line*row/2)=*pmax; *pmax=tmp; for(i=0;i<4;i++) { min_tmp=str[row*line-1]; for(j=0;j<row*line;j++) { k=0; for(;k<i;k++) if(j==min_id[k]) //如果某个下标值已经是最小下标,则不再比较 break; if(k!=i) //k!=i说明执行break了,即这时j值是最小下标,结束本次循环 continue; if(min_tmp>str[j]) { min_tmp=str[j]; min_id[i]=j; } } } tmp=*(p); *(p)=*(p+min_id[0]); *(p+min_id[0])=tmp; tmp=*(p+line-1); *(p+line-1)=*(p+min_id[1]); *(p+min_id[1])=tmp; tmp=*(p+line*(row-1)); *(p+line*(row-1))=*(p+min_id[2]); *(p+min_id[2])=tmp; tmp=*(p+line*row-1); *(p+line*row-1)=*(p+min_id[3]); *(p+min_id[3])=tmp; }
11. 在主函数中输入10个等长的字符串。用另一函数对它们排序。然后在主函数输出这10个已排好序的字符串。
解题思路:采用strcmp,返回值大于0表示第一个字符串大于第二个字符串
#include <stdio.h> #include<string.h> #define M 10 #define N 1000 int main() { int i; char d[M][N]; void sort(char str[][N]); //二维数组做形参时,列不能省 printf("请输入%d个等长的字符串:\n",M); for(i=0;i<M;i++) gets(d[i]); printf("\n"); sort(d); printf("排序后的字符串为:\n"); for(i=0;i<M;i++) printf("%s\n",d[i]); printf("\n"); return 0; } void sort(char str[M][N]) { int i,j; char temp[N]={0}; char *p; p=temp; for(i=0;i<M;i++) for(j=i;j<M;j++) if((strcmp(str[j],str[i]))>0) { strcpy(p,str[j]); strcpy(str[j],str[i]); strcpy(str[i],p); } }
12. 用指针数组处理上一题目,字符串不等长。
解题思路: 与数字的比较没什么区别,只不过需要采用strcmp进行字符串的大小比较,使用指针实现需要在最早接收数据的时候就采用字符串指针数组,这样的好处在于指针的指向可以直接通过赋值进行改变,而指针数组中的字符串的顺序只需要交换不同字符串的地址就可以实现
#include <stdio.h> #include<string.h> #define M 10 #define N 1000 int main() { int i; char d[M][N]; char *p[M]; void sort(char *str[][N]); //二维数组做形参时,列不能省 for(i=0;i<M;i++) p[i]=d[i]; printf("请输入%d个等长的字符串:\n",M); for(i=0;i<M;i++) gets(p[i]); printf("\n"); sort(p); printf("排序后的字符串为:\n"); for(i=0;i<M;i++) printf("%s\n",p[i]); printf("\n"); return 0; } void sort(char *str[M]) { int i,j; char *temp; for(i=0;i<M;i++) for(j=i;j<M;j++) if((strcmp(*(str+j),*(str+i)))>0) { temp=*(str+j); *(str+j)=*(str+i); *(str+i)=temp; } }
13. 写一个用矩形法求定积分的通用函数,分别求 ,说明: sin,cos,exp 函数已在系统的数学函数库中,程序开头要用#include <math. h>。
解题思路:
矩形法,学过高等数学就知道化曲为直的思想。将定积分化为多个函数连续的和。基本思想是将区间[a,b]化成n等分,当n越大的时候结果越准确。图形化成一小块一小块的矩形。底边长都为(b-a)/n.高为每个等分点的函数值。然后将每个矩形的面积相加即为所求。
因为被分成n等分,就可以认为每一等分是一个矩形,那么每一矩形的面积为: 每一个矩形面积为:Sn=f(x)(b-a)/n ;总面积为:S=S1+S2+…+Sn;具体计算过程根据公式套即可。
这里主要在于函数指针的应用,将函数作为参数传递给另一个函数,在另一个函数中进行调用的方式向外提供统一接口,而接口内的处理方式随着传入的函数而不同
#include <stdio.h> #include<math.h> int main() { int n; double a,b,c,(*p)(double); double jifen(double (*)(double),double,double,int); //第一个参数是float型函数指针,函数的参数是float型 double fsin(float); double fcos(double); double fexp(double); printf("请输入积分的上限和下限:"); scanf("%lf %lf",&a,&b); printf("请输入矩形法要分成的份数:"); scanf("%d",&n); p=fsin; c=jifen(fsin,a,b,n); printf("积分fsin的值为%lf:\n",c); p=fcos; c=jifen(fcos,a,b,n); printf("积分fcos的值为%lf:\n",c); p=fexp; c=jifen(fexp,a,b,n); printf("积分fexp的值为%lf:\n",c); return 0; } double jifen(double (*p)(double),double a,double b,int n) { int i; double x,h,s; h=(a-b)/n; x=b; s=0; for(i=0;i<n;i++) { x+=h; s+=(*p)(x)*h; } return s; } double fsin(double x) { return sin(x); } double fcos(double x) { return cos(x); } double fexp(double x) { return exp(x); }
14. 将n个数按输入时顺序的逆序排列,用函数实现。
#include <stdio.h> int main() { int i,n; int *p; int num[40]={0}; void chang(int *,int); printf("请输入数的个数:"); scanf("%d",&n); printf("请输入数据:"); for(i=0;i<n;i++) scanf("%d",&num[i]); p=# chang(p,n); printf("逆序后的数据为:\n"); for(i=0;i<n;i++) printf("%d",num[i]); printf("\n"); return 0; } void chang(int *p,int n) { int i; int temp; for(i=0;i<n/2;i++) { temp=*(p+i); *(p+i)=*(p+n-1-i); *(p+n-1-i)=temp; } }
15. 有一个班4个学生,5门课程。
①求第1门课程的平均分;
②找出有两门以上课程不及格的学生,输出他们的学号和全部课程成绩及平均成绩;
③找出平均成绩在90分以上或全部课程成绩在85分以上的学生。
分别编3个函数实现以上3个要求。
#include <stdio.h> #define M 4 #define N 5 float aver[M]; int main() { int i,j; int id[M]; float score[M][N],(*p)[N]; //(*p)要按列取 void aver1(float (*p)[N]); void less60(float (*p)[N],int id[]); void best(float (*p)[N],int id[]); for(i=0;i<M;i++) { printf("\n请第%d个学生的学号:",i+1); scanf("%d",&id[i]); printf("\n请第%d个学生的成绩:",i+1); for(j=0;j<N;j++) scanf("%f",&score[i][j]); } p=score; aver1(p); less60(p,id); best(p,id); return 0; } void aver1(float (*p)[N]) { int i; float aver,sum=0; for(i=0;i<M;i++) sum+=*(*(p+i)); aver=sum/4.0; printf("第一门课的平均分是:%.2f\n",aver); } void less60(float (*p)[N],int id[M]) { int i,j,n; float sum; for(i=0;i<M;i++) { sum=0; for(j=0;j<N;j++) sum+=*(*(p+i)+j); aver[i]=sum/5.0; } for(i=0;i<M;i++) { int flag=0; for(j=0;j<N;j++) { if(*(*(p+i)+j)<60.0) flag++; } if(flag>2) { printf("学号为%d的同学有两门以上成绩不及格!其全部成绩及平均成绩如下:\n",id[i]); for(n=0;n<N;n++) printf("%.2f ",*(*(p+i)+n)); printf("\n"); printf("平均成绩:%.2f\n",aver[i]); } } } void best(float (*p)[N],int id[M]) { int i,j,flag; for(i=0;i<M;i++) { flag=1; if(aver[i]<=90.0) flag=0; for(j=0;j<N;j++) if(*(*(p+i)+j)<=85.0) flag=0; if(flag==1) printf("学号为%d的同学平均成绩在90分以上或全部课程成绩在85分以上\n",id[i]); } }
16. 输入一个字符串,内有数字和非数字字符,例如:A123x456 17960? ,302tab5876,将其中连续的数字作为一个整数,依次存放到一数组a中。例如,123放在a[0],456放在a[1]…统计共有多少个整数,并输出这些数。
#include <stdio.h> #include<string.h> int main() { int i,j=0,n=0; int len,cnt=0,a[1000]={0},tmp=0; char str[1000]={0},*p,temp[1000]={0}; printf("请输入字符串:"); gets(str); len=strlen(str); p=str; for(i=0;i<=len;i++) { if(*(p+i)>='0' && *(p+i)<='9') { cnt++; temp[j++]=*(p+i); } else { int x=1; if(cnt!=0) { j=cnt; for(;cnt>0;cnt--) { tmp+=(temp[j-1]-'0')*x; x*=10; j--; } a[n++]=tmp; } j=0; tmp=0; cnt=0; } } printf("整数个数是%d\n",n); for(i=0;i<n;i++) printf("%d ",a[i]); printf("\n"); return 0; }
17. 写一函数,实现两个字符串的比较。即自己写一个strcmp函数,函数原型为int strcmp(char * p1 ,char * p2); 设p1指向字符串s1, p2指向字符串s2。要求当s1=s2时,返回值为0;若s1≠s2,返回它们二者第1个不同字符的ASCII码差值(如"BOY"与"BAD" ,第2个字母不同,0与A之差为79- 65=14)。如果s1>s2,则输出正值;如果s1<s2,则输出负值。
解题思路: 使用两个指针指向两个字符串首部,逐个往后进行比较,不相等的时候则将数据进行相减,作为返回值
#include <stdio.h> #include<string.h> int main() { int n; char str1[1000]={0},*p1,*p2,str2[1000]={0}; int strcmp1(char *p1,char *p2); printf("请输入字符串1:"); gets(str1); printf("请输入字符串2:"); gets(str2); p1=str1; p2=str2; n=strcmp1(p1,p2); printf("返回值是%d\n",n); } int strcmp1(char *p1,char *p2) { int i=0,h=0; while(*(p1+i)!='\0' && *(p2+i)!='\0') { if(*(p1+i)!=*(p2+i)) h=*(p1+i)-*(p2+i); i++; } return h; }
18. 编一程序,输入月份号,输出该月的英文月名。例如,输人3,则输出"March" ,要求用指针数组处理。
解题思路: 首先定义字符串指针数字,数组中每一个元素都存放一个字符串指针,每个指针指向不同字符串的位置。则输入月份数字后,根据下标获取对应月份字符串的地址即可
#include <stdio.h> int main() { int n; char *Month0[12]={"January","February","March","April","May","June","July","August","Septemper","October","November","December"}; //注意要加双引号 printf("请输入要查询的月份:"); scanf("%d",&n); if(n>=1 && n<=12) printf("%s\n",Month0[n-1]); else printf("输入错误\n"); return 0; }
19.(1) 编写一个函数new,对n个字符开辟连续的存储空间,此函数应返回一个指针(地址),指向字符串开始的空间。new(n)表示分配n个字节的内存空间。(2)写一函数free,将前面用new函数占用的空间释放。Free(p)表示将p(地址)指向的单元以后的内存段释放。
#include <stdio.h> #define NEWSIZE 1000 char newbuf[NEWSIZE]; char *pnew=newbuf; char *mynew(int n) { if(pnew+n<=newbuf + NEWSIZE) { pnew+=n; return(pnew-n); } else return(NULL); } void myfree(char *p) { if(p>=newbuf && p<=newbuf+NEWSIZE) pnew=p; } int main() { }
20. 用指向指针的指针的方法对5个字符串排序并输出。
解题思路:指向指针的指针其实就是二级指针,使用二级指针的保存一级指针的地址,让这个一级指针指向具体的数据空间; 定义一个字符串指针数组包含5个元素,每个元素可以保存一个字符串的首地址,而这个地址指向的是具体的字符串数据空间,通过指针访问实现对指向空间内的字符串进行比较排序交换即可。
#include <stdio.h> #include<string.h> #define SIZE 1000 int main() { int i; char *pstr[5]; char **p; char str[5][SIZE]; void sort(char **p); for(i=0;i<5;i++) pstr[i]=str[i]; //将第i个字符串的首地址赋予指针数组 pstr 的第i个元素 printf("请输入5个字符串:\n"); for(i=0;i<5;i++) scanf("%s",pstr[i]); p=pstr; //将二级指针指向指针数组 pstr 的首地址 sort(p); printf("排序后的字符串顺序为:\n"); for(i=0;i<5;i++) printf("%s\n",pstr[i]); return 0; } void sort(char **p) { int i,j; char *temp; for(i=0;i<5;i++) for(j=i+1;j<5;j++) if(strcmp(*(p+i),*(p+j))>0) { temp=*(p+j); *(p+j)=*(p+i); *(p+i)=temp; } }
21. 用指向指针的指针的方法对n个整数排序并输出。要求将排序单独写成一个函数。n个整数在主函数中输入,最后在主函数中输出。
解题思路: 指向指针的指针其实就是二级指针,使用二级指针的保存一级指针的地址,让这个一级指针指向具体的数据空间。排序就是按照每个元素指针指向空间中的数据进行比对排序即可。
#include <stdio.h> int main() { int i,n; int *pnum[20]; int **p; int num[20]; void sort(int **p,int n); printf("请输入数字的个数:"); scanf("%d",&n); for(i=0;i<n;i++) pnum[i]=&num[i]; //将第i个字符串的首地址赋予数组 pnum 的第i个元素 printf("请输入%d个数字:\n",n); for(i=0;i<n;i++) scanf("%d",pnum[i]); p=pnum; //将二级指针指向数组指针 pnum 的首地址 sort(p,n); printf("排序后的数字顺序为:\n"); for(i=0;i<n;i++) printf("%d ",*pnum[i]); printf("\n"); return 0; } void sort(int **p,int n) { int i,j; int *temp; for(i=0;i<n;i++) for(j=i+1;j<n;j++) if(*(p+i)>*(p+j)) { temp=*(p+j); *(p+j)=*(p+i); *(p+i)=temp; } }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具
· Manus的开源复刻OpenManus初探