常量与变量
常量
在程序运行过程中,其值不能被改变的量;常量一般出现在表达式或赋值语句中。
类型 | 举例 |
---|---|
整型常量 | 100 , 200 , -100 , 0 |
实型常量 | 3.14 , 0.125 , -3.123 |
字符型常量 | 'a' , ‘b’ , ‘1’ , ‘\n’ |
字符串常量 | “a” , “ab” , “12356” |
为常量定义名字
当程序含有一些有特殊意义的常量时 (比如 32.0f),建议给这些常量定义名字,以免别人在阅读程序不知道这个常量的含义。在 C 语言中我们可以采取宏定义的方式给常量命名:
#define FREEZING_PT 32.0f
这里的 #define
是预处理指令,类似于 #include
,因而结尾处也没有分号。在预处理阶段,预处理器会把每一个宏替换为其表示的值。
我们还可以利用宏来定义表达式,如:
#define SCALE_FACTOR (5.0f / 9.0f)
当宏表示一个表达式时,我们最好用括号把表达式括起来 (why?)。
因为宏定义在编译处理中是直接的替换操作,如果不使用括号括起来表达式编译之后很可能会带来一些语义错误的问题。
更多细节参考 预处理章节 中的宏定义。
变量
很少有程序会像 HelloWorld.c 那样简单。大多数程序在产生输出之前都需要执行一系列的计算,因此需要在程序执行过程中有一种临时存储数据的方法。和大多数编程语言一样,C语言中的这类存储单元被称为变量 (variable)。
既能读又能写的内存对象,称为变量;若一旦初始化后不能修改的对象则称为常量。
- 在程序运行过程中,其值可以改变
变量的本质就是一片内存空间。
要想在程序中使用一个变量,首先需要声明变量。声明变量的意义是确定变量的数据类型以及变量名。
声明
在使用变量之前必须对其进行声明,声明的格式如下:
类型 变量名;
例如,我们可以这样声明变量
float m;
int a;
如果几个变量具有相同的类型,我们可以把它们的声明合并:
类型 变量名1, 变量名2, … , 变量名n;
int b, c, d, e;
float n, l, k;
变量为什么需要类型?
- 确定内存空间的大小
- 指定编码方式
- 定义数据的操作
当变量的类型确定了,其所能存放的值的范围也就确定了。
从内存的角度来理解变量的声明(重要)
在一个C程序的编译阶段(程序未执行),当编译器编译到变量声明的语句时,编译器会识别变量的类型、名字等属性。待到程序运行,就可以根据这些确定的信息,在虚拟内存空间中为变量分配实际的内存空间。
对于一个局部变量而言,它是没有默认值的,如果不手动对它进行赋值,那么它的值是。也就是说,它的值究竟是多少,谁也不知道。
所以在C语言中,一个局部变量如果仅有声明,是不可用的。使用一个仅声明的局部变量,就是使用随机的、未定义的值,将会产生随机的、。
所谓未定义行为:指的是程序行为并未在标准中明确规定的场景,可能导致程序崩溃,可能给出一个莫名其妙的结果,也可能报错。
总之,未定义行为对C程序而言是非常严重的错误,C程序员要十分小心,规避程序中的未定义行为。
赋值
变量通过赋值操作获取值。给变量赋值,最简单的做法,就是用一个赋值运算符"="连接一个字面常量取值。如
height = 8;
length = 12;
width = 10;
我们通常会把一个浮点数赋值给 float 类型的变量,而且往往会在浮点数后面添加字母f。如:
profit = 2150.48f;
一旦变量被赋值,我们就可以用它来计算其他变量的值:
height = 8;
length = 12;
width = 10;
volumn = height * length * width;
声明与定义的区别
- 声明变量不需要建⽴存储空间,如:
extern int a;
- 定义变量需要建⽴存储空间,如:
int b;
#include <stdio.h>
int main(void) {
//extern 关键字只做声明,不能做任何定义,后⾯还会学习,这里先了解
//声明一个变量a,a在这里没有建⽴存储空间
extern int a;
a = 10;//err, 没有空间,就不可以赋值
int b = 10;//定义一个变量b,b的类型为int,b赋值为10
return 0;
}
从⼴义的角度来讲声明中包含着定义,即,所以并非所有的声明都是定义:
int b;
它既是声明,同时又是定义- 对于
extern b;
来讲它只是声明不是定义
一般的情况下,把建⽴存储空间的声明称之为“定义”,而把不需要建⽴存储空间的声明称之为“声明”。变量在使用之前必须进行定义,如果你写的代码没有定义只进行了声明,编译器会默认将变量声明提升为变量定义;这就涉及到extern声明的变量⽆法被编译器⾃动提升为变量定义。
初始化
当程序开始执行时,某些变量会被自动设置为零,而大多数变量不会。没有默认值并且尚未在程序中被赋值的变量是未初始化的。
仅声明的局部变量是不可用的,在使用该局部变量之前,还需要初始化局部变量。 变量的初始化,可以视为第一次给变量赋值。 在C语言中,某些变量类型在编译过程会被赋予默认零值,具有默认初始化。但局部变量,并没有默认初始化,必须进行手动初始化赋值。
一个手动初始化的语法参考如下:
int length = 100;
float width = 0.1f;
声明是,编译器为变量预分配了内存空间,而变量初始化是在程序运行时给予了变量一个初始值。
我们当然可以采用赋值的方式给变量赋初始值,但C语言还提供了一个更简便的方法:在声明变量的同时赋初始值。
定义
- 变量的定义是声明一个变量,并且为之分配内存空间的组合动作。
- 变量的定义意味着,告诉编译器变量的类型和名称,而且在程序运行时要确定给此变量分配内存空间。
- 很多同学,会被"变量的定义"这个概念搞混淆,它和"变量的声明"有什么区别呢?
- 实际上,变量的定义一定是变量的声明。
- 但变量的声明不一定就是变量的定义。也就是说,某些特殊的变量声明,在程序运行时期不会为此变量分配内存空间。
声明、初始化、赋值和定义(重要)
在C语言中,变量的声明、初始化、赋值和定义都有严格的定义,它们是截然不同的几个概念。在这里,我们做一下区分:
- 变量的声明:声明是给编译器看的,告诉编译器变量的类型和名字等信息,但变量的具体内存分配发生在运行时期。
- 变量的初始化:初始化是变量的第一次赋值。
- 变量的赋值:初始化一定是赋值,但赋值不是初始化。C语言中的赋值专指在变量已经初始化赋值以后,再次赋值。
一行执行多个操作
C语言允许一行声明多个变量,一行给多个变量赋值,一行进行多个变量的初始化。参考下面代码:
// 一行声明多个变量,表示这些变量的数据类型一致,但变量名不同
int height, length, width, volume;
float profit, loss;
// C语言允许一行给多个变量赋值(前提是已声明)
height = 100,loss = 100.1;
// C语言允许一行初始化多个变量,这些变量声明一致,所以数据类型一致
int a = 8, b = 12, c = 10;
这种一行执行多个操作,好处是简化代码,使得代码更紧凑。缺点是可读性不好,有时也会影响程序的Debug调试。
关于变量声明风格的建议
在C语言中,变量的声明风格是比较自由的。但从代码可读性、维护性和减少错误的角度来看,以下是一些常见的建议:
一行声明一个变量:这样可以增加代码的清晰度,使每个变量都有一个明确的类型和(可能的)初始值。例如:
cppint x; int y = 10; char c;
为相关的变量使用一行:如果某些变量有很强的逻辑关系或用于类似的目的,可以考虑将它们放在同一行。但要确保它们的类型是相同的,以避免混淆。例如:
cppint len, width, height; // 长方体的长宽高
注释:如果一行中声明了多个变量,或者变量的用途不是很明显,使用注释来描述它们的用途或原因可以帮助读者更好地理解代码。
总的来说,选择何种风格主要取决于你的个人喜好或团队的编码规范。但无论选择哪种风格,关键是始终保持一致性并确保代码的可读性和清晰度。
变量的使用
以上概念理解后,我们就可以声明,赋值或者初始化一个变量,然后使用这个变量了。
基于int和float类型的变量,我们可以执行一些运算操作,比如:
int height = 8;
int length = 12;
int width = 10;
// 计算体积
int volume = height * length * width;
显示变量的值
我们可以使用 printf
显示变量的值,如:
printf("Height: %d\n", height);
其中 %d
是占位符,我们称之为转换说明,(conversion specification),它是用来指明变量 height 在显示中的位置。
%d
仅适用于 int 类型变量,如果要显示 float 类型变量,需要用 %f
来代替 %d
。默认情况下,%f
会显示出小数点后 6 位数字。如果要强制 %f
显示小数点后 p 位数字,可以把 .p
放置在 % 和 f 之间,如:
printf("Profit: $%.2f\n", profit);
C 语言没有限制 printf
可以显示变量的数量,我们可以同时显示多个变量的值:
printf("Height: %d Length: %d Width: %d\n", height, length, width);
变量的特点
- 变量在编译时为其分配相应的内存空间
- 可以通过其和访问相应内存
变量名的本质
变量名的本质:一段连续内存空间的别名;
程序通过变量来申请和命名内存空间
int a = 0;
通过变量名访问内存空间;
不是向变量名读写数据,而是向变量所代表的内存空间中读写数据;
修改变量的两种方式:
#include <stdio.h>
#include <stdlib.h>
void test(void) {
int a = 10;
//1. 直接修改
a = 20;
printf("直接修改 a:%d\n", a);
//2. 间接修改
int *p = &a;
*p = 30;
printf("间接修改 a:%d\n", a);
}
int main(void) {
test();
return 0;
}
程序输出
直接修改 a:20
间接修改 a:30
综合实例
计算半径为3cm的圆形的周长是多少?如果把半径改为5cm呢?
/**
* circle.c
* 计算半径为3cm的圆形的周长是多少?如果把半径改为5cm呢?
*/
#include <stdio.h>
#define PI 3.1415926f
int main(void) {
int r = 3; // 半径
double n = 0; // 周长
const double pi = 3.1415926f;
// pi = 3.14; // err,常量不能修改
// PI = 3.14; // err,常量不能修改
n = PI * (2 * r);
printf("半径为%dcm时,周长为%.2fcm\n", r, n);
r = 5; // 将半径改为5
n = PI * (2 * r);
printf("半径为%dcm时,周长为%.2fcm\n", r, n);
return 0;
}
程序输出:
半径为3cm时,周长为18.85cm
半径为5cm时,周长为31.42cm