C语言编程C++动态内存分配示例讲解

目录
  • 动态内存管理
    • 为什么存在动态内存分配
  • 动态内存函数的介绍
    • malloc申请空间和free释放空间
    • 有借有还 free释放内存
  • calloc申请内存
  • realloc调整动态内存的大小
    • realloc使用的注意事项
    • 当然realloc也可以直接开辟空间
  • 常见的动态内存错误
    • 1.对NULL指针的解引用操作
    • 2.对动态开辟空间的越界访问
    • 3.对非动态开辟内存使用free释放
    • 4.使用free释放一块动态内存开辟的一部分
    • 5.对同一块动态内存多次释放
    • 6.动态开辟内存忘记释放(内存泄漏)
  • 几个面试题
    • 题目1
    • 题目2
    • 题目3
    • 题目4
  • C/C++程序的内存开辟
  • C/C++程序内存分配的几个区域:

动态内存管理

为什么存在动态内存分配

我们到现在为止掌握的是什么样的内存开辟方式呢

//创建一个变量
int val = 20;    //局部变量  在栈空间中开辟4个字节
int g_val = 10;  //全局变量  在静态区中开辟4个字节
//创建一个数组
char arr[10] = {0}; //局部区域 在栈空间中开辟10个字节连续的空间
char g_arr[5] = {0};//全局区域 在静态区空间中开辟5个字节的连续空间

但是上述的开辟空间的方式有两个特点:

1.空间开辟大小是固定的。

2.数组在申明的时候,必须指定数组的长度,它所需要的内存在编译时分配。
但是对于空间的需求,不仅仅是上述的情况。有时候我们需要的空间大小在程序运行的时候才能知道,那数组的编译时开辟空间的方式就不能满足了。 这时候就只能试试动态内存开辟了。

c99是支持变长数组的,但现在很多编译器就不支持c99,连vs都不支持,所以就有动态内存的概念

动态内存函数的介绍

malloc申请空间和free释放空间

c语言提供了一个动态内存开辟的函数

void* malloc(size_t size);

这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针。

1.如果开辟成功,则返回一个指向开辟好空间的指针。

2.如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查。

3.返回值的类型是 void ,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己来决定。*

4.如果参数 size 为0,malloc的行为是标准未定义的,取决于编译器。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
int main()
{
	//向内存申请10个整形的空间
	int* p = (int*)malloc(10 * sizeof(int));
	if (p == NULL)
	{
		//把开辟失败的信息打印出来
		printf("%s",strerror(errno));
	}
	else
	{
		//正常使用空间
		int i = 0;
		for (i = 0; i < 10; i++)
		{
			*(p + i) = i;//在找下标为i的元素
		}
		for (i = 0; i < 10; i++)//再把每个元素打印出来
		{
			printf("%d ", *(p + i));
		}
	}
	return 0;
}

那我们可不可以看开辟失败的呢

我们可以用INT_MAX(他是整形最大),一个超级大的数字

有借有还 free释放内存

free函数用来释放动态开辟的内存。
1.如果参数 ptr 指向的空间不是动态开辟的,那free函数的行为是未定义的。
2.如果参数 ptr 是NULL指针,则函数什么事都不做。

注意

malloc和free是成对使用的,谁开辟谁释放

calloc申请内存

在内存中开辟一个数组,把元素都改成零

函数的功能是为 num 个大小为 size 的元素开辟一块空间,并且把空间的每个字节初始化为0。

与函数 malloc 的区别只在于 calloc 会在返回地址之前把申请的空间的每个字节初始化为全0

realloc调整动态内存的大小

当然我们可以申请空间,但会不会遇到申请的空间不够了,想要增加一些些,大了想要去掉一些些

realloc使用的注意事项

1.如果p指向的空间之后有足够的内存空间可以追加,则直接追加,后返回p

2.如果p指向的空间之后没有足够的内存空间可以追加,则realloc函数会重新找一块新的内存区域,开辟一块满足需求的空间,并且把原来的内存中的数据拷贝回来,释放旧的内存空间,最后返回新开辟的内存空间地址

3.但也有一个大问题,就是开辟INT_MAX,用新的变量ptr来接收realloc返回值

当然realloc也可以直接开辟空间

常见的动态内存错误

1.对NULL指针的解引用操作

#include<stdio.h>
#include<stdlib.h>
int main()
{
	int* p = (int*)malloc(40);//没成功就会有大问题
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*(p + i) = i;
	}
	free(p);
	p = NULL;
	return 0;
}

所以为了防止没有开辟动态内存成功就需要做个判断

2.对动态开辟空间的越界访问

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

