C语言中的常量

整型常量

常量是指在程序运行期间其数值不发生变化的数据。整型常量通常简称为整数。

整数可以是十进制数、八进制数和十六进制数。例如,十进制的数值3356可以有下列二种不同的表示形式:

  • 八进制数 06434
  • 十六进制数 0xd1c

Tip:当我们判断十六进制或八进制的时候可以把该进位制上的每位数转化为四位二进制(对应十六进制)/三位二进制(对应八进制)的形式, 然后把这个二进制数与常量取值的最大二进制位数进行比较。因为一个十六进制中的每位数所能选用的数码区间为0·15, 而这刚好对应4个二进制位的值域, 八进制则对应三个二进制位

浮点常量

浮点常量又称为实数,一般含有小数部分。

在C语言中,实数只有十进制的实数,分为单精度和双精度。实数有两种表示方法, 即一般形式和指数形式。

一般形式的实数基本形式如下:

  • 例如, 3.5 , -12.5, 3.1415926
    在这里插入图片描述

指数常量

指数形式的实数一般是由尾数部分、字母e或E和指数部分组成。 当一个实数的符号为正号时,可以省略不写,其表示的一般形式如下:

  • 1.176e+10 表示 1.176×1010
  • 3.5789e-8 表示 -3.5789×10-8
  • 通常表示特别大或特别小的数
    在这里插入图片描述

字符常量

字符常量是指一个单一字符, 其表示形式是由两个单引号包括的一个字符。

e.g. ’A‘, ‘a’, ‘Q’, ‘0’, ‘9’, ‘+’, ‘:’, ‘?’, ‘$’ 都是字符常量。

在C语言中, 字符常量具有数值。字符常量的值就是该字符的ASCII码值。所以我们可以把字符常量看做一个字节的正整数。

例如,

  char  a, b, u, v

  a = 'F' ;         //  将70赋值给a

  b = 'A'+2;        //  b存放的是 'C' 字符

  u = '  ' + 'B';   //  u存放的是 'b' 字符

  v= 'b' - 32;      //  v存放的是 'B' 字符

它们分别相当于下列运算;

  a= 70;

  b= 65+2;

  u= 32+66 ;

  v= 97-32;

小写字母和大写字母之间的ASCII值之间差32, 也就是一个空格所对应的ASCII整数值

Waring

字符0和整数0, 虽然它们打印出来没有差别, 但它们不是同一个概念
在这里插入图片描述

code

在这里插入图片描述

result:
在这里插入图片描述

当编译器看到字符0的时候, 它会认为这是整数48

Question:如果想把输入的字符0变成真正意义上的0而不是数字48, 如何转化呢?
整数0 = ‘0’ - 48

整数0-9和字符0-9之间差48

字符串常量

所谓字符串常量是指用双引号括起来的一串字符来表示的数据。(字符串以\0结尾) 例如:“9”—‘9’,’\0’

字符串常量要么借用一个指针指向字符串常量, 要么建一个数组来存储一个字符串常量

下面给出几个字符串常量的例子:

  • “Hello!”, “StudentS”, “9”, “LINUX", “李四”

  • “北京海淀成府路***号", “姓名:”, “****@163.com", “”

  • 字符串常量在C语言中以字符数组的形式存在,例如 “abc” 实际上会被编译器存储为一个以字符 ‘a’、‘b’、‘c’ 和 ‘\0’(表示字符串结束的空字符)结尾的字符数组。当使用指针来指向字符串常量时,它实际上指向了该字符数组的首地址。
  • 只包含一个字符的字面串(字符串)不同于字符常量(字符)。字面串"a"是用指针来表示的,这个指针指向 存放字符"a"(后面紧跟空字符)的内存单元。字符常量’a’是用整数(字符集的数值码)来表 示的。

标识常量

所谓标识常量是指用标识符代替常量使用的一种常量, 其名称通常是一个标识符。

标识常量也叫符号常量,一般用大写英文字母的标识符。

在使用之前必须预先定义。说明形式为:

#define <标识常量名称> <常量>

例如

#define   MAX    50

#define   PI       3.1415926

#define   NULL    0

#define   EOF     -1

