文章目录
Hello,我们今天来讲C语言变量的一些知识。
什么是变量呢?
在C语言中把变的量叫做变量,不变的量叫做常量。
举几个例子:
变量:年龄,身高,体重,工资……
常量:血型,出生日期……
变量的创建
前面的博客,我们讲到了数据类型
那么我们用数据类型干什么的呢?
用来创建变量。
变量创建的语法形式是这样的:
data_type name;
1.数据类型 2.变量名
变量命名d一般规则:
- 只能由字母(包括大写和小写)、数字和下划线(
_)组成。 - 不能以数字开头。
- 长度不能超过63个字符。//一般名字也不会写这么长
- 变量名中区分大小写的。
- 变量名不能使用关键字。//一般可以这样命名:int_3,就是不可以是单独的int这个关键词。
在命名的时候,最好要写一个望文生义的名字(因为可以增加可读性,让别的程序员也可以比较容易读懂你代码的意思),特别是后面博客要讲的函数的函数名。比如你要打印一个1~10的数,你想封装一个函数来实现它,你就可以将这个函数名命名为print。
常见的变量创建:
int age; //整型变量
char ch; //字符变量
double weight; //浮点型变量
变量在创建的时候就给⼀个初始值,就叫初始化。
int age = 18;
char ch = ‘w’;
float score=89. 5f;
double weight = 48.0;
unsigned int height = 100;
//要是不想在创建时初始化当然也可以了
int age;
age=20;//这样也是可以的
- 这里有一个特别的点,最好还是要初始化的,防止以后使用时,忘了初始化,导致程序错误。
- 提前提一下,对于全局变量,未初始化默认为0,对于局部变量,未初始化为随机值(可能各种编译器表现形式不同,有的会打印出随机值,有的直接编译不通过)。
诶,细心的朋友肯定看到了第三行的89.5f,为什么在89.5的后面加一个f呢?因为在编译器中会默认小数为double类型,加一个f就告诉编译器这个小数是float类型。
诶,那我们这样定义可以吗?
int age=10;
int age=20;
那当然不可以,要是你后面想要使用它,那你要使用那个a呢?那就有问题了,所以编译器会报一个重定义的错误。
变量的分类
变量分为全局变量和局部变量。
- 全局变量:在大括号外部定义的变量就是全局变量。//就算是在所有函数的末尾,那也可以,因为全局变量具有 “文件作用域”,编译器会自动解析整个文件的全局变量。
全局变量的使用范围更广,整个工程中想使用,都是有办法使用的。 - 局部变量:在大括号内部定义的变量就是局部变量。
局部变量的使用范围是比较局限,只能在自己所在的局部范围内使用的。
#include <stdio.h>
int global = 2023;//全局变量
int main()
{
int local = 2018;//局部变量
printf("%d\n", global);//可以打印
printf("%d\n", local);//可以打印
return 0;
}
这里举一个形象的比喻,把全局变量比作共享单车,把局部变量比作私家自行车。共享单车谁都可以用,而私家车当然就你和你家里人能用啦。
这时就有一个问题了?当全局变量和局部变量名一样的时候, 用谁呢?
#include <stdio.h>
int n = 1000;
int main()
{
int n = 10;
printf("%d\n", n);//打印的结果是多少呢?
return 0;
}
结果是10。
其实当局部变量和全局变量同名的时候,局部变量优先使用。//同样用自行车的比喻很好理解,有了私家自行车,谁还有共享单车啊。
全局变量和局部变量在内存中存储在哪里呢?
我们会将书存储在书架上,同样的,变量也就存放在内存中。
我们在学习C语言的时候,我们会关注
内存中的三个区域:栈区、堆区、静态区。
- 局部变量是放在内存的栈区。
- 全局变量是放在内存的静态区。
- 堆区是用来动态内存管理的(后期会介绍)
其中狭义的动态区就是堆区,广义的动态区是堆区和栈区。(狭义动态区是认为需要内存空间时,是自己手动设置的才算动态的,广义动态区则是认为需要内存空间时,自己手动设置的和编译器自己设置的都是动态区)
总结:狭义动态区中“动态” 强调 “手动控制”,广义动态区中“动态” 强调 “运行时分配”,这俩种没有绝对的好坏,只要你能明确自己说的是哪种定义,两种说法都是合理的,两种说法都能被接受,只是适用场景不同。
一般我们学习的时候用的是狭义的,比如以后的博客都会是狭义的。