int main()
{
	int* p = (int*)malloc(5*sizeof(int));
	if (p == NULL)//这里我的确判断有没有开辟成功了
	{
		printf("%s", strerror(errno));
	}
	else
	{
		int i = 0;
		for (i = 0; i < 10; i++)//但是我这里访问10个整型的空间
		{
			*(p + i) = i;
		}
	}
	free(p);
	p = NULL;
	return 0;
}

3.对非动态开辟内存使用free释放

int main()
{
	int a = 0;
	int* p = &a;
	*p = 20;
	free(p);
	p = NULL;
	return 0;
}

4.使用free释放一块动态内存开辟的一部分

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
int main()
{
	int* p = (int*)malloc(40);
	if (p == NULL)
	{
		return 0;//如果是空指针就直接返回,不干了
	}
	int i = 0;
	for (i = 0; i < 10; i++)
	{
		*p++ = i;//这个++就是bug的地方
	}
	//回收空间
	free(p);
	p = NULL;
	return 0;
}

只要p不是指向申请的空间的首地址,其他地方都是错的

5.对同一块动态内存多次释放

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
int main()
{
	int* p = (int*)malloc(40);
	if (p == NULL)
	{
		return 0;
	}
	//使用
	//释放
	free(p);
	//...
	free(p);
	return 0;
}

6.动态开辟内存忘记释放(内存泄漏)

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
int main()
{
	while (1)
	{
		malloc(100);
	}
	return 0;
}

几个面试题

题目1

void GetMemory(char* p)
{
	p = (char*)malloc(100);
}
void Test(void)
{
	char* str = NULL;
	GetMemory(str);
	strcpy(str,"hello world");
	printf(str);//这个写法和printf("%s",str);是一样的
}
int main()
{
	Test();
	return 0;
}

问运行Test函数会有什么样的结果

修改正确

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<errno.h>
void GetMemory(char* *p)
{
	*p = (char*)malloc(100);
}
void Test(void)
{
	char* str = NULL;
	GetMemory(&str);
	strcpy(str,"hello world");
	printf(str);//这个写法和printf("%s",str);是一样的
	free(str);//用完就释放
	str = NULL;
}
int main()
{
	Test();
	return 0;
}

题目2

char* GetMemory(void)
{
	char p[] = "hello world";
	return p;
}
void Test(void)
{
	char* str = NULL;
	str = GetMemory();
	printf(str);
}
int main()
{
	Test();
	return 0;
}

请问运行Test 函数会有什么样的结果

输出随机值

修改正确

既然是p被销毁了,那我们让他不销毁就可以了延长它的生命周期用static

char* GetMemory(void)
{
	static char p[] = "hello world";
	return p;
}
void Test(void)
{
	char* str = NULL;
	str = GetMemory();
	printf(str);
}
int main()
{
	Test();
	return 0;
}

题目3

void GetMemory(char **p, int num)
{
*p = (char *)malloc(num);
}
void Test(void)
{
char *str = NULL;
GetMemory(&str, 100);
strcpy(str, "hello");
printf(str);
}

这题基本和第一题一样,不过这题就只有内存泄漏的错误

修改正确

#include<stdio.h>
#include<stdlib.h>
void GetMemory(char** p, int num)
{
	*p = (char*)malloc(num);
}
void Test(void)
{
	char* str = NULL;
	GetMemory(&str, 100);
	strcpy(str, "hello");
	printf(str);
	free(str);//用完就释放,防止内存泄漏
	str = NULL;
}
int main()
{
	Test();
	return 0;
}

题目4

void Test(void)
{
	char* str = (char*)malloc(100);
	strcpy(str, "hello");
	free(str);
	if (str != NULL)
	{
		strcpy(str, "world");
		printf(str);
	}
}

问题非常大的打印出结果

修改正确

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

void Test(void)
{
	char* str = (char*)malloc(100);
	strcpy(str, "hello");
	free(str);//这里考查的是free释放后并没有使str为NULL,所以下面if判断就没有作用,如果使他有作用就让str为NULL
	str = NULL;
	if (str != NULL)
	{
		strcpy(str, "world");
		printf(str);
	}
}
int main()
{
	Test();
	return 0;
}

这道题真正目的就是让你什么都不打印

C/C++程序的内存开辟

C/C++程序内存分配的几个区域:

栈区(stack):在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。 栈区主要存放运行函数而分配的局部变量、函数参数、返回数据、返回地址等。

堆区(heap):一般由程序员分配释放, 若程序员不释放,程序结束时可能由OS回收 。分配方式类似于链表。

数据段(静态区)(static)存放全局变量、静态数据。程序结束后由系统释放。

