用malloc函数头文件开辟一个动态存储区后进行强制类型转换,内存中实际发生了什么变化?

相关文章推荐
注意事项:1.不要访问已经被free函数释放了的内存(可以在释放内存后,将此指针赋值为NULL)。
2.对NULL指针进行解引用操作,对分配的内存进行操作是越界,释放并非动态开辟的...
前言:本人在学习数据结构的过程中,遇到了散列这种数据结构,在使用分离链表发构建散列的过程中,需要用到为指针的指针动态分配内存空间,所以本人写了一个C语言的Demo程序来先测试这一行为问题如图#incl...
花式实现日期类。#define _CRT_SECURE_NO_WARNINGS 1
#if 1cl...
#define DataType int
class Seqlist
friend ostream& oper...
功能分为以下模块:
a)信息创建模块:对信息进行录入,通过进行相关操作,保存所需的文件;
b)信息查询:在信息载入和信息创建的前提下,对某人的信息进行查询;
c)信息修改:在信息载入和信息创建的前提下...
动态开辟内存:
#ifndef __TELLIST_H__
#define __TELLIST_H__
#define NAME 10
#define SEX 5
#define _CRT_SECURE_NO_WARNINGS 1
#include//malloc开辟空间
int main()
int num = 5;
int *ptr = NULL;
一级指针用来保存普通变量的地址
二级指针用来保存一级指针变量的地址
数据类型** 变量名;
Intnum = 0;
一级指针:
他的最新文章
他的热门文章
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)相关文章推荐
使用malloc函数申请内存空间需要了解:(malloc的原型为:(void *) malloc(int
1)内存分配给谁?
2)分配多大的内存?
3)是否还有足...
1:malloc概述
malloc(num)动态申请num字节的内存空间,函数申请成功返回内存的起始地址(void型),申请不成功返回NULL指针,malloc不初始化内存空间;calloc(type...
鉴于上次领导告诉一个解决方案,让我把它写成文档,结果自己脑子里知道如何操作和解决,但就是不知道如何用语言文字把它给描述出来。决定以后多写一些笔记和微博来锻炼自己的文字功底和培养逻辑思维,不然只会是一个...
一、黑盒测试的测试用例设计方法
1. 等价类划分方法
2. 边界值分析方法
3. 错误推测方法
4. 因果图方法
5. 判定表驱动分析方法
C语言的函数malloc和free
(1) 函数malloc和free在头文件中的原型及参数
void * malloc(size_t size)
动态配置内存,大小有...
malloc/free 和 new/delete
相同点:都可以用于申请动态内存和释放内存。申请的内存都在堆上分配。
不同点:1、new/delete是C++的操作符,而malloc/free是C...
new/delete
new和delete是C++中的运算符(而非函数),用于动态分配和撤销内存
1> 开辟单变量地址空间
//开辟一个存放数组的...
笔试遇到的问题:自己模模糊糊,说不上来。这个介绍的很清晰明了。
c++ 内存获取和释放 new/delete,new[]/delete[]
c 内存获取和释放 malloc/free, ca...
C++学习:malloc/free和new/delete简介:
在C语言中,内存的申请和释放采用的是malloc/calloc/realloc/free来实现的,而在C++语言中,不仅可以使用以上的...
C++学习:对象的new/delete运算符与函数malloc/free摘要:
在学习java的时候,都是使用new来创建新的对象的,对象的存放在堆里的.而回收是由java虚拟机garbag...
他的最新文章
他的热门文章
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)一,函数声明
malloc 向系统申请分配指定size个字节的内存空间。
返回类型是 void* 类型。void* 表示未确定类型的指针。
C,C++规定,void* 类型可以通过类型转换强制转换为任何其它类型的指针
char *p = (char *)malloc(100);
每次都能分配成功&
。注意这里说的“堆上剩余内存块”不是所有剩余内存块之和,因为malloc函数申请的是连续的一块内存。既然malloc函数申请内存有不成功的可能,那我们在使用指向这块内存的指针时,必须用if(NULL!=p)语句来验证内存确实分配成功了。
而free函数的作用是斩断指针变量与这块内存的关系。
malloc两次只free一次会内存泄漏;malloc一次free两次肯定会出错。也就是说,在程序中malloc的使用次数一定要和free相等,否则必有错误。这种错误主要发生在循环使用malloc函数时,往往把malloc和free次数弄错了。
二,malloc和new的区别
1.new返回指定类型的指针并且可以自动计算所需大小
比如:   
p =&& //返回类型为int *类型,分配的大小为sizeof(int)
p = new int[100];&&& //返回类型为int *类型,分配的大小为sizeof(int) * 100
2) 而 malloc 则必须要由我们计算字节数,并且在返回后强行转换为实际类型的指针。   
p = (int *) malloc (sizeof(int)*128);//分配128个(可根据实际需要替换该数值)整型存储单元,并将这128个连续的整型存储单元的首地址存储到指针变量p中
double *pd=(double *) malloc (sizeof(double)*12);//分配12个double型存储单元,并将首地址存储到指针变量pd中
2.malloc只管分配内存,并不能对所得内存初始化,所以得到新的内存其值是随机的&
除了分配及最后释放的方法不一样以外,通过malloc或new得到指针,在其它操作上保持一致。
malloc和free是C/C++中的标准库函数,new和delete是C++的运算符。对于非内置数据类型的对象而言,光用maloc/free 无法满足动态对象的要求。对象在创建的同时要自动执行构造函数, 对象消亡之前要自动执行析构函数。由于malloc/free 是库函数而不是运算符,不在编译器控制权限之内,不能够把执行构造函数和析构函数的任务强加malloc/free
&&相关文章推荐
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:3235次
排名:千里之外
原创:20篇
(2)(1)(6)(8)(3)(2)
(window.slotbydup = window.slotbydup || []).push({
id: '4740887',
container: s,
size: '250,250',
display: 'inlay-fix'&&|&& &&|&& &&|&&
浅析malloc()的几种实现方式
12:46:42 && 阅读:47373&&
上海交通大学计算机科学与工程系 孙高鑫
malloc()是C语言中动态存储管理的一组标准库函数之一。其作用是在内存的动态存储区中分配一个长度为size的连续空间。其参数是一个无符号整形数,返回值是一个指向所分配的连续存储域的起始地址的指针。
&  动态内存分配就是指在程序执行的过程中动态地分配或者回收存储空间的分配内存的方法。动态内存分配不像数组等静态内存分配方法那样需要预先分配存储空间,而是由系统根据程序的需要即时分配,且分配的大小就是程序要求的大小。本文简单介绍动态内存分配函数malloc()及几种实现方法。
&  1. 简介
  malloc()是C语言中动态存储管理的一组标准库函数之一。其作用是在内存的动态存储区中分配一个长度为size的连续空间。其参数是一个无符号整形数,返回值是一个指向所分配的连续存储域的起始地址的指针。还有一点必须注意的是,当函数未能成功分配存储空间(如内存不足)就会返回一个NULL指针。所以在调用该函数时应该检测返回值是否为NULL并执行相应的操作。
&  2. 函数说明
  C语言的动态存储管理由一组标准库函数实现,其原型在标准文件&stdlib.h&里描述,需要用这些功能时应包含这个文件。与动态存储分配有关的函数共有四个,其中就包括存储分配函数malloc()。函数原型是:void *malloc (size_t n);这里的size_t是标准库里定义的一个类型,它是一个无符号整型。这个整型能够满足所有对存储块大小描述的需要,具体相当于哪个整型由具体的C系统确定。malloc的返回值为(void *)类型(这是通用指针的一个重要用途),它分配一片能存放大小为n的数据的存储块,返回对应的指针值;如果不能满足申请(找不到能满足要求的存储块)就返回NULL。在使用时,应该把malloc的返回值转换到特定指针类型,赋给一个指针。
  & 注意,虽然这里的存储块是通过动态分配得到的,但是它的大小也是确定的,同样不允许越界使用。例如上面程序段分配的块里能存n个双精度数据,随后的使用就必须在这个范围内进行。越界使用动态分配的存储块,尤其是越界赋值,可能引起非常严重的后果,通常会破坏程序的运行系统,可能造成本程序或者整个计算机系统垮台。
  下例是一个动态分配的例子:
#include &stdlib.h&
 int count,* /*count是一个计数器,array是一个整型指针,也可以理解为指向一个整型数组的首地址*/
 if((array(int *) malloc (10*sizeof(int)))==NULL)
  printf(&不能成功分配存储空间。&);
  exit(1);
 for (count=0;count〈10;count++) /*给数组赋值*/
  array[count]=
 for(count=0;count〈10;count++) /*打印数组元素*/
  printf(&%2d&,array[count]);
  上例中动态分配了10个整型存储区域,然后进行赋值并打印。例中if((array(int *) malloc (10*sizeof(int)))==NULL)语句可以分为以下几步:
  1)分配10个整型的连续存储空间,并返回一个指向其起始地址的整型指针
  2)把此整型指针地址赋给array
  3)检测返回值是否为NULL
