📜  C语言中的静态和动态内存分配

📅  最后修改于: 2021-05-25 21:36:23             🧑  作者: Mango

内存分为称为字节的较小的可寻址单元。假设这些是小盒子,以字节单位。每个字节都有自己的地址,如下表所示:例如0、1、2、3、4、5、6等。

记忆

程序如何使用内存?

内存分为三个部分。

  • 堆内存它是主内存的一部分。如果您不使用它,则需要使用它时,它是无组织的,并被视为资源。不能在指针的帮助下直接使用堆内存。
  • 堆栈存储器它存储由函数创建的临时变量。在堆栈中,在运行时声明,存储和初始化变量。它遵循“先进先出”方法,这意味着将在不使用任何元素的情况下将最后存储的任何元素都将首先删除。
  • 代码部分每当执行程序时,它将被带入主存储器。该程序将存储在代码部分下。根据程序,它将决定使用堆栈段还是堆段。

下面的图像说明了程序如何使用内存:

程序如何使用内存

静态内存分配

在静态内存分配中,无论程序何时执行,它都会确定程序将要占用的大小,并且无法进行进一步更改。因此,必须先知道确切的内存要求。内存的分配和释放将由编译器自动完成。如果在编译时(或运行时)之前完成所有操作,则称为静态内存分配。

主要特征:

  • 分配和取消分配由编译器完成。
  • 它使用数据结构堆栈进行静态内存分配。
  • 变量被永久分配。
  • 没有可重用性。
  • 执行比动态内存分配快。
  • 内存是在运行时分配的。
  • 它的效率较低。

例如:

C++
// C++ program to illustrate the
// concept of memory allocation
#include 
using namespace std;
  
// Driver Code
void main()
{
    int a; // 2 bytes
    long b; // 4 bytes
}


C
// C program to implement
// static memory allocation
#include 
#include 
  
// Driver code
int main()
{
    int size;
    printf("Enter limit of the text: \n");
    scanf("%d", &size);
    char str[size];
    printf("Enter some text: \n");
    scanf(" ");
    gets(str);
    printf("Inputted text is: %s\n", str);
    return 0;
}


C
// C program to illustrate the concept
// of memory allocation
#include 
using namespace std;
  
// Driver Code
void main()
{
    int* p; // 2 bytes
    P = (int*)malloc(5 * sizeof(int));
}


C
// C program to illustrate the above
// concepts of memory allocation
#include 
#include 
  
// Driver Code
int main()
{
    int size, resize;
    char* str = NULL;
    printf("Enter limit of the "
           "text: \n");
    scanf("%d", &size);
  
    str = (char*)malloc(size * sizeof(char));
  
    // If str is not NULL
    if (str != NULL) {
        printf("Enter some text: \n");
        scanf(" ");
        gets(str);
        printf("Inputted text by allocating"
               "memory using malloc() is: "
               "%s\n",
               str);
    }
  
    // Free the memory
    free(str);
    str = (char*)calloc(50, sizeof(char));
  
    // If str is not NULL
    if (str != NULL) {
        printf("Enter some text: \n");
        scanf(" ");
        gets(str);
        printf("Inputted text by allocating "
               "memory using calloc() is: "
               "%s\n",
               str);
    }
  
    printf("Enter the new size: \n");
    scanf("%d", &resize);
    str = (char*)realloc(str, resize * sizeof(char));
  
    printf("Memory is successfully "
           "reallocated by using "
           "realloc() \n");
  
    // If str is not NULL
    if (str != NULL) {
        printf("Enter some text: \n");
        scanf(" ");
        gets(str);
        printf("Inputted text by reallocating"
               " memory using realloc()is: "
               "%s\n",
               str);
    }
  
    // Free the memory
    free(str);
    str = NULL;
  
    return 0;
}


解释:

  • 上面的代码声明了2个变量。这里的假设是int占用2个字节long占用4个字节的内存。变量占用多少内存还是取决于编译器。
  • 这些变量将存储在堆栈部分中。对于程序中的每个函数,它将占用堆栈部分的一部分,这被称为激活记录(或)堆栈帧,并且在不使用时将由编译器删除。
  • 下图说明了这一点:

静态内存分配

下面是用于说明静态内存分配的C程序:

C

// C program to implement
// static memory allocation
#include 
#include 
  
// Driver code
int main()
{
    int size;
    printf("Enter limit of the text: \n");
    scanf("%d", &size);
    char str[size];
    printf("Enter some text: \n");
    scanf(" ");
    gets(str);
    printf("Inputted text is: %s\n", str);
    return 0;
}

输入:

输出#1

输出:

输出#2

好处:

  • 使用简单。
  • 分配和取消分配由编译器完成。
  • 高效的执行时间。
  • 它使用堆栈数据结构。

缺点:

  • 内存浪费问题。
  • 必须知道确切的内存要求。
  • 初始化后无法重新调整内存大小。

动态内存分配

