如果你从未接触过C语言, 那么我建议你先阅读前面的文章:
C语言的数据类型 和 变量
在上一篇文章中, 举了一个最简单的C语言例子:
#include <stdio.h>
int main() {
printf("Hello World");
return 0;
}
通过在main()
函数中调用printf("Hello World");
打印出来了Hello World
printf()
是函数, 那么"Hello World"
是什么呢?
在C语言中, 凡是被双引号""
包裹的字符, 被称为字符串, 也叫字符串字面量
无论里面是英文字符、数字、符号, 甚至是中文字符, 只要被双引号括起来, 它就是一个字符串
例如: "123"
、"2.333"
、"###"
、"你好"
、"Hello"
都是字符串, 哪怕只是 "1"
、" "
、"h"
这样的单字符内容, 也依然是字符串
甚至连 ""
这样什么都没有的内容, 也是一个合法的字符串, 称为空字符串
不过, 字符串实际是由一个个”字符”按顺序组成的
"Hello"由'H' 'e' 'l' 'l' 'o'组成
C语言中, 单个字符通常使用单引号 ''
包裹, 比如 'A'
、'1'
、'%'
等. 这些字符会被存储为一种特定的数据类型: char
类型
除char
类型之外, C语言中还有其他基本数据类型:
// 空类型
void
// 字符类型
char
// 短整型
short
// 整型(整数类型)
int
// 长整型
long
// 更长的整型
long long
// 单精度浮点数(单精度小数)
float
// 双精度浮点数(双精度小数)
double
// 扩展精度浮点数(不常用)
long double
这就是C语言中所有的基本数据类型了
你会发现, 这里边并没有字符串类型
实际上, C语言中字符串并不是一种单独的数据类型, 字符串是由字符组成的一种类型
变量
C语言中, 你可以使用这些数据类型, 定义并使用变量
什么是变量?
从字面上看, “变量”就是可以变化的量, 即值会发生变化的数据
而在编程语言中, 并不是这么简单的, 不过也可以 以一种简单的视角理解变量:
可以将变量, 当作一个有名字的”盒子”
这个盒子有特定的大小(由数据类型决定), 我们可以把数据放进去, 也可以随时拿到数据使用或替换成新的数据
在C语言中, 变量 具体的定义方式是这样的:
char character = 'c';
int age = 20;
float weight = 55.5;
character
age
weight
即为不同类型、不同大小的变量, 把变量当成一个”盒子”来看, 这些盒子可以存储对应类型大小的数据, 这里的大小指的是bit(位)
、byte(字节)
character
age
weight
就是变量的名字, 'c'
就是放在character
中的数据, 20
就是放在age
中的数据, 55.5
就是放在weight
中的数据
C语言中, =
被称为赋值符号, 意为 为…赋值 或 将值赋给…
已经放在变量中的数据, 在之后的代码中, 就可以直接通过变量名来使用了, 比如:
#include <stdio.h>
int main() {
int age1 = 18; // 变量age1, 放入数字18
int age2 = 20; // 变量age2, 放入数字20
printf("age1 加 age2 和为 %d\n", age1 + age2);
return 0;
}
这段代码的执行结果为:
知识点INFO——注释
各编程语言, 都会提供一种 可以实现 在代码文件中对代码片段的功能或原理等进行说明, 同时不影响代码功能 的语法, 这种语法被称为 注释语法
注释语法的功能就是在代码中插入说明性文本, 而不影响其他代码的编译
因为在正常情况下, 源代码文件中的每行语句, 都应该是符合编程语言语法标准的语句
举个例子:
在C语言中, int a = 10;
printf("hello world\n");
是符合语法标准的
如果你想对代码进行解释: 这一个语句定义了一个变量a, 并赋值为10
, 这一个语句使用printf()打印"hello world"
是不符合语法标准的
// 符合语法标准
int a = 10;
printf("hello world\n");
// 不符合语法标准
这一个语句定义了一个变量a, 并赋值为10
这一个语句使用printf()打印"hello world"
不符合语法标准的语句, 编译器是无法进行编译的, 因为编译器无法理解非法语句, 也就没有办法把代码翻译成计算机语言
所以, 各编程语言均提供有注释语法, 它可以使编译器在编译代码时, 忽略不符合语法标准的语句
当然, 注释语法事实上就是语法标准的一部分, 通常情况下 注释语法的使用都非常简单
C语言中, 注释语法分两种:
单行注释
作用范围只在当前行内
其实在上面已经使用过:
// 注释内容
以双斜杠开始, 后续的同行内容 均为注释:
//
, 无法跨行作用多行注释:
作用范围在语法包裹范围内
语法也很简单:
/* 注释内容 */
多行注释是划定范围来注释的, 以
/*
开始,*/
结束, 在开始和结束之间的所有范围均为注释/*
和*/
必须配对使用也可以同行注释
/* 注释内容 */
bit
位, 表示二进制位, 即0/1
1bit
可以表示2个数:
十进制 | 二进制 |
---|---|
0 | 0 |
1 | 1 |
2bit
可以表示4个数:
十进制 | 二进制 |
---|---|
0 | 00 |
1 | 01 |
2 | 10 |
3 | 11 |
3bit
可以表示8个数:
十进制 | 二进制 |
---|---|
0 | 000 |
1 | 001 |
2 | 010 |
3 | 011 |
4 | 100 |
5 | 101 |
6 | 110 |
7 | 111 |
4bit
可以表示16个数: …; 5bit
可以表示32个数: …; 6bit
可以表示64个数: …; 7bit
可以表示128个数: …; 8bit
可以表示256个数: …
byte
字节, 一字节是8位
在C语言程序中, 不同的数据类型, 占用的大小是不同的, 这意味着”盒子”的大小不同, 即 变量的大小不同
每种类型的大小, 具体如下表所示:
数据类型 | 占用大小 |
---|---|
char | 1 byte |
short | 2 byte |
int | 4 byte |
long | 4/8 byte (根据平台编译器的具体实现决定) |
long long | 8 byte |
float | 4 byte |
double | 8 byte |
long double | 8/16 byte (根据平台编译器的具体实现决定) |
void | 不是用来存储数据的类型, 可以看作是一种空类型占位符, 不能用于定义变量 |
这些数据类型具体的大小占用, 也可以通过代码的形式在程序中打印出来:
#include <stdio.h>
int main() {
printf("char size: %lu\n", sizeof(char));
printf("short size: %lu\n", sizeof(short));
printf("int size: %lu\n", sizeof(int));
printf("long size: %lu\n", sizeof(long));
printf("long long size: %lu\n", sizeof(long long));
printf("float size: %lu\n", sizeof(float));
printf("double size: %lu\n", sizeof(double));
printf("long double size: %lu\n", sizeof(long double));
return 0;
}
这段代码, 使用gcc main.c
将其编译为可执行程序并运行的结果是:
可以看到打印结果是符合上面表格中的内容的
变量的命名规则
已经大概了解了, 变量可以简单理解为 程序中, 一个命名的、有大小的、存储数据用的盒子
不过, 变量命名也是有一定规则的, 并不是可以随便给变量命名
C语言标准中, 标识符(变量名、函数名等)的命名规则如下:
只能包含以下字符:
- 字母:
a-z
和A-Z
- 数字:
0-9
- 下划线:
_
标准中并未提及中文字符命名的相关规则, 但编译器可能支持
- 字母:
首字符必须是字母或下划线
即, 首字符不允许是数字
区分大小写
即,
age
与Age
不属于同一标识符禁止与关键字冲突
即, 标识符的命名禁止与C语言中的关键字完全一致
有关 关键字 并非本章介绍内容
下面是一些变量命名的正确例子和错误例子:
/* 正确例子 */
int age;
int Age;
float weight1;
double _theFloat;
double Double;
/* 错误例子 */
int 2age; // 首字符禁止为数字
int float; // 禁止与关键字完全一致
float the-weight; // 非法字符
double $float; // 非法字符
变量的分类 以及 作用域和生命周期
C语言程序的入口是main()
函数
那么, 即使是最简单的C语言程序, 也会分出两种区域:
/*
入口外, 即 main() 函数外
*/
int main() {
/*
入口内, 即 main() 函数内
*/
return 0;
}
/*
入口外, 即 main() 函数外
*/
在之前的例子中, 变量都是在main()
函数内部定义的
这里可能有一个问题出现: 变量可以在main()
函数外部定义吗?
答案是可以
C语言中, 变量可以在main()
函数外部定义
并且, 定义在main()
函数内部和外部的变量, 是有一定区别的:
在
main()
函数外部定义的变量, 被称为全局变量在函数内部定义的变量, 被称为局部变量
全局变量的作用域, 一般为整个C 程序
局部变量的作用域, 则只在定义局部变量所在的范围
什么是变量的作用域?
C语言中, 变量的作用域, 就是变量能被使用的有效范围
比如, 在
main()
函数内定义的变量, 那这个变量的作用域就在main()
函数的范围内, 出了main()
函数就无法再使用实际上, 在C语言中一个
{}
声明一个代码块, 在代码块内定义变量, 此变量的作用域即为所在代码块全局变量的生命周期, 为整个C 程序
局部变量的生命周期, 为定义局部变量所在的范围
变量的生命周期, 可以简单理解为变量的存活时间
变量的生命周期, 一般是从变量完成定义到其所在作用域结束
全局变量和局部变量可以同名, 但在使用上 遵循就近原则
以实际的代码为例子:
#include <stdio.h>
int globalVar = 10; // 全局变量
int var = 20; // 全局变量
int main() {
printf("globalVar: %d\n", globalVar);
printf("var: %d\n", var);
int var = 30; // 局部变量
printf("var: %d\n", var);
{
int _var = 40;
int var = 50;
printf("_var: %d\n", _var);
printf("var: %d\n", var);
}
// printf("_var: %d\n", _var);
printf("var: %d\n", var);
return 0;
}
这段代码定义了很多个变量, 可以先来看一下执行结果:
我们可以结合现象, 分析一下每一句printf()
所使用的变量是哪一个:
序号 | 调用语句 | 打印值 | 值对应变量名 | 是否有重名变量 | 实际使用变量 |
---|---|---|---|---|---|
1 | 第7 行: printf("globalVar: %d\n", globalVar); | 10 | globalVar | 否 | globalVar(第3行) |
2 | 第8 行: printf("var: %d\n", var); | 20 | var | 是 | var(第4行) |
3 | 第11 行: printf("var: %d\n", var); | 30 | var | 是 | var(第10行) |
4 | 第16 行: printf("_var: %d\n", _var); | 40 | _var | 否 | _var(第14行) |
5 | 第17 行: printf("var: %d\n", var); | 50 | var | 是 | var(第15行) |
6 | 第21 行: printf("var: %d\n", var); | 30 | var | 是 | var(第10行) |
从结果来看, 可以分析出一些特性:
全局变量和局部变量可以重名
编译没有问题, 运行也没有问题
变量的使用, 遵循就近原则
即, 如果存在重名变量, 使用时 会使用已经定义的, 离调用位置近的变量
在例子中表现为:
局部变量
var
没有定义时, 使用var
变量, 实际使用的是全局变量var
局部变量
var
定义后, 使用var
变量, 实际使用的是局部变量var
变量只在其作用域内生效
即, 变量出了其作用域, 其生命周期就会结束, 无法再使用
在例子中的表现为:
第
17
行打印的var
值是50
, 而第21
行打印的var
值是30
如果把第
20
行代码的注释解开(删掉//
), 编译会报错:报错信息为:
_var
未声明
总结来讲, 究竟什么是变量?
变量是一个命名的存储单元, 它可以用来存储程序运行过程中可能发生变化的数据
它有: 名字(标识符)、类型(数据类型决定它能存什么数据)、大小(由类型决定)、作用域(在哪能访问)、生命周期(存在多久)
还有这些特点:
类型明确:每个变量都有明确的数据类型(如
int
、float
等)内存占用不同:不同类型的变量占用不同的字节数
命名有规则:
只能由字母、数字和下划线组成,且不能以数字开头
不能与C语言中的关键字完全一致
作用域限制:
全局变量在程序内全局有效
局部变量只能在其定义的代码块中有效。
生命周期不同:
局部变量:随函数或代码块执行完毕而消失
全局变量:存在于整个程序生命周期
支持赋值与修改:变量可以在程序中多次赋新值
使用需先定义:C语言要求变量在使用前必须先定义
const
修饰变量
与变量相对, 还存在另一个重要概念: 常量
常量, 通常指一个固定不变的量
现实生活中的代表有: 光速(恒定为约 299,792,458 米/秒
)、π(约等于3.1415926……
)…
这些量之所以被称为“常量”,是因为它们的数值具有不可修改性
const
是C语言标准中的一个关键字, 它是单词constant(常量)
的简写
const
在C语言中可以在定义变量时放在类型前修饰变量, 让变量具有常量属性, 即const
修饰变量, 可以使变量的值无法改变
来看下面的代码:
#include <stdio.h>
int main() {
int var = 10;
const int con = 20;
/*
定义变量时, cosnt 放在类型前 修饰变量
*/
printf("var: %d\n", var);
printf("con: %d\n", con);
return 0;
}
这段代码的执行结果很明显:
但是如果你试图修改con
:
#include <stdio.h>
int main() {
int var = 10;
const int con = 20;
con = 11;
printf("var: %d\n", var);
printf("con: %d\n", con);
return 0;
}
那么, 编译就会发生报错:
报错信息为: 试图给只读变量con
赋值
可以看到, 被const
修饰的变量, 具有了常量属性, 无法修改, 只能读取
const
修饰变量会使变量具有常量属性
这表示变量定义完成之后, 就无法再进行赋值
所以, 在定义变量时, 如果要使用const
修饰, 请保证变量初始化无误
变量的定义:
int var;
变量的初始化:
int var = 10;
变量的初始化是, 在变量定义的同时给变量赋初值
下面这样不叫初始化:
int var;
var = 10;