二十七.for循环
1.阶乘
n!=1*2*3*…*n-1*n
写一个程序,让用户输入n,然后计算出n!
变量:需要三个变量,用户读入需要一个int的n,每次计算的结果用一个变量保存,可以是int的factor,在计算过程中需要一个变量不断地从1递增到n,可以是int的i
从式子上看:变量n就是n!的n;变量factor就是计算到某一步骤(eg1*2*3)时保存结果的变量;变量i就是表示计算到某一步骤时所需数的个数
int n;
scanf("%d",&n);
int fact=1;//fact和i初始化都是1,你如果从低到高算阶乘
int i=1;//第一个数和第一个数的个数都是1
while(i<=n){//理解为此时参与运算到达的n或个数<=n
fact*=i;//fact=fact*i,也就是某个阶段的阶乘,eg1*2*3时
i++; //i加个1
}
printf("%d!=%d\n",n,fact);
2.for()内条件讲解
int n;
scanf("%d",&n);
int fact=1;
int i=1;
for (i=1;i<=n;i++){
fact*=i;
}
printf("%d!=%d\n",n,fact);
i=1;初始条件
i<=n;循环继续的条件
i++;循环每一轮要做的动作
调试
在for循环开始设置断点,调试输入4
for (i=1;i<=n;i++){
fact*=i;
这两段代码都会改变变量的值
3.for循环
像一个计数循环:设定一个计数器,初始化,在计数器到达某值之前,重复执行循环体,而每执行一轮循环,计数器值以一定步进进行调整,比如加1或减1
for (i=0;i<5;i=i+1){
printf("%d",i)
}
4.for=对于
for (count=10;count>0;count--)
读成:对于一开始的count=10,当count>0时,重复做循环体,每一轮循环在做完循环体内语句后,使得count--
5.小套路
做求和的程序时,记录结果的变量应该初始化为0,而做求积的变量时,记录结果的变量应该初始化为1
在这里变量应该是fact,也就是每次计算的结果用一个变量保存,可以是int的factor(fact),如果是0的话,乘起来永远都是0
6.循环控制变量i
循环控制变量i只在循环里被使用了,循环外面没有任何用处,因此可以把变量i的定义写到for语句里面
int n;
scanf("%d",&n);
int fact=1;
for (int i=1;i<=n;i++){
fact*=i;
}
printf("%d!=%d\n",n,fact);
![]()
for循环的初始化的声明只能在c99模式使用,某些说c99可以用的编译器也用不了
需要在编译代码时加上一个特殊的编译选项-std=c99
const int 变量=常量;可以用,这个用不了
7.尝试不从1开始
1*1=1,所以程序不需要从1开始,改成从多少到多少合适?
for (i=1;i<=n;i++){
fact*=i;
}
这段for循环,第一轮下来i还是1,第二轮1行开始才等于2,而fact第一轮下来还是1
for (i=2;i<=n;i++){
fact*=i;
}
运行下来看似没有问题,但是当n=1时,i>n了,跳过整个for循环了,输出定义fact时初始化为1的值,刚好是正确结果,能用就行ovo
8.尝试反过来
从n到1计算阶乘,这时候还需要循环控制变量i吗?
for (i=n;i>1;i--){//i>=2也可以
fact*=i;
}
既然i是从n到2的,不要i了,用n怎么办?
int n;
scanf("%d",&n);
int fact=1;
int a=n;
for (n=n;n>1;n--){
fact*=n;
}
printf("%d!=%d\n",a,fact);
n=n;也可以去掉,啥事情都没有做
所以,对于for循环的三个表达式,可以省去一个的(每一个)
二十八.循环的计算和选择
1.循环次数
for(i=0;i<n;i++)
则循环次数是n(从0到n),循环结束以后,i的值是n
循环控制变量i,是选择从0开始还是从1开始,是判断i<n还是判断i<=n
程序都是走五遍,但是具体i的值不一样
int i;
for(i=0;i<5;i++){
printf("i=%d",i);
}
printf("\n最后i=%d\n",i);

循环五次,i=5
int i;
for(i=1;i<=5;i++){
printf("i=%d",i);
}
printf("\n最后i=%d\n",i);
![]()
循环五次,i=6
2.for循环和while循环的联系
for循环和while循环是等价的
//for循环
for(int i=1;i<=n;i++){
fact*=i;
}
//while循环
int i=1;
while(i<=n){
fact*=i;
i++;
}
for(初始条件;条件;每轮的动作){
}
for循环中的每一个表达式都是可以省略的
for(;条件;)==while(条件)
3.三种循环流程图
for循环

while循环:先条件再循环

do-while循环:先循环再条件

4.三种循环选取
如果有固定次数,用for
如果必须执行一次,用do-while
其他情况用while
二十九.循环控制
1.素数
只能被1和自身整除的整数,叫做素数
2,3,5,7,11,13,17,19
int x;
scanf("%d",&x);
int i;
for(i=2;i<x;i++){//i相当于除数,看素数定义,初始化1和=x没意义
if(x%i==0){//看x能不能被i(非1和x自身)整除
printf("不是素数\n");//能就输入不是素数
}
}
printf("是素数\n");//再输出是素数
这段代码有两个问题,你输入非素数可以跑通,但是你输入一个素数比如6,i=2或3时这两段for循环都会输出不是素数,for循环结束还会输出是素数,还有6/2时就知道6不是素数了,能不能不做6/3

2.isPrime
解决第一个问题:你输入非素数可以跑通,但是你输入一个素数比如6,i=2或3时这两段for循环都会输出不是素数,for循环结束还会输出是素数
int x;
scanf("%d",&x);
int i;
int isPrime=1;//=1是用来判断x是素数,证明作用
for(i=2;i<x;i++){//i相当于除数,看素数定义,初始化1和=x没意义
if(x%i==0){//看x能不能被i(非1和x自身)整除
isPrime=0;//不是素数
}
}
if(isPrime==1){
printf("是素数\n");
} else{
printf("不是素数\n");
}
3.break
解决第二个问题:6/2时就知道6不是素数了,能不能不做6/3
在for循环后面加一个break;
for(i=2;i<x;i++){
if(x%i==0){
isPrime=0;
break;
}
}
break:跳过整个for循环
4.continue
break是跳过整个for循环,continue是不做此次循环后面的语句,重新下一轮循环
break你吃面飞进去一个苍蝇,你不吃了;continue你换一碗
5.break和continue流程图

6.新的处理
int x;
scanf("%d",&x);
int i;
for(i=2;i<x;i++){
if(x%i==0){
break;
}
}
if(i==x){
printf("是素数\n");
} else{
printf("不是素数\n");
}
三十.循环的嵌套
1.100以内的素数
如何写程序输出100以内的素数?
int x;
for(x=1;x<100;x++){//让第二个for循环的x使用这个for循环中的x
int i;
int isPrime=1;
for(i=2;i<x;i++){
if(x%i==0){
isPrime=0;
break;
}
}
if(isPrime==1){
printf("%d ",x);
} //因为输出100内的素数,所以不需要输出不是素数
}
printf("\n");//美观

这个是错误结果,当时把i和isPrime定义在外层for循环外边了
![]()
2.嵌套的循环
循环里面还是循环
for和while也可以
注意:外边的循环控制变量是x,里面的循环的控制变量是i,两个循环的控制变量需要不一样
上面遇到的问题会不会出现在这里?以后定义循环控制变量还是在对应的循环上
3.输出50个素数
int x;
x=1;
int cnt=0;//计数器
while(cnt<50){
int i;
int isPrime=1;
for(i=2;i<x;i++){
if(x%i==0){
isPrime=0;
break;
}
}
if(isPrime==1){
printf("%d ",x);
cnt++;//计数
}
x++;//while循环里面的,原来for循环里面也有x++
}
printf("\n");
4.用for循环嵌套怎么做
int x;
x=1;
int cnt=0;
for(x=1;cnt<50;x++){//计数器<50
int i;
int isPrime=1;
for(i=2;i<x;i++){
if(x%i==0){
isPrime=0;
break;
}
}
if(isPrime==1){
printf("%d ",x);
cnt++;
}
}//不用while循环了,在for里面x++
printf("\n");
但是这种情况可能会让人疑惑
for(x=1;cnt<50;x++){
条件是cnt和x无关
三十一.从嵌套的循环中跳出
1.凑硬币
如何用1角、2角和5角的硬币凑出10元以下的金额
int x;
int one,two,five;
scanf("%d",&x);
for(one=1;one<x*10;one++){//初始one=1,one<x*10换算单位,one加1
for(two=1;two<x*10/2;two++){
for(five=1;five<x*10/5;five++){
if(one+two*2+five==x*10){//另一种情况,还有别的,最后试试
printf("可以用%d个1角加%d个2角加%d个5角得到%d元\n",
one,two,five,x);
}
}
}
}

2.break在嵌套循环使用
希望只得到一个结果怎么办,加一个break会怎么样
for(one=1;one<x*10;one++){
for(two=1;two<x*10/2;two++){
for(five=1;five<x*10/5;five++){
if(one+two*2+five==x*10){
printf("可以用%d个1角加%d个2角加%d个5角得到%d元\n",
one,two,five,x);
}break;
}
}
}
因为break是跳出当前for循环,所以要设置多个break
int x;
int one,two,five;
scanf("%d",&x);
for(one=1;one<x*10;one++){
for(two=1;two<x*10/2;two++){
for(five=1;five<x*10/5;five++){
if(one+two*2+five==x*10){
printf("可以用%d个1角加%d个2角加%d个5角得到%d元\n",
one,two,five,x);
break;
}
}break;
}break;
}
但是这样无论什么情况都会跳出break,应该是在某个条件下发生
3.接力break
设置一个变量exit
int x;
int one,two,five;
int exit=0;
scanf("%d",&x);
for(one=1;one<x*10;one++){
for(two=1;two<x*10/2;two++){
for(five=1;five<x*10/5;five++){
if(one+two*2+five==x*10){
printf("可以用%d个1角加%d个2角加%d个5角得到%d元\n",
one,two,five,x);
exit=1;
break;
}
}if(exit) break;//exit==1
}if(exit) break;
}
4.goto
int x;
int one,two,five;
scanf("%d",&x);
for(one=1;one<x*10;one++){
for(two=1;two<x*10/2;two++){
for(five=1;five<x*10/5;five++){
if(one+two*2+five==x*10){
printf("可以用%d个1角加%d个2角加%d个5角得到%d元\n",
one,two,five,x);
goto out;
}
}
}
}
out:
我感觉goto挺好用的,但是讲解表示goto在历史上有不好的名声,破坏了程序的结构性,建议在特定条件下用goto,比如这样跳出三界之外
三十二.前n项求和
1.求前n项和
f(n)=1+1/2+1/3+1/4+…+1/n
int n;//n就是一共有几个数
int i;//i就是1/1,1/2,1/3...1/n的分母
double sum=0.0;//sum是浮点数,用0.0
scanf("%d",&n);
n=10;
for(i=1;i<=n;i++){
sum+=1.0/i;//1/i,i>1(除非i=1时),整数运算结果去掉小数点了
} //一个浮点数和整数运算,会把整数变成浮点数
printf("f(%d)=%f\n",n,sum);
2.变式
f(n)=1-1/2+1/3-1/4+…+1/n
int n;
int i;
double sum=0.0;
int sign=1;
scanf("%d",&n);
n=10;
for(i=1;i<=n;i++){
sum+=sign*1.0/i;
sign=-sign;
}
printf("f(%d)=%f\n",n,sum);
f(n)趋于某个值
另一个做法
int n;
int i;
double sum=0.0;
double sign=1.0;
scanf("%d",&n);
n=10;
for(i=1;i<=n;i++){
sum+=sign/i;
sign=-sign;
}
printf("f(%d)=%f\n",n,sum);
三十三.整数分解
1.正序分解整数
输入一个非负整数,正序输出它的每一位数字
输入:13425
输出:1 3 4 2 5
先看看逆序
int x;
scanf("%d",&x);
do{//必须先执行一次,用do-while循环
int d=x%10;//得出个位数
printf("%d",d);//打印个位数
if(x>9){//或x>=10,目的是终端输出最后一个不要空格,10/10是1,10/9是0
printf(" ");
}
x/=10;//去掉个位数,十位数变成新的个位数
}while(x>0);
printf("\n");
![]()
正序
先做整数求逆
int x;
scanf("%d",&x);
int t=0;//t来构建逆序后的数
do{
int d=x%10;//每一轮取出最右边的结果
t=t*10+d;//把最右边的结果放在左边
x/=10;//丢掉最右边的数
}while(x>0);
printf("t=%d\n",t);
do{
int d=x%10;
printf("%d",d);
if(x>9){
printf(" ");
}
x/=10;
}while(x>0);
printf("\n");

反过来了,但是没有分解整数
printf("x=%d,t=%d\n",x,t);
因为下面的x失去了作用,因为x/=10,最后x变成0了
因为t是52431,用x代替
printf("x=%d,t=%d\n",x,t);
x=t;

正确
但是输入700呢?

所以先逆序再分解的方法只实用于末尾没有0的情况
三位数逆序问题
13425/10000=1
13425&10000=3425
10000/10=1000
3425/1000=3
3424%1000=425
…
25/10=2
25%10=5
10/10=1
5/1=5
5%1=0
1/10=0
//13425/10000=1
//13425&10000=3425
//10000/10=1000
//...
int x;//13425
scanf("%d",&x);
int mask=10000;//10000
do{
int d=x/mask; //d=13425/10000
x%=mask;//x=x%10000
mask/=10;//mask=mask/10
printf("x=%d,mask=%d,d=%d",x,mask,d);
}while(x>0);
printf("\n");

70000怎么样

不对
让mask>0

正确
int x;
scanf("%d",&x);
int mask=10000;
do{
int d=x/mask;
printf("%d",d);
if(mask>9){
printf(" ");
}
x%=mask;
mask/=10;
}while(mask>0);
printf("\n");
![]()
可是现在mask是固定值,怎样通过x来计算出mask
计数器
int x;
scanf("%d",&x);
int mask=1;
int t=x;
while(t>9){
t/=10;
mask*=10;
}
printf("x=%d,mask=%d\n",x,mask);
do{
int d=x/mask;
printf("%d",d);
if(mask>9){
printf(" ");
}
x%=mask;
mask/=10;
}while(mask>0);
printf("\n");
三十四.求最大公约数
1.求最大公约数
输入两个数a和b,输出它们的最大公约数
输入:12 18
输出:6
2.枚举
设t为2
如果u和v都能被t整除,则记下这个t
t加1后重复第2步,直到t等于u或v
那么,曾经记下的最大的可以同时整除u和v的t就是gcd
int a,b;
int min;
scanf("%d %d",&a,&b);
if(a<b){
min=a;
}else{
min=b;
}
int ret=0;
int i;
for(i=1;i<min;i++){
if(a%i==0){
if(b%i==0){
ret=i;
}
}
}
printf("%d和%d的最大公约数是%d\n",a,b,ret);
3.辗转相除法
如果b等于0,计算结束,a就是最大公约数
否则,计算a除以b的余数,让a等于b,而b等于那个余数
回到第一步
/*如果b等于0,计算结束,a就是最大公约数
否则,计算a除以b的余数,让a等于b,而b就是那个余数
回到第一步
a b 余数t
12 18 12
18 12 6
12 6 0
6 0*/
#include<stdio.h>
int main()
{
int a,b;
int t;
scanf("%d %d",&a,&b);
while(b!=0){
t=a%b;
a=b;
b=t;
printf("a=%d,b=%d,t=%d\n",a,b,t);
}
printf("gcd=%d\n",a);
return 0;
}

4万+



被折叠的 条评论
为什么被折叠?



