第二章   数据类型、运算符与表达式

§2.1 C的数据类型
§2.2 常量与变量
§2.3 整型数据
§2.4 实型数据
§2.5 字符型数据
§2.6 变量赋初值
§2.7 各类数据混合运算
§2.8 算术运算符和算术表达式
§2.9 赋值运算符和赋值表达式
§2.10 逗号运算符和逗号表达式

§2.1 C的数据类型

程序的构成:数据、对数据的处理。 
计算机科学家沃思(Nikiklaus Wirth)提出的公式:数据结构 + 算法 = 程序
考虑程序设计方法和使用的语言及开发环境,表达为:程序 = 算法 + 数据结构 + 程序设计方法 + 语言工具和环境
C语言提供的数据元素的类型:


§2.2 常量与变量

2.2.1 常量(Constant)与符号常量
常量: 在程序运行过程中,其值不能被改变的量。
符号常量:代表常量的标识符(符号)。
[例2.1]

#define PRICE 30
main()
{  
  int num, total;
  num = 10;
  total = num * PRICE;
  printf("total = %d", total);
}  

2.2.2 变量(Variable)
变量:在程序运行过程中,其值可以被改变的量。

在源程序中,变量用标识符(以字母、数字、下划线组成,且第一个字符必须为字母或下划线)表示。

变量在内存中占据一定的存储单元。变量名的类型表明存储单元的数量(例如,整型变量int,占2字节存储单元。单精度实数float占4字节);变量名表示存储单元的值(该值在程序运行过程中可能随时变化)。可以用运算符&取得存储单元的地址。

合法变量名:

sum, average,class, day, month, student_name, _above, lotus_1_2_3, basic

不合法的变量名: M.D.Jhon, $123, #33, 3D64, a>b

变量名的长度:C语言中未统一规定,随不同开发系统而变。

变量名 允许长度8 允许长度32
student_name 相同变量名 不同变量名
student_number

Turbo C 2.0缺省允许的变量名长度为32。(Options|Compiler|Source|Identifier length)。

程序设计中变量的命名:

必须满足C语言的语法规定。(以字母、下划线开始,由....构成)。

应该“见名知意”。

C语言对变量的要求:“先定义、后使用”,因为:

1、编译程序不能翻译未定义变量。
2、编译程序在编译时根据变量类型确定存储单元的数量。
3、编译程序在编译时根据变量类型进行语法检查。例,整型变量a、b可以进行“求余”运算 a % b
若把a、b定义为实数,则上述运算非法。


§2.3 整型数据

2.3.1 整型常量

C语言中数值常量的表达方式:

表达方式 意义 十进制值
123 十进制 123
0123(数字字符0开头) 八进制 83
0x123(0x开头) 十六进制 291

2.3.2 整型变量

  有符号 无符号
基本型(简称整型) int unsigned int
短整型 short或short int unsigned short
长整型 long或long int unsigned long

C语言标准没有规定整型变量在计算机内存中所占的字节数,它与具体的机器和操作系统有关:

IBM PC 所占位数 数的范围
int 16 -32768~+32767
short 16 -32768~+32767
long 32 -2147483648~+2147483647
unsigned int 16 0~65535
unsigned short 16 0~65535
unsigned long 32 0~4294967295

二、整型变量的定义

int a,b; /* 指定变量a、b为整型 */
unsigned short c, d; /*指定变量c、d为无符号短整型 */
long e,f; /* 指定变量e、f为长整型*/
程序中在函数的开头部分定义变量。

[例2.2]

main()
{

int a,b,c,d; /* 指定变量a、b、c、d为整型 */

  unsigned u; /* 指定变量u为无符号整型 */
  a = 12; b = -24; u = 10;
  c = a + u; d = b+u;
  printf("a+u = %d, b+u = %d\n", c,d);
}  

程序运行显示:a+u = 22, b+u = -14

三、整型常量的类型

1、整型常量的值在-32768~+32767范围内,编译器认为是int类型。
2、整型常量的值超过上述范围,而在--2147483648~+2147483647范围内,编译器认为是long类型。
3、在整型常量的值后面加字母L(大写L或小写l),则告诉编译器,把该整型常量作为long类型处理。例:123L、0L。
4、常量无unsigned 型。


