请问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语言 动态内存分配机制(堆区) 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还是随机还是啥呢?的主要内容,如果未能解决你的问题,请参考以下文章
free(p),是啥意思?是单纯p==NULL还是说p指向的内容变为空。使用free()之后 p和内存的状态是啥情况的