• C语言程序设计笔记(浙大翁恺版) 第六周:数据类型


    按照中国大学MOOC上浙江大学翁恺老师主讲的版本所作,B站上也有资源。原课程链接如下:

    https://www.icourse163.org/course/ZJU-9001

    由于是大三抽空回头整理的,所以可能前五章会记的内容比较简略。此外,作为选学内容的A0:ACLLib的基本图形函数和链表两章也没有做。西电的考试是机试,理论上学到结构体就能够应付考试了,但为了以后的学习考虑建议全学。

     

    其他各章节的链接如下:

    C语言程序设计笔记(浙大翁恺版) 第一周:程序设计与C语言

    C语言程序设计笔记(浙大翁恺版) 第二周:计算

    C语言程序设计笔记(浙大翁恺版) 第三周:判断

    C语言程序设计笔记(浙大翁恺版) 第四周:循环

    C语言程序设计笔记(浙大翁恺版) 第五周:循环控制

    C语言程序设计笔记(浙大翁恺版) 第六周:数据类型

    C语言程序设计笔记(浙大翁恺版) 第七章:函数

    C语言程序设计笔记(浙大翁恺版) 第八周:数组

    C语言程序设计笔记(浙大翁恺版) 第九周:指针

    C语言程序设计笔记(浙大翁恺版) 第十周:字符串

    C语言程序设计笔记(浙大翁恺版) 第十一周:结构类型

    C语言程序设计笔记(浙大翁恺版) 第十二周:程序结构

    C语言程序设计笔记(浙大翁恺版) 第十三周:文件

     

    数据类型

    数据类型

    数据类型

    C语言有哪些基础数据类型,sizeof可以做什么?

     

     

    C是有类型的语言。C语言的变量,必须在使用前定义,并且确定类型

    C以后的语言向两个方向发展:C++/Java更强调类型,对类型的检查更严格。JavaScript、Python、PHP不看重类型,甚至不需要事先定义

     

     

    类型安全

    支持强类型的观点认为明确的类型有助于尽早发现程序中的简单错误。反对强类型的观点认为过度强调类型迫使程序员面对底层、实现而非事物逻辑。总的来说,早期语言强调类型,面向底层的语言强调类型

    C语言需要类型,但是对类型的安全检查并不足够

     

     

    C语言的类型

    • 整数:charshortintlonglong long
    • 浮点数:floatdoublelong double
    • 逻辑:bool
    • 指针
    • 自定义类型

     

    注:long longlong doublebool是C99的类型

     

     

    类型有何不同?

    • 类型名称:intlongdouble

    • 输入输出时的格式化:%d%ld%lf

    • 所表达的数的范围:char<short<int<float<double

    • 内存中所占据的大小:1个字节(char)到16个字节(long double

    • 内存中的表达形式:二进制数(补码)、编码

      整型变量是自然二进制码或者二进制补码,而浮点数是编码形式。编码形式意味着不能直接拿来做运算,在计算机内部不能直接拿两个浮点数做加法,而整数可以直接在加法器里做加法

     

     

    sizeof

    是一个运算符,给出某个类型或变量在内存中所占据的字节数。例:sizeof(int)sizeof(i)

    示例:

    #include 
    
    int main()
    {
        int a;
        a = 6;
        printf("sizeof(int)=%ld\n", sizeof(int));
        printf("sizeof(a)=%ld\n", sizeof(a));
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    sizeof(int)=4
    siziof(a)=4
    
    • 1
    • 2

    说明int在内存当中占据4B

    若将sizeof(int)分别改为sizeof(double)sizeof(long double),则可得doublelong double在内存当中分别占据8B和16B的空间

     

     

    sizeof是静态运算符,它的结果在编译时刻就决定了,不要在sizeof的括号里做运算,这些运算是不会做的

    示例:

    #include 
    
    int main()
    {
        int a;
        a = 6;
        printf("sizeof(double)=%ld\n", sizeof(long double));
        printf("sizeof(a)=%ld\n", sizeof(a++));
        printf("a");
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    sizeof(double)=16
    sizeof(a)=4
    a=6
    
    • 1
    • 2
    • 3

    编译器在编译时碰到sizeof就会看后面括号中的表达式结果的类型,根据类型将sizeof(a++)替换成数字。a++并没有产生实际要执行的代码

    如果将sizeof(a++)改为sizeof(a+1.0),则sizeof(a+1.0)等于8,因为aint1.0doublea+1.0double

     

    整数类型

    除了int,还有多少整数类型?

     

     

    示例:

    #include 
    
    int main()
    {
        printf("sizeof(char)=%ld\n", sizeof(char));
        printf("sizeof(short)=%ld\n", sizeof(short));
        printf("sizeof(int)=%ld\n", sizeof(int));  
        printf("sizeof(long)=%ld\n", sizeof(long));  
        printf("sizeof(long long)=%ld\n", sizeof(long long));  
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在控制台下编译运行程序,gcc test.c -o test指定编译要输出的可执行文件名为test。./test执行test,得:

    sizeof(char)=1
    sizeof(short)=2
    sizeof(int)=4
    sizeof(long)=8
    sizeof(long long)=8
    
    • 1
    • 2
    • 3
    • 4
    • 5

     

    若加一个选项gcc test.c -o test -m32再次编译执行,得:

    sizeof(char)=1
    sizeof(short)=2
    sizeof(int)=4
    sizeof(long)=4
    sizeof(long long)=8
    
    • 1
    • 2
    • 3
    • 4
    • 5

    老师演示用的电脑是64位的,-m32表示编译时当作32位的机器编译

     

    gcc --version查看编译器版本,老师演示用的是LLVM 5.1。可以在自己的编译器中运行上述程序查看在当前环境下每一个类型的大小是多少

     

     

    整数

    • char:1字节(8比特)
    • short:2字节
    • int:取决于编译器(CPU),通常的意义是“1个字”
    • long:取决于编译器(CPU),通常的意义是“1个字”
    • long long:8字节

     

    intlong的大小和计算机,编译器有关

     

    什么叫计算机的字长?

    当我们在说一台计算机的字长时,指的是这台计算机的CPU寄存器有多宽,也就是有几bit,同时也是在说在CPU和内存之间传递数据时每一次传递几bit的数据

    把32bit或64bit叫做一个字长是因为寄存器一次可以处理的数据就是32bit或64bit,它在总线上一次可以传输的数据就是32bit或64bit

    这个字长就会在C语言中反映为int,也就是说int想要表达的就是一个寄存器的大小,所以在不同平台上,在不同的CPU上int的大小不同。而其他的整数想要表达的不同,可以有固定的大小

    在这里插入图片描述

     

    整数的内部表达

    整数是如何表达的,尤其是负数如何表达?

     

     

    在计算机内部一切都是二进制

    不管是什么类型,最终都是纯二进制的形式,只是以不同的方式看待

    二进制负数用补码表达

    1个字节可以表达的数:00000000 — 11111111(0-255)

    考虑-1,我们希望-1 + 1 —> 0。而0 —> 00000000,1 —> 00000001,11111111 + 00000001 —> 100000000。在计算机内部,如果这个数为1B,多出的高位会被丢掉,剩下的结果正好是0

    换一个角度,因为0 - 1 —> -1,所以-1 = (1)00000000 - 00000001 —> 11111111

     

    11111111被当作纯二进制看待时,是255,被当作补码看待时是-1。同理,对于 − a -a a,其补码就是 0 − a 0-a 0a,实际是 2 n − a 2^n-a 2na n n n是这种类型的位数。

     

    补码的意义就是拿补码和原码可以加出一个溢出的“零”。如果用补码来表示-1,当做加法时不需要根据条件变号,而是直接做二进制加法得到期望的结果

     

    整数的范围

    如何推算整数类型所能表达的范围,越界了会怎样?

     

     

    对于一个字节(8位),可以表达的是:00000000 - 11111111。其中

    • 00000000 —> 0
    • 11111111 ~ 10000000 —> -1 ~ -128
    • 00000001 ~ 01111111 —> 1 ~ 127

    示例:

    #include 
    
    int main()
    {
        char c = 255;    // 11111111
        int i = 255;     // 00000000 00000000 00000000 11111111
        printf("c=%d,i=%d\n", c, i);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    c=-1,i=255
    
    • 1

     

     

    整数的范围

    • char:1字节:-128 ~ 127
    • short:2字节:-32768 ~ 32767
    • int:取决于编译器(CPU),通常的意义是“1个字”
    • long:4字节
    • long long:8字节

     

    由于0的存在,所有整数的范围为 − 2 n − 1 ∼ 2 n − 1 − 1 -2^{n-1}\sim 2^{n-1}-1 2n12n11

     

     

    unsigned

    示例:

    #include 
    
    int main()
    {
        unsigned char c = 255;  // 11111111
        int i = 255;         // 00000000 00000000 00000000 11111111
        printf("c=%d,i=%d\n", c, i);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    c=255,i=255
    
    • 1

    unsigned表示这个整数不以补码的形式来表示负数,这个整数没有负数部分,只有0和正整数部分,用纯二进制看待高位为1的数字

    unsigned使得类型所能够表达的正数范围扩大

     

    如果一个字面量常数想要表达自己是unsigned,也当作纯二进制看待,可以在后面加uU,如255U

    lL表示long(long)

    unsigned的初衷并非扩展数能表达的范围,而是为了做纯二进制运算,主要是为了移位

     

     

    整数越界

    整数是以纯二进制方式进行计算的,所以:

    • 11111111 + 1 —> 100000000 —> 0
    • 01111111 + 1 —> 1000000 —> -128
    • 10000000 - 1 —> 01111111 —> 127

    可以将加减法看作分别在一个圆圈上逆时针和顺时针走:

    在这里插入图片描述

    示例:

    #include 
    
    int main()
    {
        char c = 127
        int i = 255;     
        c = c + 1;
        printf("c=%d,i=%d\n", c, i);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    c=-128,i=255
    
    • 1

    如果改为char c = -128c = c - 1,得c=127

    如果改为unsigned char c = 127c = c + 1,则c=128。再改为unsigned char c = 255,则c=0。再改为unsigned char c = 0c = c - 1,则c=255

    在这里插入图片描述
     

     

    编写程序找出int的最大数

    #include 
    
    int main()
    {
        int a=0,b=0;
        while (++a>0);
        printf("int数据类型最大数是:%d\n",a-1);
        
        b++;
        while ((a=a/10)!=0) b++;
        printf("int数据类型最大的数的数位是:%d",b);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    当到int所能表达的最大数时再加1就会翻回去变成负数

     

    整数的格式化

    如何格式化输入输出整数,如何处理8进制和16进制?

     

    整数的输入输出

    虽然有很多种不同的整数,但是在做printfscanf输入输出时只有两种形式:intlong long

    所有小于int的(charshort)和int都采用%d来输出

    所有大于int的都采用%ld来输出

    如果是unsigned,可以用%u%lu来输出

     

    示例:

    #include 
    
    int main()
    {
        char c = -1;
        int i = -1;
        printf("c=%u,i=%u\n", c, i);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    c=4294967295,i=4294967295
    
    • 1

    这两个输出是unsigned int 所能表达的最大数。-1表示全部都是1,虽然c只有1个字节,但当把所有小于int的变量传给printf时编译器会把这些变量转换为int传入,在转换的过程中有符号的c会被扩展到所有位都是1

    以不同的方式看待计算机内部的数据就会得到不同的结果

     

     

    8进制和16进制

    一个以0开头的数字字面量是8进制

    一个以0x开始的数字字面量是16进制

    %o用于8进制,%x用于16进制

     

    8进制和16进制只是如何把数字表达为字符串,与内部如何表达数字无关

     

    示例:

    #include 
    
    int main()
    {
        char c = 012;
        int i = 0x12;
        printf("c=%d,i=%d\n", c, i);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    c=10,i=18
    
    • 1

    %d输出时表示期望输出十进制的结果,而写在程序当中的字面量可以以8进制或者16进制看待

    注意这个进制只是我们的看待方式,并不表示它在计算机内部会被表达为8进制或者16进制,计算机内部永远只有二进制。在程序里写一个8进制的数,编译器会替你转成对应的十进制形式,变成二进制存入

     

    如果期望printf输出8进制或者16进制的结果,用%o%x%x的x是大写还是小写决定输出大写还是小写的字母。scanf%o表示要读入的数当作8进制读

    #include 
    
    int main()
    {
        char c = 012;
        int i = 0x1A;
        printf("c=0%o,i=0x%x\n", c, i);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    c=012,i=0x1a
    
    • 1

     

     

    16进制很适合表达二进制数据,因为4位二进制正好是一个16进制位

    8进制的一位数字正好表达3位二进制

     

    选择整数类型

    没什么特殊需要就只用int

     

     

    有那么多种整数,是为了准确表达内存,做底层程序的需要。C语言作为早期语言,需要准确地表达计算机里的内存、寄存器、接口等硬件

     

    没有特殊需要,就选择int

    • 现在的CPU的字长普遍是32位或64位,一次内存读写就是一个int,一次计算也是一个int。如果读一个char,实际上是将一个int的数据全部读入再从中拿出1B,选择更短的类型不会更快,甚至可能更慢
    • 现代的编译器一般会设计内存对齐,所以更短的类型实际在内存中有可能也占据一个int的大小(虽然sizeof告诉你更小)

     

    unsigned与否只是输出的不同,内部计算是一样的。如果不是迫不得已没有必要用unsigned

     

    浮点类型

    doublefloat,它们是什么,如何输入输出?

     
     

    在这里插入图片描述

    注意到靠近0但不包括0的正负两端一小片区域是不能表达的。0, ± i n f \pm inf ±inf(正负无穷大), n a n nan nan(非有效数字)需要特殊表达

    float有效数字为7的意思是用float表达的数只有7个数字是有效的,后面的数字是不准确的

     

     

    浮点的输入输出

    在这里插入图片描述

    %f在一定位数上做四舍五入输出

    %e表示期望以科学计算法表示输出,如果换成%E则输出中表示指数的小写e变为大写E

    示例:

    #include 
    
    int main()
    {
        double ff = 1234.56789;
        printf("%e,%f\n", ff,ff);
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    1.234568e+03,1234.567890
    
    • 1

     

     

    科学计数法

    在这里插入图片描述

    既可以用%e输出科学计数法表示的值,也可以在程序中用科学记数法表示常数

    示例:

    #include 
    
    int main()
    {
        double ff = 1E-10;
        printf("%E,%f\n", ff,ff);
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    1.000000E-10,0.000000
    
    • 1

    double有15位有效数字,足以表达1E-10,但不指定要输出多少位小数时就会输出0.000000。如果将%f改为%.16f表示期望在小数点后输出16位的数字,得0.0000000001000000

     

     

    输出精度

    %f之间加上.n可以指定输出小数点后几位,这样的输出是做4舍5入的

    示例:

    #include 
    
    int main()
    {
        printf("%.3f\n", -0.0049);
        printf("%.3f\n", -0.0045);
        printf("%.30f\n", -0.0049);
        printf("%.3f\n", -0.00049);
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    -0.005
    -0.004
    -0.004899999999999999841793218991
    -0.000
    
    • 1
    • 2
    • 3
    • 4

    实际上计算机内部是-0.004899999999999999841793218991,-0.0049无法被精确地表达

    从数学上来说,数的范围内所有数是连续的,数轴上任意两点中间可以得到任意多的数,但是在计算机中最终只能用离散的数字表达数字,浮点数类型(doublefloat)不能表达位于相邻两个浮点数能够表达的数中间的数,中间的数只能选择较近的数表达,和实际的数间有一定距离,这个距离就是浮点数的误差

     

    浮点数的范围和精度

    浮点数到底能表示哪些数?

     

     

    printf输出inf表示超出范围的浮点数: ± ∞ \pm\infty ±

    printf输出nan表示不存在的浮点数

    示例:

    #include 
    
    int main()
    {
        printf("%f\n", 12.0/0.0);
        printf("%f\n", -12.0/0.0);
        printf("%f\n", 0.0/0.0);
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    inf
    -inf
    nan
    
    • 1
    • 2
    • 3

     

    如果改为printf("%d\n",12/0)就无法通过编译。整数不能除以0,因为无穷大不能用整数来表达,但无穷大可以用浮点数表达。虽然浮点数的有效范围里不包含无穷大,但是在浮点数的设计中定义了正负无穷大还有不存在的数三种特殊的值

     

     

    浮点运算的精度

    计算机中的浮点数只有一定范围内的有效数字,浮点运算是没有精度的

    示例:

    float a, b, c;
    
    a = 1.345f;
    b = 1.123f;
    c = a + b;
    if (c == 2.468)
        printf("相等\n");
    else
        prinf("不相等!c=%.10f,或%f\n",c,c);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    不相等!c=2.4679999352,或2.468000
    
    • 1

     

     

    带小数点的字面量是double而非floatfloat需要用fF后缀来表明身份

    两个浮点数直接用两个等号判断是否相等(如f1 == f2)可能失败,应该求两浮点数之差的绝对值,当其小于能够表达的精度时(如对于7个有效数字的float,小于1e-8就够了)则相等(如fabs(f1-f2) < 1e-12

     

     

    浮点数的内部表达

    整数内部用纯二进制数表达,所以两个整数可以直接做加减,但是浮点数内部用编码形式表达
    在这里插入图片描述

    浮点数在计算时是由专用的硬件部件实现的,硬件将计算结果编码回传。计算doublefloat所用的部件是一样的

     

     

    选择浮点类型

    如果没用特殊需要,只使用double

    现代CPU能直接对double做硬件运算,性能不会比float差,在64位的机器上,数据存储的速度也不比float

     

    字符类型

    char是整数也是字符

     

     

    char是一种整数,也是一种特殊的类型:字符。这是因为:

    • 用单引号表示字符字面量:‘a’,‘1’
    • ''也是一个字符
    • printfscanf里用%c来输入输出字符

     

     

    字符的输入输出

    示例:

    #include 
    
    int main()
    {
        char c;
        char d;
        c = 1;
        d = '1';
        if ( c == d ) {
            printf("相等\n");
        } else {
            printf("不相等\n");
        }
        printf("c=%d\n", c);
        printf("d=%d\n", d);
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    不相等
    c=1
    d=49
    
    • 1
    • 2
    • 3

    这表明在计算机内部’1’的值就是49

    每一个字符在计算机内部都有一个用于表达它的整数形式的对应值

     

     

    如何输入’1’这个字符给char c?

    • scanf("%c",&c);—>1
    • scanf("%d",&i); c=i;—>49

    ‘1’的ASCII编码是49,所以当c==49时,它代表’1’

    一个49各自表述,当作整数是49,当作字符是’1’

    示例:

    #include 
    
    int main()
    {
        char c;
        scanf("%c", &c);
        printf("c=%d\n", c);
        printf("c='%c'\n", c);
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    输入1后回车,得

    c=49
    c='1'
    
    • 1
    • 2

    %c的形式输入的是1,但是读到的是49。同一个变量作为整数是49,而作为字符是’1’

     

    示例2:

    #include 
    
    int main()
    {
        int i;
        char c;
        scanf("%d", &i);
        c = i;
        printf("c=%d\n", c);
        printf("c='%c'\n", c);
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13

    输入1后回车,得

    c=1
    c=''
    
    • 1
    • 2

    读入整数1再交给char c。作为整数是1,而1所代表的字符无法输出

    如果输入49后回车,得

    c=49
    c='1'
    
    • 1
    • 2

    读入整数49再交给char c。作为整数是49,而作为字符是’1’

     

    示例3:

    #include 
    
    int main()
    {
        if ( 49 == '1' ) {
            printf("OK");
        }
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    OK
    
    • 1

    49和’1’是相等的值,一个是整数的形式,一个是字符的形式

     

     

    混合输入

    scanf("%d %c", &i, &c);scanf("%d%c", &i, &c);有何不同?

    示例:

    #include 
    
    int main()
    {
        int i;
        char c;
        scanf("%d %c", &i, &c);
        printf("i=%d, c=%d, c='%c'\n",i,c,c);
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    多次运行时分别输入12 112a12 1后回车,得

    i=12, c=49, c='1'
    
    • 1
    i=12, c=97, c='a'
    
    • 1
    i=12, c=49, c='1'
    
    • 1

    读完整数后会把后面的空格都读掉

     

    如果改为 scanf("%d%c", &i, &c)后重新编译运行,再分别输入12 112a,12 1后回车,得

    i=12, c=32, c=' '
    
    • 1

    空格的ASCII码是32。字符读到32,也就是空格

     

    i=12, c=97, c='a'
    
    • 1

    只读到整数结束为止,后面的’a’被字符读到

     

    i=12, c=32, c=' '
    
    • 1

     

     

     

    字符计算

    char是整数,可以做整数的运算

    示例:

    char c = 'A';
    c++;
    printf("%c\n", c);
    
    • 1
    • 2
    • 3
    B
    
    • 1

    一个字符加一个数字得到ASCII码表中那个数之后的字符

     

    int i = 'Z' - 'A';
    printf("%d\n", i);
    
    • 1
    • 2
    25
    
    • 1

    两个字符的减,得到它们在表中的距离

     

     

    大小写转换

    字母在ASCII表中是顺序排列的

    大写字母和小写字母是分开排列的,并不在一起

    'a'-'A'可以得到两段之间的距离,于是

    • a+'a'-'A'可以把一个大写字母变成小写字母
    • a+'A'-'a'可以把一个小写字母变成大写字母

     

    逃逸字符

    反斜杠开头的字符是特殊的控制字符

     

     

    逃逸字符

    用来表达无法印出来的控制字符或特殊字符,它由一个反斜杠“\”开头,后面跟上一个字符,这两个字符合起来,组成了一个字符

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1EWxJ0bK-1659879207756)(C语言程序设计.assets/image-20220724142426807.png)]

    示例:

    printf("请分别输入身高的英尺和英寸,"
        "如输入\"5 7\"表示5英尺7英寸:");
    
    • 1
    • 2

    \"组成一个字符表示",在双引号里面不能直接出现双引号,否则会将两个双引号之间的内容视为一个字符串

     

    示例2:

    #include 
    
    int main()
    {
        printf("123\b\n456\n");
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在Subline Text中运行该程序,会输出这有一个回退字符。在另外的终端运行则没有,\b似乎没有起效

    在这里插入图片描述
    在这里插入图片描述

    因为程序和人之间还有另外一个东西来帮助解释在printf中输出的控制字符

    程序比如用Dev C++运行时,会有个叫终端的黑色窗口(Subline Text没有黑色窗口,而是在编辑区的下部显示输出结果),这个黑色窗口本身是一个别人写的叫shell的程序,它会在背后执行我们写的程序

    键盘是和shell相联系的,shell把键盘上输入的内容给程序,程序用printf输出的内容输出内容由shell发送给我们看。在这个过程中,shell会做一些翻译工作,如处理在键盘上做的回退、回车之类的操作,将程序中要输出的\n\b变成可视结果

    不同的shell会对不同的特殊控制字符做出不同的反应

    在这里插入图片描述
     

    如果改为printf("123\bA\n456\n"),得

    在这里插入图片描述

    可见\b通常做的是回去但不删除。会回去一格,让下一个输出回到该位置上覆盖刚才的输出,但如果不输出东西就什么结果也没有

     

     

    制表位

    在每一行当中有一些固定位置作为表格位,用一个\t使得输出从下一个制表位开始。\t不代表固定的字符数量,而是代表行当中固定的输出位置

    示例:

    #include 
    
    int main()
    {
        printf("123\t456\n");
        printf("12\t456\n");
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述

     

     

    回车换行

    源自早期打字机的回车和换行两个动作

    之前的所有程序中只用了\n,这是因为shell会将\n翻译成\n\r两个动作

     

    类型转换

    如何在不同类型之间做转换

     

     

    自动类型转换

    当运算符的两边出现不一致的类型时,会自动转换成较大的类型(char —> short —> int —> long —> long longint —> float —> double

    大的意思是能表达的数的范围更大

     

    对于printf,任何小于int的类型会被转换为intfloat会被转换为double

    但是scanf不会,它需要明确地知道变量的大小,要输入short,需要%hd

     

     

    强制类型转换

    要把一个量强制转换成另一个类型(通常是较小的类型)需要:(类型)值。比如:(int)10.2(short)32

    注意这时候的安全性,小的变量不总能表达大的量,比如:(short)32768

    示例1:

    #include 
    
    int main()
    {
        printf("%d\n", (short)32768);
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    -32768
    
    • 1

     

    32768=10…0(15个0),如果改为(char)32768,取低位8bit得0

     

    示例2:

    #include 
    
    int main()
    {
        int i=32768;
        short s = (short)i;
        printf("%d\n", i);
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    32768
    
    • 1

    强制类型转换只是从那个变量计算出了一个新的类型的值,它并不改变那个变量,无论是值还是类型都不改变

     

    示例3:

    double a = 1.0;
    double b = 2.0;
    int i = (int)a / b;  // i = 0
    
    • 1
    • 2
    • 3

    强制类型转换的优先级高于四则运算。如期望将a/b的结果转换成int,应改为int i = (int)(a / b)

     

    int a = 5;
    int b = 6;
    double d = (double)(a / b); // d = 0.000...
    
    • 1
    • 2
    • 3

     

    其他运算:逻辑、条件、逗号

    逻辑类型

    表示关系运算和逻辑运算结果的量

     

     

    bool

    C语言原本没有bool类型,但可以#include ,之后就可以使用booltruefalse

    示例:

    #include 
    #include 
    
    int main()
    {
        bool b = 6>5;
        bool t = true;
        t = 2;
        printf("%d\n", b);
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    1
    
    • 1

    并没有真正的bool类型,实际上仍然是整数,输入输出时也并没有特别的方式去输出bool量

     

    逻辑运算

    对逻辑量进行与、或、非运算

     

     

    逻辑运算是对逻辑量进行的运算,结果只有0或1

    逻辑量是关系运算或逻辑运算的结果

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-zYC7qHSm-1659879207760)(C语言程序设计.assets/image-20220724225113241.png)]

     

    如果要表达数学中的区间,如: x ∈ ( 4 , 6 ) x\in(4,6) x(4,6) x ∈ [ 4 , 6 ] x\in [4,6] x[4,6],应该如何写C的表达式?

    4 < x < 6这样的式子,是C能够编译但不能正确计算的式子,因为4 < x的结果是一个逻辑值(0或1),式子的结果永远都是1。正确的表达式是x > 4 && x < 6x >= 4 && x <= 6

     

    如何判断一个字符c是否是大写字母? c >= 'A' && c <= 'Z'

     

    如何理解!age < 20? 虽然逻辑运算符的优先级通常要低于比较运算符,但同时!是单目运算符,而单目运算符的优先级要高于双目运算符,所以!运算会先做。!age的结果不是0就是1(age为0则为1,否则为0),所以整个表达式永远都是0

     

     

    优先级

    !>&&>||

    !只有一个算子,作为单目运算符优先级较高。而&&||逻辑运算优先级比关系运算低,比赋值运算高

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-ruZ9vWZ5-1659879207762)(C语言程序设计.assets/image-20220724231357650.png)]

     

     

    短路

    逻辑运算是自左向右进行的,如果左边的结果已经能够决定结果了,就不会做右边的运算。如a == 6 && b += 1中右边的运算不一定会做

    对于&&,左边是false时就不做右边了

    对于||,左边是true时就不做右边了

    不要把赋值,包括复合赋值组合进表达式!

    示例:

    #include 
    
    int main()
    {
        int a = -1;
        if ( a>0 && a++>1 ) {
            printf("OK\n");
        }
        printf("%d\n", a);
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    -1
    
    • 1

     

    条件运算与逗号运算

    条件运算符

    count = (count > 20) ? count-10 : count+10;问号前面是条件,问号后面是条件满足时的值,冒号后面是条件不满足时的值。等同于:

    if ( count > 20 ) 
        count = count-10;
    else
        count = count+10;
    
    • 1
    • 2
    • 3
    • 4

     

    条件运算符的优先级高于赋值运算符,但是低于其他运算符

    条件运算符是自右向左结合的。课程中不建议使用嵌套的条件表达式

     

     

    逗号运算

    逗号用来连接两个表达式,并以其右边的表达式的值作为它的结果。逗号的优先级是所有的运算符中最低的,所以它两边的表达式会先计算;逗号的组合关系是自左向右,所以左边的表达式会先计算,而右边的表达式的值就留下来作为逗号运算的结果

    示例:

    #include 
    
    int main()
    {
        int i;
        i = 3+4,5+6;
        
        printf("%d\n",i);
        
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在这里插入图片描述

    表达式i = 3+4先计算,会警告表达式5+6的结果没有被用到

     

    如果改为i = (3+4,5+6)再编译,表达式3+4,5+6的结果5+6赋给i,会警告表达式3+4的结果没有被用到

    在这里插入图片描述

     

     

    for使用,,如for(i=0,j=10;i,实现在分号分成的各个区域中的表达式中做多个计算
    运算符的优先级通常要低于比较运算符,但同时!是单目运算符,而单目运算符的优先级要高于双目运算符,所以!运算会先做。!age的结果不是0就是1(age为0则为1,否则为0),所以整个表达式永远都是0

  • 相关阅读:
    实景三维技术在应急管理与防灾减灾领域的应用
    ExcelPatternTool: Excel表格-数据库互导工具
    SpringBoot接收参数的三种方式:
    全排列:让我看到未来所有的可能 -> 跨越CV小白的回溯算法
    记一次 .NET 某新能源系统 线程疯涨 分析
    GoLang接口
    Ceph对象网关,多区域网关
    前端后花园周刊vol.19-ESLint的下一个11年计划
    buildroot制作的嵌入式Linux根文件系统启动后不是root用户,提示没有权限
    六、RTMP协议 时间戳
  • 原文地址:https://blog.csdn.net/zimuzi2019/article/details/126217522