代码段:存放函数体(类成员函数和全局函数)的二进制代码。

以上就是C语言编程C++动态内存分配示例讲解的详细内容,更多关于C++动态内存分配的资料请关注我们其它相关文章!

(0)

相关推荐

  • C++动态内存分配(new/new[]和delete/delete[])详解

    C++动态内存分配(new/new[]和delete/delete[])详解 为了解决这个普通的编程问题,在运行时能创建和销毁对象是基本的要求.当然,C已提供了动态内存分配函数malloc( )和free( ),以及malloc( )的变种(realloc:改变分配内存的大小,calloc:指针指向内存前初始化),这些函数在运行时从堆中(也称自由内存)分配存储单元,但是运用这些库函数需要计算需要开辟内存的大小,容易出现错误. 那么通常我们在C语言中我们开辟内存的方式如下: (void*)mall

  • C++ 动态内存分配详解(new/new[]和delete/delete[])

    一.为什么需要动态内存分配? 在C++程序中,所有内存需求都是在程序执行之前通过定义所需的变量来确定的. 但是可能存在程序的内存需求只能在运行时确定的情况. 例如,当需要的内存取决于用户输入. 在这些情况下,程序需要动态分配内存,C ++语言将运算符new和delete合成在一起. (1)特点 1.C++中通过new关键字进行动态内存申请 2.C++中的动态内存分配是基于类型进行的 3.delete关键字用于内存释放 (2)语法 ①变量申请: Type* pointer = new Type;

  • 详解C++ 动态内存分配与命名空间

    1.C++中的动态内存分配 通过new关键字进行动态内存申请 C++中的动态内存申请时基于类型进行的 delete关键用于内存释放 C语言其实是不支持动态内存分配的,是通过malloc库函数来实现的,可能有一些硬件根本不支持malloc:而C++ new是一个关键字,不管在任意编译器上,任意硬件平台上都是能够进行动态内存分配的,这是本质区别. malloc是基于字节来进行动态内存分配的,new则是基于类型来进行动态内存分配 // 变量申请: Type * pointer = new Type;

  • 关于C++动态分配内存的介绍

    介绍 操作系统中存在一个内存管理器(Memory Manager),简称MM,它负责管理内存. MM提供的服务:应用程序可以向MM申请一块指定大小的内存(借出),用完之后应用程序应该释放(还回). 如: void* p = malloc(1024);//申请,从MMM借出内存 free(p); //释放,还回MM 1.MM管理的内存区域成为堆(Heap). 2.只要应用malloc,MM都会借出,如应用不归还,MM也不会主动要求你free.如果有个应用不停地malloc,而不free,最终会用光

  • C++使用动态内存分配的原因解说

    上节我们讲了C++程序的内存分布.C++程序的内存分布 本节来介绍为什么要进行内存分配. 按需分配,根据需要分配内存,不浪费. 内存拷贝函数void* memcpy(void* dest, const void* src, size_t n); 从源src中拷贝n字节的内存到dest中.需要包含头文件#include <string.h> #include <stdio.h> #include <string.h> using namespace std; int ma

  • C语言动态内存分配的详解

    C语言动态内存分配的详解 1.为什么使用动态内存分配 数组在使用的时候可能造成内存浪费,使用动态内存分配可以解决这个问题. 2. malloc和free C函数库提供了两个函数,malloc和free,分别用于执行动态内存分配和释放. (1)void *malloc(size_t size); malloc的参数就是需要分配的内存字节数.malloc分配一块连续的内存.如果操作系统无法向malloc提供更多的内存,malloc就返回一个NULL指针. (2)void free(void *poi

  • C语言编程C++动态内存分配示例讲解

    目录 动态内存管理 为什么存在动态内存分配 动态内存函数的介绍 malloc申请空间和free释放空间 有借有还 free释放内存 calloc申请内存 realloc调整动态内存的大小 realloc使用的注意事项 当然realloc也可以直接开辟空间 常见的动态内存错误 1.对NULL指针的解引用操作 2.对动态开辟空间的越界访问 3.对非动态开辟内存使用free释放 4.使用free释放一块动态内存开辟的一部分 5.对同一块动态内存多次释放 6.动态开辟内存忘记释放(内存泄漏) 几个面试题

  • C语言编程之动态内存与柔性数组的了解

    目录 介绍动态内存分配函数 常见的动态内存开辟的错误 举个例子 柔性数组 柔性数组的特点 创建变量 1,局部变量–栈区 2,全局变量–静态区 创建数组 1,局部数组–栈区 2,全局数组–静态区 介绍动态内存分配函数 malloc free calloc realloc 所有的动态内存分配,都是在堆中进行分配 分别介绍动态内存函数 malloc void* malloc(size_t size) 向内存堆中申请size个字节,并返回该空间的首地址.同时定义一个指针来接受函数返回的地址. 如: in

  • C语言深入探索动态内存分配的使用

    目录 一.动态内存分配的意义 二.malloc 和 free 三.关于 malloc(0) 四.calloc 和 realloc 五.小结 一.动态内存分配的意义 C语言中的一切操作都是基于内存的 变量和数组都是内存的别名 内存分配由编译器在编译期间决定 定义数组的时候必须指定数组长度 数组长度是在编译期就必须确定的 需求:程序运行的过程中,可能需要使用一些额外的内存空间 二.malloc 和 free malloc 和 free 用于执行动态内存分配和释放 malloc 所分配的是一块连续的内

  • 深入了解C语言中的动态内存分配

    目录 什么是动态内存分配 如何进行动态内存分配 首先我要介绍两个函数 malloc 和 free 第二个开辟空间的动态内存分配的函数 calloc 大小修改函数realloc 今天我们来学习一下C语言中的动态内存分配 开始学习吧 什么是动态内存分配 我们目前已经知道的内存开辟的方式有: int val = 20;//在栈上开辟四个字节. char arr[10] = { 0 };//在栈上开辟十个字节的连续空间 但是上述空间的开辟方式有两个特点: 1.空间开辟的大小是固定的 2.数组在申明的时候

  • C语言中关于动态内存分配的详解

    目录 一.malloc 与free函数 二.calloc 三.realloc 四.常见的动态内存的错误 [C语言]动态内存分配 本期,我们将讲解malloc.calloc.realloc以及free函数. 这是个动态内存分配函数的头文件都是 <stdlib.h>. c语言中动态分配内存的函数,可能有些初学c语言的人不免要问了:我们为什么要通过函数来实现动态分配内存呢? 首先让我们熟悉一下计算机的内存吧!在计算机的系统中大致有这四个内存区域: 1)栈:在栈里面储存一些我们定义的局部变量以及形参(

  • c语言详解动态内存分配及常见错误的解决

    目录 为什么会有动态内存分配 动态内存函数的介绍 malloc free calloc realloc 常见的错误 对NULL指针的解引用操作 越界访问 对非动态内存进行free 使用free释放动态开辟内存的一部分 对同一块动态内存多次释放 对动态内存内存忘记释放(内存泄漏) 为什么会有动态内存分配 内存使用方式有两种 1.创建一个变量 2.创建一个数组 int a = 1; int arr[10]; 但是这两种方式都有一些特点 1.空间是固定大小的,不会变 2.必须提前知道要开辟多少空间,必

  • C语言编程C++柔性数组结构示例讲解

    目录 绕指柔-柔性数组 柔性数组的特点: 第一个好处是:方便内存释放 第二个好处是:这样有利于访问速度 总结 绕指柔-柔性数组 也许你从来没有听说过柔性数组(flexible array)这个概念,但是它确实是存在的. C99 中,结构体中的最后一个元素允许是未知大小的数组,这就叫做柔性数组成员. 柔性数组的特点: 1.结构中的柔性数组成员前面必须至少一个其他成员. 2.sizeof 返回的这种结构大小不包括柔性数组的内存. 3.包含柔性数组成员的结构用malloc ()函数进行内存的动态分配,

  • c语言动态内存分配知识点及实例

    c语言怎么实现动态内存分配 我们经常会预先给程序开辟好内存空间,然后进行操作. int arr[5] ; 对这个数组我们在定义的时候必须给提前开辟好空间,并且在程序执行的过程中,这个开辟的内存空间是一直存在的,除非等到这个函数执行完毕,才会将空间释放.有个问题就是这个数组在程序中无法被修改. 这些问题给我们造成了一些使用上的不方便,所以,C中提供了malloc()函数. 关于malloc()函数,这个函数它接受一个参数:就是所需的内存的字节数.然后malloc()找到可用内存中那一个大小适合的块

  • C语言编程动态内存分配常见错误全面分析

    目录 前言:为什么存在动态内存分配? 一.动态内存函数 1.malloc和free函数 2.calloc函数 3.realloc函数 二.常见错误 1.对NULL指针解引用 2.对动态开辟空间的越界访问 3.对非动态开辟使用free函数 4.使用free释放一块动态内存开辟内存的一部分 5.对同一块空间多次释放 6.动态开辟内存忘记释放 总结 前言:为什么存在动态内存分配? 我们已经掌握的内存开辟方式如下 int a=10;//在栈空间上开辟4字节 char arr[10]={0};//在栈空间

随机推荐