&  3. malloc()工作机制
  malloc函数的实质体现在,它有一个将可用的内存块连接为一个长长的列表的所谓空闲链表。调用malloc函数时,它沿连接表寻找一个大到足以满足用户请求所需要的内存块。然后,将该内存块一分为二(一块的大小与用户请求的大小相等,另一块的大小就是剩下的字节)。接下来,将分配给用户的那块内存传给用户,并将剩下的那块(如果有的话)返回到连接表上。调用free函数时,它将用户释放的内存块连接到空闲链上。到最后,空闲链会被切成很多的小内存片段,如果这时用户申请一个大的内存片段,那么空闲链上可能没有可以满足用户要求的片段了。于是,malloc函数请求延时,并开始在空闲链上翻箱倒柜地检查各内存片段,对它们进行整理,将相邻的小空闲块合并成较大的内存块。
&  4. malloc()在操作系统中的实现
  在 C 程序中,多次使用malloc () 和 free()。不过,您可能没有用一些时间去思考它们在您的操作系统中是如何实现的。本节将向您展示 malloc 和 free 的一个最简化实现的代码,来帮助说明管理内存时都涉及到了哪些事情。
  在大部分操作系统中,内存分配由以下两个简单的函数来处理:
  void *malloc (long numbytes):该函数负责分配 numbytes 大小的内存,并返回指向第一个字节的指针。
  void free(void *firstbyte):如果给定一个由先前的 malloc 返回的指针,那么该函数会将分配的空间归还给进程的&空闲空间&。
  malloc_init 将是初始化内存分配程序的函数。它要完成以下三件事:将分配程序标识为已经初始化,找到系统中最后一个有效内存地址,然后建立起指向我们管理的内存的指针。这三个变量都是全局变量:
  清单 1. 我们的简单分配程序的全局变量
