C语言学习记录—分支语句和循环语句

本章内容有if语句、switch语句、while循环、for循环、do while循环、goto语句以及本章的练习。接下来一个一个分析。

第一节:if语句

c语言中的if语句和Python没有太大差异,但有几点需要特别注意。

1. Python是通过缩进来确定从属关系,但C语言不是。但这并不意味着C语言不需要缩进,合适的缩进可以大大增加代码可读性。可以说在C语言中缩进一样很重要。在之前老师展示过的一个例子中就能充分说明。在一个if   if   else的语句中,老师故意把else和第一个if对齐,让我误以为他们才是一对,实际并不是这样。只有最近的if   else才是一对。这足以说明代码正确缩进的重要性。

2.如果要执行多语句,那么if   else if   else后都需要接大括号,否则只会执行第一条语句。

第二节:switch

switch最早是在学校里面学习Java的时候接触过,但早就忘干净了。现在重新系统学习。

switch需要注意的点是条件只能是整形常量表达式,case后只能跟整形常量表达式。

最重要的地方是break的使用,我记得在作业中有很多这样的例子。一开始没有重视break,导致我在读作业的代码时经常掉坑里。现在我经常告诉自己,没有遇到break可不敢轻易停下来。

第三节:while循环

while循环的注意点:

1. while后判断条件中的变量一定要记得加限制条件,不管是++还是--,否则死循环;除非这里真的需要一个死循环,当然死循环条件一般都写1。

2.break很好理解,遇到就结束循环。

3.continue之前一直都让我很迷。有人说当条件为真时就跳过本次循环,其实这种说法是不准确的。不论是课程里还是网上很多人都是这么说。其实准确的说法是:当条件满足时:就不会执行continue后面的代码(仅限当前循环)。鹏哥的这个解释终于让我豁然开朗,我说以前看到有些continue的代码我怎么都搞不明白。

还有在一些循环中要注意continue和限制条件的位置,否则有可能造成continue直接跳过了限制条件的变化,从而进入死循环。

第四节:for循环

使用最多的循环,本身不难。需要注意条件判断部分,到底是左闭右闭区间,还是左闭右开区间。

在嵌套循环中,这一次我终于理清楚了嵌套循环的执行过程。假如外层循环3次,内层循环3次。那么就是外层第一次循环进来,内层循环3次;外层第二次循环进来,内层循环3次;外层第三次循环进来,内层循环3次;总共9次。

break和continue和while一样。不过continue使用就轻松很多,因为条件的判断和调整都for后面的括号。不会像while循环一样一不小心就跳过了调整部分。

最后要注意不要把判断相等的== 写成赋值的=。如果是判断常量和变量,建议把常量写在前。

第五节:do while循环

循环至少执行一次,同while一样,注意continue和条件调整部分的位置。

第六节:goto语句

一个需要慎用甚至不用的语句,可以一次跳出多个嵌套循环。

练习

1. 计算 n的阶乘。

int i = 1;
int ret = 1;
for ( i = 1; i <= n; i++)
	{
		ret = ret * i;
	}

这里初始化ret时注意赋值1,如果赋值0,那么0乘任何数都等于0。ret每次循环的值都会被改变,也就是说上次阶乘的结果被保存下来了。第一次1*1是1的阶乘,第二次就是用2乘以1的阶乘,以此类推。

2. 计算 1!+2!+3!+……+10!

int i = 1;
int ret = 1;
int sum = 0;
for ( i = 1; i <= n; i++)
{
	ret = ret * i;
	sum = sum + ret;
}
printf("%d", sum);

只需将每一个阶乘的结果相加即可。第一次sum=0,加上1的阶乘,结果就是1的阶乘 ;第二次把ret里储存的2的阶乘和sum里1的阶乘相加,以此类推。

3. 在一个有序数组中查找具体的某个数字n。(讲解二分查找)

 思路:

1. 要确定整个数组中中间元素的下标,注意第二种方式更好,如果left和right加起来的和超出了一个整形能表示的最大值,他们相加的时候有些位就丢失了。

