C++ 常量区 堆区 栈区

2024-03-17 15:38
文章标签 c++ 常量 堆区 栈区

本文主要是介绍C++ 常量区 堆区 栈区,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

C++中类的变量可以通过static、const、static const来修饰,不同的修饰在不同的情况下表示不同的含义。下面7少带大家一块详细解读一下他们的用处。

首先我们需要先了解程序运行期间的内存分区:

1.代码区:存放CPU指令码。

2.常量区:存放只读常量,该区只读,不可写。

3.静态区:存放静态变量。该区在程序编译完成后就决定了其大小,程序运行期间该区的大小不会变。该区可读写。

4.动态区:又分为堆区和栈区,程序运行期间其大小处于动态变化中。处于该区的变量也会时而被创建时而被销毁。


static关键字:

经过static修饰的变量会作为类的属性而不是实体属性存在。

static修饰的变量作为程序运行时的静态变量,存在于内存的静态区,静态区的数据初始化工作由操作系统在加载完程序后执行main函数前进行。操作系统在加载完程序后,将常量区中存放的变量初值复制给静态变量,完成其初始化。

static修饰的变量通过int ClassName::value=1这种方式进行初始化。此时不再需要static 关键字。程序运行期间也可以对变量进行赋值操作。

const关键字:

经过const修饰的属性,顾名思义是指常量。

const修饰的属性仍然属于实体属性,所以其初始化工作,需要由构造函数的初始化列表中完成。而且也只能在构造函数的初始化列表中初始化,运行期间将不能再对const属性进行修改。值得注意的是,虽然经过const修饰,但是因为变量属于实体属性,而实体对象存在于动态区,所以const属性也属于动态区,所以可以通过取址直接操作指向的内存的值,以绕过编译器对其只读的限制检查。

static const关键字:

static const 和 const static 含义相同。

static const有两种用法,一种是作为预编译声明,一种是作为类的静态常量属性。

当作为预编译声明时,static const 属性必须在声明时即指定值,而且类型仅限基本数据类型。用法如下:

class A

{

static const int a =1;

}

此时相当于C语言中的 #define a 1 宏定义了一个宏变量a,但是C++的这种方式比C的#define的优势在于,可以对类型进行检查和限制,减少了编译期间因为类型隐士转换而造成的潜在风险。

此时的 const static常量既不存在于动态区也不存在与静态区(应该是存在于常量区或代码区。。。),而是由编译器在编译期间就直接进行了值替换。也因为这个原因不可以对其进行取地址操作,因为他根本没有地址。

另一种用法是作为类的静态常量属性,此时,不能在类的声明处进行初始化。而需要通过 int ClassName::value = 1;的方式进行初始化赋值。

const static常量存在于内存的常量区,有操作系统加载程序时,加载到内存的常量区。所以可以对其取址,但是不能对该区的内存进行写操作,因为这个区从操作系统级进行了只读限定,任何对该内存区的写操作会导致程序崩溃。


总结:

static const 作为预编译声明使用时,相当于C的#define,但是需要编译器进行类型检查,保证了程序的健壮性。此时其只能用基本数据类型。

static const 作为类的常量属性,因为常量区是在程序真正执行代码前进行初始化,所以其也必须是基本数据类型。

static const 和const的区别是:

const声明的只读变量,在程序运行期间不能对其进行写操作,写操作将无法通过编译,也就是说它是通过编译器控制的只读,所以如果想下面这样:

A a;

int * pa = (int*)&a.a;

*pa = 2;

则可以绕过编译器修改他的值。

但是 static const属性虽然也可以取址,但是对其写操作将会导致程序崩溃。因为static const 存在于常量区,而const存在于动态区。

static const 和 static的区别是,static 存在于静态区,该区可以进行写操作,其初始化的值也会存在常量区,程序启动后由操作系统从常量区取值赋值给static变量。 

最后,欢迎吐槽和讨论。

最后转两个例子:

第一个:

#include<iostream.h>

void main()
{
char a[]="abc";栈 
char b[]="abc";栈 
char* c="abc";abc在常量区,c在栈上。
char* d="abc"; 编译器可能会将它与c所指向的"abc"优化成一个地方。
const char e[]="abc";栈 
const char f[]="abc";栈 

cout << a << " " << b << " " << c << " " <<d << " " <<e << " " <<f <<endl;
cout<<(a==b?1:0)<<endl<<(c==d?1:0)<<endl<<(e==f?1:0)<<endl;
}
以上程序的输出结果为 
abc abc abc abc abc abc 
0
1
0


第二个:

//main.cpp

