目录
📝学习预警:
下面文章我们将学习变量(变量的创建、命名、初始化、分类),操作符(赋值操作符、算术操作符(单目和双目)、强制类型转换),
- 算术操作符在printf中
- 1、对一个变量进行一次读取和修改
- 2、对一变量多次读取和修改,
- 强制类型转换中还拓展了隐式类型转换,并粗略讲解了字符型和整型的线性运算、并且整型和字符型可以相互转换
1️⃣变量
1.1、变量的创建
❓在数据类型的那篇文章中我们已经学习了数据类型,那么这些类型有什么用呢?
- 类型是为了创建变量
变量创建语法:数据类型+变量名
data_type name
1.1.1、变量的命名规则
- 只能由字母(大小写均可)、数字、下划线
-
组成 - 长度不可超过63个字符
- 不可以用数字开头
- 不能使用关键字
- 变量名是区分大小写的
int a_11;
int a_;
int _11;
int _2b;
以上写法均可
int a;//整型变量
char c;//字符变量
double d;//浮点型变量
······
***************
但不可以:
int char;
int 12h;
int 12_;
1.1.2、变量初始化
在变量的创建时就给一个初始值,就叫初始化
int age=10;
char ch = 'w';
double weight = 50.8;
❗️注意:
float a = 10.3;//10.3在编译器是认为double类型的
double c = 10;
float d = 18.4f;//在小数后面加个 f 才可以被认为是float类型
1.1.3、变量的分类(局部/全局)
- 全局变量:在大括号外面(main函数外)定义的变量就是全局变量
- 使用的范围更广,在整个项目中想使用都可以使用到
- 局部变量在大括号内部定义的变量就是局部变量
- 使用的范围局限,只能在自己所在的范围内使用
- ❗️当局部变量和全局变量的变量名同时, 局部变量的优先级高于全局变量
- 可以理解成大括号内就是自己的家,括号外是社会
- 局部变量好比是自己家里的电动车
- 全局变量好比共享电动车车
- 自家有车还开什么共享的车
#include<stdio.h>
int a = 10;//全局变量
int main()
{
//int a = 100;//局部变量
int b = 10;//局部变量
int c = 0;
c = a + b;
//当局部变量a没有被注释掉,就是100+10=110(a+b)
//变量名同,局部变量优先级高
//当局部变量被注释掉了,就是10+10=20(a+b)
printf("c = %d\n", c);
return 0;
}
📌局部变量和全局变量在内存的存储位置
- 变量创建的本质是:在内存中申请一块空间
我们在学习C语言时,会关注内存的三个区域:栈区、堆区、静态区
- 局部变量放在内存的栈区
- 全局变量放在内存的静态区
- 堆区是用来动态内存管理的
2️⃣赋值操作符:=
在变量创建的时候给一个初始值是初始化;而变量创建好后,再给一个值,是赋值
int a =10;//初始化
a = 90;//赋值
int b;//未初始化
b = 20;//赋值
🤔我们为什么要初始化呢?
- 在未初始化时,局部变量的值时随机值;而全局变量的值是0
在尝试时,在vs2022会报错,可以使用vscode来运行,但我试了发现全局和局部结果都是0,全局一定是0;局部一定是随机数
- 赋值操作符
=
是一个可以随时给变量赋值的操作符
2.1、连续赋值
#include<stdio.h>
int main( )
{
int a = 3;
int b = 4;
int c ;
c = b = a + 3; // 连续赋值,从右到左依次赋值
printf("%d", c);
return 0;
}
不建议连续赋值,因为这样对代码的解读能力差,建议拆开来写,这样方便观察代码,如下:
#include<stdio.h>
int main()
{
int a = 3;
int b = 4;
int c;
b = a + 3;
c = b;
printf("%d", c);
return 0;
}
2.2、复合赋值符
我们在写代码时会对一个数进行加减乘除,如下:
int a = 10;
a = a + 3;
···
我们可以使用简便的写法,如下:
int a = 10;
a += 3;//相当于a= a+3
a -= 3;//a =a-3
a *= 3;//a = a*3
a /= 3;//a =a/3
a %= 3;//a =a%3
···
- 复合赋值符有:
+=
、-=
、*=
、/=
、%=
>>
、<<=
、&=
、|=
、^=
3️⃣算术操作符
- 操作符 = 运算符(只是翻译不同罢了)
3.1、双目操作符:+
、-
、*
、/
、%
可以理解成双目操作符是有两个操作数的,位于操作符两端的就是它们的操作数
3.1.1、+
加 和 -
减
- 加法和减法
#include<stdio.h>
int main()
{
int a = 100;
int b = 10 - 5;//-
int c = 0;
c = a + b;//+
printf("c = %d\n", c);
//105
printf("c = %d\n", a + b);//+
//105
return 0;
}
3.1.2、*
乘
- 乘法
#include<stdio.h>
int main()
{
int a = 10;
int b = 2 * 5;//*
int c = 0;
c = a + b;//+
printf("c = %d\n", c);
//20
printf("c = %d\n", a * b);//*
//100
return 0;
}
3.1.3、/
除
- 除法
- 除号两端是整数,就是整数除法,最终结果也是整数
#include<stdio.h>
int main()
{
//因为9和5都是整型,相除后还是整型,取整数(不用四舍五入,直接取整数)
//取得整数1后,因为a是浮点型,输出1.000000
float a = 9 / 5;
printf("a = %f\n", a);
//因为6和4都是整型,相除后还是整型,取整数(不用四舍五入,直接取整数)
//取得整数1,输出1
int b = 6 / 4;
printf("b =%d\n", b);
//占位符不要乱用,因为a是浮点型,不应该用%d,下面的b的道理相同
//下面两个都是错误的写法,不要学习
printf("a = %d\n", a);
printf("b =%f\n", b);
return 0;
}
如果希望得到浮点数,那么必须在两个操作数中至少有一个是浮点数,这样才可以进行浮点数除法
#include<stdio.h>
int main()
{
//注意5.0是double类型,如果改成5.0f就是float类型
//因为9是整型,5.0是浮点型,相除后就变成浮点型
//因为a是浮点型,输出1.800000
float a = 9 / 5.0;//或者是9.0/5,或者是9.0/5.0
printf("a = %f\n", a);
//下面的写法相当于是将double[9 / 5.0]类型转换成int[b]类型(这个是自动转换的),可能存在数据丢失的情况
//因为将8字节的数据放进4字节的空间里
//不建议这么写
int b = 9 / 5.0;
printf("b = %d\n", b);
return 0;
}
3.1.4、%
取余数
- 取余:返回两个整数相除的余数。
- 这个操作符只能用于整数之间,不可以浮点数
- 负数取余的规则:结果的正负号由第一个运算数决定,只要第一个运算数是负数结果就是负数
#include<stdio.h>
int main()
{
int a = -5;
int b = -2;
int c;
c = a % b;
printf("%d", c);//-1
return 0;
}
3.2、单目操作符:++
、--
、+
、-
在C语言中有一些操作符时只有一个操作数,则该操作符被称为单目操作符
3.2.1、++
自增前置和后置
++
是一个自增的操作符,分别由前置和后置自增;
💥3.2.1.1、++
前置
int a = 10;
int b = ++a;
printf("a = %d\nb = %d\n",a,b);
******************************
输出结果:
a = 11
b = 11
先+1(自增),后使用
上面的代码相当于下面的:
int a = 10;
//a 先 +1(自增),变成 11
a = a + 1; //11
//后使用,将a 的值赋给 b
int b = a; //11
printf("a = %d\nb = %d\n", a, b);
💥3.2.1.2、++
后置
int a = 10;
int b = a++;
printf("a = %d\nb = %d\n",a,b);
******************************
输出结果:
a = 11
b = 10
先使用,后+1(自增)
上面的代码相当于下面的:
int a = 10;
//先使用,将a 的值赋给 b
int b = a; //10
//后面 a 要 +1(自增),变成 11
a = a + 1; //11
printf("a = %d\nb = %d\n", a, b);
📌附1:在printf中如果其
作为打印的参数会如何?
- 有些时候刷题或者考试时会看到
printf
的函数中使用了自增(或自减) - 后续自减就不讲这个了,原理是一样的
- 比如:
printf("a = %d\n", a++);
底层逻辑:
这些语句打印的就是变量a每一步变化后的值
。每执行一次a++或++a,a的值都会发生变化,打印出来的就是变化后的结果。
- 具体来说:
a++
:打印的是自增前的a,打印后a加1。++a
:先让a加1,再打印自增后的a。可以简记成:打印的是 a++ / ++a 的值
从下面的代码中可以看出其在printf中自增变化的:
#include<stdio.h>
int main()
{
int a = 0;
a++;//a == 1 ;a++ == 0
printf("a = %d\n", a); // 1
//首先a == 1
//其次a++,a自增变成-->a == 2;a++ == 1
//因为打印a++,所以输出结果为 1
printf("a = %d\n", a++); //1
//首先a == 2
//其次++a,a自增变成-->a == 3;++a == 3
//因为打印++a,所以输出结果为 3
printf("a = %d\n", ++a); //3
return 0;
}
📌附2:在printf中如果有多个其
作为打印的参数会如何?(只作为拓展)
这个只是拓展,但非常不建议这么写,要写也是分开写,
- 语法上,这样写是合法的,编译不会报错。
- 但这样写不推荐,因为你在一个表达式(printf参数列表)中多次对同一个变量a进行自增(a++、++a)[或自减)],这会导致未定义行为。
- C语言标准规定:如果在一个表达式中对同一个变量既有多次修改又有读取,结果是不可预期的。
- 为什么最终结果是这样呢❓
- a++:先用a当前的值,后自增。
- ++a:先自增,后用a的新值。
- 但在同一个printf参数列表里,编译器对参数求值的顺序没有规定,所以每次运行的结果可能不同,不同编译器、不同优化设置下结果也可能不同。
#include<stdio.h>
int main()
{
int a = 0;
printf("a = %d\na++ = %d\n++a = %d\na++ = %d\na++ = %d\n++a = %d\n", a, a++ ,++a,a++, a++, ++a);
/*运行结果
a = 5
a++ = 4
++a = 5
a++ = 2
a++ = 1
++a = 5
*/
return 0;
}
📌附3:多次对某一变量的修改和读取(本质和“附2”一样)
这个只作为例子,不讲解,本质和附2一致
不建议这么写
#include<stdio.h>
int main()
{
int a = 1;
int r = (a++) + (a++) +(++a);
printf("%d",r);
return 0;
}
*******************************
在vs2022中输出结果为:6
在vscode章输出结果为:7
3.2.2、--
自减前置和后置
--
是一个自增的操作符,分别由前置和后置自增;
💥3.2.1.1、--
前置
int a = 10;
int b = --a;
printf("a = %d\nb = %d\n",a,b);
******************************
输出结果:
a = 9
b = 9
先-1(自减),后使用
上面的代码相当于下面的:
int a = 10;
//a 先 -1(自减),变成 9
a = a - 1; //9
//后使用,将a 的值赋给 b
int b = a; //9
printf("a = %d\nb = %d\n", a, b);
💥3.2.1.2、--
后置
int a = 10;
int b = a--;
printf("a = %d\nb = %d\n",a,b);
******************************
输出结果:
a = 9
b = 10
先使用,后-1(自减)
上面的代码相当于下面的:
int a = 10;
//先使用,将a 的值赋给 b
int b = a; //10
//后面 a 要 -1(自减),变成 9
a = a - 1; //9
printf("a = %d\nb = %d\n", a, b);
3.2.3、+
正号和-
负号
- 运算符
+
对一个数没有什么影响,是一个可以忽略的运算符,但是写了也不错 - 运算符
-
是改变一个数的正负号
例如:
3.3强制类型转换
强制类型转换在大多数编程语言(如 C、C++、Java 等)中被视为一种操作符,强制类型转换是一种 显式的一元操作符,用于主动改变数据的类型,并遵循操作符的优先级规则。
语法:(type_name) expression
int a = 3.24;
//a是int类型,然而3.24是double类型,类型不一致,会警告丢失数据
*******************
*******************
要消除这个警告,我们就需要强制转换类型了
int a = (int)3.24;
//将3.24强制转换为int类型(只取整数部分,不会四舍五入)
#include <stdio.h>
int main()
{
int a = 17;
int b = 5;
double c;
//如果是下面的形式,输出的c = 3.000000;先是整数除法,只取整数部分,后面再转换为浮点型
c = a / b;
printf("c= %f\n", c);
//下面是强制类型转换,输出的c = 3.400000
c = (double)a / b;
printf("c= %f\n", c);
return 0;
}
📌附:隐式类型转换(整型提升)(拓展)
- 当字符型与整型进行运算时,编译器会自动将字符隐式转换为整数(称为 整型提升)
例如:
为什么下面的代码字符和整型可以线性运算,并且sum明明是整型却可以输出字符型呢❓(无报错,无警告)
#include <stdio.h>
int main()
{
int i = 17;
char c = 'c'; // ASCII 值是 99
int sum;
sum = i + c;
printf(" sum : %d\t%c\n", sum,sum);// 输出116 t
return 0;
}
因为:在编程语言中,字符型(
char
)和整型(int
)变量可以进行线性运算,是因为字符(ASCII码)在底层实际上是以整数的形式存储的。
为什么允许这种操作?
- 历史原因:C 语言早期设计中将字符视为整数,这种特性被后续语言继承(如 C++、Java 等)。
- 灵活性:字符的整数表示允许直接操作字符的编码。例如:
- 大小写转换:
'A' + 32
得到'a'
(因为65 + 32 = 97
)。 - 字符偏移:
'0' + 5
得到'5'
(因为48 + 5 = 53
)。
- 大小写转换:
✒️作者小结:
以上教学了变量、赋值操作符、算术操作符的使用
- 如果哪里有错误或不完整,欢迎大家指出来,我会积极进行修改
- 谢谢大家的阅读🌹🌹🌹