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

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

一、相关的库函数

1、malloc 函数

函数的原型:

1
void *malloc(unsigned int size)

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

例如:

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

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

例如:

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

2、free 函数

函数的原型:

1
void free(void *p);

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

例如:

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

示例(book107.c)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
/*
* 程序名: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);
}

运行效果

在这里插入图片描述

二、内存被耗尽

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

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

三、野指针

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

1、指针变量未初始化

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

1
int *pi=0;

1
2
int i;
int *pi=&i;

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

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

1
2
free(pi);
pi=0;

四、应用经验

1、数组申明的改进

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

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

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

1
char *str=malloc(101);

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

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

2、链表

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

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

3、我的建议

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

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

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

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

五、课后作业

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

六、版权声明

C语言技术网原创文章,转载请说明文章的来源、作者和原文的链接。
来源:C语言技术网(www.freecplus.net
作者:码农有道