&&&&&&& int has_initialized = 0;
&&&&&&& void *managed_memory_
&&&&&&& void *last_valid_
  如前所述,被映射的内存的边界(最后一个有效地址)常被称为系统中断点或者 当前中断点。在很多 UNIX? 系统中,为了指出当前系统中断点,必须使用 sbrk(0) 函数。 sbrk 根据参数中给出的字节数移动当前系统中断点,然后返回新的系统中断点。使用参数 0 只是返回当前中断点。这里是我们的 malloc 初始化代码,它将找到当前中断点并初始化我们的变量:
  清单 2. 分配程序初始化函数
/* Include the sbrk function */
void malloc_init()
/* grab the last valid address from the OS */
last_valid_address = sbrk(0);
/* we don't have any memory to manage yet, so
&*just set the beginning to be last_valid_address
managed_memory_start = last_valid_
/* Okay, we're initialized and ready to go */
&has_initialized = 1;
  现在,为了完全地管理内存,我们需要能够追踪要分配和回收哪些内存。在对内存块进行了 free 调用之后,我们需要做的是诸如将它们标记为未被使用的等事情,并且,在调用 malloc 时,我们要能够定位未被使用的内存块。因此, malloc 返回的每块内存的起始处首先要有这个结构:
  清单 3. 内存控制块结构定义
