C语言循环结构细讲

1.

求 y = 1+2+3+4+5...+100的值

int i = 1;//加数

int sum = 0;//和

0 + 1 = 1

1 + 2 = 3;

1 + 2 + 3 = 6;

1 + 2 + 3 + 4 = 10;

。。。

sum = sum + i;

i++;

sum = sum + i;

i++;

sum = sum + i;

i++;

。。

循环的本质就是重复

C语言中可以达到循环效果的语句

(1)goto语句与if构成的

(2)while

(3)do while

(4)for

(1)goto语句

goto 目标地点(在C语言中,某条指令的地址)

“指令地址” :语句标号 (它下面那条指令的地址)

“语句标号”:名字

语句标号前面只允许有空白字符

名字必须符合C语言中标识符的规定

loop:

i++;

goto loop;

语法形式:

goto 语句标号;

eg:

把求1~100的和用goto语句实现

int i = 1;//加数

int sum = 0;//和

loop:

sum = sum+i;

i++;

if(i < 100)

{

goto loop;

}

注意:

主张限制使用goto语句

如果乱用goto语句,会使程序的可读性很差

(2)while循环

语法形式:

while(表达式)

循环体语句

当 “表达式”的值为真(非0),就执行“循环体语句”

然后,在判断“表达式”的值,如果为真(非0),就继续执行“循环体语句”

.....

直到“表达式”的值为假(0)为止(循环结束)

“表达式” :C语言中任意合法的表达式

“循环体语句”:

单语句 :只有有一个;语句

复合语句

{}/if/switch/for/while/do_while

eg:

while(i < 100)

{

i++;

sum = sum +i;

}

=>编程建议

不管while后面有没有语句,先打一对{}

表示他的“管辖范围”

练习:

输入一个整数,以逆序的顺序输出

12345

=>54321

n = 12345;

x = 12345%10

printf("%d",x);

....

step1:

求取个位数

step2:

打印

========

step1:

求取个位数

step2:

打印

step3:

把个位数拿到

while(n != 0)

{

//step1:求取个位数

x = n%10;

//step2:打印

printf("%d",x);

//step3:把个位数拿掉

n = n/10;

}

(3)do while

语法形式:

do

循环体语句

while(表达式);

先执行“循环体语句”,然后在判断“表达式”的值,

当表达式的值为真(非0),返回去执行上面的“循环体语句”,然后再一次

判断“表达式”的值,如果为真,返回去执行上面的“循环体语句”,

直到“表达式”的值为假(0),循环结束

“表达式” :C语言中任意合法的表达式

“循环体语句”:

单语句 :只有有一个;语句

复合语句

{}/if/switch/for/while/do_while

eg:

do

i++;

sum = sum+i;

while(I < 100);

这个代码是有语句错误

=>编程建议

不管do后面有没有语句,先打一对{}

表示他的“管辖范围”

do

{

循环体语句

}while(表达式);

练习:

求n! (n由用户输入)

4!

4*3*2*1

类乘

int i = 1;

int s = 1;

do

{

s = s*i;

i++;

}while(i <= n);

(4)for循环

语法形式:

for(表达式1;表达式2;表达式3)

循环体语句

先做“表达式1”(仅仅执行一次),然后再去判断“表达式2”的值

如果为真(非0),则执行“循环体语句”,

执行完“循环体语句”,在执行“表达式3”

在判断“表达式2”的值,如果为真(非0),则执行“循环体语句”,

执行完“循环体语句”,在执行“表达式3”

....如此重复

直到“表达式2”的值为假(0) 循环结束

“表达式1”,“表达式2”,“表达式3”

任意C语言合法的表达式都可以

“表达式1” :一个循环只做一次,初始化条件,可一个,可多个,用逗号隔开

“表达式2”:判断表达式,它的值直接决定for循环是执行还是不执行

“表达式3”:改变循环条件的地方,每当循环体语句做完之后,执行表达式3

“表达式1”,“表达式2”,“表达式3”都可以为空

但是;一个都不能少

表达式2为空,则表示循环判断条件永远为真

for(;;) while(1);

{

}

=>编程建议

不管for后面有没有语句,先打一对{}

表示他的“管辖范围”

练习:

1.求出所有的“水仙花数” 1.c

“水仙花数”是一个三位数,并且它的个,十,百位上的数字的立方和等于它本身

[100,999]

100 ?

if(0*0*0+0*0*0+1*1*1 == 100)

{

print 100

}

101 ?

if(1*1*1+0*0*0+1*1*1 == 101)

{

print 101

}

。。。。

999

num : [100,999]

x,y,z

if(x*x*x+y*y*y+z*z*z == num)

{

}

=============

for(num = 100;num<=999;num++)

{

//求取num的个,十,百

x=

y=

z=

if(x*x*x+y*y*y+z*z*z == num)

{

}

}

2.判断一个整数x,是否为质数(素数) 2.c

