【0005】堆与栈,四大动态内存分配函数(malloc, calloc, realloc, _recalloc),以及栈内存分配函数alloca
分类:
IT文章
•
2022-04-02 22:51:56

首先说明一下32位和64位系统下的区别:
void main001()
{
int num = 20;
int *p = #
printf("%p
", &p);
printf("%d
", sizeof(p));
system("pause");
}
/*
Name Value Type
32bit &p 0x0135f7ec{0x135f7f8{20}} int **
p 0x135f7f8{20} int *
64bit &p 0x0000007A360FF898{0x0000007a360ff874{20}} int **
p 0x0000007a360ff874{20} int *
*/
32位与64位编译器下地址的表示
/*
指针(地址)由编译器决定(64bit/32bit),高位编译器兼容地位编译器
32bit操作系统的寻址能力:(指针4byte)
0x00000000-0xFFFFFFFF 2^32=2^2*2^30 = 4G
64bit操作系统的寻址能力:(指针8byte)
0x0000000000000000-0xFFFFFFFFFFFFFFFF 16T
32bitCPU与64bitCPU的本质区别:
CPU的寻址能力
64bitCPU能进行32bit的计算和64bit计算,32bitCPU只能进行32bit的计算
指针的大小的决定因素:
编译器位数
操作系统的位数
*/
多线程中,每一个线程都有自己独立的栈;堆内存则是共享的,32bit堆内存最大为2G,64bit最大为1024G
栈 auto int num 自动回收,自动释放( 栈是由编译器来维护的,自动回收,自动释放,默认大小为1M,可以手动拓展栈的大小)
堆 void *p=malloc(1024) 手动分配,手动释放
void stack(int numA) // 函数参数属于栈
{
int numB = 10; // 局部变量属于栈
printf("%p, %p
", &numA, &numB);
numA = 1;
numB = 2;
printf("
");
}
void main003()
{
//int num[1024 * 1024];
/*
0xC00000FD: Stack overflow (parameters: 0x0000000000000001, 0x000000F6826C3000). 编译器默认的保留栈大小是1M
可以从属性页查看:Property Pages-->Configuration Properties-->Linker-->System-->Stack Reserve Size(Specifies the total stack allocation size in virtual memory.Default is 1MB. (/STACK:reserve))
可以改变Stack的默认值
*/
stack(1);
printf("
");
stack(1);
printf("
");
system("pause");
}
栈中的变量,栈大小的手动修改方法
void runstack(void *p)
{
while (1)
{
int num[1024 * 1024]; // 自动回收,自动释放
}
}
void main004()
{
// 32bit堆内存最大2G
// void *p=malloc(1024*1024);
for (int i = 0; i < 3; i++)
{
_beginthread(runstack, 0, NULL); // 多线程,每一个线程都有自己独立的栈
// 堆内存则是共享的,32bit堆内存最大为2G,64bit最大为1024G
}
system("pause");
}
在多线程中演示栈的自动生成和自动回收
void goheap(void *p)
{
while (1)
{
malloc(1024 * 1024 * 100); // 多线程,每一个线程都有自己独立的栈
// 堆内存则是共享的,32bit堆内存最大为2G,64bit最大为1024G
Sleep(1000);
}
}
void main005()
{
for (int i = 0; i < 3; i++)
{
_beginthread(goheap, 0, NULL);
}
system("pause");
}
在多线程中演示堆是为多个线程共用的
内存中的堆、栈与数据结构中的堆、栈的区别:
内存中的栈的大小是编译器确定的,由编译器生成的代码完成分配和释放(自动分配和释放),每个线程都有一个独立的栈
内存中的堆,是手动管理的(手动分配、手动释放),同一个进程中的多个线程共用一个堆
数据结构中的栈——先进后出,先进先出
数据结构中的堆——堆的本质是一个二叉树,包括二分法查找,朗格朗日差值查找,堆排序查找极值
通过动态内存分配函数在堆上开辟动态内存
栈中变量的静态内存分配,静态内存,编译的时候就确定了内存的大小,自动回收,自动释放
void main024()
{
int a[1024 * 1024 * 100]; // 栈默认大小为1M,可以手动设置为较大的栈值
system("pause");
}
栈中的静态内存分配
堆中的动态内存分配
void main022()
{
//int a[10]; // 静态内存,编译的时候就确定了内存的大小
int n;
scanf("%d", &n);
int *p = malloc(n*sizeof(int));
for (int i = 0; i < n; i++)
{
p[i] = i;
printf("%d
", p[i]);
}
system("pause");
}
malloc函数
堆内存的动态分配(malloc)与手动释放(free)
void main025() // 动态分配一维数组内存
{
// int a[N]
int N;
scanf("%d", &N);
int *p = NULL;
p = malloc(N*sizeof(int));
printf("%p
", p); // 01583BA8
for (int i = 0; i < N; i++)
{
p[i] = i;
printf("%d
", p[i]);
}
free(p); // 释放内存,只能释放一次内存,不能反复释放;分配内存之后一定要通过释放指向该分配内存的指针即释放内存,否则会导致内存泄漏
printf("%p
", p); // 01583BA8
//free(p); // 20150421.exe has triggered a breakpoint. 当再次释放时,会触发一个断点
p = NULL; // 指针被释放,赋值为空
free(p); // free释放空指针不会出错
free(p);
printf("%p
", p); // 00000000
system("pause");
}
动态分配一维数组内存
void main026() // 动态分配二维数组内存
{
// int a[3][10]
int(*p)[10] = malloc(sizeof(int) * 30);
int num = 0;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 10; j++)
{
p[i][j] = num++;
printf("%3d", *(*(p + i) + j));
}
printf("
");
}
free(p);
system("pause");
}
动态分配二维数组内存
void main028()
{
int(*p)[3][5] = malloc(sizeof(int) * 60); // 三维数组
int num = 0;
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 3; j++)
{
for (int k = 0; k < 5; k++)
{
printf("%3d", p[i][j][k] = num++);
}
printf("
");
}
printf("
");
}
free(p);
system("pause");
}
动态分配三维数组内存
动态内存分配函数的返回值
// malloc 函数的返回值
void main027()
{
//int *p = malloc(23454656577889);
//int *p = malloc(-1); // 分配失败,-1补码,malloc函数的参数值类型size_t是unsigned int
//int *p = malloc(0); // 能分配成功,但是没有实际意义
int *p = malloc(2345);
printf("%p
", p);
/*
动态内存分配函数返回值
分配成功:返回内存的首地址
分配失败:返回NULL
*/
system("pause");
}
malloc函数的返回值

void main009()
{
int *pm = malloc(100); // 分配内存(以字节为最小单位),但是不会初始化,参数为内存分配的总大小
int *pc = calloc(25, sizeof(int)); // 会按照类型大小将所有内存初始化为0,参数1:变量的个数,参数2:变量的大小
int *p = pc;
printf("%p", p);
for (int i = 0; i < 25; i++)
{
p[i] = i;
}
puts("
");
puts("
");
system("puase");
}
calloc与malloc
void main010()
{
/*
realloc(parm1,parm2);
返回值为地址:
拓展成功,后续地址拓展,返回值为这片内存的首地址
拓展不成功,重新开辟内存,把原地址的数据拷贝到新地址,返回值为新内存的首地址(原内存空间free掉了,被回收了)
*/
int *p = malloc(sizeof(int) * 10); // 有效内存区域
int *p_p = malloc(100);
for (int i = 0; i < 10; i++)
{
p[i] = i;
}
printf("%p
", p); // 0x00e749d0 {0}
int *px = realloc(p, 200);
printf("%p
", px);
for (int i = 10; i < 50; i++)
{
px[i] = i;
}
puts("
");
system("pause");
}
realloc与malloc
void main011()
{
int *p = calloc(25, sizeof(int)); // 会按照类型大小将所有内存初始化为0,参数1:变量的个数,参数2:变量的大小
printf("%p", p);
for (int i = 0; i < 25; i++)
{
p[i] = i;
}
int *px = _recalloc(p, 50, sizeof(int));
for (int i = 25; i < 50; i++)
{
px[i] = i;
}
puts("
");
system("puase");
}
calloc与_recalloc
堆上开辟连续内存
void main003()
{
int(*p)[4] = malloc(sizeof(int) * 12); // 堆上开辟内存,连续分配
int num = 0;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 4; j++)
{
printf("%3d,%p", p[i][j] = num++, &p[i][j]);
}
putchar('
');
}
/*
0,01294B30 1,01294B34 2,01294B38 3,01294B3C
4,01294B40 5,01294B44 6,01294B48 7,01294B4C
8,01294B50 9,01294B54 10,01294B58 11,01294B5C
*/
system("pause");
}
开辟连续的堆内存_二维数组
堆上开辟块状的内存
void main002()
{
int **pp = calloc(3, 4); // 堆上分配指针数组
for (int i = 0; i < 3; i++)
{
pp[i] = malloc(sizeof(int) * 4); // 每个指针分配内存,块状分配
}
int num = 0;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 4; j++)
{
printf("%3d,%p", pp[i][j] = num++, &pp[i][j]);
/*
*(*(pp+i)+j) == pp[i][j]
*(pp+i) == pp[i]
pp+i == &pp[i]
*(pp+i)+j == &(pp[i][j])
*/
}
putchar('
');
}
/*
0,00F64B68 1,00F64B6C 2,00F64B70 3,00F64B74 分块数据模型
4,00F649E8 5,00F649EC 6,00F649F0 7,00F649F4
8,00F64A28 9,00F64A2C 10,00F64A30 11,00F64A34
*/
for (int i = 0; i < 3; i++)
{
free(pp[i]); // 先释放块内存
}
free(pp); // 再释放指针
system("pause");
}
开辟块状的堆内存_二维数组
通过栈内存分配函数在堆上开辟静态内存
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
/*
栈上内存分配函数:
alloca
堆上内存分配函数:
malloc
calloc
realloc
recalloc
*/
static void show()
{
int *p = alloca(sizeof(int) * 10); // alloca是栈内分配内存的函数
for (int i = 0; i < 10; i++)
{
p[i] = i;
}
//free(p); 栈上内存不能free
}
void main018()
{
show();
puts("
");
show();
puts("
");
system("pause");
}
alloca函数在栈上分配静态内存
栈上开辟连续内存
// 栈上开辟内存
void main001()
{
int *p = (int[]) { 0 }; // 栈上开辟一维数组
int a[3][4]; // 栈上开辟二维数组
int(*px)[4] = (int[][4]) { 0 }; // 栈上开辟二维数组
int(*py)[3][4] = (int[][3][4]) { 0 }; // 栈上开辟三维数组
system("pause");
}
栈上开辟连续内存
void main004()
{
int(*p)[4] = (int[3][4]) { 0 }; // 栈上开辟二维数组,连续分配,自动释放
int num = 0;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 4; j++)
{
printf("%3d,%p", p[i][j] = num++, &p[i][j]);
}
putchar('
');
}
/*
0,012FFA48 1,012FFA4C 2,012FFA50 3,012FFA54
4,012FFA58 5,012FFA5C 6,012FFA60 7,012FFA64
8,012FFA68 9,012FFA6C 10,012FFA70 11,012FFA74
*/
system("pause");
}
开辟连续的栈内存_二维数组