C++笔记-动态内存

首先介绍内存分区:


为什么要使用动态内存?
1.按需分配,根据需要分配内存,不浪费

#include <stdio.h>
#include <stdlib.h>
#include<string.h>

int main(void) {
	int farmer[10]={20, 22, 25, 19, 18, 23 ,17, 28, 30, 35};
	int num = 0;
	int *salary = NULL;

	printf("请输入需要雇佣的农民数量:\n");
	scanf_s("%d", &num);

	if(num<=10){
		//提示用户重新输入
	}

	//后面新增的都是18
	salary = new int[num];
	//第一种,逐个赋值
	/*for(int i=0; i<sizeof(farmer)/sizeof(int); i++){
		*(salary+i)= farmer[i];
	}*/
	//第二种,内存拷贝
	memcpy(salary, farmer, sizeof(farmer));

	for(int i=sizeof(farmer)/sizeof(int); i<num; i++){
		//salary[i] = 18;
		*(salary+i) = 18;
	}

	for(int i=0; i<num; i++){
		printf("第%d个农民的薪资: %d\n", i+1, salary[i]);
	}

	delete[] salary;

	system("pause");
	return 0;
}

内存拷贝函数
void *memcpy(void *dest, const void *src, size_t n);
#include<string.h>

功能:从源src所指的内存地址的起始位置开始拷贝n个字节到目标dest所指的内存地址的起始位置中

C内存分配:
void *malloc(size_t size);
void free(void *);
malloc 在内存的动态存储区中分配一块长度为size字节的连续区域返回该区域的首地址.

突破栈区的限制,可以给程序分配更多的内存

#include <stdlib.h>
#include<stdio.h>
#include<string.h>


//栈区的空间大小是有限制的,windows 上一般是1M - 2M
void demo(){
	//int a1[102400*2]; //100k*2*4 = 800K
	//int a1[102400*3]; //100k*3*4 = 1200K = 1.2M
	int * a1;
	//如果使用堆的话,64位 windows 10 系统的限制是2G
	a1 = (int *)malloc((int)(1024*1000*1000));//分配2G 
	a1[0]=0;
	printf("This is a demo.\n");
}

int main(void){
	printf("--start--\n");
	demo();
	printf("--end--\n");
	system("pause");
	return 0;
}
动态内存的分配、使用、释放

new和delete基本语法
1)在软件项目开发过程中,我们经常需要动态地分配和撤销内存空间,特别是数据结构中结点的插入与删除。在C语言中是利用库函数malloc和free来分配和撤销内存空间的。C++提供了较简便而功能较强的运算符new和delete来取代malloc和free函数。
(注意: new和delete是运算符,不是函数,因此执行效率高。)

2)虽然为了与C语言兼容,C++仍保留malloc和free函数,但建议用户不用malloc和free函数,而用new和delete运算符。

new运算符的例子:
new int; //开辟一个存放整数的存储空间,返回一个指向该存储空间的地址(即指针)
new int(10); //开辟一个存放整数的空间,并指定该整数的初值为10,返回一个指向该存储空间的地址
new char[100]; //开辟一个存放字符数组(包括100个元素)的空间,返回首元素的地址
new int[5][4]; //开辟一个存放二维整型数组(大小为5*4)的空间,返回首元素的地址
float *p=new float (3.14159); //开辟一个存放单精度数的空间,并指定该实数的初值为//3.14159,将返回的该空间的地址赋给指针变量p
3)new和delete运算符使用的一般格式为:

new 运算符 动态分配堆内存
使用方法:
指针变量 = new 类型(常量);
指针变量 = new 类型[表达式]; //数组
指针变量 = new 类型[表达式][表达式] //二维数组

作用:从堆上分配一块“类型”指定大小的存储空间,返回首偶地址
其中:“常量”是初始化值,可缺省
创建数组对象时,不能为对象指定初始值

delete 运算符 释放已分配的内存空间
使用方式:
普通类型(非数组)使用: delete 指针变量;
数组 使用: delete[] 指针变量;
其中“指针变量” 必须时一个new 返回的指针!

扫描二维码关注公众号,回复: 11258004 查看本文章
#include <stdlib.h>
#include <iostream>
using namespace std;

