C 常量、变量与存储方式
# 常量 常量是固定值,在程序执行的过程中不会发生改变。
****# 常量 常量是固定值,在程序执行的过程中不会发生改变。
整数常量
整数常量可以是十进制、八进制或十六进制的常量。
前缀指定基数:0x 或 0X 表示十六进制,0 表示八进制,不带前缀则默认表示十进制。
整数常量也可以带一个后缀,后缀是 U 和 L 的组合,U 表示无符号整数(unsigned),L 表示长整数(long)。后缀可以是大写,也可以是小写,U 和 L 的顺序任意
下面列举几个整数常量的实例:
212 /* 合法的 */
215u /* 合法的 */
0xFeeL /* 合法的 */
078 /* 非法的:8 不是八进制的数字 */
032UU /* 非法的:不能重复后缀 */
以下是各种类型的整数常量的实例:
85 /* 十进制 */
0213 /* 八进制 */
0x4b /* 十六进制 */
30 /* 整数 */
30u /* 无符号整数 */
30l /* 长整数 */
30ul /* 无符号长整数 */
整数常量可以带有一个后缀表示数据类型,例如:
int myInt = 10;
long myLong = 100000L;
unsigned int myUnsignedInt = 10U;
浮点常量
浮点常量由整数部分、小数点、小数部分和指数部分组成。您可以使用小数形式或者指数形式来表示浮点常量。
当使用小数形式表示时,必须包含整数部分、小数部分,或同时包含两者。 当使用指数形式表示时, 必须包含小数点、指数,或同时包含两者。
- 带符号的指数是用 e 或 E 引入的。
INFO: 浮点常量的写法 包含小数点的一个带符号的数字序列,接着是字母e或E,然后是一个代表10的指数的有符号值,且必须为整数。
其中 e 或 E 被称为阶码标志,e 或 E 后面的有符号整数被称为阶码。 阶码代表 10 的阶码次方。EXAMPLE
15.75 1.575E1 /* = 15.75 */ 1575e-2 /* = 15.75 */ -2.5e-3 /* = -0.0025 */ 25E-4 /* = 0.0025 */ATTENTION
- 浮点型常量可以省略正号,可以没有小数点或指数部分
- 但是不能同时没有二者
- 浮点型常量可以省略小数或者整数部分,但不能同时省略
- e前后的实数和整数不能省略
- 浮点型常量中不能有空格!
- 浮点型常量有阶码的小数点前面只能有一位非0的数字
下面列举几个浮点常量的实例:
3.14159 /* 合法的 */
314159E-5L /* 合法的 */
510E /* 非法的:不完整的指数 */
210f /* 非法的:没有小数或指数 */
.e55 /* 非法的:缺少整数或分数 */
浮点数常量可以带有一个后缀表示数据类型,例如:
float myFloat = 3.14f;
double myDouble = 3.14159;
字符常量
符常量是括在单引号中,例如,x 可以存储在 char 类型的简单变量中。
字符常量可以是一个普通的字符(例如 x)、一个转义序列(例如 \t),或一个通用的字符(例如 \u02C0)。
转义字符
在 C 中,有一些特定的字符,当它们前面有反斜杠时,它们就具有特殊的含义,被用来表示如换行符(\n)或制表符(\t)等。下表列出了一些这样的转义序列码:
| 转义序列 | 含义 |
|---|---|
| \ | \ 字符 |
| ' | ’ 字符 |
| " | “ 字符 |
| ? | ? 字符 |
| \a | 警报铃声 |
| \b | 退格键 |
| \f | 换页符 |
| \n | 换行符 |
| \r | 回车 |
| \t | 水平制表符 |
| \v | 垂直制表符 |
| \ooo | 一到三位的八进制数 |
| \xhh | 一个或多个数字的十六进制数 |
\\ |
输出反斜杠字符“\” |
\' |
输出单引号字符‘’ |
\'' |
输出双引号字符”“ |
| … | |
| o和h表示数 | |
| 例如\101, \x60 |
字符串常量
字符串字面值或常量是括在双引号 “ “ 中的。
字符串常量在内存中以 null 终止符 \0 结尾。例如:
char myString[] = "Hello, world!"; //系统对字符串常量自动加一个 '\0'
定义常量
在 C 中,有两种简单的定义常量的方式:
- 使用 #define 预处理器:
#define可以在程序中定义一个常量,它在编译时会被替换为其对应的值。 - 使用 const 关键字:
const关键字用于声明一个只读变量,即该变量的值不能在程序运行时修改。
#define预处理器
#define预处理器定义常量的形式:
#define 常量名 常量值
EXAMPLE
#define PI 3.14159
const 关键字
使用 const 前缀声明指定类型的常量
const 数据类型 常量名 = 常量值;
EXAMPLE
const int MAX_VALUE = 100;
const 声明常量要在一个语句内完成:

