你也能够上程序咖(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("%11s", 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("%11.2f", *(pscore + 5 * i + k)); printf("%11.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("%11s", 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("%11.2f", *(pscore + 5 * i + k)); printf("%11.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]; //定义字符数组 newbufchar *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 1000char 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 指针数组中的各元素的值(也就是它们的指向)扭转了。