一、前言
大家好,欢迎来到C语言深度解析专栏—C语言关键字详解第三篇,在本篇中我们将会介绍C语言当中的数据类型,并由此引出C语言当中的另外一个重要的关键字 — sizeof .
第一篇:C语言 auto和register关键字
第二篇:全面了解C语言 static 关键字
二、数据类型
1、数据类型有哪些
C语言的数据类型包括基本类型(内置类型)、构造类型(自定义类型)、指针类型以及空类型
2、为什么要有数据类型
为什么要有内置类型
我们日常生活中会遇到各种各样的场景,而不同的场景需要不同数据来表示,比如我们聚餐的人数、天气的温度、海拔的高度等事情通常用整数来描述,而像人的身高、广播的频率、商品的价格则通常用小数表示,又比如我们的车牌号、楼栋的命名、服装的尺码则需要要用字母来表示;C语言作为第一门高级程序设计语言,为了能准确描述我们生活中各种各样的场景,就有了整形、浮点型、字符型这些内置类型。
为什么要有自定义类型
我们以自定义类型中的数组类型和结构体类型举例:
数组类型:我们生活中会碰到许多相同类型的集合,比如一个学校学生的学号,每一个学生的学号都是整形,那么为了表示所有学生的学号,就势必要定义几千个整形,显然,那样太麻烦了,于是就产生了数组类型,一个数组里面的每个元素的类型都是相同的,我们在定义一个学校学生的学号时,只需要定义一个有几千个元素大小的数组即可,而不必去慢慢定义一千个整形
结构体类型:我们生活中所要描述的对象常常是复杂数据类型的集合,拿人来说,一个人有姓名、性别、身高、体重、年龄等等,这些数据类型都是不同的,那么为了能够系统的描述一个人的属性,就产生了结构体类型,它把一个人不同类型的数据都集中到一个新的类型当中,使对象描述和使用更加方便。
3、如何看待数据类型
从前面的博客中我们知道,定义变量的本质是在内存中开辟一块空间,用来存放数据,而今天我们知道不同的变量是需要定义为不同的类型的,把二者结合起来,我们就不难得出:类型决定的是变量开辟空间的大小。
这时有两个疑问点,第一、为什么要根据类型来开辟空间,我们直接开辟一块空间,将内存整体使用不好吗?答案是:不好。
原因主要有两点:
1、在任何时刻,你的电脑都不是只在运行你目前所使用的那个程序,还有其他许多的程序也在同时运行,如果把整块都分配给了你目前运行的程序,其他程序就崩溃了。
2、即使把整块内存都分配给你,你也不能保证在任何时刻都对该内存块全部都用完,这样就会导致内存的浪费。
第二、我们使用部分内存,使用多少由什么决定的?答案是:是由你的场景决定,你的计算场景,决定了你使用什么类型的变量进行计算。你所使用的类型,决定了你开辟多少字节的空间大小。这也是为什么C语言要有这么多的数据类型,就是为了满足不同的计算场景。
最后,那么不同的数据类型到底在内存开辟多少空间呢?这就需要使用我们的关键字 – sizeof 来计算了。
三、sizeof – 计算不同类型变量开辟空间的大小
1、内置类型开辟的空间大小
`#includeint main() { printf("%d\n", sizeof(char)); //1 printf("%d\n", sizeof(short)); //2 printf("%d\n", sizeof(int)); //4 printf("%d\n", sizeof(long)); //4 printf("%d\n", sizeof(long long)); //8 printf("%d\n", sizeof(float)); //4 printf("%d\n", sizeof(double)); //8 }`
2、自定义类型开辟的空间大小
数组大小
#includeint main() { int arr1[10] = { 0 }; //40 char arr2[10] = { 0 }; //10 long int arr3[10] = { 0 }; //40 long long arr4[10] = { 0 }; //80 float arr5[10] = { 0 }; //40 double arr6[10] = { 0 }; //80 printf("%d\n", sizeof(arr1)); printf("%d\n", sizeof(arr2)); printf("%d\n", sizeof(arr3)); printf("%d\n", sizeof(arr4)); printf("%d\n", sizeof(arr5)); printf("%d\n", sizeof(arr6)); return 0; }
从上面的结果我们很容易得出:数组的大小 = 数组元素的类型乘以元素个数
其他自定义类型的大小
#includestruct Test1{ int a; char b; float c; double d; }; union Test2{ int m; char n; }; enum Test3 { monday, tuesday, wednesday, thursday, frifay }; int main() { struct Test1 test1 = { 0 }; union Test2 test2 = { 0 }; enum Test3 test3; printf("%d\n", sizeof(test1)); //24 printf("%d\n", sizeof(test2)); //4 printf("%d\n", sizeof(test3)); //4 }
想必上面的结果与一些小伙伴心中的结果有所不同,确实,结构体、联合体、枚举这些自定义类型的大小和数组大小的求法是不相同的,其具体的求法涉及内存对齐、大小端、内存分配等相关知识,这些知识比较复杂,我会放在自定义类型详解模块中为大家讲解,现在大家不用去深究。
3、指针类型开辟的空间大小
大家可以看到,我们上面不管指针的类型是什么(整形、字符型、浮点型、数组型),指针的大小始终是四个字节或者八个字节(第一张图X86表示32位平台,结果为4,第二张图X64表示64位平台,结果为8),所以结论就是:指针在32位平台下是4个字节,在64位平台下是8个字节。(至于为什么是这样,这涉及到内存编址、地址线等相关知识,这一部分我会放在指针那里来详细讲解,现在大家只需要记住这个结论即可)
注:第二张图有警告是因为我的电脑是32位平台的,强制转成64位会发生大小不匹配的问题。
4、空类型开辟的空间大小
我们可以看到虽然这里编译器报错了,但它仍然打印出来了void的大小:0个字节
注:void类型的大小为0个字节,这仅仅是在visual studio这个编译器下运行的结果,但是,这个结果在不同的编环境下跑出来可能不同,就比如在Linux环境下,void类型的大小就为1,(由于水平的限制,这里暂时不能为大家演示);而导致这两者之间有差异的根本原因是不同编译环境对C语言的支持程度不同。
四、对sizeof 的进一步理解
1、sizeof 为什么不是函数
从上面我们可以看到,我们可以用 sizeof(a) 和 sizeof(int) 求一个整形的大小,这种方式也是大家所熟悉的,但是我们发现直接用
sizeof a 也能求出a的大小,而不需要圆括号,所以说,sizeof 是关键字(操作符)但是不是函数,因为函数参数需要用 () 起来才能正常使用。
注:sizeof int 报错是因为 sizeof 和 int 都是关键字,而不能用一个关键字去求另一个关键字的大小
2、sizeof 的其他使用
这里我们定义了一个整型变量 a 和 指针变量 p ,以及数组 arr,可以看到 a 的大小为 4,arr 的大小为40,这些我们都理解,
那么剩下的sizeof § 、sizeof(&arr) 、sizeof(arr) / sizeof(arr[0]) 是什么意思呢?下面为大家解释(涉及指针相关知识)
p 是一个指针变量,里面存放的是 a 的地址,arr数组名表示arr数组首元素的地址(记忆),&arr 表示取出整个数组的地址,相当于一个数组指针,所以sizeof§ 和 sizeof(&arr) 都是求的指针的大小,而在上面我们知道,指针在32位平台下是4个字节,所以这里结果为4。
最后,sizeof(arr) 求整个数组的大小,sizeof(arr[0]) 求第一个元素的大小,所以二者相除得到的是数组的元素个数10。
注:这里用sizeof(arr[0]) 来求一个数组元素的大小,而不是用arr[1] 、arr[2] 是因为我们不知道数组有几个元素,所以可能arr[1] 、arr[2] 根本不存在,但是只要定义了数组,那么arr[0] 就是一定是存在的,也就是说,这样做是为了安全。
到此这篇关于C语言数据类型与sizeof关键字的文章就介绍到这了,更多相关C语言 sizeof关键字内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!