C程序设计(谭浩强第五版)第七章习题精解
第七章 :用函数实现模块化程序设计目录:
1、写两个函数,分别求两个整数的最大公约数和最小公倍数,用主函数调用这两个函数,并输出结果。两个整数由键盘输人。
2.求方程 ${ax}^2+bx+c=0$的根,用3个函数分别求当: $b^2- 4ac$大于0、等于0和小于0时的根并输出结果。从主函数输入a,b,c 的值。
3.写一个判素数的函数,在主函数输人一个整数,输出是否为素数的信息。
4.写一个函数,使给定的一个3X3的二维整型数组转置,即行列互换。
5.写一个函数,使输人的一个字符串按反序存放,在主函数中输入和输 出字符串。
6.写一个函数,将两个字符串连接。
7.写一个函数,将一个字符串中的元音字母复制到另一字符串,然后输 出。
8.写一个函数,输人一个4位数字,要求输出这4个数字字符,但每两 个数字间空一个空格。如输人1990,应输出“1 9 9 0”。
9.编写一个函数,由实参传来一个字符串,统计此字符串中字母、数 字、空格和其他字符的个数,在主函数中输人字符串以及输出上述的 结果。
10.写一个函数,输人一行字符,将此字符串中最长的单词输出。
11.写一个函数,用“起泡法”对输人的10个字符按由小到大顺序排列。
13.用递归方法求n阶勒让德多项式的值,递归公式为
14.输人10个学生5门课的成绩, 分别用函数实现下列功能:
①计算每个学生的平均分;
②计算每门课的平均分;
③找出所有50个分数中最高的分数所对应的学生和课程;
④计算平均分方差
15.写几个函数: ①输人10个职工的姓名和职工号; ②按职工号由小到大顺序排序,姓名顺序也随之调整; ③要求输人一个职工号,用折半查找法找出该职工的姓名,从主函数输人要查找的职工号,输出该职工姓 名。
16.写一个函数,输人一个十六进制数,输出相应的十进制数。
17.用递归法将一个整数n转换成字符串。例如,输人483,应输出字 符串”483”。n的位数不确定,可以是任意位数的整数。
18.给出年、月、日,计算该日是该年的第几天。
第七章 :用函数实现模块化程序设计
1、写两个函数,分别求两个整数的最大公约数和最小公倍数,用主函数调用这两个函数,并输出结果。两个整数由键盘输人。
A解题思路
使用辗转相除法进行求最大公约数:
首先确保第一个数最大
然后循环条件为第二个数不等于0,循环体内为先求第一个数对第二个数的余数
然后第一个数等于第二个数,第二个数等于余数
如此往复,循环结束后第一个数中存放的值即为最大公约数
最小公倍数等于这俩数的乘积除以最大公约数
B代码部分
#includeint max(int m, int n) { int r; if (m < n)//先确保m中存储的为最大数 { int c = m; m = n; n = c; } while (n)//辗转相除法求最大公约数 { r = m % n; m = n; n = r; } return m; } void min(int s1, int s2) { printf("最小公倍数为:%d", s1 / s2);//输出最小公倍数 } void main() { int m, n; printf("请输入2个整数:"); scanf("%d %d", &m, &n); int s1 = m * n; int s2=max(m, n);//最大公约数 printf("最大公约数为:%dn", s2); min(s1, s2); }
C执行结果
2.求方程 ${ax}^2+bx+c=0$的根,用3个函数分别求当: $b^2- 4ac$大于0、等于0和小于0时的根并输出结果。从主函数输入a,b,c 的值。
A解题思路
根据图上的公式转为c语言的数学代码即可,在使用sqrt函数时记得要引用math.h函数库。
B代码部分
#include#include float disc;//定义全局变量判别式 float x1, x2; float p, q; void greater(int a, int b)//大于0的情况 { x1 = (-b + sqrt(disc)) / 2 * a; x2 = (-b - sqrt(disc)) / 2 * a; } void equal(int a, int b)//等于0的情况 { x1 = x2 = (-b) / 2 * a; } void less(int a, int b)//小于0的情况 { p = (-b) / 2 * a; q = sqrt(-(disc)) / 2 * a; } void main() { int a, b, c; printf("请输入a,b,c的值:"); scanf("%d %d %d", &a, &b, &c); disc = b * b - 4 * a * c; if (disc > 0) { greater(a, b); printf("该方程在判别式>0时的两根为:%.2f||%.2f", x1, x2); } else if (disc = 0) { equal(a, b); printf("该方程在判别式=0时的两根为:%.2f||%.2f", x1, x2); } else { less(a, b); printf("该方程在判别式<0时的两根为:%.2f||%.2f", p+q, p-q); } }
C执行结果
3.写一个判素数的函数,在主函数输人一个整数,输出是否为素数的信息。
A解题思路
素数判断条件:除了1和本身外没有取余为0的数,1不是素数。
将此代入成代码即可。
B代码部分
#includeint prime(int a) { int i; if (a == 1)return 0;//1不是素数 for (i = 2; i < a; i++) if ( a % i == 0) { return 0; break; } return 1; } void main() { int a; while (1) { printf("请输入一个整数:"); scanf("%d", &a); if (prime(a) == 1) printf("%d是素数。n",a); else printf("%d不是素数。n",a); } }
C执行结果
4.写一个函数,使给定的一个3X3的二维整型数组转置,即行列互换。
A解题思路
矩阵的转置:即为行变列,列变行。再定义一个数组存放转置后的矩阵就行了。
B代码部分
#includeint i, j; void transpose(int a[][3],int b[][3]) { for (i = 0; i < 3; i++) for (j = 0; j < 3; j++) b[i][j] = a[j][i]; } void main() { int a[3][3],b[3][3]; printf("请输入一个3*3的矩阵:n"); for (i = 0; i < 3; i++) for (j = 0; j < 3; j++) scanf("%d", &a[i][j]); transpose(a,b); printf("转置后的矩阵为:n"); for (i = 0; i < 3; i++) { for (j = 0; j < 3; j++) printf("%d ", b[i][j]); printf("n"); } }
C执行结果
5.写一个函数,使输人的一个字符串按反序存放,在主函数中输入和输 出字符串。
A解题思路
本题可使用两种方式求解。
第一种方式的思路是首先分别定义两个字符数组,将第一个字符串的元素从后往前赋值给第二个字符串,第二个字符串从前往后接收,循环结束后给第二个字符串加上 然后输出即可。
第二种思路是首先定义字符数组下标的左值和右值,左值为0,右值为长度-1,然后将左边的元素换成右边的元素,将右边的元素换成左边的元素。最后将遍历一遍(当左值大于右值时说明已遍历一遍)的字符串输出即可。
B代码部分
#include#include void re1(char s1[], char s2[])//第一种方式 { int i, j = 0; //while (s1[++i]); //i = i - 1; i = strlen(s1)-1;//这一条语句与上面两行相等 for (; i >= 0; i--,j++) s2[j] = s1[i]; s2[j] = ' '; } void re2(char s1[])//第二种方式 { int left = 0, right = strlen(s1) - 1; while (left < right) { char s = s1[left]; s1[left] = s1[right]; s1[right] = s; left++; right--; } } void main() { char s1[128] = {0}; //char s2[128] = {0}; gets(s1); //re1(s1, s2);//注释部分是另一种实现方式 //puts(s2); re2(s1); puts(s1); }
C执行结果
6.写一个函数,将两个字符串连接。
A解题思路
1.先使i遍历到s1的末尾位置
2.然后开始字符串拷贝,将s2的第一个元素赋值给s2的末尾处,然后逐个往后。s2中的 也会被拷贝到s1中。
3.将s1输出即可。
B代码部分
#includevoid mystrcat(char s1[], char s2[]) { int i=0, j=0; while (s1[++i]);//先使i遍历到s1的末尾位置 while (s1[i++] = s2[j++]);//开始字符串拷贝,这条语句执行完后,s2中的 也会被拷贝到s1中。 } void main() { char s1[128], s2[50]; printf("请输入两个需要连接的字符串:n"); gets(s1); gets(s2); mystrcat(s1, s2); puts(s1); }
C执行结果
7.写一个函数,将一个字符串中的元音字母复制到另一字符串,然后输 出。
A解题思路
设置相应的条件在if语句中,将满足条件的元素存放到第二个字符串中。
B代码部分
#includevoid mystrcpy(char s[], char s2[]) { int i = 0, j = 0; while (s[i]) { if (s[i] == 'a' || s[i] == 'A' || s[i] == 'e' || s[i] == 'E' || s[i] == 'i' || s[i] == 'I' || s[i] == 'o' || s[i] == 'O' || s[i] == 'u' || s[i] == 'U') s2[j++] = s[i]; i++; } s2[j] = ' '; } void main() { char s[128], s2[128]; gets(s); mystrcpy(s, s2); puts(s2); }
C执行结果
8.写一个函数,输人一个4位数字,要求输出这4个数字字符,但每两 个数字间空一个空格。如输人1990,应输出“1 9 9 0”。
A解题思路
在每个数字之间输出一个空格,最后一个字符不输出空格。
B代码部分
#includevoid myputs(char s1[]) { int i = 0; while (s1[i]) { printf("%c", s1[i++]); if(i C执行结果
9.编写一个函数,由实参传来一个字符串,统计此字符串中字母、数 字、空格和其他字符的个数,在主函数中输人字符串以及输出上述的 结果。
A解题思路
1,在循环中遍历整个数组,定义全局变量letter, num, speace, other;对应:字母、数 字、空格和其他字符,
2,全局变量初值为0且全局可用。
3,然后在循环中依次判断是否符合相应的条件,符合就相应的值+1,
4,直到将整个数组遍历完后将这些值在主函数输出。
B代码部分
#includeint letter, num, speace, other; void search(char str[]) { for (int i = 0; str[i]; i++) { if ((str[i] >= 'A' && str[i] <= 'Z') || (str[i] >= 'a' && str[i] <= 'z')) letter++; else if (str[i] >= '0' && str[i] <= '9') num++; else if (str[i] == ' ') speace++; else other++; } } void main() { char str[128]; gets(str); search(str); printf("字母%d、数字%d、空格%d,其他字符%d", letter, num, speace, other); } C执行结果
10.写一个函数,输人一行字符,将此字符串中最长的单词输出。
A解题思路
相关思路都标注在代码块注释部分了。
B代码部分
#includevoid findmax(char str[], char max[]) { int i, j; i = j = 0; int len = 0; while (str[i]) { j = i;//j等于当前单词的起始位置 while (str[j] != ' ' && str[j])//寻找当前单词的末尾处 j++; len = j - i;//计算当前单词的长度 if (len > strlen(max))//判断当前单词是否为最大长度 strncpy(max, str + i, len);//是最大长度就拷贝到max中 j++;//计算下一个单词,当前j指向下一个单词的起始处 i = j;//将i也指向下一个单词的起始处 } } void main() { char str[256] = { 0 }; char max[256] = { 0 };//字符数组一定要先初始化再使用 printf("请输入一行数据,单词之间使用空格分隔:n"); gets(str); findmax(str, max);//函数运行完毕后,max数组中存放的是最长单词 printf("最长的单词为:%s", max); } C执行结果
11.写一个函数,用“起泡法”对输人的10个字符按由小到大顺序排列。
A解题思路
起泡法也就是冒泡排序,我们只需要知道冒泡排序的核心算法即可:
for(i=0;i
for(j=0;j
if (s[j] > s[j+1])
{
char x = s[j];
s[j] = s[j + 1];
s[j + 1] = x;
}
B代码部分
#includevoid sort(char s[]) { int i, j; int len = strlen(s)-1; for(i=0;i s[j+1]) { char x = s[j]; s[j] = s[j + 1]; s[j + 1] = x; } } void main() { char s[11] = { '1','2','3','1','2','3', '1','2','3','9' }; sort(s); puts(s); } C执行结果
13.用递归方法求n阶勒让德多项式的值,递归公式为
A解题思路
将公式换成c语言代码即可。
B代码部分
#includedouble fun(int n, int x) { if (n == 0) return 1; if (n == 1) return x; if (n >= 1) return ((2 * n - 1) * x - fun(n - 1, x) - (n - 1) * fun(n - 2, x) / n); } void main() { int n,x; printf("请输入n和x的值:"); scanf("%d %d", &n,&x); printf("勒让德多项式的值为:%.2f", fun(n, x)); } C执行结果
14.输人10个学生5门课的成绩, 分别用函数实现下列功能:
①计算每个学生的平均分;
②计算每门课的平均分;
③找出所有50个分数中最高的分数所对应的学生和课程;
④计算平均分方差
A解题思路
根据题目进行函数定义,最后一个函数是求方差,将方差公式转换成代码即可。
B代码部分
#include#define M 10//10个学生 #define N 5//5门课程 float stuavg[M];//用于存放每个学生的平均分 float courseavg[N];//用于存放每门课程的平均分 int i, j; void savg(float score[][N])//①计算每个学生的平均分; { for (i = 0; i < M; i++) { float sum = 0.0; for (j = 0; j < N; j++) { sum += score[i][j]; } stuavg[i] = sum / N; } for (i = 0; i < M; i++) printf("第%d个学生的平均成绩为:%.2fn", i + 1, stuavg[i]); } void cavg(float score[][N])//②计算每门课的平均分; { for (i = 0; i < N; i++) { float sum = 0.0; for (j = 0; j C执行结果
15.写几个函数: ①输人10个职工的姓名和职工号; ②按职工号由小到大顺序排序,姓名顺序也随之调整; ③要求输人一个职工号,用折半查找法找出该职工的姓名,从主函数输人要查找的职工号,输出该职工姓 名。
A解题思路
定义职工号和姓名两个数组,职工号为整形int id[N],职工姓名为char name[N][NAME_SIZE];
2.使用冒泡排序进行职工号的排序,姓名用strcpy排序。
3.折半查找的核心方法具体看代码部分。
B代码部分
#include#include #define N 10 #define NAME_SIZE 10 void Input(int id[], char name[][NAME_SIZE]) { for (int i = 0; i < N; i++) { printf("输入职工号:"); scanf("%d", &id[i]); getchar();//用于忽略所输入的回车符号。 printf("输入职工的姓名:"); gets(name[i]); } } void Output(int id[], char name[][NAME_SIZE]) { for (int i = 0; i < N; i++) { printf("[%d],[%s]n", id[i], name[i]); } } //使用冒泡排序进行姓名与职工号同时排序 void Sort(int id[], char name[][NAME_SIZE]) { char tmp_name[NAME_SIZE];//定义临时字符串,用于存储临时变量 for (int i = 0; i < N - 1; i++) { for (int j = 0; j < N - i - 1; j++) { if (id[j] > id[j + 1]) { int tmp_id = id[j]; strcpy(tmp_name, name[j]); id[j] = id[j + 1]; strcpy(name[j], name[j + 1]); id[j + 1] = tmp_id; strcpy(name[j + 1], tmp_name); } } } } //二分查找(折半查找)算法设计查找的规律 void Search(int id[], char name[][NAME_SIZE], int key) { int low = 0; int high = N - 1; int mid; while (low <= high) { mid = (low + high) / 2; if (key == id[mid]) break; if (key < id[mid]) high = mid - 1; else low = mid + 1; } if (low <= high) printf("职工号为%d的职工姓名为:%sn", key, name[mid]); else printf("要查找的职工号为%d的职工不存在。n", key); } int main() { int id[N];//职工号 char name[N][NAME_SIZE];//职工号对应的职工姓名 Input(id, name); Output(id, name); Sort(id, name); printf("n"); Output(id, name); int no; while (1) { printf("请输入要查找的职工号:"); scanf("%d", &no); Search(id, name, no); } return 0; } C执行结果
16.写一个函数,输人一个十六进制数,输出相应的十进制数。
A解题思路
根据十六进制转10进制的规律进行转换:
每进一位需要乘以16
是大写字母时,需要将大写字母-字符A再+10
是小写字母时,需要将小写字母-字符a再+10
是0-9之间的数时,因为原来的数据是字符型,我们需要将其减去一个字符型的0才能变成整形参与运算。
B代码部分
#includeint Transpose(char str[]) { int i = 0; int n=0; while (str[i]) { if (str[i] >= 'A' && str[i] <= 'Z') n = n * 16 + str[i] - 'A' + 10; if (str[i] >= 'a' && str[i] <= 'z') n = n * 16 + str[i] - 'a' + 10; if (str[i] >= '0' && str[i] <= '9') n = n * 16 + str[i]-'0';//必须要加上-‘0’,这样保证两边是整形数据运算。 i++; } return n; } void main() { char str[128]; printf("请输入一个十六进制数:"); gets(str); printf("Ox%s=%d", str, Transpose(str)); } C执行结果
17.用递归法将一个整数n转换成字符串。例如,输人483,应输出字 符串”483”。n的位数不确定,可以是任意位数的整数。
A解题思路
使用递归关键是要有退出的条件,本题的递归思路是从后往前递归,输出字符时自然就会从前往后输出。
B代码部分
#includevoid prints(int s) { if (s / 10) prints(s / 10); putchar(s % 10 + '0');//从后往前递归,输出时从前往后 } void main() { int s; printf("请输入一个整数:"); scanf("%d", &s); if (s < 0)//如果s输入的是负数的情况下,需要将先将负号输出然后将负数变为正数运算 { putchar('-'); s *=-1; } prints(s); } C执行结果
18.给出年、月、日,计算该日是该年的第几天。
A解题思路
主函数输入年月日
将年月日传入seek函数
在seek函数中定义一个整形数组,用于存放每个月份的值
从1到当前月份每月的天数相加到sum
Sum加上当前天数
判断如果月份大于2且当前年是闰年的话给总天数加1,因为闰年的2月份比平年多1天
输出sum即可
B代码部分
#includevoid seek(int year, int mouth,int day) { int m[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 }; int sum = 0; for (int i = 1; i < mouth; i++)//i不能等于当前月份,因为当前月份没过完不能将天数计入总值 sum += m[i]; sum += day; if ((mouth > 2) && ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0))//判断如果月份大于2且当前年是闰年的话给总天数加1,因为闰年的2月份比平年多1天 sum += 1; printf("该日是该年的第%d天。", sum); } void main() { int year, mouth, day; printf("请输入年月日:"); scanf("%d %d %d", &year, &mouth, &day); seek(year, mouth, day); } C执行结果



