目录
前言
程序离不开数据,本文是对数据类型的一个大致了解的笔记总结,如有错误,欢迎大家一起来指出。
一、基本数据类型关键字概览
int //整型 |
long //长整型 |
short //短整型 |
unsigned //无符号类型 |
char //字符数据类型 |
float //单精度浮点数 |
double //双精度浮点数 |
signed //有符号类型 |
void //无类型 |
_Bool //布尔值(true/false) |
_Complex //复数 |
_Imaginary //虚数 |
1.出现这么多类型的原因是:是为了更加丰富的表达生活中的各种值
2.long,short,unsigned和signed用于提供基本整数类型的变式,如unsigned short int,long long int...
3.通过这些关键字创建的类型,按计算机的存储方式可分为两大基本类型:整数类型和浮点数类型
二、整型类型
1.基本单位的了解
(1)最小的存储单元是位(bit),可以存储0或1
(2)字节(byte)是常用的计算机存储单位,1byte=8bit
(3)1TB(万亿字节/太字节)=1024GB(吉字节) 1GB=1024MB(兆字节) 1MB=1024KB(千字节) 1KB=1024Byte
2.整数类型
(1)
名称 | 类型名 | 数据长度 | 取值范围 |
[有符号]整型 | int | 32bit | -2^31~2^31-1 |
[有符号]短整型 | short [int] | 16bit | -2^15~2^15-1 |
[有符号]长整型 | long [int] | 32bit | -2^31~2^31-1 |
无符号整型 | unsigned [int] | 32bit | 0~2^32-1 |
无符号短整型 | unsigned short [int] | 16bit | 0~2^16-1 |
无符号长整型 | unsigned long [int] | 32bit | 0~2^32-1 |
①整型家族:字符、短整型、整型和长整型,它们都分为有符号和无符号两种版本
②C语言规定:长整型至少应该和整型一样长,而整型至少应该和短整型一样长,所以长整型所能表示的值不一定比短整型所能表示的值大。
③数据长度如何算:
sizeof()是C语言内置的运算符(不是函数),以字节为单位给出指定类型的大小,所以使用sizeof()可以算出数据长度:
#include <stdio.h>
int main()
{
printf("%d\n", sizeof(int));
return 0;
}
编译并运行该程序,输出如下:
4
//4byte=32bit
④取值范围如何看:
C头文件limits.h提供了整数类型大小限制相关的详细信息,所以引用这个头文件,可以快速算出取值范围
signed | unsigned | ||
类型 | 最小值 | 最大值 | 最大值 |
字符 | SCHAR_MIN | SCHAR_MAX | UCHAR_MAX |
短整型 | SHRT_MIN | SHRT_MAX | USHRT_MAX |
整型 | INT_MIN | INT_MAX | UINT_MAX |
长整型 | LONG_MIN | LONG_MAX | ULONG_MAX |
#include <stdio.h>
#include <limits.h>
int main()
{
printf("%d\n", INT_MIN);
return 0;
}
编译并运行该程序,输出如下:
-2147483648
//-2^31的大小
(2)整数的表示:八进制,十进制,十六进制
八进制:由正号,负号和阿拉伯数字0~7组成,前缀为0
十进制:由正号,负号和阿拉伯数字0~9组成
十六进制:由正号,负号和阿拉伯数字0~9、英文字符a~f或A~F组成,前缀为0x或0X
如:16,020,0x10分别为十进制,八进制,十六进制整数,它们表示同一个数值的整数,即十进制数值16
注意:使用不同的进制是为了方便,不会影响数被存储的方式,计算机内部都以二进制进行编码
(3)数据的输入与输出
数据类型 | 十进制 | 八进制 | 十六进制 |
int | %d | %o | %x |
long | %ld | %lo | %lx |
long long | %lld | %llo | %llx |
short | %hd | %ho | %hx |
unsigned | %u | %o | %x |
unsigned long | %lu | %lo | %lx |
- 转换说明指定了printf()应该用什么格式来显示一个值,不同的进制要使用不同的转换说明
- 如果要显示前缀,可以在转换说明的%后加入#
举个例子:
#include <stdio.h>
int main()
{
int x = 100;
printf("dec = %d,octal = %o,hex = %x\n",x,x,x);
printf("dec = %d,octal = %#o,hex = %#x\n",x,x,x);
return 0;
}
编译并运行该程序,输出如下:
dec = 100,octal = 144,hex = 64 dec = 100,octal = 0144,hex = 0x64
注意:①使用错误的转换说明会得到意想不到的结果
②int类型被认为是计算机处理整型类型时最高效的类型
举个例子:
#include <stdio.h>
int main()
{
unsigned int num1 = 3000000000;
short num2 = 200;
printf("num1 = %u and not %d\n",num1,num1);
printf("num2 = %hd and %d\n",num2,num2);
return 0;
}
编译并运行该程序,输出如下:
num1 = 3000000000 and not -1294967296
num2 = 200 and 200
对于第一行输出:使用%d会生成负值,是因为无符号值3000000000和有符号值-1294967296在系统内存中的内部表示完全相同,所以如果告诉printf()该数是无符号数,它会打印一个值;如果告诉printf()该数是有符号数,它会打印另一个值。
对于第二行输出:打印出来的值相同是因为C编译器把short类型的值自动转换为int类型的值,自动转换的原因是因为int类型被认为是计算机处理整型类型时最高效的类型。使用h修饰符可以显示较大整数被截断成short类型值的情况。
(4)整数溢出:
①当无符号整数达到它能表示的最大值时,会重新从起始点0开始
②当有符号整数达到它能表示的最大值时,会重新从-2147483648开始
③以上溢出情况比较有代表性,但是也有可能会出现其他情况
3.字符类型char
(1)char类型用于存储字符(如:字母或标点符号),但是从技术层面上看,char是整型类型,因为它实际上存储的是整数而不是字符。计算机使用数字编码来处理字符,美国最常用的编码是ASCII编码。
(2)标准ASCII码的范围是0~127,只需7位二进制位表示,所以char类型容纳标准ASCII绰绰有余。许多其他系统(如:IMB PC和苹果macOS)还提供扩展ASCII码,也在8位的表示范围内。
(3)char类型的声明,初始化和大小: ①与其他类型声明相同:如:char response;
char itable,latan;
②初始化:在C语言中,用单引号括起来的单个字符被称为字符常量
#include <stdio.h>
int main()
{
char grade;//声明一个char类型的变量
grade = 'A';//正确,与 grade = 65;相比,grade = 'A';的可移植性更高
grade = 65;//与grade = 'A'等价(前提:系统使用ASCII码),因为字符是以数值的形式存储的,但不建议这样写!
grade = A;//错误!此时A是一个变量
grade = "A";//错误!此时A是一个字符串
return 0;
}
③char类型的大小:
名称 | 类型名 | 数据长度 | 取值范围 |
[有符号]字符型 | char | 8bit | -128~127 |
无符号字符型 | unsigned char | 8bit | 0~255 |
(4)打印字符:
printf()函数用%c指明待打印的字符,如果用%d转换说明打印char类型变量的值,打印的是它的ASCII码值
#include <stdio.h>
int main()
{
char ch;
scanf("%c",&ch);
printf("The code for %c is %d.\n",ch,ch);
return 0;
}
编译并运行该程序,输出如下:
C The code for C is 67.
注意:printf()中的转换说明决定的是数据的显示方式,而不是数据的存储方式
(5)非打印字符:
单引号只使用于打印字符,数字和标点符号,由ASCII码表可知,有一些ASCII字符打印不出来(如:换行,退格......),C语言提供了3种方法:
①使用ASCII码值。如:char beep = 7;//蜂鸣的ASCII码值为7 ②使用特殊的符号序列表示一些特殊的字符,这些符号序列被称为转义序列
转义序列 | 含义 |
\a | 警报(能否听见或看见取决于计算机硬件) |
\b | 退格 |
\f | 换页(把活跃位置移动到下一页的起始处) |
\n | 换行(把活跃位置移动到下一行的起始处) |
\r | 回车(把活页位置移动到当前行的开始处) |
\t | 水平制表符(把活跃位置移动到下一个水平制表点,通常是第1个、第9个、第17个......字符位置(每次加8)) |
\v | 垂直制表符(把活跃位置移动到下一个垂直制表点) |
\\ | 反斜杆(\) |
\' | 单引号 |
\" | 双引号 |
\? | 问号 |
\0oo \ooo | 八进制值(oo每个o必须是有效的八进制数,0可以省略) (ooo表示1~3个有效的八进制数) |
\xhh | 十六进制值(hh每个h必须是有效的十六进制数) |
注意:这些转义序列字符不一定在所有显示设备上都起作用,如\f和\v在PC屏幕上会生成奇怪的符号,光标不会移动,但是在打印机上输出又会有表格中描述的效果
对于\\,\'和\",它们用于打印\,'和",由于这些字符用于定义字符常量,是printf()函数的一部分,如果直接使用会造成混乱。如果我们要打印"a \ is a backslash." ,我们应该这样编写代码:printf("\"a \\ is a backslash.\"\n");我们再来看一条题:
#include <stdio.h>
#include <string.h>
int main()
{
printf("%d\n", strlen("c:\test\328\test.c"));
return 0;
}
Tip:strlen()是一个计算字符串长度的函数,后面的笔记将详细介绍
编译并运行该程序,输出如下:
14
可以看到结果并不是逐一个字符数的18,而是14,可见该字符串c:\test\328\test应该这样数字符数,c : \t e s t \32 8 \t e s t (8不是有效的八进制数,所以单独算一个字符)
对于最后两个转义序列(\0oo和\xhh)是ASCII码的特殊表示,如:如果编译器不识别‘\a’,我们可以使用ASCII码来代替:char beep = '\007'
③使用十六进制表示字符常量,即反斜杠后面跟一个x或X再加上1~3个十六进制数字。如Ctrl+P的十六进制码是10,可表示为'x10'或'010'
小结:一些整数类型的不同进制形式
类型 | 十六进制 | 八进制 | 十进制 |
char | \x41 | \101 | N.A. |
int | 0x41 | 0101 | 65 |
unsigned int | 0x41u | 0101u | 65u |
long | 0x41L | 0101L | 65L |
unsigned long | 0x41UL | 0101UL | 65UL |
long long | 0x41LL | 0101LL | 65LL |
unsigned long long | 0x41ULL | 0101ULL | 65ULL |
注意:使用ASCII码时,注意数字和数字字符的区别,4是4,‘4’是字符4,其ASCII码是52
4._Bool类型:
_Bool用于表示布尔值,即逻辑值true和false。C语言用1表示true,用0表示false,所以实际上_Bool也是一种整数类型
三.浮点数类型
1.浮点数的了解:
(1)浮点数和数学中的实数的概念差不多
(2)对于一些算术运算(如:两个很大的数相减),浮点数损失的精度更多,因为任何区间内都存在无穷多个实数,计算机的浮点数不能表示区间内的所有值,浮点数通常只是实际值的近似值。如:7.0可能被存储为浮点值6.999999。
(3)过去,浮点运算比整数运算慢。不过,现在许多CPU都包含浮点处理器,缩小了速度上的差距
(4)浮点数的存储和整数不同,计算机把浮点数分成小数部分和指数部分,并且分开存储,后面的笔记将详细讲其存储方式
(5)浮点型常量:在代码中,其书写形式多种多样,其基本形式是:有符号数字(包括小数点,正号可以省略)+e/E+有符号数字(表示10的指数),如:-1.56E+12, 2.87e-3......注意:①可以没有小数点(4e16)或指数部分(3.1415926),但是不能同时省略②可以省略小数部分(3.E5)或整数部分(.45E-6),但是不能同时省略。之后又出了一种新的形式:用十六进制表示浮点型常量,即在十六进制数前加上十六进制的前缀(0x或0X),用p和P分别代替e和E,用2的幂代替10的幂(p计数法),如:0xa.lfp10即为(10+1/16+15/256)*2^10即十进制的10364.0。
数字 | 科学计数法 | 指数计数法 |
322.56 | 3.2256*10^2 | 3.2256e2 |
(6)默认情况下,编译器假定浮点型常量是double类型的精度,所以例如float some;some=4.0*2.0;通常,4.0和2.0被存储为64位的double类型,使用双精度进行乘法运算,然后将乘积截断成float类型的宽度,这样做虽然可以提高精度,但是减慢了程序运行速度。在浮点数后面加上F或f后缀可以覆盖默认设置,编译器会将浮点型常量看作float类型
2.打印浮点值
(1)printf()函数使用%f打印十进制计数法的float和double类型浮点数;用%e打印指数计数法的浮点数。打印long double用%Lf、%Le或%La
(2)%m.nf,指定输出浮点型数据时保留n位小数,且输出宽度为m(包括符号位和小数点)。若实际位数小于m,左端补空格,若大于m,按实际位数输出。如:%5.3f表示该数一共占5个位置,小数部分占3个位置,小数点占1个位置。
3.浮点值的上溢和下溢
(1)浮点值的上溢:当计算导致数字过大时,超出当前类型所能表达的范围时就会发生上溢。C语言规定,此时会给该变量赋一个无穷大的值,并且printf()显示该值为inf或infinity(或者具有无穷含义的其他内容)
(2)浮点值的下溢:在计算过程中损失了原末尾有效位上的数字。C语言把损失了类型全精度的浮点值称为低于正常的浮点值。
浮点数舍入错误:
#include <stdio.h>
int main()
{
float a,b;
b = 2.0e20 + 1.0;
a = b - 2.0e20;
printf("%f\n",a);
return 0;
}
编译运行该程序,不同的系统下,得出的答案不同,反正不是我们想的1,原因是计算机缺少足够的小数位来完成正确的运算。
4.复数和虚数类型:
复数 | 虚数 |
float_Complex | float_Imaginary |
double_Complex | double_Imaginary |
long_Complex | long_Imaginary |
如果包含头文件complex.h,便可用complex代替_Complex,用imaginary代替_Imaginary,用I代替-1的平方根。
四.其他类型
在C语言中,仅有4种基本数据类型--整型,浮点型,指针和聚合类型(如数组和结构等)。后两种类型将在后续笔记详细补充。