struct mem_control_block {
   现在,您可能会认为当程序调用 malloc 时这会引发问题 && 它们如何知道这个结构?答案是它们不必知道;在返回指针之前,我们会将其移动到这个结构之后,把它隐藏起来。这使得返回的指针指向没有用于任何其他用途的内存。那样,从调用程序的角度来看,它们所得到的全部是空闲的、开放的内存。然后,当通过 free() 将该指针传递回来时,我们只需要倒退几个内存字节就可以再次找到这个结构。
  在讨论分配内存之前,我们将先讨论释放,因为它更简单。为了释放内存,我们必须要做的惟一一件事情就是,获得我们给出的指针,回退 sizeof(struct mem_control_block) 个字节,并将其标记为可用的。这里是对应的代码:
  清单 4. 解除分配函数
void free(void *firstbyte) {
struct mem_control_block *
/* Backup from the given pointer to find the
&* mem_control_block
mcb = firstbyte - sizeof(struct mem_control_block);
/* Mark the block as being available */
mcb-&is_available = 1;
/* That's It!& We're done. */
  如您所见,在这个分配程序中,内存的释放使用了一个非常简单的机制,在固定时间内完成内存释放。分配内存稍微困难一些。以下是该算法的略述:
  清单 5. 主分配程序的伪代码
1. If our allocator has not been initialized, initialize it.
2. Add sizeof(struct mem_control_block) to the size requested.
3. start at managed_memory_start.
4. Are we at last_valid address?
5. If we are:
&& A. We didn't find any existing space that was large enough
&&&&& -- ask the operating system for more and return that.
6. Otherwise:
&& A. Is the current space available (check is_available from
&&&&& the mem_control_block)?
&& B. If it is:
&&&&& i)&& Is it large enough (check &size& from the
&&&&&&&&&& mem_control_block)?
&&&&& ii)& If so:
&&&&&&&&&& a. Mark it as unavailable
&&&&&&&&&& b. Move past mem_control_block and return the
&&&&&&&&&&&&& pointer
&&&&& iii) Otherwise:
&&&&&&&&&& a. Move forward &size& bytes
&&&&&&&&&& b. Go back go step 4
&& C. Otherwise:
&&&&& i)&& Move forward &size& bytes
&&&&& ii)& Go back to step 4
  我们主要使用连接的指针遍历内存来寻找开放的内存块。这里是代码:
  清单 6. 主分配程序
