首页 > 系统相关 >c的内存管理

c的内存管理

时间:2023-08-03 11:15:14浏览次数:42  
标签:description 管理 函数 char 分配内存 内存 指针

C的内存管理

C 语言为内存的分配和管理提供了几个函数。这些函数可以在<stdlib.h> 头文件中找到。

在 C 语言中,内存是通过指针变量来管理的。指针是一个变量,它存储了一个内存地址,这个内存地址可以指向任何数据类型的变量,包括整数、浮点数、字符和数组等。C 语言提供了一些函数和运算符,使得程序员可以对内存进行操作,包括分配、释放、移动和复制等。

序号和函数描述
1 void *calloc(int num, int size); 在内存中动态地分配 num 个长度为 size 的连续空间,并将每一个字节都初始化为 0。所以它的结果是分配了 num*size 个字节长度的内存空间,并且每个字节的值都是 0。
2 void *malloc(int num); 在堆区分配一块指定大小的内存空间,用来存放数据。这块内存空间在函数执行完成后不会被初始化,它们的值是未知的。
3 void free(void *address); 该函数释放 address 所指向的内存块,释放的是动态分配的内存空间。
4 void *realloc(void *address, int newsize); 该函数重新分配内存,把内存扩展到 newsize。

void * 类型表示未确定类型的指针。C、C++ 规定 void * 类型可以通过类型转换强制转换为任何其它类型的指针。

动态分配内存

编程时,如果您预先知道数组的大小,那么定义数组时就比较容易。例如,一个存储人名的数组,它最多容纳 100 个字符,所以您可以定义数组,如下所示:

char name[100];

如果您预先不知道需要存储的文本长度,例如您想存储有关一个主题的详细描述。在这里,我们需要定义一个指针,该指针指向未定义所需内存大小的字符,后续再根据需求来分配内存,如下所示:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
int main()
{
   char name[100];
   char *description;
 
   strcpy(name, "Zara Ali");
 
   /* 动态分配内存 */
   description = (char *)malloc( 200 * sizeof(char) );
   if( description == NULL )
   {
      fprintf(stderr, "Error - unable to allocate required memory\n");
   }
   else
   {
      strcpy( description, "Zara ali a DPS student in class 10th");
   }
   printf("Name = %s\n", name );
   printf("Description: %s\n", description );
}

当上面的代码被编译和执行时,它会产生下列结果:

Name = Zara Ali
Description: Zara ali a DPS student in class 10th

上面的程序也可以使用 calloc() 来编写,只需要把 malloc 替换为 calloc 即可,如下所示:

calloc(200, sizeof(char));

当动态分配内存时,您有完全控制权,可以传递任何大小的值。而那些预先定义了大小的数组,一旦定义则无法改变大小。

调整内存大小和释放内存

当程序退出时,操作系统会自动释放所有分配给程序的内存,但是,建议您在不需要内存时,都应该调用函数 free() 来释放内存,尤其是使用了指针之后,避免野指针的出现。

或者,您可以通过调用函数 realloc() 来增加或减少已分配的内存块的大小。让我们使用 realloc() 和 free() 函数,再次查看上面的实例:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
int main()
{
   char name[100];
   char *description;
 
   strcpy(name, "Zara Ali");
 
   /* 动态分配内存 */
   description = (char *)malloc( 30 * sizeof(char) );
   if( description == NULL )
   {
      fprintf(stderr, "Error - unable to allocate required memory\n");
   }
   else
   {
      strcpy( description, "Zara ali a DPS student.");
   }
   /* 假设您想要存储更大的描述信息 */
   description = (char *) realloc( description, 100 * sizeof(char) );
   if( description == NULL )
   {
      fprintf(stderr, "Error - unable to allocate required memory\n");
   }
   else
   {
      strcat( description, "She is in class 10th");
   }
   
   printf("Name = %s\n", name );
   printf("Description: %s\n", description );
 
   /* 使用 free() 函数释放内存 */
   free(description);
}

当上面的代码被编译和执行时,它会产生下列结果:

Name = Zara Ali
Description: Zara ali a DPS student.She is in class 10th

您可以尝试一下不重新分配额外的内存,strcat() 函数会生成一个错误,因为存储 description 时可用的内存不足。