//分配基础类型
int main007(void) {
	//第一种分配动态内存不执行初始化
	int *p1 = new int;
	*p1 = 100;

	//第二种分配动态内存同时执行初始化
	int *p2 = new int(100);
	// 第三种 malloc 返回值是 void *
	int *p3 = (int *)malloc(sizeof(int));


	free(p1);  //基础类型可以new free  可以混搭
	delete p3; //基础类型可以malloc delete  可以混搭
	delete p2; //free(p2);  同样效果

	system("pause");
	return 0;
}

//分配数组变量
int main(void) {
	int *p1 = (int *) malloc(sizeof(int)*10);
	//p[0] - p[9]   *(p+9)
	int *p2 = new int[10];

	delete p1;   // free(p1);    可以混搭
	//free(p2);  //可以混搭
	delete[] p2;   

	system("pause");
	return 0;
}

C++程序员的噩梦-内存泄漏

内存泄漏(Memory Leak) - 是指程序中己动态分配的堆内存由于某种原因程序未释放或无法释放,造成系统内存的浪费,导致程序运行速度减慢甚至系统崩溃等严重后果,用完了一定记得还,也就是释放;

变量的4种存储类型

所有的数据都有两种类型
数据类型: 如int,float等

存储类型: 总共有四种存储类型的变量,分别为自动变量(auto)、静态变量(static)、外部变量(extern)以及寄存器变量(register)。

auto - 函数中所有的非静态局部变量。

register - 一般经常被使用的的变量(如某一变量需要计算几千次)可以设置成寄存器变量,register变量会被存储在寄存器中,计算速度远快于存在内存中的非register变量。

static - 在变量前加上static关键字的变量。

extern - 把全局变量在其他源文件中声明成extern变量,可以扩展该全局变量的作用域至声明的那个文件,其本质作用就是对全局变量作用域的扩展。

在这里插入图片描述
函数返回值使用指针

可以返回函数内部:动态分配内存地址 局部静态变量地址 以及全局静态变量和外部变量地址

#include <iostream>
#include <stdlib.h>

using namespace std;

int * add(int x, int y)
{
    int sum = x + y;
    return &sum;
}

//返回动态内存分配地址
int * add1(int x, int y)
{
	int * sum = NULL;
	sum = new int;
    *sum = x + y;
    return sum;
}

//返回局部静态变量的地址
int * add2(int x, int y)
{
	static int sum = 0;
	printf("sum: %d\n", sum);
    sum = x + y;
    return &sum;
}

int main()
{
    int a = 3, b = 5;
	int *sum = NULL;
    //cout << add(a, b) << endl;
	//sum = add(a, b);//不能使用外部函数局部变量的地址 bad
	
	//接收外部函数动态内存分配的地址  ok
	//sum = add1(a, b);
	//cout<<*sum<<endl;
	//delete sum;

	//接收外部函数局部静态变量的地址
	sum = add2(a, b);
	cout<<*sum<<endl;
	*sum = 88888;
	add2(a, b);
	system("pause");
	return 0;
}

补充:函数返回值是引用(引用当左值和右值)
C++引用使用时的难点:
当函数返回值为引用时
若返回栈变量,不能成为其它引用的初始值,不能作为左值使用
若返回静态变量或全局变量
可以成为其他引用的初始值
即可作为右值使用,也可作为左值使用
(注:C++链式编程中,经常用到引用,运算符重载专题)

常见错误总结

1.申请的内存多次释放

2.内存泄漏

3.释放的内存不是申请时的地址

4.释放空指针

5.释放一个内存块,但继续引用其中的内容

内存泄漏检测工具

VisualC++ debugger和CRT库

第一步: 包含以下头文件
#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>

第二步: 接管new 操作符
#ifdef _DEBUG
#ifndef DBG_NEW
#define DBG_NEW new ( _NORMAL_BLOCK , FILE ,LINE)
#define new DBG_NEW
#endif
#endif

第三步: 在代码结束出输出内存泄漏信息
_CrtDumpMemoryLeaks();

内存泄漏工具:
Windows : Purify,BoundsCheaker、Deleaker、VisualLeak Detector(VLD),
Linux平台:Valgrind memcheck

猜你喜欢

转载自blog.csdn.net/qq_35803412/article/details/105017079