精华内容
下载资源
问答
  • 动态内存分配

    2017-05-24 01:12:20
    1.为什么使用动态内存分配 数组在使用的时候可能造成内存浪费,使用动态内存分配可以解决这个问题。 2. malloc和free C函数库提供了两个函数,malloc和free,分别用于执行动态内存分配和释放。 (1)void ...
    《C与指针》读书笔记
    1.为什么使用动态内存分配
    数组在使用的时候可能造成内存浪费,使用动态内存分配可以解决这个问题。
    2. malloc和free
    C函数库提供了两个函数,malloc和free,分别用于执行动态内存分配和释放。
    (1)void *malloc(size_t size);
    malloc的参数就是需要分配的内存字节数。malloc分配一块连续的内存。如果操作系统无法向malloc提供更多的内存,malloc就返回一个NULL指针。
    (2)void free(void *pointer);
    free的参数要么是NULL,要么是一个先前从malloc、calloc或realloc返回的值。
    3. calloc和realloc
    (1)void *calloc(size_t num_elements,size_t element_size);
    calloc也用于内存分配。malloc和calloc之间的主要区别是后者在返回指向内存的指针之前把它初始化为0。
    (2)realloc(void *ptr,size_t new_size);
    realloc函数用于修改一个原先已经分配的内存块的大小。如果它用于扩大一个内存,那么这块内存原先的内容依然保留,新增加的内存添加到原先内存块的后面。如果它用于缩小一个内存块,该内存块尾部的部分内存被拿掉,剩余部分内存的原先内容依然保留。
    4. 使用动态分配的内存
    (1)使用示例
    int *pi;
    pi = malloc(25 * sizeof(int));
    if(pi == NULL){
    printf("out of memery\n");
    exit(1);
    }
    (2)使用间接访问
    int *pi2,i;
    pi2 = pi;
    for(i = 0;i < 25;i += 1)
    *pi2++ = 0;
    也可以使用下标。
    int i;
    for(i = 0;i < 25;i += 1)
    *pi[i] = 0;
    5. 常见的动态内存错误
    常见的错误有:对NULL指针进行解引用操作、对分配的内存进行操作时越过边界、释放并非内存分配的内存、试图释放一块动态分配的内存的一部分以及一块动态内存释放之后被继续使用。



    展开全文
  • 静态内存分配与动态内存分配

    千次阅读 2019-05-25 14:05:02
    静态内存分配与动态内存分配 动机 平时看c/c++的书籍时,总会看到一种观点,说是C/C++语言使用的时候动态内存分配是最重要的,使用malloc等函数分配的内存必须要释放,否则及其容易出现内存泄露。但是自己有时候挺...

    静态内存分配与动态内存分配

    动机

    平时看c/c++的书籍时,总会看到一种观点,说是C/C++语言使用的时候动态内存分配是最重要的,使用malloc等函数分配的内存必须要释放,否则及其容易出现内存泄露。但是自己有时候挺奇怪的,啥时候的内存要自己释放,啥时候的内存是编译器释放呢?

    内存模型

    在这里插入图片描述
    这是csapp上面的linux进程内存分布图,从图中最下面往上看,只读段和读写段,在代码编译结束的时候就已经固定了,这一部分在整个进程生命周期是不会改变的。
    这一部分的内存是动态分配的,也就是需要我们程序员自己进行释放的,
    共享库这是链接的时候复制过来的库的代码 所以其实也是固定的
    ==栈-==用户站,编译器用它来实现函数调用,它是动态的,但是在这一部分,也就是函数内部的变量,是不需要程序员手动管理的,由编译器管理。

    通过对比加深理解

    内存的静态分配和动态分配的区别主要是两个:

    一是时间不同。静态分配发生在程序编译和连接的时候。动态分配则发生在程序调入和执行的时候。
    二是空间不同堆都是动态分配的,没有静态分配的堆。栈有2种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配由函数malloc进行分配。不过栈的动态分配和堆不同,他的动态分配是由编译器进行释放,无需我们手工实现。

    对于一个进程的内存空间而言,可以在逻辑上分成3个部份:代码区,静态数据区和动态数据区。动态数据区一般就是“堆栈”。“栈(stack)”和“堆(heap)”是两种不同的动态数据区,栈是一种线性结构,堆是一种链式结构。进程的每个线程都有私有的“栈”,所以每个线程虽然代码一样,但本地变量的数据都是互不干扰。一个堆栈可以通过“基地址”和“栈顶”地址来描述。全局变量和静态变量分配在静态数据区,本地变量分配在动态数据区,即堆栈中。程序通过堆栈的基地址和偏移量来访问本地变量。

    所以,举个生动的例子就是说,静态分配内存的数据都是从生下来就拥有内存位置,不需要你去管理,而动态内存是后天要拼搏获取的内存位置,同时用完了也要释放

    动态内存分配是哪些数据?

    1.变长数组。
    2.声明的指针指向一个内存,用malloc等内存分配函数申请。

    总结

    最后发现就是一句话,如果有自己申请的就需要自己释放,不然就没有什么关系,而自己申请的大多也都是声明一个指针然后调用内存申请的函数,现代C++都是用RAII就没有这个问题了,析构的时候一般就不需要手动释放内存了。

    展开全文
  • 动态内存分配

    动态内存分配

    所谓动态内存分配(Dynamic Memory Allocation)就是指在程序执行的过程中动态地分配或者回收存储空间的分配内存的方法。动态内存分配不象数组等静态内存分配方法那样需要预先分配存储空间,而是由系统根据程序的需要即时分配,且分配的大小就是程序要求的大小。

    在c中,动态内存分配使用malloc与free来分配内存和释放内存.用法为:

    void *malloc(size_t size);
    void free(void *ptr);
    

    其中size为要申请空间的字节数

    而在c++中,动态内存分配有新的关键字new与delete,但同时也兼容c的malloc与free,但推荐使用new与delete.
    为什么呢?因为new与delete是运算符而malloc与free是函数,所以new与delete的执行效率要高些,而且new与delete可以初始化变量.

    #include <iostream>
    #include <Windows.h>
    
    using namespace std;
    
    int main(void){
    	int *a=new int(10);//动态分配一个int类型的变量,并把变量初始化为10,a指向这个变量
    	cout<<*a<<endl;
    	delete a;
    	
    	int *p=new int[5];//可以动态分配数组,但是不能在分配的同时初始化!!!
    	for(int i=0;i<5;i++){//里面是随机值
    		cout<<p[i]<<endl;
    	}
    	delete[] p;
    	
    	system("pause");
    	return 0;
    }
    

    在这里插入图片描述
    通过以上代码及注释与运行结果,大家应该了解了它的用法,下面是总结:

    1. 在使用new关键字分配变量时可以同时进行初始化,而在分配数组时不可以.
    2. 无论是new还是malloc分配内存,在使用完后一定一定要释放内存,否则会造成内存泄漏.
    3. c++中这两种分配内存的方法可以混用,即用new分配内存,用free释放内存.

    内存泄漏及检测

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

    如何检测内存泄漏呢?看以下代码:

    //包含头文件
    #define _CRTDEG_MAP_ALLOC
    #include <stdlib.h>
    #include <crtdbg.h>
    #include <iostream>
    #include <Windows.h>
    
    //接管new操作符
    #ifdef _DEBUG
    #ifndef DBG_NEW
    #define DBG_NEW new (_NORMAL_BLOCK,__FILE__,__LINE__)
    #define new DBG_NEW
    #endif
    #endif
    
    using namespace std;
    
    int main(void){
    	int *p;
    	for(int i=0;i<5;i++){
    		p=new int[5];//动态内存分配
    	}
    	
    	_CrtDumpMemoryLeaks();//输出内存泄漏信息
    	system("pause");
    	return 0;
    }
    

    运行结果:
    在这里插入图片描述
    很奇怪,对吧?什么都没输出,我们来看看IDE的输出界面:
    在这里插入图片描述
    Detected memory leaks!检测到内存泄漏,标注了泄漏的文件,泄漏的字节长度,泄漏的位置.我调用了五次new操作符且未回收,所以它报了五次内存泄漏.
    _CrtDumpMemoryLeaks();的作用:当它执行时,所有未销毁的对象均会报内存泄漏.所以我们最好在程序将要结束的时候使用它.
    要实现检测分三步:
    1.包含头文件(宏定义是为了输出内存泄漏发生在哪个文件)

    #define _CRTDEG_MAP_ALLOC
    #include <stdlib.h>
    #include <crtdbg.h>
    

    2.接管new操作符

    #ifdef _DEBUG
    #ifndef DBG_NEW
    #define DBG_NEW new (_NORMAL_BLOCK,__FILE__,__LINE__)
    #define new DBG_NEW
    #endif
    #endif
    

    3.调用

    _CrtDumpMemoryLeaks();
    

    以上的方法实际上是使用了CRT库,对于内存泄漏的检测,其实有很多工具,比如:MallocDebug,Valgrind,Kcachegrind,dmalloc,NuMega,BoundsCheck,ParaSoft,Insure++等等,随着代码量的增长,内存泄漏这种问题几乎是无法避免的,这时我们可以利用这些工具比较便捷找到问题所在.

    展开全文
  • c语言动态内存分配

    千次阅读 2019-01-03 23:00:21
    动态内存分配是许多高级程序设计技巧的关键。 所有程序都必须留下足够的内存来存储程序使用的数据。这些内存中,有些是自动分配的(栈),有些是在编译时就确定好的(静态区),c语言还可以实现动态的/运行时的内存...

    动态内存分配是许多高级程序设计技巧的关键。

    所有程序都必须留下足够的内存来存储程序使用的数据。这些内存中,有些是自动分配的(栈),有些是在编译时就确定好的(静态区),c语言还可以实现动态的/运行时的内存分配,提高程序的灵活性。

    c语言动态内存分配的主要工具是stdlib.h中的malloc()、calloc()和free()函数。

    malloc()函数会向操作系统请求内存块,并返回内存块的首地址。可以用一个指针变量保存这个地址。
    这里注意的是,这个内存块是匿名的,也就是不像int x 那样,x为内存地址的标识符。
    地址的类型为通用指针void *,我们需要为其强制类型转换。但申请失败时,返回值为NULL,所以我们申请完内存后,需要判断是否申请成功。
    malloc的参数为内存的字节大小。

    calloc()函数与malloc函数大体相同,calloc函数接受两个参数,单元数量和单元大小,并且内存块中的值为0;

    有借有还再借不难,free()函数用于释放申请的内存。如果忘记释放,那么可能把指向该内存块的指针搞丢了,我们再也无法操作这个内存,这就是内存泄露问题。

    下面是c primer plus 中的一个示例程序,程序动态分配由用户制定大小和值的double 数组,并把数组打印出来

    #include <stdio.h>
    #include <stdlib.h>
    
    int main(void)
    {
    	double *ptd = NULL;
    	int max;
    	int number;
    	int i = 0;
    
    	puts("What is the maximun number of type double entries?");
    	
    	if(scanf("%d", &max)!=1)
    	{	
    		puts("Number not correctly entered --bye.");
    		exit(EXIT_FAILURE);
    	}
    	
    	ptd = (double *) malloc(max*sizeof(double));
    	if(ptd == NULL)
    	{
    		puts("Memory allocation failed. Goodbye.");
    		exit(EXIT_FAILURE);	
    	}	
    	
    	puts("Enter the values (q to quit):");
    
    	while(i < max && scanf("%lf",&ptd[i]) == 1)
    		++i;
    	
    	printf("Here are you %d entries:\n",number = i);
    	for(i=0 ; i < number ;i++)
    	{
    		printf("%7.2f",ptd[i]);
    			if(i%7 ==6)
    			putchar('\n');	
    	}	
    	
    	if(i%7 !=0)
    		putchar('\n');
    	puts("Done.");
    	free(ptd);
    	ptd = NULL;
    
    	return 0;
    }
    

    下面是转载的

    calloc(), malloc(), realloc(), free(),alloca()

    内存区域可以分为栈、堆、静态存储区和常量存储区,局部变量,函数形参,临时变量都是在栈上获得内存的,它们获取的方式都是由编译器自动执行的。
    利用指针,我们可以像汇编语言一样处理内存地址,C 标准函数库提供了许多函数来实现对堆上内存管理,其中包括:malloc函数,free函数,calloc函数和realloc函数。使用这些函数需要包含头文件stdlib.h。

    四个函数之间的有区别,也有联系,我们应该学会把握这种关系,从而编出精炼而高效的程序。

    在说明它们具体含义之前,先简单从字面上加以认识,前3个函数有个共同的特点,就是都带有字符”alloc”,就是”allocate”,”分配”的意思,也就是给对象分配足够的内存,” calloc()”是”分配内存给多个对象”,” malloc()”是”分配内存给一个对象”,”realloc()”是”重新分配内存”之意。”free()”就比较简单了,”释放”的意思,就是把之前所分配的内存空间给释放出来。
    void *calloc(size_t nobj, size_t size);

    分配足够的内存给nobj个大小为size的对象组成的数组, 并返回指向所分配区域的第一个字节的指针;
    若内存不够,则返回NULL. 该空间的初始化大小为0字节.
    char *p = (char *) calloc(100,sizeof(char));

    void *malloc(size_t size);

    分配足够的内存给大小为size的对象, 并返回指向所分配区域的第一个字节的指针;
    若内存不够,则返回NULL. 不对分配的空间进行初始化.
    char *p = (char *)malloc(sizeof(char));

    void *realloc(void *p, size_t size);

    将p所指向的对象的大小改为size个字节.
    如果新分配的内存比原内存大, 那么原内存的内容保持不变, 增加的空间不进行初始化.
    如果新分配的内存比原内存小, 那么新内存保持原内存的内容, 增加的空间不进行初始化.
    返回指向新分配空间的指针; 若内存不够,则返回NULL, 原p指向的内存区不变.
    char *p = (char *)malloc(sizeof(char));
    p= (char *)realloc(p, 256);

    void free(void *p);

    释放p所指向的内存空间; 当p为NULL时, 不起作用.
    p必先调用calloc, malloc或realloc.

    值得注意的有以下5点:

    (1)通过malloc函数得到的堆内存必须使用memset函数来初始化

    malloc函数分配得到的内存空间是未初始化的。因此,一般在使用该内存空间时,要调用另一个函数memset来将其初始化为全0,memset函数的声明如下:void * memset (void * p,int c,int n) ;

    该函数可以将指定的内存空间按字节单位置为指定的字符c,其中,p为要清零的内存空间的首地址,c为要设定的值,n为被操作的内存空间的字节长度。如果要用memset清0,变量c实参要为0。

    malloc函数和memset函数的操作语句一般如下:

    int * p=NULL;

    p=(int*)malloc(sizeof(int));

    if(p==NULL)

    printf(“Can’t get memory!\n”);

    memset(p,0,siezeof(int));

    (2)使用malloc函数分配的堆空间在程序结束之前必须释放

    从堆上获得的内存空间在程序结束以后,系统不会将其自动释放,需要程序员来自己管理。一个程序结束时,必须保证所有从堆上获得的内存空间已被安全释放,否则,会导致内存泄露。

    我们可以使用free()函数来释放内存空间,但是,free函数只是释放指针指向的内容,而该指针仍然指向原来指向的地方,此时,指针为野指针,如果此时操作该指针会导致不可预期的错误。安全做法是:在使用free函数释放指针指向的空间之后,将指针的值置为NULL。

    (3)calloc函数的分配的内存也需要自行释放

    calloc函数的功能与malloc函数的功能相似,都是从堆分配内存,它与malloc函数的一个显著不同时是,calloc函数得到的内存空间是经过初始化的,其内容全为0。calloc函数适合为数组申请空间,可以将size设置为数组元素的空间长度,将n设置为数组的容量。

    (4)如果要使用realloc函数分配的内存,必须使用memset函数对其内存初始化

    realloc函数的功能比malloc函数和calloc函数的功能更为丰富,可以实现内存分配和内存释放的功能。realloc 可以对给定的指针所指的空间进行扩大或者缩小,无论是扩张或是缩小,原有内存的中内容将保持不变。当然,对于缩小,则被缩小的那一部分的内容会丢失。realloc 并不保证调整后的内存空间和原来的内存空间保持同一内存地址。相反,realloc 返回的指针很可能指向一个新的地址。

    所以,在代码中,我们必须将realloc返回的值,重新赋值给 p :

    p = (int *) realloc(p, sizeof(int) *15);

    甚至,你可以传一个空指针(0)给 realloc ,则此时realloc 作用完全相当于malloc。

    int* p = (int *)realloc (0,sizeof(int) * 10); //分配一个全新的内存空间,

    这一行,作用完全等同于:

    int* p = (int *)malloc(sizeof(int) * 10);

    (5)关于alloca()函数

    还有一个函数也值得一提,这就是alloca()。其调用序列与malloc相同,但是它是在当前函数的栈帧上分配存储空间,而不是在堆中。其优点是:当 函数返回时,自动释放它所使用的栈帧,所以不必再为释放空间而费心。其缺点是:某些系统在函数已被调用后不能增加栈帧长度,于是也就不能支持alloca 函数。尽管如此,很多软件包还是使用alloca函数,也有很多系统支持它。

    总结:应用时候需要记得,只有calloc可以指定个数和大小,而且能够对分配内存进行初始化,其余函数均不会对内存进行初始化工作,需要自行调用memset()函数.

    展开全文
  • C++动态内存分配

    2017-06-06 16:03:02
    笔者介绍:姜雪伟,IT公司技术合伙人,IT高级讲师,...CSDN视频网址:http://edu.csdn.net/lecturer/144 C / C ++中的动态内存分配是指程序员手动执行内存分配, 动态分配的内存分配给堆,非静态和局部变量获取在St
  • 动态内存分配函数

    千次阅读 2018-03-28 21:43:28
    一、静态存储分配与动态存储分配: 二、动态内存分配函数 malloc calloc realloc free new delete

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 29,602
精华内容 11,840
关键字:

动态内存分配