C语言基础 5. For

C语言基础 5. For

5.1. For

  • 阶乘:

    • n! : 表示n的阶乘

    • 即: n! == 1 * 2 * 3 * … * n

    • 写一个程序, 让用户输入n, 然后计算输出n!.

      • 分析:
        • 1.产生2到n之间的数,因为1*1相当于没有乘,而记录累乘结果的变量正好是1,所以1!不影响结果
        • 2.让这些数累乘
  • for:

		for (int i = 1; i <= n; i++) {
			factorial *= i;
		}
		
		for (初始条件; 判断条件; 调整) {
			执行语句;
		}
  • 执行顺序:

    • for (1.初始条件; 2.判断条件; 4.调整) {
      3.执行语句;
      }
  • for( 对于 ):

    • 可以这样翻译: 对于一开始i=1, 当i<=n时, 重复循环体, 每一轮循环在做完循环体内的语句后, 使得i++.
  • 小套路:

    • 做求和程序时, 记录结果的变量应该初始化为0, 而做求积的变量时, 变量应该初始化为1.
  • 使用while求n的阶乘:

#include <stdio.h>

int main()
{
	int n;
	printf("请输入一个数来求它的阶乘: ");
	scanf("%d", &n);
	//产生2到n之间的数
	int i = 2;	// i表示这些数
	int factorial = 1;	// factorial接收累乘的结果
	while (i <= n) {
		//printf("%d ", i);
		//让这些数累乘
		factorial *= i;
		i++;
	}
	//printf("factorial = %d ", factorial);
	printf("%d! = %d\n", n, factorial);
	return 0;
}
  • 使用for求n的阶乘:
#include <stdio.h>

int main()
{
	int n;
	printf("请输入一个数来求它的阶乘: ");
	scanf("%d", &n);
	//产生2到n之间的数
	int factorial = 1;	// factorial接收累乘的结果
	for (int i = 2; i <= n; i++) {//循环控制变量i只在循环里被使用了,外面没任何用处,所以可以定义到for语句里面
		//让这些数累乘
		factorial *= i;
	}
	或者可以产生n到2之间的数
	//for (i = n; i <= 2; i--) {
	//	//让这些数累乘
	//	factorial *= i;
	//}
	//printf("factorial = %d ", factorial);
	printf("%d! = %d\n", n, factorial);
	return 0;
}

5.2. 循环的计算和选择

  • 循环次数:
    • 两种循环的循环次数都是相同的,不同的是,上面 i 的初始值是0,最后为n,而下面的i初始值是1, 最后为n+1
		for (i = 0; i < n; i++) {
			printf("i = %d ", i);
			count++;
		}
		for (i = 1; i <= n; i++) {
			printf("i = %d ", i);
			count++;
		}
  • for == while:

    • for和while是等价的
  • for中的每一个表达式都是可以省略的

  • 如何选择不同的循环:

    • 如果有固定次数, 选择for
    • 如果必须执行一次, 用do while
    • 其他情况用while
  • 计算循环次数

#include <stdio.h>

int main()
{
	int i;
	int n = 5;
	int count = 0;
	/*for (i = 0; i < n; i++) {
		printf("i = %d ", i);
		count++;
	}*/
	for (i = 1; i <= n; i++) {
		printf("i = %d ", i);
		count++;
	}
	printf("\ni最后 = %d\n", i);
	printf("循环次数为%d\n", count);
	return 0;
}

5.3. Break&Continue

  • 素数:

    • 素数是指在大于1的自然数中,除了1和它本身以外不再有其他因数的自然数.
      • 比如:
        2, 3, 5, 7, 11, 13, 17, 19…
  • 判断一个数是否为素数:

    • 分析:
      • 1.输入一个数num
      • 2.产生2到num-1之间的数
      • 3.试除,让num一个一个除这些数
      • 4.如果能除尽则立即停止
      • 5.如果这些数都除不尽,说明num是素数
  • break VS continue:

    • break: 跳出循环
    • continue: 跳过循环这一轮剩下的语句进入下一轮循环
  • 自己写的:

#include <stdio.h>