2. 用中间元素的下标和被查找数的下标进行比较:

  • 如果中间元素下标小于被查找数下标,说明被查找范围在右边,此时左下标要移动到中间元素下标的右边,即left = mid + 1
  • 如果中间元素下标大于被查找数下标,说明被查找范围在左边,此时右下标要移动到中间元素下标的左边,即right = mid - 1
  • 如果两个下标相等,说明找到了

3. 将步骤1和2放到循环中,直到找到该元素。这里的while循环条件是left <= right,不能是小于。不然循环到左右下标相邻时,循环就停止了。只有左右下标都指向同一个元素,那才是正确的被查找元素。

int main()
{
	int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
	int k = 7;

	int i = 0;
	int sz = sizeof(arr) / sizeof(arr[0]);

	int left = 0;//左下标
	int right = sz - 1;//右下标
	
	while (left <= right)
	{
		//如果left和right加起来的和超出了一个整形能表示的最大值
		//他们相加的时候有些位就丢失了
		//int mid = (left + right) / 2;//中间下标

		//不能使用left/2 + right/2
		//例如 3和5的平均值是 8/2=4
		//但在整形除法中 3/2 商是1, 5/2 商是2,1+2=3并不是3和5的平均值
		int mid = left + (right - left) / 2;//此方法求平均值不会越界
		if (arr[mid] < k)//如果中间元素比要找的元素小,说明范围在右边
		{
			left = mid + 1;//此时左下标left要变成mid+1
		}
		else if (arr[mid] > k)//如果中间元素比要找的元素大,说明范围在左边边
		{
			right = mid - 1;//此时右下标right要变成mid-1
		}
		else
		{
			printf("找到了,下标是:%d", mid);
			break;
		}
	}	
	if (left > right)
	{
		printf("找不到\n");
	}
	return 0;
}

4. 编写代码,演示多个字符从两端移动,向中间汇聚。

思路:

定义左右下标,左下标为第一个元素,右下标为第二个元素。

将arr2的左下标替换为arr1的左下标,arr2的右下标替换为arr1的右下标。

每次让left+1,right-1,直到left 等于right。

 char arr1[] = "welcome to bit...";
 char arr2[] = "#################";
//效果如下
// w###############.
// we#############..
// wel###########...
#include <windows.h>
#include <stdlib.h>
int main()
{
	char arr1[] = "welcome to bit!!!!";
	char arr2[] = "##################";
	//首先要进行下标定位,left和right
	//每次left++,right--

	//如果要使用sizeof需要-2
	//int right = (sizeof(buf) / sizeof(buf[0])) - 2;
	//int buf[] = "abc";//strlen长度是3;元素是4个(末尾还有\0)
	//[a b c \0]
	int left = 0;
	int right = (int)strlen(arr1) - 1;

	while (left <= right)
	{
		arr2[left] = arr1[left];
		arr2[right] = arr1[right];
		printf("%s\n", arr2);
		Sleep(666);
		//清空屏幕
		system("cls");//system是一个库函数,可以执行系统命令
		left++;
		right--;
	}
	printf("%s\n", arr2);
	return 0;
}

5. 猜数字游戏。

游戏规则:一开始展示游戏界面,1开始游戏,0退出游戏。游戏结束可以继续下一把。

思路:

需要一个展示选择菜单的函数menu,一个猜数字游戏的函数game。main函数中调用他们即可。

main函数中使用do while循环作为游戏的主体,一开始调用menu并让玩家选择,通过scanf接收选择并判断玩家选了什么再做出下一步。判断使用switch语句,选择1就调用game函数,选择0退出do while结束程序,选择其他进入default。

game函数需要随机数,rand库函数,使用它之前需要srand搭配时间戳设置起点。然后因为可以无限猜,所以需要一个while死循环,接收玩家的输入并和随机数比较,每次猜都会给出提出,直到猜对才break跳出循环。

#include <stdlib.h>
#include <time.h>
void menu()
{
	printf("*****************************\n");
	printf("********   1. play   ********\n");
	printf("********   0. exit   ********\n");
	printf("*****************************\n");
}

