请问C语言free(p)释放p所指向的动态内存后p指向哪?是NULL还是随机还是啥呢?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了请问C语言free(p)释放p所指向的动态内存后p指向哪?是NULL还是随机还是啥呢?相关的知识,希望对你有一定的参考价值。

free释放后p仍然指向那块内存,所以第二次printf的值仍然和第一个一样。
但是!不代表这样的p指向的这块已经free的内存仍然可以用!!!
你两次printf打印的都是p而不是p指向的内容(内存),如果p在free后没有给他赋新的值那么p的打印永远都是这个值,但是这个值是一个地址,而这个地址所指向的内存‘可能’已经被破坏了,因为内存被free了,其他进程就可以使用这块内存。
这里‘可能’这个词要注意,就是说你可能在第二个甚至第N个printf打印出p所指向的值是一样的并没有在free后被改变,这就是所谓的野指针,一块内存从malloc开始从‘野’变‘家养’,然后通过free把‘家养’又变成了‘野’
参考技术A p还是指向原来的地址,你不重新赋值,它一般不会变。但这块地址已经被标记为回收,因此再访问就会数组越界,而数组越界报错是操作系统管理的,如果撇去操作系统的内存管理机制,那么你强制再用p是可以访问到释放前的内存空间的。 参考技术B 释放后指向随机地址。
所以free后,如果没有新地址给指针变量,p就应该给空值NULL。否则就是“野指针”。追问

谢谢您的解答。
您能给我说说为什么那个程序第二个printf输出的p的指向为什么与第一个一样吗?不是应该变成另一个随机值吗?

追答

释放的是分配内存空间,p说到底只是变量,里面的值没变,但原地址空间已经没了啊。
程序复杂的话,你能知道p指向的的地址在内存中是哪个啊。

参考技术C 人们都说:“熟读唐诗三百首,不会作诗也会吟 [6] 。”可见《唐诗三百首》影响之大。流行注本编辑

C语言 动态内存分配机制(堆区) int*p=malloc(5*sizeof)

C程序内存分配图

栈区:局部变量
堆区:动态分配的数据
静态存储区/全局区:全局变量,静态数据
代码区:代码,指令

内存分配说明

内存动态分配的相关函数

堆区:
#inlcude<stdlib.h>

Malloc(size);//分配长度为size个字节的连续空间

Calloc(n,size);//分配size个长度为n个字节的连续空间,总共有size*n个字节

Free§;//销毁指针p所指向的堆空间,其他函数和主函数不能再使用

Realloc(p,size);//重新分配指针p所指向的内存空间大小,指针所指向的地址不变,仅仅是空间扩大或缩小

Void*:

Void*:仅仅是一个纯地址,而不指向任何的对象:
Void* p;//无类型指针变量
如果是void类型,不能够用p来取得值(报错)

void*强制类型转换举例:

代码

#include<stdio.h>
//动态内存分配(堆区)--void*无类型指针

int main()
{
	int a=102;
	int *pa=&a;

	//类型转换1
	char b='c';
	char *pb=&b;
	void *p;
	char *pc;
	char *pd;
	p=(void*)pb;//强制类型转换,char*pb-->void*,并把pb地址赋值给p
	pc=(char*)p;//强制类型转换,void*p-->char*
	pd=(char*)pa;

	//记住:没有*p,p只是一个地址,不指向任何对象
	printf("类型转换1:\\n");
	printf("pb=%c address=%p self-address=%p\\n",*pb,pb,&pb);
	printf("p:address=%p self-address=%p\\n",p,&p);
	printf("pc=%c address=%p self-address=%p\\n",*pc,pc,&pc);
	printf("pd=%c address=%p self-address=%p\\n",*pd,pd,&pd);

	
	getchar();
	return 0;
}

说明:
在C99的编译器中,其他类型转void*类型,是自动类型转换:
int a=2;
void *p=&a;
低版本的则需要强制类型转换:
void *p=(void *)&a;

