计算机中的程序,离不开数据个这个单元,它是计算机操作的对象,我们将数据的不同格式叫做数据类型;而数据结构则是按一定的数据类型进行一些组合和构架。
在C语言中,数据类型可分为:基本数据类型,构造数据类型,指针类型,空类型四大类,如图3-1所示。
图3-1 数据类型
下面我们来看一下这4种数据类型的特点:
(1)基本数据类型:它的数据不可以再进行分解。
(2)构造数据类型:根据已定义的一个或多个数据类型用构造的方法来定义的。也就是说,一个构造类型的值可以由若干个“成员”或“元素”组成。其“成员”可以是一个基本数据类型或构造类型。在C语言中,构造类型有以下几种:
1)数组类型
2)结构体类型
3)共用体类型
(3)指针类型:指针是一个特殊的变量,它里面存储的数值被解释成为内存里的一个地址,也是C语言的精华所在。虽然指针变量的值类似于整型量,但从其数据类型意义来看,这是两种完全不同的类型,所以不能混为一谈。
(4)空类型:函数在被调用完成后,通常会返回一个函数值。函数值有一定的数据类型的,应在函数定义及函数说明中加以说明,如在例3-2中给出的min函数定义中,函数头为:int min(int a,int b);其中“int”表示min函数的返回值为整型数据类型。但是,我们也经常会碰到一些函数,调用后并不需要向调用者返回函数值,这时,我们应该如何来书写呢?此时,我们将这种函数定义为“空类型”,其类型说明符为void。如将int min(int a,int b);改为void min(int a,int b);即可。
在本节中,我们先介绍基本数据类型中的整型、浮点型和字符型。其余类型在以后各节中陆续介绍。
3.2.1.1 常量与变量
对于基本数据类型量,根据变量值在程序执行过程中是否发生变化,又可分为常量和变量两种。在程序执行过程中,其值不发生改变的量称为常量,其值可变的量称为变量。每个变量都会有个名字,并在内存中占据一定的存储单元,所占存储单元的数量根据数据类型的不同而不同。在程序中,常量是可以不经说明而直接引用的,而变量则必须先定义后使用。
1.常量和符号常量
常量与变量相对应,在程序执行的过程中,其值不能发生改变的量称为常量。常量与变量不同,可以有不同的数据类型,如:1,3,5为整型常量;6.9,-1.85为实型常量;‘c’,‘d’为字符常量。常量可以用一个标识符来说明,符号常量在使用之前必须先定义,其一般形式为
#define标识符 常量
其中,#define是一条编译预处理命令(预处理命令都以“#”开头),称为宏定义命令,其功能是把该标识符定义为其后的常量值。一经定义,凡在程序中所有出现该标识符的地方均用之前定义好的常量来代替。习惯上符号常量的标识符用大写字母来表示,变量标识符用小写字母,以示区别。
如下面的程序所示:
【例3-3】
程序的第一句话“#define PI 3.14”定义了一个符号常量PI,它的值为圆周率3.14,由此一来,在后面的程序代码中,凡是出现PI的地方,都代表3.14这个数。
使用符号常量的好处是:意义清楚;修改参数非常方便。如程序中很多地方都要用到这个变量,而数值又需要经常做改动,这样的情况下使用符号常量就可以做到“一改全改,一次改成”。
2.变量
在程序运行中,其值可以改变的量称为变量。一个变量有一个名字,在内存中占据一定的存储单元,如图3-2所示。变量必须先定义再使用,一般放在函数体的开头部分,当然,如果是全局变量的话,就放在函数体外面了。
3.2.1.2 整型数据
图3-2 变量与存储单元
1.整型常量的表示方法
整型常量就是整型的常数。在C语言中,整型常量可以分为八进制、十进制和十六进制三种。
1)十进制数没有前缀。用数码0~9来表示。
如以下各数是合法的十进制整型常数:
257、-518、55535、1968;
在程序中是根据前缀来区分各种进制数的。因此在书写常数时不要把前缀弄错造成结果不正确。
2)八进制数:必须以0开头,即以0作为八进制数的前缀。用数码0~7来表示。八进制数通常是无符号数。
以下各数是合法的八进制数:
016(相当于十进制数14)、0110(相当于十进制数72)、0177776(相当于十进制数65534);
以下各数不是合法的八进制数:
156(无前缀0)、01B2(包含了非八进制数字)、-0170(不应该有负号)。
3)十六进制数:以0X或0x开头。其数码取值为0~9,A~F或a~f。
以下各数是合法的十六进制整常数:
0X2B(相当于十进制43)、0XB0(相当于十进制176)、0XFFFF(相当于十进制65535);
以下各数不是合法的十六进制整常数:
7B(无前缀0X)、0X5H(含有非十六进制数码)。
2.整型变量
(1)整型变量的分类
1)基本型:类型说明符为int,在内存中占2个字节。
2)无符号型:类型说明符为unsigned。无符号型又可为unsigned int或unsigned。无符号类型量所占的内存空间字节数与相应的有符号类型量相同,但由于省去了符号位,故不能表示负数,也因此表示正数的数值范围有所扩大。
有符号整型变量:最大表示32767
无符号整型变量:最大表示65535
KEIL uVision2 C51编译器所支持的数据类型见表3-1。
表3-1 数据类型表
(2)整型变量的定义:变量定义的一般形式为
类型说明符 变量名标识符,变量名标识符,...;
例如:
int a,b,c;(a,b,c为整型变量)
unsigned int x,y;(x,y为无符号整型变量)
定义变量时,允许在一个类型说明符后,同时定义多个相同类型的变量。这时,各变量名之间用逗号间隔,类型说明符与变量名之间至少用一个空格间隔。
【例3-4】整型变量的定义与使用。
3.2.1.3 实型数据
1.实型常量的表示方法
实型数据在C语言中也称为浮点型。在C语言中,它有两种表示形式:分别为十进制小数形式和指数形式。
1)十进制数形式:由数码0~9和小数点组成。
例如:
0.0、24.0、5.189、0.93、90.0、6000.、-227.8670
等均为合法的实数。在这个数中是必须存在小数点的。
2)指数形式:在十进制数的基础上,加阶码标志“e”或“E”和阶码(只能为整数,可以带正负号)组成。
其一般形式为:
a E n(a为十进制数,n为十进制整数)
表示的数值为a*10n。
例如:
3.1E4(等于3.1*104)
1.6E-2(等于1.6*10-2)
0.8E7(等于0.8*107)
-1.14E-2(等于-1.14*10-2)
以下不是合法的实数:
385(无小数点)
E6(阶码标志E之前无数字)
-1(无阶码标志)
51.-E3(负号位置不对)
2.9E(无阶码)
标准C允许浮点数尾部加后缀,“f”或“F”即表示该数为浮点数。如328f和328.是等价的。
【例3-5】通过以下程序例子可以看到其显示输出值都是一样的。
2.实型变量
实型变量主要分为:单精度(float型)和双精度(double型),见表3-2。
表3-2 float与double类型数据
在C编译器中单精度型占4个字节(32位)内存空间,其数值范围为3.4E-38~3.4E+38,只能提供七位有效数字。双精度型占8个字节(64位)内存空间,其数值范围为1.7E-308~1.7E+308,提供16位有效数字。
关于实型变量定义的方法与整型相同,参考如下:
例如:(www.xing528.com)
float x,y;(x,y为单精度实型量)
double a,b,c;(a,b,c为双精度实型量)
3.2.1.4 字符型数据
字符型数据可分为字符常量和字符变量。
1.字符常量
我们用单引号括起来的一个字符,称为字符常量。
例如:
‘y’、‘f’、‘-’、‘+’、‘/’
这些都是合法字符常量。
我们在使用字符常量时,需要注意以下几点:
1)字符常量只能用单引号括起来,如果用双引号或其他括号,将出现错误提示。
2)字符常量只能是单个字符,不能出现多个字符。
3)字符可以是字符集中任意字符。但如果将数字定义为字符型常量后,它就不能参加数值运算了。如‘8’和8,仔细看一下是不同的。前者是字符常量,不能参与运算,而后者才是一个整型数据。
2.转义字符
转义字符在C语言中是一种特殊的字符常量。转义字符是以反斜线“\”开头的字符序列。不同的转义字符具有不同的特定含义,因此我们称它为“转义”字符。例如,我们经常在例题中看到的printf函数中用到的“\n”就是一个转义字符,其意义是“回车换行”。转义字符的作用主要用来表示有些用一般字符不便于表示的语句代码。表3-3列出了C语言常用的转义字符及含义。
表3-3 C语言常用的转义字符及含义
可以说,C语言字符集中的任何一个字符均可用转义字符来表示。表中的\ddd和\xhh正是起到了这个作用。ddd和hh分别为八进制ASCII码和十六进制ASCII码。如\102表示字母“B”,\103表示字母“C”,\XOA表示换行等。
【例3-6】转义字符的使用方法。
大家可以想一下,这个程序的输出结果是怎样的。
3.字符变量
字符变量用来存储单个字符。
字符变量的类型说明符是char。其定义方法与上面我们所讲的数据类型定义方法一样。
例如:
char a,b;
char数据类型的长度是1个字节,通常用于定义处理字符数据的变量或常量。unsigned char与signed char数据类型的区别是有无符号位,如果我们直接使用char类型的话,其默认值为signed char类型。因为unsigned char类型1个字节所有的8位均来表示数值,而signed char类型用字节中的最高位bit来表示数据的正负,“0”表示其为正数,“1”表示为负数,所以unsigned char类型可以表达的数值范围是0~255,而signed char类型可以表达的数值范围是-128~+127。
4.字符串常量
字符串常量是由一对双引号括起的字符序列。例如:“CHINA”,“C program”,“$1.3”等都是合法的字符串常量。
那么字符串常量与字符常量之间有什么不同之处呢。总结一下,主要有以下几点:
1)字符常量使用单引号括起来,而字符串常量使用双引号括起来。
2)字符常量只能是单个字符,而字符串常量却可以是一个或多个字符。
3)可以把一个字符常量赋给一个字符变量,但反过来把一个字符串常量赋予一个字符
变量是不行的。在C语言中是没有相应的字符串变量的。
4)字符常量在内存中占1个字节的空间。字符串常量在内存中所占字节的大小等于字符串的字节数加1,这是一个字符串结束的标志位,在C语言中,用字符‘\0’作为字符串的结束标志,‘\0’的ASCII码值为0。
例如:
字符串“C program”在内存中所占字节的情况为
‘\0’为字符串“C program”结束的标志位。
字符常量‘b’和字符串常量“b”,从表面上来看,虽然都只有一个字符,但在内存中的存储情况却是不同的。
‘b’在内存中占1个字节,其存储情况为:
“b”在内存中占2个字节,其存储情况为:
3.2.1.5 变量赋初值在程序中常常需要对变量赋于一个初值。C语言可以在做变量定义的同时,给变量赋上
初值,我们也称之为变量的初始化操作;也可以在后面的语句中再给变量赋上值。变量初始化赋初值的一般形式为
类型说明符 变量1=值1,变量2=值2,变量3=值3……;
例如:
与其他高级编程语言不同,C语言在变量定义中不允许出现多个“=”赋值符号,如a=b=c=3是非法的。
【例3-7】
3.2.1.6 各类数值型数据之间的混合运算
变量的数据类型是可以转换的。转换方式有两种,一种是自动类型转换,另一种是强制类型转换。当程序中不同数据类型的变量混合运算时,自动类型转换由编译器自动完成。自动类型转换遵循以下转换规则:
1)若参与运算的数据类型不一样,则先转换成同一数据类型,再进行运算。
2)转换以保证精度不降低的原则进行。
3)所有的浮点运算都是转换成双精度进行的,既使表达式中仅含float单精度的数据运算量,也要先转换成double型,再作运算处理。
4)在赋值运算中,当赋值号两边的数据类型不同时,赋值号右边的数据类型将转换成左边的数据类型。如果右边的数据类型长度大于左边的数据类型长度时,那它将丢失一部分数据,丢失的部分遵循四舍五入的原则,降低了精度。
类型自动转换的规则如图3-3所示。
当int和char同时进行运算时,则系统先将char转为int型数据;当float与double型共同存在时,则先将float转为double型数据。当int,unsigned,long,doulbe类型的数据同时存在时,则其转换高低关系为int→unsigned→long→double。如果int与long共存时,则必将int转换为long类型数据。
【例3-8】
图3-3 不同数据之间的自动类型转换
例3-8中,变量PI为实型;s,r为整型。当程序运行到s=r*r*PI语句时,变量r和变量PI都将转换成double型数据,其计算结果也为double类型,但因为s为整型变量,根据自动类型转换原则,其最终结果应该为整型,如出现小数数值,则舍去了小数部分,所以,程序的执行结果,其面积s=113。
强制类型转换是通过类型转换运算符来实现的。其一般形式为
(类型名)(表达式)
其功能是把表达式的运算结果值强制转换成类型名所表示的数据类型。
例如:
在使用强制转换时应注意以下两点:
1)当变量为多个时,类型名和表达式都必须加上括号(单个变量可以不加括号),如:把(int)(x+y)写成(int)x+y,其意义为把x转换成int型后再与y相加;而(int)(x+y)的意义是把x和y相加,其相加结果再转换成int数据类型。
2)强制类型转换时,并没有改变原来变量的类型,而是得到一个所需类型的中间变量,如上例中的变量x和变量y,其本身的数据类型和值并没有发生变化。
【例3-9】
从以上程序执行结果可以看出,float型变量f虽然在printf函数中强制类型转为int型,但它只在运算中起作用,而且是临时的,变量f其本身的类型并不改变。因此,(int)f的值为1(截去了小数部分数字),而f的值仍为1.39。
【单片机C语言设计小实例1】先来写个小程序看看unsigned char和unsigned int用于延时的不同效果,说明它们的长度是不同的,学习它们的用法。实验中用LED1的点亮表明正在用unsigned int数值延时,用LED2点亮表明正在用unsigned char数值延时。电路原理如图3-4所示。
图3-4 实验电路
实验程序如下:
执行编译烧写,上电运行你就可以看到结果了。很明显LED1点亮的时间要比LED2点亮的时间长。请注意,当定义一个变量为特定的数据类型时,在程序使用该变量时,不应使它的值超过数据类型的值域。如本例中的变量b不能赋超出0~255的值,如for(b=0;b<255;b++)改为for(b=0;b<256;b++),编译是可以通过的,但运行时就会有问题出现,就是说b的值必须是小于256的,所以无法跳出循环执行下一句P1—1=1,从而造成死循环。同样,a的值不应该超出0~65535的范围。
【单片机C语言设计小实例2】跑马灯实验例子,将P1口的全部引脚分别驱动1个LED发光管。电路原理如图3-5所示。
图3-58 路跑马灯电路
程序如下:
程序中的花样数据可以自己去定义,因这里我们的LED要AT89C51的引脚P1为低电平才会点亮,所以我们要向P1口的各引脚写数据O对应连接的LED才会被点亮,P1口的8个引脚刚好对应P1口特殊寄存器的8个二进位。如向P1口定数据0xFE,转成二进制就是11111110,最低位D0为0,这里引脚P1.0输出低电平,LED1被点亮。如此类推,大家不难算出自己想要做的效果了。大家编译烧写看看,效果就会出来,显示的速度您可以根据需要调整延时a的值,不要超过变量类型的值域就行了。
【单片机C语言设计小实例3】8路跑马灯的另一种写法。
程序如下:
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。