int main()
{
	//输入一个数
	int num;
	printf("请输入一个数,用来判断它是否为素数: ");
	scanf("%d", &num);
	int i;
	//产生2到num-1之间的数
	for ( i = 2; i <= num - 1; i++) {
		//printf("%d ", i);
		//试除,能除尽则停止
		if (num % i == 0) {
			printf("%d不是素数", num);
			break;	// 直接跳出循环, 循环中的break作用是跳出循环
		}
	}
	//都除不尽则是素数
	if (i == num) {		// i++, i==num了, 进入不了循环, 说明num已经将i变量试除完毕, 此时判断为素数
		printf("%d是素数", num);	//虽然这种方法的结果也对, 但是它是有害的, 可读性差, 不建议使用
	}
	return 0;
}
  • 跟着视频教程写的:
#include <stdio.h>

int main()
{
	//输入一个数
	int num;
	printf("请输入一个数,用来判断它是否为素数: ");
	scanf("%d", &num);
	int i;
	//定义一个判断素数的变量
	int isPrime = 1;
	//产生2到num-1之间的数
	for (i = 2; i <= num - 1; i++) {
		//printf("%d ", i);
		//试除,能除尽则停止
		if (num % i == 0) {
			isPrime = 0;
			break;	// 直接跳出循环, 循环中的break作用是跳出循环
		}
	}
	//都除不尽则是素数
	if (isPrime == 1) {
		printf("%d是素数", num);
	}
	else {
		printf("%d不是素数", num);
	}
	return 0;
}

5.4. 嵌套的循环

  • 输出100以内的素数:

    • 分析:
      • 1.产生1-100之间的数
      • 2.产生2到num-1之间的数
      • 3.试除,让num一个一个除这些数
      • 4.如果能除尽则立即停止
      • 5.如果这些数都除不尽,说明num是素数
  • 嵌套:

    • 循环里面还是循环

    • 注意: 内层和外层的循环控制变量(也就是i和j和k)不能是一样的.

  • 循环控制变量:

    • 用来控制循环的次数, index简写成i, 因为ijk挨在一起, 所以常用的循环控制变量就是这三个
  • 输出前50个素数:

    • 分析:
      • 1.产生num++,count++
      • 2.产生2到num-1之间的数
      • 3.试除,让num一个一个除这些数
      • 4.如果能除尽则立即停止
      • 5.如果这些数都除不尽,说明num是素数
  • 输出100以内的素数:

#include <stdio.h>

int main() {
	//产生1-100之间的数
	int num;
	for (num = 2; num <= 100; num++) {
		//定义一个素数变量
		int isPrime = 1;
		//产生2到num-1之间的数
		int i;
		for (i = 2; i <= num - 1; i++) {
			//试除
			if (num % i == 0) {
				isPrime = 0;	//能除尽则让素数变量为0
				break;
			}
		}
		//都除不尽则是素数
		if (isPrime == 1) {
			printf("%d ", num);
		}
	}
	return 0;
}
  • 输出前50个素数:
#include <stdio.h>

int main() {
	int count = 0;
	int num = 2;
	while (count < 50) {
		//定义一个素数变量
		int isPrime = 1;
		//产生2到num-1之间的数
		int i;
		for (i = 2; i <= num - 1; i++) {
			//试除
			if (num % i == 0) {
				isPrime = 0;	//能除尽则让素数变量为0
				break;
			}
		}
		//都除不尽则是素数
		if (isPrime == 1) {
			printf("%d ", num);
			//计数
			count++;
		}
		num++;
	}
	return 0;
}

