C语言程序设计实验课参考答案(实验十:函数、结构体、指针)

实验十 函数、结构体、指针

1. 数字统计

说明

请统计某个给定范围 [L,R] 的所有整数中,数字 7 出现的次数。

比如给定范围 [60,80] 中,7一共出现12次。分别是67,77的个位,以及 70∼79 的十位。

输入输出格式及样例

输入数据:一行两个数 L,R 表示范围,用空格分隔。

60 80

输出数据:一个整数表示数字 7 出现的次数。

12

参考答案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
/*解题思路: 定义一个自定义函数hasSeven(),通过前面学习过的循环提取个位数的数字来判断是否包含数字’7’,将’7‘个个数返回到主函数*/
#include<stdio.h>
int hasSeven(int x){
int count = 0;
while(x>0){
if(x%10 == 7){
count++;
}
x = x / 10;
}
return count;
}
int main(){
int l, r, count=0;
scanf("%d %d", &l, &r);
for(; l<=r; l++){
count = count + hasSeven(l);
}
printf("%d", count);
return 0;
}

2.转二进制

说明

请你把一个整数n转化为二进制并从低位到高位输出。

输入输出格式及样例

输入数据:一行,仅含一个正整数 n (1≤n≤10^9)。

11

输出数据:从低位到高位输出一个二进制数,表示n的二进制形式,每位之间不需要空格。

1101

参考答案

1
2
3
4
5
6
7
8
9
10
11
/*解题思路: 十进制转二进制的方法,每次除以2得到余数,就是二进制的地位至高位数字,直到商为1或0结束*/
#include<stdio.h>
int main(){
int n;
scanf("%d", &n);
while(n>0){
printf("%d", n%2);
n = n / 2;
}
return 0;
}

3. 八进制转十进制

说明

把一个八进制数转变为十进制数。

输入输出格式及样例

输入数据:一行,仅含一个八进制表示的正整数 n(1≤n≤10^9 )。

11

输出数据:一个整数,表示对应的十进制数。

9

参考答案

1
2
3
4
5
6
7
8
9
10
11
12
13
/*解题思路: 八进制转十进制的方法,个位数字*8的0次方,十位数字*8的1次方,各位结果累加 */
#include<stdio.h>
#include<math.h>
int main(){
int n, sum=0, i=0;
scanf("%d", &n);
while(n>0){
sum = sum + n % 10 * pow(8, i++);
n = n / 10;
}
printf("%d", sum);
return 0;
}

4. 求和

说明

使用递归函数,求1+2+3+4+···+n的和。
sum(n)= n + sum(n-1) n>1,sum(1)=1。

输入输出格式及样例

输入数据:输入一个整数 n(1≤n≤10^4 )

4

输出数据:输出1+2+⋯+n 的和。

10

参考答案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/*解题思路: 根据题目给的公式,可以确定递归函数重复执行的内容和结束条件,*/
#include<stdio.h>
int sum(int x){
if(x==1){
return 1;
}
return x + sum(x - 1);
}
int main(){
int n;
scanf("%d", &n);
printf("%d", sum(n));
return 0;
}

5. 求阶乘

说明

使用递归函数,求1×2×⋯×n 的乘积。

输入输出格式及样例

输入数据:输入一个整数n(1≤n≤20)。

5

输出数据:输出 1×2×⋯×n 的乘积。

120

参考答案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/*解题思路,同上一题,找到递归函数的可重复执行的代码和结束条件,这一题要注意n的取值范围到20,阶乘结果会超出int的取值范围,结果不能使用int类型*/
#include<stdio.h>
double fact(double x){
if(x == 1){
return 1;
}
return x * fact(x - 1);
}
int main(){
double n;
scanf("%lf", &n);
printf("%.f", fact(n));
return 0;
}

6. 斐波那契数列

说明

请编写递归函数:输出斐波那契数列第n项。0,1,1,2,3,5,8,13……

输入输出格式及样例

输入数据:一个正整数n,表示第n项(n<=50)。

4

输出数据:第n项是多少。

2

参考答案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*解题思路: 同样的递归函数,两个条件。*/
/*
此题要注意的是题目设置有运行时间要求,正常的运行会超时 n>45时.
每1次调用函数会再次调用2次本函数,其中有重复的计算。
所以使用数组将已经计算过的结果保存下来,再次调用时先判断数组中是否已有结果,可直接使用,否在再进行调用。
*/
#include<stdio.h>
long f[50];
long long fibo(int x){
if(f[x]) return f[x];
if(x==1 || x==2) return x-1;
return f[x] = fibo(x-1) + fibo(x-2);
}
int main(){
int n;
scanf("%d", &n);
printf("%lld", fibo(n));
return 0;
}

