单个变量的地址:
在C++中,地址是指内存中的位置。每个变量在内存中都有一个唯一的地址。通过地址,我们可以读取和修改变量的值,也可以创建指向对象的指针。
地址是一个整数值,用十六进制表示。地址的大小取决于操作系统的位数,例如32位操作系统中的地址通常是32位(即4个字节,8位十六进制数),64位操作系统中的地址通常是64位。可以使用取地址运算符(&)来获取变量的地址。例如,如果有一个整数变量x,可以使用"&x"来获取x的地址,当&作用于一个对象上时,它返回了该对象的地址。
int x;
cout << &x << endl;
细节来了!对照代码和图片,这里会输出4个地址吗?只会输出第一个地址0x1000,因为可以通过int是4个字节+第一个地址,可以计算得到由0x1000、0x1001、0x1002、0x1003共同组成了变量x的储存空间。
数组的地址:
在C++中,一维数组可以看作是一系列相同类型的元素的集合。图中我们申请了一个长度为4的整型数组,计算机给a[4]分配了快连续的区间0x1000~0x1015,其中数组首地址可以用过&a[0]来获取,c++还特别规定了数组名就是数组的首地。有关一维、二维数组的指针应用,请同学们移步C++指针类型的概念及基本应用。
内存地址空间(选读):
内容比较多,请同学们结合图片来食用。
栈是一种动态分配内存的区域,用于存储函数的局部变量和函数调用的上下文信息。
当一个函数被调用时,栈会为该函数分配一块内存空间,用于存储函数的局部变量和函数调用的上下文。局部变量是在函数内部定义的变量,它们的生命周期与函数的执行周期相对应。当函数调用结束时,栈会自动释放该函数的内存空间,包括其中的局部变量。
栈中的内存空间是按照先进后出的原则进行分配和释放的,每当一个函数被调用时,栈会将函数的局部变量和函数调用的上下文信息入栈(分配内存),当函数调用结束时,栈会将这些信息出栈(释放内存)。
由于栈的自动管理特性,局部变量的分配和释放速度相对较快,适合存储函数内部临时使用的数据。然而,需要注意的是,栈的大小是有限的,过多的局部变量或过深的函数调用可能导致栈溢出的错误。
注意,全局变量、静态变量和常量等通常存储在另外的内存区域。这些变量的生命周期不依赖于函数的执行,它们在程序运行期间一直存在。
堆是一种动态分配内存的区域,用于存储程序的动态分配数据,如使用new或malloc函数分配的内存。堆的大小在程序运行时是可变的,通常较大,且需要手动管理(必须手动释放分配过的内存)。堆中的内存分配和释放由程序员负责,需要显式地调用delete或free函数来释放已分配的内存。由于堆的动态管理特性,它的分配和释放速度相对较慢。
因此,从大小上来说,堆的大小通常比栈大。栈的大小是由操作系统或编译器预先分配的,而堆的大小可以根据程序的需要进行动态调整。
#include <bits/stdc++.h>
using namespace std;
//常量区
const int N=100;
//全局数据区
int a,b,c;
int main() {
//栈
int x,y,z;
//堆
int *p = new int[3];
printf("---常量区地址分配情况---\n");
printf("常量N的地址: %p\n", &N);
printf("---全局数据区地址分配情况---\n");
printf("全局变量a的地址: %p\n", &a);
printf("全局变量b的地址:%p\n", &b);
printf("全局变量c的地址:%p\n", &c);
printf("---堆区地址分配情况---\n");
printf(" p[0]的地址: %p\n", p);
printf(" p[1]的地址: %p\n", p+1);
printf(" p[2]的地址: %p\n", p+2);
printf("---栈区地址分配情况---\n");
printf("局部变量x的地址: %p\n", &x);
printf("局部变量y的地址:%p\n", &y);
printf("局部变量z的地址:%p\n", &z);
//需手动释放堆区空间
delete[] p;
return 0;
}
输出:
---常量区地址分配情况---
常量N的地址: 000000000048813c
---全局数据区地址分配情况---
全局变量a的地址: 00000000004a7030
全局变量b的地址:00000000004a7034
全局变量c的地址:00000000004a7038
---堆区地址分配情况---
p[0]的地址: 00000000001b1520
p[1]的地址: 00000000001b1524
p[2]的地址: 00000000001b1528
---栈区地址分配情况---
局部变量x的地址: 00000000006ffe14
局部变量y的地址:00000000006ffe10
局部变量z的地址:00000000006ffe0c
最后讲一讲很少有人提起的两块灰色区域:
保留区域是用来存储操作系统保留的内存空间,通常用于存放操作系统内核、驱动程序和其他系统级的数据结构。这些区域通常是不可被普通用户程序访问的,用于维护系统的正常运行和管理。
#include <stdio.h>
int main() {
int *reserved_memory = (int *)0x80000000; // 以0x80000000地址为例,这是一个保留区域的地址
*reserved_memory = 10; // 尝试写入保留区域的内存,通常会导致段错误或者其他异常
return 0;
}
通过内核空间,操作系统可以提供各种系统服务和功能,如进程管理、文件系统、网络通信、设备驱动等。用户程序通过系统调用接口来请求内核提供的服务,内核在内核空间中进行相应的处理,然后返回结果给用户程序。由于内核空间拥有更高的权限和更广泛的操作权限,因此内核代码的编写和修改需要非常谨慎,以确保系统的稳定性和安全性。