【C补充】动态内存分配

20 篇文章 1 订阅

使用动态内存分配创建数组,称为动态数组,便于存储未知长度的数据。
动态数组和变长数组不同,变长数组是指数组长度由变量控制的数组。

malloc —— 分配内存块,但不进行初始化
calloc —— 分配内存块(指定单元大小和个数),并将内存块清零
realloc —— 调整先前分配的内存块的大小

  • malloc 函数最常用,不需要内存清零,更高效。

  • 动态内存分配函数所在头文件为<stdlib.h>


0、空指针

当找不到满足需要的足够大的内存块时,函数会返回空指针。

空指针(NULL pointer)是不指向任何地方的指针,在把函数的返回值存储到指针变量之后,需要检验指针变量是否为空指针
(试图通过空指针访问内存是未定义行为,可能引起程序崩溃或其他不可预测的问题)

char *p;
if( ( p = (char*)malloc(100000) ) == NULL ){
	printf("Allocation failed!\n");
}
else{
	...
}
  • 名为 NULL 的宏在<locale.h>、<stddef.h>、<stdio.h>、<stdlib.h>、<string.h>、<wchar.h>(C99) 中都有定义

C语言中,空指针为假,所有非空指针都为真,如下:

//等价
if(p == NULL) ...
if(!p) ...

//等价
if(p != NULL) ...
if(p) ...

1、malloc函数

malloc —— memory allocation 内存分配

1.1 函数原型

void * malloc(size_t size);

1.2 功能

  • 从内存中临时分配一块内存出来,每个单元为 size 个字节,长度不定;
  • 分配的内存区域不会被初始化
  • 返回 void 型指针,指向所分配的内存的首地址。
  • 无内存可供分配时,返回NULL。

1.3 调用方法

int* p = (int*)malloc(sizeof(int));	
char* ch = (char*)malloc(sizeof(char));

1.4 注意事项

  • 调用前需包含函数所在头文件,#include <stdlib.h>
  • 因为是临时分配的内存空间,使用完之后需要释放free(p);,或重新分配realloc
  • freerealloc函数的参数必须是最开始malloc函数分配的内存区域的原始首地址。
  • 当需要为字符串分配内存空间时,不能忽略最后的空字符。

2、calloc函数

calloc —— contiguous allocation 连续分配

2.1 函数原型

void * calloc(size_t n,size_t size);

2.2 功能

  • 从内存中临时分配一块内存出来,每个单元为 size 个字节,长度为 n 。
  • 分配的内存区域的所有位初始化为0
  • 返回void型指针,指向所分配的内存的首地址。
  • 无内存可供分配时,返回NULL。

2.3 调用方法

int* p = (int*)calloc(n, sizeof(int));	
char* ch = (char*)calloc(n, sizeof(char));

2.4 注意事项

  • 调用前需包含函数所在头文件,#include <stdlib.h>
  • 因为是临时分配的内存空间,使用完之后需要释放free(p);,或重新分配realloc
  • freerealloc函数的参数必须是最开始calloc函数分配的内存区域的原始首地址。

3、realloc函数

realloc —— re - allocation 重分配,再分配

3.1 函数原型

void * realloc(void * p,size_t new_size);

3.2 功能

  • 使用前必须存在已经被临时分配的内存区域(malloccallocrealloc),再将临时分配的这块内存进行重新分配,内存总长度更改为 new_size 个字节。
  • 返回void型指针,指向重分配的内存的首地址,重分配之后内存区域可能会改变,函数可能将内存块移动到其他地方,因此返回的地址与传入的地址不一定相同。因此,一旦 realloc 函数返回,必须将指向原内存块的所有指针进行更新。

3.3 调用方法

int* p = (int*)malloc(sizeof(int));	
int n = 2;
int* new = (int*)realloc(p, n*sizeof(int));

调用举例:

#include <stdio.h>      /* printf, scanf, puts */
#include <stdlib.h>     /* realloc, free, exit, NULL */

int main ()
{
  int input,n;
  int count = 0;
  int* numbers = NULL;
  int* more_numbers = NULL;

  do {
     printf ("Enter an integer value (0 to end): ");
     scanf ("%d", &input);
     count++;

     more_numbers = (int*) realloc (numbers, count * sizeof(int));

     if (more_numbers!=NULL) {
       numbers=more_numbers;
       numbers[count-1]=input;
     }
     else {
       free (numbers);
       puts ("Error (re)allocating memory");
       exit (1);
     }
  } while (input!=0);

  printf ("Numbers entered: ");
  for (n=0;n<count;n++) printf ("%d ",numbers[n]);
  free (numbers);

  return 0;
}

3.4 注意事项

  • 调用前需包含函数所在头文件,#include <stdlib.h>
  • 因为是临时分配的内存空间,使用完之后需要释放free(p);
  • free函数的参数必须是最开始realloc函数分配的内存区域的原始首地址。

4、释放内存空间

4.1 free函数

动态分配的内存块都来自于“堆”, 分配的区域使用结束之后,必须手动释放原分配的内存空间,否则会丢失内存块的记录,且浪费空间。

p = malloc(...);
q = malloc(...);
p = q; 					//错误做法,p原来指向的内存区域丢失,无法访问,也无法再次被分配,成为垃圾区域

p = malloc(...);
q = malloc(...);
free(p);
p = q; 					//正确做法
  • free函数的参数必须为原来动态分配的内存地址,或空指针(无效调用,但无害)。否则将导致未定义行为。

4.2 悬空指针

某指针指向的内存区域被释放之后,该指针成为“悬空指针”,若此时试图修改该指针指向的内存区域将导致未定义行为,属于严重的错误。

char* p = (char*)malloc(4);
...
free(p);
...
strcpy(p, "abc");			//严重错误
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值