首页 > 系统相关 >内存(动态开辟)———C语言

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

时间:2024-08-19 17:57:44浏览次数:16  
标签:10 malloc include int free C语言 内存 NULL 开辟

内存管理:

 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;
}

     

标签:10,malloc,include,int,free,C语言,内存,NULL,开辟
From: https://blog.csdn.net/2301_79109608/article/details/141217239

相关文章

  • 排序算法 基数排序 RadixSort --C语言实现
    基数排序基数排序(radixsort)属于“分配式排序”(distributionsort),又称“桶子法”(bucketsort)或binsort,顾名思义,它是透过键值的部份资讯,将要排序的元素分配至某些“桶”中,藉以达到排序的作用,基数排序法是属于稳定性的排序,其时间复杂度为O(nlog(r)m),其中r为所采取的基数,而m为堆数......
  • C语言--循环链表
    循环链表实现循环链表的最后一个节点指向头节点,形成一个环。#include<stdio.h>#include<stdlib.h>typedefstructNode{  intdata;  structNode*next;//指向下一个节点}Node;typedefstruct{  Node*head;//头指针}CircularLinkedList;......
  • idea低内存报错
    问题描述:解决办法:各种解决办法通过大模型搜索已经给出。由于各种原因,我们一般采用方法一修改内存配置解决。下边带大家手搓一遍:①通过设置菜单调整内存大小②编辑配置文件......
  • 初识C语言——练习
    1.求两个数的较大值。   例:输入10、20,输出较大值20。//求两个数的较大值#include<stdio.h>intmain(){ inta=10; intb=20; intc=a>b?a:b; printf("%d\n",c); return0;}2.一个数是否能被5整除问题。  例:输入10,输出yes。//一个数是......
  • C语言典型例题45
    《C程序设计教程(第四版)——谭浩强》习题3.5给一个不多于5位的正整数,要求:     1.求出它是几位数;     2.分别输出每一位数字;     3.按逆序输出各位数字,例如:原数为321,输出为123代码://《C程序设计教程(第四版)——谭浩强》//习题3.5给一......
  • C语言学习--排序和查找
    提示:排序和查找算法是算法领域中最基本的概念之一,它们在数据组织、优化查询效率等方面发挥着至关重要的作用。目录前言12.1排序算法的介绍12.2冒泡排序12.2.1基本介绍12.2.2冒泡排序应用实例12.2.3分析冒泡的过程+代码12.3查找12.3.1介绍12.3.2案例演示12......
  • C语言学习--断点调试
    提示:断点调试作为一种重要的调试技术,能够帮助程序员逐行分析代码的执行过程,查找潜在的Bug,并最终解决问题。目录前言13.1一个实际需求13.2断点调试介绍13.3断点调试的快捷键13.4断点调试应用案例113.5断点调试应用案例213.6断点调试应用案例313.7断点调试......
  • 嵌入式初学-C语言-二五
    构造类型   数据类型分类:基本类型:整数型短整型:short(2字节)整型:int(4个字节)长整型:long(8个字节)长长整型:longlong浮点型单精度:float(4个字节)双精度:double(8个字节)字符型:char(1个字节)指针类型数据类型*:int*,char*,float*等void*:任意数据类型指针空类型void......
  • c语言 小熊猫Dev cpp6.7.5版本bug
    问题描述:请看下面代码#include<stdio.h>#include<math.h>intmain(void){ intres=0; inti=2; res=pow(10,i); printf("%d",res); return0;}期望输出100,但是在pandaDevcpp6.7.5版本中会输出99在看下面的代码正确输出100#include<stdio.h>#include<ma......
  • 利用C语言求字符串长度
    在C语言中库函数中已有求字符串长度的函数strlen,我们可以自己编写一个求字符串函数my_strlen求字符串长度注意:strlen函数返回类型是size_t,是无符号整型方法1:创建临时变量#include<stdio.h>intmy_strlen(char*str){   intcount=0;   while(*str!='\0......