• 32个关键字详解①(C语言)


    目录

    关键字分类:

    第一个C程序 - 补充内容

    变量的定义与声明 - 补充内容

    变量的分类 - 补充内容

    变量的作用域 - 补充内容

    变量的生命周期 - 补充内容

    auto 关键字

    register 关键字

    static 关键字

    static 修饰变量:

    static修饰函数

    sizeof 关键字

    基本数据类型:

    sizeof介绍:

    signed、unsigned 关键字

    整型在内存中的存储:

    大小端 补充

    整型取值范围

    if else 关键字

    什么是语句:

    什么是表达式:

    if else 语句:


    关键字分类:

    C语言中总共有多少个关键字呢?一般我们所见的书上都是32个,但是这些书是按照C90或C89的标准,其实C99后又新增了5个关键字,不过我们目前的主流编译器,对C99的支持并不好,接下来我们主要按照C90标准来讲解,即认为32个关键字!接下来我们先简单看一下这32个关键字:

    下面我们一个一个的来详解这32个关键字 

    在了解之前我们得深入认识理解一些知识:

    第一个C程序 - 补充内容

    以代码的形式解释说明:

    1. //编写第一个C程序"hello world"
    2. #include
    3. int main()
    4. {
    5. printf("hello world!\n");
    6. return 0;
    7. }
    8. //运行程序的方式,当然可以用vs直接启动
    9. //当然,也可以在vs项目中,找到代码生成的二进制可执行程序,双击即可。
    10. //所以:我们的角色是写代码,编译器的角色是把文本代码变成二进制可执行程序。
    11. //双击?不就是windows下启动程序的做法吗?
    12. //那么启动程序的本质是什么呢?就是将程序数据,加载到内存中,让计算机运行!

    变量的定义与声明 - 补充内容

    因为有些关键字是用来修饰变量的,我们在介绍关键字之前,先来深度了解一下变量!

    什么是变量(是什么)?

            在内存中开辟特定大小的空间,用来保存数据!

    如何定义变量(怎么用)?

            int x =10;

            char c='a';

            double d=3.14;

            类型 变量名 = 默认值;

    为什么要定义变量?

            计算机是为了人类计算能力不足的问题而诞生的,即,计算机是为了计算的。而计算,就需要数据,而在计算的时候,任何一个时刻,不是所有在内存中的数据立马被计算,有时部分数据是不参与运算的,而不需要计算的数据就要被临时的保存起来,等待后续处理,而这些数据我们用变量保存!以供我们后续的使用,使用那个数据就拿取其对应的变量即可!

    变量定义的本质

            我们知道:1、程序运行需要加载到内存。2、程序计算需要使用变量。那么定义变量的本质就是:在内存中开辟一块空间,用来保存数据(为何一定要保存到内存?因为定义变量也是程序逻辑的一部分,程序已经加载到内存中了,所以变量是在内存中定义的!)

    变量声明的本质

            通俗一说就是提前告诉编译器我定义了一个变量!

    注意:定义只能有一次,而声明可以有多次!

    变量的分类 - 补充内容

    局部变量:

            包含在代码块也就是大括号{}中的变量叫做局部变量,局部变量具有临时性。进入代码块,自动形成局部变量,出了代码块自动释放!

    全局变量:

            在所有函数外定义的变量,叫做全局变量,全局变量具有全局性!

    代码块:

            用{}括起来的区域,就是代码块

    上代码:

    1. #include
    2. int g_value = 20;//全局变量
    3. int main()
    4. {
    5. //main函数也是函数,也有{}代码块!
    6. int a = 10;//局部变量
    7. printf("%d\n", a);
    8. return 0;
    9. }

    变量的作用域 - 补充内容

    作用域的概念:

            变量的作用域指的是该变量可以被正常访问的代码区域!

    局部变量的作用域:

            作用域也就是该变量的作用范围,通俗点说就是该变量只能在定义它的代码块{}内使用,而出了代码块就不能使用了!

    全局变量的作用域:

            全局变量具有全局性,在整个程序运行期间都有效,作用于整个程序!

    上代码:

    1. //局部变量
    2. //只作用于本代码块{}
    3. #include
    4. int main()
    5. {
    6. int x = 10;
    7. if (x == 10)
    8. {
    9. int y = 20;
    10. printf("局部: x: %d, y: %d\n", x, y);//y只能在本代码块内有效
    11. }
    12. printf("局部: x: %d, y: %d\n", x, y); //报错,y不能被访问
    13. return 0;
    14. }
    15. //全局变量
    16. //作用于整个程序
    17. #include
    18. int sum = 100;//全局变量
    19. void test(void)
    20. {
    21. printf("test 全局:%d\n", sum);
    22. }
    23. int main()
    24. {
    25. printf("main 全局:%d\n", sum);
    26. test();
    27. return 0;
    28. }
    29. //全局变量和局部变量命名冲突时
    30. #include
    31. int a_b = 25;//全局变量
    32. int main()
    33. {
    34. int a_b = 30;
    35. printf("%d\n", a_b);//30
    36. //局部变量和全局变量命名冲突时,优先使用局部变量!
    37. //强烈不建议这样写
    38. return 0;
    39. }

    变量的生命周期 - 补充内容

    生命周期:

            指的是该变量从定义到释放的时间范围,所谓释放,指的是曾经开辟的空间被释放!

    局部变量的生命周期:

            进入代码块,形成局部变量也就是开辟空间,生命周期开始,退出代码块,释放 局部变量,生命周期结束!

    全局变量的生命周期:

            定义完成之后,程序运行的整个生命周期内,该变量一直有效!

    生命周期通俗点讲,可以理解为变量存活的时间,局部变量的作用域跟生命周期都是在出了代码块就失效了,也就是出代码块就死了,而全局变量的生命周期就是整个程序结束才失效!

            

    auto 关键字

    最宽宏大量的关键字-auto

    一般定义在代码块中的变量,即局部变量,默认都是由auto修饰的,不过省略不写!auto关键字一般默认修饰局部变量,而全局变量不是默认auto 修饰的!注意:我们所听到的,局部变量,自动变量,临时变量,都是一回事,我们统称为局部变量!

    上代码:

    1. #include
    2. //全局变量不是默认auto修斯的
    3. auto int g_va = 100;//vs编译器会有警告
    4. int main()
    5. {
    6. //局部变量默认都是由auto修饰的不过一般省略不写
    7. auto int a = 10;
    8. //auto修饰局部变量i
    9. for (auto int i = 0; i < 10; i++) {
    10. printf("i=%d\n", i);
    11. if (1)
    12. {
    13. //auto修饰局部变量j
    14. auto int j = 0; //自动变量
    15. printf("before: j=%d\n", j);
    16. j += 1;
    17. printf("after : j=%d\n", j);
    18. }
    19. }
    20. return 0;
    21. }

    register 关键字

    最快的关键字 - register

    在了解register关键字的作用之前,我们得先了解寄存器的概念!

    寄存器:

            计算机中cpu主要是负责计算的硬件单元,但是为了方便运算,一般第一步需要先把数据从内存读取到cpu内,那么也就需要cpu具有一定的数据临时存储能力!注意:cpu并不是当前要计算的时候才把特定的数据读到cpu里面,那样太慢了。所以现在的cpu内,都集成了一组叫做寄存器的硬件,用来做临时数据的保存!通俗一点讲,就是把常用的数据放到寄存器中,或者是将快要计算的数据拿到寄存器中,然后cpu直接从内部的寄存器中使用,这样速度更快,效率高!

    寄存器存在的本质:

            在硬件层面上,提高计算机的运算效率,因为不需要在内存中读取数据了,速度块! 

    register 修饰变量

            尽量将所修饰的变量,放入CPU寄存区中,从而达到提高效率的目的!register关键字是修饰变量的,那么怎样的变量,可以采用register修饰呢?

    register可修饰的变量:

    1、修饰局部变量(不可修饰全局变量,全局会导致CPU寄存器长时间被占用)

    2、不会被写入的变量(写入就继续写会内存,而register是优化到寄存器中的)

    3、高频读取使用的(提高效率)

    4、 如果要使用不要大量使用,寄存器数量有限!

    注意:register 修饰的变量不能被取地址(因为register修饰的变量会被存放在寄存区中,而地址的概念是对于内存而言的,所以不能取地址)!

    上代码:

    1. #include
    2. int main()
    3. {
    4. //用register 修饰变量
    5. //尽量将所修饰的变量放入寄存区中,
    6. //注意尽量这个词,说明也有可能没有被放到寄存区中,还是存放在内存中
    7. register int s = 20;
    8. printf("%d\n", s);
    9. register int a = 0;
    10. printf("&a = %p\n", &a);
    11. //编译器报错:错误 1 error C2103: 寄存器变量上的“&”
    12. //注意,这里不是所有的编译器都报错,目前我们的vs2019是报错的。
    13. //有些编译器不报错的原因是,有可能修饰的变量没有被优化到寄存区中
    14. //还是存放在内存中,所以可以取地址!
    15. return 0;
    16. }

    建议:在实际应用中,该关键字不用管,因为现在的编译器已经很智能了,能够进行比人更好的代码优化。早期编译器是因为需要认为指定register,来进行手动优化,现在不需要了,现在的编译器会自动给你优化好,且优化能力比人为更好!

    static 关键字

    static - 最名不符实的关键字

    认识多文件:

            在C程序中我们可以定义多个源文件,但在源文件之间函数和全局变量是可以跨文件访问的,跨文件访问的前提是需要在使用的文件或者是在头文件中进行声明之后才可以访问,然而函数可以不进行声明直接访问但是会有警告!

    上代码:

    1. //定义两个源文件,让其跨文件访问
    2. //test.c文件里的代码
    3. #include
    4. int g_value = 100;//全局变量
    5. int a = 200;//全局变量
    6. void show(void)//函数
    7. {
    8. printf("hehe\n");
    9. }
    10. //main.c文件里的代码
    11. #include
    12. //extern int a = 200;//声明的时候不可进行赋值操作!会报错
    13. extern int g_value;//声明全局变量
    14. extern void show(void);//声明函数
    15. int main()
    16. {
    17. show();//不用声明也可跨文件访问,但会有警告
    18. //声明了就没有警号
    19. printf("%d\n", g_value);//声明之后才可跨文件访问
    20. return 0;
    21. }

    对于上述代码我们其实还可以优化,直接用一个头文件来声明函数、全局变量...等,在用的时候只需要让源文件包含该头文件即可

    上代码:

    1. //创建一个头文件来声明我们所需要的数据
    2. //再创建两个源文件,进行交互操作
    3. //test.h 头文件的内容
    4. #pragma once //防止头文件被重复包含
    5. #include
    6. #include
    7. extern int g_value;//声明全局变量
    8. extern void show(void);//声明函数
    9. //test.c 文件的内容
    10. #include "test.h"//包含头文件
    11. int g_value = 100;//全局变量
    12. int a = 200;//全局变量
    13. void show(void)//函数
    14. {
    15. printf("hehe\n");
    16. }
    17. //main.c文件的内容
    18. #include "test.h"//包含头文件
    19. int main()
    20. {
    21. show();
    22. printf("%d\n", g_value);//声明之后才可跨文件访问
    23. return 0;
    24. }

    两个结论:

    1、全局变量:是可以跨文件,被访问的!

    2、全局函数:是可以跨文件,被访问的!

    为什么会跨文件访问?

            因为有一定规模的项目,一定是多文件来写的,多个文件之间,后续是一定是要进行数据”交互“的也就是互相使用的,为了很好的让多个文件的数据进行交互,所以必须是能够跨文件访问的。如果不能跨文件访问,交互的成本就比较高了,总之为了更好的实现交互,所以就得跨文件访问!

    static 修饰变量:

    修饰全局变量:

            该全局变量只能在本文件内被使用!static修饰全局变量改变的是其作用域,全局变量的生命周期是不变的!

    上代码:

    1. //创建一个头文件来声明我们所需要的数据
    2. //再创建两个源文件,进行交互操作
    3. //test.h 头文件的内容
    4. #pragma once //防止头文件被重复包含
    5. #include
    6. extern void he(void);//声明函数
    7. //test.c 文件的内容
    8. #include "test.h"//包含头文件
    9. static int g_va = 300;//全局变量
    10. void he(void)
    11. {
    12. printf("%d\n", g_va);//只能在本文件内使用,影响的是其作用域
    13. //不能被其它文件直接使用,但可以被间接的使用!
    14. }
    15. //main.c文件的内容
    16. #include "test.h"//包含头文件
    17. int main()
    18. {
    19. //printf("%d\n", g_va);//不能直接使用static修饰的全局变量会报错
    20. //可以通过函数调用间接使用
    21. he();
    22. return 0;
    23. }

    ​​​​

    修饰局部变量:     

            static修饰局部变量,改变的是变量的生命周期,不改变其作用域,将局部变量的临时生命周期,改为全局生命周期!但作用域没改变!通俗点说,就是让局部变量存活的更久,但使用的时候只能在,它所在的{}代码块中使用!

    static修饰局部变量的本质:

            我们先来了解一张布局图:

    static修饰的局部变量会被放到全局数据区内,但具体放到那个区域是由编译器决定的,而全局数据区内的变量,在整个进程中生命周期都是有效的,即static修饰局部变量,改变其生命周期! 

    上代码:

    1. #include
    2. void fun1()
    3. {
    4. //没有任何修饰
    5. //每次函数调用都会给变量开辟空间
    6. //函数结束空间会被释放!
    7. int i = 0;
    8. i++;
    9. printf("no static: i=%d\n", i);
    10. }
    11. void fun2()
    12. {
    13. //用static修饰
    14. //函数在第一次调用的时候开辟好空间
    15. //后续调用的时候不再开辟空间
    16. //函数结束也不会被释放
    17. //生命周期变为全局生命周期
    18. //作用域没变,只能在函数的{}代码块内使用
    19. static int i = 0;
    20. i++;
    21. printf("has static: i=%d\n", i);
    22. }
    23. int main()
    24. {
    25. for (int i = 0; i < 10; i++)
    26. {
    27. fun1();
    28. fun2();
    29. }
    30. return 0;
    31. }
    32. //结论:static修饰局部变量,变量的生命周期变成全局周期。(作用域不变)

    static修饰函数

    static修饰函数:

            其实跟修饰全局变量类似,被修饰的该函数,只能在本文件内使用,不能被其它文件直接访问!改变的是其作用域,生命周期不变!也就是将全局范围的作用域,改为局部范围的作用域!虽然不能被其它文件直接访问,但可以被间接访问!

    上代码:

    1. //创建一个头文件来声明我们所需要的数据
    2. //再创建两个源文件,进行交互操作
    3. //test.h 头文件的内容
    4. #pragma once //防止头文件被重复包含
    5. #include
    6. extern void poos(void);//声明函数
    7. extern void ass(void);//声明函数
    8. //test.c 文件的内容
    9. #include "test.h"//包含头文件
    10. static void poss(void)
    11. {
    12. printf("static修饰的poss函数调用(访问)成功\n");
    13. printf("static修饰函数只能在本文件test.c内使用,不能被其它文件直接访问!\n");
    14. printf("但是可以被其他文件间接访问\n");
    15. }
    16. void ass(void)
    17. {
    18. printf("通过ass函数内部调用static修饰的poss函数\n");
    19. poss();
    20. }
    21. //main.c文件的内容
    22. #include "test.h"//包含头文件
    23. int main()
    24. {
    25. //poss();//static修饰的函数 不能被其它文件直接访问,会报错
    26. ass();//通过ass函数间接访问static修饰的poss函数
    27. return 0;
    28. }
    29. //结论:static修饰函数,该函数只能在本文件中使用,改变的是其作用域

    sizeof 关键字

    基本数据类型:

    在C语言中有内置类型,以及我们自定义的类型!

    数据类型介绍:

     

    如何看待数据类型:

    前面说过定义变量的本质是:在内存中开辟一块空间,用来保存数据!然而定义一个变量是需要数据类型的,这个是基本语法决定的。那么类型决定了:变量开辟空间的大小!

    为什么要存在数据类型?

            有一个问题:为什么要根据数据类型,开辟一块空间,直接使用内存整体不好吗?

    答案:不好,因为在计算机中,程序运行需要加载到内存,而在任何时刻都不是你的一个程序在运行,还有很多其它程序也在运行,假设你的程序运行用了整块内存,那其它程序就无法正常运行了。另外还有一点,假设你整块内存都用了,但是你基本上全部空间都用不完,站在计算机的角度来说,给你空间你用不完,就是浪费!最好的解决方法就是一个程序用多大的空间,计算机就给它合理安排多大的空间使用。

    那么问题又来了,一个程序使用内存,使用多大空间是由什么决定的呢?

            其实就是你的使用场景决定的,你的计算场景,决定了你使用什么类型的变量进行计算。你所使用的类型决定了你所开辟的空间大小!

    sizeof介绍:

    sizeof也是C语言的关键字,同时它也是一个操作符,它的作用就是用来计算数据类型以及变量等...所占空间的大小单位是字节!注意:sizeof是一个操作符,不是函数!

    sizeof用途:

    我们知道定义变量的本质是:在内存中开辟一块空间,用来保存数据,而定义一个变量是需要类型的,类型决定了,变量开辟空间的大小,而sizeof就可以帮我们计算出它所开辟的空间的大小单位是字节!

    上代码:

    1. #include
    2. int main()
    3. {
    4. //计算每种数据类型的大小单位是字节
    5. //%zd是sizeof操作符匹配的占位符!
    6. //当然%d也是可以打印出来的
    7. //%u也是可以的
    8. printf("%zd\n", sizeof(char)); //1
    9. printf("%zd\n", sizeof(short)); //2
    10. printf("%zd\n", sizeof(int)); //4
    11. printf("%zd\n", sizeof(long)); //4
    12. printf("%d\n", sizeof(long long)); //8
    13. printf("%d\n", sizeof(float)); //4
    14. printf("%u\n", sizeof(double)); //8
    15. return 0;
    16. }

    sizeof和函数的书写区别

            sizeof在计算变量以及自定义类型的大小的时候是允许不带括号的!而函数就必须要有括号,总之sizeof是一个操作符,不是函数

    上代码:

    1. //定义一个结构体
    2. struct AA
    3. {
    4. int a;
    5. float b;
    6. char c;
    7. };
    8. int main()
    9. {
    10. //计算结构体的大小
    11. printf("%zd\n", sizeof(struct AA));//必须带括号
    12. //定义结构体变量
    13. struct AA s = { 0 };
    14. //可以带括号,也可不带
    15. printf("%zd\n", sizeof(s));//带括号
    16. printf("%zd\n", sizeof s);//不带括号
    17. int a = 10;
    18. printf("%zd\n", sizeof(a));
    19. printf("%zd\n", sizeof a);
    20. //对于类型必须带括号
    21. printf("%zd\n", sizeof(int));
    22. printf("%zd\n", sizeof(float));
    23. printf("%zd\n", sizeof(double));
    24. return 0;
    25. }

    sizeof 在数组中运用:

            1、sizeof(数组名):表示整个数组的大小

    上代码:

    1. #include
    2. int main()
    3. {
    4. //定义一个整型数组
    5. int arr[] = { 1,2,3,4,5 };
    6. //用sizeof计算整个数组的大小
    7. printf("%d\n", sizeof(arr));//表示整个数组的大小!
    8. printf("%d\n", sizeof arr);
    9. //sizeof计算数据类型的时候要带括号其它情况下后面也可以不带括号
    10. return 0;
    11. }

    signed、unsigned 关键字

    整型在内存中的存储:

    signed 表示有符号,unsigned 表示无符号!

    有符号整数 和 无符号整数介绍:

     原反补的概念:

            我们知道一个变量的创建是要在内存中开辟空间的,空间的大小是根据类型而决定的!那么数据在所开辟的空间中如何存储的呢?

    有符号数:

            定义两个变量:int a=20; int b=-10;  我们知道编译器对变量a和b分别开辟4个字节的空间!那么这些数值该如何存储呢?

           首先,对于有符号数,一定要能表示该数据是正数还是负数。所以我们一般用最高比特位来进行充当符号位。

    原码、反码、补码 :

    计算机中的有符号数有三种表示方法,即原码、反码和补码。 三种表示方法均有符号位和数值位两部分,符号位都是用0表示“正”,用1表示“负”,而数值位三种表示方法各不相同。

    如果一个数据是负数,那么就要遵守下面规则进行转化:

    原码:直接将二进制按照正负数的形式翻译成二进制就可以。

    反码:将原码的符号位不变,其他位依次按位取反就可以得到了。

    补码:反码+1就得到补码。

    如果一个数据是正数:

    那么它的原反补都相同。

    无符号数:

    不需要转化,也不需要符号位,原反补相同。

    对于整形来说:

    数据存放内存中其实存放的是补码。

    取数据:

    我们从开辟的空间里面取数据的时候,因为空间里面存的是二进制的补码,我们取的时候要显示的原码,所以在取的时候,有符号数和无符号数也略有差异!

    对于有符号数:

    如果该数是一个负数:先将补码转为原码,补码转原码的方法有两种:第一种是:将原码转补码倒着回去:让补码-1得到反码,再让反码符号位不变其它位按位取反得到原码。第二种是:重新让补码再走一遍原码转补码的过程:让补码符号位不变其他位按位取反得到一个二进制序列,再让这个二进制序列+1得到原码!

    如果该数是一个正数:正数的原码、反码、补码,相同,直接不加转换的取出来即可!

    对于无符号数:

    取得时候压根不关心符号位,它的最高位也是数值位,空间中放的是什么二进制序列,就将这个二进制序列的符号位当作数值位直接取出来!

    上代码:

    1. #ifndef _CRT
    2. #define _CRT
    3. #include
    4. #endif
    5. int main()
    6. {
    7. //数据的存:
    8. signed int a = 20;
    9. //20是正整数
    10. // 正数的原,反,补相同!
    11. // 原码就是补码!
    12. //补码:0000 0000 0000 0000 0000 0000 0001 0100
    13. //内存中存的就是补码
    14. signed int b = -10;
    15. //-10是负数
    16. //原码:1000 0000 0000 0000 0000 0000 0000 1010
    17. //反码:1111 1111 1111 1111 1111 1111 1111 0101
    18. //补码:1111 1111 1111 1111 1111 1111 1111 0110
    19. //内存中存的是补码
    20. //
    21. unsigned int c = -10;
    22. //c是一个无符号数 空间里面存放的是-10的补码
    23. //数据的取:
    24. printf("%d\n", a);//%d是以有符号的形式取,将有符号数a取出来结果还是20
    25. printf("%d\n", b);//b是负数,取得时候补码转成原码
    26. //补码转原码
    27. //方法一:先 - 1,在符号位不变,按位取反。
    28. //方法二:将原码到补码的过程在来一遍。
    29. printf("%u\n", c);//%u是无符号的形似取,直接将空间里的二进制序列转出数值!
    30. //把该二进制的符号位当作是数值位直接取
    31. //也就是将-10的补码,且将符号位看成数值位直接取出来!
    32. printf("%d\n", c);//然而以%d有符号的形式取的时候,取出来的是-10
    33. //但会有警告
    34. return 0;
    35. }

    深入理解变量内容的存入和取出:

    代码形式注释说明:

    1. #include
    2. int main()
    3. {
    4. signed int b = -10;
    5. unsigned int d = -10; //(是否合的)
    6. printf("%d\n", b);//取得时候补码转回原码
    7. printf("%u\n", d);//取得时候直接将补码当成数值取出来,不考虑符号位!
    8. //结论:
    9. //存:字面数据必须先转成补码,在放入空间当中。
    10. //所以,所谓符号位,完全看数据本身是否携带+-号。和变量是否有符号无关!
    11. //取:取数据一定要先看变量本身类型,然后才决定要不要看最高符号位。如果不需要,直接二进制转成十进制。
    12. // 如果需要,则需要转成原码,然后才能识别。(当然,最高符号位在哪里,又要明确大小端)
    13. return 0;
    14. }

    十进制二进制快速转换:

            1后面跟几个0就是2的几次方!

    上代码:

            

    1. #include
    2. int main()
    3. {
    4. int a = 10;
    5. //10可以分解为:8+2 等同于 2^3 + 2^1
    6. //根据口诀 2的几次方就是1后面有几个0
    7. //10的二进制原码:1010
    8. //补齐32比特为:0000 0000 0000 0000 0000 0000 0000 1010
    9. return 0;
    10. }

    为什么存的都是补码?

            在计算机系统中,数值一律用补码来表示和存储。原因在于,使用补码,可以将符号位和数值域统一处理; 同时,加法和减法也可以统一处理(CPU只有加法器)。此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。

    大小端 补充

    大小端其实就是对数据的不同存储方式产生的两种存储方式,全称是:大端字节序存储 和 小端字节序存储!

    因为计算机厂商的不同,对于内存设计的存储方式不同,所以才会产生两种不同的存储方式:大端存储和小端存储!

    大小端是如何存储:

            我们知道数据有高权值为和低权值位之分,打个比方:存在数字123,则数字1是权值最高的位,而3是权值最低的位!内存也有高地址和地址之分。在存储的时候是将数值按照字节为单位存入到内存中的!

    小端字节序存储:

            数据的低权值位存到内存的低地址处,高权值位存到高地址处(数据倒着存)

    大端字节序存储:

            数据的高权值位存到内存的低地址处,低权值位置存倒高地址处(数据顺着存)

    画图理解:

     

    数据的取:

    1、先考虑大小端

            按照大(小)端存进去,就按照大(小)端取出来,也就是怎么存进去就怎么取出来!

    2、在看变量的类型

            以何种方式取,就按照那种方式来解读存进去的这段二进制序列!

    整型取值范围

    为了方便介绍:这里使用char类型来介绍,char也是整型家族的一员!

    char又分为unsigned char 和 signed char 两种!

    signed char的取值范围:-128~127

    为什么?

            我们知道char类型的数据在内存中占1个字节,也就是8个比特位!而signed char 是有符号的char所以在8个比特位中最高的那个比特位表示符号位(1表示负数,0表示正数)剩余的7位才是数值位!然而它的取值范围其实就是8个二进制位的排列组合!解析如下:

     

    unsigned char 的取值范围:0~255

    为什么?

            char类型的数据占1个字节也就是8个比特位,unsigend char是无符号的char 所以压根就不考虑符号的问题,8个二进制位都是数值位。按照排列组合可知:取值范围就是 0~255

    解析:

    几道经典题目:

     以代码的形式注释讲解:

    第一题:

    1. #include
    2. #include
    3. int main()
    4. {
    5. char a[1000];
    6. int i;
    7. for (i = 0; i < 1000; i++)
    8. {
    9. a[i] = -1 - i;
    10. }
    11. printf("%d", strlen(a));
    12. //strlen函数碰到'\0'就结束 '\0'的ASICC码值是0
    13. //答案是255
    14. //解析:
    15. // 当i=0,a[0] = -1+(-i)=-1
    16. // 当i=1,a[1] = -1+(-1)=-2
    17. // 当i=2,a[2] = -1+(-2)=-3
    18. // 当i=3,a[3] = -1+(-3)=-4
    19. // 当i=4,a[4] = -1+(-4)=-5
    20. // .........
    21. // 因为a数组是有符号char类型的
    22. // 当i=128,a[128] = -1+(-128)=127
    23. // 当i=129,a[129] = -1+(-129)= -1+(-128)+(-1)=126
    24. // 当i=130,a[130] = -1+(-130)=125
    25. // ......
    26. // 当i=255,a[255] = -1+(-255)=0
    27. //而'\0'的ASICC值是 0 strlen遇到0就停止,计算0之前的个数
    28. //就是:255
    29. return 0;
    30. }

    第二题:

    1. #include
    2. int main()
    3. {
    4. int i = -20;
    5. unsigned int j = 10;
    6. printf("%d\n", i + j);
    7. //-20原码:10000000 00000000 00000000 00010100
    8. //-20反码:11111111 11111111 11111111 11101011
    9. //-20补码:11111111 11111111 11111111 11101100
    10. // 正数的原、反、补相同
    11. //10的补码:00000000 00000000 00000000 00001010
    12. //-20+10的补码:11111111 11111111 11111111 11110110
    13. //-20+10的反码:10000000 00000000 00000000 00001001
    14. //-20+10的原码:10000000 00000000 00000000 00001010 -10
    15. }

    第三题:

    1. #include
    2. int main()
    3. {
    4. unsigned int i;
    5. for (i = 0; i >= 0; i++)
    6. {
    7. printf("%u\n", i);
    8. }
    9. //unsigned int 是无符号整数 取值范围是:0 ~ 4294967295
    10. //而无符号数在任何情况下都是>=0的,是一个死循环!
    11. //当i++到4294967295的时候再+1 取到的结果又是0,所以是死循环!
    12. return 0;
    13. }

    if else 关键字

    什么是语句:

    在C语言中由一个分号;隔开的就是一条语句!

    上代码:

    1. #include
    2. int main()
    3. {
    4. int a = 10;//这是一条语句
    5. printf("%d\n", a);//这是一条语句
    6. int b = 0; char c = 0;//这是两条语句
    7. return 0;
    8. }

    什么是表达式:

    C语言中,用各种操作符把变量或数值连起来形成有意义的式子,就叫做表达式!

    操作符:+,-,*,/,%,<,>,=,==  ......等!

    上代码:

    1. #include
    2. int main()
    3. {
    4. int a = 10l;
    5. int b = 20;
    6. int c = 30;
    7. int d = 28;
    8. char e = 'a';
    9. float f = 3.25f;
    10. float ret = a + b + c + d + e;//这就是一条表达式
    11. printf("%f\n", ret);
    12. return 0;
    13. }

    if else 语句:

    选择语句!

    语法结构:
    1.单分支:

    1. if (表达式)
    2.     语句;

    2.双分支:

    1. if (表达式)
    2.     语句1;
    3. else
    4.     语句2;

    3. 多分支:

    1. if (表达式1)
    2.     语句1;
    3. else if (表达式2)
    4.     语句2;
    5. else
    6.     语句3;

    4. 嵌套:

    1. if (表达式1
    2. {
    3.     语句1;
    4.     if (表示式x) 
    5.     {
    6.         语句x;
    7.     }
    8. else
    9.     {
    10.         语句y;
    11.     }
    12. else if (表达式2)
    13. {
    14.     语句2;
    15. else
    16. {
    17.     语句3;
    18. }

    执行顺序:

            1、求出表达式的结果

            2、执行判断功能

            3、执行分支功能

    先计算条件表达式的结果,若结果为真则执行语句1,为假执行语句2,(在C语言中数字0表示假,非0数字表示真!)

    上代码:

    1. //先计算括号里面的表达式的结果,通常用1表示真,0表示假
    2. //再执行选择功能,看要执行那一块的代码
    3. //最后再执行分支功能执行代码
    4. #include
    5. int main()
    6. {
    7. //单分支
    8. int a = 10;
    9. if (a == 10)
    10. {
    11. printf("a==%d\n", a);
    12. }
    13. //双分支
    14. int b = 20;
    15. if (10 == b)
    16. {
    17. printf("b == 10\n");
    18. }
    19. else
    20. {
    21. printf("b != 10\n");
    22. }
    23. //多分支
    24. int c = 30;
    25. if (10 == c)
    26. {
    27. printf("c == 10\n");
    28. }
    29. else if(20 == c)
    30. {
    31. printf("c == 20\n");
    32. }
    33. else
    34. {
    35. printf("c != 10 && c!=20\n");
    36. }
    37. //嵌套
    38. int d = 40;
    39. if (50 > d)
    40. {
    41. if (40 == d)
    42. {
    43. printf("d == 40\n");
    44. }
    45. else
    46. {
    47. printf("d < 50\n");
    48. }
    49. }
    50. else if (d > 50)
    51. {
    52. if (d == 60)
    53. {
    54. printf("d == 60\n");
    55. }
    56. }
    57. else
    58. {
    59. printf("d的值为:%d\n", d);
    60. }
    61. return 0;
    62. }

  • 相关阅读:
    leetcode-518. 零钱兑换 II
    μC/OS-II---计时器管理2(os_tmr.c)
    一种基于E3处理器平台的NAS完整方案(从电脑组装到网站部署)
    【uvm function coverage】What is Coverage Metrics?
    FVP和Juno平台的Memory Layout介绍
    得物 ZooKeeper SLA 也可以 99.99%
    IP组播基础
    HTML的特殊字符
    头插法 销毁 清空链表的操作
    Git 原理备忘录
  • 原文地址:https://blog.csdn.net/dd811923461/article/details/128856145