C语言-动态内存管理常见错误

目录

请指出以下代码的错误?//忘记释放,造成内存泄露

笔试题:

1. 运行test函数的结果,为什么?

 2. 运行test的结果?//虽然打印出来10,但是代码是错误的,只是空间可能还没占用罢了

 3. 运行test的结果?//非法内存访问,但是会输出world

4.运行结果是?打印出来烫烫烫,返回栈空间地址的问题

5. 运行结果是?

这里返回的是变量本身,返回变量本身,返回的时候会在寄存器上临时保存,再返回,虽然还是会销毁,但是销毁与否与寄存器无关


calloc、malloc、realloc函数的区别及用法?
三者都是分配内存,都是stdlib.h库里的函数,但是也存在一些差异。

1).malloc函数。其原型void *malloc(unsigned int num_bytes);
        num_byte为要申请的空间大小,需要我们手动的去计算;

        如int *p = (int *)malloc(20*sizeof(int)),如果编译器默认int为4字节存储的话,那么计算结果是80Byte,一次申请一个80Byte的连续空间,并将空间基地址强制转换为int类型,赋值给指针p,此时申请的内存值是不确定的。

2).calloc函数,其原型void *calloc(size_t n, size_t size);
        其比malloc函数多一个参数,并不需要人为的计算空间的大小,比如如果他要申请20个int类型空间,会int *p = (int *)calloc(20, sizeof(int)),这样就省去了人为空间计算的麻烦。但这并不是他们之间最重要的区别,malloc申请后空间的值是随机的,并没有进行初始化,而calloc却在申请后,对空间逐一进行初始化,并设置值为0;

        既然calloc不需要计算空间并且可以直接初始化内存避免错误,那为什么不直接使用calloc函数,那要malloc要什么用呢?
        实际上,任何事物都有两面性,有好的一面,必然存在不好的地方。这就是效率。calloc函数由于给每一个空间都要初始化值,那必然效率较malloc要低,并且现实世界,很多情况的空间申请是不需要初始值的,这也就是为什么许多初学者更多的接触malloc函数的原因。

3).realloc函数和上面两个有本质的区别,其原型void realloc(void *ptr, size_t new_Size)
        用于对动态内存进行扩容(及已申请的动态空间不够使用,需要进行空间扩容操作),ptr为指向原来空间基址的指针, new_size为接下来需要扩充容量的大小。

        如果size较小,原来申请的动态内存后面还有空余内存,系统将直接在原内存空间后面扩容,并返回原动态空间基地址;如果size较大,原来申请的空间后面没有足够大的空间扩容,系统将重新申请一块(20+size)*sizeof(int)的内存,并把原来空间的内容拷贝过去,原来空间free;如果size非常大,系统内存申请失败,返回NULL,原来的内存不会释放。注意:如果扩容后的内存空间较原空间小,将会出现数据丢失,如果直接realloc(p, 0);相当于free(p).

realloc实例:栈的c语言实现中: 

void StackPush(ST* ps, STDataType x)//入栈或者说压栈
{
    assert(ps);
    //判断栈是否满了,满了就扩容,
    if (ps->capacity == ps->top)
    {
        //考虑第一次入栈,栈为空的时候(加上判断),给栈初始容量4
        int newcapcity = (ps->capacity == 0) ? 4 : (ps->capacity * 2);
        ps->a = (STDateType*)realloc(ps->a, newcapcity);
        if (ps->a == NULL)
        {
            printf("realloc error!\n");
            exit(-1);
        }
    }
    ps->a[ps->top] = x;
    ++ps->top;

}
#include<stdio.h>
#include<stdlib.h>