#define   ERROR   -1
  • 其中,MAX、PI、NULL、 EOF和ERROR都是标识常量, 它们代替的常量分别是50、3.1415926、0 、-1和-1 。

  • 一般情况,每个标识常量说明式子只能给出一个标识常量,并且占据一个书写行。

  • 定义一个宏名字之后,可以在其他宏定义中使用,例如:

  #define ONE 1

  #define TWO ONE+ONE

  #define THREE ONE+TWO  

注意宏是原样替换!!!
比如下面这个例子
在这里插入图片描述

大部分人第一次见到它可能会这样想
1 + (1 + 1)\*20 + 10 == 51, 但这是错的, 与我们常规的思维不同, 正确的方法应该是这样的
1 + 1 + 1*20 + 10 == 32
在这里插入图片描述

  • 所以此处应当注意, 宏是替换不是运算, 这是一个陷阱, 一般人很容易把它算出来如果真的想把它算出来我们该如何做?

    • 现在我们随机的更改源代码,在这里我们更改了第3行代码把原来的1改为了1 + 1,当然也可以更改为(1 + 1) , 更改此处的目的是为了使预处理后的效果更直观一点
    • 在这里插入图片描述

    然后我们再使用gcc编译器生成预处理后的源代码

    1. 首先输入gcc -E ..., 这里-o define.i 代表生成的文件的名称, -E代表预处理源代码
      在这里插入图片描述

    2. 然后使用vi define.i打开并查看预处理后的文件, 然后在命令行模式下输入G(大写 )可以快速的将光标移到末尾, 可以看到预处理后的代码,宏只是进行替换并没有进行运算, 这也进一步得出了宏只进行简单的替换, 并没有其他的操作这一结论, 所以宏的注意事项大家也应该明白了, 在这里一定要注意它的运算规则, 就是原样展开, 当然有想法的话在定义的时候该加括弧加括弧, 可以避免一些问题

    3. 在这里插入图片描述

  • 如果一个串长于一行,可在行尾用反斜线”\”续行

    #define LONG_STRING “This is a very very long \
    
    String that is used as an example”
    

总结与思考

主要讲解了基本数据的常量、标识常量。

思考:

  • 字符常量和字符串常量的区别是什么?
    答:1. 字符常量和字符串常量的区别:

    • 字符常量是单个字符,用单引号括起来,例如:‘A’,‘b’,‘1’,'@'等。
    • 字符串常量是由多个字符组成的字符序列,用双引号括起来,例如:“Hello”,“C programming”,"12345"等。

    示例:

    char c = 'A';           // 这是字符常量
    char str[] = "Hello";   // 这是字符串常量
    

    注意:字符常量在内存中以整数形式表示字符的ASCII码值,而字符串常量是以字符数组的形式存储在内存中,以空字符 ‘\0’ 结束。

  • 浮点常量有几种表式形式?
    答:浮点常量有两种表示形式:

    • 十进制形式:由数字和小数点组成,可以带有指数部分,例如:3.14,0.123,2.5e-3(表示2.5乘以10的负3次方)等。
    • 十六进制形式:以0x或0X开头,后面跟着十六进制数字和小数点,例如:0x1.2p3(表示1.2乘以2的3次方)。

    示例:

    float num1 = 3.14;        // 十进制形式的浮点常量
    float num2 = 0x1.2p3;     // 十六进制形式的浮点常量
    

    注意:浮点常量可以用于表示带小数点的实数值,而且可以使用指数形式表示非常大或非常小的数值,十六进制形式一般用于特定场景,例如在硬件编程或精确表示浮点数时使用。