C 语言中常用的内存管理函数和运算符

  • malloc() 函数:用于动态分配内存。它接受一个参数,即需要分配的内存大小(以字节为单位),并返回一个指向分配内存的指针。

  • free() 函数:用于释放先前分配的内存。它接受一个指向要释放内存的指针作为参数,并将该内存标记为未使用状态。

  • calloc() 函数:用于动态分配内存,并将其初始化为零。它接受两个参数,即需要分配的内存块数和每个内存块的大小(以字节为单位),并返回一个指向分配内存的指针。

  • realloc() 函数:用于重新分配内存。它接受两个参数,即一个先前分配的指针和一个新的内存大小,然后尝试重新调整先前分配的内存块的大小。如果调整成功,它将返回一个指向重新分配内存的指针,否则返回一个空指针。

  • sizeof 运算符:用于获取数据类型或变量的大小(以字节为单位)。

  • 指针运算符:用于获取指针所指向的内存地址或变量的值。

  • & 运算符:用于获取变量的内存地址。

  • 运算符:用于获取指针所指向的变量的值。

  • -> 运算符:用于指针访问结构体成员,语法为 pointer->member,等价于 (*pointer).member。

  • memcpy() 函数:用于从源内存区域复制数据到目标内存区域。它接受三个参数,即目标内存区域的指针、源内存区域的指针和要复制的数据大小(以字节为单位)。

  • memmove() 函数:类似于 memcpy() 函数,但它可以处理重叠的内存区域。它接受三个参数,即目标内存区域的指针、源内存区域的指针和要复制的数据大小(以字节为单位)。

小结

在学习C语言的时候,一定要注意内存管理的方式。通过指针的使用来管理内存,指针的偏移来完成对内存的操作。同时,也要搞清楚,哪些是系统层面的操作,哪些是C或者其他语言
层面的操作,就好比对于内存管理。C只有通过指针对其进行内存管理,但是系统层面会对内存进行用户态,内核态,堆,栈,数据区的划分,这些属于操作系统层面对于内存的描述,
需要分清楚。所以,C弄懂了指针操作,那也要去了解清楚,面向的应用的操作管理。不要搞混了。

标签:description,管理,函数,char,分配内存,内存,指针
From: https://www.cnblogs.com/7xiaomao/p/17602736.html

相关文章

  • 记一次 .NET某培训学校系统 内存碎片化分析
    一:背景1.讲故事前些天有位朋友微信上找到我,说他们学校的Web系统内存一直下不去,让我看下到底是怎么回事,老规矩让朋友生成一个dump文件丢给我,看一下便知。二:WinDbg分析1.托管还是非托管要想看托管还是非托管,可以用!address-summary观察下内存段。0:000>!address-summ......
  • 造价管理-6-1-
    主要集中在四个报表:《投资现金流量表》、《资本金现金流量表》、《投资各方现金流量表》、《财务计划现金流量表》《投资现金流量表》和《资本金现金流量表》的区别《投资现金流量表》《资本金现金流量表》资本金现金流量表和全投资现金流量表的差异在于是否使......
  • Java内部类持有外部类会导致内存泄露
    packageorg.example.a;importjava.util.ArrayList;importjava.util.List;classOuter{privateint[]data;publicOuter(intsize){this.data=newint[size];}staticclassInner{}InnercreateInner(){ret......
  • 3.使用智能指针管理内存资源,RAII是怎么回事?
    3.使用智能指针管理内存资源,RAII是怎么回事?什么是RAII?RAII是ResourceAcquisitionIsInitialization(wiki上面翻译成“资源获取就是初始化”)的简称,是C++语言的一种管理资源、避免泄漏的惯用法。利用的就是C++构造的对象最终会被销毁的原则。RAII的做法是使用一个对象,在其构造时......
  • 2.简要说明C++的内存分区
    2.简要说明C++的内存分区1.一个由C/C++编译的程序占用的内存分为以下几个部分:C++中的内存分区,分别是堆、栈、自由存储区、全局/静态存储区、常量存储区和代码区。如下图所示栈:在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自动被释放。栈......
  • 3.什么是内存池,如何实现
    3.什么是内存池,如何实现内存池(MemoryPool)是一种内存分配方式。通常我们习惯直接使用new、malloc等申请内存,这样做的缺点在于:由于所申请内存块的大小不定,当频繁使用时会造成大量的内存碎片并进而降低性能。内存池则是在真正使用内存之前,先申请分配一定数量的、大小相等(一般情......
  • 4.可以说一下你了解的C++得内存管理吗?
    4.可以说一下你了解的C++得内存管理吗?1.一个由c/C++编译的程序占用的内存分为以下几个部分:C++中的内存分区,分别是堆、栈、自由存储区、全局/静态存储区、常量存储区和代码区。如下图所示栈:在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元自......
  • 5.C++中类的数据成员和成员函数内存分布情况
    5.C++中类的数据成员和成员函数内存分布情况非静态成员的数据类型大小之和。编译器加入的额外成员变量(如指向虚函数表的指针)。为了边缘对齐优化加入的padding。空类(无非静态数据成员)的对象的size为1,当作为基类时,size为0。C++类是由结构体发展得来的,所以他们的成员变......
  • 《深度管理》读书笔记1
    书籍信息参考:https://book.douban.com/subject/30258984/ 一 “赢得漂亮”意味着你能长时间地维持优秀的业绩,因为你拒绝屈服于严酷而招致压力的捷径,暂时将他人当成业绩的牺牲品。你需要让精力充沛、鼓足干劲的人们共同工作。你的策略的强大取决于你的团队在第一线的执行力,要......
  • 导入分类管理功能代码
          ......