实例:
#include <stdio.h>
int main()
{
const int LENGTH = 10;
const int WIDTH = 5;
const char NEWLINE = '\n';
int area;
area = LENGTH * WIDTH;
printf("value of area : %d", area);
printf("%c", NEWLINE);
return 0;
}
ATTENTION 把常量定义为大写字母形式,是一个很好的编程习惯
#define与const区别
-
替换机制:
#define是进行简单的文本替换,而const是声明一个具有类型的常量。#define定义的常量在编译时会被直接替换为其对应的值,而const定义的常量在程序运行时会分配内存,并且具有类型信息。 -
类型检查:
#define不进行类型检查,因为它只是进行简单的文本替换。而const定义的常量具有类型信息,编译器可以对其进行类型检查。这可以帮助捕获一些潜在的类型错误。 -
作用域:
#define定义的常量没有作用域限制,它在定义之后的整个代码中都有效。而const定义的常量具有块级作用域,只在其定义所在的作用域内有效。 -
调试和符号表:使用
#define定义的常量在符号表中不会有相应的条目,因为它只是进行文本替换。而使用const定义的常量会在符号表中有相应的条目,有助于调试和可读性。
变量
类型
变量是程序可操作存储区的名称。C中每个变量都有特定的类型,类型决定了变量存储的大小和布局,该范围内的值都可以存储在内存中,运算符可应用于变量上。 变量的名称可以由字母、数字和下划线字符组成。它必须以字母或下划线开头。大写字母和小写字母是不同的,因为 C 是大小写敏感的。基于前一章讲解的基本类型,有以下几种基本的变量类型:
| 类型 | 描述 |
|---|---|
| char | 通常是一个字节(八位), 这是一个整数类型。 |
| int | 整型,4 个字节,取值范围 -2147483648 到 2147483647。 |
| float | 单精度浮点值。单精度是这样的格式,1位符号,8位指数,23位小数。![]() |
| double | 双精度浮点值。双精度是1位符号,11位指数,52位小数。![]() |
| void | 表示类型的缺失。 |
C 中的变量定义
定义整型变量:int age;
定义指针变量:int *ptr; (以上代码中,ptr 被定义为一个整型指针变量。)
定义多个变量:int i, j, k;
变量初始化
在 C 语言中,变量的初始化是在定义变量的同时为其赋予一个初始值。变量的初始化可以在定义时进行,也可以在后续的代码中进行。
初始化器由一个等号,后跟一个常量表达式组成
type variable_name = value;
其中,type 表示变量的数据类型,variable_name 是变量的名称,value 是变量的初始值。
变量不初始化
在 C 语言中,如果变量没有显式初始化,那么它的默认值将取决于该变量的类型和其所在的作用域。
对于全局变量和静态变量(在函数内部定义的静态变量和在函数外部定义的全局变量),它们的默认初始值为零。
以下是不同类型的变量在没有显式初始化时的默认值:
- 整型变量(int、short、long等):默认值为0。
- 浮点型变量(float、double等):默认值为0.0。
- 字符型变量(char):默认值为’\0’,即空字符。
- 指针变量:默认值为NULL,表示指针不指向任何有效的内存地址。
- 数组、结构体、联合等复合类型的变量:它们的元素或成员将按照相应的规则进行默认初始化,这可能包括对元素递归应用默认规则。
需要注意的是,局部变量(在函数内部定义的非静态变量)不会自动初始化为默认值,它们的初始值是未定义的(包含垃圾值)。因此,在使用局部变量之前,应该显式地为其赋予一个初始值。
C 中的变量声明
变量声明只在编译时有它的意义,在程序连接时编译器需要实际的变量声明。
变量的声明有两种情况:
- 1、一种是需要建立存储空间的。例如:
int a在声明的时候就已经建立了存储空间。 - 2、另一种是不需要建立存储空间的,通过使用extern关键字声明变量名而不定义它。 例如:
extern int a其中变量a可以在别的文件中定义的。
除非有extern关键字,否则都是变量的定义。
extern int i; //声明,不是定义
int i; //声明,也是定义
extern 关键字
extern 用在变量或者函数的声明前,用来说明“此变量/函数是在别处定义的,要在此处引用”。
extern 声明不是定义,即不分配内存空间。也就是说,在一个文件中定义了变量和函数,在其他文件中要使用它们,可以有两种方式:
- 使用头文件,然后声明它们,在其他文件中使用时包含头文件;
- 在其他文件中直接使用 extern 声明。
例如,在文件 a.h 中的代码如下:
#include<stdio.h>
int a = 10;
如果在另一个文件 a.c 中要用到文件 a.h 中的变量 a,代码如下:
#include <stdio.h>
#include "a.h" //包含该头文件
int main(int argc,char *argv[])
{
printf("a = %d \n " , a);
return 0;
}
另外一种方式是在文件 b.c 中定义变量 a,代码如下:
#include<stdio.h>
int a = 10;
在另一个文件的 main() 主函数中通过 extern 声明外部文件变量,代码如下:
#include <stdio.h>
extern int a; //使用外部文件b.c中的变量a
int main(int argc , char *argv[])
{
printf("a = %d \n " , a);
return 0;
}
/*
编译运行,结果均如下:
a = 10
*/
static 静态变量 的 用法
static 修饰符, 加在 一个变量之前,就说明 这个变量是一个静态变量
存储在 静态数据区 的变量会在程序刚开始运行时就完成初始化,⚠️也是唯一的一次初始化⚠️,声明它的函数共享这个变量
函数中的静态变量是静态局部变量,退出函数后不被释放,在程序运行结束时才释放。该变量只在函数中可使用,退出函数后就不能再使用,其生存期为整个源程序,但只能在定义该变量的函数内使用。
静态局部变量在编译时赋初值,且只赋一次,赋值语句在程序运行时不再运行。如果在定义局部变量时不赋初值,则对静态局部变量来说,编译时自动赋初值 0(对数值型变量)或空字符(对字符型变量)。
静态变量中所谓的静态,是指在程序运行的过程中,变量的内存地址始终不变,而不是其值不变。静态全局变量的作用域只在定义它的文件里,不能被其他文件使用。
static 修饰的静态变量有以下特征:
- 变量会被放在程序的数据区,在下一次被调用的时候还保持原来赋的值;
- 变量用 static 告知编译器,仅在变量的作用域内可用,这是其与全局变量的区别。
分别定义局部和全局静态变量的代码如下:
int fun(void){
static int count = 3; //事实上此赋值语句从来没有执行过
return count--;
}
static int count = 1; //全局静态变量
int main(void)
{
printf("global\t\tlocal static\n");
for(; count <= 3; ++count)
printf("%d\t\t%d\n", count, fun());
return 0;
}
/*
编译运行,结果如下:
global local static
1 3
2 2
3 1
*/
变量的存储类别和作用域限制
-
static(静态全局变量):当在全局变量前加上
static关键字时,该变量的链接属性变为“内部链接(internal linkage)”。这意味着它的作用域被严格限制在定义它的那个源文件内部,其他源文件无法通过extern引用它。这正是题目所描述的需求。 -
extern:用于声明一个在其他文件中定义的全局变量,表明该变量具有“外部链接”属性,可以跨文件使用。
-
register:暗示编译器尽量将该局部变量存储在CPU寄存器中以提高访问速度,不能用于全局变量。
-
auto:是局部变量的默认存储类别,表示变量在栈上自动分配和释放,不能用于全局变量。

