数据类型介绍
在C语言中分为内置数据类型和自定义数据类型,这次介绍的是内置数据类型。
内置数据类型分为:整型类型、浮点型类型、字符类型和布尔类型。
使用整型来描述整数,字符类型描述字符,浮点型描述小数。
类型:相似的数据拥有共同的特征,编译器只有知道了数据类型,才能知道怎么操作数据。
按照顺序,上面介绍类型的种类顺序,来讲解数据类型,我们从整型来介绍。
整型类型
整型就是十进制的整数,整型分为:整型、短整型、长整型和更长的整型。
//短整型
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
其中[ ]中数是可以省略的 ,比如short [ int ] , 我们可以写成short。
例子:
使用int类型创建一个变量,那么变量的数据类型就是整型。
#include <stdio.h>
int main()
{
int a = 0;
return 0;
}
上述我们打印的a为变量,而变量的数据就是整型类型(int) , 打印整型类型的变量,我们则需要用到 %d,%d是整型的打印格式,C语言中也叫占位符,这个本篇中不多叙述,读者朋友现在知道%d叫占位符就好。
而不同的数据类型 , 也需要用到不同的占位符去打印 。
浮点型类型
C语言中浮点型,简单来说就是小数。
浮点型分为 float 和 double 两种。
一般我们默认创建的浮点型就是double类型的。
float //单精度浮点型
double //双精度浮点型
long double
例子:
#include <stdio.h>
int main()
{
float a = 12.1;
double b = 13.1;
printf("%f\n", a);
printf("%lf", b);
return 0;
}
为什么打印出来的会是“12.100000” 和 “13.100000”?上述打印int类型的时候,我们创建的变量赋值为0,打印出来的变量就是0,而浮点型的打印却和我们赋值给a和b的值不同?
我们知道float和double是浮点型,是带小数点的,因为浮点数小数点默认有后六位的数,我们打印任何数,编译器打印出来的数都是小数点有6位数。
比如:
#include <stdio.h>
int main()
{
float a = 9.1;
double b = 10.1;
printf("%f\n", a);
printf("%lf\n", b);
return 0;
}
这次随着数的变化,打印的数也随着变化了 , 小数点后面还是会有6位数。
那么我们可不可以省略掉多余的数,只打印我们想打印的值呢?,是可以的 ,小数点后的数是可以限定的的,比如我们打印12.34,只让他打印出12.34,其余后4位省略掉。
我们只需要在打印格式%f的中间加上一个 .2.
#include <stdio.h>
int main()
{
float a = 12.34;
printf("%.2f\n", a);
return 0;
}
上述我们也说过浮点型分为:float和double,那么他们的打印格式也是不一样的,例子中我们打印用到了 %f 和 %lf ,其中 %f是打印float类型的,%lf则打印double类型
字符类型
char
[signed] int
unsigned int
字符类型我们分为: 字符类型 和 字符串类型。
我们区分字符类型和字符串类型 , 单引号内的是字符类型 ,双引号内的是字符串类型。
#include <stdio.h>
int main()
{
char arr1[] = "abcdef";
char arr2[] = {'a', 'b', 'c', 'd', 'e', 'f'};
printf("%s\n", arr1);
printf("%s\n", arr2);
return 0;
}
字符串末尾默认有一个\0,而\0是字符串的结束标志 ,遇\0字符串就结束打印 ,但\0是隐藏在字符串的末尾的的。
%s是打印字符串的,遇到\0就停止打印。
字符中是没有\0的,如果你不手动配置上给\0的话,字符中是不会有\0的。
而有\0和没有\0打印的区别是什么?
当字符中没有\0 ,是会一直打印下去的,直到遇到\0就停止打印,而遇到\0之前会打印什么,我们是不得而知的 , 会打印一些随机值。
当我们在字符类型的后面手动添加上\0。
#include <stdio.h>
int main()
{
char arr1[] = "abcdef";
char arr2[] = {'a', 'b', 'c', 'd', 'e', 'f','\0'};
printf("%s\n", arr1);
printf("%s\n", arr2);
return 0;
}
我们说%s遇到\0就停止打印,真的是这样吗,我们用一段代码来示范一下。
#include <stdio.h>
int main()
{
char arr[] = "abcd\0ef";
printf("%s", arr);
return 0;
}
我要求的是打印abcdef ,而值输出了abcd , 也由此证明,在%s中只要遇到\0就停止打印。
布尔类型
C语言中原本是没有布尔类型的,也没有为布尔类型单独设置一个类型,而是使用整数.0表示假,非零表示真,布尔类型是C99标准引入的布尔类型后,专门用来表示真假。
_Bool
要使用布尔类型要包含头文件: <stdbool.h>
布尔类型的变量的取值是:true或false , true表示真 , false表示假
a为真打印haha,为假什么都不打印。
#include <stdio.h>
#include <stdbool.h>
int main()
{
_Bool a = true;
if (a)
{
printf("haha");
}
return 0;
}
为真打印,为假则不打印。
当a为真打印haha,为假则打印hehe
#include <stdio.h>
#include <stdbool.h>
int main()
{
_Bool a = false;
if (a)
{
printf("haha");
}
else
printf("hehe");
return 0;
}
需要注意的是,当我们使用布尔类型的时候,一定要包含头文件。
使用布尔类型的时候,—Bool和bool都是可以正常使用的。
```#include <stdio.h>
#include <stdbool.h>
int main()
{
bool a = true;
if (a)
{
printf("haha");
}
return 0;
}
signed 和 unsigned
上面我们介绍整型类型和字符类型的时候都有 signed 和 unsigned,那么 signed 和 unsigned是什么意思呢?
signed 关键字,表⽰⼀个类型带有正负号,包含负值;
unsigned 关键字,表⽰该类型不带有正负号,只能表⽰零和正整数。
注:C 语⾔使⽤ signed 和 unsigned 关键字是修饰字符类型和整型类型的
在这里我给读者朋友补充一个知识点,什么是、关键字。
什么是关键字
关键字是C语言保留下来的一些名字的符号,⽐如: int 、 if 、 return ,这些符号被称为关键字, 关键字也叫保留字。
-关键字都有特殊意义,是保留给C语言使用的;
-在创建变量或者标识符时,名字不能和关键字一样;
-关键字不能被创建。
在C语言中 signed 和 unsigned 关键字是用来修饰字符型和整型类型的。
整型中的signed 和 unsigned
对于int类型默认自带正负数,也就是说int类型默认为signed int
像int类型这种特殊的情况,在我们使用signed int时,不写signe也不会错。
signed int a ;
//等同于int a
当int值表示零和正整数时,就要带上unsigned
unsigned int a;
整型类型定义为unsigned int的好处在于,相比于int,unsigned int同样⻓度的内存能够表⽰的最⼤整数值,unsigned int能表示的最大整数值比int(signed int)大。
int的取值范围可以查看<limits.h>给出的定义。
我们说括号中的值是可以省略的,signed int 里面的int也可以省略 , 那么我们的变量声明可以这样写:
signed a;
字符类型中的 signed 和 unsigned
字符类型 char 也可以设置 signed 和 unsigned 。
C语言规定char类型默认是否带正负号,由当前的系统决定。
也就是说,char类型可能是signed char,也可能是unsigned char。
signed char a; //取值范围:-128 到 127
unsigned char a; //取值范围:范围为 0 到 255
数据类型的取值范围
上面介绍了很多数据类型,但不同的数据类型的取值范围是不一样的,我们去使用这些数据类型的时候应该取最合适的数据类型去使用,比如我们需要应该最大数是10,但你使用的数据类型的最⼤值却是10的10倍,所以我们在写代码的时候,应该考虑好使用的范围来确定数据类型的使用。
limits.h 头⽂件中说明了整型类型的取值范围。
float.h 这个头⽂件中说明浮点型类型的取值范围。
具体可以通过上述两个文件查看。
各种数据类型的⻓度
每一种数据类型都有自己的长度,使用不同的数据结构,可以创建出不同长度的变量,变量长度的不同,存储数据的范围也会有所差异
sizeof操作符
sizeof是一个关键字,也是操作符,专门用来计算sizeof‘操作符数的类型长度,单位是字节。
sizeof操作符可以是类型,也可以是变量或者表达式。
sizeof (类型)
sizeof 表达式
-sizeof的操作数如果不是类型,是表达式的时候,可以省略掉后边的括号。
-sizeof后边的表达式是不真实参与运算的,是根据表达式的类型来计算出大小的。
-sizeof计算的结果是size_t 类型的。
#include <stdio.h>
int main()
{
int a = 19;
printf("%zd\n", sizeof(a));
printf("%zd\n", sizeof a);
printf("%zd\n", sizeof(int));
printf("%zd\n", sizeof(3 + 9.5));
return 0;
}
上述我们说sizeof的操作符可以是类型,也可以是变量和表达式,我们通过例子中的代码验证,得出的结果也确实是可以的 , 比如当操作数不是类型 ,是变量时,后边的括号是可以省略的。
sizeof的返回值
sizeof运算符的返回值,C语言只规定是无符号整数,没有规定具体的类型,在不同的系统中是不同的,留给系统去做决定。
不同的系统中,返回值的类型有可能是signed int , 或者是unsigned long ,再或者是unsigned long long 都有可能。
对应的 printf() 占位符分别是 %u 、 %lu 和 %llu。
当然C语言也提供了一个解决方法,创造了一个类型别名:size_t , 用来统一sizeof返回值类型 。对于当前的系统可能是unsigned int 或者是unsigned long long。
各种类型的长度
#include <stdio.h>
int main()
{
printf("%zd\n", sizeof(int));
printf("%zd\n", sizeof(short));
printf("%zd\n", sizeof(long));
printf("%zd\n", sizeof(long long));
printf("%zd\n", sizeof(float));
printf("%zd\n", sizeof(double));
printf("%zd\n", sizeof(long double));
printf("%zd\n", sizeof(char));
printf("%zd\n", sizeof(_Bool));
return 0;
}
以上就是本篇中提到的各种数据类型的长度(x86环境下)。
sizeof中表达式不计算
例子:
#include <stdio.h>
int main()
{
int a = 10;
short b = 5;
printf("%zd\n", sizeof(a = b + 19));
printf("%d\n", a);
return 0;
}
这里我解释一下,为什么打印出来的是4 和 10。
a是int类型,我们知道int类型是4个字节的大小,b是short类型,2个字节的大小,我们将a+b的值赋给a,也就是让a的值加上b的值,最终打印出14,但打印出来的却是10,也就是说,在第一个printf中,表达式并没有相加。这是因为在sizeof中表达式不计算,我们首先明白,sizeof在代码进行编译的时候,就根据表达式的类型确定了大小,而表达式的执⾏却要在程序运期间才能执⾏,编译期间就语句将sizeof处理掉了,所以在代码运行期间就不会执行表达式了。
解释了我为什么打印10,那为什么打印4呢?
a是int类型 , b是shotr类型,我们把值放在,b变量中,让int b 和 short b加在一起,而b变量是int类型的,所以最终sizeof最终计算的也是int类型的大小 , 我们把 a = a +19 , 换成 b = a + 19 , 最终打印的就是2了,因为short类型的大小就是2。
变量
变量的创建
了解了类型,那么类型是用来干嘛的?类型是用来创建变量的。
什么是变量?C语言中把可以变化的值叫变量,不能变化的值叫常量。
变量创建的语法形式:
int a
//数据类型 //变量名
char a; //字符变量
int b; //整型变量
float c; //浮点变量
变量初始化
变量在创建的时候,给一个初始值叫初始化。
int a = 10 //这就是初始化
char b = 10;
float c = 1.1;
变量的分类
变量分为:全局变量 和 局部变量
全局变量:在大括号外部定义的变量,叫全局变量。
全局变量的使用范围更广,在整个工程内都能使用。
局部变量:大括号内部定义的变量,叫局部变量。
局部变量的使用范围比较有限,只有自己局部范围内可以使用。
#include <stdio.h>
int a = 19;//全局变量
int main()
{
int a = 20; //局部变量
return 0;
}
大括号说的就是main里面和外面。
那当全局变量和局部变量的变量名是一样的,printf()函数会打印全局变量还是局部变量?
#include <stdio.h>
int a = 19;//全局变量
int main()
{
int a = 20; //局部变量
printf("%d", a);
return 0;
}
当全局变量和局部变量的变量名一样时,局部优先,先打印局部变量。
局部变量分很多种,比如比局部变量更局部的变量。
#include <stdio.h>
int a = 19;//全局变量
int main()
{
int a = 20; //局部变量
if (1)
{
int a = 21;
printf("%d", a);
}
return 0;
}
既然局部变量优先,那么比局部变量更局部的变量则更优先。
变量在内存中的存储
我们再讲一个关于变量的小知识,我们都知道变量的创建,但这些我们创建好的变量都存储在内存的那个位置呢?
我们在学习C语言的时候一般会关注内存中的三个区域:栈区、堆区、静态区。
-局部变量存放在内存的栈区;
-全局变量存放在内存的静态区;
-堆区则用来动态内存管理。
我们简单了解一下,这里不多叙述。