应用案例

代码

#include<stdio.h>
#include<stdlib.h>
//动态内存分配(堆区)--malloc()函数
//输出所有成绩中小于60的成绩
#define SIZE 5
void check(int *p,int len);//函数原型,函数声明
int *check1(int *p,int len);

int main()
{
	int *p=(int*)malloc(5*sizeof(int));//开辟5*4大小的空间,相当于一个长度为8的数组
	int i=0;
	//*p=-842150451是一个垃圾值,堆区的第一个字节,4个字节才存储一个元素,因此不能使用*p
	printf("address=%p self-address=%p\\n",*p,p,&p);
	printf("输入每一个成绩:\\n");
	while(i<5)
	{
		//p+i=arr[0]+i的地址
		//通过数组的地址来为数组每一个元素赋值
		scanf("%d",p+i);
		i++;

	}
	printf("方式1:\\n");
	//输出成绩1
	check(p,5);


	//输出成绩2
	int*k=check1(p,5);
	printf("\\n方式2:\\n");
	for(i=0;i<5;i++)
	{
		if(*k!=0)
		{
			printf("%d",*k);
			k++;
		}

	}

	getchar();//enter
	getchar();
	return 0;
}
void check(int *p,int len)
{
	int i;

	for(i=0;i<len;i++)
	{
		if(p[i]<60)
		{
			printf("%d ",p[i]);
		}
	}

}

int *check1(int *p,int len)
{
	static int i,j=0,arr[SIZE];//局部数据,使用静态static

	for(i=0;i<len;i++)
	{
		if(p[i]<60)
		{
			arr[j++]=p[i];

		}
	}

	return arr;
}

图示

练习–逆序输出字符串

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
//动态内存分配(堆区)--函数练习
//malloc()分配内存空间
//realloc()重新分配内存空间
//free()释放内存空间

char *reverse(char *s,int len);//函数声明
//逆序打印字符串
const int size=100;
int main()
{
	char *p=(char*)malloc(size*sizeof(char));//为p动态分配内存空间
	char s[size];
	gets(s);
	int len=strlen(s);
	char *p=(char*)realloc(p,len*sizeof(char));//重新为p分配更合适的内存空间
	
	//p=k[0]的地址(char*)
	p=reverse(s,len);
	int i;
	for(i=0;i<len;i++)
	{
		printf("%c",*p+i);
		//或p++
		
	}
	free(p);//释放p所指向的内存空间
	getchar();//enter
	getchar();
	return 0;
}
//逆序字符串
char *reverse(char *s,int len)
{
	int i=len-1,j=0;
	static char k[size];
	while(i>=0)
	{
		k[j++]=s[i];
		i--;
	}
	return k;
}

基本原则

1)每开辟一个内存就会占用系统开销,所以需要避免分配大量小内存块
2)内存泄漏:没有释放内存空间,这一个内存空间就会一直被占用
3)开辟了动态内存后一定要记得释放:谁分配,谁释放

指针使用一览

指针数组:
由n个指向整型元素的指针而组成,里面存放指针
Int *ptr[3];

数组指针:
指向一个有n个元素的数组的指针,里面存放的是整型变量(int类型长度为n的数组的首地址),存的是一个数组地址,而不是单个元素
int(*p)[n]

int (*p)(int ,int):指向函数的指针

以上是关于请问C语言free(p)释放p所指向的动态内存后p指向哪?是NULL还是随机还是啥呢?的主要内容,如果未能解决你的问题,请参考以下文章

[C]安全释放堆内存

C/C++——指针

刨析《C语言》进阶付费知识完结

free(p),是啥意思?是单纯p==NULL还是说p指向的内容变为空。使用free()之后 p和内存的状态是啥情况的

C语言 动态内存分配机制(堆区) int*p=malloc(5*sizeof)

delete[] p->elems和free(p->elems)有什么区别?