#include<iostream.h>
#include<string.h>
//#include<malloc.h>   //malloc的头文件可以为#include<malloc.h>也可以为#include<stdlib.h>
#include<stdlib.h>
int a = 0; 全局初始化区 
char *p1; 全局未初始化区 
main() 
{

const char* m = "123456";
int b; 栈 
char s[] = "abc"; 栈 
char *p2; 栈 
char *p3 = "123456"; 123456在常量区,p3在栈上。 
static int c =0; 全局(静态)初始化区 
p1 = (char *)malloc(10); 
p2 = (char *)malloc(20); 
分配得来得10和20字节的区域就在堆区。 
strcpy(p1, "123456"); 123456放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。 

cout<<(m == p3?1:0)<<endl;//结果为1
cout<<(p1 == p3?1:0)<<endl;//结果为0
cout<<p1<<" "<<p3<<" "<<endl;//结果为123456 123456
}




这篇关于C++ 常量区 堆区 栈区的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/819379

相关文章

C++中实现调试日志输出

《C++中实现调试日志输出》在C++编程中,调试日志对于定位问题和优化代码至关重要,本文将介绍几种常用的调试日志输出方法,并教你如何在日志中添加时间戳,希望对大家有所帮助... 目录1. 使用 #ifdef _DEBUG 宏2. 加入时间戳:精确到毫秒3.Windows 和 MFC 中的调试日志方法MFC

深入理解C++ 空类大小

《深入理解C++空类大小》本文主要介绍了C++空类大小,规定空类大小为1字节,主要是为了保证对象的唯一性和可区分性,满足数组元素地址连续的要求,下面就来了解一下... 目录1. 保证对象的唯一性和可区分性2. 满足数组元素地址连续的要求3. 与C++的对象模型和内存管理机制相适配查看类对象内存在C++中,规

在 VSCode 中配置 C++ 开发环境的详细教程

《在VSCode中配置C++开发环境的详细教程》本文详细介绍了如何在VisualStudioCode(VSCode)中配置C++开发环境,包括安装必要的工具、配置编译器、设置调试环境等步骤,通... 目录如何在 VSCode 中配置 C++ 开发环境:详细教程1. 什么是 VSCode?2. 安装 VSCo

C++11的函数包装器std::function使用示例

《C++11的函数包装器std::function使用示例》C++11引入的std::function是最常用的函数包装器,它可以存储任何可调用对象并提供统一的调用接口,以下是关于函数包装器的详细讲解... 目录一、std::function 的基本用法1. 基本语法二、如何使用 std::function

【C++ Primer Plus习题】13.4

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream>#include "port.h"int main() {Port p1;Port p2("Abc", "Bcc", 30);std::cout <<

C++包装器

包装器 在 C++ 中,“包装器”通常指的是一种设计模式或编程技巧,用于封装其他代码或对象,使其更易于使用、管理或扩展。包装器的概念在编程中非常普遍,可以用于函数、类、库等多个方面。下面是几个常见的 “包装器” 类型: 1. 函数包装器 函数包装器用于封装一个或多个函数,使其接口更统一或更便于调用。例如,std::function 是一个通用的函数包装器,它可以存储任意可调用对象(函数、函数

C++11第三弹:lambda表达式 | 新的类功能 | 模板的可变参数

🌈个人主页: 南桥几晴秋 🌈C++专栏: 南桥谈C++ 🌈C语言专栏: C语言学习系列 🌈Linux学习专栏: 南桥谈Linux 🌈数据结构学习专栏: 数据结构杂谈 🌈数据库学习专栏: 南桥谈MySQL 🌈Qt学习专栏: 南桥谈Qt 🌈菜鸡代码练习: 练习随想记录 🌈git学习: 南桥谈Git 🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈🌈�

【C++】_list常用方法解析及模拟实现

相信自己的力量,只要对自己始终保持信心,尽自己最大努力去完成任何事,就算事情最终结果是失败了,努力了也不留遗憾。💓💓💓 目录   ✨说在前面 🍋知识点一:什么是list? •🌰1.list的定义 •🌰2.list的基本特性 •🌰3.常用接口介绍 🍋知识点二:list常用接口 •🌰1.默认成员函数 🔥构造函数(⭐) 🔥析构函数 •🌰2.list对象

06 C++Lambda表达式

lambda表达式的定义 没有显式模版形参的lambda表达式 [捕获] 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 有显式模版形参的lambda表达式 [捕获] <模版形参> 模版约束 前属性 (形参列表) 说明符 异常 后属性 尾随类型 约束 {函数体} 含义 捕获:包含零个或者多个捕获符的逗号分隔列表 模板形参:用于泛型lambda提供个模板形参的名

6.1.数据结构-c/c++堆详解下篇(堆排序,TopK问题)

上篇:6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)-CSDN博客 本章重点 1.使用堆来完成堆排序 2.使用堆解决TopK问题 目录 一.堆排序 1.1 思路 1.2 代码 1.3 简单测试 二.TopK问题 2.1 思路(求最小): 2.2 C语言代码(手写堆) 2.3 C++代码(使用优先级队列 priority_queue)