内存
程序运行的时候,操作系统分配4G大小的虚拟内存,其中有一个G的大小是操作系统的内核区,无法使用,3G栈区。数据结构的栈和这个栈不是同一个东西。
(数据结构:栈,MAP)MAP存放键值对 map存放在堆区
栈下面是共享,堆,全局区静态区,常量区(存函数)。
函数的名字就是函数的地址
1.栈区(存放 局部变量+函数参数)
特点:
空间少
自动释放 (例如:函数内部定义的变量在函数结束时会自动释放内存,无需手动返回。
超出作用域后,编译器会自动回收)
访问速度快
2.全局区(存放 全局变量)
特点:
访问的时候 就近原则:局部大于全局
“局部大于全局”是编程中的一个常见原则,主要指的是在某些情况下,局部变量的作用范围和优先级高于全局变量。这一原则的具体含义可以从以下几个方面理解:
1. **作用域**:局部变量是在函数或块内部定义的变量,其作用范围仅限于该函数或块。而全局变量是在整个程序中都可以访问的变量。当局部变量和全局变量同名时,局部变量会覆盖全局变量,在局部范围内使用局部变量。
2. **优先级**:在函数内部,如果存在与全局变量同名的局部变量,函数内部的代码会优先使用局部变量。这意味着在函数内部对该变量的操作不会影响全局变量的值,除非显式地使用全局变量的引用。
3. **避免命名冲突**:使用局部变量可以避免与全局变量的命名冲突,从而提高代码的可读性和可维护性。它可以帮助程序员更好地管理变量的生命周期和作用域。
4. **内存管理**:局部变量的生命周期仅限于函数的执行时间,函数结束后自动释放内存,而全局变量在程序运行期间一直存在。因此,局部变量有助于更有效地管理内存。
总之,“局部大于全局”强调了在编程时局部变量的优先使用,鼓励开发者尽量使用局部变量来避免不必要的复杂性和潜在的错误。
生命周期:从程序的开始到程序的结束
注意事项:
多个cpp文件,全局变量发生重定义,extern关键字声明
int a;
void fun(int qq)
{
int a;
a=2;//这里访问的是局部的
}
extern int pointer;//声明pointer这个变量,表示这个变量已经存在
//导入自己写的头文件用双引号,在自己项目里面寻找,尖括号是在系统里面寻找,下载路径里面寻找
//导入就相当于把那个文件里面的代码复制粘贴过来了
//而且文件.h可以动,.cpp不能随便动,只有一个。
//导入的语句可以写多次#icnlude什么什么,效果一样的
3.堆区 (存放 动态数组 链表 图 树)
特点:
不会自动释放,需要手动释放内存
容量大
访问速度比栈区慢
#include<iostream>
using namespace std;
void test01()
{
int n;
int* p1=NULL;
cin >> n;
if (n > 0) p1 = (int*)malloc(n * sizeof(int));//在堆区申请int类型内存
if (p1)free(p1);
}
int main()
{
//申请堆区内存使用malloc;malloc(需要申请的字节个数);
//返回值:mallo会将申请到的堆区内存的首地址返回
// 如果malloc申请内存失败,则返回空
//malloc注意手动释放
char* p = (char*)malloc(500);//一个字符一个字节//malloc的返回值需要强制转换
p[3] = 'a';//p是数组首元素地址,p[3]==*(p+3)
cout << p[3];
free(p);
/*
* 原理:
* p在栈区,因为p是局部变量,(函数参数和局部变量都在栈区)
* char* p栈区
* (char*)malloc(500);堆区
* free(p)释放p指向的堆区内存
*/
return 0;
}
4.常量区(存放 各种常量 字符串常量 函数常量 常量数组 整型常量 浮点常量 字符常量 地址常量)
特点:
不可修改 只读
int num[3]={1,2,3}
num++报错,地址常量不让被修改
左值是什么?有名字的就是左值
右值是什么?没有名字的就是右值
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int main()
{
int num[3] = { 1,2,3 };
int* b = num;//num是地址常量不能修改
return 0;
}
在以上代码中,`num` 是一个数组,它的名字 `num` 在表达式中代表数组的首地址,因此 `int* b = num;` 是正确的。这行代码将 `num` 数组的首地址赋值给指针 `b`。
但是,关于你提到的 `num` 是“地址常量不能修改”的说法需要澄清:
1. **`num` 是一个数组名**:在 C++ 中,数组名(如 `num`)在大多数情况下会被转换为指向其第一个元素的指针。这个指针是一个常量,意味着你不能改变 `num` 指向的地址。例如,`num = nullptr;` 会导致编译错误,因为你不能修改数组名的值。
2. **`*b = 2;` 是合法的**:通过指针 `b` 来访问和修改数组的内容是合法的。`*b` 实际上是 `num[0]`,所以执行 `*b = 2;` 会将数组的第一个元素修改为 `2`,这在语法上是正确的。代码如下:
```cpp
int num[3] = { 1, 2, 3 };
int* b = num; // b 指向 num 数组的首地址
*b = 2; // 这将把 num[0] 的值修改为 2
```这段代码执行后,`num` 数组的内容将变为 `{ 2, 2, 3 }`。
### 总结
- `num` 是一个数组名,表示数组的首地址,不能被修改。
- 通过指针 `b` 可以访问和修改 `num` 数组中的元素,`*b = 2;` 是合法的,并会改变 `num` 数组的内容。
5.静态区(存放 静态的局部变量和静态的全局变量)
malloc p1 = (int*)malloc(n * sizeof(int));//在堆区申请int类型内存 p1这个变量在栈区 需要申请的内存字节个数
对返回值进行强制转换 本来的返回值是void*类型,释放用free
特点:
静态变量的生命周期:从程序开始到程序结束
静态变量只被初始化一次
void func() {
static int count = 0; // 静态局部变量
count++;
std::cout << count << std::endl;
}
int main() {
func(); // 输出 1
func(); // 输出 2
func(); // 输出 3
return 0;
}
静态局部变量 作用域 :当前的{}内
存放静态变量static
- 静态变量不会被分配到函数栈中。即使它们是在函数内部定义的(作为静态局部变量),它们也不会在函数调用时被创建或销毁,而是一直存在于静态区中。
静态全局变量 作用域:当前文件 ,不发生重定义,不同函数里面可以重复定义
这句话的意思是关于静态全局变量的作用域和链接性。我们可以逐步拆解来理解:
### 1. 静态全局变量的定义
静态全局变量是在文件的顶部定义的,使用 `static` 关键字修饰的全局变量。它的定义形式如下:
```cpp
static int myStaticVar = 0; // 静态全局变量
```### 2. 作用域:当前文件
- **作用域**:静态全局变量的作用域仅限于定义它的源文件。这意味着在该文件之外,其他文件无法访问或引用这个静态全局变量。即使在其他文件中有同名的全局变量,它们也不会产生冲突,因为静态全局变量在其他文件中是不可见的。
例如,如果你在 `file1.cpp` 中定义了一个静态全局变量 `static int myVar;`,那么这个变量在 `file1.cpp` 中可以被访问,但在 `file2.cpp` 中是不可见的,无法访问或使用。
### 3. 不发生重定义
- **不发生重定义**:由于静态全局变量的链接性是内部链接(internal linkage),这意味着即使在同一文件中定义了多个同名的静态全局变量,它们也不会发生重定义的错误,因为它们的作用域是局部的,只在定义它们的文件中有效。
例如:
```cpp
// file1.cpp
static int myVar = 1; // 第一个静态全局变量void func() {
static int myVar = 2; // 这是另一个静态全局变量,与上面的不同
}
```在这个例子中,`file1.cpp` 中的 `myVar` 在全局作用域和 `func` 函数中都有定义,但它们是两个不同的变量,互不影响。
### 总结
- **静态全局变量的作用域**:仅限于定义它的文件,其他文件无法访问。
- **不发生重定义**:在同一文件中,即使有同名的静态全局变量,它们也不会发生冲突,因为它们的作用域是局部的。这种特性使得静态全局变量在模块化编程中非常有用,可以避免命名冲突,同时又能在需要时保持状态。