C语言数据类型和变量
一、数据类型
1. 数据类型的介绍
1.1 字符型 char
char // character
[signed] char // 有符号的
unsigned char // 无符号的
1.2 整型
// 短整型
short [int]
[signed] short [int]
unsigned short [int]
// 整型
int
[signed] int
unsined int
// 长整型
long [int]
[signed] long [int]
unsined long [int]
// 更长的整型
// C99中引入
long long [int]
[signed] long long [int]
unsigned long long [int]
1.3 浮点型
float
double
long double
1.4 布尔类型
先来介绍一下布尔类型,它就是用来表示真假的类型,真为 非0 ,假为 0。
下面让我们来看看布尔类型的两种表达方式
_Bool //下划线 + 大写B
bool //小写b,无下划线
- 布尔类型要包含头文件
<stdbool.h>
- 布尔类型变量的取值是:
true
或者false
#define bool _Bool
#define false 0
#define true 1
代码演示:
_Bool flag = true;
if (flag)
printf("I like C\n");
1.5 数据类型的长度
不同的数据类型,其变量有不同的长度,变量长度不同,存储的数据范围就有所差异
1.5.1 介绍sizeof
操作符
sizeof
是一个关键字,也是操作符,专门计算sizeof的操作符数的 类型长度 ,单位是 字节 。
sizeof
操作符的操作数可以是类型(int,float……),也可以是变量(a,x)或者表达式(a+b)。
sizeof( 类型 ) // 必须要加上括号
sizeof 表达式 // 可以没有括号哦,但一般还是加上比较好
- 1.
sizeof
的操作数如果不是类型,是表达式的时候,可以省略掉后面的括号的; - 2.
sizeof
后边的表达式是不真实参与运算的,根据表达式的类型来得出大小; - 3.
sizeof
的计算结果是size_t
类型的。注意,size_t
是无符号整型,也就是所谓的非负,如果俩size_t
相减,结果一定也是size_t
类型,结果必为 非负; - 4.
sizeof
的占位符是%zd
.
1.5.2 sizeof
中表达式不计算
针对第2点,让我们来看看下面的代码
#include <stdio.h>
int main()
{
//测试:sizeof中表达式不计算
short s = 2;
int b = 10;
printf("%d\n", sizeof(s = b + 1));
printf("s = %d\n", s);
}
让我们来看看运行结果
2
s = 2
很明显s最终并不是b + 1,说明 sizeof中表达式不计算 。
现在我来解释一下哈:
`sizeof`在代码进行编译的时候,就根据表达式的类型确定了,类型的常用,而表达式的执行却要在程序运行期间才能执行,
在编译期间已经将sizeof处理掉了,所以在运行期间就不会执行表达式了。
1.5.3 sizeof
的占位符
针对第4点,让我们来看看下面的代码
#include <stdio.h>
int main()
{
int a = 10;
printf("%zd\n", sizeof(a)); // 4
printf("%zd\n", sizeof a ); // 4 a是变量名,可以省略sizeof后边的()
printf("%zd\n", sizeof(int)); // 4
printf("%zd\n", sizeof(3 + 3.5)); // 8
return 0;
}
1.5.4 数据类型长度
看下面代码,来比较各类型的长度
#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)); //8
}
其实C语言标准规定,sizeof(long) > sizeof(int) ,虽然大小都是4个字节
二、signed 和 unsigned
1. 简介 signed 和 unsigned
C语言中,signed
和 unsigned
关键字修饰 字符型和整型 类型的。
其中, signed
关键字,表示 有符号 ,表示一个类型带有正负号,包含负值;而 unsigned
关键字,表示 无符号 ,只能表示零和正整数。
2. 对于 int 类型
一般来说,对于 int
理性,默认是带有正负号,也就是说 int
等同于 signed int
,所以 signed
一般都省略不写。
signed int a; // 写成 int a也对
unsigned int b; // 表示非负整数
3. 对于 char 类型
字符类型 char
也可以设置 signed
和 unsigned
signed char c; // 范围为 -128 到 127
unsigned char c; // 范围为 0 到 255
注意: C语言规定 char
类型默认是带有正负号,由当前系统决定。
这就是说,char 不等同于 signed char ,它有可能是 signed char,也有可能是 unsigned char。但大部分编辑器,char = signed char。
这一点与 int
不同, int
就是等同于 signed int
。
三、变量
1. 变量的创建
上面,我们已经了解了类型,类型是用来 创建变量 的。
变量的创建实质上是对内存的申请
变量创建的格式:
数据类型 + 变量名;
比如:
int age; // 整型变量
char ch; // 字符变量
double weight; // 浮点型变量
如果在创建的时候就给一个初始值,就叫 初始化
int age = 18;
char ch = 'w';
double weight = 48.0;
unsigned int height = 100;
对于第一个来说,它实质上是指向内存申请4个字节空间,存放的是10。
2. 变量的类型
-
全局变量 :在大括号外部定义的变量。
全局变量的使用范围更广。
-
局部变量 : 在大括号内部定义的变量
范围比较局限,只能在自己所在的局部范围内使用
建议: 能使用局部变量,尽量使用局部变量;必须使用全局变量的时候,再使用全局变量。
#include <stdio.h>
int global = 2023; // 全局变量
int main()
{
int local = 2018; // 局部变量
printf("%d\n", local);
printf("%d\n", global);
return 0;
}
注: 当局部变量和全局变量同名时,局部变量优先使用
比如:
#include <stdio.h>
int n = 1000; // 全局变量
int main()
{
int n = 10; // 局部变量
printf("%d\n", n);
return 0;
}
打印结果为:
10
3.全局变量和局部变量再内存中存储的位置
一般在学习C/C++语言的时候,我们会关注内存中的三个区域:栈区 、 堆区 、 静态区。
- 局部变量 是放在内存的 栈区
- 全局变量 是放在内存的 静态区
- 堆区 是用来 动态内存管理 的
四、操作符
1. 算术操作符:+ 、- 、* 、/ 、%
算术操作符,+ - * / %
,被称为双目操作符,也就是两端都有操作数
#include <stdio.h>
int main()
{
int x = 4 + 12; // 加
int y = 61 - 23;
printf("%d %d\n", x, y);
int num = 5;
printf("%d\n", num * num); // 乘
float a = 6 / 4;
int b = 6 / 4;
printf("%f %f\n", a, b); // 除 1.000000 1
int c = 6 % 4; // 2
return 0;
}
注:
-
上面除法运算中,a 虽然是 float 类型,但由于是整数除法,所以结果会取整数,再变成浮点类型。如果是
6 / 4.0
,那么结果就是1.500000
。 -
对于
%
求模运算中,要格外注意, 这个运算符只能用于整数,不能用于浮点数 。负数求模的规则是,结果的正负号由第一个运算数的正负号决定。
2.赋值运算符 := 和复合赋值
首先让我们来区分一下初始化和赋值
int a = 100; // 初始化
a = 200; // 赋值
赋值操作符 =
是一个随时可以给变量赋值的操作符
注: 这里是一个 =
,以后会学到两个 ==
,注意区分。
2.1 连续赋值
赋值操作符可以连续赋值,如:
int a = 3;
int b = 5;
int c = 6;
c = b = a + 3;// 连续赋值,从右向左依次赋值
虽然C语言支持连续赋值,但这样不容易理解,建议拆开来写。
2.2 符合赋值符
写代码时,经常会遇见 自加 和 自减 的情况,比如:
int a = 10;
a = a + 3;
a = a - 2;
为了方便,我们可以使用 +=
和 -=
来写,如下:
int a = 10;
a += 3;
a -= 2;
C语言提供了很多复合赋值符
+= 、 -= 、 *= 、 /= 、 %=
>>= 、 <<=
&= 、 |= 、 ^=
3. 弹幕操作符 :++ 、-- 、+ 、 -
3.1 ++
和 --
++
是自增操作符,又分为 前置++ 和 后置++ ,--
同理
3.1.1 前置++
int a = 10;
int b = ++a;
printf("a = %d b = %d\n", a , b ); // 11 11
计算口诀:先加1,后使用
3.1.2 后置++
int a = 10;
int b = a++;
printf("a = %d b = %d\n", a , b ); // 11 10
计算口诀:先使用,后+1
总结: 如果是 b = a++
,可以看出来,先 b = a ,然后再 a++ 。
3.2 +
和 -
这里的 +
和-
,不是加法和减法,而是 正号 和 负号 的意思,都是 单目操作符 。
int a = +10; // 等价于 int a = 10
int b = -a; // b = -10
+
对正负无影响,可以完全省略; -
就是改变一个值的正负号。
五、强制类型转换
强制类型转换的语法形式很简单
(类型)
请看具体示例代码:
int a = 3.14;
// a 是 int 类型,3.14是 double 类型,两边类型不一致,编译器会报警告
为了消除警告,我们使用强制类型转换
int a = (int)3.14;
// 意思是将3.14强制类型转换为 int 类型,这种强制类型转换只取整数部分
这中强制类型转换有极大的好处,但也可能造成数据遗失。