5.5. 从嵌套中跳出

  • 疑问:
    排列组合现在还不是太懂

  • 凑硬币:

    • 如何用一角两角和五角的硬币凑出10元以下的金额?
    • 提示: 排列组合
  • break和continue只能对它所在的那层(离它最近的)循环做

  • 接力break:

    • 为了跳出全部的三层循环, 满足条件后, 在三个循环中都加上break, 成为接力break.
    #include <stdio.h>
    int main()
    {
    	int money;
    	int one, two, five;
    	scanf("%d", &money);
    	int exit = 0;
    	for (one = 1; one < money * 10; one++) {
    		for (two = 1; two < money * 10 / 2; two++) {
    			for (five = 1; five < money * 10 / 5; five++) {
    				if (one + two * 2 + five * 5 == money * 10) {
    					printf("可以用%d个1角加%d个2角加%d个5角得到%d元\n", one, two, five, money);
    					exit = 1;
    					break;
    				}
    			}
    			if (exit == 1) break;
    		}
    		if (exit == 1) break;
    	}
    	return 0;
    }
    
  • goto:

    • 使用goto来代替接力break

    • goto out; //out是一个标号, 从这里

    • out: //直接跳转到这里

    • 虽然goto语句有危险, 但是它可以使用在它的使用场景中, 也就是想要跳出多层循环时使用

  • 凑硬币, 列出所有的可能:

#include <stdio.h>

int main()
{
	int money;
	int one, two, five;
	scanf("%d", &money);
	for (one = 1; one < money * 10; one++) {
		for (two = 1; two < money * 10 / 2; two++) {
			for (five = 1; five < money * 10 / 5; five++) {
				if (one + two * 2 + five * 5 == money * 10) {
					printf("可以用%d个1角加%d个2角加%d个5角得到%d元\n", one, two, five, money);
				}
			}
		}
	}
	return 0;
}
  • 出现一个可能后直接结束程序:
#include <stdio.h>

int main()
{
	int money;
	int one, two, five;
	scanf("%d", &money);
	int exit = 0;
	for (one = 1; one < money * 10; one++) {
		for (two = 1; two < money * 10 / 2; two++) {
			for (five = 1; five < money * 10 / 5; five++) {
				if (one + two * 2 + five * 5 == money * 10) {
					printf("可以用%d个1角加%d个2角加%d个5角得到%d元\n", one, two, five, money);
					exit = 1;
					break;
				}
			}
			if (exit == 1) break;
		}
		if (exit == 1) break;
	}
	return 0;
}
  • 使用goto来代替接力break:
#include <stdio.h>

int main()
{
	int money;
	int one, two, five;
	scanf("%d", &money);
	for (one = 1; one < money * 10; one++) {
		for (two = 1; two < money * 10 / 2; two++) {
			for (five = 1; five < money * 10 / 5; five++) {
				if (one + two * 2 + five * 5 == money * 10) {
					printf("可以用%d个1角加%d个2角加%d个5角得到%d元\n", one, two, five, money);
					goto out;
				}
			}
		}
	}
out:
	return 0;
}

5.6. Test

5.6.1. 前n项和

  • 前n项和:

    • f(n) = 1/1 + 1/2 + 1/3 + 1/4 + … + 1/n

    • 分析:

      • 1.输入一个数n
      • 2.产生1到n之间的数
      • 3.让1/这些数 4.相加
  • f(n) = 1/1 - 1/2 + 1/3 - 1/4 + … + 1/n

    • 分析:
      • 1.输入一个数n
      • 2.产生1到n之间的数
      • 3.让1/这些数
      • 4.使用一个控制正负号的变量sign
  • fn

#include <stdio.h>

int main()
{
	//输入n
	int n;
	scanf("%d", &n);
	//求和变量
	double sum = 0.0;
	//产生1到n之间的数
	for (int i = 1; i <= n; i++) {
		//让1/这些数
		double fn = 1.0 / i;
		//相加
		sum += fn;
	}
	printf("sum = %f", sum);
	return 0;
}
  • 一加一减
#include <stdio.h>

int main()
{
	//输入n
	int n;
	scanf("%d", &n);
	//求和变量
	double sum = 0.0;
	//正负变量
	int sign = 1;
	//产生1到n之间的数
	for (int i = 1; i <= n; i++) {
		//让1/这些数
		double fn = sign * 1.0 / i;
		//相加
		sum += fn;
		//循环一次变一次正负号
		sign = -sign;
	}
	printf("sum = %f", sum);
	return 0;
}