7. 求最大公约数(gcd)

说明

用递归方法求两个数的最大公约数。(m>0,n>0)
gcd(a,b) = gcd(b, a%b) b不等于0时, gcd(a,b) = a b等于0时

输入输出格式及样例

输入数据:输入两个数,即 m 和 n 的值。

8 6

输出数据:输出最大公约数。格式如样例,中间不含空格。

gcd=2

参考答案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/*
递归函数,两个条件,循环条件就是gcd(b, a%b),结束条件就是 b=0,返回a
*/
#include<stdio.h>
int gcd(int a, int b){
if(b==0)
return a;
return gcd(b, a%b);
}
int main(){
int m, n;
scanf("%d%d", &m, &n);
printf("gcd=%d", gcd(m, n));
return 0;
}

8. 交换数值

说明

输入两个整数 x和y,请你编写一个函数, 交换两个整数的数值并输出交换后的 x 和y。

C中的格式为: void swap(int *x, int *y) 。

输入输出格式及样例

输入数据:共一行,包含两个整数 x 和 y。

3 5

输出数据:共一行,包含交换后的 x 和 y。

5 3

参考答案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/*解题思路: 给定了指针作为形参的swap函数,注意实参传递值时,传递的是地址值 即可*/
#include<stdio.h>
void swap(int *x, int *y){
int z;
z = *x;
*x = *y;
*y = z;
}
int main(){
int x, y;
scanf("%d%d", &x, &y);
swap(&x, &y);
printf("%d %d", x, y);
return 0;
}

9. 奇偶排序

说明

请用数组做参数传址方式调用,在函数中排序:数组a中存放了n(1<=n<=1e4)个正整数,要求调用函数将数组a中的数重新排列:排列要求是:将偶数放在数组的左部,奇数放在数组的右部。

特别注意:偶数按原顺序先输出,奇数按逆序输出。

输入输出格式及样例

输入数据:

10

21 34 224 25 367 41 736 37 42 456

输出数据:34 224 736 42 456 37 41 367 25 21

参考答案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
/*
解题思路:排序要求,偶数顺序不动,奇数逆序,使用选择排序法,
1.每次先判断当前数是奇偶数,
2.是偶数不动,返回第1步,执行下一次循环;
3.是奇数, 通过循环把奇数挪到最后一位,中间数字往前移动1位,同时n-1,下一个奇数放到此奇数前面
4.交换之后,当前位置数字是一个新数字,需要再次判断其奇偶,返回第1步执行判断。
*/
#include<stdio.h>
void sort(int a[], int n){
int i,k;
for(i=0; i<n;){
if(a[i] % 2){
int t = a[i];
for(k=i; k<n-1; k++){
a[k] = a[k+1];
}
a[k] = t;
n--;
}else{
i++;
}
}
}
int main(){
int i, n, a[10000];
scanf("%d", &n);
for(i=0; i<n; i++){
int t;
scanf("%d", &t);
a[i] = t;
}
sort(a, n);
for(i=0; i<n; i++){
printf("%d ", a[i]);
}
return 0;
}

10.坐标统计

说明

输入n个点在平面上的坐标(横纵坐标都是整数),对于每个点可以控制所有位于它左下方的点(即横坐标x和纵坐标y都比它小),它可以控制的点的数目称为“战斗力”。依次输出每个点的战斗力,最后输出战斗力最高的点的编号(如果若干个点的战斗力并列最高,输出其中最大的编号)。

输入输出格式及样例

输入数据:输入第一行包含一个正整数n (1≤n≤100);接下来的n行,每行描述一个点的坐标,第i+1行包含两个正整数x和y (1≤x,y≤1000),表示编号为i的点的横坐标为x,纵坐标为y。

1
2
3
4
5
6
7
6
4 2
6 6
4 8
15 6
11 9
8 14

输出数据:输出共有n+1行,第1行到第n行,每行包含一个整数,第i行的整数表示编号为i的点的战斗力,第n+1行表示战斗力最高的点的编号。

1
2
3
4
5
6
7
0
1
0
1
3
3
6

参考答案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/*解题思路: 使用结构体,通过循环判断当前坐标点的x,y值是否都大于其他点的x,y值,均大于战斗力+1*/
#include<stdio.h>
struct points{
int x;
int y;
};
int main(){
struct points p[100];
int n, i, j;
scanf("%d", &n);
for(i=0; i<n; i++){
int x, y;
scanf("%d %d", &x, &y);
p[i].x = x;
p[i].y = y;
}
int max=0, index=0;
for(i=0; i<n; i++){
int count = 0;
for(j=0; j<n; j++){
if(p[i].x>p[j].x && p[i].y>p[j].y){
count++;
}
}
if(max <= count){
max = count;
index = i+1;
}
printf("%d\n", count);
}
printf("%d", index);
return 0;
}

