C语言基础知识——动态内存分配

提示:本文是对C语言基础知识:动态内存分配部分的回顾总结。


用途

由于数组的元素存储于内存中连续的位置上,当一个数组被声明时,它所需的内存在编译时就已经被分配好了。

使用动态内存分配可以 在程序运行时数组 分配内存。


malloc 和 free

C函数库提供了两个函数:
mallocfree :分别用于执行动态内存分配和释放。这些函数维护一个可用的内存池。

malloc 函数从内存池中提取一块合适的内存,并向该程序返回一个指向这块内存的指针。
提示:被分配的这块内存此时并没有以任何方式进行初始化。

free 函数把这块内存归还给内存池,以供以后之需。

函数都在 stdlib.h 头文件中声明,原型如下:

void *malloc( size_t size );
void free ( void *pointer );

malloc的参数就是 需要分配的内存字节(字符)数。
malloc所分配的是一块连续的内存。

malloc函数的返回值:
1、如果内存池中的可用内存可以满足这个需求,malloc就返回一个指向被分配的内存块起始位置的指针。
2、如果内存池是空的或可用内存不足,malloc函数就会向操作系统请求一块新的内存,并在其上执行分配任务。
3、如果操作系统无法向malloc提供更多的内存,则函数返回一个 NULL 指针。
注意:因此对于每个从 malloc 返回的指针都要进行检查,确保它并非 NULL 。

标准表示一个 void * 类型的指针可以转换为其他任何类型的指针。

malloc函数满足边界对齐要求。


calloc 和 realloc

另外的两个内存分配的函数, callocrealloc

void *calloc( size_t num_elements, size_t element_size );
void realloc( void *ptr, size_t new_size );

calloc 和 malloc 的主要区别是前者在返回指向内存的指针之前把它 初始化为0

calloc 的参数包括 所需元素的数量每个元素的字节数。

realloc 函数用于 修改一个原先已经分配的 内存块大小。
relloc函数修改方式:
1、如果用于扩大一个内存块,那么这块内存原先的内容依然保留,新增加的内存添加到原先内存块的后面,新内存并没有以任何方式进行初始化。
2、如果用于缩小一个内存块,该内存块尾部的部分内存便被拿掉,剩余部分的原先内容依然保留。
3、如果原先的内存块无法改变大小,realloc将分配另一块正确大小的内存,并把原先那块内存的内容复制到新块上。

补充:如果relloc函数的第 1 个参数是 NULL,那么它的行为和 malloc 一摸一样。


使用动态分配的内存

如下例:

/*
** 用malloc分配一块内存给指针 pi
*/
int *pi;
...
pi = malloc( 25 * sizeof( int ) );	//分配足够存储25个整数的内存
if( pi == NULL )	//检查值是否是一个指针
{
	printf( "Out of memory!\n" );
	exit( 1 );
}

/*
** 用间接访问使用内存
*/
int *pi2, i;
...
pi2 = pi;
for( i = 0; i < 25; i++ )
	*pi2++ = 0;		//把新分配的数组的每个元素都初始化为0

/*
** 用下标使用
*/
int i;
...
for( i = 0; i < 25; i++ )
	pi[i] = 0;

常见错误

分配内存一旦在使用完毕后不释放将引起 内存泄漏(memory leak)

在那些所有执行程序共享一个通用内存池的操作系统中,内存泄漏将一点点地榨干可用内存,最终使其一无所有。只能重启系统。

其他操作系统能够记住每个程序当前拥有的内存段,这样当一个程序终止时,所有分配给它但是未被释放的内存都归还给内存池。


实例

动态内存分配一个常见的用途就是为那些长度在运行时才知道的数组分配内存空间。

如下程序:读取和排序一列整数值

/*
** 读取、排序和打印一列整型值。
*/
#include<stdlib.h>
#include<stdio.h>

/*
** 该函数由'qsort'调用,用于比较整型值。
*/
int compare_integers( void const *a, void const *b )
{
	register int const *pa = a;
	register int const *pb = b;
	
	return *pa > *pb ? 1 : *pa < *pb ? -1 : 0;
}

int main( void )
{
	int *array;
	int n_values;
	int i;
	/*
	** 观察共有多少个值。
	*/
	printf( "How many values are there?" );
	if( scanf( "%d", &n_values ) != 1 || n_values <= 0 )
	{
		printf( "Illegal number of values.\n" );
		exit( EXIT_FAILURE );
	}

	/*
	** 分配内存,用于储存这些值。
	*/
	array = malloc( n_values * sizeof( int ));
	if( array == NULL )
	{
		printf( "Can't get memory for that many calues.\n" );
		exit( EXIT_FAILURE );
	}

	/*
	** 读取这些数值。
	*/
	for( i = 0; i < n_values; i+= 1 )
	{
		printf( "? " );
		if( scanf( "%d", array + i ) != 1 )
		{
			printf( "Error reading value #%d\n", i + 1 );
			free( array );
			exit( EXIT_FAILURE );
		}
	}
	/*
	** 对这些值排序。
	*/
	qsort( array, n_values, sizeof( int ), compare_integers );
	
	/*
	** 打印这些值。
	*/
	for( i = 0; i < n_values; i += 1 )
		printf( "%d\n", array[i] );
	
	/*
	** 释放内存并退出。
	*/
	free( array );
	return EXIT_SUCCESS;
}

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值