一、switch case 关键字
先来写一段代码来直接run起来。看看switch语句中一些注意点。
#include <stdio.h> int main() { int day = 0; scanf("%d", &day); switch (day) { 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; default: break; } return 0; }
提一句:scanf函数在visual studio 2022中是会出现报警的。有两种方法可以解决:
#define _CRT_SECURE_NO_WARNINGS 1(这个必须放在文件顶部)
#pragma warining(disable:4996)(但是建议放在文件顶部)
这就是switch语句基础语法。那么我们需要知道什么呢?
if语句和switch语句很相似。但是if语句判断的条件更丰富,switch只能用在整形或者整型表达式判定。在switch语句中case执行的是判断功能,break执行的是分支功能。
注意:
- 每个case语句的结尾绝对不要忘了breaK,否则会多个分支重叠(一般情况下)
- 最后必须使用default分支。即使程序不需要,也要保留default。
如果一个判断执行多条语句呢
#include <stdio.h> int main() { int day = 0; scanf("%d", &day); switch (day) { case 1: printf("星期一\n"); printf("星期一\n"); printf("星期一\n"); printf("星期一\n"); break; case 2: printf("星期二\n"); break; case 3: printf("星期三\n"); break; default: break; } return 0; }
像这种是可以一个判断,多个语句的。那么这样可以吗?
#include <stdio.h> int main() { int day = 0; scanf("%d", &day); switch (day) { case 1: int a = 1; printf("星期一\n"); printf("星期一\n"); printf("星期一\n"); printf("星期一\n"); printf("%d\n",a); break; case 2: printf("星期二\n"); break; case 3: printf("星期三\n"); break; default: break; } return 0; }
在visual studio 2022中是可以的,但是会有报错。怎么解决呢?
int main() { int day = 0; scanf("%d", &day); switch (day) { case 1: { int a = 1; printf("星期一\n"); printf("星期一\n"); printf("星期一\n"); printf("星期一\n"); printf("%d\n", a); } break; case 2: printf("星期二\n"); break; case 3: printf("星期三\n"); break; default: break; } return 0; }
在case语句中直接加上大括号,就可以解决这个问题了。(不建议这样写,建议套用函数)
同样也可以一个多个判断条件执行同一语句。
default问题:default可以在switch语句中任何一个位置。
规则:
case中禁止用return。
switch语句中不应该是有效的bool类型。
#include <stdio.h> int main() { int day = 0; int quit = 0; while (!quit)//!quit表示没有退出 { scanf("%d", &day); switch (day) { case 1: printf("星期一\n"); break; case 2: printf("星期二\n"); break; case 3: printf("星期三\n"); quit = 1;//quit=1就表退出 default: break; } } return 0; }
有效的去掉break。
不建议这种方法:
#include <stdio.h> int main() { int day = 0; int quit = 0; while (!quit)//!quit表示没有退出 { scanf("%d", &day); switch (day == 1) { case 1: printf("星期一\n"); break; case 2: printf("星期二\n"); break; case 3: printf("星期三\n"); quit = 1;//quit=1就表退出 default: break; } } return 0; }
3. const修饰的变量是否满足switch整型判断的要求呢?
答案是不满足的。
4. 按执行频率排列case语句。
总结:
switch语法结构中,case完成判断功能,break完成分支功能,default处理异常情况。
去掉break的方法:执行语句 == 1(不要用有效的bool类型);case多条语句中不能定义变量,如果要,就用{}或者函数。
3.执行多条语句时,case语句后不用写break。
4.default可以出现在switch语句中的任何地方,建议写在结尾。
5.case中不要用const修饰的常属性变量,建议用好的布局case方式。
二、循环
(一)、while循环
#include <stdio.h> int main() { int a = 10;//循环初始化 while (a > 0)//循环判断条件 { printf("%d\n", a); a--;//循环条件更新 } return 0; }
(二)、for循环
int main() { for (int i = 1; i < 10; i++)//初始化,条件判断,条件更新 { printf("%d\n", i); } return 0; }
(三)、do while循环
先执行后循环,至少执行一次。
int main() { int a = 10;//循环初始化 do { printf("%d\n", a); a--;//条件更新 } while (a > 0);//条件判断 }
(四)、死循环
#include <stdio.h> int main() { while(1){ printf("hello\n"); } return 0; }
#include <stdio.h> int main() { for (;;) { printf("hello\n"); } return 0; }
#include <stdio.h> int main() { do { printf("hello\n"); } while (1); return 0; }
这就没什么好说的了。
(五)、getchar()了解
下面我们来看看测试。
首先初步了解基本的接口getchar()。
getchar就是从流中获取一个字符。
首先我们了解在任何c程序之后,运行时,都会打开三个输入输出流(流:简单理解就是文件输入数据,然后保存下来并显示。)
默认打开stdin(标准输入)、stdout(标准输出)、stderr(标准错误),三个文件对应的类型都是file*,程序运行时默认就打开了这三个文件,stdin对应的设备就是键盘,stdout和stderr对应的设备就是显示器。
说了上面这么多,那为什么c语言从来没有打开过文件,可以通过键盘输入数据,还能显示屏输出?就是因为默认打开了三个输入输出流文件。
#include <stdio.h> int main() { while(1) { int c = getchar(); if('#' == c){ break; } printf("%c\n",c); } pringf("循环结束\n"); return 0; }
输出结果:
那么我们可以看到输出后隔了两行 ,这是什么问题呢?
当我们输入时,我们会按下回车(enter)键,相当于一个\n,就多换行了一次。也就出现现在的结果。怎么解决呢?其实很简单,就是把%c后的\n删掉就ok了。所以,注意getchar会获取回车。
补充:getchar返回是int类型,如果返回不在八个比特位[0 ~ 255]取值范围,就会出现数据丢失,不能读取全部的二进制数据,发生截断。
通过键盘输入输出的内容全是字符,怎么证明呢?
显然就是输出的全是字符。
那么补充一点:键盘和显示器都是字符设备。
三、break、continue关键字
(一)、break关键字
#include <stdio.h> int main() { while (1) { int c = getchar(); if ('#' == c) { break; } putchar(c); } printf("\nbreak out\n"); return 0; }
运行结果:
可见:break是跳出循环。直接跳出到循环作用域外。
(二)、continue关键字
#include <stdio.h> int main() { while (1) { int c = getchar(); if ('#' == c) { continue; } putchar(c); } printf("\nbreak out\n"); return 0; }
运行结果:
可见:continue的作用是本次循环结束。下次循环再从循环开始,什么意思?看图就知。
这是在while循环中,在do while循环中:
int main() { do { int c = getchar(); if ('#' == c) continue; putchar(c); } while (1); return 0; }
continue是从条件判断处开始。
在for循环中,continue是从哪里开始呢?
int main() { int i = 0; for (; i < 10; i++) { printf("continue before:%d\n", i); if (5 == i) continue; printf("continue after:%d\n", i); } return 0; }
运行告诉我们结果;
(三)、总结
while和do while循环中的continue都是从条件判断开始,而for循环是从条件调整开始的。
四)、循环语句注意事项
- 在多重循环中,如果有可能,应当把最长的循环放在最内层,最短的循环放在最外层,以减少CPU跨切循环层的次数。(不强求,看情况)
- 建议for循环控制变量的取值采用“半开半闭区间”写法。(循环次数明确,便于进行个数计算)
#include <stdio.h> int main() { int i = 0; for(i=0;i<10;i++){ printf("%d ",i); } return 0; }//更直观的知道了循环次数,如果是i<10写成i<=9,则不是很直观
#include <stdio.h> int main() { int i = 3; for(i=3;i<10;i++){ printf("%d ",i); } return 0; }//这样直接做减法,直接求出次数
四、goto关键字
直接run代码起来。
//后goto死循环 #include <stdio.h> int main() { end: printf("hello 1\n"); printf("hello 2\n"); printf("hello 3\n"); goto end; printf("hello 4\n"); printf("hello 5\n"); printf("hello 6\n"); return 0; }
//前goto不是死循环 #include <stdio.h> int main() { goto end; printf("hello 4\n"); printf("hello 5\n"); printf("hello 6\n"); end: printf("hello 1\n"); printf("hello 2\n"); printf("hello 3\n"); return 0; }
基本goto语法知道了,下面我们来测试一下。
int main() { int i = 0; start: printf("[%d] goto running ...\n",i); i++; if (i < 10) { goto start; } printf("goto end ... \n"); return 0; }
运行结果是:
(一)、建议
能力强可以使用goto语句,并有奇效。
五、void关键字
#include <stdio.h> int main() { void v;//err printf("%d\n",sizeof(void));//打印结果是0 return 0; }
在不同的visual studio 2022中会出现报错,在别的编译器上就不一定,大家都应该理解void没有开辟空间,其实不是。在visual studio 2022中打印的是0,但是gcc编译器是1,所以不能用来定义变量是因为void在编译器中被约定的是空类型,强制的不能用来定义变量。
(一)、void的作用
1.void作为函数返回值
#include <stdio.h> void test() //test() { printf("success"); return 1; } int main() { //test(); //ok int tes = test();//err return 0; }
总结:
c语言中函数可以不带返回值,默认返回值是int类型。(不需要返回值时,应该带上void类型而不是不写返回类型,这要会让读者造成误解,到底是默认值还是你忘写了返回类型)
void修饰函数返回值时,1.作为占位符,让用户明确不需要返回值。2.告知编译器,这个返回值无法接受。
2.void作为函数参数
#include <stdio.h> int test1() { return 1; } int test2(void)//告知这个函数不需要传参 { return 1; } int main() { test1(1, 2, 3);//可以传参 test2(1, 2, 3);//也可以运行,但是有警告,void参数列表声明 return 0; }
当void作为函数参数时,作用是告知用户或者编译器不需要传参。
(二)、void指针
#include <stdio.h> int main() { void *p = NULL;//OK double* d = NULL; int* i = NULL; d = p;//ok i = p;//ok p = d;//ok p = i;//ok return 0; }//编译通过(无报错)
因此,void * 可以被任何类型的指针接收,void *可以接收任意类型指针。
(三)、void定义的指针可以进行运算操作吗?
#include <stdio.h> int main() { void *p = NULL; p++;//err p--;//err return 0; }
在visual studio 2022是不能运行的,在linux中是可以的。不同平台有不同的现象。
为什么不同平台,编译器会有不同的结果?
因为不同的平台使用的c标准也是不一样的。
补充:
void *是用来设计通用接口的。
void *是不能解引用的。