转-对指针进行初始化中的若干问题的思考与反思

转http://www.cnblogs.com/uniqueliu/archive/2011/07/16/2108302.html

        我们在最开始定义一个指针的时候,最应该做的就是先将这个指针变量进行初始化,以防止它变成“野指针”。初始化的方式很简单,就是将0赋给这个指针变量:

int *p=0;

        如果我们用上面这条语句对指针进行初始化,那么编译器就会自动为我们把指针p中的值设置成0x00000000。(注意,一共有8个0哈,原因就是因为0是int型变量。该变量的字节数就是8个~~~)但是,大家有没有想过,如果我们不这样初始化这个指针,而采用下面的方法来初始化这个指针,其结果又会有什么不同呢?

  1. 虽然初始化这个指针为0,那么*p的值是不是会不会输出0呢?
  2. 如果我们定义一个变量,那么能不能用这个变量的地址来初始化这个指针呢?
  3. 既然整型变量0可以定义这个指针,那我们能不能用另外的整型变量,比如说20来初始化这个指针呢?如果定义成功,是不是编译器也会自动将20转换成16进制的0x00000020呢?

下面,我们用一个程序来验证上面这些问题的可行性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream>
using namespace std;
 
int main()
{
    //第一组为正常的赋值,将指针变量p初始化为0。
    cout<<"第一组:"<<endl;
    int i=10;
    int *p=0;
    cout<<"i的值为"<<i<<endl;
    cout<<"&i的地址为"<<&i<<endl;
    cout<<"p的值为"<<p<<endl;
    cout<<"*p的值为"<<*p<<endl;
 
    //第二组中,我们定义一个指针r,并将其初始化为i的地址
    cout<<"第二组:"<<endl;
    int *r=&i;
    cout<<"i的值为"<<i<<endl;
    cout<<"&i的地址为"<<&i<<endl;
    cout<<"r的值为"<<r<<endl;
    cout<<"*r的值为"<<*r<<endl;
 
    //第三组,我们第一了一个指针q,并将20作为初始化指针q的值。观察会不会输出0x00014这样的16进制数
    int *q=20;
    cout<<"q的值为"<<q<<endl;
    cout<<"*q的值为"<<*q<<endl;
}

我们信心满满的一点编译,啊!!!悲剧就出来了~~~~~~

        首先,我们发现这个小程序居然,居然通不过编译!问题直指第16行。错误的原因是“无法从“int”转换为“int *”。这句话的意思其实就是*q和20的类型不匹配。*q的类型为一个指向整型变量的指针(int*),而20是整型变量,它的类型就是int。编译器当然就不会认识这个是什么了啊。想一想原因就可以知道,在这里,我们初始化指针变量q的原因就在于让q中的值能成为一个固定的值,而不是成为一个野指针。而在这里,我们的心是好的,就是让这个指针之中的值存成20。这样他就不会到处乱指了。这样的心是好的,但是我们忽略了一个最基本的问题:“指针是拿来存什么的?”答案可能大家都知道,“指针当然是拿来存地址的啊!”好了,这就是错误的根源了。既然指针是拿来存地址的,你拿来存放20有什么用呢,编译器当然就不会理会你了。所以,在这里,我们需要把这句话改一下,让这个20变成是一个地址,而不是一个值。即用下面这句话,强制把20转换成内存地址:

int *q=(int *)20

        这样一来,我们就编译通过了。注意,这里面还有一个小知识点,我们这里面的20表示的是10进制的数,那么转换成16进制时,应该是0x00000014,切忌切忌不要认为是0x00000020了。所以上面那个问题都问错了,呵呵。

        编译通过之后,我们一运行,又发现错误了,程序运行着运行着就“自动结束了”,真的是很囧啊!难道我们写点东西就那么多错!!!!!没办法,我们只有用debug了~~~

打开debug,一句一句的调试,发现在程序的第13行就运行不下去而来,截了个图:

错误

        错误的大意就是“无法读取”~~~好奇怪,有什么是无法读取的呢?其实细想一下你就会发现,我们在程序的第9 行初始化了这个指针p,那么这个时候指针p中的值应该为0x00000000。但是我们需要注意的是,这个只是初始化,我们并没有指定这个指针应该指向什么地方!这就是问题的症结所在了。我们既然没有指定这个指针p应该指定什么地方,那么在调用*p的时候编译器又怎么会知道这个*想要取得的内容究竟是什么呢?所以自然就是“无法读取”了啊!

        我们在这里需要特别注意的是,这个指针的初始化并不和我们常见的那种对变量的初始化是一样的。比如说,我们想要初始化一个变量i,那么只需要写上int i=0,那么在以后的任何地方我们想要调用这个变量的时候,它的值都是i。但是对于指针变量就不一样了。我们定义一个指针p,并利用程序中第9行的代码进行初始化。那么这句话仅仅表示的是这个指针变量p中的值是0x00000000,并不代表这个“*p”这个东东的值为0。因为这里面的*表示间接运算符,它的作用是取得p这个指针所指向的内存地址中的值。这个值就不见得是0了。我们只有在下面加上一句,p=&i。利用这句话,我们就可以把指针p中的值修改为i的内存地址,这样在调用*p的时候,它就指向的是i的地址,并取得其中的值10。

      没办法,这里,我们就只有把这一行注释起来了。好了,程序继续,但是!(我最讨厌但是了~~~)但是,在程序的第26行,程序又运行不下去了,错误原因和上面一模一样,都是“无法读取”。见下图:

错误2

        想一想原因,其实和上面那个错误的原因一样。我们在这里都只是把值赋给了q,但是并没有说*q是什么,所以编译器自然就找不到了。解决方法和上面一样,注释起来,嘿嘿~~~~~~

        好了,现在程序终于通了,程序的输出结果如下图所示:

输出

        好了,从上面我们就可以看到,其实,想要对指针进行初始化,也有三种方法:

  1. 利用int *p=0;这个语句老老实实的将指针初始化了;
  2. 把int *p=0和p=&i这两句话连成一句话: int *p=&i;这样,就既把指针变量p初始化了,又把它指向了某个值;
  3. 如果非要用常量来初始化一个指针。那么就只有利用强制类型转换,找一个内存地址,利用(ElementType *) 来把常量转换成内存中的一个地址。既采用:
ElementType *p=(ElementType *)[常量]

p.s. 这里的ElementType指的就是变量的类型哈。

        好了,到这个地方,我们基本上分析完了对指针进行初始化操作中的若干问题,最后,我们再把文章一开始提出的三个问题回答下:

  1. *p根本就不会输出任何东西,因为他不知道要输出什么;(如上面程序中的第13行)
  2. 当然可以,但是需要注意的是,这样就给指针修改这个变量的值的自由哦;(如上面程序中的第17行。比如我们在17行后面加上一句,*r=20;那么此时*r和i的值就不再是10了,就变成了20.这里注意到不要因为这个原因悲剧了哈~~~~~~这里面的机理请见我上一篇博文http://www.cnblogs.com/uniqueliu/archive/2011/07/14/2106681.html,里面有详细的分析)
  3. 首先20转换成16进制应该是0x00000014。另外,我们想要用这个常量初始化这个指针,不是不可以,而是需要进行强制类型转换,把int转换成(int *)。

好了,全部搞定了,写了好多,呼呼~~收工了……

posted @ 2017-11-22 15:14  0402zhuhui  阅读(168)  评论(0编辑  收藏  举报