c语言关键字理解和再认识(下)(1)

简介: 一、switch case 关键字先来写一段代码来直接run起来。看看switch语句中一些注意点。

一、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执行的是分支功能。

注意:

  1. 每个case语句的结尾绝对不要忘了breaK,否则会多个分支重叠(一般情况下)
  2. 最后必须使用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。

b3c4b59252a49289a5e89545dd45abee.png

不建议这种方法:

#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;
}

c7f86b36592ee4b9d8c49de656e56e29.png


3. const修饰的变量是否满足switch整型判断的要求呢?

答案是不满足的。

b546eeb03eb00617a2482960389e3b37.png

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;
}

输出结果:

707d8f1c27f94eb33ecbbd673cc3f4bd.png

那么我们可以看到输出后隔了两行 ,这是什么问题呢?

当我们输入时,我们会按下回车(enter)键,相当于一个\n,就多换行了一次。也就出现现在的结果。怎么解决呢?其实很简单,就是把%c后的\n删掉就ok了。所以,注意getchar会获取回车

补充:getchar返回是int类型,如果返回不在八个比特位[0 ~ 255]取值范围,就会出现数据丢失,不能读取全部的二进制数据,发生截断。

通过键盘输入输出的内容全是字符,怎么证明呢?

17c397a130285c5b23551e96d804f3f3.png

显然就是输出的全是字符。

那么补充一点:键盘和显示器都是字符设备。

三、break、continue关键字

(一)、break关键字

#include <stdio.h>
int main()
{
  while (1) {
    int c = getchar();
    if ('#' == c)
    {
      break;
    }
    putchar(c);
  }
  printf("\nbreak out\n");
  return 0;
}

运行结果:


1161a26cb4a1636257fe09e8573411b5.png

可见:break是跳出循环。直接跳出到循环作用域外。

(二)、continue关键字

#include <stdio.h>
int main()
{
  while (1) {
    int c = getchar();
    if ('#' == c)
    {
        continue;
    }
    putchar(c);
  }
  printf("\nbreak out\n");
  return 0;
}

运行结果:


2f7773fc49de4a04510f05901d3533cd.png

可见:continue的作用是本次循环结束。下次循环再从循环开始,什么意思?看图就知。


2868a94b8b4d7afcdb5fd04b5d89be10.png

这是在while循环中,在do while循环中:

int main()
{
  do
  {
    int c = getchar();
    if ('#' == c)
      continue;
    putchar(c);
  } while (1);
  return 0;
}

continue是从条件判断处开始。


e02764766c15718a914efcf74179d353.png

在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;
}

运行告诉我们结果;


image.png

(三)、总结

while和do while循环中的continue都是从条件判断开始,而for循环是从条件调整开始的。

四)、循环语句注意事项

  1. 在多重循环中,如果有可能,应当把最长的循环放在最内层,最短的循环放在最外层,以减少CPU跨切循环层的次数。(不强求,看情况)
  2. 建议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;
}

运行结果是:



9e25360fa3d16c130fc538337349f116.png

(一)、建议

能力强可以使用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 *是不能解引用的。



















相关文章
|
6月前
|
存储 程序员 C语言
C语言关键字是什么?什么是关键字?什么是字符和ascll码值
C语言关键字是什么?什么是关键字?什么是字符和ascll码值
|
4月前
|
C语言
|
4月前
|
存储 C语言
C语言中static关键字的作用与用法解析
C语言中static关键字的作用与用法解析
|
5月前
|
存储 C语言
C语言中的typedef关键字:为类型定义新名称
C语言中的typedef关键字:为类型定义新名称
|
5月前
|
C语言
深入探索C语言中的sizeof关键字
深入探索C语言中的sizeof关键字
|
5月前
|
存储 编译器 C语言
C语言中的关键字与标识符详解
C语言中的关键字与标识符详解
|
6月前
|
算法 编译器 API
C语言易混淆、简单算法、结构体题目练习、常见关键字总结-1
C语言易混淆、简单算法、结构体题目练习、常见关键字总结
|
6月前
|
安全 编译器 C语言
C语言中的const关键字
C语言中的const关键字
50 2
|
6月前
|
存储 C语言
【C语言】数据:数据类型关键字
【C语言】数据:数据类型关键字
|
6月前
|
存储 编译器 C语言
c语言中static关键字的作用
c语言中static关键字的作用