数据类型
第一讲中提到一个词语叫返回类型,其中的类型在C语言中有很多的分类,用来描述生活中的各种数据。
C语⾔提供了丰富的数据类型来描述⽣活中的各种数据。 使⽤整型类型来描述整数,使⽤字符类型来描述字符,使⽤浮点型类型来描述⼩数。
所谓“类型”,就是相似的数据所拥有的共同特征,编译器只有知道了数据的类型,才知道怎么操作 数据。
下⾯盘点⼀下C语⾔提供的各种数据类型。
字符型
1 char
2 [signed] char
3 unsigned char
整形
1 //短整型
2 short [int]
3 [signed] short [int]
4 unsigned short [int]
5
6 //整型
7 int
8 [signed] int
9 unsigned int
10
11 //长整型
12 long [int]
13 [signed] long [int]
14 unsigned long [int]
15
16 //更长的整型
17 //C99标准中引入
18 long long [int]
19 [signed] long long [int]
20 unsigned long long [int]
浮点型
1 float
2 double
3 long double
布尔型
在C语言中,C99标准以前并没有为布尔值设置专门的类型,而是使用整数0标示布尔值假,非零则标示布尔值的真。
在C99标准以后,引入了布尔类型,专门标示真假。
1 _Bool
和其他的类型不同,布尔类型的使用需要引入头文件<stdbool.h>才可以使用。否则会引起报错。
布尔类型变量的取值是:true或者flase。
我们在VS中定义一个布尔类型的变量,然后左键选取bool类型名称,右键点击这个类型,选取转到定义这个选项中,如下所示:
#define bool _Bool
#define false 0
#define true 1
从上面的代码中我们看出, false被定义为0 , true被定义为1。这和刚才我们所说的C语言中0为假,非零为真基本吻合。
代码演示:
#include <stdbool.h>
#include <stdio.h>
int main()
{
bool a = true;
bool b = false;
if (a)
{
printf("真");
}
if (b)
{
printf("假");
}
return 0;
}
演示效果:
数据类型的长度
每⼀种数据类型都有⾃⼰的⻓度,不同的数据类型,所创建出的变量⻓度不同,存储的数据范围就有所差异。这里的长度代表的则是这个变量在内存中所占用的空间,单位为字节。
sizeof操作符
sizeof是一个关键字,同时他还是一个操作符,专门用来计算数的类型长度的。
sizeof操作符的操作数可以是类型,也可以是变量或者表达式。
1 sizeof(类型)
2 sizeof 表达式
sizeof的操作数如果不是类型,是表达式的时候,可以省略后边的括号的。
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 long 。
int main()
{
int a = 0;
printf("%zu\n", sizeof(a));
printf("%zu\n", sizeof a);
printf("%zu\n", sizeof(int));
printf("%zu\n", sizeof (3.5+6));
return 0;
}
运行结果如下:
数据类型长度
#include <stdio.h>
int main()
{
printf("%zu\n", sizeof(char));
printf("%zu\n", sizeof(bool));
printf("%zu\n", sizeof(short));
printf("%zu\n", sizeof(int));
printf("%zu\n", sizeof(long));
printf("%zu\n", sizeof(long long));
printf("%zu\n", sizeof(float));
printf("%zu\n", sizeof(double));
printf("%zu\n", sizeof(long double));
return 0;
}
在X64中输出结果如下:
对应数值如下所示:
下面代码是为了验证sizeof是不计算其中的表达式:
//测试:sizeof中表达式不计算
#include <stdio.h>
int main()
{
short a = 2;
int x = 10;
printf("%zd\n", sizeof(a = x + 3));
printf("a =%zd\n", a);
return 0;
}
输出结果为:
我们已知short类型的值长度为2,int类型的长度为4,a在sizeof中如果计算的话应被重新赋值为13,但是第一个输出的值却为2,这个2就是short类型长度。sizeof在代码进行编译的时候,就已经根据表达式的类型决定了其值的大小,而表达式的执行是要在程序运行中才会执行,在编译期间已经被sizeof处理掉了,所以在运行期间就不会执行表达式了。
signed 和 unsigned
在C语言中,signed和unsigned关键字用来修饰字符型和整型类型的。
signed 关键字,表⽰⼀个类型带有正负号,包含负值,一般在定义整型变量时,该关键字基本省略,所以在使用short、int、long、long long默认是带有符号类型变量,即可表达数值的正负数。例如 signed int a 等同于 int a;;
unsigned关键字,表⽰该类型不带有正负号,只能表⽰零和正整数,该关键字是不能省略的。
用unsigned的好处是,其定义的变量最大值比 signed定义的变量大了一倍,至于为什么大于一倍,我们在后面会有介绍。
⽐如,16位的 signed short int 的取值范围是:-32768~32767,最⼤是32767;⽽ unsigned short int 的取值范围是:0~65535,最⼤值增⼤到了65,535。32位的 signed int 的取值范围可以参看 limits.h 中给出的定义。
字符类型 char 也可以设置 signed 和 unsigned 。
1 signd char c; // 范围为 -128 到 127
2 unsigned char c; // 范围为 0 到 255
注意,C 语⾔规定 char 类型默认是否带有正负号,由当前系统决定。
这就是说, char 不等同于 signed char ,它有可能是 signed char ,也有可能是 unsigned char 。
这⼀点与 int 不同, int 就是等同于 signed int。
数据类型的取值范围
上述的数据类型很多,尤其数整型类型就有short、int、long、long long 四种,为什么呢?
其实每⼀种数据类型有⾃⼰的取值范围,也就是存储的数值的最⼤值和最⼩值的区间,有了丰富的类 型,我们就可以在适当的场景下去选择适合的类型。
如果要查看当前系统上不同数据类型的极限值:
• limits.h ⽂件中说明了整型类型的取值范围。
• float.h 这个头⽂件中说明浮点型类型的取值范围。
为了代码的可移植性,需要知道某种整数类型的极限值时,应该尽量使⽤这些常量。 • SCHAR_MIN , SCHAR_MAX :signed char 的最⼩值和最⼤值。
• SHRT_MIN , SHRT_MAX :short 的最⼩值和最⼤值。
• INT_MIN , INT_MAX :int 的最⼩值和最⼤值。 • LONG_MIN , LONG_MAX :long 的最⼩值和最⼤值。
• LLONG_MIN , LLONG_MAX :long long 的最⼩值和最⼤值。
• UCHAR_MAX :unsigned char 的最⼤值。
• USHRT_MAX :unsigned short 的最⼤值。
• UINT_MAX :unsigned int 的最⼤值。
• ULONG_MAX :unsigned long 的最⼤值。
• ULLONG_MAX :unsigned long long 的最⼤值。
变量
变量的创建
上面讲了那么多关于类型的介绍,还有数据的各种分类,是用来做什么的呢?它是用来创建变量的。
我们前面也提到了很多次变量,什么是变量呢?在C语言中,经常变化的值被称为变量,固定不变的值被称为常量。
变量创建的语法形式是这样的:
下图示例:
int a;
short b;
float c;
double d;
我们平常定义变量时是不会这样简单的定义一下就完了,因为这样可能会发生灾难性的问题,如下图:
int a = 0;
short b = 0;
float c = 0.0f;
double d = 0.0lf;
变量在创建时要给予一个初始值,这就是常说的初始化。如上示例中, a被定义为int类型的整型变量,单个=号在C语言中被叫做赋值符号,a被赋予0的初始值。
而变量c和变量d后面添加的f和lf,是定义浮点数时候用到的。如果我们不给与一个初始值,那么变量里面存储的数值将会是个随机值,那么此时在没有赋值的情况下去调用这个变量,后果是不可预计的!
变量的分类
变量分为全局变量和局部变量。
• 全局变量:在大括号外部定义的变量就是全局变量
全局变量的使用范围更广,整个工程中想使用,都是有办法使用的。
• 局部变量:在大括号内部定义的变量就是局部变量
局部变量的使用范围是比较局限,只能在自己所在的局部范围内使用的。
#include <stdio.h>
int glocal = 13;
int main()
{
int local = 14;
printf("%d\n", glocal);
printf("%d\n", local);
return 0;
}
上面代码中我们看到, glocal变量是在main()函数外定义的,可是在main()函数中任然能够正常使用。如果全局变量和局部变量的命名一样会发生什么呢?我们对上面代码做一下修改:
#include <stdio.h>
int local = 13;
int main()
{
int local = 14;
printf("%d\n", local);
return 0;
}
代码修改后,运行发现,虽然名称同样的,但是它并没有报错,而且还正常运行了,其值是main()函数中赋予的值。
其实当局部变量和全局变量同名的时候,局部变量优先使用。
全局变量和局部变量在内存中存储在哪里呢?
⼀般我们在学习C/C++语⾔的时候,我们会关注 内存中的三个区域:栈区、堆区、静态区。
1. 局部变量是放在内存的栈区
2. 全局变量是放在内存的静态区
3. 堆区是⽤来动态内存管理的(后期会介绍)
其实内存区域的划分会更加细致,以后在操作系 统的相关知识的时候会介绍。
局部变量和函数参数是存放在栈区的,这部分数据在调用完成以后将会自动销毁,而静态区里面的全局变量和静态变量,只有在程序停止或退出运行的时候才会销毁。
本博客只为学习使用,如有错误请大家指出,感谢!