前言
Hello 大家好!我是甜美的江。
今天让我们完整地来学习c语言的常量
在C语言中,常量是程序中不可改变的固定值,其值在程序执行期间保持不变。常量为程序员提供了一种有效管理和维护数据的方式,通过引入不可变的值,增加了代码的稳定性和可维护性。
在本文中,我们将深入探讨常量的概念、作用以及在C语言编程中的重要性。
一 常量的基本概念及分类
在 C 语言中,常量是一种固定的数值或标识符,其值在程序执行期间保持不变。常量主要分为字面常量、使用 const 关键字的常量、符号常量和枚举常量。
1. 字面常量:
概念: 直接出现在代码中的数值,例如整数、浮点数、字符或字符串,不需要声明,如 42、3.14、‘A’、“Hello”。
类比: 想象你在写一本书,直接在文本中写下一些具体的数字、字母或单词。
解释: 这些直接写入文本的内容就像代码中的字面常量。它们是直接给定的值,不需要额外的声明,就像书中的文字一样。
2. 使用 const 关键字的常量:
概念: 通过 const 关键字声明的具有常量特性的变量,使其值不可修改,如 const int MAX_VALUE = 100。
类比: 想象你有一个宝箱,里面有一块金块,但你不能改变这块金块的形状或重量。
解释: 这块金块就像使用const关键字声明的常量。它是一个固定的值,不能在后续代码中更改,就像金块的形状和重量是固定的一样。
如:
const int MAX_VALUE = 100
3. 符号常量:
概念:通过 #define 预处理指令定义的标识符,用于表示一个固定值,提高代码的可读性和可维护性
类比: 想象你有一本笔记本,其中有一些重要的规则或数值,你在笔记本的第一页上用大字写下这些规则。
解释: 这些在笔记本开头写下的规则就像使用#define定义的符号常量。它们是为了提高可读性和可维护性而定义的,就像笔记本上的大字让人更容易找到关键信息一样。
如:
#define MAX_SIZE 100 #define PI 3.141592
4. 枚举常量:
概念:通过 enum 关键字定义的一组常量,它们通常表示相关的命名值。
类比: 想象你有一个颜色选择器,上面有一组命名的颜色选项,如“红色”、“绿色”等。
解释: 这个颜色选择器就像使用enum定义的枚举常量。每个颜色都有一个特定的名称,就像一周中的每一天都有一个特定的名称一样。
如:
enum Weekdays { MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY };
在这里,MONDAY、TUESDAY 等就是枚举常量,它们代表了一周中的不同天。
二 常量的存储方式
在C语言中,常量的存储方式主要取决于常量的类型。常量可以分为字面常量(如整数、浮点数、字符、字符串等)、符号常量(使用#define定义的常量)和枚举常量。以下是它们的存储方式:
字面常量:
存储方式:
字面常量通常直接存储在程序的代码段(text segment)中。 这是一个固定的区域,存储程序的机器代码。字面常量的值在编译时就已经确定,不会发生改变,因此可以被安全地存储在代码段中。
类比:
想象你有一本不可改变的书。
解释:
这本书就像代码段中的字面常量。书的内容在一开始就已经确定,不能改变,而书本本身就是存放这些内容的地方。这本书就好比字面常量,其值在编译时确定,并安全地存储在代码段中。
使用 const 关键字的常量:
存储方式:
通过 const 关键字声明的常量可能会被分配存储空间,具体取决于它们的使用方式。
如果 const常量在函数内部定义,并且未被取地址或使用extern关键字声明,编译器可能会将其视为编译时常量,直接将其值嵌入到使用该常量的代码中,而不分配存储空间。
如果在全局范围或使用extern声明,编译器可能为其分配存储空间。
类比:
想象你有一个永远不变的规则,例如“一天有24小时”。
解释:
这个规则就像使用const关键字声明的常量。如果这个规则在某个函数内部使用,并且不会被取地址或在其他地方声明为extern,编译器可能会将其视为编译时常量,直接将其值嵌入到使用它的代码中,就像这个规则会直接嵌入到使用它的地方一样。如果在全局范围或使用extern声明,编译器可能为其分配存储空间,就像这个规则可能在某个地方被明确存储一样。
符号常量:
存储方式:
符号常量使用#define定义,它们在预处理阶段被替换为其具体的值。因此,符号常量在程序的代码段中,就像字面常量一样,因为它们的值在编译时就已经确定。
类比:
假设你有一个门牌号为 #define HOME_NUMBER 123 的房子。
解释:
这个门牌号就像在代码段中使用#define定义的符号常量。
在程序中,编译器会在预处理阶段将这个门牌号替换为具体的值,就像符号常量在文本段中的值在编译时就已经确定一样。
枚举常量:
存储方式:
枚举常量表示一组命名的整数值,它们在内存中的存储方式通常是整数值。编译器会为枚举常量分配存储空间,通常是整数的大小。 这些值可以被存储在程序的数据段(data segment)中。
类比:
想象你有一个颜色的选择器,其中包含了红、绿、蓝等不同的颜色选项。
解释:
这个颜色选择器就像程序中的枚举常量。每个颜色都有一个整数值与之关联,就像枚举常量在内存中通常以整数值存储一样。这些值可以被存储在程序的数据段中,就像颜色选择器存储不同颜色的整数值。
程序的代码段概念:
在计算机程序的内存布局中,程序的代码段(text segment)是一部分用于存储可执行代码的内存区域。它也被称为代码区、文本段或只读代码段。在这个区域内存储着程序的机器语言指令,即由编译器生成的可执行二进制代码。
具体来说,代码段包含了程序的指令集,这些指令用于执行程序的各种操作。这些指令在程序运行时被读取并执行。代码段通常是只读的,这是因为程序在运行时不应该修改自身的指令集。这有助于确保程序的完整性和安全性。
在代码段中存储的内容包括函数、控制流语句和其他程序结构的机器指令。当程序启动时,操作系统会将代码段加载到内存中,并将程序计数器设置为代码段的起始地址,从而开始执行程序的指令。
总的来说,代码段是程序的一部分,用于存储可执行代码,它在程序运行时被加载到内存中,并包含了程序的机器语言指令。这是计算机程序执行的基础。
三 c语言常量和变量的具体区别
1.可变性(Mutability):
变量: 变量是可以被修改的,其值可以在程序执行过程中改变。
常量: 常量是不可变的,其值在程序运行过程中不能被修改。
2.声明方式(Declaration):
变量: 变量在使用前需要被声明,并分配一块内存用于存储数据。例如,int x; 声明了一个整数变量x。
常量: 常量通常在程序中直接使用或通过宏定义、enum、const等方式声明。例如,const int MAX_SIZE = 100;
定义了一个整数常量MAX_SIZE。
3 存储方式(Storage):
变量: 变量在内存中有一个地址,它的值存储在该地址上。
常量: 常量的值可能被编译器直接嵌入到程序中,而不一定占用内存。
4 使用方式(Usage):
变量: 用于存储和操作可变的数据。
常量: 用于表示固定的、不可变的值,例如数学常数、程序中固定的限制等。
5 命名规则(Naming):
变量: 变量有命名规则,可以根据需求进行自定义。
常量: 常量通常使用大写字母命名,以便在代码中容易识别。
6 作用域(Scope):
变量: 变量的作用域可以是全局的或局部的,取决于其声明的位置。
常量: 常量的作用域也可以是全局或局部,取决于其声明的位置。
总体而言,变量是用于存储和处理可变数据的标识符,而常量是表示固定值、不可变的标识符。在C语言中,使用它们的方式和目的各不相同。
我们可以将货币作为一个很好的例子来进行类比。
货币的数量(变量):
假设你手中有一些现金,这个数量是可以改变的。你可以花钱购买物品,也可以收到工资或其他收入增加你手中的现金数量。这就类似于在编程中使用变量来存储可变的值。
货币的面值(常量):
然而,货币的面值是一个常量。例如,一张10美元的钞票始终价值10美元,无论你持有它多长时间或在哪里使用它,这个价值都不会改变。这类似于在编程中使用常量来表示一个固定的值,无法在程序执行过程中更改。
让我们通过一个简单的例子来看看C语言常量和变量的区别。
#include <stdio.h> int main() { // 变量示例 int x = 5; // 声明一个整数变量x,并赋值为5 printf("变量 x 的值:%d\n", x); x = 10; // 修改变量x的值 printf("修改后,变量 x 的值:%d\n", x); // 常量示例 const int MAX_SIZE = 100; // 声明一个整数常量MAX_SIZE,并赋值为100 printf("常量 MAX_SIZE 的值:%d\n", MAX_SIZE); // 尝试修改常量的值(这将导致编译错误) // MAX_SIZE = 200; // 错误,常量不能被修改 return 0; }
在这个例子中:
- x 是一个整数变量,可以在程序执行过程中改变其值。
- MAX_SIZE 是一个整数常量,其值在程序运行过程中不能被修改。
通过这个例子,你可以看到变量是可以在程序执行中改变的,而常量一旦被赋值就不能被修改。这突显了常量的不可变性,而变量则具有可变性。
四 字面常量详解
在C语言中,字面常量是直接出现在代码中的数值,它们表示自身的值。字面常量不需要额外的声明,而是直接写在程序中。C语言支持多种类型的字面常量,包括整数、浮点数、字符和字符串。
4.1 常见类型的字面常量及其示例:
1.整数常量:
- 整数常量是不带小数点的数值。可以使用不同的进制表示,如十进制、八进制和十六进制。
42 // 十进制整数 075 // 八进制整数,表示为八进制的75 0x2A // 十六进制整数,表示为十六进制的2A
2.浮点数常量:
- 浮点数常量包含小数点的数值。
3.14 // 浮点数,表示π 2.5e3 // 科学计数法,表示2.5乘以10的3次方
3.字符常量:
- 字符常量用单引号括起来,表示一个字符。
'A' // 字符常量,表示大写字母A '\n' // 转义字符,表示换行符
4.字符串常量:
- 字符串常量用双引号括起来,表示一个字符串。
"Hello" // 字符串常量,表示包含字符'H', 'e', 'l', 'l', 'o'的字符串
这些字面常量在C语言中直接嵌入到源代码中,提供了固定的、不可更改的值。在程序中使用字面常量可以增加代码的可读性和清晰度。
4.2 字面常量的使用情况
字面常量通常在编程中用于表示具体的数值或文本值,而不需要通过变量来引用。它们直接出现在代码中,用于提供固定的数值或文本,通常在以下情况下使用:
1.初始化变量:
字面常量常用于初始化变量,为变量赋予初始值。这使得代码更加简洁,不需要额外的声明和赋值语句。
示例:
int count = 5; // 使用字面常量初始化变量
2.常量表达式:
字面常量经常用于构建常量表达式,这些表达式在编译时就能够被计算出来。这样的常量表达式在一些宏定义或预处理指令中特别有用。
示例:
#define PI 3.14159 // 使用字面常量定义宏
3.直接在代码中使用:
字面常量可以直接在代码中表示具体的数值或文本,提高代码的可读性和清晰度。
示例:
printf("The value of pi is %.2f\n", 3.14); // 直接在代码中使用浮点型字面常量
4.3 字面常量的优点
与其他常量相比,字面常量具有以下一些好处:
> 直观性:
字面常量直接展示数值或文本,使得代码更加直观。读者能够立即理解它们代表的具体值,而无需查看其他定义或声明。
> 简洁性:
字面常量避免了额外的声明和定义步骤,使得代码更加简洁。在一些简单的情况下,使用字面常量可以减少代码的复杂性。
> 避免错误:
使用字面常量可以避免由于变量值的修改而引起的错误。在一些场景中,我们需要确保某个值在程序的整个生命周期内保持不变,这时使用字面常量更加安全。
> 提高可维护性:
字面常量使得代码更易读懂,因为它们直接传达了特定值的信息。这有助于提高代码的可维护性,因为其他开发者可以更容易理解代码的意图。
总体而言,字面常量是编程中的一种强大工具,特别在需要使用具体值而无需引入额外变量时,它们能够使代码更简单、更清晰。
五 const 关键字常量详解
在C语言中,const关键字用于声明常量,即不可更改的变量。使用const关键字可以将标识符(变量)声明为只读,一旦赋值后就不能再修改。
5.1 const关键字在C语言中的使用情况:
1 常量变量声明:
const int MAX_VALUE = 100;
在这个例子中,MAX_VALUE被声明为一个常量,且其值不能在后续的代码中被修改。
2 指针和const:
const int* ptr; // 指向常量整数的指针 int const* ptr; // 同样是指向常量整数的指针
这里ptr是一个指向常量整数的指针,这表示通过ptr不能修改所指向的整数的值,但可以改变指针本身指向的地址。
int x = 10; const int* ptr = &x; // *ptr = 20; // 错误,不能修改通过指针间接引用的值 x = 20; // 但是可以通过原始变量修改值
3 const指针:
int y = 5; int* const ptr = &y; // 常量指针,不能修改指针本身的值
在这个例子中,ptr是一个指向整数的常量指针,表示ptr的值(即指针本身)不能在后续代码中被修改,但可以通过ptr来修改所指向的整数的值。
int y = 5; int* const ptr = &y; *ptr = 10; // 合法,可以通过常量指针修改值 // ptr = &x; // 错误,不能修改常量指针的值
4 const修饰函数参数:
void display(const int num) { // num = 20; // 错误,不能在函数内修改const修饰的参数值 printf("%d\n", num); }
在函数参数中使用const表示函数内部不能修改这个参数的值。
5 const修饰函数返回值:
const int getNumber() { return 42; }
在这里,const修饰返回的整数,表示该返回值不能被修改。
总的来说,使用const关键字可以提高代码的可读性和安全性,因为它使得开发者能够清晰地知道哪些标识符是常量,不可被修改。这有助于防止一些意外的错误,并使代码更易于理解和维护。
5.2 const 关键字的常量常见使用场景
1 防止修改:
当希望确保一个变量的值在初始化后不被修改时,使用const关键字是一种良好的选择。这有助于防止程序中的错误和意外的数据修改。
const int MAX_VALUE = 100; // MAX_VALUE = 200; // 编译错误,常量不可修改
2 提高可读性:
使用const关键字可以为常量赋予有意义的名称,从而提高代码的可读性。这样,其他程序员或者你自己在后续阅读代码时能够更容易理解常量的作用。
const double PI = 3.14159;
3 替代宏定义:
在过去,宏定义经常被用来创建常量,但宏存在一些问题,如副作用和可读性差。使用const关键字可以更安全、更可读地定义常量。
#define MAX_SIZE 100 // ... int array[MAX_SIZE + 10]; // 可能导致不直观的结果 // 使用 const 关键字 const int MAX_SIZE = 100; int array[MAX_SIZE + 10]; // 更直观和可控
4 数组大小声明:
在声明数组时,使用const关键字可以指定数组的大小,提高代码的可维护性。
const int ARRAY_SIZE = 10; int myArray[ARRAY_SIZE];
5 函数参数中的常量:
在函数声明中,使用const关键字可以指明某个参数是常量,防止在函数内部修改参数的值。
void printMessage(const char* message) { // 不允许修改 message 的值 printf("%s\n", message); }
5.3 const 关键字的常量的优点
1 类型安全:
使用const关键字的常量是具有数据类型的,这使得在编译时可以进行类型检查。这有助于捕获一些潜在的类型错误,提高代码的类型安全性。
const int MAX_SIZE = 100; // MAX_SIZE = "Hello"; // 编译错误,类型不匹配
2 更好的作用域控制:
使用const关键字的常量具有作用域,这意味着它们只在声明它们的块或文件中可见。这可以减少命名冲突,并使得常量在更小的范围内有效。
// File1.c const int FILE1_CONSTANT = 42; // File2.c const int FILE2_CONSTANT = 42; // FILE1_CONSTANT 不可见
3 更好的调试能力:
使用const关键字的常量通常在调试过程中更易于追踪。在调试器中,可以通过常量的符号名称来查看其值,而不是查看硬编码的数字或其他值。
4 可读性和可维护性:
const关键字为常量提供了有意义的名称,而不是像魔法数字一样的硬编码值。这提高了代码的可读性,并使得代码更易于维护。
const int TIMEOUT_LIMIT = 5000; // 可读性更高
5 避免宏的副作用:
当使用预处理器宏(如#define)定义常量时,可能会发生副作用,因为宏是在文本替换阶段处理的。使用const关键字避免了这些潜在的副作用。
#define MAX_SIZE 100 // ... int array[MAX_SIZE + 10]; // 预处理器宏可能导致意外的结果 // 使用 const 关键字 const int MAX_SIZE = 100; int array[MAX_SIZE + 10]; // 更直观和可控
总的来说,使用const关键字声明常量有助于提高代码的可读性、可维护性,减少错误,并且在某些情况下提供了更好的类型安全性。它是一种现代C语言编程中推崇的良好实践。
六 符号常量详解
符号常量是一种在程序中用于代表特定值或表达式的命名标识符。在C语言中,符号常量通常通过预处理器指令#define来定义,这些常量在程序的编译之前由预处理器进行处理。符号常量是一种在代码中使用具有可读性的名称来表示常量值的方式,以提高代码的可维护性和可读性。
6.1 符号常量的一些特点和示例
1 定义符号常量:
使用#define指令可以定义符号常量。通常的格式是#define identifier
value,其中identifier是符号常量的名称,value是符号常量的值。
#define PI 3.14159 #define MAX_SIZE 100
2 没有类型信息:
符号常量没有具体的数据类型,它们只是简单的文本替换。这意味着在程序中使用符号常量时,编译器不会执行类型检查。
#define MAX_SIZE 100 int array[MAX_SIZE]; // 在预处理阶段会被替换为 int array[100];
3 无需分号:
与普通变量不同,符号常量的定义不需要以分号结尾。
4 通常全大写:
为了提高可读性,符号常量的命名通常使用全大写字母,以便与变量和函数名区分开。
#define MAX_SIZE 100
5 可以包含表达式:
符号常量的值可以是一个表达式,而不仅仅是一个简单的值。
#define SQUARE(x) ((x) * (x))
在这个例子中,SQUARE(x)会被替换为((x) * (x))。
6 可以使用条件编译:
符号常量在条件编译中很有用,可以根据条件选择性地包含或排除代码块。
#define DEBUG_MODE // ... #ifdef DEBUG_MODE // 调试模式下的代码 #endif
需要注意的是,虽然符号常量在C语言中是一种常见的编码习惯,
**但由于它们是简单的文本替换,**可能导致一些问题,如不安全的替换、副作用等。因此,在使用符号常量时,应该谨慎考虑其潜在影响,并在可能的情况下考虑使用const关键字声明常量以提高类型安全性。
6.2 符号常量常见使用场景
1 避免魔法数字:
当代码中存在一些常量值,而这些值没有明显的含义时,可以使用符号常量来提高代码的可读性。替代魔法数字(hard-coded numeric
values)可以使代码更易于理解和维护。
#define MAX_SIZE 100 #define PI 3.14159
2 增强可维护性:
使用符号常量可以减少代码中的重复,当需要修改常量值时,只需要修改一处定义而不是多处使用。这有助于降低代码维护的难度。
3 提高可移植性:
在一些情况下,不同的系统或平台可能具有不同的常量值,使用符号常量可以方便地进行跨平台开发。
4 宏定义和函数参数:
符号常量经常与宏定义一起使用,用于创建通用的、可重用的代码块。例如,宏定义可以使用符号常量作为参数,实现一些通用的操作。
#define SQUARE(x) ((x) * (x))
5 条件编译:
符号常量也经常用于条件编译,通过在代码中定义或取消定义不同的符号常量,可以实现在不同条件下编译不同的代码块。
总的来说,符号常量在提高代码的可读性、可维护性以及可移植性方面发挥着重要的作用。然而,应当小心符号常量的使用,确保不会导致不安全的宏替换或其他潜在问题。在一些情况下,使用const关键字声明常量可能是更安全的选择。
6.3 符号常量的优点
符号常量(通常在C或C++中通过宏定义实现)与其他类型的常量(如直接使用字面量或使用const关键字定义的常量)相比具有几个独特的优势:
1 预处理器替换:
符号常量是在预处理阶段被替换的。这意味着在编译器实际编译代码之前,所有的符号常量都会被它们的值替换。这可以在某些情况下提高效率,因为没有变量的存储和查找开销。
2 节省内存:
由于符号常量在预处理时被替换,它们不占用程序运行时的内存空间。相比之下,使用const定义的常量可能会占用存储空间(尽管这取决于具体的编译器和优化设置)。
3 类型灵活性:
符号常量没有固定类型。它们的类型取决于它们所代替的字面量的类型。这种灵活性在某些情况下是有益的,因为相同的符号可以用于不同类型的表达式。
4 更广泛的适用范围:
符号常量可以用在任何需要字面值的地方,包括用作数组维度、用于初始化const变量、作为switch语句中的case标签等。
5 条件编译:
符号常量经常用于条件编译,可以根据不同的宏定义来包含或排除代码段,这在处理不同的编译环境或配置选项时非常有用。
然而,符号常量也有其缺点,例如它们不具有作用域的概念,容易导致命名冲突,并且在调试时可能不如const变量直观。此外,由于预处理器的文本替换特性,它们可能导致一些意想不到的副作用,尤其是在宏定义中。因此,根据具体的使用场景和需求选择适当的常量类型是非常重要的。
七 枚举常量详解
在C语言中,枚举常量是一种用户定义的数据类型,用于定义一组具有相关性的命名整数常量。通过使用枚举,可以提高代码的可读性和可维护性,因为枚举常量使得程序员能够以直观的方式表示一组有意义的值,例如星期几、月份等,而不需要硬编码整数值。枚举常量使用enum关键字定义,可以指定初始值或使用默认值,而枚举常量的作用域覆盖整个枚举类型,使得它们可以在程序的不同部分使用。
另外,在C语言中,枚举常量实际上是整数常量的一种形式,因此它们在底层被编译器解释为整数值。枚举常量在编译时被赋予一个整数值,这个值可以是任何合法的整数类型,通常是int类型。
7.1 枚举常量基本特点
1 定义枚举:
使用enum关键字来定义枚举类型,其基本语法如下:
enum enumeration_name { constant1, constant2, constant3, // ... };
例如:
enum Weekday { Monday, Tuesday, Wednesday, Thursday, Friday, Saturday, Sunday };
2 默认赋值:
如果没有为枚举中的常量指定值,编译器会为它们分配默认值,从0开始,逐个递增。在上述的Weekday例子中,Monday的值是0,Tuesday的值是1,依此类推。
3 指定常量值:
可以为枚举中的常量指定特定的值。指定值后,后续的常量会在指定值的基础上递增。
enum Month { January = 1, February, March, April, May, June, July, August, September, October, November, December };
4 使用枚举常量:
定义枚举后,可以使用枚举常量来声明变量、作为函数参数或用于其他需要整数常量的地方。
enum Weekday today; today = Wednesday; printf("Today is %d\n", today); // 输出: Today is 2
5 枚举的作用域:
枚举常量的作用域在整个枚举类型内,可以在枚举外部使用枚举常量。
enum Color { Red, Green, Blue }; enum Color myColor = Red;
6 枚举与整数的互换:
枚举类型被赋予整数值,因此可以将枚举类型转换为整数,反之亦然。这种转换对于一些需要整数值的函数和操作是有用的。
enum Month currentMonth = March; int monthValue = currentMonth; // 将枚举转换为整数
枚举常量在代码中提供了一种更加清晰和可维护的方式来表示一组相关的常量值。通过使用枚举,可以使代码更易读,减少硬编码的整数值,提高代码的可读性和可维护性。
7.2 枚举常量常见使用场景
1 定义有限的状态或选项:
当需要表示一组有限的状态、选项或类别时,枚举常量是一个很好的选择。例如,表示一周中的每一天、月份、颜色、文件状态等。
2 提高代码可读性:
使用枚举常量可以使代码更加清晰和易读。通过给常量命名,可以直观地了解其含义,而不是使用数字或字符串,这有助于降低错误发生的可能性并提高代码的可维护性。
3 减少魔术数字:
在代码中避免使用“魔术数字”(magic numbers)是一种良好的编程实践。枚举常量允许开发人员为特定的整数值赋予有意义的名称,从而减少代码中的魔术数字,并使其更具可读性。
4 提高代码的健壮性:
枚举常量可以帮助在编译时捕获一些错误,例如拼写错误或意外的值。由于枚举常量是在编译时检查的,因此如果使用了未定义的常量或者尝试赋予不允许的值,编译器会发出警告或错误信息。
5 增强代码的可维护性:
使用枚举常量可以使得代码更易维护。如果需要对常量值进行更改或扩展,只需在枚举声明中进行修改即可,而无需在代码的各个位置进行手动更改。
谢谢大家的阅读!
如果觉得这篇博客对你有用的话,别忘记三连哦。
我是甜美的江,让我们我们下次再见