「C系列」C 常量
文章目录
- 一、C 常量
- 二、C 整数常量
- 三、C 浮点常量
- 四、C 字符串常量
- 五、const 关键字
- 1. 使用`const`修饰基本数据类型
- 2. 使用`const`修饰指针
- 3. 使用`const`修饰数组和函数参数
- 4. `const`和宏的区别
- 六、相关链接
一、C 常量
在C语言中,常量(Constants)是那些值在程序执行期间不会改变的量。常量可以是整数、浮点数、字符或字符串等。常量通常用于表示一些固定的值,如数学常数(如π或e)、物理常数(如光速c)或其他在程序中不应该改变的值。
(图片来源网络,侵删)在C语言中,可以使用多种方式定义常量:
- #define 预处理指令:这是定义常量的最常见方法。使用 #define 可以为标识符(即常量名)分配一个值。这个值在编译时会被替换为其对应的值。
#define PI 3.14159 #define MAX_SIZE 100
- const 关键字:从C99标准开始,可以使用 const 关键字来声明常量。const 修饰的变量必须在声明时初始化,并且其值在程序执行期间不能被修改。
const int DAYS_IN_WEEK = 7; const float GRAVITY = 9.81;
注意:虽然 const 修饰的变量在逻辑上是常量,但在某些情况下(例如,作为数组的大小或函数参数),它们可能不能像 #define 定义的常量那样使用。
3. 枚举(Enumerations):枚举是一种用户定义的数据类型,允许你为整数值指定名称。虽然枚举值在逻辑上是常量,但它们在C语言中并不是真正的常量(即它们可以被赋值,但这通常是不推荐的)。
enum Color { RED, GREEN, BLUE };在这种情况下,RED、GREEN和BLUE都是枚举常量,但它们的值通常是整数(从0开始)。
4. 内联函数和宏:虽然这些不是真正的常量,但它们可以用于在编译时替换代码中的某些值或表达式。这种方法比使用简单的 #define 宏更灵活,因为它允许在替换时进行类型检查和参数检查。
5. 只读变量:在某些情况下,你可能想要将一个变量的值设置为只读,以便在程序的其他部分中无法修改它。这可以通过将变量声明为 static 并将其初始化为一个值来实现,但这种方法并不是真正的常量,因为变量仍然可以在声明它的同一文件的其他函数中被修改。
在选择使用哪种方法来定义常量时,你应该考虑你的具体需求、代码的可读性和可维护性。对于简单的常量值(如数学常数或物理常数),#define 或 const 通常是最合适的选择。对于需要更复杂逻辑或类型检查的情况,内联函数或宏可能更合适。
二、C 整数常量
在C语言中,整数常量是直接表示的整数数值,不需要任何变量来存储它们。整数常量可以是十进制、八进制或十六进制。以下是关于C语言中整数常量的详细信息:
- 十进制整数常量:这是最常见的整数常量形式,没有特定的前缀。它们只是由数字0-9组成的序列。
int x = 123; // 123是一个十进制整数常量
- 八进制整数常量:八进制整数常量以数字0开始,后面跟着0-7的数字。
int y = 0123; // 0123是一个八进制整数常量,等于十进制的83
注意:在C99及以后的标准中,前缀0也可以用来表示一个八进制字面量,但在C89中,如果0后面跟着的字符不是八进制数字(0-7),则会导致编译错误。
- 十六进制整数常量:十六进制整数常量以0x或0X开始,后面跟着0-9的数字和A-F(或a-f)的字母。
int z = 0xABC; // 0xABC是一个十六进制整数常量,等于十进制的2748
- 后缀:整数常量可以带有后缀来表示其类型。在C99及以后的标准中,可以使用U或u(对于无符号整数)和L或l(对于长整数)作为后缀。在C11中,还引入了LL或ll作为长长长整数的后缀。
unsigned int a = 123U; // 123U是一个无符号整数常量 long int b = 123L; // 123L是一个长整数常量 long long int c = 123LL; // 123LL是一个长长长整数常量
- 整数常量的类型:整数常量的实际类型取决于其值和上下文。例如,小的整数值可能默认为int类型,而大的整数值可能默认为long或long long类型。无符号整数常量可以通过添加U或u后缀来明确指定。
- 整数的范围:C语言中的整数常量可以表示很大的值,具体取决于编译器和平台。但是,如果整数常量超出了可以表示的范围,则可能导致编译错误或运行时错误(如果编译器没有捕获到这个问题)。
当在代码中使用整数常量时,最好明确指定其类型(如果可能的话),以确保代码的可读性和可维护性。此外,还应该注意整数溢出的问题,确保整数常量在程序中的使用不会导致意外的结果。
三、C 浮点常量
在C语言中,浮点常量(也称为浮点数)用于表示有小数部分的数值。浮点常量可以是十进制表示法,也可以是科学记数法(也称为指数表示法)。以下是关于C语言中浮点常量的详细信息:
- 十进制浮点常量:浮点常量可以直接使用十进制数表示,包含整数部分、小数点和小数部分。
float pi = 3.14159; // 3.14159是一个十进制浮点常量 double largeNumber = 123456789.0123456789; // 另一个十进制浮点常量
- 科学记数法(指数表示法):浮点常量也可以表示为尾数乘以基数(通常为10)的指数。在科学记数法中,尾数和指数之间用e或E分隔。
float smallNumber = 1.23e-4; // 等于0.000123 double bigNumber = 1.23E4; // 等于12300.0
在科学记数法中,e(或E)前面的数字是尾数,e(或E)后面的数字是指数。尾数是一个有效数字范围在1到10之间(不包括10)的浮点数,而指数是一个整数,表示基数(10)的幂次。
- 浮点常量的类型:浮点常量的默认类型是double,但如果你希望它是float类型,你可以在数值后面加上f或F后缀。
float myFloat = 3.14f; // 3.14f是一个float类型的浮点常量 double myDouble = 3.14; // 3.14是一个double类型的浮点常量(默认)
请注意,虽然浮点常量可以隐式地转换为float类型(当它们被赋值给float类型的变量时),但直接写float类型的字面量(即带有f或F后缀的)可以提高代码的可读性和明确性。
- 浮点数的精度和范围:浮点数的精度和范围取决于它们的类型(float或double)以及具体的实现(编译器和硬件)。一般来说,double类型比float类型具有更高的精度和更大的范围。然而,由于浮点数的表示方式(基于二进制),它们可能无法精确地表示所有的十进制小数。因此,在进行浮点数运算时,需要特别注意精度问题。
- 特殊浮点值:C语言还支持一些特殊的浮点值,如正无穷大(INFINITY)、负无穷大(-INFINITY)和非数字(NAN,表示“不是一个数字”的结果,如0除以0)。这些值在头文件中定义,并且主要用于浮点数的比较和错误处理。
四、C 字符串常量
在C语言中,字符串常量是由双引号 (") 包围的一系列字符,包括字母、数字、标点符号和特殊字符。字符串常量以空字符(\0)作为结尾,这是由编译器自动添加的,用于标记字符串的结束。
下面是一个字符串常量的例子:
const char *str = "Hello, World!";
在这个例子中,"Hello, World!" 是一个字符串常量,它被存储在只读内存区域(通常是程序的文本段或数据段)。const char *str 是一个指向这个字符串常量的指针,const 关键字表明这个指针指向的内容(即字符串常量本身)是不可修改的。
虽然字符串常量本身是不可修改的,但你可以通过指针来操作字符串的副本(即,你可以创建一个字符数组,并将字符串常量复制到该数组中,然后修改该数组的内容)。
char buffer[14]; // 足够存储 "Hello, World!" 和一个额外的 '\0' 字符 strcpy(buffer, "Hello, World!"); // 使用 strcpy 函数将字符串常量复制到 buffer 中 buffer[7] = ','; // 修改 buffer 中的字符(但不影响原始的字符串常量)
注意,strcpy 函数是一个标准库函数,它定义在 头文件中。在使用它之前,你需要包含这个头文件。
字符串常量在C语言中实际上是一个字符数组,但它的内容是不可变的。编译器通常会将字符串常量存储在程序的只读数据段中,以节省空间并防止程序意外地修改这些常量。试图修改一个字符串常量(例如,通过解引用指向它的指针并尝试改变其内容)会导致未定义的行为,并且很可能会导致程序崩溃。
字符串常量在C语言中并不是真正的数据类型,但它们经常被用作字符数组或字符指针的初始值。当你声明一个字符数组或字符指针并给它赋一个字符串常量时,你实际上是在让这个数组或指针指向存储该字符串常量的内存位置。
五、const 关键字
在C语言中,const关键字用于指定一个变量的值是不可变的,即它是一个常量。const可以用于修饰多种数据类型,包括基本数据类型(如int、float、char等)、指针类型以及更复杂的数据结构。
1. 使用const修饰基本数据类型
const int x = 10; // x 是一个整型常量,其值不能被修改
在这个例子中,x被声明为一个const int,这意味着一旦它被初始化,它的值就不能再被改变。尝试修改x的值将会导致编译错误。
2. 使用const修饰指针
当const用于修饰指针时,有两种可能的解释,取决于const的位置:
- 指向常量的指针:指针指向的内容是不可变的。
const int *ptr = &x; // ptr 是一个指向整型常量的指针,不能通过 ptr 修改 x 的值 // *ptr = 20; // 这行代码会编译失败,因为不能通过 ptr 修改 x 的值
- 常量指针:指针本身的值(即它所指向的地址)是不可变的,但指针指向的内容可以被修改(除非内容本身也被声明为const)。
int y = 20; int *const ptr2 = &y; // ptr2 是一个常量指针,指向整型变量 y // ptr2 = &x; // 这行代码会编译失败,因为不能改变 ptr2 所指向的地址 *ptr2 = 30; // 这行代码是合法的,可以通过 ptr2 修改 y 的值
注意:const既可以修饰指针指向的内容,也可以修饰指针本身,具体取决于const在声明中的位置。如果const在*之前,那么指针指向的内容是不可变的;如果const在*之后(或者在指针声明符的最右侧),那么指针本身的值是不可变的。
3. 使用const修饰数组和函数参数
const也可以用于修饰数组和函数参数,以确保这些值在函数内部不会被修改。
void printArray(const int arr[], int size) { // 在这个函数内部,你不能修改 arr 数组中的任何元素 // ... } const int myArray[] = {1, 2, 3, 4, 5}; // myArray 是一个包含常量的数组在这个例子中,printArray函数的参数arr是一个指向整型常量的指针,这意味着在函数内部不能修改arr指向的数组元素。同样,myArray数组被声明为包含常量,所以它的元素也不能被修改。
4. const和宏的区别
虽然const和宏(通常使用#define定义)都可以用来定义常量,但它们之间有一些重要的区别:
- 类型检查:const常量具有类型,因此编译器可以进行类型检查。而宏只是简单的文本替换,没有类型信息。
- 作用域:const常量具有明确的作用域(例如,在函数内部或全局范围内),而宏的作用域通常是文件级别的(除非它们被定义为static)。
- 存储方式:const常量通常存储在程序的只读数据段中,而宏在编译时被直接替换为相应的值。
- 调试:由于const常量具有类型和作用域,因此它们更容易在调试过程中被识别和跟踪。而宏在编译后就不再存在,因此可能更难以调试。
六、相关链接
- Visual Studio Code下载地址
- Sublime Text下载地址
- 「C系列」C 简介
- 「C系列」C 基本语法
- 「C系列」C 数据类型
- 「C系列」C 变量及常见问题梳理
