C 语言动态内存分配

C语言中内存管理主要分为以下几块:

  • 栈区
  • 堆区
  • 全局区或静态区
  • 字符常量区
  • 程序代码区

一般栈区都是由系统自动分配回收,但是栈区大小是有限制的,windows下一般为程序分配的栈内存为2M左右。超出就会抛出stack overflow错误.

如下:

void main(){
    //40M
    //静态内存分配
    int a[1024 * 1024 * 10];
    getchar();
}

上面的代码运行时就会抛出 stack overflow。这种情况下,就需要程序人员,手动在堆区分配与释放内存。

在C语言中内存管理主要通过以下几个函数进行:

  • malloc()
  • realloc()
  • calloc()
  • free()

malloc与calloc函数都是进行堆内存分配,区别主要在于传参形式不一样:

    //8M
    int * p = malloc(1024 * 1024 * 2 * sizeof(int));
    //8M
    int * p2 = calloc(1024 * 1024 * 2,sizeof(int));

realloc函数用于重新分配内存。分为两种情况:

  • 缩小:缩小的那一部分数据会丢失。
  • 增大:
    • 如果当前内存段后面有需要的内存空间,直接扩展这段内存空间,realloc返回原指针
    • 如果当前内存段后面的空闲字节不够,那么就使用堆中的第一个能够满足这一要求的内存块,将目前的数据复制到新的位置,并将原来的数据库释放掉,返回新的内存地址
    • 如果申请失败,返回NULL,原来的指针仍然有效

示例:

void main(){
    int len;
    printf("第一次输入数组的长度:");
    scanf("%d", &len);

    //int* p = malloc(len * sizeof(int));   
    int* p = calloc(len, sizeof(int));
    int i = 0;
    for (; i < len; i++){
        p[i] = rand() % 100;
        printf("%d,%#x\n", p[i], &p[i]);
    }

    int addLen;
    printf("输入数组增加的长度:");
    scanf("%d", &addLen);
    //内存不够用,扩大刚刚分配的内存空间
    //1.原来内存的指针 2.内存扩大之后的总大小        
    int* p2 = realloc(p, sizeof(int)* (len + addLen));
    if (p2 == NULL){
        printf("重新分配失败");
        free(p);
        p = NULL;
        return;
    }
    
    //重新赋值
    i = 0;
    printf("--------------------------\n");
    for (; i < len + addLen; i++){
        p2[i] = rand() % 200;
        printf("%d,%#x\n", p2[i], &p2[i]);
    }

    //手动释放内存
    if (p2 != NULL){
        free(p2);
        p2 = NULL;
    }

    getchar();
}

free函数用于释放内存。如上所示。

Note:同一块内存区不能多次释放,释放完之后(指针仍然有值),一般地给指针置NULL,标志释放完成,避免这种情况。重新分配内存成功后,如果是原地址,上面即是p =p2.如果是新开辟的内存,则p会被系统自动释放,所以后面只释放p2即可。

下面再看一个内存分配的例子:


void main(){

    int len = 4;
    char ** args = malloc(sizeof(char*)*len);
    int i = 0;
    for ( ; i < 4; i++)
    {
        args[i] = malloc(sizeof(char)* 20);
        sprintf(args[i],"array[%d]",i);
    }

    for ( i = 0; i < 4; i++)
    {
        free(args[i]);
    }

    free(args);

    getchar();
}

上面的示例中,我们进行了两次开辟,好像跟上面讲的不一样,数组开辟空间后,为啥单个元素还要再次开辟,而上面的数组却没有?其实不然。

这里我们定义的是一个字符串数组。但是C中是没有字符串的,每一个字符串其实是一个字符数组,所以,它相当于是一个二维数组,所以需要再次分配内存。

我们再举个二维数组,动态分配的例子:

#include  
#include  
int main() 
{ 
int n1,n2; 
int **array,i,j; 
printf("请输入所要创建的动态数组的第一维长度:");
scanf("%d",&n1);
printf("请输入所要创建的动态数组的第二维长度:");
scanf("%d",&n2); 
array=(int**)malloc(n1*sizeof(int*)); //第一维 
for(i=0;i

这两个例子,对比着看,相信就不会有啥疑惑了。

你可能感兴趣的:(C 语言动态内存分配)