5.6.2. 整数分解

  • 疑问:

    • 逆序后,个个位数的第一位是0,则合成整数后,0就会消失

    • 已解决, 因为此方法确实在遇到末位是0的数时行不通, 要换一种方法

  • 正序整数分解:

    • 输入一个自然数, 正序输出它的每一位数字

    • 输入: 13425

    • 输出: 1 3 4 2 5

    • 分析1:

      • 1.输入n

      • 2.先将这个数逆序输出

      • 3.再整数求逆

        • 1.取出个位数digit=n%10

        • 2.取出剩余位n/=10

        • 3.直到n/10为0

        • 4.让个个位数变成一个整数

        • 5.再让这个整数求逆

        • 发现行不通, 另谋他法

    • 分析2:

      	n=13425
      	13425 / 10000 = 1;
      	13425 % 10000 = 3425
      	10000 / 10 = 1000
      	3425 / 1000 = 3;
      	3425 % 1000 = 425
      	1000 / 10 = 100
      	425 / 100 = 4;
      	425 % 100 = 25
      	100 / 10 = 10
      	25 / 10 = 2;
      	25 % 10 = 5
      	10 / 10 = 1
      	5 / 1 = 5;
      	5 % 1 = 0
      	1 / 10 = 0
      
      • 1.输入n
      • 2.n/[10^n的(位数-1)]=第一位
      • 3.n%[10^n的(位数-1)]=剩余位
      • 4.[10^n的(位数-1)]/10
  • pow()函数:

    • 乘方函数, int ciMi = pow(10, 4); 计算10的4次方赋值给变量ciMi
    • 使用条件:
      • 引用头文件: #include <math.h>
  • 分析1行不通:

#include <stdio.h>

int main() {
	//输入
	int n;
	printf("请输入一个数, 将它正序分解: ");
	scanf("%d", &n);
	int ret = 0;
	//循环取出位数
	while (n != 0) {
		//取出个位数
		int digit = n % 10;
		//取出剩余位
		n /= 10;
		//让个个位数变成一个整数
		ret += digit;	// 5	54	543		5432	54321
		ret *= 10;		// 50	540 5430	54320	543210	
	}
	//将这个整数/10
	int r = ret / 10;
	while (r != 0) {
		int d = r % 10;
		r /= 10;
		//输出个个位数
		int result = d;
		printf("%d", result);
		//让结果格式化
		if (r != 0) {
			printf(" ");
		}
	}
	return 0;
}
  • 分析2:
#include <stdio.h>
#include <math.h>

int main() {
	//输入
	int n;
	scanf("%d", &n);
	//计算n的位数
	int num = n;	//保留n的值
	//10的次方变量
	int ciMi = 1;
	int weiShu = 0;
	while (num >= 10) {
		num /= 10;
		ciMi *= 10;	//10的(n的位数-1)次方
		/*weiShu++;*/
	}
	//int ciMi = pow(10, weiShu - 1);	//可以这样写,但是还可以将ciMi放到上面的循环,更简便
	//表每一位的变量
	int digit = 0;
	//循环得到n的每一位
	while (ciMi > 0) {		//假如判断条件再写成n>0,设n为600,则ciMi算下来为100
		//600/100=6,600%100=0, n为0直接就跳出循环了,所以判断条件应该为ciMi>0
		digit = n / ciMi;
		printf("%d", digit);
		//结果格式化
		if (ciMi >= 10) {	//同理, 这里的判断条件也应该为ciMi>=10
			printf(" ");
		}
		n %= ciMi;
		ciMi /= 10;
	}
	//可以在结果的最后输出一句话, 测试结果格式化是否正确
	/*printf("hello");*/
	return 0;
}

5.6.3. 最大公约数

  • 最大公约数(gcd):

    • 输入两个数a和b,输出它们的最大公约数(是指两个或多个整数共有约数中最大的一个),提示:枚举法和辗转相除法

    • 输入: 12 18

    • 输出: 6

    • 分析:

      • 枚举法(此方法容易理解, 但是效率不高):

        • 1.输入两个数a,b
        • 2.找出a,b中较小的
        • 3.产生1到较小的数之间的数
        • 4.将a和b都试除这些数
        • 5.公约数的最总结果就是最大公约数
      • 辗转相除法(不容易理解, 但是效率高):

        • 1.如果b等于0, 计算结束, a就是最大公约数
        • 2.否则, 计算a除以b的余数, 让a等于b, 而b等于那个余数
        • 3.回到第一步
  • 枚举法:

