卢鹏博
发布于 2025-05-28 / 46 阅读
2

C语言循环语句

while循环

基本结构

while循环是C语言中最经典的循环,其一般用法为

while(循环条件)
{
循环体
}

其中当循环条件满足时,执行循环体,直到条件不满足时跳出循环。

因此,我们需要定义一个循环变量,并在循环体中改变这个变量,以避免陷入死循环

因此while循环也常常这样使用:

循环变量
while(循环条件)
{
循环体
更改循环变量
}

比如下面程序

#include <stdio.h>
int main()
{
int i=0;          //定义循环变量
int sum=0;
while(i<=10)
	{
 	 sum = sum + i;
 	 i++;            //改变循环变量
	}
printf("sum=%d",sum);
return 0;
}

这段代码计算并输出1+2+···+10的值。

练习

练习1:输出1-100中的所有素数

分析:根据素数的定义,我们可以逐个判断2~n-1能否整除n,即可写出下面代码:

#include <stdio.h>
int main()
{
	int i=1;
	int j=2;
	printf("2\n");
	while(i<=100)
	{
		j=2;
		while(j<i)
		{
			if(i%j==0)
			{
				j++;
				break;
			}
			if(j==i-1)printf("%d\n",i);
			j++;
		}
		i++;
	}
	return 0;
}

上述是判断是否为素数最直接的代码。其实,我们可以减少判断次数。

第一,j只要判断到\sqrt{i}或者说\lfloor\sqrt{i}\rfloor即可。这是因为i=\sqrt{i}\cdot\sqrt{i}=a\cdot b\ (a\leq b),由于i的因子是成对存在的,所以如果i有非1因子a,那么a\leq\sqrt{i}

第二,所有除2的偶数也一定不是素数,这样又可以减少一部分验证。

于是,下面是改进的代码:

#include <stdio.h>
#include <math.h>
int main()
{
	int i=3;
	int j=2;
	printf("2\n3\n");
	while(i<=100)
	{
		j=2;
		while(j<=sqrt(i))
		{
			if(i%j==0)
			{
				j++;
				break;
			}
			if(j>sqrt(i)-1)printf("%d\n",i);
			j++;
		}
		i=i+2;
	}
	return 0;
}

示例输出:

练习2:输入n,并计算n!并输出

我们可以写出如下程序:

#include <stdio.h>
int main()
{
	int n = 1;
	int prod = 1;
	printf("请输入一个n的值:");
	scanf("%d",&n);
	while(n!=1)
	{
		prod *= n; 
		n--;
	}
	printf("%d!=%d",n,prod);
	return 0;
}

不过上述没有对n做出限制,如果输入的n小于0,需要提示输入数据错误。经过改进,可以得到下面代码:

#include <stdio.h>
int main()
{
	int n = 1;
	int prod = 1;
	printf("请输入一个n的值:");
	scanf("%d",&n);
	while(n<0)
	{
		printf("输入错误!\n");
		printf("请输入一个n的值:");
		scanf("%d",&n);
		if(n>=0)break;
	}
	if(n==0){printf("0!=1");return 0;}
	int j=n;
	while(n!=1)
	{
		prod *= n; 
		n--;
	}
	printf("%d!=%d",j,prod);
	return 0;
}

示例输出:

for循环

for循环和while循环十分类似,可以看成是简化版的while循环。for循环在明确了循环次数的循环语句中非常常用。

基本结构

for(初始循环变量,循环条件,改变循环变量)
{
  循环体
}

for循环比while循环更加简洁明了,不需要在外部定义循环变量。

例如下面程序,计算并输出1+2...+100的值:

#include <stdio.h>
int main()
{
	int sum=0;              //求和变量
	for(int i;i<=100;i++)   //int i这里的i变量只在for循环内起作用,如果在外部调用会报错(当然可以使用指针传递i的值)
	{
		sum += i;	
	}
	printf("%d",sum);
	return 0;
}

于是我们可以“改造”练习一,练习二的代码如下:

练习1

#include <stdio.h>
#include <math.h>
int main()
{
	printf("2\n");
    for(int i=3; i<=100; i+=2)
    {
        int is_prime = 1;  			   // 假设i是素数
        for(int j=2; j<=sqrt(i); j++)  // 从2开始检查除数
        {
            if(i%j == 0)  
            {
                is_prime = 0;          // 更改i不是素数
                break;
            }
        }
        if(is_prime)printf("%d\n", i);
    }
    return 0;
}

这里我们使用is_prime这个状态参数判断i是不是素数,先假设i是素数,方便后续调整。

练习2

#include <stdio.h>
int main()
{
	int n,prod = 1;
	printf("请输入一个n的值:");
	scanf("%d",&n);
	while(n<0)
	{
		printf("输入错误!\n请输入一个n的值:");
		scanf("%d",&n);
		if(n>=0)break;
	}
	for(int i = n;i>=2;i--)
	{
		prod *= i; 
	}
	printf("%d!=%d",n,prod);
	return 0;
}

这里我们在for循环里定义了一个临时变量i,这样,不对n做处理,可以简化0!等情况。

练习

练习3:打印形如下图用*堆积的三角形

分析:我们首先需要确定输出的行数,用n表示,这里以10为例,接下来需要打印空格和*,我们采用每一行的*的个数为2i-1,那么左边空格的个数就是n-i个,这里i代表第i行。

因此在第i行时,先输出n-i个空格,即for(int j=1;j<=n-i;j++)printf(" ");

