第5章循环结构程序设计
结构化程序设计的3种基本结构:
循环结构 顺序结构 选择结构
5.2用while语句实现循环
while循环和for循环的区别_FutureForXHF的博客-CSDN博客_while循环和for循环的区别
do-while和while的区别
Do可以简单的使用英语翻译进行理解,就是做
Do{ 做
Printf(“2 “); 输出2 (这个行为)
}while(i<=5) 当i<=5时
而while则是
While(i<=5) 当i<=5时
{
Printf(“2 “); 输出2
}
从这两个例子就可以看到,do- while循环比while多了一个“做”的命令,而这就可以理解为:不管怎么样,你先给我运行一次再说。
求1-1/4+1/7-1/10+1/13-1/16+……
输入一个正整数repeat (0<repeat<10),做repeat次下列运算:
读入1个正实数 eps,计算并输出下式的值,精确到最后一项的绝对值小于 eps(保留6位小数)。请使用 while 语句实现循环。
计算:1-1/4+1/7-1/10+1/13-1/16+……
输入输出示例:括号内是说明
输入
2 (repeat=2)
2E-4 (eps=2E-4)
0.02 (eps=0.02)
输出
sum = 0.835549
sum = 0.826310
#include <stdio.h>
#include <math.h>
int main(void)
{
int denominator, flag;
int repeat, ri;
double eps, item, sum;
scanf("%d", &repeat);
for(ri = 1; ri <= repeat; ri++){
scanf("%le", &eps);
sum=0;
denominator=1;
flag=1;
item=1.0;
while(fabs(item)>=eps){
item=flag*1.0/denominator;
sum=sum+item;
flag=-flag;
denominator=denominator+3;
}
printf("sum = %.6f\n", sum);
}
return 0;
}
40013 求奇数和
输入一个正整数repeat (0<repeat<10),做repeat次下列运算:
读入一批正整数(以零或负数为结束标志),求其中的奇数和。请使用while语句实现循环。
输入输出示例:括号内是说明
输入
2 (repeat=2)
1 3 90 7 0
8 7 4 3 70 5 6 101 -1
输出
The sum of the odd numbers is 11.
The sum of the odd numbers is 116.
#include <stdio.h>
int main(void)
{
int x, sum;
int repeat, ri;
scanf("%d", &repeat);
for(ri = 1; ri <= repeat; ri++) {
scanf("%d", &x);
sum=0;
while(x>0) {
if(x%2!=0)
sum+=x;
scanf("%d", &x);
}
printf("The sum of the odd numbers is %d.\n", sum);
}
}
40014 求整数的位数
输入一个正整数 repeat (0<repeat<10),做 repeat 次下列运算:
输入一个整数 in,求它的位数。例如123的位数是3。请使用do-while语句实现循环。
输入输出示例:括号内是说明
输入
4 (repeat=4)
12345 (in=12345)
-100 (in=-100)
-1 (in=-1)
1290 (in=1290)
输出
count = 5 (12345的位数是5)
count = 3 (-100的位数是3)
count = 1 (-1的位数是1)
count = 4 (99的位数是2)
#include <stdio.h>
int main(void)
{
int count, in;
int repeat, ri;
scanf("%d", &repeat);
for(ri = 1; ri <= repeat; ri++){
scanf("%d", &in);
count=0;
if(in<0) in=-in;
do{
count++;
in=in/10;
} while (in!=0);
printf("count = %d\n", count);
}
return 0;
}
求整数的位数以及各位数字之和
程序填空,不要改变与输入输出有关的语句。
输入一个正整数 repeat (0<repeat<10),做 repeat 次下列运算:
输入一个整数 in,求它的位数以及各位数字之和。例如 123 的各位数字之和是 6,位数是 3。
输入输出示例:括号内是说明
输入
4 (repeat=4)
0 (in=0)
23456 (in=23456)
-100 (in=-100)
-1 (in=-1)
输出
count = 1, sum = 0 (0的位数是1, 各位数字之和是0)
count = 5, sum = 20 (23456的位数是5, 各位数字之和是20)
count = 3, sum = 1 (-100的位数是3, 各位数字之和是1)
count = 1, sum = 1 (-1的位数是1, 各位数字之和是1)
#include <stdio.h>
int main(void)
{
int count, in, sum;
int repeat, ri;
scanf("%d", &repeat);
for(ri = 1; ri <= repeat; ri++){
scanf("%d", &in);
count=0; sum=0;
if(in<0) in=-in;
do{
count++;
sum+=in%10;
in=in/10;
} while (in!=0);
printf("count = %d, sum = %d\n", count, sum);
}
return 0;
}
5.4用for语句实现循环
for(表达式1;表达式2;表达式3;)
for(循环变量赋初值;循环条件;循环变量增值)
小tips:for语句会比while语句功能强,除了可以给出循环条件外,还可以赋初值,使循环变量自动增值。
求2/1+3/2+5/3+8/5+...
输入一个正整数 repeat (0<repeat<10),做 repeat 次下列运算:
输入一个正整数 n,输出 2/1+3/2+5/3+8/5+……前n项之和,保留2位小数。(该序列从第2项起,每一项的分子是前一项分子与分母的和,分母是前一项的分子)
输入输出示例:括号内是说明
输入
3 (repeat=3)
1 (n=1)
5 (n=5)
20 (n=20)
输出
sum = 2.00 (第1项是2.00)
sum = 8.39 (前5项的和是8.39)
sum = 32.66 (前20项的和是32.66)
#include <stdio.h>
int main(void)
{
int i, n;
int repeat, ri;
double denominator, numerator, sum, temp;
scanf("%d", &repeat);
for(ri = 1; ri <= repeat; ri++){
scanf("%d", &n);
sum=0;
denominator=1;
numerator=2;
for(i=1;i<=n;i++){
sum += numerator/denominator;
temp = denominator; /* 为求下一项分子,保留当前项分母 */
denominator=numerator;
numerator=numerator+temp;
}
printf("sum = %.2f\n",sum);
}
}
高空坠球 (循环语句)
程序填空,不要改变与输入输出有关的语句。
输入一个正整数 repeat (0<repeat<10),做 repeat 次下列运算:
皮球从 height(米)高度自由落下,触地后反弹到原高度的一半,再落下,再反弹,……,如此反复。问皮球在第 n 次落地时,在空中一共经过多少距离?第 n 次反弹的高度是多少?(输出保留1位小数)
输入输出示例:括号内是说明
输入
3 (repeat=3)
10 2 (height=10m, n=2)
4 1 (height=2m, n=1)
100 8 (height=100m, n=8)
输出
distance=20.0, height=2.5 (第2次落地时,空中经过距离为20米, 第2次反弹高度为2.5米)
distance=4.0, height=2.0 (第1次落地时,空中经过距离为4米,第1次反弹高度为2米)
distance=298.4, height=0.4 (第8次落地时,空中经过距离为298.4米,第8次反弹高度为0.4米)
#include <stdio.h>
int main(void)
{
int i, n;
int repeat, ri;
double distance, height, bh;
scanf("%d", &repeat);
for(ri = 1; ri <= repeat; ri++){
scanf("%lf%d", &height, &n);
/*---------*/
distance = height;
bh = height/2.0;
if ( n>1 )
for (i = 2; i<=n; i++) {
distance += bh*2;
bh = bh/2;
}
printf("distance = %.1f, height = %.1f\n", distance, bh);
}
}
5.5循环的嵌套
使用嵌套循环求e = 1+1/1!+1/2!+....+1/n!
程序填空,不要改变与输入输出有关的语句。
输入一个正整数 repeat (0<repeat<10),做 repeat 次下列运算:
输入1个正整数n,计算下式的前n+1项之和(保留4位小数)。要求使用嵌套循环。
e = 1+1/1!+1/2!+....+1/n!
输入输出示例:括号内为说明
输入:
2 (repeat=2)
2 (n=2)
10 (n=10)
输出:
e = 2.5000
e = 2.7183
#include "stdio.h"
int main(void)
{
int i, j, n;
int repeat, ri;
double e, product;
scanf("%d", &repeat);
for(ri = 1; ri <= repeat; ri++){
scanf("%d", &n);
e = 1.0;
for (i = 1; i<= n; i++) {
product = 1;
for (j = 1; j<=i ; j++) {
product *= j;
}
e += 1.0/product;
}
/*---------*/
printf("e = %0.4f\n", e);
}
}
40023 换硬币 (多重循环语句)
输入一个正整数 repeat (0<repeat<10),做 repeat 次下列运算:
将一笔零钱(大于8分,小于1元, 精确到分)换成5分、2分和1分的硬币。
输入金额,问有几种换法?针对每一种换法,每种硬币至少有一枚,请输出各种面额硬币的数量和硬币的总数量。
要求:硬币面值按5分、2分、1分顺序,各类硬币数量依次从大到小的顺序,输出各种换法。
输出使用语句:printf("fen5:%d,fen2:%d,fen1:%d,total:%d\n",fen5, fen2, fen1, fen5+fen2+fen1);
输入输出示例:括号内为说明
输入:
2 (repeat=2)
10 (money=10分)
13 (money=13分)
输出:
fen5:1,fen2:2,fen1:1,total:4
fen5:1,fen2:1,fen1:3,total:5
count = 2 (10分有2种换法)
fen5:2,fen2:1,fen1:1,total:4
fen5:1,fen2:3,fen1:2,total:6
fen5:1,fen2:2,fen1:4,total:7
fen5:1,fen2:1,fen1:6,total:8
count = 4 (13分有4种换法)
#include "stdio.h"
int main(void)
{
int count, fen1, fen2, fen5, money;
int repeat, ri;
scanf("%d", &repeat);
for(ri = 1; ri <= repeat; ri++){
scanf("%d", &money);
count=0;
for(fen5=money/5;fen5>=1;fen5--)
for(fen2=money/2;fen2>=1;fen2--)
for(fen1=money/1;fen1>=1;fen1--)
if(fen5*5+fen2*2+fen1*1==money){
printf("fen5:%d,fen2:%d,fen1:%d,total:%d\n",fen5, fen2, fen1, fen5+fen2+fen1);
count++;}
printf("count = %d\n", count);
}
return 0;
}
5.6几种循环的比较
5.7改变循环执行的状态
用break语句提前终止循环
验证歌德巴赫猜想(选作)
程序填空,不要改变与输入输出有关的语句。
验证哥德巴赫猜想:任何一个大于6的偶数均可表示为两个素数之和。例如6=3+3,8=3+5,…,18=7+11。
输入两个正整数 m 和 n(6<=m, n<=100),将 m 到 n 之间的偶数表示成两个素数之和,打印时一行打印5组。
输出使用语句:printf("%d=%d+%d ", number, i, number - i);
输入输出示例:括号内为说明
输入:
89 100 (m=90, n=100)
输出:
90=7+83 92=3+89 94=5+89 96=7+89 98=19+79
100=3+97
#include "stdio.h"
#include "math.h"
int main(void)
{
int count, i, j, k, m, n, number;
scanf("%d%d", &m, &n);
if(m % 2 != 0) m = m + 1;
if(m >= 6){
/*---------*/
}
}
#include <stdio.h>
int prime(int m)
{
int i, ifPrime=0;
if(m==1) return 0;
for(i=2;i<=m/2;i++) {
if(m%i==0)
break;
}
if(i>m/2)
ifPrime=1;
return ifPrime;
}
int main(void)
{
int count, i, m, n, number;
scanf("%d%d", &m, &n);
if(m % 2 != 0) m = m + 1;
if(m >= 6) {
count=0;
for(number=m;number<=n;number=number+2) {
for(i=1;i<=number/2;i++) {
if( prime(i) && prime(number-i) ) {
printf("%d=%d+%d ", number, i, number-i);
count++;
if(count%5==0)
printf("\n");
break;
}
}
}
}
}
注:此题标准答案是输出每个数的第一对满足条件的素数之和,但是:
90=7+83 90=11+79 90=17+73 90=19+71 90=23+67 ...90=83+7
也都是满足条件的, 而机器只对输出第一种为正确解
用continue语句提前结束本次循环
一定要记住当执行continue时只是结束本次循环而不是终止整个循环的执行。而break语句则是结束整个循环过程,不再判断执行循环的条件是否成立。
continue语句应该这样理解:当执行continue语句时,流程跳转到表示循环体结束的右花括号的前面(注意不是右花括号的后面) 也可以理解为continue后的不执行,然后重新进入下一次新的循环当中
# include <stdio.h>
int main(void)
{
int val; //variable的缩写, “变量”的意思
printf("请输入您想去的楼层:");
while (1)
{
scanf("%d", &val);
switch (val)
{
case 1:
printf("1层开!\n");
break; //跳出switch
case 2:
printf("2层开!\n");
break; //跳出switch
case 3:
printf("3层开!\n");
break; //跳出switch
default:
printf("该层不存在, 请重新输入:");
continue; //结束本次while循环
}
break; //跳出while
}
return 0;
}
区别:
continue和break的区别
continue 语句和 break 语句的区别是,continue 语句只结束本次循环,而不是终止整个循环。break 语句则是结束整个循环过程,不再判断执行循环的条件是否成立。而且,continue 只能在循环语句中使用,即只能在 for、while 和 do…while 中使用,除此之外 continue 不能在任何语句中使用。
所以,再次强调:continue 不能在 switch 中使用,除非 switch 在循环体中。此时 continue 表示的也是结束循环体的本次循环,跟 switch 也没有关系。
第五章典型题(循环):
斐波那契数列
【C语言】斐波那契数列_EurekaO-O的博客-CSDN博客_斐波那契数列c语言
斐波那契数列_详解(C语言)_小-黯的博客-CSDN博客_斐波那契数列c语言
斐波那契数列的四种实现方式(C语言)_cherrydreamsover的博客-CSDN博客_斐波那契数列c语言
第五章习题答案:
C语言程序设计第五版谭浩强课后答案 第五章习题答案_月已满西楼的博客-CSDN博客_统计出当fabs(t) >= pow(10, -6)和fabs(t) >= pow(10, -8)时
3.输人两个正整数m和n,求其最大公约数和最小公倍数
答案解析:
该题题目直接使用“辗转相除法”来求解最大公约数,以除数和余数反复做除法运算,当余数为 0 时,就取得当前算式除数为最大公约数。
最大公约数和最小公倍数之间的性质:两个自然数的乘积等于这两个自然数的最大公约数和最小公倍数的乘积。所以,当我们求出最大公约数,就可以很轻松的求出最小公倍数。
代码示例:
#include <stdio.h>
int main()
{
int p, r, n, m, temp;
printf("请输入两个正整数n,m:");
scanf("%d%d,", &n, &m);
//调整n保存较大的值
if (n < m)
{
temp = n;
n = m;
m = temp;
}
p = n * m;
while (m != 0)
{
r = n % m;
n = m;
m = r;
}
printf("它们的最大公约数为:%d\n", n);
printf("它们的最小公倍数为:%d\n", p / n);
return 0;
}
6.求∑ n = 1 20 n ! \sum\limits_{n=1}^{20}n!
n=1
∑
20
n! (即求1!+2!+3!+4!+…+20!)。
答案解析:
该题需要从1循环到20,依次求出每一个数字阶乘的结果。所以在代码当中需要有两个循环,大循环从1到20,保证1到20个数字都被循环到,小循环里计算N阶乘,累加求和。注意:对于20的阶乘已经超出了int类型能过表示的数字范围,所以在代码当中使用double类型
代码示例:
#include<stdio.h>
int main()
{
double total_sum = 0;
for(int i = 1; i <= 20; i++)
{
double single_sum = 1;
for (int j = i; j > 0; j--)
{
single_sum *= j;
}
total_sum += single_sum;
}
printf("1~20每个数字阶乘总和为:%lf\n",total_sum);
return 0;
}
8.输出所有的“水仙花数”,所谓“水仙花数”是指一个3位数,其各位数字立方和等于该数本身。例如,153是水仙花数,因为153=1*+5*+3。
答案解析:
从题目当中得到”水仙花数“为一个3位数,则范围确定为[100, 999]。另外需要获取该数字的百位数字,十位数字,个位数字相加起来等于该数本身,则我们需要使用到%除的方式,来获取每一个位权的数字。
代码示例:
#include <stdio.h>
int main()
{
//a表示百位数字,b表示十位数字,c表示各位数字
int a, b, c;
for (int i = 100; i <= 999; i++)
{
a = i / 100;
b = (i / 10) % 10;
c = i % 10;
if (a * a * a + b * b * b + c * c * c == i)
{
printf("%d\n", i);
}
}
return 0;
}
第五章目录回顾:
5.1为什么需要循环控制110
5.2用while语句实现循环111
5.3用do…while语句实现循环113
5.4用for语句实现循环116
5.5循环的嵌套120
5.6几种循环的比较121
5.7改变循环执行的状态121
5.7.1用break语句提前终止循环122
5.7.2用continue语句提前结束本次循环123
5.7.3break语句和continue语句的区别124
5.8循环程序举例127
第6章利用数组处理批量数据
C语言总结(一维数组、二维数组、字符数组和字符串)_快乐的兔子1的博客-CSDN博客_c语言一维数组 字符串 比较
数组的定义及其理解:用来表示同一性质的数据(比如说一个班的30名同学的成绩)
数组是一组有序数据的集合。数组中各数据的排列是有一定规律的,小标代表数据在数组中的序号。
用一个数组名(如s)和下标(如15)来唯一地确定数组中的元素,如s15来唯一地确定数组中的元素,如s15 就代表第十五个学生的成绩。
数组中的每一个元素都属于同一个数据类型。不能把不同类型的数据(如学生的成绩和学生的性别)放在同一个数组中。
在计算机中只能输入有限的单个字符而无法表示上下标,C语言中就规定用方括号中的数字来表示下标,如用s[15]表示s15 ,即第15个学生的成绩。
将数组与循环相结合起来可以有效的处理大批量的数据,大大提高工作效率
怎样定义和引用一维数组
int a[10];
表示定义了一个整型数组,数组名为a,此数组中包含了10个整型元素。
注意a[10]中是从a[0]开始到a[9]结束 没有a[10]!!!
常量表达式中可以包含常量和符号常量,如inta[3+5]是合法的,不能包含变量,如int a[n];是不合法的,也就是说,C语言不允许对数组的大小作动态定义,即数据的大小不依赖于程序运行过程中变量的值。
例题:简化的插入排序
输入一个正整数 repeat (0<repeat<10),做 repeat 次下列运算:
输入一个正整数 n(0<n<=9)和一组(n个)有序的整数,再输入一个整数 x,把 x 插入到这组数据中,使该组数据仍然有序。
输入输出示例:括号内为说明
输入:
4 (repeat=4)
5 (数据的个数n=5)
1 2 4 5 7 (5个有序整数)
3 (待插入整数x=3)
4 (数据的个数n=4)
1 2 5 7 (4个有序整数)
-10 (待插入整数x=-10)
3 (数据的个数n=3)
1 2 4 (3个有序整数)
100 (待插入整数x=100)
5 (数据的个数n=5)
1 2 4 5 7 (5个有序整数)
4 (待插入整数x=4)
输出:
1 2 3 4 5 7
-10 1 2 5 7
1 2 4 100
1 2 4 4 5 7
#include <stdio.h>
int main(void)
{
int i, j, n, x;
int repeat, ri;
int a[10];
scanf("%d", &repeat);
for(ri = 1; ri <= repeat; ri++){
scanf("%d", &n);
for(i = 0; i < n; i++)
scanf("%d", &a[i]);
scanf("%d", &x);
if (x >= a[n-1]) a[n] = x; /* 特殊情况:若x比所有的元素都要大 */
else
for(i = 0; i < n; i++) {
if(x > a[i]) continue; /* 将x 插入到合适的位置*/
j = n - 1; /* 从当前要插入的位置往后移位 */
while(j >= i){
a[j+1] = a[j];
j--;
}
a[i] = x; /* 将x查到当前的位置 */
break;
}
for(i = 0; i < n + 1; i++)
printf("%d ", a[i]);
putchar('\n');
}
}
一维数组的初始化
int a[10]={0,1,2,3,}
int a[10]={0}未赋值的部分自动设定为0
用数组来求fibonacci数列问题:
#include<stdio.h>
int main()
int i;
int f[20]={1,1};
for(i=2;i<20;i++)
{
f[i]=f[i-2]+f[i-1];
for(i=2;i<20;i++)
{
if(i%5==0) printf(“\n”);
printf(“%12d”,f[i]);
}
printf(“\n”);
return 0;
}
冒泡排序例题:
(算法入门,算法的重要性!)
数字的排序:
#include <stdio.h>
#define SIZE 10
int main()
{
int a[SIZE]={12 ,43,9,13,67,98,101,89,3,35};//十个数的无序数列
int i,j,t;
printf("此程序使用冒泡排序法排列无序数列!\n");
//冒泡排序
for(i=0;i<10-1;i++)//n个数的数列总共扫描n-1次
{
for(j=0;j<10-i-1;j++)//每一趟扫描到a[n-i-2]与a[n-i-1]比较为止结束
{
if(a[j]>a[j+1])//后一位数比前一位数小的话,就交换两个数的位置(升序)
{
t=a[j+1];
a[j+1]=a[j]; //t就是一个中间量用来交换2个数的值的
a[j]=t;
}
}
}
printf("排列好的数列是:\n");
//输出排列好得数列
for(i=0;i<10;i++)
{
printf("%d ",a[i]);
}
return 0;
}
字符排序:
用函数来解决这个问题:
#include <stdio.h>
#define SIZE 10
int main()
{
char a[SIZE]={'i','l','o','v','e','y','o','u','y','x'};//十个数的无序数列
int i,j;
char t;
printf("此程序使用冒泡排序法排列无序数列!\n");
//冒泡排序
for(i=0;i<10-1;i++)//n个数的数列总共扫描n-1次
{
for(j=0;j<10-i-1;j++)//每一趟扫描到a[n-i-2]与a[n-i-1]比较为止结束
{
if(a[j]>a[j+1])//后一位数比前一位数小的话,就交换两个数的位置(升序)
{
t=a[j+1];
a[j+1]=a[j];
a[j]=t;
}
}
}
printf("排列好的字符组是:\n");
//输出排列好得吃数列
for(i=0;i<10;i++)
{
printf("%c ",a[i]);
}
return 0;
}
#include <stdio.h>
void function(char a[],int);//尤其注意,此处的函数声明必须是char a[],因为这里穿的是地址,不能仅仅使用char
int main()
{
int i;
char a[10]={'i','l','o','v','e','y','o','u','y','x'};//十个数的无序字符数列
printf("此程序使用冒泡排序法排列无序数列!\n");
function(a,10);//调用冒泡排序
printf("排列好的字符组是:\n");
//输出排列好得吃数列
for(i=0;i<10;i++)
{
printf("%c ",a[i]);
}
return 0;
}
void function(char a[],int m)
{
//冒泡排序
int i,j;
char t;
for(i=0;i<m-1;i++)//n个数的数列总共扫描n-1次
{
for(j=0;j<m-i-1;j++)//每一趟扫描到a[n-i-2]与a[n-i-1]比较为止结束
{
if(a[j]>a[j+1])//后一位数比前一位数小的话,就交换两个数的位置(升序)
{
t=a[j+1];
a[j+1]=a[j];
a[j]=t;
}
}
}
return;
}
6.2怎样定义和引用二维数组
二维数组常称为矩阵。把二维数组写成行和列的排列形式,可以有助于形象化地理解二维数组的逻辑结构。
float pay[3][6];
3*6(3行6列)
多维数组在内存中的排列顺序为:第一维的下标变化最慢,最右边的下标变化最快。例如:
a[0][0][0]>>a[0][0][1]>>a[0][0][2]>>a[0][1][0]>>a[0][1][1]>>a[0][1][2]>>a[1][0][0]
*交换行和列*
#include<stdio.h>
int main()
{
int n,m,i,j,k;
int num1,num2;//要交换的两行或两列
char ch;//决定进行行变换还是列变换
int rek;//进行几次操作
int tmp;
scanf("%d %d",&n,&m);
int arr[n][m];
//输入矩阵
for(i=0;i<n;i++)
{
for(j=0;j<m;j++)
{
scanf("%d",&arr[i][j]);
}
}
scanf("%d",&k);
for(rek=0;rek<k;rek++)
{
scanf(" %c %d %d",&ch,&num1,&num2);
if(ch=='r')//进行行变换
{
for(j=0;j<m;j++)
{
tmp=arr[num1-1][j];//进行行变换的时候约定矩阵的行不变循环递归列然后交换即可
arr[num1-1][j]=arr[num2-1][j];
arr[num2-1][j]=tmp;
}
}
else if(ch=='c')//进行列变换
{
for(i=0;i<n;i++)
{
tmp=arr[i][num1-1];//同理
进行列变换的时候约定列为需要交换的两列不变后,循环递归循环行即可。
arr[i][num1-1]=arr[i][num2-1];
arr[i][num2-1]=tmp;
}
}
}
for(i=0;i<n;i++)
{
for(j=0;j<m;j++)
{
printf("%d ",arr[i][j]);
}
printf("\n");
}
return 0;
}
6.3字符数组
字符型数据是以字符的ASCII代码存储在存储单元中的,一般占1字节
C语言中没有字符串类型,也没有字符串变量,字符串是存放在字符串数组中的。
6.3.1怎样定义字符数组
char c[10]
由于字符型数据是以整数形式(ASCII代码)存放的,因此也可以用整型数组来存放字符数据,例如:
int c[10]; //合法,但浪费存储空间
c[0]=‘a’
6.3.4字符串和字符串结束标志
C语言规定了一个“字符串结束标志”,以字符串‘\0’作为结束标志。如果字符数组中存放有若干字符,前面9个字符都不是空字符‘\0’,而第十个字符是‘\0’,则认为数组中有一个字符串,其有效字符为9个。也就是说,在遇到字符‘\0’时,表示字符串结束,把它前面的字符组成一个字符串。
注意:C系统在用字符数组存储字符串常量时会自动加一个‘\0’作为结束符。例如“C program”共有9个字符。字符串是存放在一维数组中的,在数组中占10个字节,最后有一个字节‘\0’是系统自动加上的。
说明:‘\0’代表ASCII码为0的字符,从ASCII码表中可以查到,ASCII码为0的字符不是一个可以显示的字符,而是一个“空操作符”,即它什么也不做。用它来作为字符串结束标志不会产生附加的操作或增加有效字符,只起一个供辨别的标志。
对字符串的说明:
①不能用运算符对字符串做运算
②通过数组的方式可以遍历字符串
6.3.5字符数组的输入输出
字符串的结尾有‘\0’
Char string[8];
Scanf (“%s”,string); //前面不允许加&(因为在C语言中数组名代笔该数组第一个元素的地址或者也可以说是数组的起始地址)
Printf (“%s”,string);
安全的输入:
Char string[8];
Scanf (“%7s”,string);
这个7代表:最多允许读入的字符数量,应比数组数组的大小小1
6.3.6使用字符串处理函数
注意:在使用后字符串处理函数时,应当在程序文件的开头用
#include <string.h>
puts函数——输出字符串的函数
Puts(str);
gets函数——输入字符串的函数
Gets(str);
Strcat函数———字符串连接函数
Strcat(字符数组1,字符数组2)
#include <stdio.h>
#include <string.h>
int main(void) {
char str1[6] = "hello";
char str2[6] = "world";
strcat(str1,str2);
printf("str1 = %s\n",str1);
printf("str2 = %s\n",str2);
int len = strlen(str1);
printf("len的长度:%d\n",len);
return 0;
}
说明:
字符数组1必须足够大,以便容纳连接后的新字符串
连接两个字符串的后面都有‘\0’,连接时将字符串1后面的‘\0’取消,只在最后保留‘\0’。
Strcpy和strncpy——字符串复制函数
Strcpy(字符数组1,字符串2)
Char strl[10],str2[]“china”;
Strcpy(str1;str2);
说明:
字符数组1必须足够大,以便容纳连接后的新字符串
“字符数组1”必须写出数组名形式如(str1),“字符串2”可以是字符数组名,也可以是一个字符串常量。
Strcmp——字符串比较函数
Strcmp(字符串1,字符串2)
字符串比较的规则是:将两个字符串自左向右逐个字符相比(按ASCII码值大小比较)直到出现不同的字符或者是遇到‘\0’为止。
如全部字符相同,则认为两个字符串相等;
若出现并不相同的字符,则以第1对不相同的字符的比较结果为准。
比较的结果由函数值带回:
如果字符串1与字符串2相同,则函数值为0。
如果字符串1>字符串2,则函数值为一个正整数
如果字符串1<字符串2,则函数值为一个负整数
这样使用if(strcmp(str1,str2)>0)
Printf(“yes”)
Strlen函数——测字符串长度的函数
是string length(字符串的长度)的缩写。
Char str[10]=“CHINA”
Printf(“%d”,strlen(str));
输出的结果不是10,也不是6,而是5。
Strlwr函数——转换为小写的函数
Strlwr(字符串)
是string lowercase的缩写
Strupr函数——转换为大写的函数
Strupr(字符串)
6.3.7字符数组应用举例
70013 将数组中的数逆序存放
输入一个正整数 repeat (0<repeat<10),做 repeat 次下列运算:
输入一个正整数 n (1<n<=10),再输入 n 个整数,存入数组a中,先将数组a中的这n个数逆序存放,再按顺序输出数组中的n个元素。
输入输出示例:括号内为说明
输入
2 (repeat=2)
4 (n=4)
10 8 1 2
5 (n=5)
1 2 5 4 0
输出
2 1 8 10
0 4 5 2 1
#include <stdio.h>
int main(void)
{
int i, n, temp;
int repeat, ri;
int a[10];
scanf("%d", &repeat);
for(ri = 1; ri <= repeat; ri++){
scanf("%d", &n);
for(i = 0; i < n; i++)
scanf("%d", &a[i]);
i=0;
for(i=0;i<n/2;i++){
temp=a[i];
a[i]=a[n-1-i];
a[n-1-i]=temp;
}
for(i = 0; i < n; i++)
printf("%d ", a[i]);
printf("\n");
}
}
70014 求最大值及其下标
输入一个正整数 repeat (0<repeat<10),做 repeat 次下列运算:
输入一个正整数 n (1<n<=10),再输入n个整数,输出最大值及其对应的最小下标,下标从0开始。
输入输出示例:括号内为说明
输入
3 (repeat=3)
3 (n=3)
1 6 4
4 (n=4)
10 8 1 9
5 (n=5)
1 2 0 4 5
输出
max = 6, index = 1 (最大值6的下标是1)
max = 10, index = 0 (最大值10的下标是0)
max = 5, index = 4 (最大值5的下标是4)
#include <stdio.h>
int main(void)
{
int i, index, n;
int ri, repeat;
int a[10];
scanf("%d", &repeat);
for(ri = 1; ri <= repeat; ri++){
scanf("%d", &n);
for(i = 0; i < n; i++)
scanf("%d", &a[i]);
index=0;
a[index]=a[0];
for(i = 1; i < n; i++){
if(a[index]<a[i]){
a[index]=a[i];
index=i;
}
}
printf("max = %d, index = %d\n", a[index], index);
}
}
70015 交换最小值和最大值
输入一个正整数 repeat (0<repeat<10),做 repeat 次下列运算:
输入一个正整数 n (1<n<=10),再输入 n 个整数,将最小值与第一个数交换,最大值与最后一个数交换,然后输出交换后的 n 个数。
输入输出示例:括号内为说明
输入
3 (repeat=3)
5 (n=5)
8 2 5 1 4
4 (n=4)
1 5 6 7
5 (n=5)
5 4 3 2 1
输出
After swap: 1 2 5 4 8
After swap: 1 5 6 7
After swap: 1 4 3 2 5
#include <stdio.h>
int main(void)
{
int i, index, n, t;
int repeat, ri;
int a[10];
scanf("%d", &repeat);
for(ri = 1; ri <= repeat; ri++){
scanf("%d", &n);
for(i = 0; i < n; i++)
scanf("%d", &a[i]);
index=0;
for(i = 1; i < n; i++){
if(a[i]<a[index])
index=i;
}
t=a[index]; /* 最小值与第1个数交换 */
a[index]=a[0];
a[0]=t;
index=0;
for(i = 1; i < n; i++){
if(a[i]>a[index])
index=i;
}
t=a[index]; /* 最大值与最后一个数交换 */
a[index]=a[n-1];
a[n-1]=t;
printf("After swap: ");
for(i = 0; i < n; i++)
printf("%d ", a[i]);
printf("\n");
}
}
70016 选择法排序
输入一个正整数 repeat (0<repeat<10),做 repeat 次下列运算:
输入一个正整数 n (1<n<=10),再输入 n 个整数,将它们从大到小排序后输出。
输入输出示例:括号内为说明
输入
3 (repeat=3)
4 (n=4)
5 1 7 6
3 (n=3)
1 2 3
5 (n=5)
5 4 3 2 1
输出
After sorted: 7 6 5 1
After sorted: 3 2 1
After sorted: 5 4 3 2 1
#include <stdio.h>
int main(void)
{
int i, index, k, n, temp;
int repeat, ri;
int a[10];
scanf("%d", &repeat);
for(ri = 1; ri <= repeat; ri++){
scanf("%d", &n);
for(i = 0; i < n; i++)
scanf("%d", &a[i]);
for(k=0;k<n-1;k++){
index=k;
for(i=k+1;i<n;i++)
if(a[i]>a[index])
index=i;
temp=a[index];
a[index]=a[k];
a[k]=temp;
}
printf("After sorted: ");
for(i = 0; i < n; i++)
printf("%d ", a[i]);
printf("\n");
}
}
70017 在数组中查找指定的元素
输入一个正整数 repeat (0<repeat<10),做 repeat 次下列运算:
输入一个正整数 n (1<n<=10),再输入 n 个整数,将它们存入数组 a 中,再输入一个整数 x,然后在数组 a 中查找与 x 相同的元素,如果找到,输出 x 在数组 a 中对应元素的最小下标,如果没有找到,输出相应信息。
输入输出示例:括号内为说明
输入:
2 (repeat=2)
6 (n=6)
1 3 5 7 9 5
5 (x=5)
4 (n=4)
1 3 5 7
2 (x=2)
输出:
5: a[2]
2: not found
#include <stdio.h>
int main(void)
{
int flag, i, n, x;
int repeat, ri;
int a[10];
scanf("%d", &repeat);
for(ri = 1; ri <= repeat; ri++){
flag=0; /* 若标志不重新初始化的化,就会一影响下一轮循环的计算 */
scanf("%d", &n);
for(i = 0; i < n; i++) scanf("%d", &a[i]);
scanf("%d", &x);
for (i = 0; i < n; i++) {
if(x==a[i])
{
flag = 1;
break;
}
}
if(flag != 0) printf( "%d: a[%d]\n", x, i);
else printf( "%d: not found\n", x);
}
}
70021 求矩阵各行元素之和
输入2个正整数 m 和 n (1<=m<=6, 1<=n<=6),然后输入矩阵 a(m 行 n 列)中的元素,分别求出各行元素之和,并输出。
输出使用语句:printf("sum of row %d is %d\n", i, sum);
输入输出示例:括号内为说明
输入:
3 2 (m=3,n=2)
6 3
1 -8
3 12
输出:
sum of row 0 is 9
sum of row 1 is -7
sum of row 2 is 15
#include <stdio.h>
int main(void)
{
int i, j, m, n, sum;
int a[6][6];
scanf("%d%d",&m,&n);
for(i = 0; i < m; i++)
for(j = 0; j < n; j++)
scanf("%d", &a[i][j]);
for(i = 0; i < m; i++){
sum=0;
for(j = 0; j < n; j++)
sum+=a[i][j];
printf("sum of row %d is %d\n", i, sum);
}
}
70022 矩阵运算
程序填空,不要改变与输入输出有关的语句。
输入一个正整数 repeat (0<repeat<10),做 repeat 次下列运算:
读入 1 个正整数 n(1≤n≤6), 再读入 n 阶方阵 a , 计算该矩阵除副对角线、最后一列和最后一行以外的所有元素之和。副对角线为从矩阵的右上角至左下角的连线。
输入输出示例:括号内为说明
输入:
1 (repeat=1)
4 (n=4)
2 3 4 1
5 6 1 1
7 1 8 1
1 1 1 1
sum = 35 (2+3+4+5+6+7+8=35)
#include "stdio.h"
int main(void)
{
int i, j, n, sum;
int repeat, ri;
int a[6][6];
scanf("%d", &repeat);
for(ri = 1; ri <= repeat; ri++){
scanf("%d", &n);
for(i = 0; i < n; i++)
for(j = 0; j < n; j++)
scanf("%d", &a[i][j]);
sum=0;
for(i = 0; i < n; i++){
for(j = 0; j < n; j++)
sum+=a[i][j];
}
for(i = 1; i < n-1; i++)
sum-=a[i][n-i-1]; /* 减去副对角线的元素 */
for(j =0; j <n; j++)
sum-=a[n-1][j]; /* 减去最下一行 */
for(i =0; i <n; i++)
sum-=a[i][n-1]; /* 减去最右一列 */
sum=sum+a[n-1][n-1]; /* 右下角元素减了两次,补回一次 */
printf("sum = %d\n", sum);
}
}
70023 九九乘法表
程序填空,不要改变与输入输出有关的语句。
输入一个正整数 repeat (0<repeat<10),做 repeat 次下列运算:
输入一个正整数 n(0<n<10),输出九九乘法表的前n×n项。
提示:将乘数、被乘数和乘积放入一个二维数组中,再输出该数组。
输入输出示例:括号内为说明
输入:
1 (repeat=1)
3 (n=3)
输出:
* 1 2 3
1 1
2 2 4
3 3 6 9
#include "stdio.h"
int main(void)
{
int i, j, n;
int a[10][10];
int repeat, ri;
scanf("%d",&repeat);
for(ri = 1; ri <= repeat; ri++){
scanf("%d", &n);
for(j = 0; j <= n; j++)
a[0][j]=j; /* 乘数 */
for(i = 0; i <= n; i++)
a[i][0]=i; /* 被乘数 */
for(i = 1; i <= n; i++)
for(j = 1; j <= n; j++)
a[i][j]=i*j; /* 结果 */
for(i = 0; i <= n; i++){
for(j = 0; j <= n; j++)
if(i == 0 && j == 0) printf("%-4c", '*');
else if(i == 0 || j <= i) printf("%-4d", a[i][j]);
printf("\n");
}
}
}
70024 判断上三角矩阵
输入一个正整数 repeat (0<repeat<10),做 repeat 次下列运算:
输入1 个正整数 n (1≤n≤6)和 n 阶方阵 a 中的元素,如果 a 是上三角矩阵, 输出"YES", 否则, 输出"NO"。上三角矩阵指主对角线以下的元素都为0的矩阵, 主对角线为从矩阵的左上角至右下角的连线。
输入输出示例:括号内为说明
输入:
2 (repeat=2)
3 (n=3)
1 2 3
0 4 5
0 0 6
2 (n=2)
1 0
-8 2
输出:
YES
NO
#include "stdio.h"
#include "math.h"
int main(void)
{
int flag, i, j, n;
int a[6][6];
int repeat, ri;
scanf("%d", &repeat);
for(ri = 1; ri <= repeat; ri++){
scanf("%d", &n);
for(i = 0; i < n; i++)
for(j = 0; j < n; j++)
scanf("%d", &a[i][j]);
flag=1;
for(i = 0; i < n; i++){
for(j = 0; j < i; j++){
if(a[i][j]!=0){
flag=0; break; /* 只要一个数值不满足就可以否定 */
}
}
if (!flag) break;
}
if(flag != 0) printf("YES\n");
else printf("NO\n");
}
}
第六章课后习题:
谭浩强 C语言程序设计第五版 第六章 习题 答案_月已满西楼的博客-CSDN博客_月已满西楼谭浩强
3. 求一个3 X 3的整形矩阵对角线元素之和
【答案解析】
矩阵:即二维数组,矩阵行和列相等的二维数组称为方阵。
1 2 3
4 5 6
7 8 9
左上角到右下角对角线上数字:行下标和列下标相加
右上角到左下角对角线上数字:列下标减1 行下标加一
通过两个循环来取到对角线上的元素,并对其求和即可。
【代码实现】
#include<stdio.h>
int main()
{
int array[3][3];
int sumLT2RB = 0; // 标记左上角到右下角对角线元素之和
int sumRT2LB = 0; // 标记右上角到左下角对角线元素之和
printf("请输入3行3列的矩阵:\n");
for (int i = 0; i < 3; ++i)
{
for (int j = 0; j < 3; ++j)
scanf("%d", &array[i][j]);
}
// 左上角到右下角对角线
for (int i = 0; i < 3; ++i)
sumLT2RB += array[i][i];
for (int i = 0, j = 2; i < 3; ++i, j--)
sumRT2LB += array[i][j];
printf("左上角到右下角对角线元素之和: %d\n", sumLT2RB);
printf("右上角到左下角对角线元素之和: %d\n", sumRT2LB);
return 0;
}
5. 将一个数组中的值按逆序重新存放。例如:原来顺序为8,6,5,4,1。要求改为1,4,5,6,8。
【答案解析】
该题为数组的逆置,具体处理方式如下:
如果begin < end时,则循环进行一下操作
给定两个下标begin和end,begin放在数组起始的位置,end放在数组最后一个元素的位置
交换begin和end位置的元素
begin往后移动,end往前移动
【代码实现】
#include<stdio.h>
int main()
{
int array[5] = {8,6,5,4,1};
int begin = 0, end = 4;
printf("逆序之前数组为:");
for (int i = 0; i < 5; ++i)
printf("%d ", array[i]);
printf("\n");
// 逆序:begin在数组最左侧,end在数组最右侧
// 只要begin < end,将begin和end位置元素进行交换
// 然后begin往后移动一步,end往前移动一步
while (begin < end)
{
int temp = array[begin];
array[begin] = array[end];
array[end] = temp;
begin++;
end--;
}
printf("逆置之后数组为:");
for (int i = 0; i < 5; ++i)
printf("%d ", array[i]);
printf("\n");
return 0;
}
第六章目录回顾:
6.1怎样定义和引用一维数组139
6.1.1怎样定义一维数组140
6.1.2怎样引用一维数组元素140
6.1.3一维数组的初始化142
6.1.4一维数组程序举例142
6.2怎样定义和引用二维数组145
6.2.1怎样定义二维数组146
6.2.2怎样引用二维数组的元素147
6.2.3二维数组的初始化148
6.2.4二维数组程序举例149
6.3字符数组151
6.3.1怎样定义字符数组151
6.3.2字符数组的初始化152
6.3.3怎样引用字符数组中的元素152
6.3.4字符串和字符串结束标志153
6.3.5字符数组的输入输出156
6.3.6使用字符串处理函数157
6.3.7字符数组应用举例162
用函数实现模块化程序设计
7.1为什么要用函数
为了更好的实现模块化程序设计 函数(function)也有功能的意思
7.2怎样定义函数
为什么要定义函数?
事先编辑好的功能,编译系统按照定义的功能去执行
定义函数应包括以下内容:
指定函数的名字,以便以后按名调用
指定函数的类型,即函数返回值的类型
指定函数的参数的名字和类型,以便在调用函数时向它们传递数据。对无参函数不需要这项
指定函数应该完成什么操作,也就是函数是做什么工作的,即函数的功能
定义函数的方法:
定义无参函数的方法:
函数名()
{
函数体
}
或者
函数名(void)
{
函数体
}
函数体内包含声明部分和语句部分
定义有参函数
函数程序设计
编写一个函数,利用参数传入一个3位数number,找出101~number之间所有满足下列两个条件的数:
它是完全平方数,又有两位数字相同,如144、676等,函数返回找出这样的数据的个数。请同时编写主函数。
例:(括号内为说明)
输入
3 (repeat=3)
150
500
999
输出
count=2
count=6
count=8
#include <stdio.h>
#include <string.h>
int search(int n); //对函数的声明
int main(void)
{
int number,ri,repeat;
scanf("%d",&repeat);
for(ri=1;ri<=repeat;ri++){
do{
scanf("%d",&number);
}while(number<101||number>999);
printf("count=%d\n",search(number));
}
return 0;
}
int search(int n) //对函数的定义
{
int i,j,a1,a2,a3, flag=0;
for (i = 101; i <= n; i++)
{
for (j = 1; j <= i; j++)
{
if (j * j == i)
{
a1 = i % 10;
a2 = i / 10 % 10;
a3 = i /100 % 10;
if ( (a1==a2)||(a1==a3) || (a2==a3) )
{
flag += 1;
break;
}
}
}
}
return flag;
}
定义有参函数的一般形式:
函数名(形式参数表列)
{
函数体
}
7.3调用函数
7.3.1函数调用的形式171
计算函数P(n,x) (函数递归)
输入一个正整数repeat (0<repeat<10),做repeat次下列运算:
输入一个整数n (n>=0)和一个双精度浮点数x,输出函数p(n,x)的值(保留2位小数)。
[1 (n=0)
p(n, x) = [x (n=1)
[((2*n-1)*p(n-1,x)-(n-1)*p(n-2,x))/n (n>1)
例:括号内是说明
输入
3 (repeat=3)
0 0.9 (n=0,x=0.9)
1 -9.8 (n=1,x=-9.8)
10 1.7 (n=10,x=1.7)
输出
p(0, 0.90)=1.00
p(1, -9.80)=-9.80
p(10, 1.70)=3.05
#include <stdio.h>
double p(int n, double x); //对函数的声明
int main(void)
{
int repeat, ri;
int n;
double x, result;
scanf("%d", &repeat);
for(ri = 1; ri <= repeat; ri++)
{
scanf("%d%lf", &n, &x);
result = p(n, x);
printf("p(%d, %.2lf)=%.2lf\n", n, x, result);
}
}
double p(int n, double x) //对函数的定义
{
double t;
if(n==0) t=1;
else if(n==1)
t=x;
else
t=((2*n-1)*p(n-1,x)-(n-1)*p(n-2,x))/n;
return t;
}
7.3.2函数调用时的数据传递
形式参数和实际参数
在定义函数时函数名后面的括号中的变量名称为“形式参数”或“虚拟参数”。
在主调函数中调用一个函数时,函数名后面括号中的参数称为“实际参数”。
实际参数可以是常量,变量或表达式。
实参和形参间的数据传递
在调用函数过程中,系统会把实参的值传递给被调用函数的形参。也可以这么理解,形参从实参得到一个值。该值在函数调用期间有效,可以参加该函数的运算。
7.3.3函数调用的过程
一个函数只能有一个返回值,(想返回多个可以参考后面的指针中的内容)
如果函数不需要返回值,则不需要return语句,这是函数的类型应定义为void类型。
7.4对被调用函数的声明和函数原型
在一个函数中调用另一个函数(即被调用函数)需要具备以下条件:
首先被调用的函数必须是已经定义的函数(是库函数或用户自己定义的函数)
如果使用库函数,应该在本文件开头用#include指令将调用有关库函数时所需用到的信息“包含”到本文件中去
#include<stdio.h>在stdio.h文件中包含了输入输出库函数的声明
使用数学库中的函数,应使用#include<math.h>
(3)如果使用用户自己定义的函数,而该函数的位置在调用它的函数(即主调函数)的后面(在同一文件中),应该在主调函数中被调用的函数作声明(declaration)。声明的作用是把函数名,函数参数的个数和参数类型等信息通知编译系统,以便在遇到函数调用时,编译系统能正确识别函数并检查调用是否合法。
思考总结:
可以发现,函数的声明和函数定义中的第1行(函数首部)基本上是相同的。只差一个分号(函数声明比函数定义中的首行多一个分号)
为什么要用函数的首部来作为函数声明呢?
这是为了对函数调用的合法性进行检查。因为在函数的首部包含了检查调用函数是否合法的基本信息(包含了函数名,函数值类型,参数个数,参数类型和参数顺序),在检查函数调用时要求函数名,函数类型,参数个数,参数类型和参数顺序必须和函数声明一致,实参类型必须与函数声明中的形参类型相同,这样就能保证函数的正确调用。
函数的“定义”和‘声明’并不是同一回事
函数的定义是指对函数功能的确立,包括指定函数名,函数值类型,形参及其类型以及函数体等,它是一个完整的,独立的函数单位。
而函数的声明的作用则是把函数名,函数值类型,参数个数,参数类型和参数顺序通知编译系统,以便在调用该函数时系统按此进行对照检查(例如:函数名,函数值类型,参数个数,参数类型和参数顺序),他不包含函数体。
7.5函数的嵌套调用
C语言的函数定义是互相平行,独立的,也就是说,在定义函数时,一个函数内不能再定义另一个函数,即不能嵌套定义,但可以嵌套调用函数,即在调用一个函数的过程中,又调用另一个函数。
7.6函数的递归调用
在调用一个函数的过程中又出现直接或间接地调用该函数本身,称为函数的递归调用。
C语言函数递归调用_外太空程序员的博客-CSDN博客_c语言函数的递归调用
范例:计算5的阶乘,其实就是计算 1*2*3*4*5,
我们并不知道5的阶乘是多少,但是我们知道一点,4的阶乘 * 5他就等于5的阶乘。
我们并不知道4的阶乘是多少,但是我们知道一点,3的阶乘 * 4他就等于4的阶乘。
我们并不知道3的阶乘是多少,但是我们知道一点,2的阶乘 * 3他就等于3的阶乘。
所以递归调用的出口肯定是在1的阶乘,因为1的阶乘是1,可以作为出口,我们能够求出2的阶乘,也就是1*2;以此类推。
#include<stdio.h>
// 函数声明
int dg_jiecheng(int n);
int main() //主函数
{
int result = dg_jiecheng(5);
printf("result=%d\n",result); // 结果为120
}
// 函数定义
int dg_jiecheng(int n)
{
int result; // 局部变量,保存阶乘结果
if(n==1) // 1的阶乘就是1
{
return 1; // 这里就是该递归调用的出口
}
else
{
// 第一次是 result = dg_jiecheng(4)*5,然后进入到了 dg_jiecheng(4),这行代码就被暂存了;
第二次是 result = dg_jiecheng(3)*4,然后进入到了 dg_jiecheng(3),这行代码就被暂存了;
第三次是 result = dg_jiecheng(2)*3,然后进入到了 dg_jiecheng(2),这行代码就被暂存了;
第四次是 result = dg_jiecheng(1)*2,然后进入到了 dg_jiecheng(1),这行代码就被暂存了;
此时,dg_jiecheng(1)的出口条件成立了,终于,能够执行return 1,这可是 return 语句第一次捞着执行。
第一次:return 1,返回的是1,返回到dg_jiecheng(2)这里:
return =1*2 并且也执行return result;,返回1*2=2;
返回到dg_jiecheng(3)这里:
return =2 并且也执行return result;,返回2*3=6;
返回到dg_jiecheng(4)这里:
return =6 并且也执行return result;,返回6*4=24;
返回到dg_jiecheng(5)这里:
return =24 并且也执行return result;,返回24*5=120;
result = dg_jiecheng(n-1)* n;
}
return result;
}
递归的优缺点
优点:
代码少,代码看起来简洁,精妙。
缺点:
虽然代码简洁,精妙,但是不好理解。
如果调用的层次太深,调用栈(内存),可能会溢出,如果真出现这种情况,那么说明不能用递归解决该问题。
效率和性能都不高,这深层次的调用,要保存的东西很多,所以效率和性能肯定高不起来。有些问题用不用递归都行,有些问题可能必须用递归解决。汉诺塔
递归函数的直接和间接调用:
递归函数的直接调用:调用递归函数f的过程中,f函数有调用自己,这就是直接调用。
递归函数的间接调用:调用函数f1的过程中要调用f2函数,然后f2函数又调用f1函数,这就是间接调用。
7.7数组作为函数参数
编程题(指针数组)
输入一个正整数repeat (0<repeat<10),做repeat次下列运算:
编写程序,输入一个月份,输出对应的英文名称,要求用指针数组表示12个月的英文名称。
若输入月份错误,输出提示信息。
输入输出示例:括号内为说明
输入:
3 (repeat=3)
5
9
14
输出:
May
September
Wrong input!
#include<stdio.h>
void main()
{
int ri,repeat;
int month;
char *month_name[]={"","January","February","March","April","May","June","July","August","September","October","November","December"};
scanf("%d",&repeat);
for(ri=1;ri<=repeat;ri++){
scanf("%d",&month);
if((month>=1)&&(month<=12))
puts(month_name[month]);
else
printf("Wrong input!");
}
}
编程题 (指针数组,查找相同的字符串)
程序填空,不要改变与输入输出有关的语句。
输入一个正整数repeat (0<repeat<10),做repeat次下列运算:
定义一个指针数组将下表的星期信息组织起来,输入一个字符串,在表中查找,若存在,输出该字符串在表中的序号,否则输出-1。
(表格详见实验教材P99)
输入输出示例:括号内为说明
输入:
3 (repeat=3)
Tuesday
Wednesday
year
输出:
3
4
-1
#include<stdio.h>
#include<string.h>
void main()
{
int i,ri,repeat,dateNum;
char *date[]={"Sunday","Monday","Tuesday","Wednesday","Thursday","Friday","Saturday"};
char str[80];
scanf("%d",&repeat);
getchar();
for(ri=1;ri<=repeat;ri ++){
scanf("%s",str);
/*---------*/
dateNum=sizeof(date)/sizeof(char *);
for (i = 0; i<dateNum; i++){
if (strcmp(date[i],str) == 0) {
printf("%d\n",i+1); break;
}
}
if (i==dateNum) printf("%d\n",-1);
}
}
计算最长的字符串长度
编写一个函数int max_len(char *s[ ], int n),用于计算有n(n<10)个元素的指针数组s中最长的字符串的长度,并编写主程序验证。
例:(括号内为说明)
输入
4 (n=4)
blue
yellow
red
green
输出
length=6
#include <stdio.h>
#include <string.h>
int max_len(char *s[],int n);
void main()
{
int i,n;
char s[10][80],*p[10];
scanf("%d",&n);
for(i=0;i<n;i++){
scanf("%s",s[i]);
p[i]=s[i];
}
printf("length=%d\n",max_len(p,n));
}
int max_len(char *s[],int n)
{
int max,i;
max=strlen(s[0]);
for(i=1;i<n;i++)
if(max<strlen(s[i]))
max=strlen(s[i]);
return max;
}
静态局部变量的值(static局部变量):
有时希望函数中的局部变量的值在函数调用结束后不消失而继续保留原值,即其占用的存储单元不释放,在下一次调用该函数时,该变量已有值(就是上一次函数调用结束时的值),这时就应该指定该局部变量为“静态局部变量”,用关键字static进行声明。
自动变量(auto变量)
函数中的局部变量,如果不专门声明为static(静态)存储类别,都是动态地分配存储空间的,数据存储在动态存储去中,函数中的形参和在函数中定义的局部变量(包括在复合语句中定义的局部变量),都属于此类。在调用该函数时,系统会给这些变量分配存储空间,在函数调用结束时就自动释放这些存储空间。
实际上,关键字auto可以省略,不写auto则隐含指定为“自动存储类别”
int b,c=3 ========== auto int b,c=3
第七章课后题
C语言程序设计第五版谭浩强 第七章答案_月已满西楼的博客-CSDN博客_c语言第七章课后题答案
第七章目录回顾:
第7章用函数实现模块化程序设计167
7.1为什么要用函数167
7.2怎样定义函数169
7.2.1为什么要定义函数169
7.2.2定义函数的方法170
7.3调用函数171
7.3.1函数调用的形式171
7.3.2函数调用时的数据传递172
7.3.3函数调用的过程174
7.3.4函数的返回值174
7.4对被调用函数的声明和函数原型176
7.5函数的嵌套调用179
7.6函数的递归调用181
7.7数组作为函数参数189
7.7.1数组元素作函数实参189
7.7.2一维数组名作函数参数191
7.7.3多维数组名作函数参数194
7.8局部变量和全局变量196
7.8.1局部变量196
7.8.2全局变量197
*7.9变量的存储方式和生存期201
7.9.1动态存储方式与静态存储方式201
7.9.2局部变量的存储类别202
7.9.3全局变量的存储类别205
7.9.4存储类别小结209
7.10关于变量的声明和定义211
*7.11内部函数和外部函数212
7.11.1内部函数212
7.11.2外部函数213