在动态内存分配中,大小的初始化和分配是由程序员完成的。它通过指向我们称为堆的区域中新分配的内存空间的指针进行管理和服务。堆内存是无组织的,如果不释放就需要使用它,则将其视为资源。在运行时或执行时完成所有操作时,称为动态内存分配。

主要特征:

  • 在运行时动态分配
  • 如果需要,我们还可以重新分配内存大小。
  • 动态分配在运行时完成。
  • 没有内存浪费

stdlib.h标头中有一些可用的功能,这些功能将有助于动态分配内存。

  • malloc() 在运行时分配内存的最简单函数称为malloc()。由于自变量返回了返回的地址的第一个字节的地址,因此需要指定需要分配的内存字节数,因为返回的地址是唯一的放置指针的位置。

句法:

上面malloc()的参数清楚地表明,应提供足够的字节来容纳int类型的值的数量。还要注意强制转换(int *),它将函数返回的地址转换为指向int的类型指针。 malloc()函数返回一个值为NULL的指针。

  • calloc() calloc()函数相对于malloc()具有许多优点。它将内存分配为给定大小的多个元素。它初始化分配的内存,以便所有字节均为零。 calloc()函数需要两个参数值:
    • 需要空间的数据项的数量。
    • 每个数据项的大小。

这与使用malloc()非常相似,但是最大的好处是您知道内存区域将被初始化为零。

句法:

  • realloc() realloc()函数使您可以重用或扩展以前使用malloc()或calloc()分配的内存。包含一个地址的指针,该地址先前是通过调用malloc(),calloc()返回的。需要分配的新内存的大小(以字节为单位)。它分配由第二个自变量指定的内存,并将由作为第一个自变量传递的指针引用的先前分配的内存的内容传输到新分配的内存。

句法:

  • free() 动态分配内存时,应在不再需要内存时将其释放。在程序结束时,分配在堆上的内存将自动释放,但最好还是在完成后显式释放内存,即使它只是在退出程序之前也是如此。发生内存泄漏内存是动态分配的,并且对它的引用未保留,因此无法释放内存。

句法:

例如:

C

// C program to illustrate the concept
// of memory allocation
#include 
using namespace std;
  
// Driver Code
void main()
{
    int* p; // 2 bytes
    P = (int*)malloc(5 * sizeof(int));
}

例子:

  • 在上面的代码中,声明了一个指针p。假定指针p将占用2个字节的内存,并且它再次取决于编译器。
  • 该指针将存储在堆栈部分中,并将指向在堆中分配的第一个索引的数组地址。堆内存不能直接使用,但是可以在指针的帮助下进行访问。

自由

  • 当不使用该程序时,应释放内存。否则,将导致内存泄漏。

内存泄漏

  • 取消分配堆中分配的内存后。下图显示了释放后的主内存。

取消分配堆内存

下面是用于说明动态内存分配的C程序:

C

// C program to illustrate the above
// concepts of memory allocation
#include 
#include 
  
// Driver Code
int main()
{
    int size, resize;
    char* str = NULL;
    printf("Enter limit of the "
           "text: \n");
    scanf("%d", &size);
  
    str = (char*)malloc(size * sizeof(char));
  
    // If str is not NULL
    if (str != NULL) {
        printf("Enter some text: \n");
        scanf(" ");
        gets(str);
        printf("Inputted text by allocating"
               "memory using malloc() is: "
               "%s\n",
               str);
    }
  
    // Free the memory
    free(str);
    str = (char*)calloc(50, sizeof(char));
  
    // If str is not NULL
    if (str != NULL) {
        printf("Enter some text: \n");
        scanf(" ");
        gets(str);
        printf("Inputted text by allocating "
               "memory using calloc() is: "
               "%s\n",
               str);
    }
  
    printf("Enter the new size: \n");
    scanf("%d", &resize);
    str = (char*)realloc(str, resize * sizeof(char));
  
    printf("Memory is successfully "
           "reallocated by using "
           "realloc() \n");
  
    // If str is not NULL
    if (str != NULL) {
        printf("Enter some text: \n");
        scanf(" ");
        gets(str);
        printf("Inputted text by reallocating"
               " memory using realloc()is: "
               "%s\n",
               str);
    }
  
    // Free the memory
    free(str);
    str = NULL;
  
    return 0;
}

输入:

输出#1

输出:

输出#2

好处:

  • 动态分配在运行时完成。
  • 我们可以在需要时分配(创建)其他存储。
  • 只要我们完成了对内存的处理,就可以释放内存(释放/删除)动态空间。
  • 因此,一个人总是可以精确地拥有所需的空间量-不多也不少。
  • 如果需要,可以重新分配内存大小。

缺点:

  • 由于在运行时分配内存,因此需要更多时间。
  • 完成后,用户需要释放内存。这很重要,因为它更有可能变成难以发现的错误。
想要从精选的最佳视频中学习和练习问题,请查看《基础知识到高级C的C基础课程》。