操作符(部分)
那么我们怎么使用变量呢?
就是用操作符,称呼偏向于对象(也叫运算符,称呼偏向于过程)了。
(有一些需要之后的知识的,之后会讲,先讲常用的)
操作符的基础知识
操作符有优先级和结合性(后面博客会详细讲解)
- 优先级就是在一个变量左右俩边有不同的操作符时,谁先用这个变量呢?这就有优先级去决定,谁的优先级高,谁先来用。(比如我们常用的先算乘除后算加减就是优先级的体现)
- 结合性就是在有多个连续并且相同的操作符时,是从左到右运算,还是从右到左呢?

- 有三类运算符是从右到左的。
- 所有双目运算符中只有赋值运算符的结合方向是从右往左。
- 另外两个从右往左结合的运算符也很好记,因为它们很特殊:一个是单目运算符,一个是三目运算符。
算数操作符
分别有+ - * / %,它们都是双目操作符,
什么叫双目呢?
双目就是有俩个操作数,当然也有单目(有一个操作数)和三目(有三个操作数)了。
+ 、-、*、/
其实就是我们小学就学过的加减乘除,不过在编程中有一些要注意的点,就是除号的使用。
#include<stdio.h>
int main()
{
int a=10;
int b=20;
float c=10.0;
float x1=6/4;
float x2=6.0/4;
printf("%d\n",a+b);// +
printf("%d\n",a-b);// -
printf("%d\n",a*b);// *
printf("%f\n",a/b);// /
printf("%f\n",c/b);// /
printf("%f\n",x1);// /
printf("%f\n",x2);// /
return 0;
}
在前面俩个使用除法的地方,我们用了"%f"打印小数(这个叫占位符,之后的博客会讲),按照数学上的算法,应该俩个都是0.5才对吧,但实际上只有第二给除法才是0.5,第一个为0。
那为什么呢?
我们看到了10/20结果为0,那会不会是接受的变量要是float类型才可以呢?那我们来看第三个除法那里,打印出来的是1,所以说和接受结果的变量的类型并无关系,从这四个除法中,我们很容易发现,当我们将10写成10.0,将6写成6.0的时候,答案就符合我们的预期了。
- 原因就在于 C 语言里的整数除法是整除,只会返回整数部分,丢弃小数部分(比如你6/4,按照这个规则就是商1余2,而我们要的就是这个1,所以算不出来1.5的,是这样算的)。
- 如果希望得到浮点数的结果,两个运算数必须至少有⼀个浮点数,这时 C 语言就会进行浮点数除法。
再举一个例子:
#include <stdio.h>
int main()
{
int score = 5;
int score1= 0;
int score2= 0;
score1 = (score / 20) * 100;
score2 = (score / 20.0) * 100;
printf("%d\n",score1);
printf("%d\n",score2);
return 0;
}
- 和那个同理机器先算的是大括号里面的内容,可不会像我们一样还将括号拆开来算的,所以自然一个是0(因为用的是整数除法,是整除),一个是25了(因为用的是浮点数除法)。
- 当然,还有一个点就是
score2 = (score / 20.0) * 100;这个会报警告,为什么?因为score是int类型而20.0是double类型的,所以算出的结果是double类型的,乘上一个100也是double类型的,而score2是int类型的,在赋值时会截断,所以有丢失数据的可能所以会报警告。(复习了上个博客的知识)
%
% 是取模(余)运算符,表示求模(余)运算,即返回两个整数相除的余数。这个运算符只能用于整数,不能用于浮点数。(前面我们说 C 语言里的整数除法是整除,只会返回整数部分,丢弃小数部分,而取模就是要的余数,可以认为是一对的,当然浮点数自然就不宜用了,毕竟浮点数哪来的余数呢?)
#include <stdio.h>
int main()
{
int x = 6 % 4;
printf("%d",x);//2
return 0;
}
负数求模的规则是,结果的正负号由第⼀个运算数的正负号决定。
#include <stdio.h>
int main()
{
printf("%d\n", 11 % -5); // 1
printf("%d\n",-11 % -5); // -1
printf("%d\n",-11 % 5); // -1
return 0;
}
上面示例中,第⼀个运算数的正负号( 11 或 -11 )决定了结果的正负号。(并非我们想的只存在一个负数,余数就是负数,只存在整数或只存在负数,余数就是整数的)
赋值操作符:=和复合赋值
在变量创建的时候给⼀个初始值叫初始化(初始化用的好像是赋值操作符,其实不是,他们是语法上一样,语义上不同,初始化的=我们叫它 “初始化赋值符”,重点是强调它是 “为变量赋初始值” 的语法标识,和后续的 “赋值操作符” 区分开,它不是赋值操作符,比如const常量(后面会讲,它可以让别人修改不了我们的变量值)允许初始化=,但禁止赋值=),在变量创建好后,再给⼀个值,这叫赋值。
int a = 100;//初始化
a = 200;//赋值,这里使用的就是赋值操作符
- 赋值操作符 = 是⼀个随时可以给变量赋值的操作符。
连续赋值
赋值操作符也可以连续赋值,如:
int a = 3;
int b = 5;
int c = 0;
c = b = a+3;//连续赋值,从右向左依次赋值的。
但是为了方便理解和方便调试,最好还是写分开写。
int a = 3;
int b = 5;
int c = 0;
b = a + 3;
c = b;
复合赋值符
int a=10;
a=a+10;//这么写是不是有点麻烦呢?有没有什么方法可以在这种自增的时候可以书写简便一点呢?C语言也考虑到了这一点
a+=10;//这个等价于上面的但是书写更加简便
当然a*=10;//等等都是一样的,以此类推即可
复合赋值符有:
+= -=
*= /= %=
//下面的操作符后期讲解
&=, |=, ^=, >>= ,<<=
单目操作符:++、- -、+、-
- 前面讲解的操作符都是双目操作符,有2个操作数的。C语言中还有一些操作符只有一个操作数,被称为单目操作符。
- ++、- -、+(正)、-(负) 就是单目操作符的。
++、- -
++、- -分为前置++,后置++,前置- -,后置- -。
前置++
#include<stdio.h>
int main()
{
int a = 10;
int b = ++a;//++的操作数是a,是放在a的前面的,就是前置++
printf("a=%d b=%d\n",a , b);//b为11,a也为11
return 0;
}
- 计算口诀:先+1(先++),后使用;
a原来是10,先+1(先++),后a变成了11,再使用就是赋值给b,b得到的也是11,所以计算技术后,a和b都是11,相当于这样的代码:
#include<stdio.h>
int main()
{
int a = 10;
int b;
a = a+1;
b = a;
printf("a=%d b=%d\n",a , b);
return 0;
}
后置++
#include<stdio.h>
int main()
{
int a = 10;
int b = a++;//++的操作数是a,是放在a的后⾯的,就是后置++
printf("a=%d b=%d\n",a , b);//a为11,b为10
return 0;
}
计算口诀:先使用,后+1(后++)
a原来是10,先使用,就是先赋值给b,b得到了10,然后再+1(再++),然后a变成了11,所以直接结束后a是11,b是10,相当于这样的代码:
#include<stdio.h>
int main()
{
int a = 10;
int b = a;
a = a+1;
printf("a=%d b=%d\n",a , b);
return 0;
}
前置,后置- -
与上文一样的形式,一样的口诀,以此类推。
+、-
+(正),-(负),其实没什么的,和我们数学上的正负没什么区别,就是10就是+10,+可以省略,加一个-可以使得10变为负值即-10,也可以在-10前加一个-变为10。
强制类型转换
在操作符中还有⼀种特殊的操作符是强制类型转换,语法形式很简单,形式如下:
(数据类型)
有的时候可用可不用强制类型转换操作符,如:
#include<stdio.h>
int main()
{
int a=(int)3.14;//意思是将3.14强制类型转换为int类型,这种强制类型转换只取整数部分,自己手动截断,转换
printf("a=%d\n",a);
return 0;
}
这里编译器可以自己转化(有的编译器会报警告,告诉你这样,可能会丢失数据),但是你不担心丢失数据的话,也不想自己转换类型,编译器就可以转换。
- 俗话说,强扭的瓜不甜,我们使用强制类型转换都是万不得已的时候使用,如果不需要强制类型转化就能实现代码,这样自然是更好的。(最好在要截断的地方加上强制类型转换操作符,比如上面的例子)
提前说一个知识点:
一般在malloc(以后就讲)会用到强制类型转换操作符,C里面是可用可不用,但是在C++中是必须要用的,所以最好要用。
总结
谢谢观看!
3118

被折叠的 条评论
为什么被折叠?