§2.4 实型数据

2.4.1 实型常量

实数(real)又称为浮点数(float),有两种表达方式:
0.123、 .123、 123.0、 123.、 0.0(必须有小数点)
123e3或123E3、123E-2

2.4.2 实型变量

    占内存单元
单精度实型变量 float 4字节(32位)
双精度实型变量 double 8字节(64位)

例:

float x,y; /* 指定x、y为单精度实型变量 */
double z; /* 指定z为双精度实型变量 */
实型常量不分float和double。


§2.5 字符型数据

2.5.1 字符常量

用单引号(撇号)括起来的一个字符。如:'a'、'x'、'D'、'?'、'$'。注意,'a'和'A'是不同的字符常量。

以"\"开头的字符序列,称为“转义序列”,“\”使其后面的字符变为另外的意义。见下表。

字符形式 功能
\n 换行符
\t 横向跳格:跳到下一个输出区(每一输出区为8个字符位置)
\v 竖向跳格
\b 退格
\r 回车(回到本行起始字符位置)
\f 走纸换页
\\ 反斜杠字符\
\' 单引号(撇号)'
\ddd 1~3位八进制数所代表的字符。如\101表示'A'
\xhh 1~2位十六进制数所代表的字符。如\x40表示'A'

转义序列主要用来控制打印机和屏幕输出。 例:printf("\n sum is %d\n\n",sum);

2.5.2 字符变量

char c1,c2; /* 定义c1、c2为字符变量 */
c1 = 'a'; c2 = 'b';
字符变量在内存中占一字节。

2.5.3 字符数据在内存中的存储形式及其使用方法
   字符在内存中以ASCII码存放。

字符 ASCII
'A' 0x40(64)
'B' 0x41(65)
'a' 0x61(97)
'a' 0x62(98)
'0' 0x30(48)
'1' 0x31(49)

[例2.4]

main()
{ char c1,c2;
  c1 = 97; c2 = 98;
  printf("%c %c",c1,c2);
}  

该例的输出是:a b

字符以ASCII码存储,其存储方式与整数类似。从而,C语言允许字符和整数之间进行运算。

[例2.5]

main()
{ char c1,c2;
  c1 = 'a'; c2 = 'b';
  c1 = c1 - 32; c2 = c2 - 32;
  printf("%c %c",c1,c2);
}  

另外:Turbo C允许使用unsigned char。

2.5.4 字符串常量

字符常量:单引号括起来的一个字符。

字符串常量:双引号括起来的字符序列(0~N个字符)。如:

"How do you do.", "CHINA", "a", "$123.45"

字符串常量在内存中的存放:每一个字符均以其ASCII码存放,且最后添加一个“空字符”(二进制00000000,记为NULL或\0。字符'0'在内存中存0x30即00100000)。例:

字符串常量"CHINA"存放在内存中的情况是:(6字节存储器,不是5字节)

C H I N A \0

因此,字符'a'和字符串"a"的区别是:

字符'a' :1字节(值为97)

字符串"a":2字节(值为97,0)

另外:

char c;
c = 'a'; /* 字符'a' */
c = "a"; /* 字符串"a" */


§2.6 变量赋初值

在定义变量的同时指定其初值。例、

int a = 3;

float f = 3.56;

char c = 'a';

int a,b, c = 5; /* 指定c的初值为5,未指定ab的初值 */

注意:多个变量指定相同的初值。

int a = b = c = 3;

int a = 3, b = 3, c = 3;

指定初值是在程序运行时完成的(不是在编译时完成)。

定义方法 相当的语句
int a = 3;

int a;
a = 3; /* 运行时执行赋值语句 */

int a,b,c=5;

int a,b,c;
c = 5;

 


§2.7 各类数据混合运算

整型、实型(包括单、双精度)、字符型数据可以混合运算。例、

10 + 'a' + 1.5 - 8765.1234 * 'b'

混合运算时,先转换成同一种类型,然后进行运算。转换规则如下:

例:int数据可以转换为unsigned数据;

