在C语言中,编写程序的时候不能确定内存的大小,希望程序在运行的过程中根据数据量的大小动态的分配内存。动态内存管理,就是指在程序运行过程中动态的申请和释放内存空间。

C语言允许程序动态管理内存,需要时随时开辟,不需要时随时释放。内存的动态管理是通过调用库函数来实现的,主要有malloc和free 函数。

一、相关的库函数

1、malloc 函数

函数的原型:

void *malloc(unsigned int size);

malloc的作用是向系统申请一块大小为size的连续内存空间,如果申请失败,函数返回0,如果申请成功,返回成功分配内存块的起始地址。

例如:

  malloc(100); // 申请 100 个字节的临时分配域,返回值为其第一个字节的地址

malloc的返回值的地址的基类型为 void,即不指向任何类型的数据,只提供一个地址,程序中需要定义一个指针来指向动态分配的内存地址。

例如:

  int *pi=malloc(sizeof(int));

2、free 函数

函数的原型:

void free(void *p);

free的作用是释放指针p指向的动态内存空间,p是调用malloc函数时返回的地址,free函数无返回值。

例如:

  free(pi);     // 释放指针变量pi指向的已分配的动态空间

示例(book107.c)

/*
 * 程序名:book107.c,此程序用于演示C程序动态内存管理。
 * 作者:C语言技术网(www.freecplus.net) 日期:20190525
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
 
struct st_girl  // 超女结构体
{
  char name[50];     // 姓名
  int  age;          // 年龄
};
 
int main(int argc,char *argv[])
{
  int    *pi=malloc(sizeof(int));    // 分配int类型大小的内存
  long   *pl=malloc(sizeof(long));   // 分配long类型大小的内存
  double *pd=malloc(sizeof(double)); // 分配double类型大小的内存
  char   *pc=malloc(101);            // 分配101字节的内存,可存放100个字符的字符串
  struct st_girl *pst=malloc(sizeof(struct st_girl)); // 分配struct st_girl结构体大小的内存
 
  // 以下代码是像普通指针和变量一样使用动态分配的内存
  *pi=10;     printf("*pi=%d\n",*pi);
  *pl=20;     printf("*pl=%d\n",*pl);
  *pd=10.5;   printf("*pd=%.1f\n",*pd);
  strcpy(pc,"西施"); printf("*pc=%s\n",pc);
  strcpy(pst->name,"杨玉环"); pst->age=21;
  printf("name=%s,age=%d\n",pst->name,pst->age);
 
  // 释放动态分配的内存
  free(pi); free(pl); free(pd); free(pc); free(pst);
}

运行效果

 image.png

二、内存被耗尽

使用动态分配内存技术的时候,分配出来的内存必须及时释放,否则会引起系统内存耗尽,这话说起来简单,好像很容易做到,但是在实际开发中,程序员往往是漏洞百出。

内存问题是C程序员的主要问题之一,是初学者的恶梦。

三、野指针

野指针就是无效的指针,与空指针不同,野指针无法通过简单地判断是否为 NULL避免,而只能通过养成良好的编程习惯来尽力减少。

1、内存指针变量未初始化

指针变量刚被创建时不一定会自动初始化成为空指针(与编译器有关),它的缺省值是可能随机的,它会随便乱指。所以,指针变量在创建的同时应当被初始化,要么将指针的值设置为0,要么让它指向合法的内存。

  int *pi=0;

  int i;
  int *pi=&i;

2、内存释放后之后指针未置空

调用free函数把指针所指的内存给释放掉,但指针不一定会赋值 0(也与编译器有关),如果对释放后的指针进行操作,相当于非法操作内存。释放内存后应立即将指针置为0。

  free(pi);
  pi=0;

四、应用经验

1、数组声明的改进

在C语言的早期标准中,定义数组必须用常量指明大小,不能用变量。

  char str[101];        // 可以这样
  int len=101;
  char str[len];         // 不可以这样

程序在运行的时候,如果要定义一个字符串存放100个字符,那怎么办,只能通过动态分配内存技术。

  char *str=malloc(101);

现在,定义数组可以用变量指明大小,就不必为数组动态分配内存了。

还有,C++的string是一个变长的字符串,非常好用,程序员根本不必关心内存的问题。

2、链表

链表是C语言的一个经典的数据结构,相当于一个动态的结构体数组,非常巧妙,功能强大,但操作也麻烦,在这里我就不介绍了。

在C++中,容器全完代替了链表的功能,极其好用,程序员也不必关心内存的问题。

3、我的建议

在中国,没有纯C程序员,如果他不会C++,不是他对C有多么执着,可能是不会C++。

至少十年了,我不再使用动态内存分配技术,也想不到有什么场景非得用动态内存分配技术。

哦,嵌入式开发可能是个例外,可能还有其它只能用C不能用C++的场景。

动态内存分配并不是什么高大上的技术,我是一个实用的程序员,绝不给自己挖坑,这与水平高低无关。

五、课后作业

编写示例程序,把本章节介绍的知识点全部演示一遍,用程序演示可以加深您的理解和映象。

六、版权声明

C语言技术网原创文章,转载请说明文章的来源、作者和原文的链接。

来源:C语言技术网(www.freecplus.net

作者:码农有道

如果文章有错别字,或者内容有错误,或其他的建议和意见,请您联系我们指正,非常感谢!!!

 


C语言技术网(www.freecplus.net),粤ICP备19156379号

友情链接: 猿说编程    程序分享   

点击关闭