<think>嗯,用户现在想了解C语言常量的内存分配机制。首先,我需要回忆一下C语言常量的类型和存储方式。根据引用里的信息,C语言的内存分配包括静态内存、动态内存、堆栈等。常量可能属于不同的内存区域,具体要看它们的定义方式。 用户提到的常量可能包括字面常量、const修饰的常变量、#define定义的宏常量,还有枚举常量。这些不同类型的常量在内存中的存放位置可能不同。比如,字面常量如字符串可能存储在只读数据段,而const变量可能放在栈或全局区,取决于定义的位置。 引用5提到,const修饰的常变量本质还是变量,但具有只读属性。所以它们的存储位置应该和普通变量类似,比如全局的const可能在全局区,函数内的const在栈上。而#define定义的宏在预处理阶段替换,不占用内存,但字面常量如数字或字符串会有存储位置。 枚举常量在引用5中也有说明,它们属于整型常量,可能存储在代码段或只读数据段。需要确认枚举常量的具体存储方式,可能和编译器的实现有关。 另外,字符串常量通常存储在.rodata段或.data段的只读部分,这部分可能在静态存储区。而像全局变量和静态变量,根据引用1和3,全局变量在静态内存区,所以全局的常量可能也在这里。 动态分配的内存如malloc是在堆上,但常量一般不会在这里,除非用户显式分配并初始化。不过用户的问题是关于常量的,所以可能不需要涉及堆。 总结下来,需要分类型讨论:字面常量、const变量、宏、枚举,各自的内存分配位置。同时要引用相关的引用资料,比如引用5提到const是常变量,引用1和3关于静态内存和堆栈的区别。 可能用户还混淆了常量和常变量,需要明确说明const变量和真正常量的区别。比如,const变量实际可能存储在栈或全局区,而字面量在只读段。 另外,需要注意内存段的划分,如代码段、数据段、BSS、堆、栈等。常量的存储位置可能在这些不同的段中,具体取决于类型和定义方式。 需要确保回答结构清晰,分点说明每种常量的内存机制,并引用正确的资料。同时生成相关问题时要围绕C语言常量、内存分配的其他方面,比如和动态内存的区别,或者不同常量类型的使用场景。</think>### C语言常量内存分配机制 在C语言中,常量的内存分配方式取决于其类型和定义方式,主要分为以下几类: --- #### 1. **字面常量** 字面常量(如整数、浮点数、字符串字面量)存储在**只读数据段(`.rodata`)**中。例如: ```c printf("Hello"); // 字符串字面量"Hello"存储在.rodata段 int a = 10; // 字面量10可能直接嵌入指令或存储在.rodata段 ``` - **特点**:生命周期与程序一致,不可修改,内存由编译器静态分配[^3][^5]。 --- #### 2. **`const`修饰的常变量** `const`修饰的变量本质是**只读变量**,其存储位置取决于定义位置: - **全局作用域**:存储在**全局/静态存储区**(`.data`或`.bss`段)。 ```c const int MAX = 100; // 存储在.data段(已初始化)或.bss段(未初始化) ``` - **局部作用域**:存储在**栈区**,函数执行时分配,结束后释放。 ```c void func() { const int local_const = 5; // 存储在栈区 } ``` - **特点**:语法层面不可修改,但通过指针仍可能间接修改(依赖编译器实现)。 --- #### 3. **`#define`定义的宏常量** 宏常量通过预处理器替换,**不占用内存**。例如: ```c #define PI 3.14159 // 编译时替换为字面量,无独立内存空间 ``` - **特点**:仅文本替换,类型安全性较低,无内存分配过程[^5]。 --- #### 4. **枚举常量** 枚举常量本质是**整型常量**,通常存储在**代码段或`.rodata`段**: ```c enum Color { RED, GREEN, BLUE }; // RED=0, GREEN=1, BLUE=2 ``` - **特点**:编译时转换为整数值,内存分配方式与字面常量类似[^5]。 --- ### 内存区域对比 | 常量类型 | 存储区域 | 生命周期 | 是否可修改 | |-----------------|------------------|----------------|-----------| | 字面常量 | `.rodata` | 程序运行期 | 否 | | 全局`const`变量 | 全局/静态存储区 | 程序运行期 | 否[^1] | | 局部`const`变量 | 栈区 | 函数执行期 | 否(语法层面)| | 枚举常量 | 代码段/`.rodata` | 程序运行期 | 否 | --- ### 关键机制 1. **只读保护**:字面常量和全局`const`变量通常位于只读段,修改会触发段错误[^3]。 2. **编译器优化**:常量可能直接嵌入指令(如立即数),减少内存访问。 3. **符号表管理**:编译器将常量名称映射到固定地址,简化运行时寻址。 ---
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

DevGeek

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值