然后再输出2i-1个*即for(int j=1;j<=2*i-1;j++)printf("*");

于是可以写出下述代码:

#include<stdio.h>
int main()
{
	int n=10;
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n-i;j++)printf(" ");
        for(int j=1;j<=2*i-1;j++)printf("*");
        printf("\n");
    }
	return 0;
}

输出结果:

练习4:做出函数x^3-x^2-x+2的图像(该题较难,可借助ai辅助完成)

源代码:

#include <stdio.h>
#include <math.h>
// 定义函数
double f(double x) {
    return x*x*x - x*x - x + 2;
}
int main() {
    int width = 60;    // 图形宽度
    int height = 20;   // 图形高度
    double x_min = -2.0;
    double x_max = 3.0;
    double y_min = -5.0;
    double y_max = 15.0;
    double x_step = (x_max - x_min) / width;
    double y_step = (y_max - y_min) / height;
    // 计算每个点的y值
    for (int row = 0; row < height; row++) {
        double y = y_max - row * y_step;
        for (int col = 0; col < width; col++) {
            double x = x_min + col * x_step;
            double y_val = f(x);
            // 判断是否在函数值附近
            if (fabs(y_val - y) <= y_step) {
                printf("*");
            } else if (fabs(y) <= y_step) {  // x轴
                printf("-");
            } else if (fabs(x) <= x_step) {   // y轴
                printf("|");
            } else {
                printf(" ");
            }
        }
        printf("\n");
    }  
    // 打印坐标轴标签
    printf("\n");
    printf("x从 %.1f 到 %.1f, y从 %.1f 到 %.1f\n", x_min, x_max, y_min, y_max);
    printf("函数: f(x) = x^3 - x^2 - x + 2\n");
    return 0;
}

输出:

while循环与for循环之间的关系

for循环是在while循环的基础上改进而来,因此for循环与while均可完成循环操作和任务。

for循环有三个参数,for(初始循环变量,循环条件,改变循环变量)

其中初始循环变量是在进入循环体之前执行一次,之后不再执行;改变循环变量是在循环体结束之后再执行,因此二者可以相互转换,二者有如下关系:

for(初始循环变量,循环条件,改变循环变量)
{
  循环体
}

初始循环变量
while(循环条件)
{
  循环体
  改变循环变量
}

等价。

比如:

#include <stdio.h>
int main()
{
int i=0;         
int sum=0;
while(i<=10)
	{
 	 sum += i;
 	 i++;          
	}
printf("sum=%d",sum);
return 0;
}

#include <stdio.h>
int main()
{
int sum=0;
for(int i=0;i<10;i++)
{
  sum += i;
}
printf("sum=%d",sum);
return 0;
}

等价。

do...while循环

基本结构

do...while循环和while循环类似,只是运行的初值不同,其基本结构为:

do
{
  循环体
}
while(循环条件);

为了防止死循环,一般使用如下格式:

定义循环变量
do
{
  循环体
  改变循环条件
}
while(循环条件);

特点

do...while的特点是,无论循环条件是否满足,先执行一遍循环体,再判断是否满足循环条件。如果条件满足,则继续循环,如果条件不满足,则停止循环。

与while循环的转换

定义循环变量
do
{
  循环体
  改变循环条件
}
while(循环条件);

定义循环变量
循环体          //执行1次
改变循环条件     //执行1次
while(循环条件)
{
  循环体
  改变循环条件
}

例如

#include <stdio.h>
int main()
{
	int i = 5;
	i--;
	printf("%d\n",i);
	while(i)
	{
		i--;
		printf("%d\n",i);
	}
	return 0;
}

#include <stdio.h>
int main()
{
	int i = 5;
	do
	{
		i--;
		printf("%d\n",i);
	}while(i);
	return 0;
}

完全等价。

这样,我们可以把练习2的代码进行修改。

练习二修改后的代码:

#include <stdio.h>
int main()
{
	int n,prod = 1;
	do
	{
		if(n<0)printf("输入错误!\n");
		printf("请输入一个n的值:");
		scanf("%d",&n);
		if(n>=0)break;
	}while(n<0);
	for(int i = n;i>=2;i--)
	{
		prod *= i; 
	}
	printf("%d!=%d",n,prod);
	return 0;
}

练习

练习5:使用牛顿迭代法计算x^3-x^2-x+2=0的近似解(该方程仅有一个根)。

提示:迭代公式为:

x_{n+1}=x_{n}-\frac{f(x_n)}{f^{'}(x_n)}

分析:我们可以选定一个误差e,当|x_{n+1}-x_{n}|<e 即认为x_{n+1}满足精度要求并输出其值。{f^{'}(x)}=3x^2-2x-1

首先我们可以确定其解在[-2,-1]之间,故可取x_0=-1进行迭代。

故可写出如下代码:

#include <stdio.h>
int main()
{
	double x,y=-1;
	double e=0.01;
	do
	{
		y = x;
		x = x-(x*x*x-x*x-x+2)/(3*x*x-2*x-1);
		if(x-y<=e&&y-x<=e)break;
	}while(1);                //一直循环,直到满足条件跳出循环
	printf("近似解为x=%lf",x);
	return 0;
}

输出为:

这与真实解x=-1.205569430...非常接近。

如果想要提升精度,一方面可以将上述结果重新赋予x,y进行迭代,另一方面需要减小e的值,并增加输出的小数位数(比如%.10f)。