float数据可以转换为double数据;

int数据可以转换为double数据,(直接转换,不需先转换为unsigned,long,再转换为double)。

例:

int i;
float f;
double d;
long e;

10 + 'a' + i*f - d/e

上式的运算次序是:

① 进行10+'a'运算。先将'a'转换为整数97,运算结果为整数107。

② 进行i*f运算。先将i和f均转换为double类型(实运算过程总是使用double类型,仅在把结果存入存储器时,才可能使用float类型),运算结果是double类型。

③ 整数107与i*f的积相加。先将整数107转换为double类型(107.0),运算结果是double类型。

④ 进行d/e运算。先将long e转换为double类型,运算结果是double类型。

⑤ 进行③-④运算,结果为double类型。

注意:上述转换过程是由系统自动完成的。(程序员可以强制进行某种转换,见§2.8)。


§2.8 算术运算符和算术表达式

2.8.1 C运算符简介

算术运算符 +、-、*、/、%
关系运算符 >、<、==、>=、<=、!=
逻辑运算符 !、&&、||
位运算符 <<、>>、~、|、∧、&
赋值运算符 =
条件运算符 ?、:
逗号运算符
指针运算符 *、&
求字节数运算符 sizeof
强制类型转换运算符 (类型)
分量运算符 .(点)、→
下标运算符 []
其他 函数调用运算符()

 

2.8.2 算术运算符和算术表达式

一、基本的算术运算符

+ 加法运算符,如3+5
正值运算符,如+3
- 减法运算符,如5-2
负值运算符,如-3

*

乘法运算符,如3*5
/ 除法运算符,如5/3
% 模运算符(或称求余运算符),如7%4

注:-5/3 = -1(余-2) 或 -2(余+1),Turbo C 取-1结果(“向零取整”)。

二、算术表达式和运算符的优先级与结合性

算术表达式:用算术运算符和括号将运算对象(也称操作数,如常量、变量、函数等)连接起来、符合C语法规则的式子。如:

a*b/c - 1.5 + 'a'

运算符的优先级:先乘除、后加减;先括号。

运算符的结合性:运算对象两侧的运算符优先级相同时,运算符的结合方向(左、右)。

左结合性:结合方向为从左至右(先左后右,简称左结合)。算术运算符为左结合。

例:a - b + c

由于算术运算符为左结合,故先执行a-b,再执行加c的运算。

右结合性:结合方向为从右至左(先右后左,简称右结合)。赋值运算符=为右结合。

例: a = b + c

由于赋值运算符=为右结合,先执行右边的b+c,再赋值给a。

三、强制类型转换

运算符两侧的数据类型不同时,先自动进行类型转换,再运算。程序员可以强制进行某种转换。强制类型转换的一般形式是:

(类型名)(表达式)

例、

(double)a; /* 将a转换为double类型 */

(int)(x+y); /* 将x+y的值转换为int类型 */

(float)(5 % 3);/* 将5%3的值转换为float类型 */

区别:

(int)(x+y); /* 将x+y的值转换为int类型 */

(int)x+y; /* 将x的值转换为int类型,再与y相加 */

(int)(x);

(int)x;(表达式仅为一个变量时,括号可以省略)

int(x);

说明:强制类型转换时,得到一个所需类型的中间变量,原来变量的类型不发生变化。

例、 (int)x

变量x的类型不发生变化。

 

四、自增、自减运算符

自增:使变量的值加1; 自减:使变量的值减1。

++i;/* 在使用i之前使i加1 */

--i; /* 在使用i之前使i减1 */

i++; /* 在使用i之后使i加1 */

i--; /* 在使用i之后使i减1 */

例:

j = 3;

j = ++i; /* 先使i加1,再赋给j。执行后:j=4, i=4 */

j = 3;

j = i++; /* 先把i赋给j,再使i加1。执行后:j=3,i=4 */

注意:

(1)++和--只能用于变量,不能用于常量和表达式。例、

5++;

(a+b)++;

#define ONE 1; ONE++;

(2) ++和--的结合方向为“右结合”。例:

-i++

负值运算符-和自增运算符优先级相同

