IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> C语言——动态内存管理、C语言的内存布局规律、高级宏定义 -> 正文阅读

[C++知识库]C语言——动态内存管理、C语言的内存布局规律、高级宏定义

目录

一、动态内存管理

1.malloc

2.free

3.内存泄漏

4.calloc

5.realloc

二、C语言的内存布局规律

三、高级宏定义?

1.不带参数的宏定义

2.带参数的宏定义


一、动态内存管理

  • malloc:申请动态内存空间
  • free:释放动态内存空间
  • calloc:中请并初始化一条列内存空间
  • realloc:重新分配内存空间

1.malloc

  • 函数原型:void *malloc (size_t size);
  • malloc函数向条统申请分配 size 个字节的内存空间,并返回一个指向这块空间的指针。
  • 如果函数调用成功,返回一个指向申请的内存空间的指针,由于返回类型是 void 指针(void*),所以它可以被转换成任何类型的数据;如果函数调用失败,返回值是NULL。另外,如果size参数设置为0,返回值也可能是NULL,但这并不意味着函数调用失败。

代码举例:

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

int main()
{
	int *ptr;
	
	ptr = (int *)malloc(sizeof(int));
	
	if(ptr == NULL)
	{
		printf("分配内存失败!\n");
		exit(1);
	}
	
	printf("请输入一个整数:");
	scanf("%d",ptr);
	
	printf("你输入的整数是:%d\n",*ptr);
	return 0;
}

运行结果:

  • 初始化内存空间:以mem开头的函数被编入字符串标准库,函数的声明包含在string.h这个头文件中:(memset;-使用一个帝量字节填充内存空间;memcpy:拷贝内存空间;memmove:拷贝内存空间;memcmp:比较内存空间;memchr:在内存空间中搜秦一个字符。)

代码举例:

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

#define N 10

int main(void)
{
	int *ptr = NULL;
	int i;
	
	ptr = (int *)malloc(N * sizeof(int));
	if(ptr == NULL)
	{
		exit(1);
	}
	
	memset(ptr, 0, N * sizeof(int));
	for(i = 0;i < N;i++)
	{
		printf("%d ",ptr[i]);
	}
	putchar('\n');
	
	free(ptr);
}

运行结果:

?

2.free

  • 函数原型:void free (void *ptr);
  • free函数释放ptr参数指向的内存空间。该内存空间必须是由malloc、calloc或realloc函教申请的。否则,该函数将导致未定义行为。如果ptr参数是NULL,则不执行任何操作。注意:该函数并不会修改ptr参数的值,所以调用后它仍然指向原来的地方(变为非法空间)。

3.内存泄漏

  • 隐式内存泄漏(即用完内存块没有及时使用free函数释放)
  • 丢失内存块地址

4.calloc

  • 函数原型:void *calloc (size_t nmemb,size_t size);
  • calloc函数在内存中动态地申请nmemb个长度为size的连续内存空间(即申请的总空间尺寸为nmemb *size),这些内存空间全部被初始化为0。
  • calloc函数与malloc函数的一个重要区别是:calloc函数在申请完内存后,自动初始化该内存空间为零;malloc函数不进行初始化操作,里边数据是随机的。
  • 下面两种写法是等价的:

?代码举例:

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

int main(void)
{
	int *ptr1 = NULL;
	int *ptr2 = NULL;
	
	//第一次申请的内存空间
	ptr1 = (int *)malloc(10 * sizeof(int));
	
	//进行若干操作之后发现ptr1申请的内存空间竟然不够用!
	
	//第二次申请的内存空间
	ptr2 = (int *)malloc(20 * sizeof(int));
	
	//将ptr1的数据拷贝到ptr2中
	memcpy(ptr2,ptr1,10);
	free(ptr1);
	
	//对ptr2申请的内存空间进行若干操作…
	
	free(ptr2);
	
	return 0;
	 
}

