C程序设计(谭浩强第五版)第七章习题精解
1、写两个函数,分别求两个整数的最大公约数和最小公倍数,用主函数调用这两个函数,并输出结果。两个整数由键盘输人。
2.求方程 ${ax}^2+bx+c=0$的根,用3个函数分别求当: $b^2- 4ac$大于0、等于0和小于0时的根并输出结果。从主函数输入a,b,c 的值。
3.写一个判素数的函数,在主函数输人一个整数,输出是否为素数的信息。
4.写一个函数,使给定的一个3X3的二维整型数组转置,即行列互换。
5.写一个函数,使输人的一个字符串按反序存放,在主函数中输入和输 出字符串。
7.写一个函数,将一个字符串中的元音字母复制到另一字符串,然后输 出。
8.写一个函数,输人一个4位数字,要求输出这4个数字字符,但每两 个数字间空一个空格。如输人1990,应输出“1 9 9 0”。
9.编写一个函数,由实参传来一个字符串,统计此字符串中字母、数 字、空格和其他字符的个数,在主函数中输人字符串以及输出上述的 结果。
10.写一个函数,输人一行字符,将此字符串中最长的单词输出。
11.写一个函数,用“起泡法”对输人的10个字符按由小到大顺序排列。
14.输人10个学生5门课的成绩, 分别用函数实现下列功能:
17.用递归法将一个整数n转换成字符串。例如,输人483,应输出字 符串”483”。n的位数不确定,可以是任意位数的整数。
第七章 :用函数实现模块化程序设计
1、写两个函数,分别求两个整数的最大公约数和最小公倍数,用主函数调用这两个函数,并输出结果。两个整数由键盘输人。
A解题思路
使用辗转相除法进行求最大公约数:
首先确保第一个数最大
然后循环条件为第二个数不等于0,循环体内为先求第一个数对第二个数的余数
然后第一个数等于第二个数,第二个数等于余数
如此往复,循环结束后第一个数中存放的值即为最大公约数
最小公倍数等于这俩数的乘积除以最大公约数
B代码部分
#include<stdio.h>
int 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("最大公约数为:%d\n", 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<stdio.h>
#include<math.h>
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代码部分
#include<stdio.h>
int 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代码部分
#include<stdio.h>
int 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然后输出即可。
第二种思路是首先定义字符数组下标的左值和右值,左值为0,右值为长度-1,然后将左边的元素换成右边的元素,将右边的元素换成左边的元素。最后将遍历一遍(当左值大于右值时说明已遍历一遍)的字符串输出即可。
B代码部分
#include<stdio.h>
#include<string.h>
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] = '\0';
}
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中的\0也会被拷贝到s1中。
3.将s1输出即可。
B代码部分
#include<stdio.h>
void mystrcat(char s1[], char s2[])
{
int i=0, j=0;
while (s1[++i]);//先使i遍历到s1的末尾位置
while (s1[i++] = s2[j++]);//开始字符串拷贝,这条语句执行完后,s2中的\0也会被拷贝到s1中。
}
void main()
{
char s1[128], s2[50];
printf("请输入两个需要连接的字符串:\n");
gets(s1);
gets(s2);
mystrcat(s1, s2);
puts(s1);
}
C执行结果
7.写一个函数,将一个字符串中的元音字母复制到另一字符串,然后输 出。
A解题思路
设置相应的条件在if语句中,将满足条件的元素存放到第二个字符串中。
B代码部分
#include<stdio.h>
void 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] = '\0';
}
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代码部分
#include<stdio.h>
void myputs(char s1[])
{
int i = 0;
while (s1[i])
{
printf("%c", s1[i++]);
if(i<strlen(s1))
printf(" ");
}
}
void main()
{
char s1[5];
gets(s1);
myputs(s1);
}
C执行结果
9.编写一个函数,由实参传来一个字符串,统计此字符串中字母、数 字、空格和其他字符的个数,在主函数中输人字符串以及输出上述的 结果。
A解题思路
1,在循环中遍历整个数组,定义全局变量letter, num, speace, other;对应:字母、数 字、空格和其他字符,
2,全局变量初值为0且全局可用。
3,然后在循环中依次判断是否符合相应的条件,符合就相应的值+1,
4,直到将整个数组遍历完后将这些值在主函数输出。
B代码部分
#include<stdio.h>
int 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代码部分
#include<stdio.h>
void 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<len;i++)
for(j=0;j<len-i;j++)
if (s[j] > s[j+1])
{
char x = s[j];
s[j] = s[j + 1];
s[j + 1] = x;
}
B代码部分
#include<stdio.h>
void sort(char s[])
{
int i, j;
int len = strlen(s)-1;
for(i=0;i<len;i++)
for(j=0;j<len-i;j++)
if (s[j] > 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代码部分
#include<stdio.h>
double 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<stdio.h>
#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个学生的平均成绩为:%.2f\n", i + 1, stuavg[i]);
}
void cavg(float score[][N])//②计算每门课的平均分;
{
for (i = 0; i < N; i++)
{
float sum = 0.0;
for (j = 0; j <M; j++)
{
sum += score[j][i];
}
courseavg[i] = sum / M;
}
for (i = 0; i < N; i++)
printf("第%d门课程的平均分为:%.2f\n", i + 1, courseavg[i]);
}
void findmax(float score[][N])//③找出所有50个分数中最高的分数所对应的学生和课程;
{
float max = score[0][0];
int x, y;
for (i = 0; i < M; i++)
{
for (j = 0; j < N; j++)
if (max < score[i][j])
{
max = score[i][j];
x = i;
y = j;
}
}
printf("所有50个分数中最高的分数为:%.2f所对应的学生是第%d个,课程是第%d个.\n", max, x + 1, y + 1);
}
void sum(float score[][N])//④计算平均分方差:
{
float sum1 = 0.0;//平均分平方和
float sum2 = 0.0;//平均分和
for (i = 0; i < M; i++)
{
sum1 += stuavg[M] * stuavg[M];
sum2 += stuavg[M];
}
printf("平均分方差为:%.2f", sum1 / M - (sum2 / M) * (sum2 / M));
}
void main()
{
float score[M][N] = { 0 };
for (i = 0; i < M; i++)
{
printf("请输入第%d名学生的%d门成绩:", i + 1, N);
for (j = 0; j < N; j++)
{
scanf("%f", &score[i][j]);
}
}
savg(score);
cavg(score);
findmax(score);
sum(score);
}
C执行结果
15.写几个函数: ①输人10个职工的姓名和职工号; ②按职工号由小到大顺序排序,姓名顺序也随之调整; ③要求输人一个职工号,用折半查找法找出该职工的姓名,从主函数输人要查找的职工号,输出该职工姓 名。
A解题思路
定义职工号和姓名两个数组,职工号为整形int id[N],职工姓名为char name[N][NAME_SIZE];
2.使用冒泡排序进行职工号的排序,姓名用strcpy排序。
3.折半查找的核心方法具体看代码部分。
B代码部分
#include<stdio.h>
#include<string.h>
#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的职工姓名为:%s\n", 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代码部分
#include<stdio.h>
int 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代码部分
#include<stdio.h>
void 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代码部分
#include<stdio.h>
void 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执行结果