[C/C++]内存管理,对内存进行操作

目录

一.内存结构

二.内存拷贝函数

三.栈空间与堆空间

四.变量的四种存储类型

五.函数返回值使用指针

六.常见错误总结


  • 个人主页:北·海
  •  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
  • 功能 : 从源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 
#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 
using namespace std;
extern int b;
extern int value;
int main1() {
	cout <<"b :"<< b << endl;
	cout << "value :" << value << endl;
	return 0;
}

五.函数返回值使用指针

#include 
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 ;"<

六.常见错误总结

  • 申请的内存被多次释放,程序会崩掉
#include 

using namespace std;

int main() {

	//动态内存被多次释放
	int* p = new int[18];
	p[0] = 0;
	//...
	delete[]p;
	//...
	delete[]p;

	//检测释放运行到次处
	cout << "come here" << endl;
}

[C/C++]内存管理,对内存进行操作_第1张图片

  •  内存泄露,只开辟空间,不进行释放,次数达到一定时,会将堆区的资源耗尽
	//内存泄露
	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;

[C/C++]内存管理,对内存进行操作_第2张图片

  •  释放空指针
//释放空指针
	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;

[C/C++]内存管理,对内存进行操作_第3张图片

  •  越界访问
//越界访问
	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;
	}

[C/C++]内存管理,对内存进行操作_第4张图片

你可能感兴趣的:(C语言,C++,c++,开发语言,c语言)