c语言程序设计习题答案与实验指导(C语言程序设计谭浩强第五版)
你也可以上程序咖(https://meta.chengxuka.com),打开大学幕题板块,不但有答案,讲解,还可以在线答题。
本章习题均要求用指针方法处理。
题目1:输入3个整数,按由小到大的顺序输出。
解:
答案代码:
#include <stdio.h>
int main()
{
void swap(int *p1, int *p2);
int n1, n2, n3;
int *p1, *p2, *p3;
printf("input three integer n1,n2,n3:");
scanf("%d,%d,%d", &n1, &n2, &n3);
p1 = &n1;
p2 = &n2;
p3 = &n3;
if (n1 > n2)
swap(p1, p2);
if (n1 > n3)
swap(p1, p3);
if (n2 > n3)
swap(p2, p3);
printf("Now,the order is:%d,%d,%d\n", n1, n2, n3);
return 0;
}
void swap(int *p1, int *p2)
{
int p;
p = *p1;
*p1 = *p2;
*p2 = p;
}
运行结果:
题目2:输入3个字符串,按由小到大的顺序输出。
解:
#include <stdio.h>
#include <string.h>
int main()
{
void swap(char *, char *);
char str1[20], str2[31], str3[20];
printf("input three line:\n");
gets(str1);
gets(str2);
gets(str3);
if (strcmp(str1, str2) > 0)
swap(str1, str2);
if (strcmp(str1, str3) > 0)
swap(str1, str3);
if (strcmp(str2, str3) > 0)
swap(str2, str3);
printf("Now,the order is:\n");
printf("%s\n%s\n%s\n", str1, str2, str3);
return 0;
}
void swap(char *p1, char *p2)
{
char p[20];
strcpy(p, p1);
strcpy(p1, p2);
strcpy(p2, p);
}
运行结果:
输入3行文字,程序把它们按字母由小到大的顺序输出。
题目3:输入10个整数,将其中最小的数与第一个数对换,把最大的数与最后一个数对换。写3 个函数:
①输入 10个数;
②进行处理;
③输出 10 个数。
解:
#include <stdio.h>
int main()
{
void input(int *);
void max_min_value(int *);
void output(int *);
int number[10];
input(number); //调用输入10 个数的函数
max_min_value(number); //调用交换函数
output(number); //调用输出函数
return 0;
}
//输入10 个数的函数
void input(int *number)
{
int i;
printf("input 10 numbers:");
for (i = 0; i < 10; i )
scanf("%d", &number[i]);
}
// 交换函数
void max_min_value(int *number)
{
int *max, *min, *p, temp;
max = min = number; //开始时使 max和 min都指向第1个数
for (p = number 1; p < number 10; p )
if (*p > *max)
max = p; //若 p指向的数大于max指向的数,就使 max指向p指向的大数
else if (*p < *min)
min = p; //若 p指向的数小于min指向的数,就使 min指向p指向的小数
temp = number[0]; //将最小数与第1个数 number[0]交换
number[0] = *min;
*min = temp;
if (max == number)
max = min; //如果 max和 number相等,表示第1个数是最大数,则使 max指向当前的最大数
temp = number[9]; //将最大数与最后一个数交换
number[9] = *max;
*max = temp;
}
//输出函数
void output(int *number)
{
int *p;
printf("Now, they are: ");
for (p = number; p < number 10; p )
printf("%d ", *p);
printf("\n");
}
分析:关键在 max_min_value 函数,请认真分析此函数。形参 number 是指针,局部变量 max,min和 p都定义为指针变量,max 用来指向当前最大的数,min 用来指向当前最小的数。
number 是第 1 个数 number[0] 的地址,开始时执行 max=min=number 的作用就是使 max 和 min 都指向第 1 个数 number[0] 。以后使 p 先后指向10个数中的第 2~10 个数。如果发现第 2 个数比第 1 个数 number[0] 大,就使 max 指向这个大的数,而 min 仍指向第 1 个数。如果第 2 个数比第. 1个数 number[0] 小,就使 min 指向这个小的数,而 max 仍指向第 1个数。然后使 p 移动到指向第 3 个数,处理方法同前。直到 p 指向第 10 个数,并比较完毕为止。此时 max. 指向 10个数中的最大者,min 指向 10 个数中的最小者。假如原来 10 个数是:
32 24 56 78 1 98 36 44 29 6
在经过比较和对换后,max和 min的指向为
32 24 56 78 1 98 36 44 29 6
↑ ↑
min max
此时,将最小数 1 与第 1 个数(即 number[0] )32 交换,将最大数 98 与最后一个数 6 交换。因此应执行以下两行:
temp = number[0]; number[0] = *min;*min = temp;//将最小数与第1个数 number[0]交换
temp = number[9]; number[9] = *max;*max = temp;//将最大数与最后一个数交换
最后将已改变的数组输出。
运行结果:
但是,有一个特殊的情况应当考虑:如果原来 10 个数中第 1 个数 number[0] 最大,如:
98 24 56 78 1 32 36 44 29 6
在经过比较和对换后,max 和 min 的指向为
98 24 56 78 1 32 36 44 29 6
↑ ↑
max min
在执行完上面第1行"temp=number[0] ;number[0]=*min;*min=temp;"后,最小数 1 与第 1个数 number[0] 对换,这个最大数就被调到后面去了(与最小的数对调)。
1 24 56 78 98 32 36 44 29 6
↑ ↑
max min
请注意:数组元素的值改变了,但是 max 和 min 的指向未变,max 仍指向 number[0]。此时如果接着执行下一行:temp= number[9];number[9]=* max;* max= temp; 就会出问题,因为此时 max 并不指向最大数,而指向的是第1个数,结果是将第 1个数(最小的数已调到此处)与最后一个数 number[9] 对调。结果变成:
6 24 56 78 98 32 36 44 29 1
显然就不对了。
为此,在以上两行中间加上一行:
if(max== number)max = min;
由于经过执行"temp= number[0]; number[0]=* min;* min=temp;"后,10 个数的排列为
1 24 56 78 98 32 36 44 29 6
↑ ↑
max min
max指向第 1 个数,if 语句判别出 max 和 number 相等(即 max 和 number 都指向 number[0] ),而实际上 max 此时指向的已非最大数了,就执行"max=min",使 max 也指向 min 当前的指向。而 min 原来是指向最小数的,刚才与 number[0] 交换,而 number[0] 原来是最大数,所以现在 min 指向的是最大数。执行 max=min 后 max也指向这个最大数。
1 24 56 78 98 32 36 44 29 6
↑
max,min
然后执行下面的语句:
temp = number[9]; number[9]=*max;* max= temp;
这就没问题了,实现了把最大数与最后一个数交换。
运行结果:
读者可以将上面的"if(max==number)max=min;" 删去,再运行程序,输入以上数据,分析一下结果。
也可以采用另一种方法:先找出 10 个数中的最小数,把它和第 1 个数交换,然后再重新找 10 个数中的最大数,把它和最后一个数交换。这样就可以避免出现以上的问题。重写void max_min_value 函数如下:
//交换函数
void max_min_value(int *number)
{
int *max, *min, *p, temp;
max = min = number; //开始时使max和min都指向第1个数
for (p = number 1; p < number 10; p )
if (*p < *min) //若p指向的数小于min指向的数,就使min指向p指向的小数
min = p;
temp = number[0]; //将最小数与第1个数 number[0] 交换
number[0] = *min;
*min = temp;
for (p = number 1; p < number 10; p )
if (*p > *max) //若p指向的数大于max指向的数,就使max指向p指向的大数
max = p;
temp = number[9]; //将最大数与最后一个数交换
number[9] = *max;
*max = temp;
}
这种思路容易理解。
这道题有些技巧,请读者仔细分析,学会分析程序运行时出现的各种情况,并善于根据情况予以妥善处理。
题目4:有n个整数,使前面各数顺序向后移 m 个位置,最后 m 个数变成最前面 m 个数,见图 8.43。写一函数实现以上功能,谜在主函数中输入 n个整数和输出调整后的n个数。
解:
答案代码:
#include <stdio.h>
int main()
{
void move(int[20], int, int);
int number[20], n, m, i;
printf("how many numbers?"); //问共有多少个数
scanf("%d", &n);
printf("input %d numbers:\n", n);
for (i = 0; i < n; i )
scanf("%d", &number[i]); //输入n 个数
printf("how many place you want move?"); //问后移多少个位置
scanf("%d", &m);
move(number, n, m); //调用move 函数
printf("Now,they are:\n");
for (i = 0; i < n; i )
printf("%d ", number[i]);
printf("\n");
return 0;
}
//循环后移一次的函数
void move(int array[20], int n, int m)
{
int *p, array_end;
array_end = *(array n - 1);
for (p = array n - 1; p > array; p--)
*p = *(p - 1);
*array = array_end;
m--;
if (m > 0) //递归调用,当循环次数m减至为0时,停止调用
move(array, n, m);
}
运行结果:
题目5:有 n 个人围成一圈,顺序排号。从第 1 个人开始报数。(从1到3报数),凡报到3 的 人退出圈子,问最后留下的是原来第几号的那位。
解:N-S图如图8.2所示。
答案代码:
#include <stdio.h>
int main()
{
int i, k, m, n, num[50], *p;
printf("\ninput number of person: n=");
scanf("%d", &n);
p = num;
for (i = 0; i < n; i )
*(p i) = i 1; //以1至 n 为序给每个人编号
i = 0; // i为每次循环时计数变量
k = 0; // k 为按1,2,3报数时的计数变量
m = 0; // m为退出人数
while (m < n - 1) //当退出人数比 n-1少时(即未退出人数大于1时)执行循环体
{
if (*(p i) != 0)
k ;
if (k == 3)
{
*(p i) = 0; //对退出的人的编号置为0
k = 0;
m ;
}
i ;
if (i == n) //报数到尾后,i 恢复为0了
i = 0;
}
while (*p == 0)
p ;
printf("The last one is NO.%d\n", *p);
return 0;
}
运行结果:
题目6:写一函数,求一个字符串的长度。在 main 函数中输入字符串,并输出其长度。
解:
答案代码:
#include <stdio.h>
int main()
{
int length(char *p);
int len;
char str[20];
printf("input string: ");
scanf("%s", str);
len = length(str);
printf("The length of string is %d.\n", len);
return 0;
}
//求字符串长度函数
int length(char *p)
{
int n;
n = 0;
while (*p != '\0')
{
n ;
p ;
}
return (n);
}
运行结果:
题目7:有一字符串,包含 n 个字符。写一函数,将此字符串中从第 m 个字符开始的全部字符复制成为另一个字符串。
解:
答案代码:
#include <stdio.h>
#include <string.h>
int main()
{
void copystr(char *, char *, int);
int m;
char str1[20], str2[20];
printf("input string:");
gets(str1);
printf("which character that begin to copy?");
scanf("%d", &m);
if (strlen(str1) < m)
printf("input error!");
else
{
copystr(str1, str2, m);
printf("result:%s\n", str2);
}
return 0;
}
void copystr(char *p1, char *p2, int m) //字符串部分复制函数
{
int n;
n = 0;
while (n < m - 1)
{
n ;
p1 ;
}
while (*p1 != '\0')
{
*p2 = *p1;
p1 ;
p2 ;
}
*p2 = '\0';
}
运行结果:
题目8:输入一行文字,找出其中大写字母、小写字母、空格、数字以及其他字符各有多少。
解:
答案代码:
#include <stdio.h>
int main()
{
int upper = 0, lower = 0, digit = 0, space = 0, other = 0, i = 0;
char *p, s[20];
printf("input string: ");
while ((s[i] = getchar()) != '\n')
i ;
p = &s[0];
while (*p != '\n')
{
if (('A' <= *p) && (*p <= 'Z'))
upper;
else if (('a' <= *p) && (*p <= 'z'))
lower;
else if (*p == ' ')
space;
else if ((*p <= '9') && (*p >= '0'))
digit;
else
other;
p ;
}
printf("upper case:%d lower case:%d", upper, lower);
printf(" space:%d digit:%d other:%d\n", space, digit, other);
return 0;
}
运行结果:
题目9:写一函数,将一个 3×3 的整型矩阵转置。
解:
答案代码:
#include <stdio.h>
int main()
{
void move(int *pointer);
int a[3][3], *p, i;
printf("input matrix:\n");
for (i = 0; i < 3; i )
scanf("%d %d %d", &a[i][0], &a[i][1], &a[i][2]);
p = &a[0][0];
move(p);
printf("Now,matrix:\n");
for (i = 0; i < 3; i )
printf("%d %d %d\n", a[i][0], a[i][1], a[i][2]);
return 0;
}
void move(int *pointer)
{
int i, j, t;
for (i = 0; i < 3; i )
for (j = i; j < 3; j )
{
t = *(pointer 3 * i j);
*(pointer 3 * i j) = *(pointer 3 * j i);
*(pointer 3 * j i) = t;
}
}
运行结果:
说明: a 是二维数组,p 和形参 pointer 是指向整型数据的指针变量,p 指向数组 0 行 0 列元素 a[0][0] 。在调用 move 函数时,将实参p的值&a[0][0] 传递给形参 pointer,在 move 函数中将 a[i][j]与 a[j][i] 的值互换。由于 a 数组的大小是 3×3,而数组元素是按行排列的,因此 a[i][j] 在 a 数组中是第(3×i j)个元素,例如,a[2][1]是数组中第(3×2+1)个元素,即第 7 个元素(序号从 0 算起)。a[i][j]的地址是(pointer十3*i j,同理,a[i][j] 的地址是(pointer十3*j i)。将*(pointer+3*i j)和*(pointer 3*j i)互换,就是将a[i][j]和 a[j][i]互换。
题目10:将一个 5×5 的矩阵中最大的元素放在中心,4 个角分别放 4 个最小的元素(顺序为从左到右,从上到下依次从小到大存放),写一函数实现之。用 main 函数调用。
解:
答案代码(1):
#include <stdio.h>
int main()
{
void change(int *p);
int a[5][5], *p, i, j;
printf("input matrix:\n"); //提示输入二维数组各元素
for (i = 0; i < 5; i )
for (j = 0; j < 5; j )
scanf("%d", &a[i][j]);
p = &a[0][0]; //使p指向0行0列元素
change(p); //调用change 函数,实现交换
printf("Now,matrix:\n");
for (i = 0; i < 5; i ) //输出已交换的二维数组
{
for (j = 0; j < 5; j )
printf("%d ", a[i][j]);
printf("\n");
}
return 0;
}
//交换函数
void change(int *p)
{
int i, j, temp;
int *pmax, *pmin;
pmax = p;
pmin = p;
for (i = 0; i < 5; i ) //找最大值和最小值的地址,并赋给 pmax,pmin
for (j = i; j < 5; j )
{
if (*pmax < *(p 5 * i j))
pmax = p 5 * i j;
if (*pmin > *(p 5 * i j))
pmin = p 5 * i j;
}
temp = *(p 12); //将最大值换给中心元素
*(p 12) = *pmax;
*pmax = temp;
temp = *p; //将最小值换给左上角元素
*p = *pmin;
*pmin = temp;
pmin = p 1;
for (i = 0; i < 5; i ) //找第二最小值的地址并赋给 pmin
for (j = 0; j < 5; j )
if (((p 5 * i j) != p) && (*pmin > *(p 5 * i j)))
pmin = p 5 * i j;
temp = *pmin; //将第二最小值换给右上角元素
*pmin = *(p 4);
*(p 4) = temp;
pmin = p 1;
for (i = 0; i < 5; i ) //找第三最小值的地址并赋给 pmin
for (j = 0; j < 5; j )
if (((p 5 * i j) != (p 4)) && ((p 5 * i j) != p) && (*pmin > *(p 5 * i j)))
pmin = p 5 * i j;
temp = *pmin; //将第三最小值换给左下角元素
*pmin = *(p 20);
*(p 20) = temp;
pmin = p 1; //找第四最小值的地址并赋给 pmin
for (i = 0; i < 5; i )
for (j = 0; j < 5; j )
if (((p 5 * i j) != p) && ((p 5 * i j) != (p 4)) && ((p 5 * i j) != (p 20)) && (*pmin > *(p 5 * i j)))
pmin = p 5 * i j;
temp = *pmin; //将第四最小值换给右下角元素
*pmin = *(p 24);
*(p 24) = temp;
}
运行结果:
说明:程序中用 change 函数来实现题目所要求的元素值的交换,分为以下几个步骤:
①找出全部元素中的最大值和最小值,将最大值与中心元素互换,将最小值与左上角元素互换。中心元素的地址为p 12(该元素是数组中的第 12 个元素——序号从 0 算起)。
②找出全部元素中的次小值。由于最小值已找到并放在 a[0][0]中,因此,在这一轮的比较中应不包括a[0][0],在其余 24 个元素中值最小的就是全部元素中的次小值。在双重 for 循环中应排除 a[0][0]参加比较。在 if 语句中,只有满足条件 ((p 5*i j)!=p) 才进行比较。不难理解, (p 5*i j) 就是 &a[i][j] ,p 的值是 &a[0][0] 。((p 5*i j)!=p) 意味着在 i 和 j 的当前值条件下 &a[i][j] 不等于 &a[0][0] 才满足条件,这样就排除了 a[0][0] 。因此执行双重 for 循环后得到次小值,并将它与右上角元素互换,右上角元素的地址为 p 4。
③找出全部元素中第 3 个最小值。此时 a[0][0] 和 a[0][4](即左上角和右上角元素)不应参加比较。可以看到∶在 if 语句中规定,只有满足条件 ((p 5*i j)!=p)&&((p 5*i j)!=(p 4)) 才进行比较。((p 5*i j)!=p) 的作用是排除 a[0][0],((p 5*i j)!=(p+4)) 的作用是排除 a[0][4] 。(p 5*i j) 是 &a[i][j] ,(p 4) 是 &a[0][4] ,即右上角元素的地址。满足 ((p 5*i j)!=(p 4)) 条件意味着排除了 a[0][4] 。执行双重 for 循环后得到除了 a[0][0] 和 a[0][4] 外的最小值,也就是全部元素中第 3 个最小值,将它与左下角元素互换,左下角元素的地址为 p 20。
④找出全部元素中第 4 个最小值。此时 a[0][0] ,a[0][4] 和 a[4][0](即左上角、右上角和左下角元素)不应参加比较,在 if 语句中规定,只有满足条件 ((p 5*i j)!=p)&&((p 5*i j)!=(p+4))&&((p 5*i j)!=(p+20)) 才进行比较。((p 5*i j)!=p) 和((p 5*i j)!=(p 4)) 的作用前已说明,((p 5*i j)!=(p 20)) 的作用是排除 a[4][0] ,理由与前面介绍的类似。执行双重 for 循环后得到除了 a[0][0] ,a[0][4] 和 a[4][0] 以外的最小值,也就是全部元素中第 4 个最小值,将它与右下角元素互换,左下角元素的地址为 p 24。
上面所说的元素地址是指以元素为单位的地址,p+24 表示从指针 p 当前位置向前移动 24 个元素的位置。如果用字节地址表示,上面右下角元素的字节地址应为 p 4*24,其中4 是整型数据所占的字节数。
(2)可以改写上面的 if 语句,change 函数可以改写如下∶
//交换函数
void change(int *p)
{
int i, j, temp;
int *pmax, *pmin;
pmax = p;
pmin = p;
for (i = 0; i < 5; i ) //找最大值和最小值的地址,并赋给 pmax,pmin
for (j = i; j < 5; j )
{
if (*pmax < *(p 5 * i j))
pmax = p 5 * i j;
if (*pmin > *(p 5 * i j))
pmin = p 5 * i j;
}
temp = *(p 12); //将最大值与中心元素互换
*(p 12) = *pmax;
*pmax = temp;
temp = *p; //将最小值与左上角元素互换
*p = *pmin;
*pmin = temp;
pmin = p 1;
//将 a[0][1]的地址赋给 pmin,从该位置开始找最小的元素
for (i = 0; i < 5; i ) //找第二最小值的地址并赋给 pmin
for (j = 0; j < 5; j )
{
if (i == 0 && j == 0)
continue;
if (*pmin > *(p 5 * i j))
pmin = p 5 * i j;
}
temp = *pmin; //将第二最小值与右上角元素互换
*pmin = *(p 4);
*(p 4) = temp;
pmin = p 1;
for (i = 0; i < 5; i ) //找第三最小值的地址并赋给 pmin
for (j = 0; j < 5; j )
{
if ((i == 0 && j == 0) || (i == 0 && j == 4))
continue;
if (*pmin > *(p 5 * i j))
pmin = p 5 * i j;
}
temp = *pmin; //将第三最小值与左下角元素互换
*pmin = *(p 20);
*(p 20) = temp;
pmin = p 1; //找第四最小值的地址并赋给 pmin
for (i = 0; i < 5; i )
for (j = 0; j < 5; j )
{
if ((i == 0 && j == 0) || (i == 0 && j == 4) || (i == 4 && j == 0))
continue;
if (*pmin > *(p 5 * i j))
pmin = p 5 * i j;
}
temp = *pmin; //将第四最小值与右下角元素互换
*pmin = *(p 24);
*(p 24) = temp;
}
这种写法可能更容易为一般读者所理解。
题目11:在主函数中输入 10 个等长的字符串。用另一函数对它们排序。然后在主函数输出这 10 个已排好序的字符串。
解∶
(1)用字符型二维数组
答案代码:
#include <stdio.h>
#include <string.h>
int main()
{
void sort(char s[][6]);
int i;
char str[10][6]; // p 是指向由 6个元素组成的一维数组的指针
printf("input 10 strings:\n");
for (i = 0; i < 10; i )
scanf("%s", str[i]);
sort(str);
printf("Now,the sequence is:\n");
for (i = 0; i < 10; i )
printf("%s\n", str[i]);
return 0;
}
void sort(char s[10][6]) //形参s是指向由6个元素组成的一维数组的指针
{
int i, j;
char *p, temp[10];
p = temp;
for (i = 0; i < 9; i )
for (j = 0; j < 9 - i; j )
if (strcmp(s[j], s[j 1]) > 0)
{
//以下3行是将s[i]指向的一维数组的内容与s[j 1]指向的一维数组的内容互换
strcpy(p, s[j]);
strcpy(s[j], s[ j 1]);
strcpy(s[j 1], p);
}
}
运行结果:
(2) 用指向一维数组的指针作函数参数
#include <stdio.h>
#include <string.h>
int main()
{
void
sort(char(*p)[6]);
int i;
char str[10][6];
char(*p)[6];
printf("input 10 strings:\n");
for (i = 0; i < 10; i )
scanf("%s", str[i]);
p = str;
sort(p);
printf("Now, the sequence is:\n");
for (i = 0; i < 10; i )
printf("%s\n", str[i]);
return 0;
}
void sort(char (*s)[6])
{
int i, j;
char temp[6], *t = temp;
for (i = 0; i < 9; i )
for (j = 0; j < 9 - i; j )
if (strcmp(s[j], s[j 1]) > 0)
{
strcpy(t, s[j]);
strcpy(s[j], s[ j 1]);
strcpy(s[j 1], t);
}
}
运行结果同(1)。
题目12:用指针数组处理上一题目,字符串不等长。
解:
答案代码:
#include <stdio.h>
#include <string.h>
int main()
{
void sort(char *[]);
int i;
char *p[10], str[10][20];
for (i = 0; i < 10; i )
p[i] = str[i]; //将第i个字符串的首地址赋予指针数组 p的第i个元素
printf("input 10 strings:\n");
for (i = 0; i < 10; i )
scanf("%s", p[i]);
sort(p);
printf("Now,the sequence is:\n");
for (i = 0; i < 10; i )
printf("%s\n", p[i]);
return 0;
}
void sort(char *s[])
{
int i, j;
char *temp;
for (i = 0; i < 9; i )
for (j = 0; j < 9 - i; j )
if (strcmp(*(s j), *(s j 1)) > 0)
{
temp = *(s j);
*(s j) = *(s j 1);
*(s j 1) = temp;
}
}
运行结果:
题目13:写一个用矩形法求定积分的通用函数,分别求
$$\int _0^1 sinxdx, \int _0^1 cosxdx,\int_0^1e^xdx$$
说明:sin,cos,exp 函数已在系 统的数学函数库中,程序 开头要用 # include <math.h>。
解:
可以看出,每次需要求定积分的函数是不一样的。可以编写一个求定积分的通用函数 integral,它有3个形参,即下限 a、上限 b及指向函数的指针变量 fun。函数原型可写为
float integral(float a, float b,float(* fun)());
先后调用integral函数3次,每次调用时把 a,b,sin,cos,exp 之一作为实参,把上限、下限及有关函数的入口地址传送给形参 fun。在执行 integral 函数过程中求出定积分的值。根据以上思路编写出程序:
#include <stdio.h>
#include <math.h>
int main()
{
float integral(float (*)(float), float, float, int); //对 integarl函数的声明
float fsin(float); //对 fsin 函数的声明
float fcos(float); //对 fcos 函数的声明
float fexp(float); //对fexp 函数的声明
float a1, b1, a2, b2, a3, b3, c, (*p)(float);
int n = 20;
printf("input a1,b1:");
scanf("%f,%f", &a1, &b1); //输入求 sin(x)定积分的下限和上限
printf("input a2,b2:");
scanf("%f,%f", &a2, &b2); //输入求 cos(x)定积分的下限和上限
printf("input a3,b3:");
scanf("%f,%f", &a3, &b3); //输入求e的x次方的定积分的下限和上限
p = fsin; //使p指向 fsin 函数
c = integral(p, a1, b1, n); //求出 sin(x)的定积分
printf("The integral of sin(x)is:%f\n", c);
p = fcos; //使 p指向fcos 函数
c = integral(p, a2, b2, n); //求出 cos(x)的定积分
printf("The integral of cos(x)is:%f\n", c);
p = fexp; //使p指向 fexp 函数
c = integral(p, a3, b3, n); //求出e的x次方的定积分
printf("The integral of exp(x)is:%f\n", c);
return 0;
}
//下面是用矩形法求定积分的通用函数
float integral(float (*p)(float), float a, float b, int n)
{
int i;
float x, h, s;
h = (b - a) / n;
x = a;
s = 0;
for (i = 1; i <= n; i )
{
x = x h;
s = s (*p)(x)*h;
}
return (s);
}
float fsin(float x) //计算 sin(x)的函数
{
return sin(x);
}
float fcos(float x) //计算 cos(x)的函数
{
return cos(x);
}
float fexp(float x) //计算e的 x次方的函数
{
return exp(x);
}
运行结果:
说明:sin,cos 和 exp 是系统提供的数学函数,在程序中定义3 个函数,即 fsin,fcos 和 fexp。分别用来计算 sin(x) ,cos(x) 和exp(x) 的值。在 main 函数中要对这 3 个函数作声明。在 main 函数定义中 p为指向函数的指针变量,定义形式是"float(*p)(float)",表示 p 指向的函数有一个实型形参,p 指向返回值为实型的函数。在 main 函数中有"p=fsin;",表示将 fsin 函数的入口地址传赋给 p,在调用 integral 函数时,用 p 作为实参,把 fsin 函数的入口地址传递给形参 p(相当于 fsin(x) 。fsin(x) 的值就是 sin(x)的值。因此通过调用 integral 函数求出 sin(x) 的定积分。求其余两个函数的定积分的情况与此类似。
题目14:将 n 个数按输入时顺序的逆序排列,用函数实现。
解:
答案代码:
#include <stdio.h>
int main()
{
void sort(char *p, int m);
int i, n;
char *p, num[20];
printf("input n:");
scanf("%d", &n);
printf("please input these numbers: \n");
for (i = 0; i < n; i )
scanf("%d", &num[i]);
p = &num[0];
sort(p, n);
printf("Now,the sequence is:\n");
for (i = 0; i < n; i )
printf("%d ", num[i]);
printf("\n");
return 0;
}
//将n 个数逆序排列函数
void sort(char *p, int m)
{
int i;
char temp, *p1, *p2;
for (i = 0; i < m / 2; i )
{
p1 = p i;
p2 = p (m - 1 - i);
temp = *p1;
*p1 = *p2;
*p2 = temp;
}
}
运行结果:
题目15:有一个班 4 个学生,5 门课程。
①求第 1 门课程的平均分;
②找出有两门以上课程不及格的学生,输出他们的学号和全部课程成绩及平均成绩;
③找出平均成绩在 90 分以上或全部课程成绩在 85分以上的学生。
分别编3个函数实现以上 3个要求。
解:
答案代码:
#include <stdio.h>
int main()
{
void avsco(float *, float *); //函数声明
void avcour1(char(*)[10], float *); //函数声明
void fali2(char course[5][10], int num[], float *pscore, float aver[4]); //函数声明
void good(char course[5][10], int num[4], float *pscore, float aver[4]); //函数声明
int i, j, *pnum, num[4];
float score[4][5], aver[4], *pscore, *paver;
char course[5][10], (*pcourse)[10];
printf("input course:\n");
pcourse = course;
for (i = 0; i < 5; i )
scanf("%s", course[i]);
printf("input NO. and scores:\n");
printf("NO.");
for (i = 0; i < 5; i )
printf(",%s", course[i]);
printf("\n");
pscore = &score[0][0];
pnum = &num[0];
for (i = 0; i < 4; i )
{
scanf("%d", pnum i);
for (j = 0; j < 5; j )
scanf("%f", pscore 5 * i j);
}
paver = &aver[0];
printf("\n\n");
avsco(pscore, paver); //求出每个学生的平均成绩
avcour1(pcourse, pscore); //求出第 1 门课的平均成绩
printf("\n\n");
fali2(pcourse, pnum, pscore, paver); //找出两门课不及格的学生
printf("\n\n");
good(pcourse, pnum, pscore, paver); //找出成绩好的学生
return 0;
}
//求每个学生的平均成绩的函数
void avsco(float *pscore, float *paver)
{
int i, j;
float sum, average;
for (i = 0; i < 4; i )
{
sum = 0.0;
for (j = 0; j < 5; j )
sum = sum (*(pscore 5 * i j)); //累计每个学生的各科成绩
average = sum / 5; //计算平均成绩
*(paver i) = average;
}
}
//求第1课程的平均成绩的函数
void avcour1(char (*pcourse)[10], float *pscore)
{
int i;
float sum, average1;
sum = 0.0;
for (i = 0; i < 4; i )
sum = sum (*(pscore 5 * i)); //累计每个学生的得分
average1 = sum / 4; //计算平均成绩
printf("course 1:%s average score:%7.2f\n", *pcourse, average1);
}
//找两门以上课程不及格的学生的函数
void fali2(char course[5][10], int num[], float *pscore, float aver[4])
{
int i, j, k, label;
printf(" ======Student who is fail in two courses ======\n");
printf("NO. ");
for (i = 0; i < 5; i )
printf("s", course[i]);
printf(" average\n");
for (i = 0; i < 4; i )
{
label = 0;
for (j = 0; j < 5; j )
if (*(pscore 5 * i j) < 60.0)
label ;
if (label >= 2)
{
printf("%d", num[i]);
for (k = 0; k < 5; k )
printf(".2f", *(pscore 5 * i k));
printf(".2f\n ", aver[i]);
}
}
}
//找成绩优秀学生(各门85分以上或平均 90分以上)的函数
void good(char course[5][10], int num[4], float *pscore, float aver[4])
{
int i, j, k, n;
printf(" ======Students whose score is good ======\n");
printf("NO. ");
for (i = 0; i < 5; i )
printf("s", course[i]);
printf(" average\n");
for (i = 0; i < 4; i )
{
n = 0;
for (j = 0; j < 5; j )
if (*(pscore 5 * i j) > 85.0)
n ;
if ((n == 5) || (aver[i] >= 90))
{
printf("%d", num[i]);
for (k = 0; k < 5; k )
printf(".2f", *(pscore 5 * i k));
printf(".2f\n", aver[i]);
}
}
}
运行结果:
程序中 num 是存放 4 个学生学号的一维数组,course 是存放 5 门课名称的二维字符数组,score 是存放 4 个学生 5 门课成绩的二维数组,aver 是存放每个学生平均成绩的数组。pnum 是指向 num数组的指针变量,pcou 是指向 course 数组的指针变量,psco 是指向 score 数组的指针变量,pave是指向 aver 数组的指针变量,见图8.3。
函数的形参用数组,调用函数时的实参用指针变量。形参也可以不用数组而用指针变量,请读者自己分析。
题目16:输入一个字符串,内有数字和非数字字符,例如∶
A123x456 17960?302tab5876
将其中连续的数字作为一个整数,依次存放到一数组 a 中。例如,123放在 a[0],456放在a[1]……统计共有多少个整数,并输出这些数。
解∶
答案代码:
#include <stdio.h>
int main()
{
char str[50], *pstr;
int i, j, k, m, e10, digit, ndigit, a[10], *pa;
printf("input a string:\n");
gets(str);
pstr = &str[0]; //字符指针 pstr置于数组 str 首地址
pa = &a[0]; //指针 pa 置于a数组首地址
ndigit = 0; // ndigit 代表有多少个整数
i = 0; //代表字符串中的第几个字符
j = 0;
while (*(pstr i) != '\0')
{
if ((*(pstr i) >= '0') && (*(pstr i) <= '9'))
j ;
else
{
if (j > 0)
{
digit = *(pstr i - 1) - 48; //将个数位赋予digit
k = 1;
while (k < j) //将含有两位以上数的其他位的数值累加于digit
{
e10 = 1;
for (m = 1; m <= k; m )
e10 = e10 * 10; // e10 代表该位数所应乘的因子
digit = digit (*(pstr i - 1 - k) - 48) * e10; //将该位数的数值\累加于 digit
k ; //位数k自增
}
*pa = digit; //将数值赋予数组 a
ndigit ;
pa ; //指针 pa 指向 a数组下一元素
j = 0;
}
}
i ;
}
if (j > 0) //以数字结尾字符串的最后一个数据
{
digit = *(pstr i - 1) - 48; //将个数位赋予 digit
k = 1;
while (k < j)
{
e10 = 1; //将含有两位以上数的其他位的数值累加于 digit
for (m = 1; m <= k; m )
e10 = e10 * 10; // e10代表位数所应乘的因子
digit = digit (*(pstr i - 1 - k) - 48) * e10; //将该位数的数值累加于 digit
k ; //位数k自增
}
*pa = digit; //将数值赋予数组 a
ndigit ;
j = 0;
}
printf("There are %d numbers in this line, they are:\n", ndigit);
j = 0;
pa = &a[0];
for (j = 0; j < ndigit; j ) //输出打印数据
printf("%d ", *(pa j));
printf("\n");
return 0;
}
运行结果:
题目17:写一函数,实现两个字符串的比较。即自己写一个 strcmp 函数,函数原型为
int strcmp(char * p1,char * p2);
设 p1指向字符串sl,p2指向字符串s2。要求当s1=s2时,返回值为0;若 s1≠s2,返回它们二者第 1 个不同字符的 ASCII 码差值(如"BOY"与"BAD",第 2个字母不同,O与 A 之差为79-65=14)。如果 s1>s2,则输出正值;如果 s1<s2,则输出负值。
解:
答案代码:
#include <stdio.h>
int main()
{
int m;
char str1[20], str2[20], *p1, *p2;
printf("input two strings:\n");
scanf("%s", str1);
scanf("%s", str2);
p1 = &str1[0];
p2 = &str2[0];
m = strcmp(p1, p2);
printf("result:%d,\n", m);
return 0;
} //两个字符串比较函数
strcmp(char *p1, char *p2)
{
int i;
i = 0;
while (*(p1 i) == *(p2 i))
if (*(p1 i ) == '\0') //相等时返回结果0
return (0);
return (*(p1 i) - *(p2 i)); /*不等时返回结果为第一个不等字符ASCII码的差值 */
}
运行结果∶
①:
②:
题目18:编一程序,输入月份号,输出该月的英文月名。例如,输入 3,则输出"March",要求用指针数组处理。
解:
答案代码:
#include <stdio.h>
int main()
{
char *month_name[13] = {"illegal month ", " January", " February", " March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};
int n;
printf("input month:\n");
scanf("%d", &n);
if ((n <= 12) && (n >= 1))
printf("It is %s.\n", *(month_name n));
else
printf("It is wrong.\n");
return 0;
}
运行结果∶
①:
②:
③:
题目19:(1)编写一个函数 new,对 n 个字符开辟连续的存储空间,此函数应返回一个指针(地址),指向字符串开始的空间。new(n)表示分配 n 个字节的内存空间。(2)写一函数 free;将 前面用 new 函数占用的空间释放。free(p)表示将 p(地址))指向的单元以后的内存段释放。
解∶
(1)编写函数new 程序如下∶
#include <stdio.h>
#define NEWSIZE 1000 //指定开辟存储区的最大容量
char newbuf[NEWSIZE]; //定义字符数组 newbuf
char *newp = newbuf; //定义指针变量 newp,指向可存储区的始端
//定义开辟存储区的函数 new,开辟存储区后返回指针
char *new (int n)
{
if (newp n <= newbuf NEWSIZE) //开辟区未超过 newbuf 数组的大小
{
newp = n; // newp指向存储区的末尾
return (newp - n); //返回一个指针,它指向存储区的开始位置
}
else
return (NULL); //当存储区不够分配时,返回一个空指针
}
new 函数的作用是:分配 n 个连续字符的存储空间。为此,应先开辟一个足够大的连续存储区,今设置字符数组 newbuf[1000],new 函数将在此范围内进行操作。指针变量 newp 开始指向存储区首字节。在每当请求用 new 函数开辟 n 个字符的存储区时,要先检查一下 newbuf 数组是否还有足够的可用空间。若有,则使指针变量 newp 指向开辟区的末尾(newp=newp十n),见图8.4中的 newp 。此时 newp 指向下面的空白(未分配)的区域的开头,即 newp 的值是下一次可用空间的开始地址。如果再一次调用 new 函数,就从 newp 最后所指向的字节开始分配下一个开辟区。如果若存储区不够分配,则返回 NULL,表示开辟失败。
new返回一个指向字符型数据的指针,指向新开辟的区域的首字节。
在主函数中可以用以下语句:
pt = new(n);
把新开辟的区域首字节的地址赋给 pt,使指针变量 pt 也指向新开辟的区域的开头。
(2)编写函数 free
free 的作用是使newp 的值恢复为p。
free 函数如下∶
#include <stdio.h>
#define NEWSIZE 1000
char newbuf[NEWSIZE];
char *newp = newbuf;
//释放存区函数
void free(char *p)
{
if (p >= newbuf && p < newbuf NEWSIZE)
newp = p;
}
在主函数中用以下语句指令释放 pt 指向的存储区。
free(pt);
调用 free时,实参 pt 的值传给形参 p,因此 p的值也是新开辟的区域首字节的地址。用 if 语句检查 p 是否在已开辟区的范围内(否则不合法,不能释放未分配的区域)。如果确认 p 在上述范围内,就把 p(即 pt)的值赋给 newp,使 newp 重新指向原来开辟区的开头,这样,下次再开辟新区域时就又从 newp 指向的字节开始分配,这就相当于释放了此段空间,使这段空间可再分配作其他用途。
有人可能对 if语句所检查的条件 "p>=newbuf && p<newbuf + NEWSIZE" 不理解,为什么不直接检查 "p==newbuf" 呢?他们认为 p 应当指向 newbuf 的开头。这里有个细节要考虑∶当第 1 次调用 new 函数开辟存储区时,new 函数的返回值(也是 pt 的值)的确是 newbuf。但是如果接着再开辟第 2 个存储区,new 函数的返回值(也是 pt 的值)就不是newbuf了,而是指针变量 newp的当前值,即 newbuf n了。因此,调用free 函数时,形参p得到的值也是第 2个存储区的起始地址。要释放的是第 2个存储区,而不是第1个存储区。但p的值必然在"newbuf 到 newbuf NEWSIZE"的范围内。
上面只是编写了两个函数,并不是完整的程序,它没有main 函数。本题是示意性的,可以大体了解开辟存储区的思路。
题目20:用指向指针的指针的方法对 5个字符串排序并输出。
解:
程序如下
#include <stdio.h>
#include <string.h>
#define LINEMAX 20 //定义字符串的最大长度
int main()
{
void sort(char **p);
int i;
char **p, *pstr[5], str[5][LINEMAX];
for (i = 0; i < 5; i )
pstr[i] = str[i]; //将第i个字符串的首地址赋予指针数组 pstr 的第i个元素
printf("input 5 strings:\n");
for (i = 0; i < 5; i )
scanf("%s", pstr[i]);
p = pstr;
sort(p);
printf("\nstrings sorted:\n");
for (i = 0; i < 5; i )
printf("%s\n", pstr[i]);
return 0;
}
//用冒泡法对5个字符串排序函数
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 i);
*(p i) = *(p j);
*(p j) = temp;
}
}
}
}
运行结果:
题目21:用指向指针的指针的方法对 n个整数排序并输出。要求将排序单独写成一个函数。n 个整数在主函数中输入,最后在主函数中输出。
解:
答案代码:
#include <stdio.h>
int main()
{
void sort(int **p, int n);
int i, n, data[20], **p, *pstr[20];
printf("input n:\n");
scanf("%d", &n);
for (i = 0; i < n; i )
pstr[i] = &data[i]; //将第i个整数的地址赋予指针数组 pstr 的第i个元素
printf("input %d integer numbers:", n);
for (i = 0; i < n; i )
scanf("%d", pstr[i]);
p = pstr;
sort(p, n);
printf("Now,the sequence is:\n");
for (i = 0; i < n; i )
printf("%d ", *pstr[i]);
printf("\n");
return 0;
}
void sort(int **p, int n)
{
int i, j, *temp;
for (i = 0; i < n - 1; i )
{
for (j = i 1; j < n; j )
{
if (**(p i) > **(p j)) //比较后交换整数地址
{
temp = *(p i);
*(p i) = *(p j);
*(p j) = temp;
}
}
}
}
运行结果:
data数组用来存放n个整数,pstr 是指针数组,每一个元素指向 data 数组中的一个元素,p 是指向指针的指针,请参考图8.5。图8.5(a)表示的是排序前的情况,图8.5(b)表示的是排序后的情况。可以看到,data 数组中的数的顺序没有变化,而 pstr 指针数组中的各元素的值(也就是它们的指向)改变了。
,
免责声明:本文仅代表文章作者的个人观点,与本站无关。其原创性、真实性以及文中陈述文字和内容未经本站证实,对本文以及其中全部或者部分内容文字的真实性、完整性和原创性本站不作任何保证或承诺,请读者仅作参考,并自行核实相关内容。文章投诉邮箱:anhduc.ph@yahoo.com