基本数据类型:在C语言中,仅有 4 种基本数据类型(整型、浮点型、指针 和 聚合类型)。
整型一共有 9 种,它们是:
字符型(3种):char ; signed char ; unsigned char 执行sizeof( char ) 、sizeof( signed char ) 和 sizeof( unsigned char ) 的结果都是 1 (字节)
短整型(2种): [ signed ] short int ; unsigned short int 执行sizeof( short int ) 和 sizeof( unsigned short int ) 的结果都是 2 (字节)
整型(2种):[ signed ] int ; unsigned int 执行sizeof( int ) 和 sizeof( unsigned int ) 的结果都是 4 (字节),此处的执行结果还有可能是 2(字节)哦。
长整型(2种):[ signed ] long int ; unsigned long int 执行sizeof( long int ) 和 sizeof( unsigned long int ) 的结果都是 4(字节)
浮点型一共有 3 种,它们是:
单精度:float 执行sizeof( float ) 的结果是 4 (字节)
双精度:double 执行sizeof( double) 的结果是 8 (字节)
扩展精度:long double 执行sizeof( long double ) 的结果是 12(字节)
整型变量的最小范围表(ANSI C 标准):
长整型至少应该和整型一样长,而整型至少应该和短整型一样长。
short int 至少2个字节,long int 至少4个字节,至于缺省的int究竟是2个字节还是4个字节或者是其他值则由编译器设计者决定。这三个值有可能相同。
查看limits.h文件(linux环境下在根目录下输入命令 find -name 'limits.h' 然后用 cat 命令查看该文件的内容 在VC6.0的安装目录下也能搜索到)可以看到字符、短整型、整型和长整型的范围限制的宏定义。S开头代表有符号的类型,U开头的代表无符号的类型。
字符型其实本质上是小整型值,缺省的char要么是signed char,要么是 unsigned char,取决于编译器。只有当程序所使用的char型变量的值位于signed char 和 unsigned char 的交集中,这个程序才是可移植的(就是说不管编译器默认的char是signed char 还是 unsigned char,程序中定义的变量都能得到正确表示,而不会发生溢出)。
整型字面值:字面值(literal)是 字面值常量 的缩写。字面值是一种尸体,指定了自身的值,并且不允许发生改变。
当一个程序内出现整型字面值时,它是属于整型家族9种不同类型中的哪一种呢?
答案取决于字面值是如何书写的。整型字面值的类型默认为 int 或 long,其精度取决于值大小,当其值比 int 大时就是 long 类型,否则就是 int 类型。但通过增加后缀,可以将其强制指定为 long、unsigned 或 unsigned long 类型。通过L或 l 将其指定为 long 类型,通过 U 或 u 将其指定为 unsigned 类型,通过同时加 L 和 U 可以指定为unsigned long类型。字面值、L 和 U三者中任意两者之间不能有空格。定义长整形时,建议使用大写字母L,防止与数字1混淆。
在源代码中,用于表示整型字面值的方法很多,可以用十进制、八进制或十六进制。十进制最为自然,当在数值前加数字0 ,即为八进制表示,八进制表示中不能出现数字 8 和 9 。当在数值前加0x ,即为十六进制表示,可以使用 ABCDEF 或 abcdef 。八进制和十六进制字面值可能的类型是 int 、unsigned int 、long 或 unsigned long 。在缺省的情况下,字面值的类型就是上述类型中最短但是足以容纳整个值的类型。
浮点数字面值在缺省情况下都是double类型的,除非它的后面跟一个 L 或 l 表示它是一个long double 类型的值,或者跟一个 F 或 f 表示它是一个float 类型的值。
如果一个多字节字符常量的前面有一个 L ,那么它就是宽字符常量(wide character literal),如: L'X' L'e^' 。不准在字符字面值后面添加 U 或 L 。
枚举类型:枚举类型(enumerated)就是指它的值为符号常量而不是字面值的类型。
枚举类型的原型声明形式为:
形式1:
enum 枚举类型名称(tag){ 字段1 , 字段2 , 字段3 , ... ... };
enum 枚举类型名称(tag) 变量1 , 变量2 , 变量3 , ... ... ;
形式2:
enum 枚举类型名称(tag){ 字段1 , 字段2 , 字段3 , ... ... }变量1 , 变量2 , 变量3 , ... ... ;
这种类型的变量实际上以整型的方式存储,并且规定:字段1 , 字段2 , 字段3 , ... ... 的值为:0 , 1 , 2 ... ...
也可以显示指定这些字段的值,如:
enum 枚举类型名称(tag){ 字段1=2 , 字段2=8 , 字段3=1 , ... ... }; //每个字段都指定
enum 枚举类型名称(tag){ 字段1 , 字段2 =5, 字段3 , ... ... }; //指定部分字段,结果为:字段1=0 字段3 =6 若前一个制定了后一个就比前一个大 1 。
浮点型:包括单精度、双精度 和 扩展精度。ANSI 标准仅仅规定 long double 至少和 double 一样长,而 double 至少和 float 一样长。 标准同时规定了一个最小范围:所有浮点类型至少能容纳从10^(-37) 到 10^37 之间的任何值。头文件 float.h 中定义了存储范围的宏和一些和浮点值的实现有关的某些特性的名字。
浮点数字面值总是写成十进制的形式,它必须有一个小数点 或 一个指数,也可以两者都有。
字符串常量和指针:你可以把字符串常量赋值给一个“指向字符的指针”,但你不能把字符串常量赋值给一个字符数组,因为字符串常量的直接值是一个指针,而不是这些字符本身。
char* str="hello"; //正确,这条语句把str声明为一个指向字符的指针,并用字符串常量中第1个字符的地址对该指针进行初始化。
上面这条语句其实应该这样写:char* str ; str = “ hello ” ; //这样更好说明,因为 “hello” 的直接值是一个指针,str 也是一个指针。
char s[ ] = "hello"; //错误
数组:C 数组中一个值得关注的地方是,编译器并不检查程序对数组下标的引用是否在数组的合法范围之内。
我们的应对措施是:如果下标值是从那些已知是正确的值计算得来,那么就无需检查它的值。如果一个用作下标的值是根据某种方法从用户输入的数据产生而来的,那么在使用它之前必须进行检测,确保这些值位于有效的范围之内。
隐式声明:虽然不提倡使用隐式声明,但我们有必要知道这些细节。函数如果不显示地声明返回值的类型,它就默认返回整型。如果编译器可以得到充足的信息,推断出一条语句实际上是一个声明时,如果它缺少类型名,编译器会假定它为整型。
int a[10];
int c;
b[10];
d;
f( x )
{
return x+1;
}
前两行很寻常,第 3 和第 4 行在ANSI C 中是非法的,在K&R编译器中却可能是合法的。 函数 f 缺少返回类型,于是编译器就默认它返回整型。参数 x 也没有类型名,同样被默认为整型。
typedef:允许我们为各种数据类型定义新名字。例如:
char *ptr_to_char; //把 ptr_to_char 声明为一个指向字符的指针
typedef char *ptr_to_char; //把标示符ptr_to_char 作为指向字符的指针类型的姓名字
我们可以这样使用它:
ptr_to_char a; //声明a是一个指向字符的指针
我们应该使用typedef而不是#define来创建新的类型名,因为后者无法正确的处理指针类型。例如:
#define d_ptr_to_char char *
d_ptr_to_char a , b;
正确的声明了a,但是b却被声明为一个字符。
常量:常量的值不允许被修改。使用const关键字来声明常量。如:
int const a=10; //或:
const int a=10;
因为常量的值不允许被修改,所以需要我们在声明的时候就将其初始化。
还有一种给常量初始化的方法就是:在函数中声明为const的形参在函数被调用时会得到实参的值。
三种比较重要的常量:
int const *pci;//指向 常量 的 指针
int *const cpi;//指向 变量 的 常指针
int const *const cpci;//指向 常量 的 常指针
区分这三种常量的方法即以 *为分界线,* 以前有const 则为指针所指的目标为常量, * 以后有const 则指针为常指针。
#define指令是另一种创建名字常量的机制。如:#define MAX_LENGTH 100
当然也可以const关键字来实现,即:int const max_length=100;
但是像这种情况下,建议使用#define