第3章 基本数据类型、运算符和表达式

  1. C语言的数据类型。
    1. 数据类型是指数据的内在表现形式。通俗地说,数据在加工计算中的特征就是数据的类型。
    2. 我们把整型和实型合称为“数值型”,把数值型和字符型合称为“基本数据类型”。
    3. 构造类型是指由若干个相关的基本类型数据组合在一起形成的一种复杂的数据类型。构造类型包括数组型和结构型。
    4. 数组是由相同类型数据组合而成的。
    5. 结构型可以由不同数据类型组合而成的。
    6. 指针型是一种特殊的数据类型,它是用来表示内存地址的。指针类型的数据可以表示基本类型数据的地址,也可以表示结构类型数据中第1个数据的地址(称为首地址)和其中某个具体数据的地址。
    7. 空类型是从语法完整性角度给出的数据类型,表示该处不需要数据值,因而没有类型。
    8. 程序中,要对每个数据在内存中(个别数据可能在寄存器中)分配若干个字节,用于存放该数据。
    9. 数据所占的内存字节数就称为该数据的“数据长度”。
    10. 不同类型数据的长度是不同的,因此C语言规定每使用一个数据之前,必须对数据的类型加以定义,以便为其安排长度适合的内存。
  1. 常量。常量又叫常数,它是程序运行过程中其值不改变的数据。由于它是以字面格式直接写在程序中,所以也称字面常量。常量也有类型。常量是不需要事先定义的,只要在程序中需要的地方直接写出即可。常量的数据类型是由书写方法自动默认的。
    1. 整型常量。
      1. 整型常量就是通常的整数,包括正整数、负整数和0,其数据类型显然是整型。
      2. 在C语言中,整型常量有三种书写形式:
        1. 十进制整数。十进制整数就是通常整数的写法。例如0、-111、+15、21等。
        2. 八进制整数。八进制整数的书写形式是在通常八进制整数的前面加一个数字0。例如00、-0111、+015、021等。
        3. 十六进制整数。十六进制整数的书写形式是在通常十六进制整数的前面加0x。例如0x0、-0x111、+0x15、0x21等。
      3. 正整数前面的“+”号可以省略。
      4. 整型常量在一般微型机中占2个字节,它们的数值范围都是十进制的-32768~+32767。
      5. C语言还提供了一种“长整型常量”。它们的数值范围是十进制的-2147483648~2147483647,在计算机中占用4个字节。书写方法也分为三种,唯一不同的是在整数的末尾要加上小写字母“l”或大写字母“L”。
      6. 相对于“长整型常量”,我们把前面介绍的一般整型常量称为“短整型常量”。
      7. 如果整型常量后面没有“l”或“L”,而且超过短整型常量所能表示的数值范围,则自动认为该常量是长整形常量。
      8. 10和10L是不同的整型常量,虽然它们有相同的数值,但它们在内存中占用不同的字节。
    2. 实型常量。实型常量只使用十进制,它的书写形式有两种:
      1. 一般形式的实数。它是由整数部分、小数点、小数部分组成,其中整数部分或小数部分可以省略其中的一个。数的正负可以用前面的“+”(可以省略)号或“-”号来区分。例如:-1.2345、-.234、47.等都是实型常量。
      2. 指数形式的实数。它是由尾数部分、小写字母e或大写字母E、指数部分组成,形式如“尾数E指数”。尾数部分可以是十进制整数或一般形式的十进制实数,指数部分是十进制的短整数(可以带“+”、“-”)。指数形式实数的数值可以用下列公式计算:尾数×10指数。例如12.345e-2、0.1234E4等都是实型常量。
      3. 实型常量一般在微型机中占用4个字节,它们的数值范围都是-1038~1038,有效数字是7位,所以1.23456789和1.234567是相同的。
    3. 字符常量。
      1. 字符常量用两个单引号(')前后括住的单个字符来表示。例如'a'、'1'、'%'、'A'都是字符常量。
      2. 可以用转义字符组成字符常量。例如'n'、'r'、'101'、'x41'都是字符常量。在用到“”、“'”,“"”时,必须写成转义字符形式。
      3. C语言规定,字母是区分大小写的,所以“a”和“A”是不同的字符常量。
      4. 在内存中,每个字符常量都占用一个字节,具体存放的是该字符对应的ASCII代码值。
      5. 在C语言中,一个字符常量也可以看成是“整型常量”,其值就是该字符的ASCII代码值。例如,'a'+5、'A'-5、'1'+10分别等于102、60、59。
      6. 由于整型常量在内存中存放的是整数值,如果其值在0~127之间,C语言规定也可以将其看成一个字符型常量,对应的字符就是该值作为ASCII代码值所对应的那个字符。例如,整型常量111、70可以当成字符常量'0'、'F'来使用。
    4. 字符串常量。
      1. 字符串常量简称“字符串”。字符串就是用两个双引号(")前后括住的一串字符。
      2. 转义字符也可以出现在字符串中。
      3. C语言规定,字符串中的字母是区分大小写的,所以"a"和"A"是不同的字符串。
      4. 没有字符串称为“空字符串”。
      5. 一个字符串中所有字符的个数称为该字符串的长度,其中每个转义字符只当做一个字符。
      6. C语言规定,每个字符串在内存中占用的字节数等于字符串的长度+1。其中最后一个字节存放的字符为“空字符”,其值为0,书写时常用转义字符''来表示,在C语言中称为字符串结束标记。
      7. 字符串"A”和'A'是不同的,前者是用双引号括住的,是字符串,在内存中占用2个字节;后者是单引号括住的,是字符常量,在内存中只占一个字节。
    5. 符号常量。
      1. 符号常量是常量的另一种表示方法。
      2. C编译程序将在程序编译前将所有的符号常量自动替换为对应的常量。
      3. 符号常量的定义方法如下:
        #define 符号常量 常量
      4. 符号常量应按标识符的规则构成,建议用大写英文字母组成。其中的常量可以是任意类型。
      5. 符号常量的定义一般放在程序的开头,每个定义必须独占一行,其后不跟分号。
    6. 宏定义命令。
      1. 符号常量定义是C语言的一条命令,称为“宏定义命令”。
      2. 宏定义命令的一般格式如下:
        #define 宏名 一串符号
      3. 在程序清单中可以出现已经定义过的“宏名”,称为宏调用;当对源程序清单进行编译之前,将把所有的“宏名”替换成对应的“一串符号”,称为“宏替换”。
      4. 由于宏替换是在编译前进行的,所以宏定义命令属于C语言的“预编译命令”。
      5. 在定义宏时,其中的“一串符号”还可以含有已经定义过的“宏名”,称为嵌套宏定义。这种宏名在替换时,首先用“一串符号”替换相应的“宏名”,然后再对一串符号中的其他“宏名”进行替换,知道替换后的式子中没有宏名为止。
      6. 在宏替换时,仅仅把宏名替换成对应的一串符号,并不考虑其含义。
      7. 如果一个变量名中包含宏名,则该变量名不会被替换。
  2. 变量。
    1. 变量的数据类型及其定义。在程序中使用任何变量,都必须明确变量名、变量值、变量类型这三个概念。变量中第一个字节的地址称为变量的地址。C语言规定,程序中变量的地址用“&变量名”来表示。
      1. C语言规定,变量可以是任何一种数据类型。
      2. 通常把具有某种数据类型的变量叫做该类型变量。
      3. 字符串只能是常量,C语言中没有字符串变量。
      4. 每个变量在使用前都必须定义,定义变量的语句格式如下:
        数据类型符 变量名1, 变量名2, ……;
      5. 基本数据的数据类型符及其含义:
        1. (表头)数据类型 数据类型符 占用字节数 数值范围
        2. 整型 int 2(或4) 同短整型(或长整型)
        3. 短整型 short 2 -32768~+32767(-215~215-1)
        4. 长整型 long 4 -2147483648~2147483647(-231~231-1)
        5. 无符号整型 unsigned [int] 2(或4) 同无符号短整型(或长整型)
        6. 无符号短整型 unsigned short 2 0~65535(0~216-1)
        7. 无符号长整型 unsigned long 4 0~4294967295(0~232-1)
        8. 单精度实型 float 4 -1038~1038(保留7位有效数字)
        9. 双精度实型 double 8 -10308~10308(保留11位有效数字)
        10. 字符型 char 1 -128~127
        11. 方括号([])中的内容是可以省略不写的。
        12. 整型和无符号整型所占用的字节数是随编译程序的不同而不同的。
      6. 对变量进行定义时,要注意以下几点:
        1. 被定义为整型的变量,若其值在-128~127之间,可以当做字符型变量使用。
        2. 被定义为无符号整型的变量,若其值在0~255之间,也可以当做字符型变量使用。
        3. 相反的,被定义为字符型的变量,也可以当做整型变量和无符号整型变量使用。
        4. 当定义了某个变量后,会自动给它分配连续的内存单元。
    2. 变量的初始化。
      1. 在定义变量的同时给变量赋予初始值就称为变量的初始化。
      2. 初值可以是常量或符号常量,也可以是常量或前面已经定义过的符号常量组成的表达式。
      3. 含有变量赋初值的变量定义语句格式如下:
        数据类型符 变量名1=初值1, 变量名2=初值2,……;
    3. 变量的定义语句。一般的变量定义语句格式如下:
      数据类型符 变量名1=初值1, ……, 变量名n=初值n;
      该语句的功能是定义指定数据类型的若干个变量,并给其赋初值。若省略了变量后面的“=初值”,则不给该变量赋初值。
    4. 有名常量的定义。
      1. 在程序中,如果定义了常量并赋其初值,但又不希望程序中修改其值,可以将该变量定义成有名常量(因为其值不变,本质上还是常量)。
      2. 有名常量的定义方法如下:
        const 数据类型符 变量名1=初值1, 变量名2=初值2, ……;
      3. 有名常量的值是通过赋初值的方式获得的,不能用赋值方式获得。而且,获得初值后,程序中将不能改变其值。
  3. 运算符。用来表示各种运算的符号称为运算符。C语言中运算符的运算对象可以只有一个,称单目运算符,类似的还有双目运算符、三目运算符、前缀单目运算符、后缀单目运算符、双目中缀运算符。“*”在指针运算中表示指针指向的变量,“&”在指针运算中表示取地址的运算。
    1. 算术运算符(+、-、+、-、*、/、%)。
      1. 基本的算术运算符。
        1. +(正,取原值)、-(负,取负值)、+(加,加法)、-(减,减法)、*(乘,乘法)、/(除,除法)、%(模,整除取余)。
        2. 除运算(/)和运算对象的数据类型有关。若两个对象都是整型数据,该运算称为“整除”,除得的商是整数;若两个运算对象有一个或两个都是实型,则运算结果是实型。
        3. 使用模运算符时,运算结果的符号和被除数相同。
        4. 单目算术运算符优先于双目算术运算符。
      2. 增1、减1运算符。
        1. 增1(++)、减1(--)运算符用来对整型、字符型、指针型等变量进行算术运算,运算的结果仍是原来的类型,并存回原来的运算对象。
        2. 增1、减1运算符和单目算术运算符+、-的优先级是相同的,结合性是自右向左。
        3. 增1、减1作为前缀使用时,先对运算对象加1(或减1),然后再使用加1(或减1)后的运算对象;作为后缀时,顺序相反,对像加1或减1是在其所在的表达式全部做完后才进行的。
        4. 当出现若干个+或-组成运算符串时,C语言规定自左向右取尽可能多的符号组成运算符。
    2. 关系运算符(<、<=、>、>=、==、!=)。
      1. 关系运算符用来比较两个数据的大小,逻辑值“真”用整数“1”表示;逻辑值“假”用整数“0”表示。
      2. 运算对象类型为整型、实型或字符型。结果类型为0或1(整型)。
      3. 算术运算符优先于关系运算符。
      4. <、<=、>、>=优先于==、!=。
      5. 下面一段代码输出结果为1 0
        int a = 1, b= 0;
        a || (b = 2);
        printf("%d %d", a, b);
      6. n1 < n2 < n3相当于(n1 < n2) < n3。
    3. 逻辑运算符(!、&&、||)。
      1. 运算对象类型数值型或字符型等。结果类型是逻辑值0或1(整型)。
      2. 逻辑非(!)的结合性自右向左。
      3. 优先于 双目算术运算符 优先于 关系运算符 优先于 && 优先于 ||。
      4. 单目逻辑运算符!和单目算术运算符的优先级是相同的,结合性自右向左。
      5. !!!10计算顺序相等于!(!(!10))。
      6. 用&&对两个表达式进行计算时,若第一个表达式的值为“假”(或者用||对两个表达式进行计算时,第一个表达式的值为“真”),则运算结果与第二个表达式无关,所以C语言规定此时第二个表达式将不再计算。
      7. 0 && (a++),运算结果为0,a的值不变。 1 || (a++),运算结果为1,a的也值不变。
    4. 赋值运算符(=、+=、-=、*=、/=、%=)。
      1. 基本赋值运算符。
        1. 赋值运算符左边必须是变量,右边是表达式。
        2. 运算对象类型:任何类型。运算结果类型:变量的类型。
        3. 由于任何运算符和运算对象组成的式子都是表达式,所以“变量=表达式”也是表达式,称为赋值表达式。每个表达式都有值,赋值表达式的值等于赋予左边变量的那个值。
        4. 算术运算符 优先于 关系运算符 优先于 双目逻辑运算符 优先于 赋值运算符。
        5. 赋值运算符的结合性自右向左。
      2. 算术自反赋值运算符。
        1. 除模赋值的运算对象类型是整型外,其他自反赋值运算符的运算对象类型都是数值型。
        2. 赋值运算符的优先级都是相同的。
    5. 逗号运算符(,)。
      1. 逗号运算符的运算对象类型是任何类型的表达式,结果类型是右边表达式的类型。运算规则是依次计算左边、右边的表达式。
      2. 由逗号运算符组成的式子也是表达式,其值等于右边表达式的值。
    6. 条件运算符(?:)。
      1. 条件运算符的结合性自右向左。
      2. 三个运算对象类型都是表达式。
      3. 其他运算符 优先于 条件运算符 优先于 赋值运算符 优先于 逗号运算符。
    7. 长度运算符(sizeof())。
      1. 用于测试数据类型所占用的字节数。
      2. 运算对象可以是任何数据类型符或变量。运算结果是整型。
      3. 使用格式为:sizeof(数据类型符)或sizeof(变量)。
      4. 长度运算符的优先级和单目算术运算符的优先级相同。结合性自右向左。
    8. 位运算符(~、&、|、^、<<、>>、&=、|=、^=、<<=、>>=)。
      1. 位逻辑运算符。
        1. 位逻辑运算符将数据中每个二进制位上的“0”或“1”看成逻辑值,逐位进行逻辑运算。
        2. 按位加运算符(^),同则为0,不同为1。
        3. 优先于 算术运算符 优先于 关系运算符 优先于优先于优先于优先于 双目逻辑运算符。
        4. ~和单目逻辑运算符相同。
      2. 位移位运算符。
        1. 运算对象类型和结果类型都是整型。
        2. 位移运算符是将数据看成二进制数,对其进行向左或向右移动若干位的运算。
        3. a << b,a向左移动b位。运算完毕后,a的值不变。
        4. 移位时,移出的位数全部丢弃,移出的空位补入的数与左移还是右移有关。如果是左移,则规定补入的数全部是0;如果是右移,还与被移位的数据是否带符号有关。若是不带符号数,则补入的数全部为0;若是带符号数,则补入的数全部等于原数最左边位上的数(即原数的符号位)。
        5. 算术运算符 优先于 位移运算符 优先于 关系运算符
        6. 计算机是用补码来存储数据的。正数的补码与原码相同,负数的补码是将x的二进制位按位取反后在最低位上加1。(二进制数转十进制数时)
          short int x = 0x8000;
          printf("%dn", x); // 输出-32768
      3. 位自反赋值运算符。
        1. 条件运算符 优先于 位自反赋值运算符。
  4. 表达式。
    1. 表达式。
      1. 用运算符将运算对象连接形成的运算式就是表达式。
      2. 表达式的一般构成规则如下:
        1. 单个的常量、变量、函数调用都是表达式;
        2. “单目前缀运算符表达式”是表达式;
        3. “表达式 单目后缀运算符”是表达式;
        4. “表达式 双目运算符表达式”是表达式;
        5. “表达式 ? 表达式 : 表达式”是表达式;
        6. 有限次使用上述规则获得的运算式也是表达式。
      3. 每个表达式运算获得的一个数据为该表达式的值。表达式的数据类型就是表达式值的数据类型。
      4. 表达式的计算结果可能是整形、实型、字符型、逻辑型和指针型,由于字符型和逻辑型可以看成实型,所以表达式的基本数据类型实际上只分整型和实型两大类,这两种数据类型合称为数值型。
      5. 在程序中使用表达式时,要按照语法和表达式的位置来理解表达式的具体类型。例如“10 ? a : c”中的“10”就是逻辑型。
    2. 算术表达式。由算术运算符连接数值型运算对象构成。
    3. 关系表达式。由关系运算符连接表达式构成。表达式“(1, 2) != (2, 1)”的值是1.
    4. 逻辑表达式。由逻辑运算符连接表达式构成。
    5. 赋值表达式。由赋值运算符或自反赋值运算符连接变量和表达式构成。
    6. 逗号表达式。由逗号运算符连接表达式构成。
    7. 条件表达式。由条件运算符连接表达式构成。
  5. 变量赋值及表达式计算时的数据类型转换规则。
    1. 为什么要转换?
      1. 任何变量在参加运算前都必须有值,变量的值是通过各种赋值方式获得的。最基本的方式就是赋值表达式,格式如下:
        变量 = 表达式
      2. C语言并不要求参加表达式计算的常量和变量的数据类型必须一致,因此在表达式计算时,存在数据类型转换的问题。如果表达式值的类型和左边变量类型不一致时,也存在数据类型转换问题。针对这两点,C语言提供两条自动转换规则和一条强制性转换规则。
    2. 表达式计算中数据类型的自动转换规则。
      1. 参加运算的各个数据都转换成数据长度最长的数据类型,然后计算。结果值的类型就是长度最长的数据类型。
      2. 这也就是“就长不就短”规则。
    3. 运算结果存入变量时数据类型的自动转换规则。
      1. 先将运算结果的数据类型自动转换成左边变量的数据类型,然后再赋予该变量。
      2. 这也就是“就左不就右”规则。
    4. 运算结果的强制性数据类型转换规则。
      1. 在需要进行类型转换的表达式前加上圆括号括住的数据类型符,格式如下:
        (数据类型符) (表达式)
    5. 进行类型转换时需要注意:
      1. 表达式计算过程中,类型自动转换是临时的,其常量或变量的原类型和值均不变。
      2. 运算结果存入变量的类型转换中,会截去超长的部分,可能造成数据错误。例如:
        short int b = 0;
        long int a = 65536;
        b = a;
        printf("%dn", b);   // 输出0
      3. 类型转换将占用系统时间。在进行程序设计时,应尽量选好数据类型,以减少不必要的类型转换。

发表评论

电子邮件地址不会被公开。 必填项已用*标注