内存(动态开辟)———C语言

内存管理:

 1.C语言运行时的内存分配

2.static关键字

1.修饰变量

局部变量:

        <1>在编译的过程中,会在数据区为该变量开辟空间,如果代码中未对其进行初始化,则系统默认初始化为0。

        <2>用static修饰的局部变量,会延长局部变量的生命周期

#include <stdio.h>
void fun(){
        static int var= 10;
        var++;
        printf("var=%d\n",var);}
int main(){
        fun();
        fun();
        fun();
        return 0;
}

修饰全局变量

        <1>static修饰全局变量,会在数据区域分配存储空间,如果全局变量未初始化,编译器会自动初始化为0.

        <2>static修饰全局变量,会限制全局变量的使用范围,让其只能在本文件使用,其他文件不能使用。


#include <stdio.h>
static int global_var = 10;

main.c

#include <stdio.h>
extern int global_var;
void fun(){
    printf("global_var = %d\n", global_var);
    return;
}//此时就不能被正常使用

2.修饰函数:

修饰函数后函数变为静态函数

<1>静态函数只能在声明它的文件中使用,其他文件不能引用该函数

<2>不同的文件可以使用相同名字的静态函数,互不影响

动态内存分配:

固定开辟的内存大小在程序运行时我们无法准确掌握,因此就需要进行动态开辟内存

<1>malloc和free:

如果开辟成功,则返回一个指向开辟空间的指针如果开辟失败,则返回一个NULL指针,因此malloc的返回值要进行检查返回值的类型是 void* ,所以malloc函数并不知道开辟空间的类型,具体在使用时由使用者决定如果参数size=0,malloc的行为是标准未定义的,取决于编译器

#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <stdlib.h>
int main() {
    int* p =(int*) malloc(sizeof (int)*10);
    //动态开辟内存
    if(NULL==10){
        printf("%s\n", strerror(errno));//用于判断内存开辟是否失败
    } else{
        for (int i = 0; i < 10; i++) {
            *(p + i) = i + 1;//进行赋值
        }                //打印
        for (int i = 0; i < 10; i++) {
            printf("%-4d", *(p + i));
        }
        printf("\n");
    }
    return 0;
}

void free(void* memblock)

  • 如果参数memblock指向的空间不是动态开辟的,那么free函数的行为是未定义的
  • 如果参数memblock是NULL指针,则函数什么也不做

Tips:

<1>C语言中可以创建变长数组,C99标准支持

<2> malloc和free都声明在stdlib.h的头文件中

<2>calloc:

void* calloc(size_t num,size_t size);

与malloc不同的是calloc会返回地址之前把申请的每个字节初始化为0

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main() {
        // 向内存申请15个整型类型的空间
        int* p = (int*)calloc(10, sizeof(int));
        //判断是否开辟成功
        if (NULL == p) {
                // 打印错误信息
                printf("%s\n", strerror(errno));
        }
        else {
                // 给10个空间进行赋值并打印
                for (int i = 0; i < 10; i++) {
                        *(p + i) = i + 1;
                }
                // 打印
                for (int i = 0; i < 15; i++) {
                        printf("%-4d", *(p + i));
                }
        printf("\n");
                // 释放空间
                free(p);
                p = NULL;
        }
        return 0;
}

<3>realloc:

realloc函数会让动态内存管理更灵活,调整对应的内存地址大小

原型:void* realloc(void* ptr,size_t size)

  1. ptr是要调整的内存地址
  2. size 调整之后的内存大小
  3. 返回值为调整之后的内存起始地址
  4. 这个函数会将原内存中的数据迁移到新的内存空间
  5. 这个函数会将原内存空间自动释放
  6. realloc在调整动态分配的内存空间大小时,有两种情况  

    <1>如果原指针指向的空间之后有足够的内存空间可以追加,则直接追加

    <2>如果原指针指向的空间之后没有足够的内存空间,该函数会重新找一块新的内存区域,按照指定大小重新开辟空间。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main() {
        // 向内存申请5个整型类型的空间
        int* p = (int*)calloc(5, sizeof(int));
        //判断是否开辟成功
        if (NULL == p)
        {
                // 打印错误信息
                printf("%s\n", strerror(errno));
        }        else        {
                //给5个空间进行赋值并打印
            for (int i = 0; i < 5; i++) {
                        *(p + i) = i + 1;
                }
                // 在这里20个字节的空间不能满足要求,需要进行调整
                int* np = (int*)realloc(p, 40);
                for (int i = 5; i < 10; i++) {
                        *(np + i) = i + 10;
                }
                //打印
                for (int i = 0; i < 10; i++) {
          printf("%-4d", *(np + i));
                }
                printf("\n");
        // 释放空间
        free(np);
        np=NULL;
        }
        return 0;
}

常见的动态内存错误:

1. 对NULL指针的解引用操作

int main(){
    int* p = (int*)malloc(-1);
    *p = 20;
    // 如果分配失败,P=NULL,此时就会报错
    free(p);
    p = NULL;
    return 0;
}

2. 对动态开辟空间的越界访问

int main() {
    int i = 0;
    int* p = (int*)malloc(10 * sizeof(int));
    if (NULL == p)     {
        exit(EXIT_FAILURE);
    }    else     {
        for (int i = 0; i <= 10; i++) {
            *(p + i) = i + 1;
     // 越界访问        }
    }
    free(p);
    p = NULL;
    return 0;
}

3. 使用free释放一块动态开辟内存的一部分

int main() {
    int* p = (int*)malloc(10 * sizeof(int));
    if (NULL == p)
    {
        exit(EXIT_FAILURE);
    }    else     {
        p++;
        free(p);
    // p不再指向动态内存的起始地址
        p = NULL;
    }
    return 1;
}  

4. 对非动态开辟的空间使用free函数

int main() {
    int  a = 10;
    int* p = &a;
    free(p);
    // p不是动态开辟的空间
    p = NULL;
    return 0;
}

5. 对同一块动态内存多次释放

 int main() {
    int* p = (int*)malloc(20);
    if (NULL == p) {
        exit(EXIT_FAILURE);
    }
    free(p);
    free(p);
    //重复释放
    p = NULL;
    return 0;
}
    // 如何避免重复释放
int main() {
    int* p = (int*)malloc(20);
    if (NULL == p) {
        exit(EXIT_FAILURE);
    }
    free(p);
    p = NULL;
    // 释放完成后,将指针置为NULL
    free(p); // free(NULL)时,此函数啥功能都不做
    return 0;
}

6. 动态开辟的内存忘记释放(内存泄露)

int main() {
    while (1) {
        malloc(10);
    }
    return 1;
}

     

  • 6
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值