1、什么是数据类型?
数据类型在我们日常生活中就是表示每一类数据的标识,我们通过大脑来存储这些数据标识,那么在计算机中我们认为数据类型就是计算机表示数据的一个属性,我们程序员通过编译器和解释器向计算机表示我要进行的数据类型操作。当然这些数据存储在计算机当中。下面我就来讲解C语言中数据的不同类型以及它们所占的存储空间、怎样定义一个常量、常量的命名规范......
1.1数据类型的分类
🤼那么在C语言中数据类型分为四种:
- 基本数据类型-整数型、浮点型和字符型
- 空类型-void类型
- 构造类型-数组、结构体、共用体、枚举类型
- 指针类型- *
本期我们主要讲解最常用的-基本数据类型,后面几期我们再来探讨其他几种数据类型
1.2基本数据类型有哪些?
C语言中基本数据类型有整数类型和浮点类型,他们都是算术类型。分别为:
char(%c)- 字符型:可以是大小写字母(例'a'、'A'),数字(例'1'),转义字符(例'\t')等,它在16位编译器、32位编译器、64位编译器中都占1个字节;
short(%d)- 短整型:可以是小型数字取值较短,它在16位编译器、32位编译器、64位编译器中都占2个字节;
int(%d)- 整形:可以是中长度的一个数字取值比,正常我们定义一个整形变量就用int,它在16位编译器占2个字节、32位编译器占4个字节、64位编译器占4个字节;
long(%ld)- 长整型:当我们要求的数字较大超出了正常范围,我们可以用long来定义,它在16位编译器、32位编译器都占4个字节、64位编译器中占8个字节;
long long(%lld)- 更长的长整型:当数字太大了,已经数不过来了,我们可以用long long,它在16位编译器、32位编译器、64位编译器中都占8个字节 ;
float(%f)- 单精度浮点型:我们一般都用float来表示小数,如6.6,6.66这种小数位数少的,它在16位编译器、32位编译器、64位编译器中都占4个字节;
double(%lf)- 双精度浮点型:当小数位数过大,如6.666699897我们就用双精度来表示,它在16位编译器、32位编译器、64位编译器中都占8个字节;
long double(%llf)- 更高精度的浮点型:long double是C99中新增的数据类型。ANSIC标准规定了double类型为64 位(8 个字节)浮点数, 但未规定long double类型的位数,只规定了long double的精度不少于double的精度。它的不同的系统位占的字节也不同。
数据类型 | 系统16位 | 系统32位 | 系统64位 |
char | 1(字节) | 1(字节) | 1(字节) |
short | 2(字节) | 2(字节) | 2(字节) |
int | 2(字节) | 4(字节) | 4(字节) |
long | 4(字节) | 4(字节) | 4(字节) |
long long | 8(字节) | 8(字节) | 8(字节) |
float | 4(字节) | 4(字节) | 4(字节) |
double | 8(字节) | 8(字节) | 8(字节) |
以上是我们对基本数据类型的一个初步了解,以下内容我们来深入了解一下什么是基本数据类型
那么我们想要得到某个类型的存储大小,我们可以使用sizeof运算符,表达式sizeof(数据类型)来得到该类型或对象在存储占用多少字节数,🤼♀️下图所示:
注意,各个类型的存储大小与系统位相关,上图是以目前主流的64位操作系统,诸位可以打开编译器试试(●'◡'●)
1.3整型
整形家族:char - 字符数据类型、short - 短整型、int - 整形、long - 长整型、long long - 更长的整形
类型 | 存储大小 | 取值范围 | 格式符 |
char | 1字节 | -128 到 127 或 0 到 255 | %c |
int | 4 字节 | -2,147,483,648 到 2,147,483,647 | %d |
short | 2 字节 | -32,768 到 32,767 | %d |
long | 8 字节 | -2,147,483,648 到 2,147,483,647 | %ld |
long long | 8 字节 | -2^64到2^64-1 | %lld |
怎样理解C语言中的整型呢,见名知意,是指一个没有小数位数的整数。只不过在计算机中我们称为整型。在生活中一个整数,可以是负数、正数,计算机里面也是一样的可以是正数、负数。那么计算机表示数可以是八进制、十进制、十六进制等。表示八进制数,数字前面加0(零)。表示十进制数不需要加任何符号,C语言中默认一个数字为十进制。表示十六进制数,则在数字前面加0x(零x)。
有一程序,定义一个数,分别输出它的八进制数、十进制数、十六进制数:
intmain() { intn=20; printf("对应的八进制数为: %#o\n", n);//%o输出八进制形式printf("对应的十进制数为: %d\n", n);//%d输出十进制形式printf("对应的十六进制数为:%#x\n", n);//%x输出十六进制形式return0; }
输出的结果为:
对应的八进制数为: 024
对应的十进制数为: 20
对应的十六进制数为:0x14
printf 可以使用使用格式控制串“%o”、“%X”分别输出八进制整数和十六进制整数,并使用修饰符“#”控制前导显示
1.4浮点型
浮点型家族:float - 单精度浮点型字符、double - 双精度浮点型字符
类型 | 存储大小 | 值范围 | 精度 | 格式符 |
float(单精度) | 4 字节 | 1.2E-38 到 3.4E+38 | 6 位有效位 | %f |
double(双精度) | 8 字节 | 2.3E-308 到 1.7E+308 | 15 位有效位 | %lf |
long double | 16 字节 | 3.4E-4932 到 1.1E+4932 | 19 位有效位 | %llf |
怎么理解浮点型呢,一个小数66.6它可以写为6.66*10^1也可以写为0.666*10^2。这个数它的小数点是可以移动的漂浮不定的,我们称之为浮点型。在C语言中浮点型分为单精度浮点型和双精度浮点型。我们如何定义它呢?
如一个小数6.6。在C语言中我们默认这个小数为double类型(双精度浮点型字符),但是这个小数6.6貌似不是很大好像不用那么高的精度来给它定义。那么我们可以在6.6后面加上一个f即6.6f这就形式我们一目了然这是一个单精度浮点型6.6。
如何得到单精度与双精度所占字节以及取值范围呢?步骤如下图所示:
//引入头文件<float.h>intmain() { printf("float 存储最大字节数 : %lu \n", sizeof(float));//sizeof取float的字节数printf("float 最小值: %E\n", FLT_MIN);//输出float最小值printf("float 最大值: %E\n", FLT_MAX);//输出float最大值printf("精度值: %d\n", FLT_DIG);//输出float精度值printf("double 存储最大字节数 : %lu \n", sizeof(double));//sizeof取double的字节数printf("double 最小值: %E\n",DBL_MIN);//输出double最小值printf("double 最大值: %E\n", DBL_MAX);//输出double最大值printf("精度值: %d\n", DBL_DIG);//输出double精度值return0; }
- float.h是C语言标准库头文件,提供了浮点型的范围和精度的宏,一般用于数值分析。 float.h包含了一组与浮点值相关的依赖于平台的常量。DBL_MAX:double型的最大值,DBL_MIN:double型的最小值,FLT_MAX:float型的最大值,FLT_MIN:float型的最小值。分别把这几个参数带入输出式中,可以得到结果。
- 那么float.h被定义宏有float、double、long double。上图中我只列出了两个最常用的类型。
- %E 为以指数形式输出单、双精度实数。
以下为输出结果,可以上面代码深入了解一下:
总结:
- 引入头文件#include<float.h>
- DBL_MAX:double型的最大值
- DBL_MIN:double型的最小值
- FLT_MAX:float型的最大值
- FLT_MIN:float型的最小值
- 字符型,单独的一个字符用英文状态下单引号''引起来如'A'、'*'、'a'、'\t';
- 字符型,字符串应用英文状态下的""引起来如"ABC";
- 浮点型,单精度6.6应写为6.6f,双精度6.6还是6.6(C语言默一个小数为双精度浮点型)。
2、变量与常量
基本数据类型分为常量与变量
2.1变量与常量是什么?
在日常生活中,一个人的姓名、身份证号码、性别、血型。我们理解为这个人的不变的量,这里也就是常量。那么这个人的年龄、体重、相貌、工资。我们理解为这个的可变的量,这里也就是变量。那么理解上述两段话后,我们就不难理解C语言中常量与变量是怎么个回事了。
C语言中可以改变的值我们称为变量,不可改变的值我们称为常量
2.2怎样定义一个常量
通过赋值来定义,看一个小例子定义一个int a=10和一个char ch='A',意思是定义一个整形变量a,把10赋值给a和定义一个字符型变量ch,把A赋值给ch。我们可以这样理解=号前面是变量的命名,=号后面是一个量这个量可以变。我们可以再通过赋值来改变,亦或者通过scanf输入来改变。
intmain() { inta=10;//定义一个整形变量a=10charch='A';//定义一个字符型变量ch=Aprintf("a=%d,ch=%c\n\n", a,ch);//输出变量a,cha=20;//把整形变量a改为20ch='B';//把字符型变量ch改为Bprintf("a=%d,ch=%c\n", a,ch);//输出变量a,chreturn0; }
众所周知,C语言是一个从按照顺序来执行代码的一个语言,上述代码中,首先我定义了一个整形变量a=10和一个字符型变量ch=‘A’,分别输出10和A,后来我又通过赋值操作把变量a该为20,变量ch改为B,我再输出20与B。 通过这一个小案例,我们可以知道如何定义一个变量。
定义一堆常量,直接上代码:
intmain() { charzifu='A';//定义一个字符变量zifu,赋值给它Achar*zifu2="ABC";//定义一个指针字符变量指向名为zifu2字符串的首地址,赋值给它ABCshortduan=1010;//定义一个短整型变量duan,赋值给它1010intzheng=2022;//定义一个整形变量zheng,赋值给它2022longchang=10000;//定义一个长整型变量chang,赋值给它10000longlongchaoChang=100000000;//定义一个更长的长整型chaoChang,赋值给它100000000printf("定义一个字符 %c\n",zifu); printf("定义一个字符串 %s\n", zifu2); printf("定义一个短整型 %d\n", duan); printf("定义一个整形 %d\n", zheng); printf("定义一个长整型 %ld\n", chang); printf("定义一个更长的长整型 %lld\n", chaoChang); return0; }
输出结果:
2.3变量的命名规范
- 只能由字母、数字和下划线( _ )组成。
- 不能以数字开头。
- 长度不能超过63个字符。
- 变量名中区分大小写的。
- 变量名不能使用关键字。
3、变量的分类
变量分为局部变量与全局变量局部变量与全局变量之前,我们必须了解到作用域和生命周期这两个概念。
作用域,作用域(scope)是程序设计概念,通常来说,一段程序代码中所用到的名字并不总是有效/可用的而限定这个名字的可用性的代码范围就是这个名字的作用域。
- 局部变量的作用域是变量所在的局部范围。
- 全局变量的作用域是整个工程。
生命周期,变量的生命周期指的是变量的创建到变量的销毁之间的一个时间段。
- 局部变量的生命周期是:进入作用域生命周期开始,出作用域生命周期结束。
- 全局变量的生命周期是:整个程序的生命周期。
3.1局部变量
局部变量我们理解为括号{}内定义的变量,局部变量的作用域是变量所在的局部范围局部变量的生命周期是:进入作用域生命周期开始,出作用域生命周期结束。我们看代码:
intmain() { inta=20; //定义一个局部变量a=20printf("a=%d\b", a); return0; }
结果: a=20
这就是一个简单的局部变量,当然我们可以再通过赋值、scanf输入来改变这个变量。
intmain() { { inta=20; printf("a=%d\n", a); } return0; }
输出结果:a=20
那么我们把printf语句放在第二个{}外面,上个程序与下个程序有什么不同呢?
#include<stdio.h> int main() { { int a = 20; } printf("a=%d\n", a); return 0; }
会显示未定义标识符a
为什么这个地方会显示a未定义标识符呢? 因为我们是在第二个{}里面定义的a=20,脱离了第二个{}后我们就脱离了这个{}的作用域,也就是上方这句话的意思局部变量的生命周期是:进入作用域生命周期开始,出作用域生命周期结束。
3.2全局变量
全局变量我们理解为括号{}外定义的变量,全局变量的作用域是整个工程。局变量的生命周期是:整个程序的生命周期。
inta=10;//定义一个全局变量a=10intmain() { printf("a=%d\b", a); return0; }
结果:a = 10
那么这就是一个简单的定义全局变量程序,我们刚开始学习就应该以理解为主,在后来的学习中,我们的难度才会慢慢增长。不要站架没学会就想着怎么出拳,一步一步来。
🤼下面我们来看一个程序:
inta=2021;//定义一个全局变量a=2021intmain() { intb=2022;//定义一个局部变量a=2023;//把a更改为2023printf("a=%d\n", a);//输出a现在的值return0; }
结果:a=2023
可能有些小伙伴看了这个,就有些疑惑了,诶你不是定义a=2021了吗,为啥输出结果为2023呢?诸位注意,我定义的a=2021是在{}前面定义的,我们成这个为全局变量,而{}内定义的a=2023是一个全局变量。所以我们认为局部变量与全局变量名冲突时,我们优先输出局部变量。这就是为什么上述结果为2023。
总结🥊:
- 局部变量的作用域是变量所在的局部范围。
- 全局变量的作用域是整个工程。
- 局部变量的生命周期是:进入作用域生命周期开始,出作用域生命周期结束。
- 全局变量的生命周期是:整个程序的生命周期。
4、常量的使用
4.1常量分类
C语言中常量与变量的命名是有着极大的不同的,上面我们说过常量是不可改变的量,那么设置它的时候自然有着不同之处。C语言中的常量有以下几种:
- 常见常量
- const修饰的常变量
- #define定义的标识符常量
- 枚举常量
4.2#define宏定义
#define是什么?
#define命令是C语言中的一个宏定义命令,它用来讲一个标识符定义为一个字符串,该标识符被称为宏名,被定义的字符串称为替换文本。该命令有两种格式:一种是简单的宏定义(不带参数的宏定义),另一种是带参数的宏定义。
#define是一个宏定义,它定义一个文本给这个文本赋不变的值,我们可以在main函数里面通过这个文本调用这个文本所赋给的值。这个值是不变的,所以我们称为常量。
🤼以下有一程序输入圆的半径求圆的面积:
include<stdio.h>//宏定义文本pai=3.14intmain() { doubler=0; doubles=0; printf("请输入圆的半径:"); scanf("%lf", &r); s=pai*r*r; printf("圆的面积为:%.1lf\n", s); return0; }
🤼♀️结果为:
那么这个程序就用到了宏定义#define,我令pai为宏名(标识名),赋值给它3.14。
大家思考一下上述宏定义,只是定义一个值。如果定义一个算术类型呢?例如#define N 3+2,那么这个定义是否可以呢?例:有一矩形已知一边长宏定义为10,另一边长为5,并求出它的面积,我们来看代码:
//4+6没有括号intmain() { intn=5; ints=0; s=N*n; printf("矩形的面积为:%d\n",s); return0; }
输出的结果为:
矩形的面积为:34
为什么会这样呢,在编译时我们预想s=10*5,实际打印结果是34原因是在预处理阶段,编译器将 s=10*5 处理成 s=4+6*5,这就是 define 宏的边缘效应,所以我们应该写成 #define N (2+3)。
这样我们才能输出正确的答案 :
矩形的面积为:50
🤼♀️当然你也可以#define多个命名,直接看代码
intmain() { intS=0; S=A*B; printf("A*B=%d", S); printf("%c", C); return0; }
上述程序我们可以看到宏定义可以定义转义字符'\n'换行
总结🥊:
- 宏定义一个算术类型时要加()如:#define N (2+3)
- 宏定义可以是转义字符,如:'\n'、'\t'
4.3const修饰的常变量
const是一个关键字,那么const修饰的为什么可以是一个常量,也可以是一个变量呢?下面我就来讲解。首先,我们要知道定义一个const修饰的常量的格式:const int a =20 ;1、const-关键字2、int-数据类型3、a-变量名4、20-变量值5、;-结束符
🤼当const修饰一个常量时,这个常量的值是不可更改的:
我们可以看到上图中,const 修饰整形变量a=20后,a再不能被赋值了。也就是说const把a定死了,它只能是20。
🤼♀️当const修饰一个指针变量时,这个指针变量可以通过指向不同的地址来改变:
intmain() { inta=20; constint*p=&a; printf("%d\n", *p); a=30; printf("%d\n", *p); return0; }
结果为:20
30
当把 const 放最前面的时候,它修饰的就是 *p,那么 *p 就不可变。*p 表示的是指针变量 p 所指向的内存单元里面的内容,此时这个内容不可变。其他的都可变,如 p 中存放的是指向的内存单元的地址,这个地址可变,即 p 的指向可变。但指向谁,谁的内容就不可变。
intmain() { inta=20; int*constp=&a; printf("%d\n", *p); a=30; printf("%d\n", *p); return0; }
结果:20
30
总结🥊:
- const修饰一个常量时,这个常量是不可改变的
- const修饰一个指针变量时,这个指针变量可以通过地址来改变原本的值
4.4枚举常量
上面我们已经见过const字符常量、还有宏常量了但是如果想要定义一组有意义的数字,这一组的数字都有“排比”一样的规律我们可以定义为枚举常量。
🤼直接看代码:
intmain() { enumStudent { shuxue, yingyu, wuli }; printf("shuxue=%d\n", shuxue); printf("yingyu=%d\n", yingyu); printf("wuli= %d\n", wuli); return0; }
那么括号中的shuxue,yingyu,wuli都枚举常量。那么枚举常量只能是int类型的,且声明和赋值整数,平常在排列时用的较多。至于他的用法以后我会在后面几期文章内提到,我们暂时只用知道什么是枚举常量。
注意,枚举常量的默认是从0开始,依次向下递增1的
好了,本期博文到这里就结束了。下期预告:选择结构。