1基本数据类型
数据类型分为2类:基本数据类型、复合类型
基本类型:char、short、int、long、float、double
复合类型:数组、结构体、共用体、类(C无类,C++有)
1.1内存占用与sizeof运算符
数据类型就好像一个一个的模子,这个模子实例化出C语言的变量。变量存储在内存中,需要占用一定的内存空间。一个变量占用多少空间是由变量的数据类型决定的。
每种数据类型,在不同的机器平台上占用内存是不同的,我们一般讲的时候都是以32位CPU为默认硬件平台来描述:
数据类型 | 占用字节 |
---|---|
char | 1字节 |
short | 2字节 |
int | 4字节 |
long | 4字节 |
float | 4字节 |
double | 8字节 |
1.2有符号数与无符号数
对于char、short、int、long等整型类型的数,都分有符号数和无符号数。而对于float与double这种浮点型数来说,只有有符号数,没有无符号数。
对于C语言来说,数(也就是变量)是存储在内存中一个一个的格子中的,存储的时候是以二进制方式存储的。对于有符号数和无符号数来说,存储方式是不同的。
如对于int来说,unsigned int无符号数32位(4字节)全部用来存储数的内容,范围是0~4294967295(2^32-1);signed int有符号数,32位中最高位用来存储符号(0表示正数,1表示负数),剩余31位用来存储数据,所以可以表示的数范围
-2147483648~2147483647(2^31-1)
总结:
从绝对数值来说,无符号数所表示的范围要大一些,因为有符号数使用1个二进制来表示正负号。
1.3整型数和浮点数型数存储方式上的不同
对于float和double这种浮点类型的数,它在内存中的存储方式和整型数不一样。所以float和int相比,虽然都是4字节,但是在内存中存储的方式不同,所以同一个4字节的内存,如果存储时是按照int存放的,取得时候一定要按照int型方式去取。如果存的时候和取的时候理解的方式不同,那数据就完全错了。(好比你把人家当恋人,人家却把你当朋友。)
总结:
存储方式主要有两种:一种是整型,一种是浮点型。
这两种存取方式完全不同,没有任何关联,所以绝对不能随意改变一个变量的存取方式,在整型与浮点型之间,如说4中整型char、short、int、long只是范围大小不同而已,存储方式是一摸一样的。float和double存储原理是相同的,方式上有差异,导致了能表示的浮点型的范围和精度不同。
2空类型(关键字void)
(1)C语言中的void类型,代表任意类型,而不是空的意思。任意类型的意思不是说想变成谁就变成谁,而是说它的类型是未知的,是还没指定的。
(2)在函数参数列表和返回值中,void代表的含义是:一个函数形参列表为void,表示这个函数调用时不需要给它传参。返回值类型是void,表示这个函数不会返回一个有意义的返回值,所以调用者也不要想着去使用该返回值。(其实C语言都是有返回值,只不过因void不管了)
(3)void *是void类型的指针。void类型的指针的含义是:这是一个指针变量,该指针指向一个void类型的数。void类型的数就是说这个数有可能是int,也有可能是float,也有可能是个结构体,哪种类型都有可能,只是我当前无法确定。
void类型指针的作用就是,程序不知道那个变量的类型,但是程序员自己心里知道。程序员如何知道?当时这个变量赋值的时候是什么类型,现在取的时候就是什么类型。这些类型对不对,能否兼容,完全由程序员自己负责。编译器看到void就没办法帮你做类型检查了。
代码参考
int main(void)
{
int a = 444;
void *pVoid;
pVoid = &a;
//printf("*pVoid = %d.\n", *pVoid);
printf("*pVoid = %d.\n", *(int *)pVoid);
return 0;
}
注释句:直接这样写不太好,因为没有告诉printf是以char、short、int、long的哪种类型去取值,虽然内存中存的都是0和1,但是取的方式不同,结构就不同。
执行句:所以最好先将指针变量强制类型转换成int类型,然后再去取数据,这时候就会根据int型4字节4字节的方式读取内存中的0和1的值,从而正确解析。
(4)C语言设计的基本理念:
C语言相信程序员永远是对的;C语言相信程序员都是高手;C语言赋予程序员最大的权力。所以C语言的程序员必须自己对程序的对错负责,必须随时闹到清楚自己在干嘛。这也是黑客最喜欢的语言。
3数据类型转换
C语言中有各种数据类型,写程序时需要定义各种类型的变量。这些类型需要参与运算。C语言有一个基本要求就是:不同类型的变量不能直接运算。也就是说,int和float类型的变量不能直接加减等运算,必须先把两种类型转换成相同的类型才可以。比如简单的6+6.5。
隐式转换
隐式转换就是自动转换,是C语言默认会进行的,不用程序员干涉。C语言的转换理念:隐式转换默认朝精度更高、范围更大的方向转换。所以隐式转换不会出现错误,只会出现精度问题。
代码分析1:
int main(void)
{
int a = 3;
float b = 3.5;
printf("a+b=%f.\n", a+b); //6.500000
printf("a+b=%d.\n", a+b); //0
printf("a+b=%d.\n", (int)(a+b)); //6
printf("a=%d.\n", a); //3
return 0;
}
逐步分析:
(1)编译器发现a+b中a和b的类型不同。这时候两个要加,编译器会进行隐式转换把两个转成类型相同。根据隐式类型转换的规则,编译器构造了一个临时变量(如叫float f1),然后把f1赋值为a转换成float类型的值,但是本身的a还是int类型,不可能经历一次相加操作就把本质都变了。
(2)之后参与运算时用f1和b相加,加完后得到一个临时变量(如叫float f2),f2=f1+b,这个临时变量再参与之后的运算。
(3)题目中printf("a+b=%f.\n", a+b); printf中是%f,所以需要一个float类型的变量来打印。于是,f2直接拿去打印显示,得到结果6.500000
代码分析2:
//接着分析1的a、b
int c;
c = a + b;
printf("c=%d.\n", c);
结果等于:6
逐步分析:
(1)编译器发现a和b类型不同,于是隐式类型转换,将a转成float类型的临时变量f1;
(2)f1+b,得到一个临时变量f2,值为float类型的6.500000;
(3)c = f2,编译器发现c和f2的类型不相同,但是赋值时必须以等号=左边的类型为准,于是编译器隐式类型转换,将f2转成临时变量i,值为6,然后再将i赋值给c;
(4)printf打印时发现%d,右边的变量c类型为int,编译器检查发现类型匹配,直接打印。
强制类型转换
C语言默认不会这么做,但是程序员我想这么做,所以我强制这么做了。
4C语言与bool类型
C语言中原生类型没有bool类型,C++中有。在C语言中如果需要使用bool类型,可以用int来代替。很多代码体系中,用以下宏定义来定义真与假。
#define TRUE 1
#define FALSE 0
//除了0为假,其余(正负数)都为真。
网友评论