C语言数据类型

大家好,我们今天来讲数据结构了

数据类型介绍

什么是数据类型呢?

在我们生活中就有很多的类型,只是我们或许没关注,比如:

  1. 你的体重是65.5公斤,你的体重是185.5cm。
  2. 你买一打达12个鸡蛋,买了10个苹果。
  3. 你的名字是张三,你家住在xxx公寓。

第一行都是小数,第二行都是整数,第三行都是字符或字符串,而C语言中就使用整型类型来描述整数,使用字符类型来描述字符,使用浮点型类型来描述小数。

那C语言要为什么要创建数据类型呢

“类型”实际上就是相似的数据所拥有的共同特征,编译器只有知道了数据的类型,才知道怎么操作。

数据类型分类

在这里插入图片描述

而今天我们主要讲内置类型

字符型

字符的英文单词是 character ,在C语言中使用char表示字符类型。
细分有:

char
[signed] char
unsigned char

整型

整数的英文单词是 integer ,在C语言中使用int 表示整型类型。
细分有:

//短整型
short [int]
[signed] short [int]
unsigned short [int]
//整型
int
[signed] int
unsigned int
//长整型
long [int]
[signed] long [int]
unsigned long [int]
//更长的整型
//C99中引入
long long [int]
[signed] long long [int]
unsigned long long [int]

其中unsigned表示无符号,signed表示有符号。
其中[unsigned]表示unsigned可以去掉,因为C语言中int默认是有符号的,
但是上面的char,C语言官方并没有明确规定char就是有符号的,只是在vs2022中的64底下是默认为有符号的,但在其他系统中就不一定了,可能是默认为无符号的(这一点要注意)。
C语言中默认unsigned int与unsigned是一个东西,以此类推long int与long也一样,当然只有一个int时,自然不能省略。

浮点型

细分有:

float//单精度浮点型
double//双单精度浮点型
long double//高单精度浮点型

浮点型化为二进制的方式特别,所以仅支持有符号浮点型。

布尔类型

C 语言原来并没有为布尔值单独设置⼀个类型,而是使用整数 0 表示假,非零值表示真。
而在在 C99 中引入了布尔类型 ,是专门表示真假的。

_Bool就是布尔类型
布尔类型的用得包含头文件 <stdbool.h>
布尔类型变量的取值是: true 或者 false 。

怎么用呢?

#include<stdio.h>
#include<stdbool.h>
int main()
{
_Bool flag = true;
if (flag)
printf("i like C\n");//会打印,true是真的意思
flag =false;
if(flag)
{
printf("i like not C\n");//不会打印,flase是假的意思
}
return 0;
}

前面说了是C99中引入的布尔类型,那之前怎么判断真假呢?

#include<stdio.h>
int main()
{
int flag=1;
if (flag)
printf("i like C\n");//会打印,C语言中用非0表示真
flag=0;
if(flag)
{
printf("i like not C\n");//不会打印,C语言中用0表示假
}
return 0;
}

看到了布尔类型_Bool和使用它要包含的头文件#include<bool.h>,你可能会想_Bool在实际操作中并不好用,这怎么办呢?
这个时候,C语言就用#define bool _Bool(define是定义的意思),
它的意思是,定义bool的意思是_Bool,在编译阶段会将所有的bool替换成_Bool,(换句话说就是布尔类型的本质就是_Bool,但是在实际编译过程中也可以用bool表示,并且更加方便)
同理也有:
#define true 1
#define false 0

各种数据类型的长度

sizeof的使用

  • sizeof 是⼀个关键字,也是操作符,专门是用来计算 sizeof 的操作符数的类型长度的,单位是字节。
  • sizeof 操作符的操作数可以是类型,也可是变量或者表达式。
  • sizeof 的操作数如果不是类型,是表达式的时候,可以省略掉后边的括号的。

sizeof(类型)
sizeof 表达式//最好不要省略,可能会造成结果并非所愿

