5.C语言循环结构

循环结构(由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编译器在开发的时候用了一个思想叫自举

  1. 会开发一个只包含很少的c语言的一个子集编译器,这个编译器用汇编语言写

  2. 然后用这个子集编译器往后扩充,得到一个更大的子集编译器,这个编译器就是二代 ,它就可以用一代编译器编译而来

  3. 经过多代,就可以得到现在的gcc了。

  4. 结果:假设第一代编译器有一个后面,后面的所有的编译器就都会有这个后门,并且你根本就看不出来

    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个数

  1. 求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;
}

题目:找满足条件的序列

  1. 连续的正整数之和,一个正整数有可能可以被表示为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;
    	}
    }*/
    
    

    题目:正整数分解质因式

    1. 将一个正整数分解质因式
      ​ 如:输入 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以内的所有的素数

  1. 求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;
}

题目:求某范围内的完数

  1. 求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;
}









  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值