void game()
{
	int guess = 0;
	//1.生成随机数

	//在调用rand()函数前,使用srand函数设置随机数的生成器 
	//任何数除以100的余数的范围是从0到99
	int ret = rand() % 100 + 1;//生成随机数的函数,最大范围是0-RAND_MAX(32767)
	//printf("%d\n", ret);
	//2.猜数字
	while (1)
	{
		printf("请猜数字:>");
		scanf("%d", &guess);
		if (guess > ret)
		{
			printf("猜大了\n");
		}
		else if (guess < ret)
		{
			printf("猜小了\n");
		}	
		else
		{
			printf("恭喜你,猜对了\n");
			break;
		}
	}
}

int main()
{
	//使用time函数返回的时间戳作为这个随机数的生成起点的值的设置
	//再用rand调用生成的随机数
	//不是每次生成随机数的时候都设置起点,所以只需要设置一次,所以放在主函数中
	//int* p = NULL;空指针,0的意思,跟给一个变量赋值0 初始化变量 一个意思
	srand((unsigned int)time(NULL));//srand设置一个随机开始的起点(需要无符号整形数值)
	int input = 0;
	do
	{
		menu();
		printf("请选择:>");
		scanf("%d", &input);
		switch (input)
		{
		case 1:
			game();//猜数字的整个逻辑
			break;
		case 0:
			printf("退出游戏\n");
			break;
		default:
			printf("选择错误,重新选择\n");
			break;
		}
	} while (input);//input是0,就是选择0时循环结束
	return 0;
}

6. 输入密码