第二点举个例子

#include<stdio.h>
int main()
{
int a=10;
int b=20;
int r=sizeof(a+b); //t为4
int t=sizeof a+b;//t为24,因为省略了(),所以编译系统认为sizeofa是一起的,得不到想要的结果
int c=sizeof a;//不用加括号的正确用法、
printf("%zd\n%zd\n%zd",r,t,c);
return 0;
}

这是vs2022运行的结果,有的编译器可能第二个通过不了编译。
在这里插入图片描述

  • sizeof 后边的表达式是不真实参与运算的,根据表达式的类型来得出大小。
  • sizeof 的计算结果是 size_t 类型的。

sizeof 运算符的返回值,C 语言只规定是无符号整数,并没有规定具体的类型,而是留给系统自己去决定, sizeof 到底返回什么类型。不同的系统中,返回值的类型有可能是unsigned int ,也有可能是 unsigned long ,甚至是 unsigned long long ,对应的 printf() 占位符分别是 %u 、 %lu 和 %llu 。这样不利于程序的可移植性。
C 语言提供了⼀个解决方法,创造了⼀个类型别名 size_t ,用来统⼀表示sizeof 的返回值类型。对应当前系统的 sizeof 的返回值类型,可能是 unsigned int ,unsigned long,也可能是
unsigned long long ,而其对应的占位符是%zd(也是C语言为此创造的)。

特别说明一下前面的博客说到了ASCII值,char底层放的就是ASCII值,所以可以认为字符型也是整型家族的

用sizeof计算各种数据类型的长度

在VS2022 X64配置下的输出:

#include <stdio.h>
int main()
{
printf("%zd\n", sizeof(char));//1
printf("%zd\n", sizeof(_Bool));//1
printf("%zd\n", sizeof(short));//2
printf("%zd\n", sizeof(int));//4
printf("%zd\n", sizeof(long));//4
printf("%zd\n", sizeof(long long));//8
printf("%zd\n", sizeof(float));//4
printf("%zd\n", sizeof(double));//8
printf("%zd\n", sizeof(long double));//在vs上是8个字节,在gcc上测试是16
return 0;
}

诶,你可能会问为什么int是4个字节,long也是4的字节呢?为什么是一样的?
因为在C语言规定中要求long的长度>=int的长度,所以这里就有了操作空间了。
C语言官方介绍的长度:
在这里插入图片描述
诶,你可能会问,这个小格子是什么啊,实际上他们是bit(比特)(位)(比特位),八个bit(位)组成一个byte(字节)。
那bit是什么啊?
在计算系统中只能识别二进制的信息,所以,一个bit中就存放了0/1的数,八个0/1的数放在一起,构成了一个字节。

sizeof中表达式不计算

//测试:sizeof中表达式不计算
#include <stdio.h>
int main()
{
short s = 2;
int b = 10;
printf("%d\n", sizeof(s = b+1));
printf("s = %hd\n", s);
return 0;
}

涉及到一个知识点,就是说
整型要赋值给短整型,就是低人一等,相当于求人办事,所以整型就会截断,从4个字节截断为2个字节,再赋值给s,当然这里的赋值啊,什么的都是编译系统推理出来的,什么意思呢?

sizeof 在代码进行编译的时候,就根据表达式结果的类型,推导并确定了类型的长度,而表达式真要被执行,是要在程序运行期间才会发生,因为在编译期间已经将 sizeof 处理掉了,所以在运行期间就不会执行表达式了。

所以打印的都是2了,你算对了吗?

unsigned与signed

前面讲到char的时候,讲到了一些,现在详细讲解一下。

  • C 语言使用signed和unsigned 关键字修饰字符型和整型类型的。
  • signed这个关键字表示有符号,表示⼀个类型带有正负号,包含负数。
  • unsigned这个关键字表示无符号,表示⼀个类型不带有正负号,只包含0和正整数。
  • 对于 int 类型,默认是带有正负号的,也就是说 int 等同于 signed int 。
    由于这是默认情况,关键字 signed 一般都省略不写,但是写了也不算错。