void *malloc(long numbytes) {
/* Holds where we are looking in memory */
void *current_
/* This is the same as current_location, but cast to a
&* memory_control_block
struct mem_control_block *current_location_
/* This is the memory location we will return.& It will
&* be set to 0 until we find something suitable
void *memory_
/* Initialize if we haven't already done so */
if(! has_initialized) {
malloc_init();
/* The memory we search for has to include the memory
&* control block, but the users of malloc don't need
&* to know this, so we'll just add it in for them.
numbytes = numbytes + sizeof(struct mem_control_block);
/* Set memory_location to 0 until we find a suitable
&* location
memory_location = 0;
/* Begin searching at the start of managed memory */
current_location = managed_memory_
/* Keep going until we have searched all allocated space */
while(current_location != last_valid_address)
/* current_location and current_location_mcb point
&* to the same address.& However, current_location_mcb
&* is of the correct type, so we can use it as a struct.
&* current_location is a void pointer so we can use it
&* to calculate addresses.
current_location_mcb =
(struct mem_control_block *)current_
if(current_location_mcb-&is_available)
if(current_location_mcb-&size &= numbytes)
/* Woohoo!& We've found an open,
&* appropriately-size location.
/* It is no longer available */
current_location_mcb-&is_available = 0;
/* We own it */
memory_location = current_
/* Leave the loop */
/* If we made it here, it's because the Current memory
&* move to the next one
current_location = current_location +
current_location_mcb-&
/* If we still don't have a valid location, we'll
&* have to ask the operating system for more memory
if(! memory_location)
/* Move the program break numbytes further */
sbrk(numbytes);
/* The new memory will be where the last valid
&* address left off
memory_location = last_valid_
/* We'll move the last valid address forward
&* numbytes
last_valid_address = last_valid_address +
/* We need to initialize the mem_control_block */
current_location_mcb = memory_
current_location_mcb-&is_available = 0;
current_location_mcb-&size =
/* Now, no matter what (well, except for error conditions),
&* memory_location has the address of the memory, including
&* the mem_control_block
/* Move the pointer past the mem_control_block */
memory_location = memory_location + sizeof(struct mem_control_block);
/* Return the pointer */
return memory_
  这就是我们的内存管理器。现在,我们只需要构建它,并在程序中使用它即可。
  5. malloc()的其他实现
  malloc() 的实现有很多,这些实现各有优点与缺点。在设计一个分配程序时,要面临许多需要折衷的选择,其中包括:
分配的速度。
回收的速度。
有线程的环境的行为。
内存将要被用光时的行为。
局部缓存。
簿记(Bookkeeping)内存开销。
虚拟内存环境中的行为。
小的或者大的对象。
实时保证。
每一个实现都有其自身的优缺点集合。在我们的简单的分配程序中,分配非常慢,而回收非常快。另外,由于它在使用虚拟内存系统方面较差,所以它最适于处理大的对象。
  还有其他许多分配程序可以使用。其中包括:
  Doug Lea Malloc:Doug Lea Malloc 实际上是完整的一组分配程序,其中包括 Doug Lea 的原始分配程序,GNU libc 分配程序和 ptmalloc。 Doug Lea 的分配程序有着与我们的版本非常类似的基本结构,但是它加入了索引,这使得搜索速度更快,并且可以将多个没有被使用的块组合为一个大的块。它还支持缓存,以便更快地再次使用最近释放的内存。 ptmalloc 是 Doug Lea Malloc 的一个扩展版本,支持多线程。在本文后面的 参考资料部分中,有一篇描述 Doug Lea 的 Malloc 实现的文章。
  BSD Malloc:BSD Malloc 是随 4.2 BSD 发行的实现,包含在 FreeBSD 之中,这个分配程序可以从预先确实大小的对象构成的池中分配对象。它有一些用于对象大小的 size 类,这些对象的大小为 2 的若干次幂减去某一常数。所以,如果您请求给定大小的一个对象,它就简单地分配一个与之匹配的 size 类。这样就提供了一个快速的实现,但是可能会浪费内存。在 参考资料部分中,有一篇描述该实现的文章。
  Hoard:编写 Hoard 的目标是使内存分配在多线程环境中进行得非常快。因此,它的构造以锁的使用为中心,从而使所有进程不必等待分配内存。它可以显著地加快那些进行很多分配和回收的多线程进程的速度。在 参考资料部分中,有一篇描述该实现的文章。
众多可用的分配程序中最有名的就是上述这些分配程序。如果您的程序有特别的分配需求,那么您可能更愿意编写一个定制的能匹配您的程序内存分配方式的分配程序。不过,如果不熟悉分配程序的设计,那么定制分配程序通常会带来比它们解决的问题更多的问题。
&  6. 结束语
  前面已经提过,多次调用malloc()后空闲内存被切成很多的小内存片段,这就使得用户在申请内存使用时,由于找不到足够大的内存空间,malloc()需要进行内存整理,使得函数的性能越来越低。聪明的程序员通过总是分配大小为2的幂的内存块,而最大限度地降低潜在的malloc性能丧失。也就是说,所分配的内存块大小为4字节、8字节、16字节、字节,等等。这样做最大限度地减少了进入空闲链的怪异片段(各种尺寸的小片段都有)的数量。尽管看起来这好像浪费了空间,但也容易看出浪费的空间永远不会超过50%。
&  参考文献:
  [1]& Jonathan Bartlett,内存管理内幕. developerWorks 中国,2004年11月
  [2]& Jan Lindblad,内存碎片处理技术. EDN电子设计技术,日
后参与讨论
淡泊以明志
宁静以致远
阅读:1204
阅读:3002
阅读:3087
阅读:3701

我要回帖

更多关于 malloc函数头文件 的文章

 

随机推荐