#include <stdio.h>

int main() {
	//输入
	int a, b;
	scanf("%d %d", &a, &b);
	//找出较小值
	int min;
	if (a < b) {
		min = a;
	}
	else {
		min = b;
	}
	//产生1到a之间的数
	int i;
	int ret = 0;
	for (i = 1; i <= min; i++) {
		//printf("%d ", i);
		//试除,得到所有公约数
		if (a % i == 0 && b % i == 0) {
			//将公约数赋值给结果变量, 最后赋值的结果也就是最大公约数, 因为公约数是递增的
			ret = i;
		}
	}
	printf("%d和%d的最大公约数为: %d", a, b, ret);
	return 0;
}
  • 辗转相除法:
#include <stdio.h>

int main() {
	//输入
	int a, b;
	scanf("%d %d", &a, &b);
	//余数变量
	int yushu = 0;
	while (b != 0) {
		yushu = a % b;
		a = b;
		b = yushu;
	}
	printf("a和b的gcd是%d", a);
	return 0;
}

5.7. PAT

  • 05-0. 求序列前N项和(15)

    • 疑问: 精确到两位小数?

    • 已解决

    • 本题要求编写程序,计算序列 2/1+3/2+5/3+8/5+… 的前N项之和。注意该序列从第2项起,每一项的分子是前一项分子与分母的和,分母是前一项的分子。

    • 输入格式:
      输入在一行中给出一个正整数N。

    • 输出格式:
      在一行中输出部分和的值,精确到小数点后2位。题目保证计算结果不超过双精度范围。

    • 输入样例:
      20

    • 输出样例:
      32.66

    • 分析:

      • 分子变量:fenZi 分母变量:fenMu

      • 通项公式: fenZi+fenMu / fenZi

      • 初始值: fenZi=2, fenMu=1

      • 1.输入n

      • 2.初始化变量

      • 3.通项公式

      • 4.求和,精确到两位小数(%.2f 表示只取小数点后两位的数)

  • 代码:
#include <stdio.h>

int main() {
	//输入n
	int n;
	scanf("%d", &n);
	//分子,分母变量
	double fenZi = 2.0;
	double fenMu = 1.0;
	double sum = 0.0;
	int i = 1;
	while (i <= n) {
		//求和
		sum += fenZi / fenMu;
		//通项公式
		double tmp = fenMu;		//1
		fenMu = fenZi;			//2
		fenZi = fenZi + tmp;	//2+1
		i++;
	}
	printf("%.2f\n", sum);	//%.2f 表示只取小数点后两位的数
	return 0;
}
  • 05-1. 约分最简分式(15)

    • 分数可以表示为“分子/分母”的形式。编写一个程序,要求用户输入一个分数,然后将其约分为最简分式。最简分式是指分子和分母不具有可以约分的成分了。如6/12可以被约分为1/2。当分子大于分母时,不需要表达为整数又分数的形式,即11/8还是11/8;而当分子分母相等时,仍然表达为1/1的分数形式。

    • 输入格式:
      输入在一行中给出一个分数,分子和分母中间以斜杠“/”分隔,如:12/34表示34分之12。分子和分母都是正整数(不包含0,如果不清楚正整数的定义的话)。

    • 提示:在scanf的格式字符串中加入“/”,让scanf来处理这个斜杠。

    • 输出格式:
      在一行中输出这个分数对应的最简分式,格式与输入的相同,即采用“分子/分母”的形式表示分数。如5/6表示6分之5。

    • 输入样例:
      60/120

    • 输出样例:
      1/2

    • 分析:

      • 1.输入fenZi/fenMu
      • 2.找到它们的最大公约数gcd
      • 3.让它们分别除以gcd
      • 4.输出结果
  • 代码:

