第 2 章 数据类型及其运算
基本知识点:C 语言的数据类型、常量和变量、运算符、表达式等相关概念。
重 点:各种类型的数据之间的相互转换。
难 点:在程序设计中正确利用各种数据类型和相关运算符解决实际问题。
2.1 知识点1:数据类型
2.1.1 要 点 归 纳
1. 基本数据类型
C 语言的数据类型有基本数据类型和非基本数据类型之分。基本数据类型是C语言内部 预先定义的数据类型。非基本数据类型是由用户指定的,也称为用户定义数据类型。 C 语言 的数据类型如图2.1所示。
图中的type 表示C语言的非空数据类型。
从中看到,C 语言基本数据类型只有5种,即整型 (int)、字符型(char)、 单精度浮点 型 (float) 、 双精度浮点型 (double) 和枚举类型 (enum) 。 除了这些基本数据类型外,还有 一些数据类型修饰符,用来改变基本类型的意义。这些修饰符有long (长型符)、 short( 短型符)、 signed ( 有 符 号 ) 和unsigned (无符号)。
使用修饰符时有以下规定:
● short只能修饰int,short int表示短整数类型,可以省略为short。
·long 只能修饰 int 和 double 。long int为长整数类型,可省略为long;long double为 长双精度类型。
·unsigned 和 signed 只能修饰char 和 int。一般情况下,默认的char 和 int 分 别 为signed char 和 signed int。实型 float 和 double 总是有符号的,不能用unsigned 修饰。
数据类型的描述确定了其内存所占空间大小,也确定了其表示范围。以16位机表示为 例,基本数据类型加上修饰符的描述如表2 . 1所示。在32位机中, int 用4个字节表示,其他均同。
类型(等价的类型) | 说明 | 长度 (字节) | 表示范围 | 说明 |
char(signed char) | 字符型 | 1 | -128~127 | -2⁷~(2⁷-1) |
unsigned char | 无符号字符型 | 1 | 0~255 | 0~(2⁸-1) |
int(signed int,short int,signed short int) | 整型 | 2 | -32768~32767 | -2¹⁵~(2¹⁵-1) |
unsigned int(unsigned short int) | 无符号整型 | 2 | 0~65535 | 0~(2¹⁶-1) |
long int (signed long int) | 长整型 | 4 | -2147483648~2147483647 | -2³¹~(2³¹-1) |
unsigned long int | 无符号长整型 | 4 | 0~4294967295 | 0~(2³²-1) |
float | 单精度型 | 4 | -3.4×10³~3.4×10³8 | 7位有效位 |
double | 双精度型 | 8 | -1.7×10308~1.7×10308 | 15位有效位 |
long double | 长双精度型 | 10 | -3.4×102~1.1×10⁴⁹32 | 19位有效位 |
2. 变量
变量是其值可以改变的量,变量有三个要素。
● 变量名:每个变量都必须有一个名称,即变量名,通过变量名对其进行操作。
● 变量值:在程序运行过程中,变量的值存储在内存中;不同类型的变量,占用的内 存单元(字节)数不同,以便用来存放相应变量的值。
● 变量地址:每个变量都存放在内存中,该内存地址就是变量地址。
C 语言是一种强类型语言,它要求在使用数据之前对数据的类型进行声明,也就是说, 在 C 语言中,要求对所有用到的变量,必须先定义后使用。在定义变量的同时,进行赋初 值的操作称为变量初始化。变量定义的格式如下:
[存储类型]数据类型变量名1,变量名2 … ;
例如:
变量初始化的一般格式如下:
[存储类型]数据类型变量名1[=初值1],变量名2[=初值2],… ;
例如:
float f1=1.23,f2,f3;
该语句定义了f1 、f2 和f3 三个实型变量,同时初始化了变量f1。
变量定义和变量声明是不同的。变量定义就是(编译器)创建一个变量,为这个变量按照指定的数据类型分配一块内存空间并给它取上一个名字,这个名字就是变量名,变量名和分配的内存块绑定起来,程序员通过变量名对这块内存进行存 取操作。变理声明是告诉编译器,这个变量在别的地方已经定义了,不会为它再 重新分配内存,如extern int n;语句是声明整型变量n。在一个作用区域(如函数) 内,一个变量只能定义一次,而声明可以出现多次。
3. 常量
常量又称常数,是指在程序运行过程中其值不能被改变的量。在C语言中,常量有不同 的类型,有整型常量、实型常量和字符串常量。
常量的类型从字面形式即可区分,如整型常量只用数字表示,不能带小数点;实型常 量通常用带小数点的数表示;字符型常量只有一个字符。C编译程序就是以此来确定数值常 量的类型的。
(1)整型常量
整型常量可以是十进制、八进制或十六进制数字表示的整数。
● 十进制常量
其形式是:d
其中,d可以是从0到9的一个或多个十进制数位,第一位不能是0。
● 八进制常量
其形式是:Od
其中,d可以是一个或多个八进制数(0~7之间),起始0是必须的引导符。
●十六进制常量
其形式是:Oxd
其中,d可以是一个或多个十六进制数(从0~9的数字,并从 “a”~“f” 的字母)。 引导符0是必须有的,字母X可用大写或小写。
空白字符(包括空格符、 Tab键等)不可出现在整数数字之间
在一个常数后面加一个字母1或L, 则认为是长整型,如10L 、79L 、012L 、0115L 、0X AL 、0x4fL等。
整型数据在内存中是以二进制方式存放的,最高位为符号位,并以补码表示。将一个 十进制整数转化为补码表示的方法如下:
●对于正数,其补码表示与原码相同。
●对于负数,其补码表示为它的反码加1;负数的反码为其绝对值的所有位(含符号 位)取反(1变为0,0变为1)得到。
例如,求十进制短整型数据-100的补码表示的过程如图2.2所示(-100为short int型 数据,在内存中占两个字节)。所以, -100 在内存中的表示形式为:[1111111110011100]₂ (表示为二进制数,下同)。
对于用补码表示的数据,还原为原码的方法如下:
●对于正数(补码表示的符号为0),原码与补码相同。
●对于负数,原码一定为负数,其绝对值为除符号位外所有位取反后加1。
例如,求补码为[1111111110011100]2的原码的过程如下:
由于符号位为1,所以原码为负数,将[111111110011100]₂求反后得到[000000001100 011]₂,再加1后得到[000000001100100]₂,即为[100]10(表示十进制数,下同),其前加上 一个负号变为-100。
(2)实型常量
实型常量又称浮点型常量,是一个十进制表示的符号实数。符号实数的值包括整数部 分、尾数部分和指数部分。实型常量的形式如下:
[d][.d][[Ele][+I-]d]
其 中 ,d 是一位或多位十进制数字(0~9)。 E (也可用e) 是指数符号。小数点之前的 是整数部分,小数点之后是尾数部分,它们是可省略的。小数点在没有尾数时可省略。例 如,以下是合法的实型数据:
12.34,.34,-.123,-0.0023,-2.5e-3,25E-4
(3)字符常量
字符常量又分为普通字符常量、字符串常量、转义字符和符号常量四种类型。
①字符型常量
字符型常量是指用一对单引号括起来的一个字符。如'a','0',!。字符型常量中的单引 号只起定界作用并不表示字符本身。单引号中的字符不能是单引号(')和反斜杠(),它 们特有的表示法将在转义字符中介绍。
在C语言中,字符是按其所对应的ASCII码值来存储的,一个字符占一个字节。例如,' a'的ASCII码为97,'A'的ASCII码为65,'O'的ASCII码为48。
②字符串常量
字符串常量是指用一对双引号括起来的一串字符。双引号只起定界作用,双引号括起 的字符串中不能有双引号(")和反斜杠(\),它们特有的表示法将在下面的转义字符中介 绍。例如,以下是合法的字符串常量:
C语言中,字符串常量在内存中存储时,系统自动在字符串的末尾加一个“串结束标志”, 即ASCI 码值为0的字符NULL, 常用\0表示。因此在程序中,长度为n个字符的字符串常量, 在内存中占有n+1个字节的存储空间。
③转义字符
转义字符是C语言中表示字符的一种特殊形式。通常使用转义字符表示ASCII 码字符集 中不可打印的控制字符和特定功能的字符。表2.2列出了常用的转义字符。例如,以下程序 的输出为字符T:
转义字符中只能使用小写字母,每个转义字符只能看做一个字符。
④符号常量
C 语言允许将程序中的常量定义为一个标识符,称为符号常量。符号常量一般使用大写 英文字母表示,以区别于一般用小写字母表示的变量。符号常量在使用前必须先定义,定 义的形式是:
#define 符号常量名常量
#define PI 3.1415926
4. 运算符
根据作用的运算数,又将运算符分为算术运算符、增1减1运算符、自反赋值运算符、 关系运算符、逻辑运算符、逗号运算符、条件运算符、长度运算符、位逻辑运算符、位移
位运算符和位自反赋值运算符等不同的类型。
(1)算术运算符
C 语言提供的算术运算符如表2.3所示。其中,正、负号运算符必须出现在运算数的左 边,只需要一个运算数的运算符,称为单目运算符;其他运算符都需要两个运算数,称为 双目运算符。其使用说明如下:
●双目运算符两边运算数的类型必须一致才能进行运算。所得结果的类型与运算数的 类型一致。例如,表达式1.0/2.0的运算结果为0.5;表达式1/2的运算(整除)结 果为0。
●如某双目运算符两边运算数的类型不一致,如一边是整型数, 一边是实型数时,系 统将自动把整型转换为实型数,使运算符两边的类型达到一致后,再进行运算。
● 所有实型数的运算均以双精度方式进行。若是单精度数,则在尾数部分补0,使之 转化为双精度数。
在 C 语言中,常量、变量、函数调用以及按C 语言语法规则用运算符把运算数连起来 的式子都是合法的表达式。凡是表达式都有一个值,即运算结果。由算术运算符构成的表 达式称为算术表达式。
算术运算符和圆括号的优先级高低次序如图2.3所示。
#include <stdio.h>
void main()
{ int n=2+5*3%5-1;printf("n=d\n",n);
}
其执行结果为n=1 。因为*、%运算符的优先级较高,先执行5*3%5,结果为0,再执行 2+0- 1,结果为1。
(2)自增和自减运算符
C语言提供的自增和自减运算符如表2.4所示。
自增和自减运算符只适用于单个变量,而不能用于其他表达式,诸如(x+y)++ --(x+y) 和5++等表达式都是非法的。
程序执行结果为:x=2,y=3,z=2,s=1 。因为a++ 返回a增1前的值, x=2;++b 返回b增 1 后 的值,y=3;c-- 返回c减1前的值,z=2;--d 返回d减1后的值,s=1。
(3)赋值运算符
C语言提供的赋值运算符如表2.5所列。由赋值运算符构成的表达式称为赋值表达式。 赋值运算符(含复合、位复合赋值运算符)将表达式分为左、右两部分,例如, x=y,
x为左值,y 为右值。C 编译器认为左值x的含义是x所代表的地址,这个地址只有编译器知道, 在编译时确定,程序员不必考虑这个地址保存在哪里,所以左值必须对应着内存地址单元, 可以是变量、数组的某个单元或指针等,但不能是其他表达式,否则会出现错误,如:
对于右值y, 它可以是一个表达式,编译器认为y的含义是y所代表的地址里面的内容, 这个内容是什么,只有到运行时才知道。
(4)复合赋值运算符
C语言提供的复合赋值运算符如表2.6所示。由复合赋值运算符构成的表达式称为复合 赋值表达式。
其执行结果为: a=3.000000,b=1.800000,a=1.200000,b=1.800000。 这 里 对a和b两个实数执 行+=和-=运算。
(5)关系运算符
C 语言提供的关系运算符如表2.7所示。由关系运算符构成的表达式称为关系表达式。 例如,有以下程序:
其执行结果为: a=1,b=0。
这 里 , 将 1 < 2 的 结 果 1 ( 真 ) 赋 给a, 将1 . 5>5 . 8的结果0(假)赋给b。
(6)逻辑运算符
C语言提供的逻辑运算符如表2.8所示。由逻辑运算符构成的表达式称为逻辑表达式。
其执行结果为:a=0,b=1。这里,将!(1<2) || (2>5)的结果0(假)赋给a, 将!(1.5>5.8)&&
'a'<z'的结果1(真)赋给b。
(7)逗号运算符
C语言提供的逗号运算符如表2.9所示。由逗号运算符构成的表达式称为逗号表达式。 逗号运算符的优先级最低。例如,有以下程序:
其执行结果为: c=10.400000。 这里,“2*a,2*b”为一个逗号表达式,返回第二个表达 式即2*b的结果。
#include <stdio.h>
void main()
{int a = 2;float b = 5.2;float c = a?2*a:2*b;printf("c=8f\n",c);
}
其执行结果为: c=4.000000 。 这里,“a?2*a:2*b” 是一个条件表达式,a=2 即为真,所 以这个条件表达式返回2*a的值。
(9)长度运算符
C语言提供的长度运算符如表2.11所示。由长度运算符构成的表达式称为长度表达式。 例如,有以下程序:
其执行结果为:2,2,4,4。说明整型变量a和整型均占用两个字节,实型变量b和实型均占 用4个字节。
sizeof是一个运算而不是函数,如有int n=2;printf("%d\n",sizeof n);在Visual C++6.0中输出结果为4,表明变量n占4个字节。
5. 表达式
C 语言中表达式是由运算数和运算符构成的一个可以计算的式子,一个表达式中又可以 包含子表达式,根据不同的运算符又分为算术表达式、逻辑表达式、赋值表达式等。
每个表达式都有一个值,例如,有以下程序:
执行c=(b=a);语句时,b=a是一个赋值表达式,该表达式返回b的值即2,然后将2赋给 变量c; 执行c==(b==a); 语句,b==a 是一个逻辑表达式,它返回0(假),而c为2,所以整个 逻辑表达式返回0。
表达式的优先级由表达式的运算符的优先级和运算符的结合方向来确定,如表2.15所 示,其中数值越大表示优先级越高。例如,分析以下程序在32位计算机中的运行结果:
unsigned char占一个字节,在上述程序中,a=[10100101]₂, 对于b=~a>>4+1 表达式,因 为“~”优先级高于“>>”,所以先对[10100101]₂取反变为[01011010]₂,然后再右移。是先 右移4位再加1,还是先加1再右移5位呢?因为“+”的优先级高于“>>”,所以先加1, 然后再右移5位,变为[00000010]₂,即输出结果为2,但实际上输出结果250,这是因为高 级语言程序转换为汇编语言以后,将结果放在16位寄存器中,这样a对应的寄存器中值为 [0000000010100101]₂,取反后变为[11111101011010]₂,再右移5 位变为[00000111 11111010]₂,而unsigned char表示一个字节,结果为b=[11111010]₂, 即十进制250。
6. 类型转换
不同类型的数据在运算符的作用下构成表达式时要进行类型转换,即把不同类型的数 据先转换成统一的类型,然后再进行运算。
(1)数据的混合运算和自动类型转换
C语言允许不同类型数据的混合运算,即整型、实型和字符型数据都可以出现在同一个 表达式中。但要遵循一定的规则,使运算符两边的操作数具有共同的类型。转换原则是将 运算符两边的数据转换成为它们之中数据最长的数据类型,以保证运算精度不会降低。
体转换原则如图2.4所示。
图中横向箭头表示必须进行的转换,即float型数据必须先转换为double型,即使运算符 两边都是float型数据,同样需要将float 型数据转换为double型,运算结果为double型。这样 可提高运算精度。同理char和short类型数据先转换为int型数据。纵向箭头表示仅当运算符两 边的数据类型不同时才进行转换的方向。箭头方向表示低级别数据类型向高级别数据类型 转化。如int型数据与long型数据一起运算,是将int型数据转化为long型数据,类型相同后再 运算,结果为long型数据。
(2)强制类型转换
在C 语言中可以通过强制类型转换将表达式强制转换成所需的类型。强制类型转换的一 般形式:
(类型名称)表达式
其中,“类型名称”称为强制类型转换运算符,可以利用强制类型转换运算符,将一个 表达式的值转换成指定的类型。这种转换是根据人为要求而进行的。例如,表达式(int)2.12 3把2. 123转换成整数2,表达式(double)(10%3)把10%3所得结果1转换成双精度数1.0。
7.C 语句
一个C程序应包含数据描述(由数据声明部分来实现)和数据操作(由执行语句来实现)。 数据描述主要定义数据结构(用数据类型表示)和数据初值,数据操作的任务是对已提供 的数据进行加工。C语句分为以下5类。
(1)控制语句
完成一定的控制功能,C 语言中只有以下9种控制语句。
● if… (条件语句)
● for … (循环语句)
● while … (循环语句)
● do…while….(循环语句)
● continue(结束本次循环语句)
● break(中止执行switch 或循环语句)
● switch … (多分支选择语句)
·goto … (转向语句
● return… (从函数返回语句)
(2)函数调用语句
由一次函数调用加一个分号构成一个语句,如printf("n=%dn",n);
(3)表达式语句
由一个表达式和一个分号构成一个语句,也就是说,任何表达式都可以加上分号而成 为语句,例如,n++; 是一个语句,x+y;也是一个语句,其作用是完成x+y的操作,它是合法 的,但不把结果赋给另一变量,所以它无实际意义。
(4)空语句
空语句只有一个分号,它什么也不做。
(5)复合语句
复合语句的一般形式为:
一个复合语句在语法上等价于单个语句,这包含两层含意: 一是凡单个语句能够出现 的地方都能够出现复合语句;二是花括号中所有语句是一个整体,要么全部执行,要么一 个也不执行。复合语句可以嵌套,即复合语句中还可以有复合语句。
复合语句的最后一个语句中的分号不能忽略。
2.1.2 例题解析
1. 单项选择题
【例2-1-1】在 C 语言中,int 、char 和 short 三种类型数据所占用的内存是
A. 均为2个字节 B. 由用户自已定义
C. 由所用机器的机器字长决定 D. 是任意的
① 解:这三种类型数据所占用的内存是由所用机器的机器字长决定的,例如,在16 位机中,int 型数据占2个字节,在32位机上, int 型数据占4个字节。本题答案为C。
【例2-1-2】下列叙述中正确的是
A.C 语言中既有逻辑类型也有集合类型
B.C 语言中没有逻辑类型但有集合类型
C.C 语言中有逻辑类型但没有集合类型
D.C 语言中既没有逻辑类型也没有集合类型
① 解:C 语言中逻辑类型用int类型表示,没有集合类型。本题答案为D。 【例2-1-3】以下选项中不属于C 语言的类型的是 o
A.signed short int B.unsigned long int
C.unsigned int D.long short
D 解:long 不能与short一起使用。本题答案为D。
【例2-1-4】错误的int 类型(16位机)的常量是 o
A.32768 B.0 C037 D.OxAF D 解:int类型(16位机)的常量取值范围为-32768~32767。本题答案为A。 【例2-1-5】16位机中为求出s=10!, 则变量s 的类型应当是 0
A.int B.long C.unsigned long D. 以上都不对
D 解:10!的结果为3628800,超出了int类型的常量取值范围,所以应用long int类型。 本题答案为B。
【例2-1-6】设 int 类型的数据长度为两个字节,则unsigned int类型数据的取值范围是
o
A.0~255 B.0~65535 C.-32768~32765 D.-256~255
解 :unsigned int类型数据的取值范围是0000000000000000(0)~1111111111111111 (2¹⁶-1)即0~65535。本题答案为B。
【例2-1-7】下列变量名中合法的是 o
A.B.C.Tom B.3a6b C._6a7b D.$ABC
D 解 :选项A中出现“.”字符错误;选项B中以数字开头错误;选项D中出现“$”字 符错误。本题答案为C。
【例2-1-8】下列变量定义中合法的是 o
A.short _a=1-.1e-1; B.double b=1+5e2.5;
C.long do=0xfdaL; D.float 2_and=1-e-3;
解:_a 是合法的变量名。本题答案为A。
【例2-1-9】已知各变量的类型定义如下:
则以下不符合C 语言语法的表达式是 0
A.x%(-3) B.w+=-2
C.k=(a=2,b=3,a+b) D.a+=a-=(b=4)*(a=3) D 解:%运算符只能用于整型数。本题答案为A。
【例2-1-10】若变量a 是 int 类型,并执行了语句a='A'+1.6;, 则正确的叙述是 o
A.a 的值是字符C B.a 的值是浮点型
C. 不允许字符型和浮点型相加 D.a 的值是字符'A'的ASCII值加上1。 D 解:a='A'+1.6中1.6转换为int数即1。本题答案为D。
【例2-1-11】已知字母A 的 ASCII 码为十进制数65,且c2 为字符型,则执行语句c2 ='A'+'6'-'3'; 后 ,c2 中的值为 o
A.D B.68 C. 不确定的值 D.C
① 解 :c2='A'+'6'-'3'='A'+3='D'。本题答案为A。
【例2-1-12】长整型long 数据在内存中的存储形式是 o
A.ASCII 码 B. 原码 C. 反码 D. 补码
D 解:整数在内存中均以补码形式存储。本题答案为D。
【例2-1-13】字符型常量在内存中存放的是 o
A.ASCII 码 B.BCD 码 C. 内部码 D. 十进制码
① 解:字符数据在内存中均以ASCII码形式存储。本题答案为A。
【例2-1-14】-8在16位机内存中的存储形式是 _o
A.1111111111111000 B.1000000000001000
C.0000000000001000 D. 11111111111101111
① 解:8对应的二进制数为0000000000001000,-8对应的补码为0000000000001000 的反码即1111111111110111加1得到1111111111111000。本题答案为A。
【例2-1-15】下面错误的字符串常量是
A.'abc' B."12'12" C."0" D."" D 解:字符串应以双引号括起来。本题答案为A。
【例2-1-16】以下不合法的十六进制数是 0
A.oxff B.0Xabc C.Ox11 D.0x19
D 解:十六进制的数必须以0x或 0X开头,选项A不符合这一规定,所以本题答案为A。 【例2-1-17】下列浮点数的表示中错误的是
A.100. B..5E2 C.le2b D.12e2.0
① 解:C 语言中,浮点型常量有常规和指数两种形式,其中,指数形式的标志符e或E 前必须有数字,而指数本身必为整数。本题答案为D。
【例2-1-18】字符串常量"I22a,0\n"的长度是 o
A.8 B.7 C.6 D.5
D 解:该字符串中含有转义字符,开头两个反斜杠算一个字符,其后的\22算一个字 符(22为八进制数),a算一个字符,,算一个字符,0算一个字符,\n算一个字符,总共6 个字符。本题答案为C。
例2-1-19】字符串常量"BB\nlll'r" 在内存中占的字节数为① ,此字符串的长度为
② o
A.6 B.7 C.8 D.9
D 解 :字符串常量"BB\nlII'\r"中含有的字符为B、B、\n、I1、'和\r, 共6个字符,在内 存中有一个结尾符\0。本题答案为①B,②A。
【例2-1-20】以下符合C 语言语法的赋值表达式是 。
A.d=9+e+f=d+9 B.d=9+e,f=d+9
C.d=9+e,e++,d+9 D.d=9+e++=d+7
解:选择B是一个逗号表达式,由于逗号的优先级最低,它由d=9+e和f=d+9 两部分 组成,均为合法的赋值表达式。本题答案为B。
声明:
由于习题太多,这里就不一一写出来了,有需要的可以私信我免费获取。
下一章节内容为:选择语句和循环语句。