11. 总分排名

说明

小明的班上一共有n名同学,已知他们的语文、数学、英语成绩,小明想知道自己的总分以及排第几,你来帮帮他吧!

输入输出格式及样例

输入数据:

第一行输入一个正整数n(1<n≤1000),代表班级人数,以及一个字符串(不含空白符,长度小于30),表示小明的英文名字。

接下来 n行,每行输入一位同学的信息,按顺序输入字符串(不含空白符,长度小于30),表示同学姓名,以及 3 个正整数,分别表示该同学的语文、数学、外语成绩。

1
2
3
4
3 Jason
Ada 90 91 95
Bob 92 89 97
Jason 92 97 98

输出数据:2 个正整数,表示小明的总分以及在班级的排名(若总分相同,则并列),中间用一个空格隔开。

287 1

参考答案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
/*解题思路,结构体,每次录入学生3科成绩,并计算出总分,记录要计算排名学生的总成绩,再通过循环与每个人的总成绩进行比较,计算出排名*/
#include<stdio.h>
#include<string.h>
struct ss{
char name[30];
int chinese;
int math;
int english;
int sum;
};
int main(){
struct ss s[1000];
int n;
char name[30];
scanf("%d %s", &n, name);
int count = 0, sum=0;
for(int i=0; i<n; i++){
scanf("%s%d%d%d", s[i].name, &s[i].chinese, &s[i].math, &s[i].english);
s[i].sum = s[i].chinese + s[i].english + s[i].math;
if(strcmp(s[i].name, name)==0){
sum = s[i].sum;
}
}
for(int i=0; i<n; i++){
if(strcmp(s[i].name, name)!=0 && sum < s[i].sum){
count++;
}
}
printf("%d %d", sum, count+1);
return 0;
}

12. 修改员工信息

说明

小丁是阿里巴巴公司程序员,这天项目经理给他一个结构体定义:

1
2
3
4
5
typedef struct {
int id;
char name[20];
int age;
} worker;

小丁一看,这不是一个工人的定义吗,包括编号 id,姓名,年龄什么的。经理说,我需要你写一个函数,能更改数据区中某个id的工人姓名和年龄。函数声明是这样的:

int modifyworker(worker *w, int n ,int id, char *name, int age);

经理说,参数 w 是这批工人数据的首地址,这批数据是连续存放的,n 是工人的数目,id是要修改的工人编号,name和age是新的姓名和年龄。

如果查到工人并完成修改工作,返回 1,如果查不到这个工人,返回 0。

请你帮小丁完成这个函数.

输入输出格式及样例

输入数据:

第一行一个整数 n

第二行开始,连续输入 n 行,每行依次输入一个整数 id,一个字符串姓名,一个整数年龄。

接着输入一行,依次输入一个整数 id,一个字符串姓名,一个整数年龄,为要修改的员工信息。

1
2
3
4
5
3
1 Andy 23
3 Bob 19
4 Cindy 20
3 Bill 23

输出数据:如果修改成功,输出 n 行,依次为每个员工的 id,姓名,年龄;否则,输出 error!

1
2
3
1 Andy 23
3 Bill 23
4 Cindy 20

参考答案

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/*程序补充完整即可,在注释代码中间完成,其他内容不需要修改,考查结构体成员的引用*/
/*通过循环判断id找到要找到的人员,然后替换姓名和年龄,*/
#include <stdio.h>
#include <string.h>
#include <math.h>
typedef struct {
int id;
char name[20];
int age;
}worker;
int modifyworker(worker *w, int n, int id, char *name, int age) {
/*****在以下位置编写完善代码Program****/
for(int i=0; i<n; i++){
if(w[i].id == id){
strcpy(w[i].name,name);
w[i].age = age;
return 1;
}
}
return 0;
/*End*/
}
int main() {
int n;
worker P[100], pmodify;
scanf("%d", &n);
for (int i = 0; i < n; i++)
scanf("%d%s%d", & P[i].id, P[i].name, & P[i].age);
scanf("%d%s%d", & pmodify.id, pmodify.name, & pmodify.age);
if (modifyworker(P, n, pmodify.id, pmodify.name, pmodify.age) == 0)
printf("error!");
else
for (int i = 0; i < n; i++)
printf("\n%d %s %d", P[i].id, P[i].name, P[i].age);
return 0;
}