探索C语言的数据类型:解密编程世界的核心秘密
✨✨ 欢迎大家来到贝蒂大讲堂✨✨
🎈🎈养成好习惯,先赞后看哦~🎈🎈
所属专栏:C语言学习
贝蒂的主页:Betty‘s blog
1. 常量与变量
1.1 常量
(1) 常量的概念
常量顾名思义就是无法改变的量,比如一周有7天,一天有24小时,这些都是无法改变的量。
(2) 常量的分类
- 整数常量:1,2,3,-1,-2等
- 小数常量:小数在C语言中有两种表示形式,一种是直接表示如:1.1,1.3,3.14,200.2 还有一种便是科学表示法如2.1433×102,用C语言表示就是2.1433e2或者2.1433E2。
- 字符常量:因为字符在内存中是以ASCII码值存储,所以字符也是常量,如'a','b','\n','\111'等。
- 标识常量:也就是用宏定义的常量,它常常大写放在开头,语法形式也特别简单
#define 标识符号名 常量数据
#include <stdio.h>
#define MAX 10
//后续代码会将MAX替换为10
int main()
{
int a = MAX;
return 0;
}
- 枚举常量:是由枚举类型代表的常量,这个会在之后的章节详细为大家讲解。
(3) 二进制,八进制,十六进制
- 二进制:二进制在计算领域应用广泛,它的数字每⼀位都是0~1的数字组成,并且满2进1。
- 八进制,与二进制类似,由数字0~7组成,并且满8进1。
- 十六进制,由0~9,a~f代表10~15组成,并且满16进1.
在C语言中,八进制是以0开头表示,十六进制以0x开头,输出占位符分别为%o,%x。
int main()
{
int a = 0111;//八进制
int b = 0x43a;//十六进制
printf("八进制输出%o 十进制输出%d\n", a, a);
printf("十六进制输出%x 十进制输出%d\n", b, b);
return 0;
}
输出结果:
(4) 二进制与其他进制之间的转换
- 二进制转十进制,按权重直接转换,假设二进制的1001,转换如图
- 二进制转八进制,从右往左每三个二进制转换为一个八进制位,最后不够直接转为八进制。以二进制11010111为例
- 二进制转十六进制与转八进制类似,从右往左每四个二进制转换为一个十六进制位,最后不够直接转为十六进制进制。以二进制11010111为例
- 十进制转换为二进制,可以利用除法取余。如图为63转换为二进制的过程
1.2 变量
(1) 变量的概念
变量顾名思义就是不断改变的量,如我们的年龄,体重,身高等都可以称之为变量
(2) 变量的命名规则
在C语言中有一套严格的命名规则,如下
- 变量名的开头必须是字母或下划线,不能是数字。
- 变量名中的字母是区分大小写的。
- 变量名绝对不可以是C语言关键字。
- 变量名中不能有空格。这个可以这样理解:因为上面我们说过,变量名是字母、数字、下划线的组合,没有空格这一项。
(3) 局部变量和全局变量
全局变量简单来说就是可以作用于全局的变量,在整个编程中都可以使用。而局部变量就是只能在特定区域使用的变量。
#include <stdio.h>
int a = 1;
//全局变量,任何地方都能使用
int main()
{
int b = 2;
//局部变量,只能在main函数中使用
return 0;
}
(4) 局部优先原则
当局部变量和全局变量同名的时候,局部变量优先使⽤!
我们可以看看这段代码
#include <stdio.h>
int a = 1;//全局变量
int main()
{
int a = 2;//局部变量
printf("%d ", a);//输出什么?
return 0;
}
输出结果:
2. 数据类型
2.1 介绍
在我们日常生活中我们描述物品可以描述它的形状,大小,颜色,气味……,但是对于计算机而言,存储的数据都是以二进制的形式,那么它又该区别这些数据呢?因此,C语言就为大家提供了丰富的数据类型,方便大家描述不同的数据,比如说描述整数的short,int……,描述字符的char,小数的float,double等等,而在数据类型主要分为两种:一种是系统自带的内置类型,另一种就是可以自定义的自定义类型,本章就重点围绕数据类型中的内置类型来为大家详细谈谈。
以下是常见的一些数据类型:
- 顾名思义整型是用来描述整数的,浮点型是用来描述小数的,具体细分与其表示的精度有关。
- 每次声明一个变量时都需要声明其类型。
- 其中因为字符在内存中存储是以ASCII码的形式,所以也算作整型。
- C99中还新增了一种数据类型用来表示正(true)误(false)的布尔类型(_Bool),使用它必须包含头文件<stdbool.h>。
2.2 举例使用
#include<stdbool.h>
int main()
{
char ch = 'a';//字符型
int a = 1;//整形
float b = 1.0f;//单精度浮点型
double c = 2.1;//双精度浮点型
bool m = false;//布尔类型
return 0;
}
2.3 signed和unsigned
在C语⾔中使⽤ signed(有符号) 和 unsigned(无符号) 关键字修饰字符型和整型类型。signed表示被修饰的关键字有正负之分,unsigned表示被修饰的关键字无负数,其中当关键字不经修饰时默认为有符号类型。
int main()
{
signed int a = 10;
//等价于int a=10
signed char ch = 'a';
//等价于 char ch='a';
unsigned int m = 1;
unsigned char n = 'b';
return 0;
}
- 在同一类型下,unsigned的表示范围更大,如果想知道为什么的同学可以看看——>数据在内存中的存储
2.4 强制类型转换
在C语言中,不同类型的值是无法相互赋值的,否则可能发生意料之外的结果。比如说:“浮点型的小数无法赋值给整型。”但是C语言中有一个操作符,能把变量从一种类型转换为另一种数据类型。这就是我们的强制类型转换操作符。
语法形式很简单,形式如下:
(类型) 数据
代码示例:
#include <stdio.h>
int main()
{
int a = 10;//正确
int b = 3.1;
//b是整型,3.1是浮点型,错误
int c = (int)3.1;//强制类型转换后正确
printf("%d ", c);
return 0;
}
2.5 数据类型的大小
(1) sizeof操作符
sizeof 是⼀个关键字,也是操作符,专⻔是⽤来计算sizeof的操作符数的类型⻓度的,单位是字节。sizeof 操作符的操作数可以是类型,也可是变量或者表达式。
sizeof( 类型 )
sizeof 表达式
- sizeof 的操作数如果不是类型,是表达式或变量的时候,可以省略掉后边的括号的。
- sizeof 后边的表达式是不真实参与运算的,根据表达式的类型来得出⼤⼩。
- sizeof 的计算结果是 size_t 类型的。
#include <stdio.h>
int main()
{
int a = 10;
printf("%zd\n", sizeof(a));
printf("%zd\n", sizeof a); //a是变量可以省略掉sizeof后边的()
printf("%zd\n", sizeof(int));//类型不可以省略
printf("%zd\n", sizeof(3 + 1));
printf("%zd\n", sizeof 3 + 1);//表达式可以省略
return 0;
}
- size_t的占位符为%zd,写成%d也是可以的
特别注意:
sizeof 运算符的返回值,C语⾔只规定是⽆符号整数,并没有规定具体的类型,⽽是留给系统⾃⼰去决定, sizeof 到底返回什么类型。不同的系统中,返回值的类型有可能是unsigned int ,也有可能是 unsigned long ,甚⾄是 unsigned long long ,对应的 printf() 占位符分别是 %u 、 %lu 和 %llu 。这样不利于程序的可移植性。C语⾔提供了⼀个解决⽅法,创造了⼀个类型别名 size_t ,⽤来统⼀表⽰ sizeof 的返回值类型。对应当前系统的 sizeof 的返回值类型,可能是 unsigned int ,也可能是unsigned long long 。
其中在VS2022 ×86 环境中是unsigned int
其中在VS2022 ×64 环境中是unsigned long long
(2) 计算大小
在我们知道sizeof的用法之后,我们就可以计算不能数据类型的大小,单位为字节(byte)。
#include <stdio.h>
int main()
{
printf("%zd\n", sizeof(char));
printf("%zd\n", sizeof(_Bool));
printf("%zd\n", sizeof(short));
printf("%zd\n", sizeof(int));
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));
return 0;
}
输出结果:
(3) 表达式不计算
#include <stdio.h>
int main()
{
short s = 2;
int b = 10;
printf("%d\n", sizeof(s = b + 1));
printf("s = %d\n", s);
return 0;
}
- sizeof 在代码进⾏编译的时候,就根据表达式的类型确定了大小,⽽表达式的执⾏却要在程序运⾏期间才能执⾏,在编译期间已经将sizeof处理掉了,所以在运⾏期间就不会执⾏表达式。
2.6 数据类型的范围
因为不同的数据表示范围,整型短整型,整型,长整型......,浮点数分为单精度浮点型,双精度浮点型。为了方便大家熟练掌握每个数据类型的应用,下表展现了常见数据类型的范围
数据类型 | 大小(byte) | 范围 |
---|---|---|
char(signed char) | 1 | -128~127 |
unsigned char | 1 | 0~255 |
short int(signed short int) | 2 | -32,768~32,767 |
unsigned short int | 2 | 0~65,535 |
int(signed int) | 4 | -2,147,483,648~2,147,483,647(-231 ~ 231-1) |
unsigned int | 4 | 0~4,294,967,295 |
long int(signed long int) | 4 | -2,147,483,648~2,147,483,647(-231 ~ 231-1) |
unsigned long int | 4 | 0~4,294,967,295 |
float | 4 | -3.4x10-38 ~ 3.4x1038 |
double | 8 | -1.7x10-308 ~ 1.7x10308 |
3. 基本运算符
3.1 赋值
在变量创建的时候给⼀个初始值叫初始化,在变量创建好后,再给⼀个值,这叫赋值。而=就是一种简单赋值运算符
int main()
{
int a = 1;//给a赋值为1
int t = m=1;//C语言可以这样连续赋值
char b = 'a';//为b赋值字符a
float c = 1.0f;//1.0为double类型
//加f转换为float型
return 0;
}
3.2 加(+)减(-)乘(*)
C语言中的加减乘与数学中的加减乘类似,直接类比使用就行。
int main()
{
int a = 1;
int b = 2;
int c = 1 + 2;//加法
int m = 1 - 2;//减法
int n = 1 * 2;//乘法
printf("1+2=%d\n1-2=%d\n1*2=%d\n", c, m, n);
return 0;
}
输出结果:
3.3 除号(/)和取模(%)
除号的两端如果是整数,执⾏的是整数除法,得到的结果也是整数(舍去余数)。
如果两端有一个是小数,执行的小数除法,得到小数。
int main()
{
int a = 1;
int b = 2;
int c = 1 / 2;
double d = 1.0 / 2;
printf("%d %lf\n", c, d);
return 0;
}
输出结果:
运算符 % 表⽰求模运算,即返回两个整数相除的余值。这个运算符只能⽤于整数,不能⽤于浮点数。
负数求模的规则是,结果的正负号由第⼀个运算数的正负号决定。
int main()
{
int a = 1;
int b = 2;
int m = 1 % 2;
int n = -1 % 2;//负数在前
int t = 1 % 2;//负数在后
printf("%d %d %d\n",m,n,t);
return 0;
}
输出结果:
3.4 自增与自减
++是⼀种⾃增的操作符,⼜分为前置++和后置++,--是⼀种⾃减的操作符,也分为前置--和后置--。
int main()
{
int a = 1;
a++;
printf("a=%d\n", a);
++a;
printf("a=%d\n", a);
a--;
printf("a=%d\n", a);
--a;
printf("a=%d\n", a);
return 0;
}
- 前置与后置a++都相当于a=a+1,前置与后置--都相当于a=a-1
那前置与后置之间有什么区别呢·?请看下面这段代码。
int main()
{
int a = 1;
int b = a++;//后置++
printf("a=%d b=%d\n", a, b);
int c = ++a;//前置++
printf("a=%d c=%d\n", a, c);
int m = a--;//后置
printf("a=%d m=%d\n", a, m);
int n = --a;//前置--
printf("a=%d n=%d\n", a, n);
return 0;
}
通过上述代码,我们可以总结以下结论:
- 前置++,--,先执行++或--,然后对等式左边进行赋值
- 后置++,--,恰好相反,先对等式左边进行赋值,然后再++或--