C语言是一种结构化的程序设计语言,所谓结构化就是三种结构:顺序结构,选择结构和循环结构。现在我们重点谈的是选择结构和循环结构。
要控制C语言的结构,需要用到控制语句,控制语句分为三大类,分支语句(if/else),循环语句(do while/while/for)和转向语句(break/go to/continue/return),括号中是他们都有特定的关键字。
if(条件)
语句;//如果条件满足,执行语句,不满足,什么也不发生
if(表达式)
语句;
else
语句
if(表达式)
语句一;
else if(表达式)
语句二;
else
语句三;
注:1.c语言没有18<=age<30的写法
2.if和else的匹配问题,else总是和最近的if匹配,使用{ }代码块提高代码风格,推荐书籍高质量c/c++编程
代码练习1.判断奇数
#include
int main()
{
int n = 0;
scanf("%d", &n);
if (n % 2)//n%2!=0 or n%2==1
{
printf("是奇数");
}
else
{
printf("不是奇数");
}
}
代码练习2.输入1~100的奇数
#include
int main()
{
int i = 1;
while (i <= 100)
{
if (i % 2)
{
printf("%d ", i);
}
i++;
}
}
//这种方法是利用while循环产生1~100个数字,再判断,另一种方法是直接在循环体内i+=2
if/else的形式过于复杂,使用switch语句可以增加代码的可读性
适用于多分支,入口与情况相互匹配,入口决定从哪里进,break决定从哪里出,break根据需要加在适合的位置,
如果你并不想忽略不匹配所有标签的表达式的值时该怎么办呢? 你可以在语句列表中增加一条default子句,把下面的标签 default:
写在任何一个 case 标签可以出现的位置。 当 switch 表达式的值并不匹配所有 case 标签的值时,这个 default子句后面的语句就会执行。所以,每个switch语句中只能出现一条default子句。
但是它可以出现在语句列表的任何位置,而且语句流会像执行一个case标签一样执行default子句
switch(入口:整型表达式)
{
语句项;
}
//是一些case语句:
//如下:
case 情况:整形常量表达式:
语句;
练习代码:输入几打印星期几
#include
int main()
{
int n = 0;
scanf("%d", &n);
switch(n)
{
case(1):
printf("周一\n");
break;
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;
}
根据需要也可以让多条case语句合并,最后只执行一条语句
#include
int main()
{
int n = 0;
scanf("%d", &n);
switch (n)
{
case(1):
case(2):
case(3):
case(4):
case(5):
printf("工作日\n");
break;
case(6):
case(7):
printf("休息日\n");
break;
default:
printf("输入错误\n");
break;
}
return 0;
}
switch语句允许嵌套使用
看下面这段代码,结果是什么呢?
#include
int main()
{
int n = 1;
int m = 2;
switch (n)
{
case 1:
m++;
case 2:
n++;
case 3:
switch (n)
{//switch允许嵌套使用
case 1:
n++;
case 2:
m++; n++;
break;
}
case 4:
m++;
break;
default:
break;
}
printf("m = %d, n = %d\n", m, n);
return 0;
}
m = 5, n = 3
//while 语法结构
while(表达式)
循环语句;
//break 代码实例
#include
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在while循环中的作用:
其实在循环中只要遇到break,就停止后期的所有的循环,直接终止循环。
所以:while中的break是用于永久终止循环的。
//continue 代码实例1
#include
int main()
{
int i = 1;
while(i<=10)
{
if(i == 5)
continue;
printf("%d ", i);
i = i+1;
}
return 0;
}
这里代码输出的结果是什么?
1 2 3 4
//continue代码示例2
#include
int main()
{
int i = 1;
while (i <= 10)
{
i = i + 1;
if (i == 5)
continue;
printf("%d ", i);
}
return 0;
}
这里代码输出的结果是什么?
2 3 4 6 7 8 9 10
总结: continue在while循环中的作用就是:
continue是用于终止本次循环的,也就是本次循环中continue后边的代码不会再执行,而是直接跳转到while语句的判断部分。进行下一次循环的入口判断。
while循环中的调整部分会让循环走到终止条件,如果continue跳过了调整部分则循环无法终止
getchar
int getchar ( void );
Get character from stdin
读取成功返回字符的ASCII码,读取失败返回EOF,本质为-1,
EOF - end of file 均为int类型(char存不下)
与之对应的是putchar(ch),Ctrl+Z可以使他读取失败返回EOF
#include
int main()
{
int ch = getchar();//'a'
putchar(ch);
return 0;
}
char password[20] = { 0 };
printf("请输入密码:>");
scanf("%s", password);//123456
printf("请确认密码(Y/N):>");
int ch = getchar();
if ('Y' == ch)
printf("确认成功\n");
else
printf("确认失败\n");
会显示确认失败,原因是用户通过键盘输入12345之后,scanf会读取空格之前的,所以scanf在读取时不读取\n也不读取空格,getchar()发现缓冲区里面有东西就会读取,所以可以利用getchar()清空缓冲区,getchar()工作一次,缓冲区就会少一个字符
//方法1
getchar();//处理\n
//方法2
int tmp = 0;
while ((tmp = getchar()) != '\n')
{
;
}
利用循环的方法清空缓冲区,为了让用户输入Y/N时没有干扰
#include
int main()
{
char ch = '\0';
while ((ch = getchar()) != EOF)
{
if (ch < '0'|| ch > '9')
continue;
putchar(ch);
}
return 0;
}
//这个代码的作用是:只打印数字字符,跳过其他字符的、
int ch = 0;
//可以持续输入,直到用户输入Ctrl+Z(VS下3次)
while ((ch = getchar()) != EOF)
putchar(ch);
while (scanf("%d", &ch) != EOF)
printf("%d ", ch);
注:在VS下测试的时候两种代码会有差别
for(表达式1; 表达式2; 表达式3)
循环语句;
表达式1: 表达式1为初始化部分,用于初始化循环变量的。
表达式2: 表达式2为条件判断部分,用于判断循环时候终止。
表达式3:表达式3为调整部分,用于循环条件的调整。
//for循环打印1~10
#include
int main()
{
int i = 0;
for (i = 1; i <= 10; i++)
{
printf("%d ", i);
}
return 0;
}
对于for循环的continue会来到调整部分,while会来到判断部分
相比while循环,for循环的三个必须条件很集中,查找修改方便。所以,for循环的风格更胜一筹;for循环使用的频率也最高。
for语句的循环控制变量
建议:
- 不可在for 循环体内修改循环变量,防止 for 循环失去控制。
- 建议for语句的循环控制变量的取值采用“前闭后开区间”写法
一些for循环的变种
#include
int main()
{
//代码1
//for循环的判断部分省略了,就意味着判断恒为真
for(;;)
{
printf("hehe\n");
}
//for循环中的初始化部分,判断部分,调整部分是可以省略的,但是不建议初学时省略,容易导致问题。
//代码2
int i = 0;
int j = 0;
//这里打印多少个hehe?
for(i=0; i<10; i++)
{
for(j=0; j<10; j++)
{
printf("hehe\n");
}
}
//代码3
int i = 0;
int j = 0;
//如果省略掉初始化部分,这里打印多少个hehe?
for(; i<10; i++)
{
for(; j<10; j++)
{
printf("hehe\n");
}
}
//代码4-使用多余一个变量控制循环
int x, y;
for (x = 0, y = 0; x<2 && y<5; ++x, y++)
{
printf("hehe\n");
}
return 0;
1.打印100个hehe
2.10个hehe
//请问循环要循环多少次?
#include
int main()
{
int i = 0;
int k = 0;
for(i =0,k=0; k=0; i++,k++)
k++;
return 0;
}
0次
do
循环语句;
while(表达式);
循环至少执行一次,使用的场景有限,所以不是经常使用。
do…while();循环的break和continue与while很类似
#include
int main()
{
int n = 0;
scanf("%d", &n);
int i = 0;
int ret = 1;
for (i = 1; i <= n; i++)
{
ret = ret * i;
}
printf("%d", ret);
return 0;
}
#include
int main()
{
int n = 5;
int i = 0;
int ret = 1;
int sum = 0;
for (i = 1; i <= n; i++)
{
ret = ret * i;
sum = sum + ret;
}
printf("%d", sum);
return 0;
}
1.二分查找的思路
2.代码实现
#include
int main()
{
int arr[] = { 1,2,3,4,5,6,7,8,9 };
int n = 0;
printf("请输入你要查找的数字");
scanf("%d", &n);
int left = 0;
int right = sizeof(arr)/sizeof(arr[0])-1;
while (left <= right)
{
int mid = left + (right - left) / 2;
int mid = (left + right) / 2;
if (arr[mid] < n)
{
left = mid + 1;
}
else if (arr[mid] > n)
{
right = mid - 1;
}
else
{
printf("找到了,下标为%d", mid);
return 0;
}
}
printf("找不到");
return 0;
}
//4. 编写代码,演示多个字符从两端移动,向中间汇聚。
// hello world!!!
// ##############
// h############!
// he##########!!
// ……
// hello world!!!
#include
#include
#include
int main()
{
char arr1[] = "hello world!!!";
char arr2[] = "##############";
int left = 0;
int right = sizeof(arr1) / sizeof(arr1[0]) - 2;
while (left <= right)
{
arr2[left] = arr1[left];
arr2[right] = arr1[right];
printf("%s\n", arr2);
left++;
right--;
Sleep(1000);
system("cls");
}
printf("%s", arr2);
}
这里涉及到sizeof()和strlen()的问题,strlen需要include
,他是库函数,统计\0之前的字符串的长度(不含\0),sizeof()统计的是元素整个的大小,如果是字符串也会计算\0(含\0)
//5. 编写代码实现,模拟用户登录情景,并且只能登录三次。(只允许输入三次密码,如果密码正确则
//提示登录成,如果三次均输入错误,则退出程序。
#include
#include
int main()
{
char psword[20] = { 0};
printf("请输入密码");
int i = 0;
for (i = 0; i < 3; i++)
{
scanf("%s", psword);
char arr[] = "abcdef";
if (strcmp(psword, arr) == 0)
{
printf("输入正确");
return 0;
}
else
{
printf("重新输入");
}
}
if (i == 3)
{
printf("三次均失败");
return 0;
}
}
在VS下,char psword[20] = {0};和char psword[20] = { };char psword[20]=" ";
psword里面的元素都被初始化为\0,ASCII码也是0 如果是’0’则是字符0,ASCII为48
1.产生1~100的随机数
2.玩家猜(互动)
3.游戏可以一直玩,循环至少进入一次,考虑使用do…while();,用户选择不同数字对应不同的游戏结果,所以采用switch的分支语句
int rand(void) 函数返回0~0X7FFF的数,也就是0至32767,如果使用 int ret=rand();,则每次产生一样的随机数,错误,在文档中对rand函数的说明中有 use the srand function to seed the psendorandom-number generator before calling rand,而文档对srand函数的解释是void srand(unsigned int seed),所以我们的思路是要给srand函数传一个随机数作为参数,这里可以想到时间作为一个一直变化的数字很适合,这里引入时间戳的概念,他是当前时间相较于计算机起始时间的差值,获取时间戳的方法是调用time函数,time函数可以返回一个时间戳
time_t time(time_t* timer) timer:storage location for time
如果要把时间戳存起来就要传一个地址给time函数,在外面创建一个time_t 类型的t变量,t的地址是time_t*类型的变量,然后把这个值传给timer,这样函数会把时间戳的值放进t,如果不想传,可以直接给NULL,该time函数会返回一个时间戳,只需要接收这个时间戳就可以,既可以把时间戳时间放进timer所指向的空间,也可以通过返回值
//调用time函数的方法:
time_t t=time(NULL);
time_t t;
time(&t);
tips:time_t本质是一个整数,srand需要一个unsigned int 的整数作为参数,所以需要这样写
> srand((unsigned int)time(NULL));
> int ret=rand();
但是发现这样还是不够随机原因是每次调用一次srand,频繁生成起点,那么便不够随机,就好像每次随机数都要重新算,为了让srand函数只调用一次就把他放进主函数
代码实现
#include
#include
#include
void meau()
{
printf("****** 猜数字游戏*******\n");
printf("******按1进入游戏*******\n");
printf("******按0退出游戏*******\n");
}
void game()
{
int ret = rand()%101;//控制范围
printf("请输入数字");
int guess = 0;
while (1)
{
scanf("%d", &guess);//这个要写在循环体内
if (guess > ret)
{
printf("猜大了\n");
}
else if (guess < ret)
{
printf("猜小了\n");
}
else
{
printf("猜对了\n");
break;
}
}
}
int main()
{
srand((unsigned int)time(NULL));
int n = 0;
do {
meau();
scanf("%d", &n);
switch (n)
{
case 1://玩游戏
game();
break;
case 0://退出游戏
printf("退出游戏\n");
break;
default:
printf("选择错误,重新选择\n");
break;
}
} while(n);
return 0;
}
C语言中提供了可以随意滥用的 goto语句和标记跳转的标号。 从理论上
goto语句是没有必要的,实践中没有goto语句也可以很容易的写出代码。
但是某些场合下goto语句还是用得着的,最常见的用法就是终止程序在某些深度嵌套的结构的处理过程。 例如:一次跳出两层或多层循环。
多层循环这种情况使用break是达不到目的的。它只能从最内层循环退出到上一层的循环
//goto语言真正适合的场景如下:
for(...)
for(...)
{
for(...)
{
if(disaster)
goto error;
}
}
…
error:
if(disaster)
// 处理错误情况
while VS goto
#include
#include
#include
int main()
{
char s[20] = "";
system("shutdown -s -t 60");
while (1)
{
printf("输入我是猪,取消关机\n");
scanf("%s", s);
if (strcmp(s, "我是猪") == 0)
{
system("shutdown -a");
break;
}
else
{
printf("重新输入\n");
}
}
return 0;
}
#include
#include
#include
int main()
{
char s[20] = "";
system("shutdown -s -t 60");
again:
printf("输入我是猪,取消关机\n");
scanf("%s", s);
if (strcmp(s, "我是猪") == 0)
{
system("shutdown -a");
}
else
{
goto again;
printf("重新输入\n");
}
return 0;
}