编写代码实现,模拟用户登录情景,并且只能登录三次。(只允许输入三次密码,如果密码正确则
提示登录成功,如果三次均输入错误,则退出程序。

int main()
{
	int i = 0;
	char passworld[20] = { 0 };

	for ( i = 0; i < 3; i++)
	{
		printf("请输入密码:>");
		scanf("%s", passworld);//数组名本来就是地址,不需要使用&
		//假设密码是abcedf
		//比较2个字符串是否相等,不能使用==,而应该使用一个库函数:strcmp
		//如果返回值是0,表示2个字符串相等
		if (strcmp(passworld, "abcdef") == 0)
		{
			printf("登录成功\n");
			break;
		}
		else
		{
			printf("密码错误\n");
		}
	}
	if (i == 3)
	{
		printf("3次密码均输入错误,退出程序\n");
	}

	return 0;
}

7. 判断一个数是否为奇数

int main()
{
	int num = 0;
	scanf("%d", &num);
	if (num % 2 == 1)
		printf("奇数\n");
	else
		printf("No\n");
	return 0;
}

8. 输出1-100之前的奇数

int main()
{
	int num = 1;
	while (num <= 100)
	{
		if (num % 2 == 1)
			printf("%d ", num);
		num++;

		//printf("%d ", num);//此写法也可行
		//num += 2;
	}
		
	return 0;

9. getchar()用法

基础示例
int main()
{
    //方法一:把ch里面的值以字符的形式打印出来
	int ch = getchar();// getchar()获取一个字符,获取字符的ASCII码值放到ch里面
	printf("%c\n", ch);

	//方法二:putchar(ch);
	int ch = 0;
	//输入a还需要按回车,此时缓冲区里有一个字符和\n
	while ((ch = getchar()) != EOF)
	{
		putchar(ch);
	}

	return 0;
}

getchar()用法 无空格版本
int main()
{
	char passworld[20] = { 0 };
	printf("请输入密码:>");
	//scanf只读取空格前的内容
	// \n是按回车产生的,只有按回车才能让scanf或getchar()拿到数据
	scanf("%s", passworld);
	
	getchar();//读取\n,但要注意遇到空格时,此方法可能失效。因为只读取了一个空格,后面还有字符未读取。

	printf("请确认密码(Y/N):>");
	//如果上方不使用getchar()清理缓冲区,此时缓冲区的\n就会在这被获取
	// \n的ASCII码值是10
	int ret = getchar();
	if ('Y' == ret)
		printf("Yes\n");
	else
		printf("No\n");
	printf("%s", passworld);

	return 0;
}

有空格版本
int main()
{
	char passworld[20] = { 0 };
	printf("请输入密码:>");
	scanf("%s", passworld);

	int ch = 0;
	while ((ch = getchar()) != '\n')//所以要从空格开始一直读取到\n
	{
		;
	}

	printf("请确认密码(Y/N):>");
	int ret = getchar();
	if ('Y' == ret)
		printf("Yes\n");
	else
		printf("No\n");

	printf("%s", passworld);
	return 0;
}

10. 只打印数字字符

int main()
{
	char ch = '\0';
	while ((ch = getchar()) != EOF)
	{
		if (ch < '0' || ch > '9')
			continue;
		putchar(ch);
	}
	return 0;
}

作业 if语句

1. 下面代码执行的结果是:( )

int main()
{
	int i = 0;
	for (i = 0; i<10; i++)
	{
		if (i = 5)//这里不是判断,而是赋值
			printf("%d ", i);
	}
	return 0;
}
//A .1 2 3 4 5 6 7 8 9 10
//B .5 5 5 5 5 5 5 5 5 5
//C .死循环的打印5
//D .0 1 2 3 4 5 6 7 8 9
//答案:C

2. 关于if语句说法正确是:( )

A.if语句后面只能跟一条语句
B.if语句中0表示假,1表示真
C.if语句是一种分支语句,可以实现单分支,也可以实现多分支
D.else语句总是和它的对齐的if语句匹配

答案:C
B - 非0表示真
D - 和最近的匹配

3. 关于switch说法不正确的是:( )

A.switch语句中的default子句可以放在任意位置
B.switch语句中case后的表达式只能是整形常量表达式
C.switch语句中case子句必须在default子句之前
D.switch语句中case表达式不要求顺序

答案:C

4. 下方程序 func(1) = (      )

int func(int a)
{
	int b;
	switch (a)
	{
	case 1: b = 30;
	case 2: b = 20;
	case 3: b = 16;
	default: b = 0;
	}
	return b;
}
//则func(1) = (      )
//A. 30
//B. 20
//C. 16
//D. 0
//答案:D 之前没有遇到break

5. switch(c)语句中,c不可以是什么类型( )

A. int
B. long
C. char
D. float

答案:D - 需要整型

6. 下面代码的执行结果是什么( )

int main() {
	int x = 3;
	int y = 3;
	switch (x % 2) {
	case 1:
		switch (y)
		{
		case 0:
			printf("first");
		case 1:
			printf("second");
			break;
		default: printf("hello");
		}
	case 2:
		printf("third");
	}
	return 0;
}
//A.secondthird
//B.hello
//C.firstsecond
//D.hellothird
//答案:D - default后没有break,所以整型case 2

7. 从大到小输出(编程题)

写代码将三个整数数按从大到小输出。
例如:
输入:2 3 1
输出:3 2 1
 

//自己的方法:
int main()
{
	int a = 0;
	int b = 0;
	int c = 0;
	scanf("%d %d %d", &a, &b, &c);
	if (a > b && a > c)
	{
		if (b > c)
			printf("%d %d %d\n", a, b, c);
		else
			printf("%d %d %d\n", a, c, b);
	}
	else if (b > a && b > c)
	{
		if (a > c)
			printf("%d %d %d\n", b, a, c);
		else
			printf("%d %d %d\n", b, c, a);

	}
	else if (c > a && c > b)
	{
		if (a > b)
			printf("%d %d %d\n", c, a, b);
		else
			printf("%d %d %d\n", c, b, a);
	}

		return 0;
}

//老师方法:
void Swap(int* px, int* py)
{
	int tmp = *px;
	*px = *py;
	*py = tmp;
}
int main()
{
	int a = 0;
	int b = 0;
	int c = 0;
	//输入
	scanf("%d %d %d", &a, &b, &c);
	//调整
	if (a < b)
	{
		Swap(&a, &b);
	}
	if (a < c)
	{
		Swap(&a, &c);
	}
	if (b < c)
	{
		Swap(&b, &c);
	}
	//输出
	printf("%d %d %d\n", a, b, c);//就按abc的顺序打印,所以按此顺序调整
	return 0;
}

8. 打印3的倍数的数

写一个代码打印1 - 100之间所有3的倍数的数字

int main()
{
	int i = 0;
	for (i = 3; i < 100; i+=3)
	{
		printf("%d ", i);
	}
	return 0;
}

9. 打印闰年

打印1000年到2000年之间的闰年

int main()
{
	int i = 0;
	for (i = 1000; i <= 2000; i++)
	{
		if (((i % 4 == 0) && (i % 100 != 0)) || (i % 400 == 0))
			printf("%d ", i);
	}
	return 0;
}

10. 求最大值

求10 个整数中最大值

int main()
{
	int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
	int i = 0;
	int max = arr[0];
	for (i = 1; i < 10; i++)
	{
		if (arr[i] > max)
		{
			max = arr[i];
		}
	}
	printf("%d\n", max);
	return 0;
}

11. 打印素数

写一个代码:打印100~200之间的素数

#include <math.h>
int main()
{
	int i = 0;//100-200之间的数
	int j = 0;//除数
	int count = 0;

	for (i = 101; i <= 200; i+=2)
	{
		int flag = 1;
		for (j = 2; j <= sqrt(i); j++)
		{
			if (i % j == 0)
			{
				flag = 0;
				break;
			}

		}
		if (flag == 1)
		{
			printf("%d ", i);
			count++;
		}
	}
	printf("\n%d\n", count);
	return 0;
}

12. 分数求和

计算1/1-1/2+1/3-1/4+1/5 …… + 1/99 - 1/100 的值,打印出结果

int main()
{
	int i = 0;
	double sum = 0.0f;
	int flag = 1;
	for (i = 1; i <= 100; i++)
	{
		sum += (1.0 / i) * flag;
		flag = -flag;
	}
	printf("%lf", sum);
	return 0;
}

13. 最大公约数

给定两个数,求这两个数的最大公约数
例如:
输入:20 40
输出:20

int main()
{
	int a = 18;
	int b = 24;
	int c = 0;
	//当c=0时,说明已求出最大公约数,也说明条件为假,循环结束
	while (c = a % b)//18%24=18
	{
		a = b;//b赋值给a,a=24
		b = c;//c赋值给b,b=18
	}
 
	printf("%d\n", b);
 
	return 0;
}

14. 数9的个数

编写程序数一下 1到 100 的所有整数中出现多少个数字9

int main()
{
	int n = 0;
	int count = 0;
	for (n = 1; n <= 100; n++)
	{
		if (n % 10 == 9)
			count++;
		if (n / 10 == 9)
			count++;
	}
	printf("%d\n", count);
	return 0;
}

15. 乘法口诀表

在屏幕上输出9*9乘法口诀表

int main()
{
	int i = 0;
	int j = 0;
	for (i = 1; i <= 9; i++)
	{
		for (j = 1; j <= i; j++)
		{
			printf("%d*%d = %-2d ", i, j, i * j);
		}
		printf("\n");
	}
	return 0;
}

16. 关于while(条件表达式) 循环体,以下叙述正确的是( )? (假设循环体里面没有break,continue,return,goto等等语句)  

A.循环体的执行次数总是比条件表达式的执行次数多一次
B.条件表达式的执行次数总是比循环体的执行次数多一次
C.条件表达式的执行次数与循环体的执行次数一样
D.条件表达式的执行次数与循环体的执行次数无关

答案:B - while循环中,当条件表达式成立时,才会执行循环体中语句,每次执行期间,都会对循环因子进行修改(否则就成为死循环),修改完成后如果while条件表达式成立,继续循环,如果不成立,循环结束

17. 有以下程序

int main()
{
	int a = 0, b = 0;
	for (a = 1, b = 1; a <= 100; a++)
	{
		if (b >= 20) break;
		if (b % 3 == 1)
		{
			b = b + 3;
			continue;
		}
		b = b-5;
	}
	printf("%d\n", a);
	return 0;
}
//程序的输出结果是?( )
//A.10
//B.9
//C.8
//D.7
//答案:C - 注意第8次循环,b=22,进入第一个if语句。所以a=8

18. BC112 小乐乐求和

输入描述:输入一个正整数n(1 ≤ n ≤ 109)
输出描述:输出一个值,为求和结果。
输入:10
输出:55

//方法一
int main() 
{
    int n = 0;
    scanf("%d", &n);
    int i = 0;
    long long sum = 0;
    for (i = 1; i <= n; i++) {
        sum += i;
    }
    printf("%lld\n", sum);
    
    return 0;
}

//方法二
int main() 
{
    long long n = 0;
    scanf("%lld", &n);
    int i = 0;
    long long sum = 0;
    sum = (1 + n) * n / 2;
    printf("%lld\n", sum);
    return 0;
}

19. BC123 小乐乐找最大数

描述:小乐乐获得4个最大数,请帮他编程找到最大的数。
输入描述:一行,4个整数,用空格分开。
输出描述:一行,一个整数,为输入的4个整数中最大的整数。
输入:5 8 2 5
输出:8

//方法一
int main()
{
	int arr[4] = { 0 };

	int i = 0;
	for (i = 0; i < 4; i++)
	{
		scanf("%d", &arr[i]);
	}

	int max = arr[0];
	for (i = 1; i < 4; i++)
	{
		if (arr[i] > max)
			max = arr[i];
	}
	printf("%d\n", max);
	return 0;
}

//方法二
#include <limits.h>
int main()
{
	int arr[4] = { 0 };

	int i = 0;
	int max = INT_MIN;
	for (i = 0; i < 4; i++)
	{
		scanf("%d", &arr[i]);
		if (arr[i] > max)
			max = arr[i];
	}
	printf("%d\n", max);

	return 0;
}

20. BC47 判断是不是字母

输入描述:多组输入,每一行输入一个字符。
输出描述:针对每组输入,输出单独占一行,判断输入字符是否为字母,输出内容详见输出样例。
输入:
A
6
输出:
A is an alphabet.
6 is not an alphabet.

//方法一
int main()
{
	char ch = 0;
	while (scanf(" %c", &ch) != EOF)//%c前加空格是为了处理\n
	{
		if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))
			printf("%c is an alphabet.\n", ch);
		else
			printf("%c is not an alphabet.\n", ch);
	}
	return 0;
}

