目录
如果参数 size 为0,malloc的行为是标准是未定义的,取决于编译器。2.free
为什么存在动态内存分配?
int main()
{
int ret = 0;//在栈区开辟四个字节
char arr[10] = { 0 };//在栈区开辟10个字节的连续空间
return 0;
}
特点:
- 空间大小是确定的(固定的);
- 数组在声明的时候,指定多少个字节,则内存就分配多少空间。
对于空间需求我们不仅仅局限于固定值,某些情况我们不能确定所需空间大小。这时我们就需要动态内存开辟
补充:动态内存都是在堆区开辟,由程序员主动或程序结束自动释放。
动态内存函数
1.malloc
意义:向内存申请一块连续内存空间,返回指向这块内存的指针。
注意:返回值的类型是void* 需要程序员自己确定(强转)。
如果参数 size 为0,malloc的行为是标准是未定义的,取决于编译器。
2.free
意义:释放动态开辟的内存
注意:如果参数不是指向动态开辟的,则free函数的行为是未定义的。
如果参数是NULL指针,则函数什么也不做。
代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include<stdio.h>
#include<stdlib.h>
int main()
{
//int ret = 0;//在栈区开辟四个字节
//char arr[10] = { 0 };//在栈区开辟10个字节的连续空间
int* ptr = 0;
ptr = (int *)malloc(sizeof(int) * 10);//开辟10个4个字节的数据
if (ptr == NULL)//判断是否开辟成功
{
perror("malloc");
}
for (int i = 0; i < 10; i++)
{
*(ptr + i) = i;//赋值
}
for (int j = 0; j < 10; j++)
{
printf("%d ", *(ptr + j));
}
free(ptr);
ptr = NULL;
return 0;
}
3.calloc
意义:为 num 个大小为 size 的元素开辟一块空间,并且把空间的每个字节初始化为0。
和malloc相似,区别:元素会被初始化(每个字节初始化为0)
代码:
int main()
{
int* ptr = 0;
ptr =(int*) calloc(10, sizeof(int));
if (ptr == NULL)
{
perror("calloc");
}
for (int i = 0; i < 10; i++)//
{
printf("%d ", *(ptr + i));
}
printf("\n");
free(ptr);
ptr = NULL;
return 0;
}
4.realloc
让动态开辟更加灵活,某些情况开辟的太大或太小,所以为了更灵活,realloc可以对动态开辟进行调整。
两种特殊情况:
1.原有空间之后有足够的空间。
2.没有足够的空间。
代码:
int main()
{
int* ptr = 0;
ptr = (int*)malloc(sizeof(int)*10);//申请10个4个字节数据
if (ptr == NULL)
{
perror("malloc");
}
for (int i = 0; i < 10; i++)
{
*(ptr + i) = i;
}
int* p = (int*)realloc(ptr,sizeof(int) * 20);//追加10个4字节的空间
if (p == NULL)
{
perror("realloc");
}
ptr = p;
for (int j = 10; j < 20; j++)
{
*(ptr + j) = j;
}
for (int m = 0; m < 20; m++)
{
printf("%d ", *(ptr + m));
}
free(ptr);
ptr = NULL;
return 0;
}
常见的动态内存错误:
//对NULL指针解引用
//对动态开辟内存越界访问
//对非动态内存开辟进行free
//使用free释放动态开辟的一部分
//对一块动态内存连续释放
//动态开辟忘记释放.....会造成内存泄露;
void test1()
{
//对NULL指针解引用
int* p = (int*)malloc(sizeof(int));
*p = 20;//没有进行判断若p为NULL,是有问题的。
free(p);
p = NULL;
}
void test2()
{
int* p = (int*)malloc(sizeof(int) * 10);
if (p == NULL)
{
perror("malloc");
}
for (int i = 0; i < 20; i++)
{
*(p + i) = i;
}
free(p);
p = NULL;
}
void test3()
{
int a = 10;
int* p = &a;
free(p);
p = NULL;
}
void test4()
{
int* p = (int*)malloc(sizeof(int) * 10);
if (p == NULL)
{
perror("malloc");
}
for (int i = 0; i < 5; i++)
{
*(p++) = i;
}
free(p);//这是的p不指向动态开辟的起始地址。
}
void test5()
{
int* p = (int*)malloc(sizeof(int) * 10);
free(p);
free(p);
}
void test6()
{
while (1)
{
int* p = (int*)malloc(sizeof(int));
if (p == NULL)
{
perror("malloc");
}
*p = 20;
}
}
int main()
{
//对NULL指针解引用
//test1();
//对动态开辟内存越界访问
//test2();
//对非动态内存开辟进行free
//test3();
//使用free释放动态开辟的一部分
//test4();
//对一块动态内存连续释放
//test5();
//动态开辟忘记释放.....会造成内存泄露;
test6();
return 0;
}
面试题:
1.
#include<string.h>
void GetMemory(char* p)
{
p= (char*)malloc(100);
}
void Test(void)
{
char* str = NULL;
GetMemory(str);//这里是传值,所以不会改变实参,无意义
strcpy(str, "hello world");
printf(str);//程序崩溃,啥都没有。
}
int main()
{
Test();
return 0;
}
2.
char* GetMemory(void)
{
char p[] = "hello world";
return p;//返回p的内容会被销毁,
}
void Test(void)
{
char* str = NULL;
str = GetMemory();//所以str野指针
printf(str);//打印随机
}
int main()
{
Test();
return 0;
}