signed int //等同于int
unsigned int//想要只表示非负整数只能这样写

同理char也一样。

unsigned的好处

你可能会有疑惑,为什么[signed]int就可以表示非负整数,那为什么还要创建unsigned这个关键词呢? 好像是多此一举,但实际上不是的,拿整型举例:

  • 整数变量声明为unsigned的好处是,同样长度的内存能够表示的最大整数值,增大了一倍。

比如,16位的 signed short int 的取值范围是:-32768~32767,最大是32767;而
unsigned short int 的取值范围是:0~65535,最大值增大到了65535。

这时又有一个问题怎么就算出了这些数字呢?
前面我们提到了一个bit(比特)存放的是0/1的数,一个byte(字节)存放的八个bit。
那这一个字节可以放多少的数呢?
怎么放的呢?

  • 类比一下1,10,100,11,是不是可以写成1:1*10^0
    10:1*10^1
    100:1*10^2
    11:1*10^0+1*10^1。

为什么?
我们小学就知道了各个位数最大是9,碰到10就进一。

同样的我们的二进制各个位数最大是1,碰到2就进一,所以二进制00000111就可以写成1*2^0+1*2^1+1*2^2。所以这个数就是1+2+4=7。

这个了解以后,再简单说一下一个知识点,

  • [signed] int有4个字节,要表示正整数,0,负整数,怎么表示负整数呢,就是定义最高位为符号位,为0表示正,为1表示负。

那么回到最初的问题上来,所以说[signed]int看起来和unsigned int都是16位的,但是因为[signed]int要存储负数,所以最高位用0/1表示用正/负。所以存储整数只有15位了。

那为什么16位的 signed short int 的取值范围是:-32768~32767,其中最大值和最小值的绝对值不一样呢?

  • 那是因为在最高位是0的时候,有一个16位全0来表示0,所以右边是0~32767(可以表示32768个数),左边是-32768~-1(可以表示32768个数),实际上俩边可以表示的数的数量是一样的。

怎么表示这个最大的数32767呢?

  • 就是最高位为0,其余为1,怎么表示最小数-32768呢?,最高位为1,其余为0(后面的博客会讲到,这个实际上是官方规定的,因为如果不这样规定这个数就表示-0,而-0在数学上和0重复了,那么就直接规定了这个数就是最小值-32768,其他的比如1,4,8个字节可以表示的最小值都是这样的,同理的)

数据类型的取值范围

我们在以后的编程中可能会用到一个数据的极限范围,那我们肯定记不下来,也不用记下来,C语言规定了几个常量表示这个极限值,那怎么在用的时候可以快速找到它们呢?用Everything,直接在浏览器上下载(免费的)

如何使用Everything查找类型范围

limits.h 文件中说明了整型类型的取值范围。
float.h 这个头文件中说明浮点型类型的取值范围。
limits.h
在这里插入图片描述

在这里插入图片描述
讲一下几个,比如:

#define CHAR_BIT 8//它的小写是char_bit(望文生义)
#define SCHAR_MIN (-128)//它的小写是schar_min,是signed char_min的缩写
#define UCHAR_MAX 0xff//0xff是16进制,表示255,它小写是uchar_max,是unsigned char_max的缩写
其他的也多是小写是可以明白意思的,有的也缩写了,比如SHRT_MAX是short_max

再来个float.h
在这里插入图片描述
当前阶段,只要明白
#define DBL_MAX这种类型表示什么意思即可,其他的不用管。

当要使用这种极限值时,只要记下这个特别的符号就特别方便找到了极限值,这个记忆非常容易,因为望文生义,当然忘记了,也可以按上述的方法查找。

总结:

谢谢观看!

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值