循环结构(由while、for等循环语句构成)
文章目录
一、问题引入:
求:
sum = 1 + 2 + … + 100
sum = 0;
i = 1;
sum += i;
i++;
sum += i;
i++;
sum += i;
i++;
sum += i;
i++;
sum += i;
i++;
sum += i;
........
/*-> 我们如果手动去做这些代码 很明显 你会疯
所有,让计算机去疯吧
让计算机给你去做重复的事情
这种事情我们就叫循环 -> 本质就是为了重复*/
二、goto语句
1.语法形式:
标记名字:
语句1;
...
goto 标记名字;
2.用法解释:
goto 目标地点; 去到某个地方,这个目标地点在c语言里面就是一个标记,用来标记某个地址。goto去跳转这个
标记的时候实际上就是跳转到这个,标记的地址上面去执行代码。
3.使用goto语句需要注意的地方:
goto优先级很高,无条件进行跳转,不管你的这个地址是否有效,这会造成你的代码的可读性很差
因此作为小白 ,尽量避免使用
*自举的思想
gcc编译器在开发的时候用了一个思想叫自举
-
会开发一个只包含很少的c语言的一个子集编译器,这个编译器用汇编语言写
-
然后用这个子集编译器往后扩充,得到一个更大的子集编译器,这个编译器就是二代 ,它就可以用一代编译器编译而来
-
经过多代,就可以得到现在的gcc了。
-
结果:假设第一代编译器有一个后面,后面的所有的编译器就都会有这个后门,并且你根本就看不出来
goto是很好用的一个工具 当你没有办法驾驭它的时候尽量不要用
使用goto
题目:求某值以内的奇数和
练习题1:
求10000以内的的所有的奇数的和
//求10000以内所有奇数的和,loop标记,goto跳转到loop,执行loop下的条件
#include<stdio.h>
int main()
{
int i = 1,sum = 0;
loop:
sum += i;
i +=2;
if(i<10000)
goto loop;
printf("%d\n",sum);
return 0;
}
三、while语句
1.语法形式
while(表达式)
{
循环体;//复合语句
}
//表达式只要是c语言里面合法的表达式都可以
2.用法解释
先判断表达式的值,如果为真,就执行循环体
然后再次过来判断表达式的值 ,如果为真 ,继续执行循环体
…
直到表达式的值为假则就退出循环
3.需要注意的地方
打了花括号:花括号里的内容都是while的管辖下。表达式为真时,花括号里的语句都会执行。
没打花括号:while语句只能管紧接其后的一条语句。表达式为真时,只会执行紧接其后的一条语句。
4.拓展:\n的另一个用法
\n:
1.换行
2.在标准输入输出里面,它还代表着刷新缓冲区
程序错误查找方法:
使用情况:当出现段错误、核心已转储这种只告诉我们程序出错了,但却不告诉我们错在哪里的情况,我们就可以使用
printf("%s %d\n",__FUNCTION__,__LINE__);
语句进行测试,以锁定出错的地方。
该语句的功能:打印输出当前程序执行地方属于哪一函数,行数是多少
如在某函数里写了这条语句,但未打印输出相关信息,则说明该函数中存在错误,由此锁定了错误的位置。
题目:某范围内3的倍数和
练习题2:
求10000以内 , 3的倍数的和
//法一:使用while语句
#include<stdio.h>
int main()
{
int i = 0; sum = 0;
while(i < 10000)
{
sum += i;
i += 3;
}
printf("%d\n",sum);
return 0;
}
//法二:使用goto语句
#include<stdio.h>
int main()
{
int i = 3, sum = 0;
loop:
sum += i;
i += 3;
if(i<10000)
goto loop;
printf("%d\n",sum);
return 0;
}
题目:求水仙花数
练习题2:
求100 ~ 999里面的水仙花数
水仙花数:个位,十位,百位的立方和为自己本身
//求100~999里面的水仙花数。水仙花数
//个位、十位、百位的立方和为自己本身
//double pow(double x,double y);求x的y次方,需要添加头文件math.h,
//使用gcc编译的时候需要添加库 gcc main.c -o main -lm
#include<stdio.h>
#include<math.h>
int main()
{
int n = 100;
while(n<1000)
{
if(n == (int)pow(n/100,3)+(int)pow(n/10%10,3)+(int)pow(n%10,3))
printf("%d\n",n);
++n;
}
return 0;
}
题目:求寄存器中1的个数
练习题3:
求一个寄存器里面有多少个1(32bit) ----------> 求一个十进制数的二进制中有几个1
//求一个十进制数的二进制中有几个1
/*方法1:十进制转二进制的方法 一个数不断进行除2操作,直到余数为0为止,判断每次的余数1是否为1,是的话num++;*/
/*方法2:使用a=a&(a-1),使得最靠右的 1 置零后,其他的高位的 1 没有发生变化,每运行一次,就可以知道有一个 1*/
/*方法3:&1判断最后一位是否为零,每判断完一次,右移一位,判断下一位*/
//方法1:十进制转二进制进行除2操作,只适用于正整数
#include<stdio.h>
int main()
{
int n,num = 0;
printf("请输入一个整数:");
scanf("%d",&n);
while (n)
{
if(1 == n%2)
{
++num;
}
n = n/2;
}
printf("%d\n",num);
return 0;
}
//方法2:n&(n-1)适用于正整数,也适用于负整数,有多少个1就循环多少次
#include<stdio.h>
int main()
{
int n,num = 0;
printf("请输入一个整数:");
scanf("%d",&n);
while (n)
{
++num;
n = n & (n - 1);
}
printf("%d\n",num);
return 0;
}
//方法3:按位与判断,循环判断32次(即32位)适用于整数也适用于负数
#include<stdio.h>
int main()
{
int n,num = 0;
printf("请输入一个整数:");
scanf("%d",&n);
for(int i = 0;i < 32;i++)
{
if(1 == (n>>i & 1))
++num;
}
printf("%d\n",num);
return 0;
}
/*
测试错误原因:
运算符优先级记错
if(1 == (n>>i) & 1)
优先级:==(关系运算符)高于 &(按位与逻辑运算符)
所以if(1 == (n>>i)& 1)等同于if((1 == n>>i) & 1)
与我想要表达的意思不同,应该为
if(1==((n>>i) & 1)) 即 if(1 == (n>>i &1)
*/
四、do while语句
1.语法形式:
do
{
语句1;
语句2;
...
}
while(表达式);
2.用法解释:
跟while是一样的 ,表达式也是一样的 ,只不过 while是先判断在执行
do while不管你的条件怎么样 都会先执行一次
3.需要注意的地方:
与while语句类似,do后面如果没有大括号,那么只会认下面一句, 那么这个语句就可能出现问题
建议do写完直接打大括号 ,以示主权
int i=1,j=1;
do
i ++; //在循环体内
j ++; //不在循环体内
while(i<5);
五、for循环语句
1.语法形式
for(表达式1;表达式2;表达式3)
{
循环体;
}
2.用法解释
for循环开始的时候 , 首先走表达式1 -> 接着去判断表达式2的值, 如果为真 -> 执行循环体 -> 执行表达式3
->继续判断表达式2 ,为真 -> 执行循环体 -> 执行表达式3 -> 判断表达式2 , 为假了 ->退出循环
3.需要注意的地方
(1)表达式1:整个循环里面只会执行一次
(2)for里面的三个表达式 ,都可以不用写 , 但是两个;;一个都不能少
(3)如果表达式2如果不写 ,表示条件恒成立
(4)表达式3是属于for的 ,不属于循环体
4.关于死循环
for 和while都可以形成死循环,效率一样,没区别
for(;😉; //死循环
while(1); //死循环
六、break 和 continue
1) break: 结束循环,跳出循环体
while(1)
{
while(2)
{
break; //结束while(2)
}
if(1)
{
break; // 结束的是while(1)
}
}
注意:
break也可以结束switch,它匹配到switch后,就只会结束switch,不会结束循环
while(1)
{
switch(a)
{
case 1:
break; //这个break会和这个switch匹配了
//那么就只会结束switch , 不会结束循环
}
}
2) continue:结束本次循环 ,开始下一次
注意while与for的不同之处
int i = 88;
while(i < 100)
{
if(i > 50)
{
continue; //不再执行后面的语句,开始下一次循环,这个时候就会形成死循环
}
i++;
}
for(i = 0;i < 100;i++)
{
if(i > 50)
{
continue;//不在执行后面的语句 ,开始下一次循环,但是i++还是要执行,因为i++属于for,不属于循环体
//那么就不会有死循环了
}
i += 2;
}
七、题目练习
题目:求最大公约数
1.求两个数的最大公约数和最小公倍数
//求两个数的最大公约数和最小公倍数
//辗转相除法:(15,10)->(10,5)->(5,0) ->最大公约数为5
//暴力求解法: 找出1~b能被a,b都整除的所有数,把最大的赋给变量t;
#include<stdio.h>
int main()
{
int a,b,temp,m,n;
printf("请输入两个数:");
scanf("%d %d",&a,&b);
//判断a是否大于b,不大于则交换位置
if(a<b)
{
a = a^b;
b = a^b;
a = a^b;
}
m = a; n =b;
while (a%b != 0)
{
temp = b;
b = a%b;
a = temp;
}
printf("最大公约数为%d\n",b);
printf("最小公倍数为%d\n",m*n/b);
return 0;
}
/*
法二:暴力求解法,效率不如辗转相除法
int i,a,b,n,t;
scanf("%d %d",&a,&b);
if(a<b)
{
a = a^b;
b = a^b;
a = a^b;
}
n = b;
while(n <= b)
{
if(a%i == 0 && b%i == 0)
break;
n--;
}
printf("最大公约数为%d\n",t);
printf("最小公倍数为%d\n",a*b/t);
*/
题目:求a+aa+aaa+…
2 .求S = a + aa + aaa + aaaa + …
a = 1 ~ 9之间的值
有n个 ,a ,n由用户自己输入
//求s = a + aa + aaa + aaaa + ....
//a是1~9之间的值,有n个,a,n由用户输入
//9 99 999 -> 9 9+9*10 9+99*10
#include<stdio.h>
int main()
{
int a,n,s = 0,temp = 0;
printf("请输入a和n:");
scanf("%d %d",&a,&n);
temp = a;
for(int i = 0;i<n;i++)
{
s += temp;
temp = a + temp*10;
//printf("%d\n",temp);
}
printf("%d\n",s);
return 0;
}
题目:求某数阶乘末尾含0个数
- 求10000000!末尾有多少个0
2 * 5 10 * 20 = 200 2 5 2 2 5
1 ~ 10000000 100 / 5 … 0 20 / 5 … 0 4 / 5 … 4
也就是求每个数里面有多少个因子是 5
//求10000000!(阶乘)末尾有多少个0
//思路:有多少个5就有多少个0
#include<stdio.h>
int main()
{
int i,j,num = 0;
for(i = 5;i <= 10000000; i++)
{
j = i; //易忽略的地方,在做完while后,i的值不能变
while(j%5==0)
{
++num;
j = j/5;
}
}
printf("10000000!末尾有%d个0\n",num);
return 0;
}
题目:找满足条件的序列
-
连续的正整数之和,一个正整数有可能可以被表示为n个连续的正整数之和
如: 6 = 1 + 2 + 3 7 = 3 + 4
15 = 1 + 2 + 3 + 4 + 5 = 4 + 5 + 6 = 7 + 8
请编程, 输入一个数,找出所有的可能的序列
注意:也有可能没有//输入一个正整数,将这个正整数表示为n个连续的正整数序列相加 //如 6 = 1 + 2 + 3 , 7 = 3 + 4 //暴力求解法:列举所有的序列 看哪个相等就可以了 //伸缩法: left right 小了就将right+1 大了就将left+1 // 求left ~ right之间的所有的数的和 看是否相等 相等就是的 #include<stdio.h> int main() { int n,j,left,right = 1,sum = 1; printf("请输入一个大于2的数:"); scanf("%d",&n); for(left = 1;left<=n/2;left++) { loop: if(sum==n) { for(j=left;j<=right;j++) printf("%d,",j); printf("\n"); } if(sum<n) { right++; sum = sum+ right; goto loop; } sum -= left; } return 0; } /*老师代码 int n; scanf("%d",&n); int left = 1,right = 2; int sum = 3; while(right <= n / 2 + 1) { if(sum < n)//往右边伸展 { right++; sum += right; } else if(sum > n)//往左收缩 { sum -= left; left++; } else //相等 { //区间有了 printf("区间是:%d~%d\n",left,right); right++; sum += right; } }*/
题目:正整数分解质因式
- 将一个正整数分解质因式
如:输入 90
打印 90 = 2 * 3 * 3 * 5
//将一个正整数分解质因式 //如:输入 90 打印 90 = 2 * 3 * 3 * 5 短除法 //循环里面嵌套循环=一个循环+continue语句=一个循环+loop: goto loop; #include<stdio.h> int main() { int i = 2,n,t; printf("请输入一个正整数:"); scanf("%d",&n); printf("%d = 1",n); t = n; while(1!=t) //除到最后商为一的时候结束 { while(t%i == 0) //如果余数为零,i是一个因数,打印i { printf("* %d ",i); t = t/i; } //否则,i++,测试下一个数 ++i; } printf("\n"); return 0; } /*老师代码: int n; scanf("%d",&n); printf("%d = 1 ",n); int i = 2; for(;i <= n;)//i <= n { //我们要将这个n里面的质因式全部拿出来 if(n % i == 0)//如果余数为0 那么就能整除 这个时候i就可以拿出来 { printf("* %d ",i); //你后面还有质因式 你还是需要继续往下面执行 //n就应该是没有这个拿出来之后的质因式 n = n / i; //接下来你应该是从这个i开始的 因此没有必要回去 //考虑重复的结果 continue; } i++; } printf("\n"); */
- 将一个正整数分解质因式
题目:求10000以内的所有的素数
-
求10000以内的所有的素数
// 求10000以内的所有的素数,素数:除了1和它本身以外没有别的因子 //法一:暴力破解,除到这个数的开方就可以了 //法二: 开一个数组 保存从1开始到10000之间的所有素数 //我们拿到一个数之后 ,将小于它的所有的素数除一遍就可以知道答案了 #include<stdio.h> int main() { int i,j; //外循环,1~10000 for(i = 2;i <= 10000;i++) { //内循环,i除以数2~i-1 for(j = 2;j <= i-1;j++) { //判断i能不能整除j if(i%j==0) { break; } } //判断是否素数(跳出循环原因是找到了2~i-1之间i能被整除的数, //还是没找到i能被整除的数) if(j == i) printf("%d\t",i); } printf("\n"); return 0; } /*可改进的地方 for(j = 2;j <= i-1;j++) 条件可改为j <= i/2 */
题目:求15的1024次方的末尾的3位
7. 求15的1024次方的末尾的3位是多少
// 求15的1024次方的末尾的3位是多少
//思路: 每次都取后面的三位
//最后的结果的后三位只跟每次乘出来的时候的后三位有关
#include<stdio.h>
int main()
{
int s = 1;
for(int i = 1;i<=1024;i++)
{
s *= 15;
s %= 1000;
}
printf("15的1024次方末尾3位为%d\n",s);
return 0;
}
题目:求某范围内的完数
- 求10000以内的所有的完数
//求10000以内的所有的完数
//完数:除了它自己本身的这个因子以外的所有的因子的和等于这个数本身
//6 -> 1 * 2 * 3 , 1 + 2 + 3 = 6 这个数就是完数
//8 -> 1 * 2 * 4 , 1 + 2 + 4 != 8 这个数就不是完数
#include<stdio.h>
int main()
{
int i,j,sum;
for(i = 1;i < 10000; i++)
{
sum = 0;
//找因子
for(j = 1;j < i; j++)
{
if(0 == i%j)
sum += j;
}
if(i == sum)
printf("%d\t",i);
}
printf("\n");
return 0;
}