#include <stdio.h>

int main() {
	//输入
	int fenZi, fenMu;
	scanf("%d/%d", &fenZi, &fenMu);
	//定义求最大公约数的变量,来保留fenZi和fenMu变量的值
	int a = fenZi;
	int b = fenMu;
	while (b != 0) {
		//辗转相除法,求最大公约数
		int yuShu = a % b;//余数变量
		a = b;
		b = yuShu;
	}
	int gcd = a;
	//printf("gcd = %d", gcd);
	//化简
	fenZi /= gcd;
	fenMu /= gcd;
	//输出结果
	printf("%d/%d", fenZi, fenMu);
	return 0;
}
  • 05-2. 念数字(15)

    • 输入一个整数,输出每个数字对应的拼音。当整数为负数时,先输出“fu”字。十个数字对应的拼音如下:
      0: ling
      1: yi
      2: er
      3: san
      4: si
      5: wu
      6: liu
      7: qi
      8: ba
      9: jiu

    • 输入格式:
      输入在一行中给出一个整数,如:1234。

    • 提示:整数包括负数、零和正数。

    • 输出格式:
      在一行中输出这个整数对应的拼音,每个数字的拼音之间用空格分开,行末没有最后的空格。如yi er san si。

    • 输入样例:
      -600

    • 输出样例:
      fu liu ling ling

    • 分析:

      • 1.输入num
      • 2.判断num的正负及零
      • 3.正序整数分解
      • 4.switch-case语句判断( 此处只能使用这种笨方法, 后面学到数组后会有更简洁的方法)
      • 5.输出
  • 代码:

#include <stdio.h>

int main() {
	//输入
	int num;
	scanf("%d", &num);
	//判断正负及0
	if (num != 0) {
		//去负号*-1
		if (num < 0) {
			num *= -1;
			printf("fu ");
		}
		//10的次幂的变量
		int ciMi = 1;
		int tmp = num;	//保留num的值
		//计算10的num的位数-1次幂
		while (tmp >= 10) {
			tmp /= 10;
			ciMi *= 10;
		}
		//表每一位的变量
		int digit = 0;
		while (ciMi > 0) {
			digit = num / ciMi;
			num %= ciMi;
			ciMi /= 10;
			//switch-case判断数字
			switch (digit) {
			case 0:
				printf("ling");
				break;
			case 1:
				printf("yi");
				break;
			case 2:
				printf("er");
				break;
			case 3:
				printf("san");
				break;
			case 4:
				printf("si");
				break;
			case 5:
				printf("wu");
				break;
			case 6:
				printf("liu");
				break;
			case 7:
				printf("qi");
				break;
			case 8:
				printf("ba");
				break;
			case 9:
				printf("jiu");
				break;
			}
			//格式化
			if (ciMi > 0) {
				printf(" ");
			}
		}
		printf("hello");
	}
	//判断零
	else {
		printf("ling\n");
	}
	return 0;
}
  • 05-3. 求a的连续和(15)

    • 输入两个整数a和n,a的范围是[0,9],n的范围是[1,8],求数列之和S = a+aa+aaa+…+aaa…a(n个a)。如a为2、n为8时输出的是2+22+222+…+22222222的和。

    • 输入格式:
      输入在一行中给出两个整数,先后表示a和n。

    • 输出格式:
      在一行中输出要求的数列之和。

    • 输入样例:
      2 4

    • 输出样例:
      2468

    • 分析:

      • 2+22+222+2222+…+22222222

      • 210=20 20+2=22 2210=220 220+2=222

      • a*=10 a+=2

      • 1.输入

      • 2.循环n次

      • 3.通项公式a*=10,a+=2

      • 4.每一项相加

  • 代码:

#include <stdio.h>

int main() {
	//输入
	int a, n;
	scanf("%d %d", &a, &n);
	//求和变量
	int sum = 0;
	//循环n次
	for (int i = 1; i <= n; i++) {
		//每一项相加
		sum += a;
		//通项公式
		a *= 10;
		a += 2;
	}
	printf("%d", sum);
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值