对于C语言free()函数的一些反思

上周在解决一道课后习题的时候,偶然间发现了一个自己从未注意过的问题,问题描述如下:
在遍历一个循环链表时,我发现在我调用free()函数删除了一个节点之后,仍然能用printf打印出原先的数据,起初我以为是巧合,并未加以注意。今天我又尝试free其他节点,之后仍然能够通过printf打印出原先的值,这个问题立刻引起了我的注意。下面将出现问题的代码附在下方,供各位查看:

#include<stdio.h>
#include<stdlib.h>
#include<time.h>
#define OK 1
#define ERROR 0
#define TRUE 1
#define FALSE 0
typedef int status;
typedef int elemtype;
typedef struct node{
    elemtype data;
    struct node * next;
}node;
typedef struct node * linkqueue;

int main(void){
    linkqueue rear,pmove,head,qmove;
    int i=0;
    pmove=rear=(linkqueue)malloc(sizeof(node));
    if(!pmove||!rear)
       return ERROR;
    head=pmove;

    /*建立循环链表,并让0~9入队*/ 
    for(i=0;i<10;i++){
        qmove=(linkqueue)malloc(sizeof(node));
        qmove->data=i;
        rear->next=qmove;
        rear=qmove;
    }
    rear->next=head;
    pmove=head->next;

    printf("将0~9入队后\n");
    while(pmove!=head){
        printf("%d ",pmove->data);
        pmove=pmove->next;
    }
    printf("\n");

    /*出队算法*/ 
    pmove=head->next;
    printf("出队元素为:%d\n",pmove->data);
    linkqueue smove=pmove->next;
    free(pmove);
    ***printf("%d ",pmove->data);/*注意这行代码,这是问题之所在*/***
    pmove=smove;

    printf("出队后,遍历队列\n"); 
    while(pmove!=head){
        printf("%d ",pmove->data);
        pmove=pmove->next;
    }
    printf("\n");
}

从理论上看,free之后不应该打印出原数值,但事实是,我加粗的那行代码成功地打印出了原数值,在我google之后,得到了这样的解答:
“你在free(p)之后,最好加上p = NULL;

要不然容易导致野指针。你在free(p)之后,你只是使用
if(p != NULL)
你想的是用来进行防止误用操作对吧。。

你进入了一个误区,误认为free(p)之后,p就指向了NULL,而其实不然。

free(p)的言外之意就是告诉编译器:大家注意啦哈,这块内存我现在不用了,你们谁想用就拿去用哈。而p在这里你可以完全理解成就是这块内存的地址,也就是告诉编译器,这块内存现在不被占用了,而里面的内容此时就是我们所说的“垃圾”,因为作为主人的我已经丢弃它了,里面的内容就是不可控的。

注意p是个地址,你没有强行置为空,那还是原来的那个值。只是里面的内容不受控啦,有可能不会变,有可能会被改写,而结果是未知的。”

之前在知乎上总是看到大牛们大书特书C语言内存管理机制的缺陷,野指针的种种危害。却从未想过究竟什么是“野指针”,今天遇到的这个问题就是野指针带来的,看来自己对C指针的认识还不够深刻,还需要更深层次的学习,特地写下此文,加以反思。

看来水平离熟练使用C还差很远,静下心继续反思吧。

2016-04-27 晨
于教学实验综合楼

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值