void test4()
{
	int* p = (int*)malloc(100);
	free(p);
	free(p);//重复释放
}
void test3()
{
	int* p = (int*)malloc(100);
	p++;
	free(p);//p不再指向动态内存的起始位置
}
void test2()
{
	int a = 10;//栈上的空间是自动释放的
	int* p = &a;
	free(p);//ok?//对非动态开辟的空间进行释放
}
void test1()
{
	int i = 0;
	int* p = (int*)malloc(10 * sizeof(int));
	if (NULL == p)
	{
		exit(EXIT_FAILURE);
	}
	for (i = 0; i <= 10; i++)
	{
		*(p + i) = i;//当i是10的时候越界访问
	}
	free(p);
}
void test()
{
	//申请空间过大,可能开辟失败
	int* p = (int*)malloc(INT_MAX / 4);
	*p = 20;//如果p的值是NULL,就会有问题
	free(p);
}
int main()
{
	test();
	test1();
	test2();
	test3();
	test4();
	return 0;
}

请指出以下代码的错误?//忘记释放,造成内存泄露

#include<stdio.h>
#include<stdlib.h>
//void test()
int* test()
{
	int* p = (int*)malloc(100);
	if (NULL != p)
	{
		*p = 20;
	}
	//free(p);
	//p = NULL;
	return p;
}
int main()
{
	int* ptr = test();
	free(ptr);
	//test();
	return 0;
}

笔试题:

1. 运行test函数的结果,为什么?

void GetMemory(char* p)//刚传过来的时候p也是空指针
{
	p = (char*)malloc(100);//p指向堆区的这一块空间
}//但是p是临时变量,出了函数就销毁了,但是malloc的空间还在,只是找不到了
void Test(void)
{
	char* str = NULL;
	GetMemory(str);//把str本身直接传过去了
	strcpy(str, "hello world");
//p的改变不会改变str,str还是空指针,这个时候用helloworld去覆盖NULL指针,会非法访问内存
	printf(str);
}
int main()
{
	Test();
	return 0;
}

运行结果:程序崩溃

 2. 运行test的结果?//虽然打印出来10,但是代码是错误的,只是空间可能还没占用罢了

int* test()
{
	int a = 10;
	return &a;
}
int main()
{
	int* p = test();
	//printf("hehe\n");//加上这句话,就打印不出10了
	printf("%d\n", *p);
	return 0;
}//虽然打印出来10,但是代码是错误的,只是空间可能还没占用罢了

 3. 运行test的结果?//非法内存访问,但是会输出world

void Test(void)
{
	char* str = (char*)malloc(100);
	strcpy(str, "hello");
	free(str);//free不会让str置成空
	if (str != NULL)
	{
		//此时str指向的空间已经被free了,造成非法访问内存
		strcpy(str, "world");
		//free后房子可能还在,只是你没有了钥匙,你再访问就取决于房东和新的租客了
		//回收只是从你手里回收给房东
		printf(str);
	}
}
int main()
{
	Test();
	return 0;
}

4.运行结果是?打印出来烫烫烫,返回栈空间地址的问题

char* GetMemory(void)
{
	char p[] = "hello world";
	return p;//注意:这里不是返回的变量,而是栈空间上的地址
	//数组名是数组首元素的地址,所以会销毁
}
void Test(void)
{
	char* str = NULL;
	str = GetMemory();
	printf(str);
}
int main()
{
	Test();
	return 0;
}

p在GETMEMORY创建,出了空间就被销毁,返回的是数组的地址,
但是出了函数后,p的空间回收了,
str虽然记着p的地址,这个时候str就变成了野指针。
因为p的所有权已经不属于我们了。
可以加上static,空间就还在
就是本来租的房间,到期后不属于我们了,返给房东了
房东可以把房子再租出去,我们没有权利管理了

加上static,他就不是在栈区了,变成了 静态数据,延长了寿命,所以能正常打印出hello,world

5. 运行结果是?(最易错,重点)

这里返回的是变量本身,返回变量本身,返回的时候会在寄存器上临时保存,再返回,虽然还是会销毁,但是销毁与否与寄存器无关


int test()
{
	int a = 10;
	return a;//这里返回的是变量本身,返回变量本身,返回的时候会在寄存器上临时保存,再返回,销毁与否与寄存器无关
}
int main()
{
	int m = test();
	printf("%d\n", m);
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值