对于指针以前就说过了,没有赋值地址的指针是不可以写的,这里就给一个更加深入的说法:
第一、指针指向一个地址,因此,在不管以后写或是不写的情况下,它可以指向任何一个地址,而且都是可以的,比如:
int *p , a, b;
p = &a;
p = &b;
即便是ab都没有分配值,但是它的地址是存在的;
第二、上面的那种情况是有局限性的,他的成立条件就是系统已经给这个指针分配好4个字节的情况,因此,也并不是所有的指针都可以任意指向,当一个指针以另外一个对象的指针的形式存在的时候,指针的4个字节是确定的了,同情况一,但是作为指针的内部指针存在的时候,分给指针的4个字节的空间就不是那么的明朗了,这个时候就牢记一点,这个4个字节也是指针的内部值,在没有大的指针分配地址空间的时候,内部依旧不可以写,那么这个小的内部指针也是不可以写的,因此它不可以指向任何地址!
#include <stdio.h>
#include <malloc.h>
typedef struct sim {
sim *next;
}sim ;
int main() {
sim *d = (sim *)malloc(sizeof(sim) );
sim e;
e.next = d; //next要用到的4字节空间已经随着e对象的系统自动分配产生,因此可以写!
sim *a = &e; //也是可以的,独立的指针,要用到的用于存放指针的4个字节空间也是分配好的
sim *b; b->next = &e; //Oh, b认为是一个独立的指针,并没有分配一个sim大小的空间,内部自然不可写
//即便next是指针,他的4字节空间不确定,编译通过,运行失败!
}
#include <stdio.h>
#include <malloc.h>
typedef struct sim {
sim *next;
}sim ;
int main() {
sim *d = (sim *)malloc(sizeof(sim) );
sim e;
e.next = d; //next要用到的4字节空间已经随着e对象的系统自动分配产生,因此可以写!
sim *a = &e; //也是可以的,独立的指针,要用到的用于存放指针的4个字节空间也是分配好的
sim *b;
b->next = &e; //Oh, b认为是一个独立的指针,并没有分配一个sim大小的空间,内部自然不可写
//即便next是指针,他的4字节空间不确定,编译通过,运行失败!
}
因此还是那句话,指针没有分配地址空间的时候,内部不可写!
我们看一个链表的错误的删除操作,而且这种操作我在好多地方见过,如下:
{
//
……
list p;
//
p is a list object created with head and lnode is the node of the list!
lnode current
=
p
->
head;
//
delete opration
while
(current
!=
NULL) { free(current); current
=
current
->
next; }
//
……
}
这里问题就出来了,current被free之后,他的next还可以指向他之前指向的那个对象否?那他的自带的值还可以被写否?
前者是否定的,后者是不一定,一般的情况甚至是肯定的。
首先补充一点,就是一个指针也特别结构体指针,在没有分配地址空间的时候,不管是对象还是指针都是不可以写的,指针可以写NULL。如下,malloc的头文件在vs2005要代malloc.h头文件,linux的gcc编译器只要stdio.h就可以了:
#include
<
stdio.h
>
#include
<
malloc.h
>
typedef
struct
simple {
int
test; simple
*
next; }simple ;
int
main() { simple
*
a,
*
b,
*
c; a
->
test
=
100
; a
->
next
=
b; }
这个程序在vs2005里面运行就是一个很响亮的“当”,linux下就是程序中断得到一个段错误。
回到上面的问题,既然free了那就相当于没有分配空间,肯定也就不能写哦,为什么答案是可以写呢(一般情况下)?
这样,我们创建一个小链表,就两个对象,a和b,让a的next指向b,然后free释放a,再看看:
#include
<
stdio.h
>
#include
<
malloc.h
>
typedef
struct
simple {
int
test; simple
*
next; }simple ;
int
main() { simple
*
a,
*
b,
*
c; a
=
(simple
*
)malloc(
sizeof
(simple) ); b
=
(simple
*
)malloc(
sizeof
(simple) ); c
=
(simple
*
)malloc(
sizeof
(simple) ); a
->
test
=
100
; b
->
test
=
200
; c
->
test
=
300
; a
->
next
=
b; b
->
next
=
NULL; c
->
next
=
NULL; printf(
"
The addr of a is %d !
"
, (
void
*
)a); printf(
"
The addr of b is %d !
"
, (
void
*
)b); printf(
"
The addr of c is %d !
"
, (
void
*
)c); printf(
"
The addr of a->next is %d !
"
, (
void
*
)a
->
next ); printf(
"
The number of a->test is %d !
"
, (a
->
test)); printf(
"
The addr of a->test is %d !
"
, (
void
*
)
&
(a
->
test)); puts(
""
); free(a); printf(
"
The addr of a is %d !
"
, (
void
*
)a); printf(
"
The addr of b is %d !
"
, (
void
*
)b); printf(
"
The addr of c is %d !
"
, (
void
*
)c); printf(
"
The addr of a->next is %d !
"
, (
void
*
)a
->
next); printf(
"
The number of a->test is %d !
"
, (a
->
test)); printf(
"
The addr of a->test is %d !
"
, (
void
*
)
&
(a
->
test)); puts(
""
); a
->
next
=
c; a
->
test
=
100
; printf(
"
The addr of c is %d !
"
, (
void
*
)a
->
next); printf(
"
Test is %d
"
, b
->
test);
return
0
; }
程序输出:
The addr of a
is
3887080
!
The addr of b
is
3876984
!
The addr of c
is
3877040
!
The addr of a
->
next
is
3876984
!
The number of a
->
test
is
100
!
The addr of a
->
test
is
3887080
!
The addr of a
is
3887080
!
The addr of b
is
3876984
!
The addr of c
is
3877040
!
The addr of a
->
next
is
-
572662307
!
The number of a
->
test
is
-
572662307
!
The addr of a
->
test
is
3887080
!
The addr of c
is
3877040
!
Test
is
200
在这个程序里面我们就看到了,free之前,a的内容如下:
The addr of a->next is 3876984 !
The number of a->test is 100 !
The addr of a->test is 3887080 !
free之后,内容如下: The addr of a->next is -572662307 !
The number of a->test is -572662307 !
The addr of a->test is 3887080 !
test和next的值都已经变化了,但是从test的地址可以看出a并没有从原来的地址“撤兵”,他依旧指向他以前的地址,但是有一点很明显就是a里面的所有的值都已经变化,而且是很奇怪了。
这里就回答了前面的两个问题,free之后的对象不再指向他原来的值,但是他依旧可以写,但是,如果他用的这个内存在此被分配给别的变量的时候,就不再可写了。
再回到最上面的delete操作,再上面的这段程序里面加点东西,让a的地址变为a的next,开始已经知道了,next已经变了,但是还是可写的。
如下:
#include
<
stdio.h
>
#include
<
malloc.h
>
typedef
struct
simple {
int
test; simple
*
next; }simple ;
int
main() { simple
*
a,
*
b,
*
c; a
=
(simple
*
)malloc(
sizeof
(simple) ); b
=
(simple
*
)malloc(
sizeof
(simple) ); c
=
(simple
*
)malloc(
sizeof
(simple) ); a
->
test
=
100
; b
->
test
=
200
; c
->
test
=
300
; a
->
next
=
b; b
->
next
=
NULL; c
->
next
=
NULL; printf(
"
The addr of a is %d !
"
, (
void
*
)a); printf(
"
The addr of b is %d !
"
, (
void
*
)b); printf(
"
The addr of c is %d !
"
, (
void
*
)c); printf(
"
The addr of a->next is %d !
"
, (
void
*
)a
->
next ); printf(
"
The number of a->test is %d !
"
, (a
->
test)); printf(
"
The addr of a->test is %d !
"
, (
void
*
)
&
(a
->
test)); puts(
""
); free(a); printf(
"
The addr of a is %d !
"
, (
void
*
)a); printf(
"
The addr of b is %d !
"
, (
void
*
)b); printf(
"
The addr of c is %d !
"
, (
void
*
)c); printf(
"
The addr of a->next is %d !
"
, (
void
*
)a
->
next); printf(
"
The number of a->test is %d !
"
, (a
->
test)); printf(
"
The addr of a->test is %d !
"
, (
void
*
)
&
(a
->
test)); puts(
""
); a
=
a
->
next; a
->
next
=
c; a
->
test
=
100
; printf(
"
The addr of c is %d !
"
, (
void
*
)a
->
next); printf(
"
Test is %d
"
, b
->
test);
return
0
; }
这样一来,在执行到a->next = c的时候程序崩溃,a指向了一个不可写的地址,a = a->next不会崩溃,因为这里只是改变了一个地址值,而不是写内存。
解决方案:
对于free了的指针,我们补上一句话,用NULL给它赋地址!