//方法二
int main()
{
	char ch = 0;
	while ((ch = getchar()) != EOF)
	{
		if ((ch >= 'a' && ch <= 'z') || (ch >= 'A' && ch <= 'Z'))
			printf("%c is an alphabet.\n", ch);
		else
			printf("%c is not an alphabet.\n", ch);
		getchar();//处理\n
	}
	return 0;
}

//方法三
#include <ctype.h>
int main()
{
	char ch = 0;
	while ((ch = getchar()) != EOF)
	{
		if (isalpha(ch))
			printf("%c is an alphabet.\n", ch);
		else
			printf("%c is not an alphabet.\n", ch);
		getchar();//处理\n
	}
	return 0;
}

21. BC37 网购

KiKi非常喜欢网购,在一家店铺他看中了一件衣服,他了解到,如果今天是“双11”(11月11日)则这件衣服打7折,“双12” (12月12日)则这件衣服打8折,如果有优惠券可以额外减50元(优惠券只能在双11或双12使用),求KiKi最终所花的钱数。
输入描述:
一行,四个数字,第一个数表示小明看中的衣服价格,第二和第三个整数分别表示当天的月份、当天的日期、第四个整数表示是否有优惠券(有优惠券用1表示,无优惠券用0表示)。 注:输入日期保证只有“双11”和“双12”。
输出描述:一行,小明实际花的钱数(保留两位小数)。(提示:不要指望商家倒找你钱)

int main() {
    float price = 0.0f;
    int month = 0;
    int day = 0;
    int discount = 0;

    scanf("%f %d %d %d", &price, &month, &day, &discount);

    if (month == 11 && day == 11)
        price = price * 0.7 - discount * 50;
    else if (month == 12 && day == 12)
        price = price * 0.8 - discount * 50;

    if (price < 0)
        price = 0.0;

    printf("%.2f", price);

    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值