目录
一.内存结构
二.内存拷贝函数
三.栈空间与堆空间
四.变量的四种存储类型
五.函数返回值使用指针
六.常见错误总结
- 🎈个人主页:北·海
- 🎐CSDN新晋作者
- 🎉欢迎 👍点赞✍评论⭐收藏
- ✨收录专栏:C/C++
- 🤝希望作者的文章能对你有所帮助,有不足的地方请在评论区留言指正,大家一起学习交流!🤗
一.内存结构
- 栈区(stack)
- 由编辑器自动分配释放,存放函数的参数值,局部变量等
- 堆区(heap)
- 一般由程序员分配释放,随叫随到,挥之即走
- new进行分配
- delete进行销毁内存(数组用delete [] 数组名)
- 分配了不进行释放,则为内存泄漏,如果不释放,则时间久了会将资源耗尽,程序结束
- 可以在任务管理器内看到资源的变化
- 全局/静态区(static)
- 全局变量和静态变量的存储时存放在一起的,在程序编译时分配
- 文字常量区
- 存放常量字符串
- 所有的字符串常量都是不被修改的,所以同一个字符串被其他指针所指向时候,地址都是一样的
- 一下p和p1的地址都是一样的
//字符串常量
char* p = "你好";
char* p1 = "你好";
- 程序代码区
- 存放函数体(包括类的成员函数,全局函数)的二进制代码
- 只存函数体内的指令,不存函数体内的变量,常量
二.内存拷贝函数
- void* memcpy(void* dest,const void* src,size_tn)
- #include <string.h>
- 功能 : 从源src所指向的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中
三.栈空间与堆空间
- 栈空间一般为 1M - 2M
- 在64位windows 10系统的限制时2G
- 如果使用大的空间,最好使用堆内存
- 1000字节 = 1k
- 1000k = 1 M
- 1000M = 1G
四.变量的四种存储类型
- auto - 函数中所有的非静态局部变量,在c语言中可以声明为 auto int i= 0;,但是在c++里面必须省略掉int写为auto i = 0;编辑器会根据值得类型来推断该变量的类型,不能加int
- register - 寄存器变量,没有内存地址,存在于寄存器,不属于内存,c语言保留下来的关键字,在全部变量中不能声明寄存器变量,C++的register关键字已经优化,如果我们打印他的地址,他就变成了普通的auto变量
- static - 使用范围有限制,但是程序不结束,该值不会释放,会一直存在,全局静态变量和局部静态变量只是作用域不同
- extern - 变量必须为全局变量,在a.cpp文件里定义全局变量int value = 10;,可在b.cpp函数里面声明extern int value; 则该值在b.cpp函数里面的值为10
#include <iostream>
#include "标头.h"//存放了文件2里面函数的声明
using namespace std;
static int d = 40;
//register int c = 30;//error 不能声明为全局
auto b = 20;
int value = 40;
//extern int e ;//error
extern int e = 20;//success
int main() {
auto a = 10;
e = 30;
cout << e << endl;
{
main1();//其他文件
static int f = 30;//success
register int g = 30;//success
auto h = 30;//success
//auto int i = 30;//error 在c++中不能定义为auto int 应该省略掉int,c语言中可以定义为auto int
}
//cout << f << endl;error 块内定义的
}
//文件2
#include <iostream>
using namespace std;
extern int b;
extern int value;
int main1() {
cout <<"b :"<< b << endl;
cout << "value :" << value << endl;
return 0;
}
五.函数返回值使用指针
#include <iostream>
using namespace std;
int* add(int x, int y) {
int* sum = new int;
*sum = x + y;
return sum;
}
int* add1(int x, int y) {
int sum = x + y;
return ∑
}
//返回局部静态变量的地址
int* add2(int x, int y) {
static int sum = 0;
cout << "sum ;" << sum << endl;
sum = x + y;
return ∑
}
int main() {
int* sum = nullptr;
cout << *add1(2, 5) << endl;//error 不能使用外部函数局部变量的地址 bad
//接收动态内存分配的地址
sum = add(2, 9);//success 局部的堆空间,必须在外部拿到他的地址,从而对他进行释放
cout <<"sum ;"<<sum << endl;
delete sum;
//接收静态内存分配的地址
sum = add2(2, 5);
cout << *sum << endl;
*sum = 8888;
add2(2, 5);//值被改变为8888
}
六.常见错误总结
- 申请的内存被多次释放,程序会崩掉
#include <iostream>
using namespace std;
int main() {
//动态内存被多次释放
int* p = new int[18];
p[0] = 0;
//...
delete[]p;
//...
delete[]p;
//检测释放运行到次处
cout << "come here" << endl;
}
- 内存泄露,只开辟空间,不进行释放,次数达到一定时,会将堆区的资源耗尽
//内存泄露
do {
int* p1 = new int[1024];
} while (1 == 1);
- 释放的内存不是申请的地址,地址偏移,导致内存不能被释放,程序无响应的崩掉
//释放的内存不是申请的地址
int* p2 = new int[10];
p2[0] = 1;
for (int i = 0; i < 10; i++) {
p2++;
cout << *p2 << endl;
}
delete[]p2;//此时p2的地址已经偏移了 4* 10个字节 不再是起初的p2地址,无法释放
cout << "come here p2" << endl;
- 释放空指针
//释放空指针
int* p3 = NULL;
if (1==0) {//模拟文件是否能打开
p3 = new int;
}
delete p3;
cout << "come here" << endl;
- 释放一个内存块,但继续引用其中的内容
//释放一个内存块,又继续使用
int* p4 = new int;
delete p4;
*p4 = 1;
cout << "come here" << endl;
- 越界访问
//越界访问
int* p = new int[10];
memset(p, 0, 10 * sizeof(int));
for (int i = 0; i < 10; i++) {
cout << *(p++) << endl;
}
//下面的都越界
for (int i = 0; i < 10; i++) {
cout << *(p++) << endl;
}