(-i)++
-(i++)

 

五、有关表达式使用中的问题说明

1. 在表达式中使用++或--,容易出错。

i = 3;

k = (i++) + (i++) + (i++)

k值等于9。

i++:先使用i,再加1。
执行后: k = 3 + 3 + 3 = 9。
     i = 6。

k = (++i) + (++i) + (++i)

k值等于18。

++i:先加1,再使用i。

连续3次使i加1后,i的值等于6

k = 6+6+6 = 18;

2. 出现多个运算符时,编译器在处理时尽可能多的(从左到右)将若干个字符组合成一个运算符。例、

i+++j; (i++)+j
i+(++j)

3. Turbo C中,调用函数时,实际参数的处理顺序是从右到左(称为C调用约定。实际参数的处理顺序从左到右,称为PASCAL调用约定)。例:

i = 3;

printf("%d,%d",i,i++);

先右:i++,先使用i(3),再使i加1。

后左:i(现在值为4)。

因此,输出结果:4,3

菜单:Options|Compiler|Code generation|Calling convention


§2.9 赋值运算符和赋值表达式

一、赋值运算符:=

作用:将一个表达式的值赋给变量。例、

a = 3;/*常数3赋给变量a。常数是特殊的表达式 */

a = b + c + 1;

二、赋值时的类型转换

当赋值运算符两侧的类型不同时,在赋值前进行类型转换。

1、float、double int:舍弃小数(截断)。

2、int float、double:值不变。

3、char(1字节) int(2字节)

(1)(unsigned char) int:赋给int的低8位,int的高8位补0。

(2)(signed char)int:赋给int的低8位,若signed char的最高位是0,则int的高8位全为0;若signed char的最高位是1,则int的高8位全为1。(称为“符号扩展”)

4、 int long int(符号扩展)

long int int(截断)

5、 unsigned int int

6、非unsigned数据 位数相同的unsigned 数据。

三、复合的赋值运算符

复合赋值运算符 例子语句 等价语句
+= a += 3; a = a + 3;
*= x *= y + 8; x = x*(y+8)
%= x %= 3; x = x % 3;

四、赋值表达式

一般形式:<变量> <赋值运算符> <表达式>

例:

赋值表达式: a = 5
赋值语句: a = 5;

赋值表达式中的“表达式”也可以是赋值表达式。例、

a = (b = 5) /* b的值等于5,表达式b=5的值等于5,因此a的值等于5 */

a = b = 5 /* 与上述表达式的意义相同 */

例、

a = 5 + (c = 6) /* c=6, a=11 */

a = (b = 4) + (c = 6) /* c=6, b=4, a=10 */

a = (b = 10) / (c = 2) /* c=2,b=10,a=5 */

a += a -= a*a /* 先a=a-a**,再a=a+a */


§2.10 逗号运算符和逗号表达式

逗号运算符:,

逗号表达式:用逗号运算符把两个表达式连接起来的表达式。其一般形式为:

表达式1,表达式2

例、

3+5,6+8 /* 是一个逗号表达式 */

逗号表达式的值等于“表达式2”的值,但C语言中使用逗号表达式的一般目的是分别获得两个表达式的值,因此,逗号运算符又称为“顺序求值运算符”。

逗号表达式可以扩展为更一般的形式:

表达式1,表达式2,表达式3,.....,表达式n

例、

a = 3*5,a*4

(a=3*5,a*4),a+5

区别:(逗号运算符在所有运算符中优先级最低)

x = (a=3,6*3) /*赋值表达式 */

x = a =3,6*a /* 逗号表达式 */

区别:(逗号可以作运算符,也可以作分隔符)

printf("%d,%d,%d",a,b,c); /* 逗号做分隔符 */

printf("%d,%d,%d",(a,b,c),b,c); /* (a,b,c)中的逗号是运算符,其余逗号是分隔符 */

 


本章要求

本章有关常量、变量、运算符、表达式的细节非常多,它们不是程序设计的最重要的内容,但细节错误也导致程序最终错误,因此,还是要引起注意。

细节不能死记,要注意本质概念;对于无把握的细节,要在Turbo C中进行测试。