基本数据类型
现实社会中,数据有不同的表现形式,有的是整数、有的是小数、有的是字符等,为了区别这些不同的类型,定义变量时必须和一个具体的数据类型相联系,C语言中数据类型主要有整型、实型、字符型、枚举类型、构造类型、指针类型、无类型等。
一、整型数据
整型变量的基本类型符为int,根据表示数据的范围不同分为:short int、int、long int、long long int,short int 、long int、long long int后面的int可以省略,每种类型又分为有符号数(signed)和无符号数(unsigned)两种,有符号数(signed)可以省略,所谓有符号数就是使用最高位表示正负,“0”是正数,“1”是负数,这样整型变量就有8种,如下表:
关键字 | 一般字节数 | 表示数据范围 |
unsigned short [int] | 2 | 0---65535(0----216-1) |
[signed] short [int] | 2 | -32768---32767(-215---215-1) |
unsigned int | 4 | 0--4294967295(0----232-1) |
[signed] int | 4 | -2147483648--2147483647(-231---231-1) |
unsigned long [int] | 4 | 0--4294967295(0----232-1) |
[signed] long [int] | 4 | -2147483648--2147483647(-231---231-1) |
unsigned long long [int] | 8 | (0----264-1) |
[signed] long long [int] | 8 | (-263---263-1) |
1、整型变量的定义
关键字 变量名;
定义多个变量时在变量名之间加“,”,如:
int a;
int a,b;
2、整型数据溢出
2.1、无符号整型溢出
无符号整型溢出,C的规范是有定义的——“溢出后的数会以2^(8*sizeof(type))作模运算”。如:unsigned short a=65535;
a的值
1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
a+1:
1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
(a+1)除以63536的余数为0,相当于1丢弃。
2.2、有符号整型溢出
有符号整型溢出,与编译器有关
如:signed short a=32767;
a的值
0 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 |
a+1:
1 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
最高位为符号位,加一后为最小负数:-32768
程序设计中,要估计变量的数据范围和类型,选用合适的数据类型,避免数据溢出。
3、整型常量表示
一般根据常量所在的数据范围确定常量类型,也可使用后缀表示法,表示常量类型:
(1)用L或l表示long int型;
(2)用LL或ll表示long long int型;
(3)用U或u表示unsigned型;
二、浮点型数据
1、浮点型变量
浮点数就是数学上的实数,浮点类型除可以使用常用的十进制小数写法外,还可以使用科学计数法表示,科学计数法表示也称为e表示法,即尾数和指数写在一排,E或e在中间,尾数在前指数在后。
浮点数有三种类型,分别为:float、double、long double。
浮点数的存储方式:
分为三个部分
(1)符号位
(2)指数部分
(3)尾数部分
各种类型表示占用的字节和表示范围如下表:
关键字 | 占用字节 | 有效位数 | 数据范围 |
float | 4 | 6—7 | -3.4*10^38~+3.4*10^38 |
double | 8 | 15--16(精确到15位,可以显示到16位) | -1.7*10^-308~1.7*10^308 |
long double | 16(与编译器有关) |
printf函数输出long double数据时存在问题,使用c++的cout输出。
2、浮点型常量
默认的表示形式是double,float在数字后面加L或l,long double 在数字后面加L或l。
浮点数计算时会出现舍入误差或错误,当一个大数与小数相加时,由于有效位数的影响造成被加的小数被舍弃掉,从而造成误差。
三、字符型数据
1、字符型变量
基本类型符为char,只能放一个字符,使用一个字节储存数据,虽然也可以加unsigned和signed限定符,但意义不大,asc码表有0---127个字符。
2、字符常量
字符常量为单引号括起来的一个字符,如:’A’等。
3、转义字符
C语言中还有一种有特殊意义的字符常量,是以“\”开始的字符序列,有特殊含义:
转义字符 | 含义 | ASCII码 |
\0 | 空字符(NULL) | |
\n | 换行符(LF) | |
\r | 回车符(CR) | |
\t | 水平制表符 | |
\v | 垂直制表 | |
\a | 响铃 | |
\b | 退格符 | |
\f | 换页符 | |
\’ | 单引号 | |
\” | 双引号 | |
\\ | 反斜杠 | |
\? | 问号 | |
\ddd | 三位八进制 | |
\xhh | 二位十六进制 |
如:i='\101' 则显示十进制65
4、字符串常量
用双引号括起来的字符序列,为字符串常量。
c++又增加了布尔数据类型。
四、赋值运算符和赋值表达式
1、赋值运算符
C语言的赋值运算符为等号,表示形式“=”。
此外,还有复合赋值运算符,后续陆续介绍。
2、赋值表达式
“=”的左侧是变量,右侧是常量、变量、表达式、函数等,“=”的含义是将右边的值赋给左侧的变量,程序运行时先计算右侧值,然后赋给左侧变量。
3、赋值语句
赋值表达式句尾加上“;”就是赋值语句。
注意:const float PI=3.14中“=”含义是用3.14初始化PI。
五、算术运算符和算术表达式
对计算机中数据进行算术运算的运算符,称为算术运算符,包括数学中学到的加减乘除和一些扩展。
1、加法和减法运算符
加法运算符为“+”,使运算符两侧的值相加,两侧的值可以是变量、常量和表达式等。
减法运算符为“-”,使运算符左侧的值减去右侧的值。
2、乘法和除法运算符
乘法运算符为“*”,使运算符两侧的值相乘。
除法运算符为“/”,使运算符两侧的值相除,”/”左侧的值是被除数,右侧的值是除数。
3、求模运算符
求模运算符为“%”,求出左侧整数除以右侧整数的余数。
上面运算符为二元运算符,所谓二元运算符为运算符两边有两个操作数。
4、符号运算符
“+”(正号)不改变操作数的值及符号, “-“(负号)可用于得到一个数的相反数。
5、自增和自减运算符
自增运算符为“++”,自减运算符为“--”。
自增运算符使运算对象递增1,有两种形式:运算符在变量的左侧,称前缀模式,运算符在变量的右侧,称后缀模式。
前缀形式指变量的值加1作为表达式的值,同时变量的值加1;后缀形式指将变量的值作为表达式的值,然后变量值加1。
例3.1 自增运算符使用
#include <stdio.h>
int main()
{
int i;
i=1;
printf("%d\n",++i);
printf("%d\n",i);
i=5;
printf("%d\n",i++);
printf("%d\n",i);
return 0;
}
执行结果为:
2
2
5
6
printf("%d\n",++i)执行前i的值为1,语句执行时先进行i加1,输出为2,i变为2,下一步输出2;printf("%d\n",i++)执行前i的值为5,先输出i的值5,然后i加1,i变为6,下一个语句输出6。
符号运算符、自增和自减运算符为一元运算符。
6、复合赋值运算符
复合赋值运算符有:+=、-=、*=、/=、%=,分别等同于以下:
x+=y+1等同x=x+(y+1)依次类推,注意:右侧表达式为一个整体。
7、括号()
与数学上的括号一样,能改变运算的顺序。
8、算术表达式
使用算术运算符将运算对象连接起来、符合C语言语法规则的式子。
9、算术运算符的优先级
优先级 | 运算符 | 含义 |
1 | () | 括号 |
2 | - | 负号 |
++ | 自增 | |
-- | 自减 | |
3 | * | 乘 |
/ | 除 | |
% | 余数 | |
4 | + | 加 |
- | 减 | |
5 | = | 赋值 |
10、表达式的结合性
表达式求值时先按照运算符的优先级,优先级相同时,不同的表达式结合方向不同,根据结合方向的不同,分为:自左向右称左结合性;自右向左称右结合性。
算术运算符中的()、*、/、%、+、-是左结合性,++、--是右结合性;赋值表达式是右结合性。
例3.2 3+5-2
按照左结合性,先算3+5=8,再8-2=6。
例3.3 3+2+5*6
先计算5*6=30,然后结算3+2+30。
例3.4 (2+5)*6
先计算”(2+5”,再计算7*6。
例3.5 a=10+5*6-3%2
先计算”=”右边表达式的值,计算顺序为5*6à3%2--à10+30-1-à40-1---à39。
然后将39赋值给a。
11、自增、自减运算的不确定性
例3.6
i=1;
printf(“%d %d”,i,i++);
本例中printf语句可能造成输出结果的不确定,一般输出2 1,但也有的编译系统输出1 1。
编程时要避免这种不确定,一个变量在一个表达式中多处不要对该变量进行自增、自减操作。
六、数据类型的自动转换和强制转换
1、数据类型的自动转换
当表达式中运算对象的数据类型不同时,要将运算对象转换成同一种类型,才能进行计算,通常是向占用字节数多或表示数据范围大的方向转变。如下图:
注意点:当int型数据与float型或double型,int型直接转变为double型,float型也转变为double型。
例3.7 int 与 unsigned int混合运算时:int--à unsigned int
#include <iostream>
using namespace std;
int main()
{
unsigned int a;
signed int b;
a=3;
b=-1;
cout<<a*b;
return 0;
}
输出结果为:4294967293
在一个赋值语句中,赋值运算符两侧的数据类型不一致,也发生自动类型转换。如果右侧表示范围小于左侧,一般不发生数据缺失,有以下规律:
(1)无符号数赋值给高级别数据时,原样内存复制;
(2)有符号数赋值给高级别数据时,符号位要进行扩展,有符号数到无符号数,将导致数据失真;
例3.8
#include <stdio.h>
int main()
{
unsigned char a;
unsigned short b;
a='\x81';
b=a;
printf("%d\n",b); //无符号数扩展到无符号数,最高位不扩展
unsigned char c;
short d;
c='\x81';
d=c;
printf("%d\n",d); //无符号数扩展到有符号数,最高位不扩展
char e;
unsigned short f;
e='\x81';
f=e;
printf("%d\n",f); //有符号数扩展到无符号数,最高位1扩展,负数放入整数中,高位符号位扩展
char g;
short h;
g='\x81';
h=g;
printf("%d\n",h); //有符号数扩展到有符号数,最高位1扩展,不丢失精度
return 0;
}
输出结果:
129
129
65409
-127
如果右侧表示范围大于左侧,如果实际数据大于右侧数据范围,发生数据截断。这种情况一般使用强制类型转换。
2、数据类型的强制转换
可以将表达式的数据类型强制转换为另外一种类型,命令形式:(数据类型)表达式。
强制转换一般用在大转小,是一元运算符,仅作用在最近邻的运算对象。例如:
(double)a 将a转换为double型;
(double)(x+y) 将(x+y)的值转为double型;
(double)x+y 将x的值转为double型。
float型、double型转为整型时,截断小数部分,字节多的整数转为字节少的整数时,低位字节放入字节少的整数中。