C语言系列(16)——动态内存分配
一、堆、栈
内存存储区域大致可分为:代码区、常量区、静态区、栈区、堆区。
栈区:
- 存取速度比堆要快,仅次于寄存器。
- 存在栈中的数据大小与生存期必须是确定的,缺乏灵活性。
- 自动申请和回收地址。
如:
int a = 10; // a变量的内存空间分配在栈区
堆区:
- 存取速度相比栈较慢。
- 可以动态分配内存大小,灵活性高。
- 手动申请和回收地址。
因为栈的空间有限,不能够存储大量数据,否则会造成栈溢出
;所以在开发中大部分数据存储在堆中。
那如何在堆区分配内存空间呢?
二、操作堆区地址
- 申请堆区地址:
void* malloc(int num);
在堆区分配一块指定大小的内存空间,用来存放数据。这块内存空间在函数执行完成后不会被初始化
,它们的值是未知的
;void * 类型可以通过类型转换强制转换
为任何其它类型的数据类型。
- 申请存储基础类型的地址:
malloc(1);//向堆空间,申请了1字节大小的空间。
申请了一个空间,但是因为没有变量名,无法对其进行操作,所以需要用到指针存储该空间的地址。
//在堆区申请了一个整型类型(4个字节)的空间,用指针p存储了其地址并指向该地址
int *p = (int*)malloc(sizeof(int));
*p = 1;
printf("%p, %d\n", p, *p);//打印p存储的堆区地址,和地址中存储的值1
double* f = (double*)malloc(sizeof(double));//申请double类型存储地址
*f = 3.1415;
printf("%p, %f\n", f, *f);
char* c = (char*)malloc(sizeof(char));//申请char类型存储地址
*c = 'A';
printf("%p, %c\n", c, *c);
以上分别打印:地址打印不一致属正常
0x103906530, 1
0x103906950, 3.141500
0x103906340, A
- 申请数组类型存储地址:
int size = 10, i = 0;
// 申请了10个4字节大小的空间(40字节)
int* pArr = (int*)malloc(sizeof(int) * size);
//请输入10个数
printf("请输入10个数:");
for (i = 0; i < size; i++)
{
scanf("%d", pArr + i);
}
for ( i = 0; i < size; i++)
{
printf("%d ", *(pArr + i));
}
交互输出:
请输入10个数:1 2 3 4 5 6 7 8 9 10
1 2 3 4 5 6 7 8 9 10
- 申请字符空间:
char* p = NULL;
int size = 100;
p = (char*)malloc(sizeof(char)*size);
printf("请输入一段字符串:");
gets(p);//输入
puts(p);//输出 输入的字符
交互输出:
请输入一段字符串:hello,world
hello,world
三、释放堆区地址
释放堆区地址:
void free(void *p);
该函数释放指针所指向的内存块。
int size = 100;
p = (char*)malloc(sizeof(char)*size);
//p操作使用结束后,要释放堆空间
free(p);//释放之后,p还是指向了该地址,但是如果再修改该地址的值,就不合法了。
gets_s(p, sizeof(char)*size);//不合法,可能引起内存崩溃
p = NULL;//free之后,将p 赋值为 NULL,若未赋值为NULL,称其为野指针。
注意:
1. 一个申请(malloc等),必定要对应一个释放free,谁申请谁free;
2. 若没释放free申请的空间,则称为内容泄露;
3. 释放后的指针要赋值为空,未赋空,称为野指针;
4. 操作野指针是不合法的,会引起程序异常。
四、其他方式:申请堆区地址
- calloc
void *calloc(int num, int size);
在内存中动态地分配 num 个长度为 size 的连续空间,并将每一个字节都初始化为 0。
int num = 100;
char *p = (char*)calloc(num, sizeof(char));
puts(p);//不再打印乱码。
free(p);//使用完,释放空间。
p = NULL;//置空,养成好习惯。
- realloc
void *realloc(void *address, int newsize);
该函数重新分配内存,把内存扩展到 newsize。
int num = 100;
int newNum = 1000;
char *p = (char*)calloc(num, sizeof(char));
//重新分配内存空间,如果p为NULL,则realloc功能与malloc一致
p = (char *)realloc(p, sizeof(char)*newNum);
free(p);
练习:
用动态内存分配实现:
1、输入一段字符串,如果字符串中出现了”123”则替换为”abc”。
2、根据用户输入的行数,实现杨辉三角。
3、实现动态(用户输入行和列)矩阵转置。
4、输入一个字符串,内有数字、字母、其他字符,将其中的数字作为整数输出,
如:123a456b85,62.895; 输出整数123 456 85 62 895