今天由于老师代码中free()函数过后又进行 =NULL操作特来反馈、回忆深入理解。 其实早在我的这篇文章当中就对于C++的一些指针的机制进行反思过。 自己对于已经学过去的知识并没有即使的反思回顾。导致遗忘。
对于C语言free()函数的一些反思
上周在解决一道课后习题的时候,偶然间发现了一个自己从未注意过的问题,问题描述如下: 在遍历一个循环链表时,我发现在我调用free()函数删除了一个节点之后,仍然能用printf打印出原先的数据,起初我以为是巧合,并未加以注意。今天我又尝试free其他节点,之后仍然能够通过printf打印出原先的值,这个问题立刻引起了我的注意。下面将出现问题的代码附在下方,供各位查看:
include
include
include
include
include
include
include
using namespace std;
int main()
{
struct stu
{
int num;
char name;
char sex;
float score;
} ps;
ps = (struct stu)malloc(sizeof(struct stu));
ps->num = 102;
ps->name = “Zhang ping”;
ps->sex = ‘M’;
ps->score = 62.5;
printf(“Number=%d Name=%s “, ps->num, ps->name);
printf(“sex=%c Score=%f “, ps->sex, ps->score);
free(ps);
cout << endl << “新的 free() 测试开始: “;
cout << endl;
int \a = (int *)malloc(sizeof(int));
a = 5;
printf(“前 本身地址 a = %d 和值:%d 存放地址:%d\\n”, &a, a,a);
//free(a);
printf(“后 本身地址 a = %d 和值:%d 存放地址:%d\\n”, &a, a, a);
a = 4;
printf(“本身地址a = %d 和值:%d 存放地址:%d\\n”, &a, a, a);
int b;
b = (int )malloc(sizeof(int));
b = 5;
printf(“b赋值后 b本身地址:%d 和值:%d 存放地址:%d\\n”, &b, b, b);
printf(“a赋值后 a本身地址:%d 和值:%d 存放地址:%d\\n”, &a, a, a);
cout << “int 的长度: “ << sizeof(int) << endl;
cout << “a指针 的长度: “ << sizeof(a) << endl;
cout << “&a指针 的长度: “ << sizeof(&a) << endl;
system(“pause”);
return 0;
}
从理论上看,free之后不应该打印出原数值,但事实是,我加粗的那行代码成功地打印出了原数值,在我google之后,得到了这样的解答: “你在free(p)之后,最好加上p = NULL; 要不然容易导致野指针。你在free(p)之后,你只是使用 if(p != NULL) 你想的是用来进行防止误用操作对吧。。 你进入了一个误区,误认为free(p)之后,p就指向了NULL,而其实不然。 free(p)的言外之意就是告诉编译器:大家注意啦哈,这块内存我现在不用了,你们谁想用就拿去用哈。而p在这里你可以完全理解成就是这块内存的地址,也就是告诉编译器,这块内存现在不被占用了,而里面的内容此时就是我们所说的“垃圾”,因为作为主人的我已经丢弃它了,里面的内容就是不可控的。 注意p是个地址,你没有强行置为空,那还是原来的那个值。只是里面的内容不受控啦,有可能不会变,有可能会被改写,而结果是未知的。” 之前在知乎上总是看到大牛们大书特书C语言内存管理机制的缺陷,野指针的种种危害。却从未想过究竟什么是“野指针”,今天遇到的这个问题就是野指针带来的,自己对于已经学过去的知识并没有即使的反思回顾。导致遗忘。
关于占位——字节对齐回顾
一般都是用sizeof来看占位的字节数。 %d &a 取地址因为是d所以地址为十进制每字节。~~~
引用 6 楼 u012461368 的回复:
Quote: 引用 5 楼 bhfdcn 的回复:
Quote: 引用 3 楼 u012461368 的回复:
Quote: 引用 1 楼 bhfdcn 的回复:
第一个是因为内存对齐的原因,你的32位机器指针大小是4,第二个是因为两个指针
内存对齐?就是也有可能不是6吗?
举个简单的例子吧,比如你的代码改成如下:
C/C++ code
1
2
3
4
5
typedef
struct
qnode
{
char
data;
struct
qnode * next;
}QNode;
然后你在输出sizeof(QNode),大小为8,因为data之后补齐了3个字节,实际指针还是4个字节,内存布局如下图所示:
哦哦,是指结构体运用指针后大小始终保持4的倍数的意思吗?
不完全正确,你把指针换成int类型或别的大于1字节的类型也可能引起结构体大小变化,比如:
C/C++ code
1
2
3
4
5
typedef
struct
qnode
{
char
data;
int
next;
}QNode;
大小也为8,再比如:
C/C++ code
1
2
3
4
5
6
typedef
struct
qnode
{
char
data1;
char
data2;
int
next;
}QNode;
的大小也为8,但是你要把data2和next位置换一下,大小就变成12了,如下:
C/C++ code
1
2
3
4
5
6
typedef
struct
qnode
{
char
data1;
int
next;
char
data2;
}QNode;
大小为12。