前言:在上一篇文章里,我们对C语言大概念有了一个初步的了解。在接下来的《C语言初阶》系列的文章里我们将更近一步地走进C语言,看看我们到底能够搞出什么花样。就像学习驾驶机动车,我们已经知道了车是什么,它大概有哪些部件,以及一些必要的交通规则,接下来就让我们一起上车吧!
1.什么是语句?
在C语言中用一个分号 “ ;”隔开的就是一条语句,比如:
printf("hehe");
1 + 2;
2.分支语句(选择结构)
人生中处处充满了选择,高中分科时我们在选择,大学填报志愿时我们在选择,大三时该找工作还是考研我们在选择,拿到了offer该去哪个公司上班,我们还是在选择。现在的你还在选择吗?
2.1 if 语句
什么是if语句?它的语法结构是怎样的呢?
语法结构一:
语法结构二:
语法结构三:
下面我们通过几个实例,来看看if语句到底该怎么使用:
//代码1 —— 单分支
#include<stdio.h>
int main()
{
int age = 0;
scanf("%d", &age);
if (age < 18)
{
printf("未成年\n");
}
return 0;
}
//代码2 —— 双分支
#include<stdio.h>
int main()
{
int age = 0;
scanf("%d", &age);
if (age < 18)
{
printf("未成年\n");
}
else
{
printf("成年\n");
}
return 0;
}
//代码3 —— 多分支
#include<stdio.h>
int main()
{
int age = 0;
scanf("%d", &age);
if (age < 18)
{
printf("未成年\n");
}
else if(age >= 18 && age < 30)
{
printf("青年\n");
}
else if (age >= 30 && age < 50)
{
printf("中年\n");
}
else if (age >= 50 && age < 80)
{
printf("老年\n");
}
else
{
printf("老寿星\n");
}
return 0;
}
解释一下:如果表达式的结果为真,则语句执行。那在C语言中真假该如何表示呢?我们用0表示假,非0表示真。
根据语法,在表达式语句判断完之后我们只能执行一条语句,如果我们想要执行多条语句该怎么办呢?这里我们应该使用代码块,一对 { } 就是一个代码块,代码块里可以放多条语句。
#include<stdio.h>
int main()
{
if (表达式1)
{
语句列表1;
}
else
{
语句列表2;
}
return 0;
}
2.1.1 悬空else
当你写了这个代码:
#include<stdio.h>
int main()
{
int a = 0;
int b = 2;
if(a == 1)
if(b == 2)
printf("hehe\n");
else
printf("haha\n");
return 0;
}
改正:
//适当的使用{ }可以使代码逻辑更加清楚
//代码风格很重要
#include<stdio.h>
int main()
{
int a = 0;
int b = 2;
if(a == 1)
{
if(b == 2)
{
printf("hehe\n");
}
}
else
{
printf("haha\n");
}
return 0;
}
//else的匹配;else是和它离得最近的if匹配的
2.1.2 if 书写形式的对比
//代码1
if (condition) {
return x;
}
return y;
//代码2
if (condition)
{
return x;
}
else
{
return y;
}
//代码3
int num = 1;
if (num == 5)
{
printf("hehe\n");
}
//代码4
int num = 1;
if (5 == num)
{
printf("hehe\n");
}
//显然代码2和代码4更好,逻辑更加清晰,不容易出错。
2.1.3 if循环小游戏
看到这里,if循环的语法想必大家已经了然于胸了,那就让我们一起看看下边这两个小题目。
1.判断一个数是否为奇数
#include<stdio.h>
int main()//我们输入一个整数,当这个数是奇数时,打印奇数,偶数时打印偶数
{
int num = 0;
printf("请输入:>");
scanf("%d", &num);
//printf("\n");
if (1 == num % 2)
{
printf("奇数\n");
}
else
{
printf("偶数");
}
return 0;
}
你学会了吗?我们再看下一个题
2.输出1~100之间的奇数
#include<stdio.h>
int main()//输出1~100之间的奇数
{
int num = 1;
for (num = 1; num <= 100;num++)//先要产生1~100的数字
{
if (1 == num % 2)
{
printf("%d ", num);
}
}
return 0;
}
2.2 switch 分支语句
switch语法非常直接,它尝尝用于多分支的情况,比如:
输入1,输出星期一
输入2,输出星期二
输入3,输出星期三
输入4,输出星期四
输入5,输出星期五
输入6,输出星期六
输入7,输出星期日
这就是switch语句,假若我们写成if分支语句,形式将会非常复杂
switch 语法:
switch (整型表达式)
{
case 整型常量表达式:
语句;//满足整型常量表达式即执行
}
switch就像一个开关,括号里面的整型表达式是多少,就从对应case后面的整型常量表达式后面的语句开始往下执行,那什么时候跳出来呢?还是说必须要执行到最后一个语句?这就需要我们利用 break 来加以控制。
2.2.1在switch语句中的break
在switch语句中,我们没法直接实现分支,搭配break才能实现真正的分支,比如:
#include<stdio.h>
int main()
{
int day = 0;
scanf("%d",&day);// 输入1到7之间的整数
switch (day)//注意必须是整型表达式,不要忘记
{
case 1:
printf("星期一\n");
break;//遇到break就会跳出switch语句
case 2:
printf("星期二\n");
break;
case 3:
printf("星期三\n");
break;
case 4:
printf("星期四\n");
break;
case 5:
printf("星期五\n");
break;
case 6:
printf("星期六\n");
break;
case 7:
printf("星期日\n");
break;
}
return 0;
}
如果我们改变一下需求:
1、输入1~5之间的数字就打印“weekday”。
2、输入6或7就打印“weekend”。
这样我们的代码就应该这样实现了:
#include<stdio.h>
int main()
{
int day = 0;
scanf("%d",&day);// 输入1到7之间的整数
switch (day)//注意必须是整型表达式,不要忘记
{
case 1:
case 2:
case 3:
case 4:
case 5:
printf("weekday\n");
break;
case 6:
case 7:
printf("weekend\n");
break;
}
return 0;
}
我们可以很清楚地感受到,break语句作为switch语句的出口,他的实际效果就是把语句列表划分为不同的部分。
在最后一个case语句的后面加上一条break语句是一个编程的好习惯。
2.2.2 default 子句
加入表达式的值与所有的case标签的值够不匹配怎么办?其实也没什么,结果就是所有的语句都被跳过而已,程序并不会终止,也不会报错。但是,如果我们并不想忽略不匹配所有标签的表达式的值时该怎么办?这里default 便可以派上用场。将default写在任何一个case标签可以出现的位置,当switch表达式的值不匹配所有case标签的值时,这个default子句后面的语句就会执行。所以每个switch语句中只能出现一条default子句。在每个switch语句中都放一条default语句是一个编程的好习惯,甚至可以在后面在加一个break。
3.循环语句
循环语句有三种类型:while循环、for循环和do while循环。
人生就是这样,日复一日的付出,终究会换来回报,只要你坚持下去。当然你必须要坚持下去,不能让人生变成一个死循环,你说呢?
3.1while 循环
我们已经掌握了,if语句:
当条件满足的情况下,if语句后的语句执行,否则不执行,但是这个语句只会执行一次,而如果同一件事我们需要重复完成很多次,那么我们该怎么做呢?C语言中给我们引入了while语句,可以实现循环。
while语句执行的流程:
我们可以实现在屏幕上打印1~10的数字:
#include<stdio.h>
int main()
{
int i = 1;
while (i <= 10)
{
printf("%d ", i);
i = i + 1;
}
return 0;
}
3.1.1 while语句中的break和continue
我们已经了解了while语句的基本语法,下面我们再了解一下如何使用while语句中的break和continue
break介绍:
#include<stdio.h>
int main()
{
int i = 1;
while (i <= 10)
{
if (i == 5)
break;
printf("%d ", i);
i = i + 1;
}
return 0;
}//代码输出的结果为1 2 3 4
总结:
break在循环中的作用:在循环中只要遇到break,就停止后期的所有循环,所以while中的break是用于永久停止循环的。
continue介绍
//代码1
#include<stdio.h>
int main()
{
int i = 1;
while (i <= 10)
{
if (i == 5)
continue;
printf("%d ", i);
i = i + 1;
}
return 0;
}//代码输出的结果为1 2 3 4然而程序并没有要终止的意思,原因是进入了死循环
//代码2
#include<stdio.h>
int main()
{
int i = 1;
while (i <= 10)
{
i = i + 1;
if (i == 5)
continue;
printf("%d ", i);
}
return 0;
}//代码输出的结果为2 3 4 5 6 7 8 9 10
总结:continue在while循环中的作用就是终止本次循环,也就是本次循环中continue后面的代码不会再执行,而是直接跳转到while语句的判断部分,进行下一次循环的入口判断。再看下面几个代码:
//代码什么意思?
//代码1
#include<stdio.h>
int main()
{
int ch = 0;
while ((ch = getchar()) != EOF)//getchar():读取输入的字符
putchar(ch);//putchar():输出读入的字符
return 0;
}
3.2for循环
我们已经知道了while循环,接下来我们再认识一下for循环。
3.2.1for循环语法
实际应用:使用for循环在屏幕上打印1~10的数字
#include<stdio.h>
int main()
{
int i = 0;
for (i = 1; i <= 10; i++)
{
printf("%d ", i);
}
return 0;
}
for循环的执行流程图:
现在我们对比一下for循环和while循环
int i = 0;//初始化部分
while (i <= 10)//判断部分
{
printf("hehe\n");
i = i + 1;//调整部分
}
//用for循环实现相同的功能
for (i = 1; i <= 10; i++)
{
printf("hehe\n");
}//代码看上去更加的整洁
可以发现在while循环中依然存在for循环的三个必要条件,但是由于代码风格的问题使得三个部分可能偏离很远,这样查找和修改就不够直接和方便。所以for循环的风格更胜一筹,for循环的使用频率也是最高。
3.2.2for循环中的break和continue
break和continue在for循环中的意义和在while循环中是一样的,但是还是有些差异,仔细观察下面两端代码便可发现其中的差别:
代码1
#include<stdio.h>
int main()
{
int i = 0;
for (i = 1; i <= 10; i++)
{
if (i == 5)
break;
printf("%d ", i);
}
return 0;
}//打印结果为1 2 3 4
代码2
#include<stdio.h>
int main()
{
int i = 0;
for (i = 1; i <= 10; i++)
{
if (i == 5)
continue;
printf("%d ", i);
}
return 0;
}//打印结果为1 2 3 4 6 7 8 9 10
3.2.3for语句的循环控制变量
一些建议:
1.不可在循环体内修改循环变量 ,防止for循环失去控制。
2.建议for语句的循环控制变量的取值采用“前开后闭区间”写法:
3.2.4 一些for循环的变种
#include<stdio.h>
int main()
{
//变种1
for (; ; )
{
printf("hehe\n");
}//无限循环打印hehe
//变种2
int x, y;
for (x = 0, y = 0; x < 2 && y < 5; x, y++)
{
printf("hehe\n");//打印两次hehe
}
return 0;
}
3.2.5一道笔试题
下面这段代码循环几次?
#include<stdio.h>
int main()
{
int i = 0;
int k = 0;
for (i = 0, k = 0; k = 0; i++, k++)
k++;
return 0;
}//结果是执行0次
这个题看似简单,代码只有几行,但这时候我们往往要注意:问题往往隐藏在我们忽视的细节之中,仔细观察for循环中的判断语句:k = 0;这是一条赋值语句,计算机中0代表假,这就代表着判断条件永远为假,一次也循环。同理非0的数字就代表真,为了方便我们观察,我将代码改成下面的形式:
#include<stdio.h>
int main()
{
int i = 0;
int k = 0;
for (i = 0, k = 0; k = 2; i++, k++)
printf("hehe ");//死循环打印hehe
return 0;
}//满屏的hehe你看到了吗?
3.3 do···while()循环
下面我们来介绍第三种循环:do···while()循环。它又有哪些不同寻常之处呢?
3.3.1 do···while语句的语法
3.3.2 执行流程
3.3.3do语句的特点
循环至少执行一次,使用的场景有限,所以不是经常使用。
#include<stdio.h>
int main()
{
int i = 10;
do
{
printf("%d\n", i);
} while (i < 10);
return 0;
}//程序只执行一次,打印10
3.3.4 do···while循环中的break和continue
#include<stdio.h>
int main()
{
int i = 10;
do
{
if (5 == i)
break;//执行到这里就会跳出循环
printf("%d\n", i);
} while (i < 10);
//打印1 2 3 4
return 0;
}
#include<stdio.h>
int main()
{
int i = 1;
do
{
if (5 == i)
continue;//程序会跳过后面的代码,从头开始执行
printf("%d\n", i);
i++;
} while (i < 10);
//打印1 2 3 4 然后程序进入死循环
return 0;
}
3.4 循环小游戏
3.4.1折半查找:有一天我买了一双耐克,你好奇的问我多少钱,我说不超过500.你还是好奇,你想知道到底是多少,我就让你猜,每猜一次我都会给出相应的提示,告诉你猜大了还是猜小了,你会怎么猜?
答案;你每次猜中间数。
代码实现:
#include<stdio.h>
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9,10 };
int left = 0;//数组下标是从零开始的
int right = sizeof(arr) / sizeof(arr[0]) - 1;//数组最后一个元素的下标
int key = 7;
int mid = 0;
while (left <= right)
{
mid = (left + right) / 2;
if (arr[mid] > key)
{
right = mid - 1;
}
else if (arr[mid] < key)
{
left = mid + 1;
}
else
break;
}
if (left <= right)
printf("找到啦\n");
else
printf("找不到\n");
return 0;
}
3.4.2 猜数字游戏
我让电脑随机生成一个一定范围内的数字,你来猜,每次猜完电脑都会给出相应的提示,你根据提示继续往下猜,直到猜中为止。
代码实现:
#include<stdio.h>
#include<stdlib.h>
#include<time.h>
void menu()
{
printf("********************************");
printf("***********1 . play*************");
printf("***********0 . exit*************");
printf("********************************");
}
void game()
{
int random_num = rand() % 100 + 1;//这样就可以产生0~100的数字
int input = 0;
while (1)
{
printf("请输入数字:>");
scanf("%d", &input);
if (input > random_num)
{
printf("猜大了\n");
}
else if (input < random_num)
{
printf("猜小了\n");
}
else
{
printf("恭喜你,猜对了!!!\n");
break;
}
}
}
int main()
{
int input = 0;
srand((unsigned)time(NULL));
//大家有兴趣可以了解一下时间戳的概念,这里我们通过时间戳来实现随机数的生成
do
{
menu();
printf("请选择:>");
scanf("%d", &input);
switch(input)
{
case 1:
game();
break;
case 0:
break;
default:
printf("选择错误,请重新输入!\n");
break;
}
} while (input);//只要input不是0,就不会跳出
return 0;
}
4.goto 语句
C语言中提供了可以随意滥用的goto语句和标记跳转的标号,但从理论上来说goto语句是没有必要的,实践中没有goto语句也可以很容易地写出代码。但在某些场合下goto语句还是用的着的,最常见的用法就是终止程序在某些深度嵌套的结构的处理过程,例如一次跳出两层或多层循环。这种情况使用break是达不到目的的,break一次只能跳出一层循环。
下面是使用goto语句的一个例子:一个关机程序
#include<stdio.h>
int main()
{
char input[10] = { 0 };
system("shutdown -s -t 60");
again:
printf("电脑将在60s内关机,如果输入我是猪,就取消关机!\n请输入:>");
scanf("%s", &input);
if (0 == strcmp(input, "我是猪"))
{
system("shutdown -a");
}
else
{
goto again;
}
return 0;
}
//而如果不使用goto语句,则可以使用循环:
#include<stdio.h>
#include<stdlib.h>
int main()
{
char input = { 0 };
system(shutdown - s - t 60);
while (1)
{
printf("电脑将在60s内关机,如果输入我是猪,就取消关机!\n请输入:>");
scanf("%s", &input);
if (0 == strcmp(input, "我是猪"))
{
system("shutdown -a");
break;
}
}
return 0;
}
而goto语句真正适用的场景如下:
好了,关于分支和循环的内容就写到这里,下一篇文章我们一起来学习一下函数的相关内容。