5.realloc

  • 函数原型:void *realloc(void *ptr,size_t size);
  • realloc函数修改ptr指向的内存空间大小为size字节;
  • 如果新分配的内存空间比原来的大,则旧内存块的数据不会发生改变;如果新的内存空间大小小于旧的内存空间,可能会导致数据丢失,慎用!
  • 该函数将移动内存空间的数据并返回新的指针;
  • 如果ptr参数为NULL,那么调用该函数就相当于调用malloc(size);
  • 如果size参数为0,并且ptr参数不为NULL,那么调用该函数就相当于调用free(ptr);
  • 除非ptr参数为NULL,否则ptr的值必须由先前调用malloc、calloc或realloc函数返回。

代码举例:

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

int main(void)
{
	int i,num;
	int count = 0;
	int *ptr = NULL;//这里必须初始化为NULL 
	
	do
	{
		printf("请输入一个整数(输入-1表示结束):");
		scanf("%d",&num);
		count++;
		
		ptr = (int *)realloc(ptr,count * sizeof(int)); 
		if(ptr == NULL)
		{
			exit(1);
		}
		
		ptr[count-1] = num;
	}while(num != -1);
	
	printf("输入的整数分别是:");
	for(i = 0;i < count;i++)
	{
		printf("%d ",ptr[i]);
	}
	putchar('\n');
	
	free(ptr);
	
	return 0;
	
}

运行结果:

二、C语言的内存布局规律

?

  • 代码段(Text segment)通常是指用来存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读。在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等。
  • 数据段(Initialized data segment)通常用来存放已经初始化的全局变量和局部静态变量。
  • BSS段(Bss segment/Uninitialized data segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域。BSS是英文Block Started by Symbol的简称,这个区段中的数据在程序运行前将被自动初始化为数字0。
  • 是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩展或缩小。当进程调用malloc等玉数分配内存时,新分配的内存就被动态添加到堆上;当利用free等函数释放内存时,被释放的内存从堆中被剔除。
  • 是函数执行的内存区域,通常和堆共享同一片区域。

堆和栈的区别:

(1)申请方式:

  • 堆由程序员手动申请
  • 栈由系统自动分配

(2)释放方式:

  • 堆由程序员手动释放
  • 栈由系统自动释放

(3)生存周期:

  • 堆的生存周期由动态申请到程序员主动释放为止,不同函数之间均可自由访问
  • 栈的生存周期由函数调用开始到函数返回时结束,函数之间的局部变量不能互相访问

(4)发展方向:

  • 堆和其它区段一样,都是从低地址向高地址发展
  • 栈则相反,是由高地址向低地址发展

代码举例:

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

int main(void)
{
	int *ptr1 = NULL;
	int *ptr2 = NULL;
	
	ptr1 = (int *)malloc(sizeof(int));
	ptr2 = (int *)malloc(sizeof(int));
	
	printf("stack: %p -> %p\n",&ptr1,&ptr2);
	printf("heap: %p -> %p\n",ptr1,ptr2);
	
	return 0;
	
}

运行结果:

三、高级宏定义?

1.不带参数的宏定义

  • 为了和普通的变量进行区分,宏的名字通常我们约定是全部由大写字母组成
  • 宏定义只是简单地进行替换,并且由于预处理是在编译之前进行,而编译工作的任务之一就是语法检查,所以编译器不会对宏定义进行语法检查
  • 宏定义不是说明或语句,在末尾不必加分号
  • 宏定义的作用域是从定义的位置开始到整个程序结束
  • 可以用 #undef 来终止宏定义的作用域
  • 宏定义允许嵌套

代码举例:

#include <stdio.h>

#define R 6371
#define PI 3.14
#define V PI * R * R * R * 4/3

int main(void)
{
	int r;
	float s;
	
	printf("请输入圆的半径:");
	scanf("%d",&r);

	s = PI * r * r;
	printf("圆的面积是:%.2f\n",s);
	
	printf("地球的体积大概是:%.2f\n",V);
	
	return 0;
}

运行结果:

2.带参数的宏定义

代码举例:

#include <stdio.h>

#define MAX(x,y)(((x) > (y)) ? (x) : (y))

int main(void)
{
	int x,y;
	
	printf("请输入两个整数:");
	scanf("%d%d",&x,&y);
	printf("%d 是较大的那个数!\n",MAX(x,y));
	
	return 0;
	
}

运行结果:

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-08-19 18:45:50  更:2022-08-19 18:50:07 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/13 12:22:20-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码