美文网首页设计语言
C语言内存分配函数比较

C语言内存分配函数比较

作者: konishi5202 | 来源:发表于2019-02-21 14:51 被阅读1次

一、函数介绍

1.1 函数原型

C语言应用程序编程中动态分配内存的函数主要有realloc、malloc、calloc三个函数,其原型如下(都在stdlib.h函数库内):

void *malloc(size_t size);
void *realloc(void *ptr, unsigned newsize);
void *calloc(size_t numElements, size_t sizeofElement);

它们的返回值都是请求系统分配的地址,如果请求失败就返回NULL。

注意:这里的空间长度都是以字节为单位

1.2 malloc函数

malloc用于在内存的动态存储区中分配一块长度为size字节的连续区域,返回该区域的首地址,参数size为需要内存空间的长度,如:

char *p = NULL;
p = (char *)malloc(20);

1.3 realloc

realloc是给一个已经分配了地址的指针重新分配空间,将ptr内存大小增大到size,参数ptr为原有的空间地址,newsize是重新申请的地址长度,如:

char *p = NULL;
p = (char *)malloc(sizeof(char)*20);
p = (char *)realloc(p, sizeof(char)*40);

1.3 calloc

calloc与malloc相似,用于在内存的动态存储区中分配n块长度为size字节的连续区域,返回首地址,参数sizeofElement为申请地址的单位元素长度,numElements为元素的个数,如:

char *p = NULL;
p = (char *)calloc(20,sizeof(char));

1.4 malloc和calloc的异同:

  1. 他们的返回值都是void *类型;
  2. malloc和calloc都是从空间内存池中分配内存;
  3. malloc返回一个对象,而calloc返回的是一个数组;
  4. calloc分配的内存空间中的值默认为0,而malloc分配的内存中可以是任意值。

二、内存常见异常

*** glibc detected *** free(): invalid pointer:
*** glibc detected *** malloc(): memory corruption:
*** glibc detected *** double free or corruption (out): 0x00005c1a ***
*** glibc detected *** corrupted double-linked list: 0x00005c1a ***

当遇到这种报错,程序无端coredump,gdb到core文件里面也看不出个所以然,这对于一个大型的商业系统来说太令人恐怖了,事故随时可能发生。

内存问题始终是C/C++程序员需要去面对的问题,也是C/C++语言门槛较高的原因之一。通常我们会犯的内存问题大概有以下几种:

  • 内存重复释放,出现double free()时,通常是由于这种情况所致;
  • 内存泄露,分配的内存忘记释放;
  • 空指针,对一个空指针进行操作;
  • 使用了无效指针;
  • 内存越界使用,使用了不该使用的内存;

对于前面三种,不用多说,会产生什么后果应该都很清楚。对于第四种,通常指操作已经释放的指针对象,如:多线程中某一动态分配的对象同时被两个线程使用,一个线程释放了对象,而另一个线程继续对该对象进行操作。

下面重点讲述第五中情况。内存越界使用,这样的错误引起的问题存在极大的不确定性,有时大,有时小,有时可能不会对程序的运行产生影响。正是这种不易重现的错误,才是最致命的,一旦出错破坏性极大。下面列举几个常见造成越界使用的情况。

【例1】:

char buf[32] = {0};
for(int i = 0; i < n; i++)  //n < 32 or n > 32
    buf[i] = x;

【例2】:

char buf[32] = {0};
string str = "this is a test string !!!";
sprintf(buf, "this is a test buf!string:%s", str); // out of buffer space

【例3】:

string str = "this is a test string !!!";
char buf[16] = {0};
strcpy(buf, str);  //out of buffer space

类似的还存在隐患的函数还有:strcat,vsprintf,memcpy,memset,memmove等。

这样的代码一旦运行,错误就在所难免,会带来的后果也不确定,通常可能会造成的后果如下:

  • 破坏了堆中的内存分配信息数据,特别是动态分配的内存块的内存信息数据,因为操作系统在分配和释放内存时需要访问该数据,一旦该数据破坏,以下的几种情况都可能会出现:
*** glibc detected *** free(): invalid pointer:
*** glibc detected *** malloc(): memory corruption:
*** glibc detected *** double free or corruption (out): 0x00005c1a ***
*** glibc detected *** corrupted double-linked list: 0x00005c1a ***
  • 破坏了程序自己的其他对象的内存空间,这种破坏会影响程序执行的不正确性,当然也会诱发coredump,如破坏了指针数据。
  • 破坏了空闲内存块,很荣幸,这样不会产生什么问题,但谁知道什么时候不幸会降临呢?

而通常,代码错误被激发也是偶然的,也就是说之前你的程序一直正常,可能由于你为类增加了两个成员变量,或者改变了某一部分代码,coredump就频繁发生,而你增加的代码不会有任何问题,这时就应该考虑是否是某些内存被破坏了。

排查的原则,首先是保证能重现错误,根据错误估计可能的环节,逐步裁剪代码,缩小排查空间。检查所有的内存操作函数,检查内存越界的可能。常用的内存操作函数有:

sprintf snprintf
vsprintf vsnprintf
strcpy strncpy strcat
memcpy memmove memset bcopy

同时,如果有用到自己编写的动态库的情况,要确保动态库的编译与程序编译的环境一致。

最后,在别处看到如下实例的用法:

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

int main()
{
    int *p1 = (int *)malloc(0);
    int *p2 = (int *)realloc(p1, 10*sizeof(int));
    int *p3 = (int *)realloc(NULL, 10*sizeof(int));

    printf("malloc(0) return :%p\n", p1);
    printf("realloc(p1, 10*sizeof(int)) return :%p\n", p2);
    printf("realloc(NULL, 10*sizeof(int)) return :%p\n", p3);

    return 0;
}

其输出为:

malloc(0) return :0x1b01010
realloc(p1, 10*sizeof(int)) return :0x1b01010
realloc(NULL, 10*sizeof(int)) return :0x1b01040

留着将来有空再研究一下。

相关文章

网友评论

    本文标题:C语言内存分配函数比较

    本文链接:https://www.haomeiwen.com/subject/feiryqtx.html