质数?

除了1和它本身以外没有其他的因数,这样的数就称为质数

6 :1 2 3 6

x

[2,x-1]

2 是不是x的因子

3 是不是x的因子

。。。

x-1 是不是x的因子

=>

for(i = 2;i < x;i++)

{

if(x % i == 0)//只要发现一个因子,不需要往下判断

{

printf("no\n");

break; //提前结束循环

}

}

if(i== x)

{

printf("yes\n");

}

一个循环结束有两种情况

(1)判断条件满足

因为break跳出循环 =》提前结束 非正常死亡

(2)判断条件不满足

“判断表达式”的值为0

(5)break和continue

break 在C语言中有两个作用

(1)break在switch中,用来跳出它所属的switch语句

(2)break用在循环语句(while/do_while/for)中,用来跳出它所属的循环

for()

{

while()

{

if()

{

break;//跳出while

}

}

}

/*

test1.c: In function ‘main’:

test1.c:9:3: error: break statement not within loop or switch

break;

^

*/

if()

{

break;

} //有语法错误

continue:

continue只能用于循环体内(while/do_while/for)

用于提前执行下一次循环(结束本次循环,继续下一次循环)

作业:

1、求1000以内所有的“完数”

“完数”:如果一个数除了它本身以外其他因子之和等于其本身,这个数就是完数

6 :1 2 3 6

m % n == 0;

=》m是n的倍数 ,n是m的因子(因数)

num [1,1000]

int sum = 0;

for(num = 1;num <=1000;num++)

{

sum = 0;

//判断num是不是一个完数

for(x = 1; x <num;x++)

{

if(num % x == 0)

{

sum += x;

}

}

if(sum == num)

{

printf("%d\n",num);

}

}

2.求两个数(a,b)的最大公约数和最小公倍数

a % m == 0 =>a是m的倍数,m是a的约数

b % m == 0 =>b是m的倍数,m是b的约数

=>m是a和b的公约数

15 45

算法一:

“穷举法”

a % x == 0 && b % x == 0

从[1,min(a,b)] 区间里面找

找最大的公约数绝对不会大于min(a,b)

=> min = a <b ? a : b;

for(;min >0;min--)

{

if(a % min== 0 && b % min == 0)

{

min就是最大公约数

break;

}

}

======

算法二:

欧几里德算法

GCD(a,b)

假设a >= b

GCD(b,a mod b)

r = a mod b = a%b

证明 :

a,b的公约数集合 == b,a mod b的公约数的集合

A == B

A是B的子集,B是A的子集

A是B的子集 :

GCD(a,b)

x是GCD(a,b)中任意一个元素

a = K1 x (K1为整数)

b = K2 x (K2为整数)

r = a mod b

=>a = K*b +r (K为整数)

=> K1x = kK2x +r

=>r = (K1-KK2)x

=>x是r的约数

x是b的约数

x属于b,r的公约数 =》x 属于 GCD(b,r)

GCD(15,10) => GCD(10,5) =>GCD(5,0) =>5就是最大公约数

GCD(125,64) =>(64,61) =>(61,3) =>(3,1) =>(1,0) =>1

int a,b;

scanf("%d%d",&a,&b);

//确保 a>= b

while(a % b != 0)

{

r = a%b;

a = b;

b = r;

}

//最大公约数为a

优化:

while(b)

{

r = a%b;

a = b;

b = r;

}

3.连续的正整数之和。一个正整数有可能可以被表示为n(n>=2)个连续的正整数之和

x = 15

15 = 1+2+3+4+5

15 = 4+5+6

15 = 7+8

"穷举法"

i :1~x/2

sum = i;

if(sum == x)

{

}

i++;

sum += i;

if(sum == x)

{

}

===========

int i,x,num,sum;

scanf("%d",&num);

for(i = 1;i < num/2+1;i++)

{

sum = i;

for(x = i+1;;x++)

{

sum += x;

if(sum == num)

{

//输出处理

break;

}

else if(sum > num)

{

break;

}

}

}

算法二:

[L,R]

sum = [l,r]区间各元素之和

1:从1开始 1+ 2 +3 + 4+5+6

if sum < num //往右边扩展区间

r++;

sum += r;

if sum >num//

sum -= l;

l++;

if sum == num //找到这个区间

//输出处理

r++;

sum += r;

15

1+2+3+4+5...15

4 +5 +6 +7

=====

for(l = 1,r = 1,sum = 1;l <= num/2;)

{

if(sum < num) //往右边扩展区间

{

r++;

sum += r;

}

else if(sum >num)//把区间最左边的那个数拿掉

{

sum -= l;

l++;

}

else

{

int i;

//输出处理

//15 = 1+2+3+4+5

printf("%d = ",num);

for(i = l;i<r;i++)

{

printf("%d+",i);

}

printf("%d\n",r);

r++;

sum += r;

}

}